--- a/mojoshader_effects.c Tue Oct 13 12:08:55 2015 -0400
+++ b/mojoshader_effects.c Fri Jan 01 02:12:19 2016 -0500
@@ -10,12 +10,15 @@
#define __MOJOSHADER_INTERNAL__ 1
#include "mojoshader_internal.h"
+#ifdef MOJOSHADER_EFFECT_SUPPORT
+
#include <math.h>
-#if SUPPORT_PRESHADERS
void MOJOSHADER_runPreshader(const MOJOSHADER_preshader *preshader,
- const float *inregs, float *outregs)
+ 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;
@@ -56,21 +59,32 @@
{
case MOJOSHADER_PRESHADEROPERAND_LITERAL:
{
- const double *lit = &preshader->literals[index];
- assert((index + elems) <= preshader->literal_count);
if (!isscalar)
- memcpy(&src[opiter][0], lit, elemsbytes);
+ {
+ assert((index + elems) <= preshader->literal_count);
+ memcpy(&src[opiter][0], &preshader->literals[index], elemsbytes);
+ } // if
else
{
- const double val = *lit;
for (elemiter = 0; elemiter < elems; elemiter++)
- src[opiter][elemiter] = val;
+ src[opiter][elemiter] = preshader->literals[index];
} // else
break;
} // case
case MOJOSHADER_PRESHADEROPERAND_INPUT:
- if (isscalar)
+ 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
{
@@ -159,6 +173,7 @@
final += src0[i] * src1[i];
for (i = 0; i < elems; i++)
dst[i] = final; // !!! FIXME: is this right?
+ break;
} // case
default:
@@ -181,7 +196,6 @@
} // else
} // for
} // MOJOSHADER_runPreshader
-#endif
static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -202,357 +216,671 @@
return retval;
} // readui32
-// !!! FIXME: this is sort of a big, ugly function.
-const 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)
+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->value_type = (MOJOSHADER_symbolType) type;
+ value->value_class = (MOJOSHADER_symbolClass) valclass;
+ value->name = readstring(base, name, m, d);
+ value->semantic = readstring(base, semantic, m, d);
+ value->element_count = 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->column_count = columncount;
+ value->row_count = 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)
+ {
+ /* TODO: Maybe this is like parse_ctab_typeinfo? -flibit */
+ assert(0 && "Effect struct value parsing not implemented!");
+ } // 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, *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 = 24; // 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, *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; // supply both or neither.
+ 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;
- MOJOSHADER_effect *retval = m(sizeof (MOJOSHADER_effect), d);
+ /* malloc base effect structure */
+ MOJOSHADER_effect *retval = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect), d);
if (retval == NULL)
- return &MOJOSHADER_out_of_mem_effect; // supply both or neither.
+ 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;
- const uint8 *ptr = (const uint8 *) buf;
- uint32 len = (uint32) _len;
- size_t siz = 0;
- int i, j, k;
-
if (len < 8)
goto parseEffect_unexpectedEOF;
+ /* Read in header magic, seek to initial offset */
const uint8 *base = NULL;
- if (readui32(&ptr, &len) != 0xFEFF0901) // !!! FIXME: is this always magic?
+ 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;
-//printf("base offset == %u\n", offset);
if (offset > len)
goto parseEffect_unexpectedEOF;
ptr += offset;
len -= offset;
} // else
- // params...
-
if (len < 16)
goto parseEffect_unexpectedEOF;
+ /* Parse structure counts */
const uint32 numparams = readui32(&ptr, &len);
const uint32 numtechniques = readui32(&ptr, &len);
-
- readui32(&ptr, &len); // !!! FIXME: there are 8 unknown bytes here. Annotations?
- /*const uint32 numobjects = */ readui32(&ptr, &len);
-
- if (numparams > 0)
- {
- siz = sizeof (MOJOSHADER_effectParam) * numparams;
- retval->params = (MOJOSHADER_effectParam *) m(siz, d);
- if (retval->params == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->params, '\0', siz);
-
- retval->param_count = numparams;
-
- for (i = 0; i < numparams; i++)
- {
- if (len < 16)
- goto parseEffect_unexpectedEOF;
-
- const uint32 typeoffset = readui32(&ptr, &len);
- /*const uint32 valoffset =*/ readui32(&ptr, &len);
- /*const uint32 flags =*/ readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- for (j = 0; j < numannos; j++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- // !!! FIXME: parse annotations.
- readui32(&ptr, &len);
- readui32(&ptr, &len);
- } // for
-
- const uint8 *typeptr = base + typeoffset;
- unsigned int typelen = 9999999; // !!! FIXME
- /*const uint32 paramtype =*/ readui32(&typeptr, &typelen);
- /*const uint32 paramclass =*/ readui32(&typeptr, &typelen);
- const uint32 paramname = readui32(&typeptr, &typelen);
- const uint32 paramsemantic = readui32(&typeptr, &typelen);
+ /*const uint32 FIXME =*/ readui32(&ptr, &len);
+ const uint32 numobjects = readui32(&ptr, &len);
- // !!! FIXME: sanity checks!
- const char *namestr = ((const char *) base) + paramname;
- const char *semstr = ((const char *) base) + paramsemantic;
- uint32 len;
- char *strptr;
- len = *((const uint32 *) namestr);
- strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- retval->params[i].name = strptr;
- len = *((const uint32 *) semstr);
- strptr = (char *) m(len + 1, d);
- memcpy(strptr, semstr + 4, len);
- strptr[len] = '\0';
- retval->params[i].semantic = strptr;
- } // for
- } // if
-
- uint32 numshaders = 0; // we'll calculate this later.
-
- // techniques...
-
- if (numtechniques > 0)
- {
- siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
- retval->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
- if (retval->techniques == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->techniques, '\0', siz);
-
- retval->technique_count = numtechniques;
-
- for (i = 0; i < numtechniques; i++)
- {
- if (len < 12)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectTechnique *technique = &retval->techniques[i];
-
- const uint32 nameoffset = readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- const uint32 numpasses = readui32(&ptr, &len);
-
- if (nameoffset >= _len)
- goto parseEffect_unexpectedEOF;
+ /* 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);
- if (numannos > 0)
- {
- // !!! FIXME: expose these to the caller?
- for (j = 0; j < numannos; j++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- readui32(&ptr, &len); // typedef offset
- readui32(&ptr, &len); // value offset
- } // for
- } // if
-
- // !!! FIXME: verify this doesn't go past EOF looking for a null.
- {
- const char *namestr = ((char *) base) + nameoffset;
- uint32 len = *((const uint32 *) namestr);
- char *strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- technique->name = strptr;
- }
-
- if (numpasses > 0)
- {
- technique->pass_count = numpasses;
-
- siz = sizeof (MOJOSHADER_effectPass) * numpasses;
- technique->passes = (MOJOSHADER_effectPass *) m(siz, d);
- if (technique->passes == NULL)
- goto parseEffect_outOfMemory;
- memset(technique->passes, '\0', siz);
-
- for (j = 0; j < numpasses; j++)
- {
- if (len < 12)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectPass *pass = &technique->passes[j];
-
- const uint32 passnameoffset = readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- const uint32 numstates = readui32(&ptr, &len);
-
- if (passnameoffset >= _len)
- goto parseEffect_unexpectedEOF;
+ /* Parse effect parameters */
+ retval->param_count = numparams;
+ readparameters(numparams, base, &ptr, &len,
+ &retval->params, retval->objects,
+ m, d);
- // !!! FIXME: verify this doesn't go past EOF looking for a null.
- {
- const char *namestr = ((char *) base) + passnameoffset;
- uint32 len = *((const uint32 *) namestr);
- char *strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- pass->name = strptr;
- }
-
- if (numannos > 0)
- {
- for (k = 0; k < numannos; k++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- // !!! FIXME: do something with this.
- readui32(&ptr, &len);
- readui32(&ptr, &len);
- } // for
- } // if
-
- if (numstates > 0)
- {
- pass->state_count = numstates;
+ /* Parse effect techniques */
+ retval->technique_count = numtechniques;
+ readtechniques(numtechniques, base, &ptr, &len,
+ &retval->techniques, retval->objects,
+ m, d);
- siz = sizeof (MOJOSHADER_effectState) * numstates;
- pass->states = (MOJOSHADER_effectState *) m(siz, d);
- if (pass->states == NULL)
- goto parseEffect_outOfMemory;
- memset(pass->states, '\0', siz);
-
- for (k = 0; k < numstates; k++)
- {
- if (len < 16)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectState *state = &pass->states[k];
- const uint32 type = readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: don't know what this field does.
- /*const uint32 offsetend = */ readui32(&ptr, &len);
- /*const uint32 offsetstart = */ readui32(&ptr, &len);
- state->type = type;
-
- if ((type == 0x92) || (type == 0x93))
- numshaders++;
- } // for
- } // if
- } // for
- } // if
- } // for
- } // if
-
- // textures...
+ /* Initial effect technique/pass */
+ retval->current_technique = &retval->techniques[0];
+ retval->current_pass = -1;
if (len < 8)
goto parseEffect_unexpectedEOF;
- const int numtextures = readui32(&ptr, &len);
- const int numobjects = readui32(&ptr, &len); // !!! FIXME: "objects" for lack of a better word.
-
- if (numtextures > 0)
- {
- siz = sizeof (MOJOSHADER_effectTexture) * numtextures;
- retval->textures = m(siz, d);
- if (retval->textures == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->textures, '\0', siz);
-
- for (i = 0; i < numtextures; i++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectTexture *texture = &retval->textures[i];
- const uint32 texparam = readui32(&ptr, &len);
- const uint32 texsize = readui32(&ptr, &len);
- // apparently texsize will pad out to 32 bits.
- const uint32 readsize = (((texsize + 3) / 4) * 4);
- if (len < readsize)
- goto parseEffect_unexpectedEOF;
-
- texture->param = texparam;
- char *str = m(texsize + 1, d);
- if (str == NULL)
- goto parseEffect_outOfMemory;
- memcpy(str, ptr, texsize);
- str[texsize] = '\0';
- texture->name = str;
-
- ptr += readsize;
- len -= readsize;
- } // for
- } // if
-
- // shaders...
-
- if (numshaders > 0)
- {
- siz = sizeof (MOJOSHADER_effectShader) * numshaders;
- retval->shaders = (MOJOSHADER_effectShader *) m(siz, d);
- if (retval->shaders == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->shaders, '\0', siz);
-
- retval->shader_count = numshaders;
+ /* Parse object counts */
+ const int numsmallobjects = readui32(&ptr, &len);
+ const int numlargeobjects = readui32(&ptr, &len);
- // !!! FIXME: I wonder if we should pull these from offsets and not
- // !!! FIXME: count on them all being in a line like this.
- for (i = 0; i < numshaders; i++)
- {
- if (len < 24)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectShader *shader = &retval->shaders[i];
- const uint32 technique = readui32(&ptr, &len);
- const uint32 pass = readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: don't know what this does.
- readui32(&ptr, &len); // !!! FIXME: don't know what this does (vertex/pixel/geometry?)
- readui32(&ptr, &len); // !!! FIXME: don't know what this does.
- const uint32 shadersize = readui32(&ptr, &len);
-
- if (len < shadersize)
- goto parseEffect_unexpectedEOF;
-
- shader->technique = technique;
- shader->pass = pass;
- shader->shader = MOJOSHADER_parse(profile, ptr, shadersize,
- swiz, swizcount, smap, smapcount,
- m, f, d);
-
- // !!! FIXME: check for errors.
+ /* Parse "small" object table */
+ readsmallobjects(numsmallobjects, &ptr, &len,
+ retval,
+ profile, swiz, swizcount, smap, smapcount,
+ m, f, d);
- ptr += shadersize;
- len -= shadersize;
- } // for
- } // if
-
- // !!! FIXME: we parse this, but don't expose the data, yet.
- // mappings ...
- assert(numshaders <= numobjects);
- const uint32 nummappings = numobjects - numshaders;
- if (nummappings > 0)
- {
- for (i = 0; i < nummappings; i++)
- {
- if (len < 24)
- goto parseEffect_unexpectedEOF;
+ /* Parse "large" object table. */
+ readlargeobjects(numlargeobjects, numsmallobjects, &ptr, &len,
+ retval,
+ profile, swiz, swizcount, smap, smapcount,
+ m, f, d);
- /*const uint32 magic = */ readui32(&ptr, &len);
- /*const uint32 index = */ readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: what is this field?
- readui32(&ptr, &len); // !!! FIXME: what is this field?
- /*const uint32 type = */ readui32(&ptr, &len);
- const uint32 mapsize = readui32(&ptr, &len);
- if (mapsize > 0)
- {
- const uint32 readsize = (((mapsize + 3) / 4) * 4);
- if (len < readsize)
- goto parseEffect_unexpectedEOF;
- } // if
- } // for
- } // if
-
+ /* Store MojoShader profile in effect structure */
retval->profile = (char *) m(strlen(profile) + 1, d);
if (retval->profile == NULL)
goto parseEffect_outOfMemory;
@@ -560,7 +888,6 @@
return retval;
-
// !!! FIXME: do something with this.
parseEffect_notAnEffectsFile:
parseEffect_unexpectedEOF:
@@ -570,6 +897,22 @@
} // MOJOSHADER_parseEffect
+void freevalue(MOJOSHADER_effectValue *value, MOJOSHADER_free f, void *d)
+{
+ int i;
+ f((void *) value->name, d);
+ f((void *) value->semantic, d);
+ if (value->value_type == MOJOSHADER_SYMTYPE_SAMPLER
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || value->value_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;
@@ -578,8 +921,9 @@
MOJOSHADER_free f = effect->free;
void *d = effect->malloc_data;
- int i, j;
+ int i, j, k;
+ /* Free errors */
for (i = 0; i < effect->error_count; i++)
{
f((void *) effect->errors[i].error, d);
@@ -587,39 +931,702 @@
} // 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++)
{
- f((void *) effect->params[i].name, d);
- f((void *) effect->params[i].semantic, d);
+ 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(effect->params, d);
+ 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++)
{
- f((void *) technique->passes[j].name, d);
- f(technique->passes[j].states, d);
+ 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, f, d);
+ 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
+
+
+void copyvalue(MOJOSHADER_effectValue *dst,
+ MOJOSHADER_effectValue *src,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ uint32 siz = 0;
+ char *stringcopy = NULL;
+
+ // !!! 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
+
+ COPY_STRING(name)
+ COPY_STRING(semantic)
+ dst->element_count = src->element_count;
+ dst->row_count = src->row_count;
+ dst->column_count = src->column_count;
+ dst->value_class = src->value_class;
+ dst->value_type = src->value_type;
+ dst->value_count = src->value_count;
+
+ if (dst->value_class == MOJOSHADER_SYMCLASS_SCALAR
+ || dst->value_class == MOJOSHADER_SYMCLASS_VECTOR
+ || dst->value_class == MOJOSHADER_SYMCLASS_MATRIX_ROWS
+ || dst->value_class == MOJOSHADER_SYMCLASS_MATRIX_COLUMNS)
+ {
+ 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->value_class == MOJOSHADER_SYMCLASS_OBJECT)
+ {
+ if (dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER
+ || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || dst->value_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
+ else if (dst->value_class == MOJOSHADER_SYMCLASS_STRUCT)
+ {
+ /* TODO: See readvalue! -flibit */
+ } // else if
+
+ #undef COPY_STRING
+} // copyvalue
+
+
+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
- f(technique->passes, d);
+ } // 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
- f(effect->techniques, d);
+ /* 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; \
- for (i = 0; i < effect->texture_count; i++)
- f((void *) effect->textures[i].name, d);
- f(effect->textures, d);
+ /* 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
- for (i = 0; i < effect->shader_count; i++)
- MOJOSHADER_freeParseData(effect->shaders[i].shader);
- f(effect->shaders, d);
+ /* 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);
- f(effect, d);
-} // MOJOSHADER_freeEffect
+ 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 ...