Changed a magic mystery value from 24 to 16.
There was a logic bug in MOJOSHADER_parsePreshader() that was fixed in the
merge, but it caused this mystery value to be wrong (before, we would step
too far in an array and this value was covering for it).
We still don't know what's at the end of this array, but at least we aren't
crashing now and it appears to work as well as before. It's still a mystery.
/**
* MojoShader; generate shader programs from bytecode of compiled
* Direct3D shaders.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#define __MOJOSHADER_INTERNAL__ 1
#include "mojoshader_internal.h"
#ifdef MOJOSHADER_EFFECT_SUPPORT
#include <math.h>
void MOJOSHADER_runPreshader(const MOJOSHADER_preshader *preshader,
float *outregs)
{
const float *inregs = preshader->registers;
// this is fairly straightforward, as there aren't any branching
// opcodes in the preshader instruction set (at the moment, at least).
const int scalarstart = (int) MOJOSHADER_PRESHADEROP_SCALAR_OPS;
double *temps = NULL;
if (preshader->temp_count > 0)
{
temps = (double *) alloca(sizeof (double) * preshader->temp_count);
memset(temps, '\0', sizeof (double) * preshader->temp_count);
} // if
double dst[4] = { 0, 0, 0, 0 };
double src[3][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
const double *src0 = &src[0][0];
const double *src1 = &src[1][0];
const double *src2 = &src[2][0];
MOJOSHADER_preshaderInstruction *inst = preshader->instructions;
int instit;
for (instit = 0; instit < preshader->instruction_count; instit++, inst++)
{
const MOJOSHADER_preshaderOperand *operand = inst->operands;
const int elems = inst->element_count;
const int elemsbytes = sizeof (double) * elems;
const int isscalarop = (inst->opcode >= scalarstart);
assert(elems >= 0);
assert(elems <= 4);
// load up our operands...
int opiter, elemiter;
for (opiter = 0; opiter < inst->operand_count-1; opiter++, operand++)
{
const int isscalar = ((isscalarop) && (opiter == 0));
const unsigned int index = operand->index;
switch (operand->type)
{
case MOJOSHADER_PRESHADEROPERAND_LITERAL:
{
if (!isscalar)
{
assert((index + elems) <= preshader->literal_count);
memcpy(&src[opiter][0], &preshader->literals[index], elemsbytes);
} // if
else
{
for (elemiter = 0; elemiter < elems; elemiter++)
src[opiter][elemiter] = preshader->literals[index];
} // else
break;
} // case
case MOJOSHADER_PRESHADEROPERAND_INPUT:
if (operand->array_register_count > 0)
{
int i;
const int *regsi = (const int *) inregs;
int arrIndex = regsi[((index >> 4) * 4) + ((index >> 2) & 3)];
for (i = 0; i < operand->array_register_count; i++)
{
arrIndex = regsi[operand->array_registers[i] + arrIndex];
}
src[opiter][0] = arrIndex;
} // if
else if (isscalar)
src[opiter][0] = inregs[index];
else
{
int cpy;
for (cpy = 0; cpy < elems; cpy++)
src[opiter][cpy] = inregs[index+cpy];
} // else
break;
case MOJOSHADER_PRESHADEROPERAND_OUTPUT:
if (isscalar)
src[opiter][0] = outregs[index];
else
{
int cpy;
for (cpy = 0; cpy < elems; cpy++)
src[opiter][cpy] = outregs[index+cpy];
} // else
break;
case MOJOSHADER_PRESHADEROPERAND_TEMP:
if (temps != NULL)
{
if (isscalar)
src[opiter][0] = temps[index];
else
memcpy(src[opiter], temps + index, elemsbytes);
} // if
break;
default:
assert(0 && "unexpected preshader operand type.");
return;
} // switch
} // for
// run the actual instruction, store result to dst.
int i;
switch (inst->opcode)
{
#define OPCODE_CASE(op, val) \
case MOJOSHADER_PRESHADEROP_##op: \
for (i = 0; i < elems; i++) { dst[i] = val; } \
break;
//OPCODE_CASE(NOP, 0.0) // not a real instruction.
OPCODE_CASE(MOV, src0[i])
OPCODE_CASE(NEG, -src0[i])
OPCODE_CASE(RCP, 1.0 / src0[i])
OPCODE_CASE(FRC, src0[i] - floor(src0[i]))
OPCODE_CASE(EXP, exp(src0[i]))
OPCODE_CASE(LOG, log(src0[i]))
OPCODE_CASE(RSQ, 1.0 / sqrt(src0[i]))
OPCODE_CASE(SIN, sin(src0[i]))
OPCODE_CASE(COS, cos(src0[i]))
OPCODE_CASE(ASIN, asin(src0[i]))
OPCODE_CASE(ACOS, acos(src0[i]))
OPCODE_CASE(ATAN, atan(src0[i]))
OPCODE_CASE(MIN, (src0[i] < src1[i]) ? src0[i] : src1[i])
OPCODE_CASE(MAX, (src0[i] > src1[i]) ? src0[i] : src1[i])
OPCODE_CASE(LT, (src0[i] < src1[i]) ? 1.0 : 0.0)
OPCODE_CASE(GE, (src0[i] >= src1[i]) ? 1.0 : 0.0)
OPCODE_CASE(ADD, src0[i] + src1[i])
OPCODE_CASE(MUL, src0[i] * src1[i])
OPCODE_CASE(ATAN2, atan2(src0[i], src1[i]))
OPCODE_CASE(DIV, src0[i] / src1[i])
OPCODE_CASE(CMP, (src0[i] >= 0.0) ? src1[i] : src2[i])
//OPCODE_CASE(NOISE, ???) // !!! FIXME: don't know what this does
//OPCODE_CASE(MOVC, ???) // !!! FIXME: don't know what this does
OPCODE_CASE(MIN_SCALAR, (src0[0] < src1[i]) ? src0[0] : src1[i])
OPCODE_CASE(MAX_SCALAR, (src0[0] > src1[i]) ? src0[0] : src1[i])
OPCODE_CASE(LT_SCALAR, (src0[0] < src1[i]) ? 1.0 : 0.0)
OPCODE_CASE(GE_SCALAR, (src0[0] >= src1[i]) ? 1.0 : 0.0)
OPCODE_CASE(ADD_SCALAR, src0[0] + src1[i])
OPCODE_CASE(MUL_SCALAR, src0[0] * src1[i])
OPCODE_CASE(ATAN2_SCALAR, atan2(src0[0], src1[i]))
OPCODE_CASE(DIV_SCALAR, src0[0] / src1[i])
//OPCODE_CASE(DOT_SCALAR) // !!! FIXME: isn't this just a MUL?
//OPCODE_CASE(NOISE_SCALAR, ???) // !!! FIXME: ?
#undef OPCODE_CASE
case MOJOSHADER_PRESHADEROP_DOT:
{
double final = 0.0;
for (i = 0; i < elems; i++)
final += src0[i] * src1[i];
for (i = 0; i < elems; i++)
dst[i] = final; // !!! FIXME: is this right?
break;
} // case
default:
assert(0 && "Unhandled preshader opcode!");
break;
} // switch
// Figure out where dst wants to be stored.
if (operand->type == MOJOSHADER_PRESHADEROPERAND_TEMP)
{
assert(preshader->temp_count >=
operand->index + (elemsbytes / sizeof (double)));
memcpy(temps + operand->index, dst, elemsbytes);
} // if
else
{
assert(operand->type == MOJOSHADER_PRESHADEROPERAND_OUTPUT);
for (i = 0; i < elems; i++)
outregs[operand->index + i] = (float) dst[i];
} // else
} // for
} // MOJOSHADER_runPreshader
static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static uint32 readui32(const uint8 **_ptr, uint32 *_len)
{
uint32 retval = 0;
if (*_len < sizeof (retval))
*_len = 0;
else
{
const uint32 *ptr = (const uint32 *) *_ptr;
retval = SWAP32(*ptr);
*_ptr += sizeof (retval);
*_len -= sizeof (retval);
} // else
return retval;
} // readui32
static char *readstring(const uint8 *base,
const uint32 offset,
MOJOSHADER_malloc m,
void *d)
{
// !!! FIXME: sanity checks!
// !!! FIXME: verify this doesn't go past EOF looking for a null.
const char *str = ((const char *) base) + offset;
const uint32 len = *((const uint32 *) str);
char *strptr = NULL;
if (len == 0) return NULL; /* No length? No string. */
strptr = (char *) m(len, d);
memcpy(strptr, str + 4, len);
return strptr;
} // readstring
static int findparameter(const MOJOSHADER_effectParam *params,
const uint32 param_count,
const char *name)
{
int i;
for (i = 0; i < param_count; i++)
if (strcmp(name, params[i].value.name) == 0)
return i;
assert(0 && "Parameter not found!");
}
static void readvalue(const uint8 *base,
const uint32 typeoffset,
const uint32 valoffset,
MOJOSHADER_effectValue *value,
MOJOSHADER_effectObject *objects,
MOJOSHADER_malloc m,
void *d)
{
int i;
const uint8 *typeptr = base + typeoffset;
const uint8 *valptr = base + valoffset;
unsigned int typelen = 9999999; // !!! FIXME
const uint32 type = readui32(&typeptr, &typelen);
const uint32 valclass = readui32(&typeptr, &typelen);
const uint32 name = readui32(&typeptr, &typelen);
const uint32 semantic = readui32(&typeptr, &typelen);
const uint32 numelements = readui32(&typeptr, &typelen);
value->type.parameter_type = (MOJOSHADER_symbolType) type;
value->type.parameter_class = (MOJOSHADER_symbolClass) valclass;
value->name = readstring(base, name, m, d);
value->semantic = readstring(base, semantic, m, d);
value->type.elements = numelements;
/* Class sanity check */
assert(valclass >= MOJOSHADER_SYMCLASS_SCALAR && valclass <= MOJOSHADER_SYMCLASS_STRUCT);
if (valclass == MOJOSHADER_SYMCLASS_SCALAR
|| valclass == MOJOSHADER_SYMCLASS_VECTOR
|| valclass == MOJOSHADER_SYMCLASS_MATRIX_ROWS
|| valclass == MOJOSHADER_SYMCLASS_MATRIX_COLUMNS)
{
/* These classes only ever contain scalar values */
assert(type >= MOJOSHADER_SYMTYPE_BOOL && type <= MOJOSHADER_SYMTYPE_FLOAT);
const uint32 columncount = readui32(&typeptr, &typelen);
const uint32 rowcount = readui32(&typeptr, &typelen);
value->type.columns = columncount;
value->type.rows = rowcount;
uint32 siz = columncount * rowcount;
if (numelements > 0)
siz *= numelements;
value->value_count = siz;
siz *= 4;
value->values = m(siz, d);
memcpy(value->values, valptr, siz);
} // if
else if (valclass == MOJOSHADER_SYMCLASS_OBJECT)
{
/* This class contains either samplers or "objects" */
assert(type >= MOJOSHADER_SYMTYPE_STRING && type <= MOJOSHADER_SYMTYPE_VERTEXSHADER);
if (type == MOJOSHADER_SYMTYPE_SAMPLER
|| type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
{
unsigned int vallen = 9999999; // !!! FIXME
const uint32 numstates = readui32(&valptr, &vallen);
value->value_count = numstates;
const uint32 siz = sizeof(MOJOSHADER_effectSamplerState) * numstates;
value->values = m(siz, d);
memset(value->values, '\0', siz);
for (i = 0; i < numstates; i++)
{
MOJOSHADER_effectSamplerState *state = &value->valuesSS[i];
const uint32 stype = readui32(&valptr, &vallen) & ~0xA0;
/*const uint32 FIXME =*/ readui32(&valptr, &vallen);
const uint32 statetypeoffset = readui32(&valptr, &vallen);
const uint32 statevaloffset = readui32(&valptr, &vallen);
state->type = (MOJOSHADER_samplerStateType) stype;
readvalue(base, statetypeoffset, statevaloffset,
&state->value, objects,
m, d);
if (stype == MOJOSHADER_SAMP_TEXTURE)
objects[state->value.valuesI[0]].type = (MOJOSHADER_symbolType) type;
} // for
} // if
else
{
uint32 numobjects = 1;
if (numelements > 0)
numobjects = numelements;
value->value_count = numobjects;
const uint32 siz = 4 * numobjects;
value->values = m(siz, d);
memcpy(value->values, valptr, siz);
for (i = 0; i < value->value_count; i++)
objects[value->valuesI[i]].type = (MOJOSHADER_symbolType) type;
} // else
} // else if
else if (valclass == MOJOSHADER_SYMCLASS_STRUCT)
{
uint32 siz;
value->type.member_count = readui32(&typeptr, &typelen);
siz = value->type.member_count * sizeof (MOJOSHADER_symbolStructMember);
value->type.members = (MOJOSHADER_symbolStructMember *) m(siz, d);
uint32 structsize = 0;
for (i = 0; i < value->type.member_count; i++)
{
MOJOSHADER_symbolStructMember *mem = &value->type.members[i];
mem->info.parameter_type = (MOJOSHADER_symbolType) readui32(&typeptr, &typelen);
mem->info.parameter_class = (MOJOSHADER_symbolClass) readui32(&typeptr, &typelen);
const uint32 memname = readui32(&typeptr, &typelen);
/*const uint32 memsemantic =*/ readui32(&typeptr, &typelen);
mem->name = readstring(base, memname, m, d);
mem->info.elements = readui32(&typeptr, &typelen);
mem->info.columns = readui32(&typeptr, &typelen);
mem->info.rows = readui32(&typeptr, &typelen);
// !!! FIXME: Nested structs! -flibit
assert(mem->info.parameter_class >= MOJOSHADER_SYMCLASS_SCALAR
&& mem->info.parameter_class <= MOJOSHADER_SYMCLASS_VECTOR);
assert(mem->info.parameter_type >= MOJOSHADER_SYMTYPE_BOOL
&& mem->info.parameter_type <= MOJOSHADER_SYMTYPE_FLOAT);
mem->info.member_count = 0;
mem->info.members = NULL;
uint32 memsize = mem->info.columns * mem->info.rows;
if (mem->info.elements > 0)
memsize *= mem->info.elements;
structsize += memsize;
} // for
value->type.columns = structsize;
value->type.rows = 1;
value->value_count = structsize;
if (numelements > 0)
value->value_count *= numelements;
siz = value->value_count * 4;
value->values = m(siz, d);
memcpy(value->values, typeptr, siz); /* Yes, typeptr. -flibit */
} // else if
} // readvalue
static void readannotations(const uint32 numannos,
const uint8 *base,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effectAnnotation **annotations,
MOJOSHADER_effectObject *objects,
MOJOSHADER_malloc m,
void *d)
{
int i;
if (numannos == 0) return;
const uint32 siz = sizeof(MOJOSHADER_effectAnnotation) * numannos;
*annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
memset(*annotations, '\0', siz);
for (i = 0; i < numannos; i++)
{
MOJOSHADER_effectAnnotation *anno = &(*annotations)[i];
const uint32 typeoffset = readui32(ptr, len);
const uint32 valoffset = readui32(ptr, len);
readvalue(base, typeoffset, valoffset,
anno, objects,
m, d);
} // for
} // readannotation
static void readparameters(const uint32 numparams,
const uint8 *base,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effectParam **params,
MOJOSHADER_effectObject *objects,
MOJOSHADER_malloc m,
void *d)
{
int i;
if (numparams == 0) return;
uint32 siz = sizeof(MOJOSHADER_effectParam) * numparams;
*params = (MOJOSHADER_effectParam *) m(siz, d);
memset(*params, '\0', siz);
for (i = 0; i < numparams; i++)
{
MOJOSHADER_effectParam *param = &(*params)[i];
const uint32 typeoffset = readui32(ptr, len);
const uint32 valoffset = readui32(ptr, len);
/*const uint32 flags =*/ readui32(ptr, len);
const uint32 numannos = readui32(ptr, len);
param->annotation_count = numannos;
readannotations(numannos, base, ptr, len,
¶m->annotations, objects,
m, d);
readvalue(base, typeoffset, valoffset,
¶m->value, objects,
m, d);
} // for
} // readparameters
static void readstates(const uint32 numstates,
const uint8 *base,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effectState **states,
MOJOSHADER_effectObject *objects,
MOJOSHADER_malloc m,
void *d)
{
int i;
if (numstates == 0) return;
const uint32 siz = sizeof (MOJOSHADER_effectState) * numstates;
*states = (MOJOSHADER_effectState *) m(siz, d);
memset(*states, '\0', siz);
for (i = 0; i < numstates; i++)
{
MOJOSHADER_effectState *state = &(*states)[i];
const uint32 type = readui32(ptr, len);
/*const uint32 FIXME =*/ readui32(ptr, len);
const uint32 typeoffset = readui32(ptr, len);
const uint32 valoffset = readui32(ptr, len);
state->type = (MOJOSHADER_renderStateType) type;
readvalue(base, typeoffset, valoffset,
&state->value, objects,
m, d);
} // for
} // readstates
static void readpasses(const uint32 numpasses,
const uint8 *base,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effectPass **passes,
MOJOSHADER_effectObject *objects,
MOJOSHADER_malloc m,
void *d)
{
int i;
if (numpasses == 0) return;
const uint32 siz = sizeof (MOJOSHADER_effectPass) * numpasses;
*passes = (MOJOSHADER_effectPass *) m(siz, d);
memset(*passes, '\0', siz);
for (i = 0; i < numpasses; i++)
{
MOJOSHADER_effectPass *pass = &(*passes)[i];
const uint32 passnameoffset = readui32(ptr, len);
const uint32 numannos = readui32(ptr, len);
const uint32 numstates = readui32(ptr, len);
pass->name = readstring(base, passnameoffset, m, d);
pass->annotation_count = numannos;
readannotations(numannos, base, ptr, len,
&pass->annotations, objects,
m, d);
pass->state_count = numstates;
readstates(numstates, base, ptr, len,
&pass->states, objects,
m, d);
} // for
} // readpasses
static void readtechniques(const uint32 numtechniques,
const uint8 *base,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effectTechnique **techniques,
MOJOSHADER_effectObject *objects,
MOJOSHADER_malloc m,
void *d)
{
int i;
if (numtechniques == 0) return;
const uint32 siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
*techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
memset(*techniques, '\0', siz);
for (i = 0; i < numtechniques; i++)
{
MOJOSHADER_effectTechnique *technique = &(*techniques)[i];
const uint32 nameoffset = readui32(ptr, len);
const uint32 numannos = readui32(ptr, len);
const uint32 numpasses = readui32(ptr, len);
technique->name = readstring(base, nameoffset, m, d);
technique->annotation_count = numannos;
readannotations(numannos, base, ptr, len,
&technique->annotations, objects,
m, d);
technique->pass_count = numpasses;
readpasses(numpasses, base, ptr, len,
&technique->passes, objects,
m, d);
} // for
} // readtechniques
static void readsmallobjects(const uint32 numsmallobjects,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effect *effect,
const char *profile,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
MOJOSHADER_malloc m,
MOJOSHADER_free f,
void *d)
{
int i, j;
if (numsmallobjects == 0) return;
for (i = 1; i < numsmallobjects + 1; i++)
{
const uint32 index = readui32(ptr, len);
const uint32 length = readui32(ptr, len);
MOJOSHADER_effectObject *object = &effect->objects[index];
if (object->type == MOJOSHADER_SYMTYPE_STRING)
{
if (length > 0)
{
char *str = (char *) m(length, d);
memcpy(str, *ptr, length);
object->string.string = str;
} // if
} // if
else if (object->type == MOJOSHADER_SYMTYPE_TEXTURE
|| object->type == MOJOSHADER_SYMTYPE_TEXTURE1D
|| object->type == MOJOSHADER_SYMTYPE_TEXTURE2D
|| object->type == MOJOSHADER_SYMTYPE_TEXTURE3D
|| object->type == MOJOSHADER_SYMTYPE_TEXTURECUBE)
{
// No-op. Why is this even here?
} // else if
else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
{
if (length > 0)
{
char *str = (char *) m(length, d);
memcpy(str, *ptr, length);
object->mapping.name = str;
} // if
} // else if
else if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
|| object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
{
object->shader.technique = -1;
object->shader.pass = -1;
object->shader.shader = MOJOSHADER_parse(profile, NULL, *ptr, length,
swiz, swizcount, smap, smapcount,
m, f, d);
// !!! FIXME: check for errors.
for (j = 0; j < object->shader.shader->symbol_count; j++)
if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
object->shader.sampler_count++;
object->shader.param_count = object->shader.shader->symbol_count;
object->shader.params = (uint32 *) m(object->shader.param_count * sizeof (uint32), d);
object->shader.samplers = (MOJOSHADER_samplerStateRegister *) m(object->shader.sampler_count * sizeof (MOJOSHADER_samplerStateRegister), d);
uint32 curSampler = 0;
for (j = 0; j < object->shader.shader->symbol_count; j++)
{
int par = findparameter(effect->params,
effect->param_count,
object->shader.shader->symbols[j].name);
object->shader.params[j] = par;
if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
{
object->shader.samplers[curSampler].sampler_name = object->shader.shader->symbols[j].name;
object->shader.samplers[curSampler].sampler_register = object->shader.shader->symbols[j].register_index;
object->shader.samplers[curSampler].sampler_state_count = effect->params[par].value.value_count;
object->shader.samplers[curSampler].sampler_states = effect->params[par].value.valuesSS;
curSampler++;
} // if
} // for
if (object->shader.shader->preshader)
{
object->shader.preshader_param_count = object->shader.shader->preshader->symbol_count;
object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
for (j = 0; j < object->shader.shader->preshader->symbol_count; j++)
{
object->shader.preshader_params[j] = findparameter(effect->params,
effect->param_count,
object->shader.shader->preshader->symbols[j].name);
} // for
} // if
} // else if
else
{
assert(0 && "Small object type unknown!");
} // else
/* Object block is always a multiple of four */
const uint32 blocklen = (length + 3) - ((length - 1) % 4);
*ptr += blocklen;
*len -= blocklen;
} // for
} // readstrings
static void readlargeobjects(const uint32 numlargeobjects,
const uint32 numsmallobjects,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effect *effect,
const char *profile,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
MOJOSHADER_malloc m,
MOJOSHADER_free f,
void *d)
{
int i, j;
if (numlargeobjects == 0) return;
int numobjects = numsmallobjects + numlargeobjects + 1;
for (i = numsmallobjects + 1; i < numobjects; i++)
{
const uint32 technique = readui32(ptr, len);
const uint32 index = readui32(ptr, len);
/*const uint32 FIXME =*/ readui32(ptr, len);
const uint32 state = readui32(ptr, len);
const uint32 type = readui32(ptr, len);
const uint32 length = readui32(ptr, len);
uint32 objectIndex;
if (technique == -1)
objectIndex = effect->params[index].value.valuesSS[state].value.valuesI[0];
else
objectIndex = effect->techniques[technique].passes[index].states[state].value.valuesI[0];
MOJOSHADER_effectObject *object = &effect->objects[objectIndex];
if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
|| object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
{
object->shader.technique = technique;
object->shader.pass = index;
const char *emitter = profile;
if (type == 2)
{
/* This is a standalone preshader!
* It exists solely for effect passes that do not use a single
* vertex/fragment shader.
*/
object->shader.is_preshader = 1;
const uint32 start = *((uint32 *) *ptr) + 4;
const uint32 end = 16; // FIXME: Why? -flibit
const char *array = readstring(*ptr, 0, m, d);
object->shader.param_count = 1;
object->shader.params = (uint32 *) m(sizeof (uint32), d);
object->shader.params[0] = findparameter(effect->params,
effect->param_count,
array);
f((void *) array, d);
object->shader.preshader = MOJOSHADER_parsePreshader(*ptr + start, length - end,
m, f, d);
// !!! FIXME: check for errors.
object->shader.preshader_param_count = object->shader.preshader->symbol_count;
object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
for (j = 0; j < object->shader.preshader->symbol_count; j++)
{
object->shader.preshader_params[j] = findparameter(effect->params,
effect->param_count,
object->shader.preshader->symbols[j].name);
} // for
} // if
else
{
object->shader.shader = MOJOSHADER_parse(emitter, NULL, *ptr, length,
swiz, swizcount, smap, smapcount,
m, f, d);
// !!! FIXME: check for errors.
for (j = 0; j < object->shader.shader->symbol_count; j++)
if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
object->shader.sampler_count++;
object->shader.param_count = object->shader.shader->symbol_count;
object->shader.params = (uint32 *) m(object->shader.param_count * sizeof (uint32), d);
object->shader.samplers = (MOJOSHADER_samplerStateRegister *) m(object->shader.sampler_count * sizeof (MOJOSHADER_samplerStateRegister), d);
uint32 curSampler = 0;
for (j = 0; j < object->shader.shader->symbol_count; j++)
{
int par = findparameter(effect->params,
effect->param_count,
object->shader.shader->symbols[j].name);
object->shader.params[j] = par;
if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
{
object->shader.samplers[curSampler].sampler_name = object->shader.shader->symbols[j].name;
object->shader.samplers[curSampler].sampler_register = object->shader.shader->symbols[j].register_index;
object->shader.samplers[curSampler].sampler_state_count = effect->params[par].value.value_count;
object->shader.samplers[curSampler].sampler_states = effect->params[par].value.valuesSS;
curSampler++;
} // if
} // for
if (object->shader.shader->preshader)
{
object->shader.preshader_param_count = object->shader.shader->preshader->symbol_count;
object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
for (j = 0; j < object->shader.shader->preshader->symbol_count; j++)
{
object->shader.preshader_params[j] = findparameter(effect->params,
effect->param_count,
object->shader.shader->preshader->symbols[j].name);
} // for
} // if
}
} // if
else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
{
if (length > 0)
{
char *str = (char *) m(length, d);
memcpy(str, *ptr, length);
object->mapping.name = str;
} // if
} // else if
else if (object->type != MOJOSHADER_SYMTYPE_VOID) // FIXME: Why? -flibit
{
assert(0 && "Large object type unknown!");
} // else
/* Object block is always a multiple of four */
const uint32 blocklen = (length + 3) - ((length - 1) % 4);
*ptr += blocklen;
*len -= blocklen;
} // for
} // readobjects
MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
const unsigned char *buf,
const unsigned int _len,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
MOJOSHADER_malloc m,
MOJOSHADER_free f,
void *d)
{
const uint8 *ptr = (const uint8 *) buf;
uint32 len = (uint32) _len;
/* Supply both m and f, or neither */
if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
return &MOJOSHADER_out_of_mem_effect;
/* Use default malloc/free if m/f were not passed */
if (m == NULL) m = MOJOSHADER_internal_malloc;
if (f == NULL) f = MOJOSHADER_internal_free;
/* malloc base effect structure */
MOJOSHADER_effect *retval = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect), d);
if (retval == NULL)
return &MOJOSHADER_out_of_mem_effect;
memset(retval, '\0', sizeof (*retval));
/* Store m/f/d in effect structure */
retval->malloc = m;
retval->free = f;
retval->malloc_data = d;
if (len < 8)
goto parseEffect_unexpectedEOF;
/* Read in header magic, seek to initial offset */
const uint8 *base = NULL;
uint32 header = readui32(&ptr, &len);
if (header == 0xBCF00BCF)
{
/* The Effect compiler provided with XNA4 adds some extra mess at the
* beginning of the file. It's useless though, so just skip it.
* -flibit
*/
const uint32 skip = readui32(&ptr, &len) - 8;
ptr += skip;
len += skip;
header = readui32(&ptr, &len);
} // if
if (header != 0xFEFF0901)
goto parseEffect_notAnEffectsFile;
else
{
const uint32 offset = readui32(&ptr, &len);
base = ptr;
if (offset > len)
goto parseEffect_unexpectedEOF;
ptr += offset;
len -= offset;
} // else
if (len < 16)
goto parseEffect_unexpectedEOF;
/* Parse structure counts */
const uint32 numparams = readui32(&ptr, &len);
const uint32 numtechniques = readui32(&ptr, &len);
/*const uint32 FIXME =*/ readui32(&ptr, &len);
const uint32 numobjects = readui32(&ptr, &len);
/* Alloc structures now, so object types can be stored */
retval->object_count = numobjects;
const uint32 siz = sizeof (MOJOSHADER_effectObject) * numobjects;
retval->objects = (MOJOSHADER_effectObject *) m(siz, d);
if (retval->objects == NULL)
goto parseEffect_outOfMemory;
memset(retval->objects, '\0', siz);
/* Parse effect parameters */
retval->param_count = numparams;
readparameters(numparams, base, &ptr, &len,
&retval->params, retval->objects,
m, d);
/* Parse effect techniques */
retval->technique_count = numtechniques;
readtechniques(numtechniques, base, &ptr, &len,
&retval->techniques, retval->objects,
m, d);
/* Initial effect technique/pass */
retval->current_technique = &retval->techniques[0];
retval->current_pass = -1;
if (len < 8)
goto parseEffect_unexpectedEOF;
/* Parse object counts */
const int numsmallobjects = readui32(&ptr, &len);
const int numlargeobjects = readui32(&ptr, &len);
/* Parse "small" object table */
readsmallobjects(numsmallobjects, &ptr, &len,
retval,
profile, swiz, swizcount, smap, smapcount,
m, f, d);
/* Parse "large" object table. */
readlargeobjects(numlargeobjects, numsmallobjects, &ptr, &len,
retval,
profile, swiz, swizcount, smap, smapcount,
m, f, d);
/* Store MojoShader profile in effect structure */
retval->profile = (char *) m(strlen(profile) + 1, d);
if (retval->profile == NULL)
goto parseEffect_outOfMemory;
strcpy((char *) retval->profile, profile);
return retval;
// !!! FIXME: do something with this.
parseEffect_notAnEffectsFile:
parseEffect_unexpectedEOF:
parseEffect_outOfMemory:
MOJOSHADER_freeEffect(retval);
return &MOJOSHADER_out_of_mem_effect;
} // MOJOSHADER_parseEffect
void freetypeinfo(MOJOSHADER_symbolTypeInfo *typeinfo,
MOJOSHADER_free f, void *d)
{
int i;
for (i = 0; i < typeinfo->member_count; i++)
{
f((void *) typeinfo->members[i].name, d);
freetypeinfo(&typeinfo->members[i].info, f, d);
} // for
f((void *) typeinfo->members, d);
} // freetypeinfo
void freevalue(MOJOSHADER_effectValue *value, MOJOSHADER_free f, void *d)
{
int i;
f((void *) value->name, d);
f((void *) value->semantic, d);
freetypeinfo(&value->type, f, d);
if (value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER
|| value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
for (i = 0; i < value->value_count; i++)
freevalue(&value->valuesSS[i].value, f, d);
f(value->values, d);
} // freevalue
void MOJOSHADER_freeEffect(const MOJOSHADER_effect *_effect)
{
MOJOSHADER_effect *effect = (MOJOSHADER_effect *) _effect;
if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
return; // no-op.
MOJOSHADER_free f = effect->free;
void *d = effect->malloc_data;
int i, j, k;
/* Free errors */
for (i = 0; i < effect->error_count; i++)
{
f((void *) effect->errors[i].error, d);
f((void *) effect->errors[i].filename, d);
} // for
f((void *) effect->errors, d);
/* Free profile string */
f((void *) effect->profile, d);
/* Free parameters, including annotations */
for (i = 0; i < effect->param_count; i++)
{
MOJOSHADER_effectParam *param = &effect->params[i];
freevalue(¶m->value, f, d);
for (j = 0; j < param->annotation_count; j++)
{
freevalue(¶m->annotations[j], f, d);
} // for
f((void *) param->annotations, d);
} // for
f((void *) effect->params, d);
/* Free techniques, including passes and all annotations */
for (i = 0; i < effect->technique_count; i++)
{
MOJOSHADER_effectTechnique *technique = &effect->techniques[i];
f((void *) technique->name, d);
for (j = 0; j < technique->pass_count; j++)
{
MOJOSHADER_effectPass *pass = &technique->passes[j];
f((void *) pass->name, d);
for (k = 0; k < pass->state_count; k++)
{
freevalue(&pass->states[k].value, f, d);
} // for
f((void *) pass->states, d);
for (k = 0; k < pass->annotation_count; k++)
{
freevalue(&pass->annotations[k], f, d);
} // for
f((void *) pass->annotations, d);
} // for
f((void *) technique->passes, d);
for (j = 0; j < technique->annotation_count; j++)
{
freevalue(&technique->annotations[j], f, d);
} // for
f((void *) technique->annotations, d);
} // for
f((void *) effect->techniques, d);
/* Free object table */
for (i = 0; i < effect->object_count; i++)
{
MOJOSHADER_effectObject *object = &effect->objects[i];
if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
|| object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
{
if (object->shader.is_preshader)
MOJOSHADER_freePreshader(object->shader.preshader);
else
MOJOSHADER_freeParseData(object->shader.shader);
f((void *) object->shader.params, d);
f((void *) object->shader.samplers, d);
f((void *) object->shader.preshader_params, d);
} // if
else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
f((void *) object->mapping.name, d);
else if (object->type == MOJOSHADER_SYMTYPE_STRING)
f((void *) object->string.string, d);
} // for
f((void *) effect->objects, d);
/* Free base effect structure */
f((void *) effect, d);
} // MOJOSHADER_freeEffect
// !!! FIXME: Out of memory check!
#define COPY_STRING(location) \
if (src->location != NULL) \
{ \
siz = strlen(src->location) + 1; \
stringcopy = (char *) m(siz, d); \
strcpy(stringcopy, src->location); \
dst->location = stringcopy; \
} // if
void copysymboltypeinfo(MOJOSHADER_symbolTypeInfo *dst,
MOJOSHADER_symbolTypeInfo *src,
MOJOSHADER_malloc m,
void *d)
{
int i;
uint32 siz = 0;
char *stringcopy = NULL;
memcpy(dst, src, sizeof (MOJOSHADER_symbolTypeInfo));
if (dst->member_count > 0)
{
siz = dst->member_count * sizeof (MOJOSHADER_symbolStructMember);
dst->members = (MOJOSHADER_symbolStructMember *) m(siz, d);
for (i = 0; i < dst->member_count; i++)
{
COPY_STRING(members[i].name)
copysymboltypeinfo(&dst->members[i].info, &src->members[i].info, m, d);
} // for
} // if
} // copysymboltypeinfo
void copyvalue(MOJOSHADER_effectValue *dst,
MOJOSHADER_effectValue *src,
MOJOSHADER_malloc m,
void *d)
{
int i;
uint32 siz = 0;
char *stringcopy = NULL;
COPY_STRING(name)
COPY_STRING(semantic)
copysymboltypeinfo(&dst->type, &src->type, m, d);
dst->value_count = src->value_count;
if (dst->type.parameter_class == MOJOSHADER_SYMCLASS_SCALAR
|| dst->type.parameter_class == MOJOSHADER_SYMCLASS_VECTOR
|| dst->type.parameter_class == MOJOSHADER_SYMCLASS_MATRIX_ROWS
|| dst->type.parameter_class == MOJOSHADER_SYMCLASS_MATRIX_COLUMNS
|| dst->type.parameter_class == MOJOSHADER_SYMCLASS_STRUCT)
{
siz = dst->value_count * 4;
dst->values = m(siz, d);
// !!! FIXME: Out of memory check!
memcpy(dst->values, src->values, siz);
} // if
else if (dst->type.parameter_class == MOJOSHADER_SYMCLASS_OBJECT)
{
if (dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER
|| dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
{
siz = dst->value_count * sizeof (MOJOSHADER_effectSamplerState);
dst->values = m(siz, d);
// !!! FIXME: Out of memory check!
memset(dst->values, '\0', siz);
for (i = 0; i < dst->value_count; i++)
{
dst->valuesSS[i].type = src->valuesSS[i].type;
copyvalue(&dst->valuesSS[i].value,
&src->valuesSS[i].value,
m, d);
} // for
} // if
else
{
siz = dst->value_count * 4;
dst->values = m(siz, d);
// !!! FIXME: Out of memory check!
memcpy(dst->values, src->values, siz);
} // else
} // else if
} // copyvalue
#undef COPY_STRING
void copysymbolinfo(MOJOSHADER_symbolTypeInfo *dst,
MOJOSHADER_symbolTypeInfo *src,
MOJOSHADER_malloc m,
void *d)
{
int i;
uint32 siz;
char *stringcopy;
dst->parameter_class = src->parameter_class;
dst->parameter_type = src->parameter_type;
dst->rows = src->rows;
dst->columns = src->columns;
dst->elements = src->elements;
dst->member_count = src->member_count;
if (dst->member_count > 0)
{
siz = sizeof (MOJOSHADER_symbolStructMember) * dst->member_count;
dst->members = (MOJOSHADER_symbolStructMember *) m(siz, d);
// !!! FIXME: Out of memory check!
for (i = 0; i < dst->member_count; i++)
{
if (src->members[i].name != NULL)
{
siz = strlen(src->members[i].name) + 1;
stringcopy = (char *) m(siz, d);
strcpy(stringcopy, src->members[i].name);
dst->members[i].name = stringcopy;
} // if
copysymbolinfo(&dst->members[i].info, &src->members[i].info, m, d);
} // for
} // if
} // copysymbolinfo
void copysymbol(MOJOSHADER_symbol *dst,
MOJOSHADER_symbol *src,
MOJOSHADER_malloc m,
void *d)
{
uint32 siz = strlen(src->name) + 1;
char *stringcopy = (char *) m(siz, d);
// !!! FIXME: Out of memory check!
strcpy(stringcopy, src->name);
dst->name = stringcopy;
dst->register_set = src->register_set;
dst->register_index = src->register_index;
dst->register_count = src->register_count;
copysymbolinfo(&dst->info, &src->info, m, d);
} // copysymbol
MOJOSHADER_preshader *copypreshader(const MOJOSHADER_preshader *src,
MOJOSHADER_malloc m,
void *d)
{
int i, j;
uint32 siz;
MOJOSHADER_preshader *retval;
retval = (MOJOSHADER_preshader *) m(sizeof (MOJOSHADER_preshader), d);
// !!! FIXME: Out of memory check!
memset(retval, '\0', sizeof (MOJOSHADER_preshader));
siz = sizeof (double) * src->literal_count;
retval->literal_count = src->literal_count;
retval->literals = (double *) m(siz, d);
// !!! FIXME: Out of memory check!
memcpy(retval->literals, src->literals, siz);
retval->temp_count = src->temp_count;
siz = sizeof (MOJOSHADER_symbol) * src->symbol_count;
retval->symbol_count = src->symbol_count;
retval->symbols = (MOJOSHADER_symbol *) m(siz, d);
// !!! FIXME: Out of memory check!
memset(retval->symbols, '\0', siz);
for (i = 0; i < retval->symbol_count; i++)
copysymbol(&retval->symbols[i], &src->symbols[i], m, d);
siz = sizeof (MOJOSHADER_preshaderInstruction) * src->instruction_count;
retval->instruction_count = src->instruction_count;
retval->instructions = (MOJOSHADER_preshaderInstruction *) m(siz, d);
// !!! FIXME: Out of memory check!
memcpy(retval->instructions, src->instructions, siz);
for (i = 0; i < retval->instruction_count; i++)
for (j = 0; j < retval->instructions[i].operand_count; j++)
{
siz = sizeof (unsigned int) * retval->instructions[i].operands[j].array_register_count;
retval->instructions[i].operands[j].array_registers = (unsigned int *) m(siz, d);
// !!! FIXME: Out of memory check!
memcpy(retval->instructions[i].operands[j].array_registers,
src->instructions[i].operands[j].array_registers,
siz);
} // for
siz = sizeof (float) * 4 * src->register_count;
retval->register_count = src->register_count;
retval->registers = (float *) m(siz, d);
// !!! FIXME: Out of memory check!
memcpy(retval->registers, src->registers, siz);
return retval;
} // copypreshader
MOJOSHADER_parseData *copyparsedata(const MOJOSHADER_parseData *src,
MOJOSHADER_malloc m,
void *d)
{
int i;
uint32 siz;
char *stringcopy;
MOJOSHADER_parseData *retval;
retval = (MOJOSHADER_parseData *) m(sizeof (MOJOSHADER_parseData), d);
memset(retval, '\0', sizeof (MOJOSHADER_parseData));
/* Copy malloc/free */
retval->malloc = src->malloc;
retval->free = src->free;
retval->malloc_data = src->malloc_data;
// !!! FIXME: Out of memory check!
#define COPY_STRING(location) \
siz = strlen(src->location) + 1; \
stringcopy = (char *) m(siz, d); \
strcpy(stringcopy, src->location); \
retval->location = stringcopy; \
/* Copy errors */
siz = sizeof (MOJOSHADER_error) * src->error_count;
retval->error_count = src->error_count;
retval->errors = (MOJOSHADER_error *) m(siz, d);
// !!! FIXME: Out of memory check!
memset(retval->errors, '\0', siz);
for (i = 0; i < retval->error_count; i++)
{
COPY_STRING(errors[i].error)
COPY_STRING(errors[i].filename)
retval->errors[i].error_position = src->errors[i].error_position;
} // for
/* Copy profile string constant */
retval->profile = src->profile;
/* Copy shader output */
retval->output_len = src->output_len;
stringcopy = (char *) m(src->output_len, d);
memcpy(stringcopy, src->output, src->output_len);
retval->output = stringcopy;
/* Copy miscellaneous shader info */
retval->instruction_count = src->instruction_count;
retval->shader_type = src->shader_type;
retval->major_ver = src->major_ver;
retval->minor_ver = src->minor_ver;
/* Copy uniforms */
siz = sizeof (MOJOSHADER_uniform) * src->uniform_count;
retval->uniform_count = src->uniform_count;
retval->uniforms = (MOJOSHADER_uniform *) m(siz, d);
// !!! FIXME: Out of memory check!
memset(retval->uniforms, '\0', siz);
for (i = 0; i < retval->uniform_count; i++)
{
retval->uniforms[i].type = src->uniforms[i].type;
retval->uniforms[i].index = src->uniforms[i].index;
retval->uniforms[i].array_count = src->uniforms[i].array_count;
retval->uniforms[i].constant = src->uniforms[i].constant;
COPY_STRING(uniforms[i].name)
} // for
/* Copy constants */
siz = sizeof (MOJOSHADER_constant) * src->constant_count;
retval->constant_count = src->constant_count;
retval->constants = (MOJOSHADER_constant *) m(siz, d);
// !!! FIXME: Out of memory check!
memcpy(retval->constants, src->constants, siz);
/* Copy samplers */
siz = sizeof (MOJOSHADER_sampler) * src->sampler_count;
retval->sampler_count = src->sampler_count;
retval->samplers = (MOJOSHADER_sampler *) m(siz, d);
// !!! FIXME: Out of memory check!
memset(retval->samplers, '\0', siz);
for (i = 0; i < retval->sampler_count; i++)
{
retval->samplers[i].type = src->samplers[i].type;
retval->samplers[i].index = src->samplers[i].index;
COPY_STRING(samplers[i].name)
retval->samplers[i].texbem = src->samplers[i].texbem;
} // for
/* Copy attributes */
siz = sizeof (MOJOSHADER_attribute) * src->attribute_count;
retval->attribute_count = src->attribute_count;
retval->attributes = (MOJOSHADER_attribute *) m(siz, d);
// !!! FIXME: Out of memory check!
memset(retval->attributes, '\0', siz);
for (i = 0; i < retval->attribute_count; i++)
{
retval->attributes[i].usage = src->attributes[i].usage;
retval->attributes[i].index = src->attributes[i].index;
COPY_STRING(attributes[i].name)
} // for
/* Copy outputs */
siz = sizeof (MOJOSHADER_attribute) * src->output_count;
retval->output_count = src->output_count;
retval->outputs = (MOJOSHADER_attribute *) m(siz, d);
// !!! FIXME: Out of memory check!
memset(retval->outputs, '\0', siz);
for (i = 0; i < retval->output_count; i++)
{
retval->outputs[i].usage = src->outputs[i].usage;
retval->outputs[i].index = src->outputs[i].index;
COPY_STRING(outputs[i].name)
} // for
#undef COPY_STRING
/* Copy swizzles */
siz = sizeof (MOJOSHADER_swizzle) * src->swizzle_count;
retval->swizzle_count = src->swizzle_count;
retval->swizzles = (MOJOSHADER_swizzle *) m(siz, d);
// !!! FIXME: Out of memory check!
memcpy(retval->swizzles, src->swizzles, siz);
/* Copy symbols */
siz = sizeof (MOJOSHADER_symbol) * src->symbol_count;
retval->symbol_count = src->symbol_count;
retval->symbols = (MOJOSHADER_symbol *) m(siz, d);
// !!! FIXME: Out of memory check!
memset(retval->symbols, '\0', siz);
for (i = 0; i < retval->symbol_count; i++)
copysymbol(&retval->symbols[i], &src->symbols[i], m, d);
/* Copy preshader */
if (src->preshader != NULL)
retval->preshader = copypreshader(src->preshader, m, d);
return retval;
} // copyparsedata
MOJOSHADER_effect *MOJOSHADER_cloneEffect(const MOJOSHADER_effect *effect)
{
int i, j, k;
MOJOSHADER_effect *clone;
MOJOSHADER_malloc m = effect->malloc;
void *d = effect->malloc_data;
uint32 siz = 0;
char *stringcopy = NULL;
uint32 curSampler;
if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
return NULL; // no-op.
clone = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect), d);
if (clone == NULL)
return NULL; // Maybe out_of_mem_effect instead?
memset(clone, '\0', sizeof (MOJOSHADER_effect));
/* Copy malloc/free */
clone->malloc = effect->malloc;
clone->free = effect->free;
clone->malloc_data = effect->malloc_data;
#define COPY_STRING(location) \
siz = strlen(effect->location) + 1; \
stringcopy = (char *) m(siz, d); \
if (stringcopy == NULL) \
goto cloneEffect_outOfMemory; \
strcpy(stringcopy, effect->location); \
clone->location = stringcopy; \
/* Copy errors */
siz = sizeof (MOJOSHADER_error) * effect->error_count;
clone->error_count = effect->error_count;
clone->errors = (MOJOSHADER_error *) m(siz, d);
if (clone->errors == NULL)
goto cloneEffect_outOfMemory;
memset(clone->errors, '\0', siz);
for (i = 0; i < clone->error_count; i++)
{
COPY_STRING(errors[i].error)
COPY_STRING(errors[i].filename)
clone->errors[i].error_position = effect->errors[i].error_position;
} // for
/* Copy profile string */
COPY_STRING(profile)
/* Copy parameters */
siz = sizeof (MOJOSHADER_effectParam) * effect->param_count;
clone->param_count = effect->param_count;
clone->params = (MOJOSHADER_effectParam *) m(siz, d);
if (clone->params == NULL)
goto cloneEffect_outOfMemory;
memset(clone->params, '\0', siz);
for (i = 0; i < clone->param_count; i++)
{
copyvalue(&clone->params[i].value, &effect->params[i].value, m, d);
/* Copy parameter annotations */
siz = sizeof (MOJOSHADER_effectAnnotation) * effect->params[i].annotation_count;
clone->params[i].annotation_count = effect->params[i].annotation_count;
clone->params[i].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
if (clone->params[i].annotations == NULL)
goto cloneEffect_outOfMemory;
memset(clone->params[i].annotations, '\0', siz);
for (j = 0; j < clone->params[i].annotation_count; j++)
copyvalue(&clone->params[i].annotations[j],
&effect->params[i].annotations[j],
m, d);
} // for
/* Copy techniques */
siz = sizeof (MOJOSHADER_effectTechnique) * effect->technique_count;
clone->technique_count = effect->technique_count;
clone->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
if (clone->techniques == NULL)
goto cloneEffect_outOfMemory;
memset(clone->techniques, '\0', siz);
for (i = 0; i < clone->technique_count; i++)
{
COPY_STRING(techniques[i].name)
/* Copy passes */
siz = sizeof (MOJOSHADER_effectPass) * effect->techniques[i].pass_count;
clone->techniques[i].pass_count = effect->techniques[i].pass_count;
clone->techniques[i].passes = (MOJOSHADER_effectPass *) m(siz, d);
if (clone->techniques[i].passes == NULL)
goto cloneEffect_outOfMemory;
memset(clone->techniques[i].passes, '\0', siz);
for (j = 0; j < clone->techniques[i].pass_count; j++)
{
COPY_STRING(techniques[i].passes[j].name)
/* Copy pass states */
siz = sizeof (MOJOSHADER_effectState) * effect->techniques[i].passes[j].state_count;
clone->techniques[i].passes[j].state_count = effect->techniques[i].passes[j].state_count;
clone->techniques[i].passes[j].states = (MOJOSHADER_effectState *) m(siz, d);
if (clone->techniques[i].passes[j].states == NULL)
goto cloneEffect_outOfMemory;
memset(clone->techniques[i].passes[j].states, '\0', siz);
for (k = 0; k < clone->techniques[i].passes[j].state_count; k++)
{
clone->techniques[i].passes[j].states[k].type = effect->techniques[i].passes[j].states[k].type;
copyvalue(&clone->techniques[i].passes[j].states[k].value,
&effect->techniques[i].passes[j].states[k].value,
m, d);
} // for
/* Copy pass annotations */
siz = sizeof (MOJOSHADER_effectAnnotation) * effect->techniques[i].passes[j].annotation_count;
clone->techniques[i].passes[j].annotation_count = effect->techniques[i].passes[j].annotation_count;
clone->techniques[i].passes[j].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
if (clone->techniques[i].passes[j].annotations == NULL)
goto cloneEffect_outOfMemory;
memset(clone->techniques[i].passes[j].annotations, '\0', siz);
for (k = 0; k < clone->techniques[i].passes[j].annotation_count; k++)
copyvalue(&clone->techniques[i].passes[j].annotations[k],
&effect->techniques[i].passes[j].annotations[k],
m, d);
} // for
/* Copy technique annotations */
siz = sizeof (MOJOSHADER_effectAnnotation) * effect->techniques[i].annotation_count;
clone->techniques[i].annotation_count = effect->techniques[i].annotation_count;
clone->techniques[i].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
if (clone->techniques[i].annotations == NULL)
goto cloneEffect_outOfMemory;
memset(clone->techniques[i].annotations, '\0', siz);
for (j = 0; j < clone->techniques[i].annotation_count; j++)
copyvalue(&clone->techniques[i].annotations[j],
&effect->techniques[i].annotations[j],
m, d);
} // for
/* Copy the current technique/pass */
for (i = 0; i < effect->technique_count; i++)
if (&effect->techniques[i] == effect->current_technique)
{
clone->current_technique = &clone->techniques[i];
break;
} // if
assert(clone->current_technique != NULL);
clone->current_pass = effect->current_pass;
assert(clone->current_pass == -1);
/* Copy object table */
siz = sizeof (MOJOSHADER_effectObject) * effect->object_count;
clone->object_count = effect->object_count;
clone->objects = (MOJOSHADER_effectObject *) m(siz, d);
if (clone->objects == NULL)
goto cloneEffect_outOfMemory;
memset(clone->objects, '\0', siz);
for (i = 0; i < clone->object_count; i++)
{
clone->objects[i].type = effect->objects[i].type;
if (clone->objects[i].type == MOJOSHADER_SYMTYPE_PIXELSHADER
|| clone->objects[i].type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
{
clone->objects[i].shader.technique = effect->objects[i].shader.technique;
clone->objects[i].shader.pass = effect->objects[i].shader.pass;
clone->objects[i].shader.is_preshader = effect->objects[i].shader.is_preshader;
siz = sizeof (uint32) * effect->objects[i].shader.preshader_param_count;
clone->objects[i].shader.preshader_param_count = effect->objects[i].shader.preshader_param_count;
clone->objects[i].shader.preshader_params = (uint32 *) m(siz, d);
memcpy(clone->objects[i].shader.preshader_params,
effect->objects[i].shader.preshader_params,
siz);
siz = sizeof (uint32) * effect->objects[i].shader.param_count;
clone->objects[i].shader.param_count = effect->objects[i].shader.param_count;
clone->objects[i].shader.params = (uint32 *) m(siz, d);
memcpy(clone->objects[i].shader.params,
effect->objects[i].shader.params,
siz);
if (clone->objects[i].shader.is_preshader)
{
clone->objects[i].shader.preshader = copypreshader(effect->objects[i].shader.preshader,
m, d);
continue;
} // if
clone->objects[i].shader.shader = copyparsedata(effect->objects[i].shader.shader,
m, d);
siz = sizeof (MOJOSHADER_samplerStateRegister) * effect->objects[i].shader.sampler_count;
clone->objects[i].shader.sampler_count = effect->objects[i].shader.sampler_count;
clone->objects[i].shader.samplers = (MOJOSHADER_samplerStateRegister *) m(siz, d);
if (clone->objects[i].shader.samplers == NULL)
goto cloneEffect_outOfMemory;
curSampler = 0;
for (j = 0; j < clone->objects[i].shader.shader->symbol_count; j++)
if (clone->objects[i].shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
{
clone->objects[i].shader.samplers[curSampler].sampler_name = clone->objects[i].shader.shader->symbols[j].name;
clone->objects[i].shader.samplers[curSampler].sampler_register = clone->objects[i].shader.shader->symbols[j].register_index;
clone->objects[i].shader.samplers[curSampler].sampler_state_count = clone->params[clone->objects[i].shader.params[j]].value.value_count;
clone->objects[i].shader.samplers[curSampler].sampler_states = clone->params[clone->objects[i].shader.params[j]].value.valuesSS;
curSampler++;
} // if
} // if
else if (clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER
|| clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
{
COPY_STRING(objects[i].mapping.name)
} // else if
else if (clone->objects[i].type == MOJOSHADER_SYMTYPE_STRING)
{
COPY_STRING(objects[i].string.string)
} // else if
} // for
#undef COPY_STRING
return clone;
cloneEffect_outOfMemory:
MOJOSHADER_freeEffect(clone);
return NULL;
} // MOJOSHADER_cloneEffect
void MOJOSHADER_effectSetRawValueHandle(const MOJOSHADER_effectParam *parameter,
const void *data,
const unsigned int offset,
const unsigned int len)
{
// !!! FIXME: uint32* case is arbitary, for Win32 -flibit
memcpy((uint32 *) parameter->value.values + offset, data, len);
} // MOJOSHADER_effectSetRawValueHandle
void MOJOSHADER_effectSetRawValueName(const MOJOSHADER_effect *effect,
const char *name,
const void *data,
const unsigned int offset,
const unsigned int len)
{
int i;
for (i = 0; i < effect->param_count; i++)
{
if (strcmp(name, effect->params[i].value.name) == 0)
{
// !!! FIXME: uint32* case is arbitary, for Win32 -flibit
memcpy((uint32 *) effect->params[i].value.values + offset, data, len);
return;
} // if
} // for
assert(0 && "Effect parameter not found!");
} // MOJOSHADER_effectSetRawValueName
const MOJOSHADER_effectTechnique *MOJOSHADER_effectGetCurrentTechnique(const MOJOSHADER_effect *effect)
{
return effect->current_technique;
} // MOJOSHADER_effectGetCurrentTechnique
void MOJOSHADER_effectSetTechnique(MOJOSHADER_effect *effect,
const MOJOSHADER_effectTechnique *technique)
{
int i;
for (i = 0; i < effect->technique_count; i++)
{
if (technique == &effect->techniques[i])
{
effect->current_technique = technique;
return;
} // if
} // for
assert(0 && "Technique is not part of this effect!");
} // MOJOSHADER_effectSetTechnique
const MOJOSHADER_effectTechnique *MOJOSHADER_effectFindNextValidTechnique(const MOJOSHADER_effect *effect,
const MOJOSHADER_effectTechnique *technique
)
{
int i;
if (technique == NULL)
return &effect->techniques[0];
for (i = 0; i < effect->technique_count; i++)
{
if (technique == &effect->techniques[i])
{
if (i == effect->technique_count - 1)
return NULL; /* We were passed the last technique! */
return &effect->techniques[i + 1];
} // if
} // for
assert(0 && "Technique is not part of this effect!");
} // MOJOSHADER_effectFindNextValidTechnique
#endif // MOJOSHADER_EFFECT_SUPPORT
// end of mojoshader_effects.c ...