mojoshader_effects.c
changeset 1150 02c0f0afb39a
parent 1104 9147482e1ec7
child 1152 8f7653f0dc37
equal deleted inserted replaced
1149:265ab4117525 1150:02c0f0afb39a
     8  */
     8  */
     9 
     9 
    10 #define __MOJOSHADER_INTERNAL__ 1
    10 #define __MOJOSHADER_INTERNAL__ 1
    11 #include "mojoshader_internal.h"
    11 #include "mojoshader_internal.h"
    12 
    12 
       
    13 #ifdef MOJOSHADER_EFFECT_SUPPORT
       
    14 
    13 #include <math.h>
    15 #include <math.h>
    14 
    16 
    15 #if SUPPORT_PRESHADERS
       
    16 void MOJOSHADER_runPreshader(const MOJOSHADER_preshader *preshader,
    17 void MOJOSHADER_runPreshader(const MOJOSHADER_preshader *preshader,
    17                              const float *inregs, float *outregs)
    18                              float *outregs)
    18 {
    19 {
       
    20     const float *inregs = preshader->registers;
       
    21 
    19     // this is fairly straightforward, as there aren't any branching
    22     // this is fairly straightforward, as there aren't any branching
    20     //  opcodes in the preshader instruction set (at the moment, at least).
    23     //  opcodes in the preshader instruction set (at the moment, at least).
    21     const int scalarstart = (int) MOJOSHADER_PRESHADEROP_SCALAR_OPS;
    24     const int scalarstart = (int) MOJOSHADER_PRESHADEROP_SCALAR_OPS;
    22 
    25 
    23     double *temps = NULL;
    26     double *temps = NULL;
    54             const unsigned int index = operand->index;
    57             const unsigned int index = operand->index;
    55             switch (operand->type)
    58             switch (operand->type)
    56             {
    59             {
    57                 case MOJOSHADER_PRESHADEROPERAND_LITERAL:
    60                 case MOJOSHADER_PRESHADEROPERAND_LITERAL:
    58                 {
    61                 {
    59                     const double *lit = &preshader->literals[index];
       
    60                     assert((index + elems) <= preshader->literal_count);
       
    61                     if (!isscalar)
    62                     if (!isscalar)
    62                         memcpy(&src[opiter][0], lit, elemsbytes);
    63                     {
       
    64                         assert((index + elems) <= preshader->literal_count);
       
    65                         memcpy(&src[opiter][0], &preshader->literals[index], elemsbytes);
       
    66                     } // if
    63                     else
    67                     else
    64                     {
    68                     {
    65                         const double val = *lit;
       
    66                         for (elemiter = 0; elemiter < elems; elemiter++)
    69                         for (elemiter = 0; elemiter < elems; elemiter++)
    67                             src[opiter][elemiter] = val;
    70                             src[opiter][elemiter] = preshader->literals[index];
    68                     } // else
    71                     } // else
    69                     break;
    72                     break;
    70                 } // case
    73                 } // case
    71 
    74 
    72                 case MOJOSHADER_PRESHADEROPERAND_INPUT:
    75                 case MOJOSHADER_PRESHADEROPERAND_INPUT:
    73                     if (isscalar)
    76                     if (operand->array_register_count > 0)
       
    77                     {
       
    78                         int i;
       
    79                         const int *regsi = (const int *) inregs;
       
    80                         int arrIndex = regsi[((index >> 4) * 4) + ((index >> 2) & 3)];
       
    81                         for (i = 0; i < operand->array_register_count; i++)
       
    82                         {
       
    83                             arrIndex = regsi[operand->array_registers[i] + arrIndex];
       
    84                         }
       
    85                         src[opiter][0] = arrIndex;
       
    86                     } // if
       
    87                     else if (isscalar)
    74                         src[opiter][0] = inregs[index];
    88                         src[opiter][0] = inregs[index];
    75                     else
    89                     else
    76                     {
    90                     {
    77                         int cpy;
    91                         int cpy;
    78                         for (cpy = 0; cpy < elems; cpy++)
    92                         for (cpy = 0; cpy < elems; cpy++)
   157                 double final = 0.0;
   171                 double final = 0.0;
   158                 for (i = 0; i < elems; i++)
   172                 for (i = 0; i < elems; i++)
   159                     final += src0[i] * src1[i];
   173                     final += src0[i] * src1[i];
   160                 for (i = 0; i < elems; i++)
   174                 for (i = 0; i < elems; i++)
   161                     dst[i] = final;  // !!! FIXME: is this right?
   175                     dst[i] = final;  // !!! FIXME: is this right?
       
   176                 break;
   162             } // case
   177             } // case
   163 
   178 
   164             default:
   179             default:
   165                 assert(0 && "Unhandled preshader opcode!");
   180                 assert(0 && "Unhandled preshader opcode!");
   166                 break;
   181                 break;
   179             for (i = 0; i < elems; i++)
   194             for (i = 0; i < elems; i++)
   180                 outregs[operand->index + i] = (float) dst[i];
   195                 outregs[operand->index + i] = (float) dst[i];
   181         } // else
   196         } // else
   182     } // for
   197     } // for
   183 } // MOJOSHADER_runPreshader
   198 } // MOJOSHADER_runPreshader
   184 #endif
       
   185 
   199 
   186 static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
   200 static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
   187     1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
   201     1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
   188 };
   202 };
   189 
   203 
   200         *_len -= sizeof (retval);
   214         *_len -= sizeof (retval);
   201     } // else
   215     } // else
   202     return retval;
   216     return retval;
   203 } // readui32
   217 } // readui32
   204 
   218 
   205 // !!! FIXME: this is sort of a big, ugly function.
   219 static char *readstring(const uint8 *base,
   206 const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
   220                         const uint32 offset,
   207                                                 const unsigned char *buf,
   221                         MOJOSHADER_malloc m,
   208                                                 const unsigned int _len,
   222                         void *d)
   209                                                 const MOJOSHADER_swizzle *swiz,
   223 {
   210                                                 const unsigned int swizcount,
   224     // !!! FIXME: sanity checks!
   211                                                 const MOJOSHADER_samplerMap *smap,
   225     // !!! FIXME: verify this doesn't go past EOF looking for a null.
   212                                                 const unsigned int smapcount,
   226     const char *str = ((const char *) base) + offset;
   213                                                 MOJOSHADER_malloc m,
   227     const uint32 len = *((const uint32 *) str);
   214                                                 MOJOSHADER_free f,
   228     char *strptr = NULL;
   215                                                 void *d)
   229     if (len == 0) return NULL; /* No length? No string. */
   216 {
   230     strptr = (char *) m(len, d);
       
   231     memcpy(strptr, str + 4, len);
       
   232     return strptr;
       
   233 } // readstring
       
   234 
       
   235 static int findparameter(const MOJOSHADER_effectParam *params,
       
   236                          const uint32 param_count,
       
   237                          const char *name)
       
   238 {
       
   239     int i;
       
   240     for (i = 0; i < param_count; i++)
       
   241         if (strcmp(name, params[i].value.name) == 0)
       
   242             return i;
       
   243     assert(0 && "Parameter not found!");
       
   244 }
       
   245 
       
   246 static void readvalue(const uint8 *base,
       
   247                       const uint32 typeoffset,
       
   248                       const uint32 valoffset,
       
   249                       MOJOSHADER_effectValue *value,
       
   250                       MOJOSHADER_effectObject *objects,
       
   251                       MOJOSHADER_malloc m,
       
   252                       void *d)
       
   253 {
       
   254     int i;
       
   255     const uint8 *typeptr = base + typeoffset;
       
   256     const uint8 *valptr = base + valoffset;
       
   257     unsigned int typelen = 9999999;  // !!! FIXME
       
   258     const uint32 type = readui32(&typeptr, &typelen);
       
   259     const uint32 valclass = readui32(&typeptr, &typelen);
       
   260     const uint32 name = readui32(&typeptr, &typelen);
       
   261     const uint32 semantic = readui32(&typeptr, &typelen);
       
   262     const uint32 numelements = readui32(&typeptr, &typelen);
       
   263 
       
   264     value->value_type = (MOJOSHADER_symbolType) type;
       
   265     value->value_class = (MOJOSHADER_symbolClass) valclass;
       
   266     value->name = readstring(base, name, m, d);
       
   267     value->semantic = readstring(base, semantic, m, d);
       
   268     value->element_count = numelements;
       
   269 
       
   270     /* Class sanity check */
       
   271     assert(valclass >= MOJOSHADER_SYMCLASS_SCALAR && valclass <= MOJOSHADER_SYMCLASS_STRUCT);
       
   272 
       
   273     if (valclass == MOJOSHADER_SYMCLASS_SCALAR
       
   274      || valclass == MOJOSHADER_SYMCLASS_VECTOR
       
   275      || valclass == MOJOSHADER_SYMCLASS_MATRIX_ROWS
       
   276      || valclass == MOJOSHADER_SYMCLASS_MATRIX_COLUMNS)
       
   277     {
       
   278         /* These classes only ever contain scalar values */
       
   279         assert(type >= MOJOSHADER_SYMTYPE_BOOL && type <= MOJOSHADER_SYMTYPE_FLOAT);
       
   280 
       
   281         const uint32 columncount = readui32(&typeptr, &typelen);
       
   282         const uint32 rowcount = readui32(&typeptr, &typelen);
       
   283 
       
   284         value->column_count = columncount;
       
   285         value->row_count = rowcount;
       
   286 
       
   287         uint32 siz = columncount * rowcount;
       
   288         if (numelements > 0)
       
   289             siz *= numelements;
       
   290         value->value_count = siz;
       
   291         siz *= 4;
       
   292         value->values = m(siz, d);
       
   293         memcpy(value->values, valptr, siz);
       
   294     } // if
       
   295     else if (valclass == MOJOSHADER_SYMCLASS_OBJECT)
       
   296     {
       
   297         /* This class contains either samplers or "objects" */
       
   298         assert(type >= MOJOSHADER_SYMTYPE_STRING && type <= MOJOSHADER_SYMTYPE_VERTEXSHADER);
       
   299 
       
   300         if (type == MOJOSHADER_SYMTYPE_SAMPLER
       
   301          || type == MOJOSHADER_SYMTYPE_SAMPLER1D
       
   302          || type == MOJOSHADER_SYMTYPE_SAMPLER2D
       
   303          || type == MOJOSHADER_SYMTYPE_SAMPLER3D
       
   304          || type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
       
   305         {
       
   306             unsigned int vallen = 9999999; // !!! FIXME
       
   307             const uint32 numstates = readui32(&valptr, &vallen);
       
   308 
       
   309             value->value_count = numstates;
       
   310 
       
   311             const uint32 siz = sizeof(MOJOSHADER_effectSamplerState) * numstates;
       
   312             value->values = m(siz, d);
       
   313             memset(value->values, '\0', siz);
       
   314 
       
   315             for (i = 0; i < numstates; i++)
       
   316             {
       
   317                 MOJOSHADER_effectSamplerState *state = &value->valuesSS[i];
       
   318                 const uint32 stype = readui32(&valptr, &vallen) & ~0xA0;
       
   319                 /*const uint32 FIXME =*/ readui32(&valptr, &vallen);
       
   320                 const uint32 statetypeoffset = readui32(&valptr, &vallen);
       
   321                 const uint32 statevaloffset = readui32(&valptr, &vallen);
       
   322 
       
   323                 state->type = (MOJOSHADER_samplerStateType) stype;
       
   324                 readvalue(base, statetypeoffset, statevaloffset,
       
   325                           &state->value, objects,
       
   326                           m, d);
       
   327                 if (stype == MOJOSHADER_SAMP_TEXTURE)
       
   328                     objects[state->value.valuesI[0]].type = (MOJOSHADER_symbolType) type;
       
   329             } // for
       
   330         } // if
       
   331         else
       
   332         {
       
   333             uint32 numobjects = 1;
       
   334             if (numelements > 0)
       
   335                 numobjects = numelements;
       
   336 
       
   337             value->value_count = numobjects;
       
   338 
       
   339             const uint32 siz = 4 * numobjects;
       
   340             value->values = m(siz, d);
       
   341             memcpy(value->values, valptr, siz);
       
   342 
       
   343             for (i = 0; i < value->value_count; i++)
       
   344                 objects[value->valuesI[i]].type = (MOJOSHADER_symbolType) type;
       
   345         } // else
       
   346     } // else if
       
   347     else if (valclass == MOJOSHADER_SYMCLASS_STRUCT)
       
   348     {
       
   349         /* TODO: Maybe this is like parse_ctab_typeinfo? -flibit */
       
   350         assert(0 && "Effect struct value parsing not implemented!");
       
   351     } // else if
       
   352 } // readvalue
       
   353 
       
   354 static void readannotations(const uint32 numannos,
       
   355                             const uint8 *base,
       
   356                             const uint8 **ptr,
       
   357                             uint32 *len,
       
   358                             MOJOSHADER_effectAnnotation **annotations,
       
   359                             MOJOSHADER_effectObject *objects,
       
   360                             MOJOSHADER_malloc m,
       
   361                             void *d)
       
   362 {
       
   363     int i;
       
   364     if (numannos == 0) return;
       
   365 
       
   366     const uint32 siz = sizeof(MOJOSHADER_effectAnnotation) * numannos;
       
   367     *annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
       
   368     memset(*annotations, '\0', siz);
       
   369 
       
   370     for (i = 0; i < numannos; i++)
       
   371     {
       
   372         MOJOSHADER_effectAnnotation *anno = &(*annotations)[i];
       
   373 
       
   374         const uint32 typeoffset = readui32(ptr, len);
       
   375         const uint32 valoffset = readui32(ptr, len);
       
   376 
       
   377         readvalue(base, typeoffset, valoffset,
       
   378                   anno, objects,
       
   379                   m, d);
       
   380     } // for
       
   381 } // readannotation
       
   382 
       
   383 static void readparameters(const uint32 numparams,
       
   384                            const uint8 *base,
       
   385                            const uint8 **ptr,
       
   386                            uint32 *len,
       
   387                            MOJOSHADER_effectParam **params,
       
   388                            MOJOSHADER_effectObject *objects,
       
   389                            MOJOSHADER_malloc m,
       
   390                            void *d)
       
   391 {
       
   392     int i;
       
   393     if (numparams == 0) return;
       
   394 
       
   395     uint32 siz = sizeof(MOJOSHADER_effectParam) * numparams;
       
   396     *params = (MOJOSHADER_effectParam *) m(siz, d);
       
   397     memset(*params, '\0', siz);
       
   398 
       
   399     for (i = 0; i < numparams; i++)
       
   400     {
       
   401         MOJOSHADER_effectParam *param = &(*params)[i];
       
   402 
       
   403         const uint32 typeoffset = readui32(ptr, len);
       
   404         const uint32 valoffset = readui32(ptr, len);
       
   405         /*const uint32 flags =*/ readui32(ptr, len);
       
   406         const uint32 numannos = readui32(ptr, len);
       
   407 
       
   408         param->annotation_count = numannos;
       
   409         readannotations(numannos, base, ptr, len,
       
   410                         &param->annotations, objects,
       
   411                         m, d);
       
   412 
       
   413         readvalue(base, typeoffset, valoffset,
       
   414                   &param->value, objects,
       
   415                   m, d);
       
   416     } // for
       
   417 } // readparameters
       
   418 
       
   419 static void readstates(const uint32 numstates,
       
   420                        const uint8 *base,
       
   421                        const uint8 **ptr,
       
   422                        uint32 *len,
       
   423                        MOJOSHADER_effectState **states,
       
   424                        MOJOSHADER_effectObject *objects,
       
   425                        MOJOSHADER_malloc m,
       
   426                        void *d)
       
   427 {
       
   428     int i;
       
   429     if (numstates == 0) return;
       
   430 
       
   431     const uint32 siz = sizeof (MOJOSHADER_effectState) * numstates;
       
   432     *states = (MOJOSHADER_effectState *) m(siz, d);
       
   433     memset(*states, '\0', siz);
       
   434 
       
   435     for (i = 0; i < numstates; i++)
       
   436     {
       
   437         MOJOSHADER_effectState *state = &(*states)[i];
       
   438 
       
   439         const uint32 type = readui32(ptr, len);
       
   440         /*const uint32 FIXME =*/ readui32(ptr, len);
       
   441         const uint32 typeoffset = readui32(ptr, len);
       
   442         const uint32 valoffset = readui32(ptr, len);
       
   443 
       
   444         state->type = (MOJOSHADER_renderStateType) type;
       
   445         readvalue(base, typeoffset, valoffset,
       
   446                   &state->value, objects,
       
   447                   m, d);
       
   448     } // for
       
   449 } // readstates
       
   450 
       
   451 static void readpasses(const uint32 numpasses,
       
   452                        const uint8 *base,
       
   453                        const uint8 **ptr,
       
   454                        uint32 *len,
       
   455                        MOJOSHADER_effectPass **passes,
       
   456                        MOJOSHADER_effectObject *objects,
       
   457                        MOJOSHADER_malloc m,
       
   458                        void *d)
       
   459 {
       
   460     int i;
       
   461     if (numpasses == 0) return;
       
   462 
       
   463     const uint32 siz = sizeof (MOJOSHADER_effectPass) * numpasses;
       
   464     *passes = (MOJOSHADER_effectPass *) m(siz, d);
       
   465     memset(*passes, '\0', siz);
       
   466 
       
   467     for (i = 0; i < numpasses; i++)
       
   468     {
       
   469         MOJOSHADER_effectPass *pass = &(*passes)[i];
       
   470 
       
   471         const uint32 passnameoffset = readui32(ptr, len);
       
   472         const uint32 numannos = readui32(ptr, len);
       
   473         const uint32 numstates = readui32(ptr, len);
       
   474 
       
   475         pass->name = readstring(base, passnameoffset, m, d);
       
   476 
       
   477         pass->annotation_count = numannos;
       
   478         readannotations(numannos, base, ptr, len,
       
   479                         &pass->annotations, objects,
       
   480                         m, d);
       
   481 
       
   482         pass->state_count = numstates;
       
   483         readstates(numstates, base, ptr, len,
       
   484                    &pass->states, objects,
       
   485                    m, d);
       
   486     } // for
       
   487 } // readpasses
       
   488 
       
   489 static void readtechniques(const uint32 numtechniques,
       
   490                            const uint8 *base,
       
   491                            const uint8 **ptr,
       
   492                            uint32 *len,
       
   493                            MOJOSHADER_effectTechnique **techniques,
       
   494                            MOJOSHADER_effectObject *objects,
       
   495                            MOJOSHADER_malloc m,
       
   496                            void *d)
       
   497 {
       
   498     int i;
       
   499     if (numtechniques == 0) return;
       
   500 
       
   501     const uint32 siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
       
   502     *techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
       
   503     memset(*techniques, '\0', siz);
       
   504 
       
   505     for (i = 0; i < numtechniques; i++)
       
   506     {
       
   507         MOJOSHADER_effectTechnique *technique = &(*techniques)[i];
       
   508 
       
   509         const uint32 nameoffset = readui32(ptr, len);
       
   510         const uint32 numannos = readui32(ptr, len);
       
   511         const uint32 numpasses = readui32(ptr, len);
       
   512 
       
   513         technique->name = readstring(base, nameoffset, m, d);
       
   514 
       
   515         technique->annotation_count = numannos;
       
   516         readannotations(numannos, base, ptr, len,
       
   517                         &technique->annotations, objects,
       
   518                         m, d);
       
   519 
       
   520         technique->pass_count = numpasses;
       
   521         readpasses(numpasses, base, ptr, len,
       
   522                    &technique->passes, objects,
       
   523                    m, d);
       
   524     } // for
       
   525 } // readtechniques
       
   526 
       
   527 static void readsmallobjects(const uint32 numsmallobjects,
       
   528                              const uint8 **ptr,
       
   529                              uint32 *len,
       
   530                              MOJOSHADER_effect *effect,
       
   531                              const char *profile,
       
   532                              const MOJOSHADER_swizzle *swiz,
       
   533                              const unsigned int swizcount,
       
   534                              const MOJOSHADER_samplerMap *smap,
       
   535                              const unsigned int smapcount,
       
   536                              MOJOSHADER_malloc m,
       
   537                              MOJOSHADER_free f,
       
   538                              void *d)
       
   539 {
       
   540     int i, j;
       
   541     if (numsmallobjects == 0) return;
       
   542 
       
   543     for (i = 1; i < numsmallobjects + 1; i++)
       
   544     {
       
   545         const uint32 index = readui32(ptr, len);
       
   546         const uint32 length = readui32(ptr, len);
       
   547 
       
   548         MOJOSHADER_effectObject *object = &effect->objects[index];
       
   549         if (object->type == MOJOSHADER_SYMTYPE_STRING)
       
   550         {
       
   551             if (length > 0)
       
   552             {
       
   553                 char *str = (char *) m(length, d);
       
   554                 memcpy(str, *ptr, length);
       
   555                 object->string.string = str;
       
   556             } // if
       
   557         } // if
       
   558         else if (object->type == MOJOSHADER_SYMTYPE_TEXTURE
       
   559               || object->type == MOJOSHADER_SYMTYPE_TEXTURE1D
       
   560               || object->type == MOJOSHADER_SYMTYPE_TEXTURE2D
       
   561               || object->type == MOJOSHADER_SYMTYPE_TEXTURE3D
       
   562               || object->type == MOJOSHADER_SYMTYPE_TEXTURECUBE)
       
   563         {
       
   564             // No-op. Why is this even here?
       
   565         } // else if
       
   566         else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
       
   567               || object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
       
   568               || object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
       
   569               || object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
       
   570               || object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
       
   571         {
       
   572             if (length > 0)
       
   573             {
       
   574                 char *str = (char *) m(length, d);
       
   575                 memcpy(str, *ptr, length);
       
   576                 object->mapping.name = str;
       
   577             } // if
       
   578         } // else if
       
   579         else if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
       
   580               || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
       
   581         {
       
   582             object->shader.technique = -1;
       
   583             object->shader.pass = -1;
       
   584             object->shader.shader = MOJOSHADER_parse(profile, *ptr, length,
       
   585                                                      swiz, swizcount, smap, smapcount,
       
   586                                                      m, f, d);
       
   587             // !!! FIXME: check for errors.
       
   588             for (j = 0; j < object->shader.shader->symbol_count; j++)
       
   589                 if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
       
   590                     object->shader.sampler_count++;
       
   591             object->shader.param_count = object->shader.shader->symbol_count;
       
   592             object->shader.params = (uint32 *) m(object->shader.param_count * sizeof (uint32), d);
       
   593             object->shader.samplers = (MOJOSHADER_samplerStateRegister *) m(object->shader.sampler_count * sizeof (MOJOSHADER_samplerStateRegister), d);
       
   594             uint32 curSampler = 0;
       
   595             for (j = 0; j < object->shader.shader->symbol_count; j++)
       
   596             {
       
   597                 int par = findparameter(effect->params,
       
   598                                         effect->param_count,
       
   599                                         object->shader.shader->symbols[j].name);
       
   600                 object->shader.params[j] = par;
       
   601                 if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
       
   602                 {
       
   603                     object->shader.samplers[curSampler].sampler_name = object->shader.shader->symbols[j].name;
       
   604                     object->shader.samplers[curSampler].sampler_register = object->shader.shader->symbols[j].register_index;
       
   605                     object->shader.samplers[curSampler].sampler_state_count = effect->params[par].value.value_count;
       
   606                     object->shader.samplers[curSampler].sampler_states = effect->params[par].value.valuesSS;
       
   607                     curSampler++;
       
   608                 } // if
       
   609             } // for
       
   610             if (object->shader.shader->preshader)
       
   611             {
       
   612                 object->shader.preshader_param_count = object->shader.shader->preshader->symbol_count;
       
   613                 object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
       
   614                 for (j = 0; j < object->shader.shader->preshader->symbol_count; j++)
       
   615                 {
       
   616                     object->shader.preshader_params[j] = findparameter(effect->params,
       
   617                                                                        effect->param_count,
       
   618                                                                        object->shader.shader->preshader->symbols[j].name);
       
   619                 } // for
       
   620             } // if
       
   621         } // else if
       
   622         else
       
   623         {
       
   624             assert(0 && "Small object type unknown!");
       
   625         } // else
       
   626 
       
   627         /* Object block is always a multiple of four */
       
   628         const uint32 blocklen = (length + 3) - ((length - 1) % 4);
       
   629         *ptr += blocklen;
       
   630         *len -= blocklen;
       
   631     } // for
       
   632 } // readstrings
       
   633 
       
   634 static void readlargeobjects(const uint32 numlargeobjects,
       
   635                              const uint32 numsmallobjects,
       
   636                              const uint8 **ptr,
       
   637                              uint32 *len,
       
   638                              MOJOSHADER_effect *effect,
       
   639                              const char *profile,
       
   640                              const MOJOSHADER_swizzle *swiz,
       
   641                              const unsigned int swizcount,
       
   642                              const MOJOSHADER_samplerMap *smap,
       
   643                              const unsigned int smapcount,
       
   644                              MOJOSHADER_malloc m,
       
   645                              MOJOSHADER_free f,
       
   646                              void *d)
       
   647 {
       
   648     int i, j;
       
   649     if (numlargeobjects == 0) return;
       
   650 
       
   651     int numobjects = numsmallobjects + numlargeobjects + 1;
       
   652     for (i = numsmallobjects + 1; i < numobjects; i++)
       
   653     {
       
   654         const uint32 technique = readui32(ptr, len);
       
   655         const uint32 index = readui32(ptr, len);
       
   656         /*const uint32 FIXME =*/ readui32(ptr, len);
       
   657         const uint32 state = readui32(ptr, len);
       
   658         const uint32 type = readui32(ptr, len);
       
   659         const uint32 length = readui32(ptr, len);
       
   660 
       
   661         uint32 objectIndex;
       
   662         if (technique == -1)
       
   663             objectIndex = effect->params[index].value.valuesSS[state].value.valuesI[0];
       
   664         else
       
   665             objectIndex = effect->techniques[technique].passes[index].states[state].value.valuesI[0];
       
   666 
       
   667         MOJOSHADER_effectObject *object = &effect->objects[objectIndex];
       
   668         if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
       
   669          || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
       
   670         {
       
   671             object->shader.technique = technique;
       
   672             object->shader.pass = index;
       
   673 
       
   674             const char *emitter = profile;
       
   675             if (type == 2)
       
   676             {
       
   677                 /* This is a standalone preshader!
       
   678                  * It exists solely for effect passes that do not use a single
       
   679                  * vertex/fragment shader.
       
   680                  */
       
   681                 object->shader.is_preshader = 1;
       
   682                 const uint32 start = *((uint32 *) *ptr) + 4;
       
   683                 const uint32 end = 24; // FIXME: Why? -flibit
       
   684                 const char *array = readstring(*ptr, 0, m, d);
       
   685                 object->shader.param_count = 1;
       
   686                 object->shader.params = (uint32 *) m(sizeof (uint32), d);
       
   687                 object->shader.params[0] = findparameter(effect->params,
       
   688                                                          effect->param_count,
       
   689                                                          array);
       
   690                 f((void *) array, d);
       
   691                 object->shader.preshader = MOJOSHADER_parsePreshader(*ptr + start, length - end,
       
   692                                                                      m, f, d);
       
   693                 // !!! FIXME: check for errors.
       
   694                 object->shader.preshader_param_count = object->shader.preshader->symbol_count;
       
   695                 object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
       
   696                 for (j = 0; j < object->shader.preshader->symbol_count; j++)
       
   697                 {
       
   698                     object->shader.preshader_params[j] = findparameter(effect->params,
       
   699                                                                        effect->param_count,
       
   700                                                                        object->shader.preshader->symbols[j].name);
       
   701                 } // for
       
   702             } // if
       
   703             else
       
   704             {
       
   705                 object->shader.shader = MOJOSHADER_parse(emitter, *ptr, length,
       
   706                                                          swiz, swizcount, smap, smapcount,
       
   707                                                          m, f, d);
       
   708                 // !!! FIXME: check for errors.
       
   709                 for (j = 0; j < object->shader.shader->symbol_count; j++)
       
   710                     if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
       
   711                         object->shader.sampler_count++;
       
   712                 object->shader.param_count = object->shader.shader->symbol_count;
       
   713                 object->shader.params = (uint32 *) m(object->shader.param_count * sizeof (uint32), d);
       
   714                 object->shader.samplers = (MOJOSHADER_samplerStateRegister *) m(object->shader.sampler_count * sizeof (MOJOSHADER_samplerStateRegister), d);
       
   715                 uint32 curSampler = 0;
       
   716                 for (j = 0; j < object->shader.shader->symbol_count; j++)
       
   717                 {
       
   718                     int par = findparameter(effect->params,
       
   719                                             effect->param_count,
       
   720                                             object->shader.shader->symbols[j].name);
       
   721                     object->shader.params[j] = par;
       
   722                     if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
       
   723                     {
       
   724                         object->shader.samplers[curSampler].sampler_name = object->shader.shader->symbols[j].name;
       
   725                         object->shader.samplers[curSampler].sampler_register = object->shader.shader->symbols[j].register_index;
       
   726                         object->shader.samplers[curSampler].sampler_state_count = effect->params[par].value.value_count;
       
   727                         object->shader.samplers[curSampler].sampler_states = effect->params[par].value.valuesSS;
       
   728                         curSampler++;
       
   729                     } // if
       
   730                 } // for
       
   731                 if (object->shader.shader->preshader)
       
   732                 {
       
   733                     object->shader.preshader_param_count = object->shader.shader->preshader->symbol_count;
       
   734                     object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
       
   735                     for (j = 0; j < object->shader.shader->preshader->symbol_count; j++)
       
   736                     {
       
   737                         object->shader.preshader_params[j] = findparameter(effect->params,
       
   738                                                                            effect->param_count,
       
   739                                                                            object->shader.shader->preshader->symbols[j].name);
       
   740                     } // for
       
   741                 } // if
       
   742             }
       
   743         } // if
       
   744         else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
       
   745               || object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
       
   746               || object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
       
   747               || object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
       
   748               || object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
       
   749         {
       
   750             if (length > 0)
       
   751             {
       
   752                 char *str = (char *) m(length, d);
       
   753                 memcpy(str, *ptr, length);
       
   754                 object->mapping.name = str;
       
   755             } // if
       
   756         } // else if
       
   757         else if (object->type != MOJOSHADER_SYMTYPE_VOID) // FIXME: Why? -flibit
       
   758         {
       
   759             assert(0 && "Large object type unknown!");
       
   760         } // else
       
   761 
       
   762         /* Object block is always a multiple of four */
       
   763         const uint32 blocklen = (length + 3) - ((length - 1) % 4);
       
   764         *ptr += blocklen;
       
   765         *len -= blocklen;
       
   766     } // for
       
   767 } // readobjects
       
   768 
       
   769 MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
       
   770                                           const unsigned char *buf,
       
   771                                           const unsigned int _len,
       
   772                                           const MOJOSHADER_swizzle *swiz,
       
   773                                           const unsigned int swizcount,
       
   774                                           const MOJOSHADER_samplerMap *smap,
       
   775                                           const unsigned int smapcount,
       
   776                                           MOJOSHADER_malloc m,
       
   777                                           MOJOSHADER_free f,
       
   778                                           void *d)
       
   779 {
       
   780     const uint8 *ptr = (const uint8 *) buf;
       
   781     uint32 len = (uint32) _len;
       
   782 
       
   783     /* Supply both m and f, or neither */
   217     if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
   784     if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
   218         return &MOJOSHADER_out_of_mem_effect;  // supply both or neither.
   785         return &MOJOSHADER_out_of_mem_effect;
   219 
   786 
       
   787     /* Use default malloc/free if m/f were not passed */
   220     if (m == NULL) m = MOJOSHADER_internal_malloc;
   788     if (m == NULL) m = MOJOSHADER_internal_malloc;
   221     if (f == NULL) f = MOJOSHADER_internal_free;
   789     if (f == NULL) f = MOJOSHADER_internal_free;
   222 
   790 
   223     MOJOSHADER_effect *retval = m(sizeof (MOJOSHADER_effect), d);
   791     /* malloc base effect structure */
       
   792     MOJOSHADER_effect *retval = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect), d);
   224     if (retval == NULL)
   793     if (retval == NULL)
   225         return &MOJOSHADER_out_of_mem_effect;  // supply both or neither.
   794         return &MOJOSHADER_out_of_mem_effect;
   226     memset(retval, '\0', sizeof (*retval));
   795     memset(retval, '\0', sizeof (*retval));
   227 
   796 
       
   797     /* Store m/f/d in effect structure */
   228     retval->malloc = m;
   798     retval->malloc = m;
   229     retval->free = f;
   799     retval->free = f;
   230     retval->malloc_data = d;
   800     retval->malloc_data = d;
   231 
   801 
   232     const uint8 *ptr = (const uint8 *) buf;
       
   233     uint32 len = (uint32) _len;
       
   234     size_t siz = 0;
       
   235     int i, j, k;
       
   236 
       
   237     if (len < 8)
   802     if (len < 8)
   238         goto parseEffect_unexpectedEOF;
   803         goto parseEffect_unexpectedEOF;
   239 
   804 
       
   805     /* Read in header magic, seek to initial offset */
   240     const uint8 *base = NULL;
   806     const uint8 *base = NULL;
   241     if (readui32(&ptr, &len) != 0xFEFF0901) // !!! FIXME: is this always magic?
   807     uint32 header = readui32(&ptr, &len);
       
   808     if (header == 0xBCF00BCF)
       
   809     {
       
   810         /* The Effect compiler provided with XNA4 adds some extra mess at the
       
   811          * beginning of the file. It's useless though, so just skip it.
       
   812          * -flibit
       
   813          */
       
   814         const uint32 skip = readui32(&ptr, &len) - 8;
       
   815         ptr += skip;
       
   816         len += skip;
       
   817         header = readui32(&ptr, &len);
       
   818     } // if
       
   819     if (header != 0xFEFF0901)
   242         goto parseEffect_notAnEffectsFile;
   820         goto parseEffect_notAnEffectsFile;
   243     else
   821     else
   244     {
   822     {
   245         const uint32 offset = readui32(&ptr, &len);
   823         const uint32 offset = readui32(&ptr, &len);
   246         base = ptr;
   824         base = ptr;
   247 //printf("base offset == %u\n", offset);
       
   248         if (offset > len)
   825         if (offset > len)
   249             goto parseEffect_unexpectedEOF;
   826             goto parseEffect_unexpectedEOF;
   250         ptr += offset;
   827         ptr += offset;
   251         len -= offset;
   828         len -= offset;
   252     } // else
   829     } // else
   253 
   830 
   254     // params...
       
   255 
       
   256     if (len < 16)
   831     if (len < 16)
   257         goto parseEffect_unexpectedEOF;
   832         goto parseEffect_unexpectedEOF;
   258 
   833 
       
   834     /* Parse structure counts */
   259     const uint32 numparams = readui32(&ptr, &len);
   835     const uint32 numparams = readui32(&ptr, &len);
   260     const uint32 numtechniques = readui32(&ptr, &len);
   836     const uint32 numtechniques = readui32(&ptr, &len);
   261 
   837     /*const uint32 FIXME =*/ readui32(&ptr, &len);
   262     readui32(&ptr, &len); // !!! FIXME: there are 8 unknown bytes here. Annotations?
   838     const uint32 numobjects = readui32(&ptr, &len);
   263     /*const uint32 numobjects = */ readui32(&ptr, &len);
   839 
   264 
   840     /* Alloc structures now, so object types can be stored */
   265     if (numparams > 0)
   841     retval->object_count = numobjects;
   266     {
   842     const uint32 siz = sizeof (MOJOSHADER_effectObject) * numobjects;
   267         siz = sizeof (MOJOSHADER_effectParam) * numparams;
   843     retval->objects = (MOJOSHADER_effectObject *) m(siz, d);
   268         retval->params = (MOJOSHADER_effectParam *) m(siz, d);
   844     if (retval->objects == NULL)
   269         if (retval->params == NULL)
   845         goto parseEffect_outOfMemory;
   270             goto parseEffect_outOfMemory;
   846     memset(retval->objects, '\0', siz);
   271         memset(retval->params, '\0', siz);
   847 
   272 
   848     /* Parse effect parameters */
   273         retval->param_count = numparams;
   849     retval->param_count = numparams;
   274 
   850     readparameters(numparams, base, &ptr, &len,
   275         for (i = 0; i < numparams; i++)
   851                    &retval->params, retval->objects,
   276         {
   852                    m, d);
   277             if (len < 16)
   853 
   278                 goto parseEffect_unexpectedEOF;
   854     /* Parse effect techniques */
   279 
   855     retval->technique_count = numtechniques;
   280             const uint32 typeoffset = readui32(&ptr, &len);
   856     readtechniques(numtechniques, base, &ptr, &len,
   281             /*const uint32 valoffset =*/ readui32(&ptr, &len);
   857                    &retval->techniques, retval->objects,
   282             /*const uint32 flags =*/ readui32(&ptr, &len);
   858                    m, d);
   283             const uint32 numannos = readui32(&ptr, &len);
   859 
   284             for (j = 0; j < numannos; j++)
   860     /* Initial effect technique/pass */
   285             {
   861     retval->current_technique = &retval->techniques[0];
   286                 if (len < 8)
   862     retval->current_pass = -1;
   287                     goto parseEffect_unexpectedEOF;
       
   288                 // !!! FIXME: parse annotations.
       
   289                 readui32(&ptr, &len);
       
   290                 readui32(&ptr, &len);
       
   291             } // for
       
   292 
       
   293             const uint8 *typeptr = base + typeoffset;
       
   294             unsigned int typelen = 9999999;  // !!! FIXME
       
   295             /*const uint32 paramtype =*/ readui32(&typeptr, &typelen);
       
   296             /*const uint32 paramclass =*/ readui32(&typeptr, &typelen);
       
   297             const uint32 paramname = readui32(&typeptr, &typelen);
       
   298             const uint32 paramsemantic = readui32(&typeptr, &typelen);
       
   299 
       
   300             // !!! FIXME: sanity checks!
       
   301             const char *namestr = ((const char *) base) + paramname;
       
   302             const char *semstr = ((const char *) base) + paramsemantic;
       
   303             uint32 len;
       
   304             char *strptr;
       
   305             len = *((const uint32 *) namestr);
       
   306             strptr = (char *) m(len + 1, d);
       
   307             memcpy(strptr, namestr + 4, len);
       
   308             strptr[len] = '\0';
       
   309             retval->params[i].name = strptr;
       
   310             len = *((const uint32 *) semstr);
       
   311             strptr = (char *) m(len + 1, d);
       
   312             memcpy(strptr, semstr + 4, len);
       
   313             strptr[len] = '\0';
       
   314             retval->params[i].semantic = strptr;
       
   315         } // for
       
   316     } // if
       
   317 
       
   318     uint32 numshaders = 0;  // we'll calculate this later.
       
   319 
       
   320     // techniques...
       
   321 
       
   322     if (numtechniques > 0)
       
   323     {
       
   324         siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
       
   325         retval->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
       
   326         if (retval->techniques == NULL)
       
   327             goto parseEffect_outOfMemory;
       
   328         memset(retval->techniques, '\0', siz);
       
   329 
       
   330         retval->technique_count = numtechniques;
       
   331 
       
   332         for (i = 0; i < numtechniques; i++)
       
   333         {
       
   334             if (len < 12)
       
   335                 goto parseEffect_unexpectedEOF;
       
   336             
       
   337             MOJOSHADER_effectTechnique *technique = &retval->techniques[i];
       
   338 
       
   339             const uint32 nameoffset = readui32(&ptr, &len);
       
   340             const uint32 numannos = readui32(&ptr, &len);
       
   341             const uint32 numpasses = readui32(&ptr, &len);
       
   342 
       
   343             if (nameoffset >= _len)
       
   344                 goto parseEffect_unexpectedEOF;
       
   345 
       
   346             if (numannos > 0)
       
   347             {
       
   348                 // !!! FIXME: expose these to the caller?
       
   349                 for (j = 0; j < numannos; j++)
       
   350                 {
       
   351                     if (len < 8)
       
   352                         goto parseEffect_unexpectedEOF;
       
   353                     readui32(&ptr, &len);  // typedef offset
       
   354                     readui32(&ptr, &len);  // value offset
       
   355                 } // for
       
   356             } // if
       
   357 
       
   358             // !!! FIXME: verify this doesn't go past EOF looking for a null.
       
   359             {
       
   360                 const char *namestr = ((char *) base) + nameoffset;
       
   361                 uint32 len = *((const uint32 *) namestr);
       
   362                 char *strptr = (char *) m(len + 1, d);
       
   363                 memcpy(strptr, namestr + 4, len);
       
   364                 strptr[len] = '\0';
       
   365                 technique->name = strptr;
       
   366             }
       
   367 
       
   368             if (numpasses > 0)
       
   369             {
       
   370                 technique->pass_count = numpasses;
       
   371 
       
   372                 siz = sizeof (MOJOSHADER_effectPass) * numpasses;
       
   373                 technique->passes = (MOJOSHADER_effectPass *) m(siz, d);
       
   374                 if (technique->passes == NULL)
       
   375                     goto parseEffect_outOfMemory;
       
   376                 memset(technique->passes, '\0', siz);
       
   377 
       
   378                 for (j = 0; j < numpasses; j++)
       
   379                 {
       
   380                     if (len < 12)
       
   381                         goto parseEffect_unexpectedEOF;
       
   382 
       
   383                     MOJOSHADER_effectPass *pass = &technique->passes[j];
       
   384 
       
   385                     const uint32 passnameoffset = readui32(&ptr, &len);
       
   386                     const uint32 numannos = readui32(&ptr, &len);
       
   387                     const uint32 numstates = readui32(&ptr, &len);
       
   388 
       
   389                     if (passnameoffset >= _len)
       
   390                         goto parseEffect_unexpectedEOF;
       
   391 
       
   392                     // !!! FIXME: verify this doesn't go past EOF looking for a null.
       
   393                     {
       
   394                         const char *namestr = ((char *) base) + passnameoffset;
       
   395                         uint32 len = *((const uint32 *) namestr);
       
   396                         char *strptr = (char *) m(len + 1, d);
       
   397                         memcpy(strptr, namestr + 4, len);
       
   398                         strptr[len] = '\0';
       
   399                         pass->name = strptr;
       
   400                     }
       
   401 
       
   402                     if (numannos > 0)
       
   403                     {
       
   404                         for (k = 0; k < numannos; k++)
       
   405                         {
       
   406                             if (len < 8)
       
   407                                 goto parseEffect_unexpectedEOF;
       
   408                             // !!! FIXME: do something with this.
       
   409                             readui32(&ptr, &len);
       
   410                             readui32(&ptr, &len);
       
   411                         } // for
       
   412                     } // if
       
   413 
       
   414                     if (numstates > 0)
       
   415                     {
       
   416                         pass->state_count = numstates;
       
   417 
       
   418                         siz = sizeof (MOJOSHADER_effectState) * numstates;
       
   419                         pass->states = (MOJOSHADER_effectState *) m(siz, d);
       
   420                         if (pass->states == NULL)
       
   421                             goto parseEffect_outOfMemory;
       
   422                         memset(pass->states, '\0', siz);
       
   423 
       
   424                         for (k = 0; k < numstates; k++)
       
   425                         {
       
   426                             if (len < 16)
       
   427                                 goto parseEffect_unexpectedEOF;
       
   428 
       
   429                             MOJOSHADER_effectState *state = &pass->states[k];
       
   430                             const uint32 type = readui32(&ptr, &len);
       
   431                             readui32(&ptr, &len);  // !!! FIXME: don't know what this field does.
       
   432                             /*const uint32 offsetend = */ readui32(&ptr, &len);
       
   433                             /*const uint32 offsetstart = */ readui32(&ptr, &len);
       
   434                             state->type = type;
       
   435 
       
   436                             if ((type == 0x92) || (type == 0x93))
       
   437                                 numshaders++;
       
   438                         } // for
       
   439                     } // if
       
   440                 } // for
       
   441             } // if
       
   442         } // for
       
   443     } // if
       
   444 
       
   445     // textures...
       
   446 
   863 
   447     if (len < 8)
   864     if (len < 8)
   448         goto parseEffect_unexpectedEOF;
   865         goto parseEffect_unexpectedEOF;
   449 
   866 
   450     const int numtextures = readui32(&ptr, &len);
   867     /* Parse object counts */
   451     const int numobjects = readui32(&ptr, &len);  // !!! FIXME: "objects" for lack of a better word.
   868     const int numsmallobjects = readui32(&ptr, &len);
   452 
   869     const int numlargeobjects = readui32(&ptr, &len);
   453     if (numtextures > 0)
   870 
   454     {
   871     /* Parse "small" object table */
   455         siz = sizeof (MOJOSHADER_effectTexture) * numtextures;
   872     readsmallobjects(numsmallobjects, &ptr, &len,
   456         retval->textures = m(siz, d);
   873                      retval,
   457         if (retval->textures == NULL)
   874                      profile, swiz, swizcount, smap, smapcount,
   458             goto parseEffect_outOfMemory;
   875                      m, f, d);
   459         memset(retval->textures, '\0', siz);
   876 
   460 
   877     /* Parse "large" object table. */
   461         for (i = 0; i < numtextures; i++)
   878     readlargeobjects(numlargeobjects, numsmallobjects, &ptr, &len,
   462         {
   879                      retval,
   463             if (len < 8)
   880                      profile, swiz, swizcount, smap, smapcount,
   464                 goto parseEffect_unexpectedEOF;
   881                      m, f, d);
   465 
   882 
   466             MOJOSHADER_effectTexture *texture = &retval->textures[i];
   883     /* Store MojoShader profile in effect structure */
   467             const uint32 texparam = readui32(&ptr, &len);
       
   468             const uint32 texsize = readui32(&ptr, &len);
       
   469             // apparently texsize will pad out to 32 bits.
       
   470             const uint32 readsize = (((texsize + 3) / 4) * 4);
       
   471             if (len < readsize)
       
   472                 goto parseEffect_unexpectedEOF;
       
   473 
       
   474             texture->param = texparam;
       
   475             char *str = m(texsize + 1, d);
       
   476             if (str == NULL)
       
   477                 goto parseEffect_outOfMemory;
       
   478             memcpy(str, ptr, texsize);
       
   479             str[texsize] = '\0';
       
   480             texture->name = str;
       
   481 
       
   482             ptr += readsize;
       
   483             len -= readsize;
       
   484         } // for
       
   485     } // if
       
   486 
       
   487     // shaders...
       
   488 
       
   489     if (numshaders > 0)
       
   490     {
       
   491         siz = sizeof (MOJOSHADER_effectShader) * numshaders;
       
   492         retval->shaders = (MOJOSHADER_effectShader *) m(siz, d);
       
   493         if (retval->shaders == NULL)
       
   494             goto parseEffect_outOfMemory;
       
   495         memset(retval->shaders, '\0', siz);
       
   496 
       
   497         retval->shader_count = numshaders;
       
   498 
       
   499         // !!! FIXME: I wonder if we should pull these from offsets and not
       
   500         // !!! FIXME:  count on them all being in a line like this.
       
   501         for (i = 0; i < numshaders; i++)
       
   502         {
       
   503             if (len < 24)
       
   504                 goto parseEffect_unexpectedEOF;
       
   505 
       
   506             MOJOSHADER_effectShader *shader = &retval->shaders[i];
       
   507             const uint32 technique = readui32(&ptr, &len);
       
   508             const uint32 pass = readui32(&ptr, &len);
       
   509             readui32(&ptr, &len);  // !!! FIXME: don't know what this does.
       
   510             readui32(&ptr, &len);  // !!! FIXME: don't know what this does (vertex/pixel/geometry?)
       
   511             readui32(&ptr, &len);  // !!! FIXME: don't know what this does.
       
   512             const uint32 shadersize = readui32(&ptr, &len);
       
   513 
       
   514             if (len < shadersize)
       
   515                 goto parseEffect_unexpectedEOF;
       
   516 
       
   517             shader->technique = technique;
       
   518             shader->pass = pass;
       
   519             shader->shader = MOJOSHADER_parse(profile, ptr, shadersize,
       
   520                                               swiz, swizcount, smap, smapcount,
       
   521                                               m, f, d);
       
   522 
       
   523             // !!! FIXME: check for errors.
       
   524 
       
   525             ptr += shadersize;
       
   526             len -= shadersize;
       
   527         } // for
       
   528     } // if
       
   529 
       
   530     // !!! FIXME: we parse this, but don't expose the data, yet.
       
   531     // mappings ...
       
   532     assert(numshaders <= numobjects);
       
   533     const uint32 nummappings = numobjects - numshaders;
       
   534     if (nummappings > 0)
       
   535     {
       
   536         for (i = 0; i < nummappings; i++)
       
   537         {
       
   538             if (len < 24)
       
   539                 goto parseEffect_unexpectedEOF;
       
   540 
       
   541             /*const uint32 magic = */ readui32(&ptr, &len);
       
   542             /*const uint32 index = */ readui32(&ptr, &len);
       
   543             readui32(&ptr, &len);  // !!! FIXME: what is this field?
       
   544             readui32(&ptr, &len);  // !!! FIXME: what is this field?
       
   545             /*const uint32 type = */ readui32(&ptr, &len);
       
   546             const uint32 mapsize = readui32(&ptr, &len);
       
   547             if (mapsize > 0)
       
   548             {
       
   549                 const uint32 readsize = (((mapsize + 3) / 4) * 4);
       
   550                 if (len < readsize)
       
   551                     goto parseEffect_unexpectedEOF;
       
   552             } // if
       
   553         } // for
       
   554     } // if
       
   555 
       
   556     retval->profile = (char *) m(strlen(profile) + 1, d);
   884     retval->profile = (char *) m(strlen(profile) + 1, d);
   557     if (retval->profile == NULL)
   885     if (retval->profile == NULL)
   558         goto parseEffect_outOfMemory;
   886         goto parseEffect_outOfMemory;
   559     strcpy((char *) retval->profile, profile);
   887     strcpy((char *) retval->profile, profile);
   560 
   888 
   561     return retval;
   889     return retval;
   562 
       
   563 
   890 
   564 // !!! FIXME: do something with this.
   891 // !!! FIXME: do something with this.
   565 parseEffect_notAnEffectsFile:
   892 parseEffect_notAnEffectsFile:
   566 parseEffect_unexpectedEOF:
   893 parseEffect_unexpectedEOF:
   567 parseEffect_outOfMemory:
   894 parseEffect_outOfMemory:
   568     MOJOSHADER_freeEffect(retval);
   895     MOJOSHADER_freeEffect(retval);
   569     return &MOJOSHADER_out_of_mem_effect;
   896     return &MOJOSHADER_out_of_mem_effect;
   570 } // MOJOSHADER_parseEffect
   897 } // MOJOSHADER_parseEffect
   571 
   898 
   572 
   899 
       
   900 void freevalue(MOJOSHADER_effectValue *value, MOJOSHADER_free f, void *d)
       
   901 {
       
   902     int i;
       
   903     f((void *) value->name, d);
       
   904     f((void *) value->semantic, d);
       
   905     if (value->value_type == MOJOSHADER_SYMTYPE_SAMPLER
       
   906      || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER1D
       
   907      || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER2D
       
   908      || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER3D
       
   909      || value->value_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
       
   910         for (i = 0; i < value->value_count; i++)
       
   911             freevalue(&value->valuesSS[i].value, f, d);
       
   912     f(value->values, d);
       
   913 } // freevalue
       
   914 
       
   915 
   573 void MOJOSHADER_freeEffect(const MOJOSHADER_effect *_effect)
   916 void MOJOSHADER_freeEffect(const MOJOSHADER_effect *_effect)
   574 {
   917 {
   575     MOJOSHADER_effect *effect = (MOJOSHADER_effect *) _effect;
   918     MOJOSHADER_effect *effect = (MOJOSHADER_effect *) _effect;
   576     if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
   919     if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
   577         return;  // no-op.
   920         return;  // no-op.
   578 
   921 
   579     MOJOSHADER_free f = effect->free;
   922     MOJOSHADER_free f = effect->free;
   580     void *d = effect->malloc_data;
   923     void *d = effect->malloc_data;
   581     int i, j;
   924     int i, j, k;
   582 
   925 
       
   926     /* Free errors */
   583     for (i = 0; i < effect->error_count; i++)
   927     for (i = 0; i < effect->error_count; i++)
   584     {
   928     {
   585         f((void *) effect->errors[i].error, d);
   929         f((void *) effect->errors[i].error, d);
   586         f((void *) effect->errors[i].filename, d);
   930         f((void *) effect->errors[i].filename, d);
   587     } // for
   931     } // for
   588     f((void *) effect->errors, d);
   932     f((void *) effect->errors, d);
   589 
   933 
       
   934     /* Free profile string */
   590     f((void *) effect->profile, d);
   935     f((void *) effect->profile, d);
   591 
   936 
       
   937     /* Free parameters, including annotations */
   592     for (i = 0; i < effect->param_count; i++)
   938     for (i = 0; i < effect->param_count; i++)
   593     {
   939     {
   594         f((void *) effect->params[i].name, d);
   940         MOJOSHADER_effectParam *param = &effect->params[i];
   595         f((void *) effect->params[i].semantic, d);
   941         freevalue(&param->value, f, d);
   596     } // for
   942         for (j = 0; j < param->annotation_count; j++)
   597     f(effect->params, d);
   943         {
   598 
   944             freevalue(&param->annotations[j], f, d);
       
   945         } // for
       
   946         f((void *) param->annotations, d);
       
   947     } // for
       
   948     f((void *) effect->params, d);
       
   949 
       
   950     /* Free techniques, including passes and all annotations */
   599     for (i = 0; i < effect->technique_count; i++)
   951     for (i = 0; i < effect->technique_count; i++)
   600     {
   952     {
   601         MOJOSHADER_effectTechnique *technique = &effect->techniques[i];
   953         MOJOSHADER_effectTechnique *technique = &effect->techniques[i];
   602         f((void *) technique->name, d);
   954         f((void *) technique->name, d);
   603         for (j = 0; j < technique->pass_count; j++)
   955         for (j = 0; j < technique->pass_count; j++)
   604         {
   956         {
   605             f((void *) technique->passes[j].name, d);
   957             MOJOSHADER_effectPass *pass = &technique->passes[j];
   606             f(technique->passes[j].states, d);
   958             f((void *) pass->name, d);
       
   959             for (k = 0; k < pass->state_count; k++)
       
   960             {
       
   961                 freevalue(&pass->states[k].value, f, d);
       
   962             } // for
       
   963             f((void *) pass->states, d);
       
   964             for (k = 0; k < pass->annotation_count; k++)
       
   965             {
       
   966                 freevalue(&pass->annotations[k], f, d);
       
   967             } // for
       
   968             f((void *) pass->annotations, d);
   607         } // for
   969         } // for
   608         f(technique->passes, d);
   970         f((void *) technique->passes, d);
   609     } // for
   971         for (j = 0; j < technique->annotation_count; j++)
   610 
   972         {
   611     f(effect->techniques, d);
   973             freevalue(&technique->annotations[j], f, d);
   612 
   974         } // for
   613     for (i = 0; i < effect->texture_count; i++)
   975         f((void *) technique->annotations, d);
   614         f((void *) effect->textures[i].name, d);
   976     } // for
   615     f(effect->textures, d);
   977     f((void *) effect->techniques, d);
   616 
   978 
   617     for (i = 0; i < effect->shader_count; i++)
   979     /* Free object table */
   618         MOJOSHADER_freeParseData(effect->shaders[i].shader);
   980     for (i = 0; i < effect->object_count; i++)
   619     f(effect->shaders, d);
   981     {
   620 
   982         MOJOSHADER_effectObject *object = &effect->objects[i];
   621     f(effect, d);
   983         if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
       
   984          || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
       
   985         {
       
   986             if (object->shader.is_preshader)
       
   987                 MOJOSHADER_freePreshader(object->shader.preshader, f, d);
       
   988             else
       
   989                 MOJOSHADER_freeParseData(object->shader.shader);
       
   990             f((void *) object->shader.params, d);
       
   991             f((void *) object->shader.samplers, d);
       
   992             f((void *) object->shader.preshader_params, d);
       
   993         } // if
       
   994         else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
       
   995               || object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
       
   996               || object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
       
   997               || object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
       
   998               || object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
       
   999             f((void *) object->mapping.name, d);
       
  1000         else if (object->type == MOJOSHADER_SYMTYPE_STRING)
       
  1001             f((void *) object->string.string, d);
       
  1002     } // for
       
  1003     f((void *) effect->objects, d);
       
  1004 
       
  1005     /* Free base effect structure */
       
  1006     f((void *) effect, d);
   622 } // MOJOSHADER_freeEffect
  1007 } // MOJOSHADER_freeEffect
   623 
  1008 
       
  1009 
       
  1010 void copyvalue(MOJOSHADER_effectValue *dst,
       
  1011                MOJOSHADER_effectValue *src,
       
  1012                MOJOSHADER_malloc m,
       
  1013                void *d)
       
  1014 {
       
  1015     int i;
       
  1016     uint32 siz = 0;
       
  1017     char *stringcopy = NULL;
       
  1018 
       
  1019     // !!! FIXME: Out of memory check!
       
  1020     #define COPY_STRING(location) \
       
  1021         if (src->location != NULL) \
       
  1022         { \
       
  1023             siz = strlen(src->location) + 1; \
       
  1024             stringcopy = (char *) m(siz, d); \
       
  1025             strcpy(stringcopy, src->location); \
       
  1026             dst->location = stringcopy; \
       
  1027         } // if
       
  1028 
       
  1029     COPY_STRING(name)
       
  1030     COPY_STRING(semantic)
       
  1031     dst->element_count = src->element_count;
       
  1032     dst->row_count = src->row_count;
       
  1033     dst->column_count = src->column_count;
       
  1034     dst->value_class = src->value_class;
       
  1035     dst->value_type = src->value_type;
       
  1036     dst->value_count = src->value_count;
       
  1037 
       
  1038     if (dst->value_class == MOJOSHADER_SYMCLASS_SCALAR
       
  1039      || dst->value_class == MOJOSHADER_SYMCLASS_VECTOR
       
  1040      || dst->value_class == MOJOSHADER_SYMCLASS_MATRIX_ROWS
       
  1041      || dst->value_class == MOJOSHADER_SYMCLASS_MATRIX_COLUMNS)
       
  1042     {
       
  1043         siz = dst->value_count * 4;
       
  1044         dst->values = m(siz, d);
       
  1045         // !!! FIXME: Out of memory check!
       
  1046         memcpy(dst->values, src->values, siz);
       
  1047     } // if
       
  1048     else if (dst->value_class == MOJOSHADER_SYMCLASS_OBJECT)
       
  1049     {
       
  1050         if (dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER
       
  1051          || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER1D
       
  1052          || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER2D
       
  1053          || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER3D
       
  1054          || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
       
  1055         {
       
  1056             siz = dst->value_count * sizeof (MOJOSHADER_effectSamplerState);
       
  1057             dst->values = m(siz, d);
       
  1058             // !!! FIXME: Out of memory check!
       
  1059             memset(dst->values, '\0', siz);
       
  1060             for (i = 0; i < dst->value_count; i++)
       
  1061             {
       
  1062                 dst->valuesSS[i].type = src->valuesSS[i].type;
       
  1063                 copyvalue(&dst->valuesSS[i].value,
       
  1064                           &src->valuesSS[i].value,
       
  1065                           m, d);
       
  1066             } // for
       
  1067         } // if
       
  1068         else
       
  1069         {
       
  1070             siz = dst->value_count * 4;
       
  1071             dst->values = m(siz, d);
       
  1072             // !!! FIXME: Out of memory check!
       
  1073             memcpy(dst->values, src->values, siz);
       
  1074         } // else
       
  1075     } // else if
       
  1076     else if (dst->value_class == MOJOSHADER_SYMCLASS_STRUCT)
       
  1077     {
       
  1078         /* TODO: See readvalue! -flibit */
       
  1079     } // else if
       
  1080 
       
  1081     #undef COPY_STRING
       
  1082 } // copyvalue
       
  1083 
       
  1084 
       
  1085 void copysymbolinfo(MOJOSHADER_symbolTypeInfo *dst,
       
  1086                     MOJOSHADER_symbolTypeInfo *src,
       
  1087                     MOJOSHADER_malloc m,
       
  1088                     void *d)
       
  1089 {
       
  1090     int i;
       
  1091     uint32 siz;
       
  1092     char *stringcopy;
       
  1093 
       
  1094     dst->parameter_class = src->parameter_class;
       
  1095     dst->parameter_type = src->parameter_type;
       
  1096     dst->rows = src->rows;
       
  1097     dst->columns = src->columns;
       
  1098     dst->elements = src->elements;
       
  1099     dst->member_count = src->member_count;
       
  1100 
       
  1101     if (dst->member_count > 0)
       
  1102     {
       
  1103         siz = sizeof (MOJOSHADER_symbolStructMember) * dst->member_count;
       
  1104         dst->members = (MOJOSHADER_symbolStructMember *) m(siz, d);
       
  1105         // !!! FIXME: Out of memory check!
       
  1106         for (i = 0; i < dst->member_count; i++)
       
  1107         {
       
  1108             if (src->members[i].name != NULL)
       
  1109             {
       
  1110                 siz = strlen(src->members[i].name) + 1;
       
  1111                 stringcopy = (char *) m(siz, d);
       
  1112                 strcpy(stringcopy, src->members[i].name);
       
  1113                 dst->members[i].name = stringcopy;
       
  1114             } // if
       
  1115             copysymbolinfo(&dst->members[i].info, &src->members[i].info, m, d);
       
  1116         } // for
       
  1117     } // if
       
  1118 } // copysymbolinfo
       
  1119 
       
  1120 
       
  1121 void copysymbol(MOJOSHADER_symbol *dst,
       
  1122                 MOJOSHADER_symbol *src,
       
  1123                 MOJOSHADER_malloc m,
       
  1124                 void *d)
       
  1125 {
       
  1126     uint32 siz = strlen(src->name) + 1;
       
  1127     char *stringcopy = (char *) m(siz, d);
       
  1128     // !!! FIXME: Out of memory check!
       
  1129     strcpy(stringcopy, src->name);
       
  1130     dst->name = stringcopy;
       
  1131     dst->register_set = src->register_set;
       
  1132     dst->register_index = src->register_index;
       
  1133     dst->register_count = src->register_count;
       
  1134     copysymbolinfo(&dst->info, &src->info, m, d);
       
  1135 } // copysymbol
       
  1136 
       
  1137 
       
  1138 MOJOSHADER_preshader *copypreshader(const MOJOSHADER_preshader *src,
       
  1139                                     MOJOSHADER_malloc m,
       
  1140                                     void *d)
       
  1141 {
       
  1142     int i, j;
       
  1143     uint32 siz;
       
  1144     MOJOSHADER_preshader *retval;
       
  1145 
       
  1146     retval = (MOJOSHADER_preshader *) m(sizeof (MOJOSHADER_preshader), d);
       
  1147     // !!! FIXME: Out of memory check!
       
  1148     memset(retval, '\0', sizeof (MOJOSHADER_preshader));
       
  1149 
       
  1150     siz = sizeof (double) * src->literal_count;
       
  1151     retval->literal_count = src->literal_count;
       
  1152     retval->literals = (double *) m(siz, d);
       
  1153     // !!! FIXME: Out of memory check!
       
  1154     memcpy(retval->literals, src->literals, siz);
       
  1155 
       
  1156     retval->temp_count = src->temp_count;
       
  1157 
       
  1158     siz = sizeof (MOJOSHADER_symbol) * src->symbol_count;
       
  1159     retval->symbol_count = src->symbol_count;
       
  1160     retval->symbols = (MOJOSHADER_symbol *) m(siz, d);
       
  1161     // !!! FIXME: Out of memory check!
       
  1162     memset(retval->symbols, '\0', siz);
       
  1163 
       
  1164     for (i = 0; i < retval->symbol_count; i++)
       
  1165         copysymbol(&retval->symbols[i], &src->symbols[i], m, d);
       
  1166 
       
  1167     siz = sizeof (MOJOSHADER_preshaderInstruction) * src->instruction_count;
       
  1168     retval->instruction_count = src->instruction_count;
       
  1169     retval->instructions = (MOJOSHADER_preshaderInstruction *) m(siz, d);
       
  1170     // !!! FIXME: Out of memory check!
       
  1171     memcpy(retval->instructions, src->instructions, siz);
       
  1172     for (i = 0; i < retval->instruction_count; i++)
       
  1173         for (j = 0; j < retval->instructions[i].operand_count; j++)
       
  1174         {
       
  1175             siz = sizeof (unsigned int) * retval->instructions[i].operands[j].array_register_count;
       
  1176             retval->instructions[i].operands[j].array_registers = (unsigned int *) m(siz, d);
       
  1177             // !!! FIXME: Out of memory check!
       
  1178             memcpy(retval->instructions[i].operands[j].array_registers,
       
  1179                    src->instructions[i].operands[j].array_registers,
       
  1180                    siz);
       
  1181         } // for
       
  1182 
       
  1183     siz = sizeof (float) * 4 * src->register_count;
       
  1184     retval->register_count = src->register_count;
       
  1185     retval->registers = (float *) m(siz, d);
       
  1186     // !!! FIXME: Out of memory check!
       
  1187     memcpy(retval->registers, src->registers, siz);
       
  1188 
       
  1189     return retval;
       
  1190 } // copypreshader
       
  1191 
       
  1192 
       
  1193 MOJOSHADER_parseData *copyparsedata(const MOJOSHADER_parseData *src,
       
  1194                                     MOJOSHADER_malloc m,
       
  1195                                     void *d)
       
  1196 {
       
  1197     int i;
       
  1198     uint32 siz;
       
  1199     char *stringcopy;
       
  1200     MOJOSHADER_parseData *retval;
       
  1201 
       
  1202     retval = (MOJOSHADER_parseData *) m(sizeof (MOJOSHADER_parseData), d);
       
  1203     memset(retval, '\0', sizeof (MOJOSHADER_parseData));
       
  1204 
       
  1205     /* Copy malloc/free */
       
  1206     retval->malloc = src->malloc;
       
  1207     retval->free = src->free;
       
  1208     retval->malloc_data = src->malloc_data;
       
  1209 
       
  1210     // !!! FIXME: Out of memory check!
       
  1211     #define COPY_STRING(location) \
       
  1212         siz = strlen(src->location) + 1; \
       
  1213         stringcopy = (char *) m(siz, d); \
       
  1214         strcpy(stringcopy, src->location); \
       
  1215         retval->location = stringcopy; \
       
  1216 
       
  1217     /* Copy errors */
       
  1218     siz = sizeof (MOJOSHADER_error) * src->error_count;
       
  1219     retval->error_count = src->error_count;
       
  1220     retval->errors = (MOJOSHADER_error *) m(siz, d);
       
  1221     // !!! FIXME: Out of memory check!
       
  1222     memset(retval->errors, '\0', siz);
       
  1223     for (i = 0; i < retval->error_count; i++)
       
  1224     {
       
  1225         COPY_STRING(errors[i].error)
       
  1226         COPY_STRING(errors[i].filename)
       
  1227         retval->errors[i].error_position = src->errors[i].error_position;
       
  1228     } // for
       
  1229 
       
  1230     /* Copy profile string constant */
       
  1231     retval->profile = src->profile;
       
  1232 
       
  1233     /* Copy shader output */
       
  1234     retval->output_len = src->output_len;
       
  1235     stringcopy = (char *) m(src->output_len, d);
       
  1236     memcpy(stringcopy, src->output, src->output_len);
       
  1237     retval->output = stringcopy;
       
  1238 
       
  1239     /* Copy miscellaneous shader info */
       
  1240     retval->instruction_count = src->instruction_count;
       
  1241     retval->shader_type = src->shader_type;
       
  1242     retval->major_ver = src->major_ver;
       
  1243     retval->minor_ver = src->minor_ver;
       
  1244 
       
  1245     /* Copy uniforms */
       
  1246     siz = sizeof (MOJOSHADER_uniform) * src->uniform_count;
       
  1247     retval->uniform_count = src->uniform_count;
       
  1248     retval->uniforms = (MOJOSHADER_uniform *) m(siz, d);
       
  1249     // !!! FIXME: Out of memory check!
       
  1250     memset(retval->uniforms, '\0', siz);
       
  1251     for (i = 0; i < retval->uniform_count; i++)
       
  1252     {
       
  1253         retval->uniforms[i].type = src->uniforms[i].type;
       
  1254         retval->uniforms[i].index = src->uniforms[i].index;
       
  1255         retval->uniforms[i].array_count = src->uniforms[i].array_count;
       
  1256         retval->uniforms[i].constant = src->uniforms[i].constant;
       
  1257         COPY_STRING(uniforms[i].name)
       
  1258     } // for
       
  1259 
       
  1260     /* Copy constants */
       
  1261     siz = sizeof (MOJOSHADER_constant) * src->constant_count;
       
  1262     retval->constant_count = src->constant_count;
       
  1263     retval->constants = (MOJOSHADER_constant *) m(siz, d);
       
  1264     // !!! FIXME: Out of memory check!
       
  1265     memcpy(retval->constants, src->constants, siz);
       
  1266 
       
  1267     /* Copy samplers */
       
  1268     siz = sizeof (MOJOSHADER_sampler) * src->sampler_count;
       
  1269     retval->sampler_count = src->sampler_count;
       
  1270     retval->samplers = (MOJOSHADER_sampler *) m(siz, d);
       
  1271     // !!! FIXME: Out of memory check!
       
  1272     memset(retval->samplers, '\0', siz);
       
  1273     for (i = 0; i < retval->sampler_count; i++)
       
  1274     {
       
  1275         retval->samplers[i].type = src->samplers[i].type;
       
  1276         retval->samplers[i].index = src->samplers[i].index;
       
  1277         COPY_STRING(samplers[i].name)
       
  1278         retval->samplers[i].texbem = src->samplers[i].texbem;
       
  1279     } // for
       
  1280 
       
  1281     /* Copy attributes */
       
  1282     siz = sizeof (MOJOSHADER_attribute) * src->attribute_count;
       
  1283     retval->attribute_count = src->attribute_count;
       
  1284     retval->attributes = (MOJOSHADER_attribute *) m(siz, d);
       
  1285     // !!! FIXME: Out of memory check!
       
  1286     memset(retval->attributes, '\0', siz);
       
  1287     for (i = 0; i < retval->attribute_count; i++)
       
  1288     {
       
  1289         retval->attributes[i].usage = src->attributes[i].usage;
       
  1290         retval->attributes[i].index = src->attributes[i].index;
       
  1291         COPY_STRING(attributes[i].name)
       
  1292     } // for
       
  1293 
       
  1294     /* Copy outputs */
       
  1295     siz = sizeof (MOJOSHADER_attribute) * src->output_count;
       
  1296     retval->output_count = src->output_count;
       
  1297     retval->outputs = (MOJOSHADER_attribute *) m(siz, d);
       
  1298     // !!! FIXME: Out of memory check!
       
  1299     memset(retval->outputs, '\0', siz);
       
  1300     for (i = 0; i < retval->output_count; i++)
       
  1301     {
       
  1302         retval->outputs[i].usage = src->outputs[i].usage;
       
  1303         retval->outputs[i].index = src->outputs[i].index;
       
  1304         COPY_STRING(outputs[i].name)
       
  1305     } // for
       
  1306 
       
  1307     #undef COPY_STRING
       
  1308 
       
  1309     /* Copy swizzles */
       
  1310     siz = sizeof (MOJOSHADER_swizzle) * src->swizzle_count;
       
  1311     retval->swizzle_count = src->swizzle_count;
       
  1312     retval->swizzles = (MOJOSHADER_swizzle *) m(siz, d);
       
  1313     // !!! FIXME: Out of memory check!
       
  1314     memcpy(retval->swizzles, src->swizzles, siz);
       
  1315 
       
  1316     /* Copy symbols */
       
  1317     siz = sizeof (MOJOSHADER_symbol) * src->symbol_count;
       
  1318     retval->symbol_count = src->symbol_count;
       
  1319     retval->symbols = (MOJOSHADER_symbol *) m(siz, d);
       
  1320     // !!! FIXME: Out of memory check!
       
  1321     memset(retval->symbols, '\0', siz);
       
  1322     for (i = 0; i < retval->symbol_count; i++)
       
  1323         copysymbol(&retval->symbols[i], &src->symbols[i], m, d);
       
  1324 
       
  1325     /* Copy preshader */
       
  1326     if (src->preshader != NULL)
       
  1327         retval->preshader = copypreshader(src->preshader, m, d);
       
  1328 
       
  1329     return retval;
       
  1330 } // copyparsedata
       
  1331 
       
  1332 
       
  1333 MOJOSHADER_effect *MOJOSHADER_cloneEffect(const MOJOSHADER_effect *effect)
       
  1334 {
       
  1335     int i, j, k;
       
  1336     MOJOSHADER_effect *clone;
       
  1337     MOJOSHADER_malloc m = effect->malloc;
       
  1338     void *d = effect->malloc_data;
       
  1339     uint32 siz = 0;
       
  1340     char *stringcopy = NULL;
       
  1341     uint32 curSampler;
       
  1342 
       
  1343     if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
       
  1344         return NULL;  // no-op.
       
  1345 
       
  1346     clone = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect), d);
       
  1347     if (clone == NULL)
       
  1348         return NULL; // Maybe out_of_mem_effect instead?
       
  1349     memset(clone, '\0', sizeof (MOJOSHADER_effect));
       
  1350 
       
  1351     /* Copy malloc/free */
       
  1352     clone->malloc = effect->malloc;
       
  1353     clone->free = effect->free;
       
  1354     clone->malloc_data = effect->malloc_data;
       
  1355 
       
  1356     #define COPY_STRING(location) \
       
  1357         siz = strlen(effect->location) + 1; \
       
  1358         stringcopy = (char *) m(siz, d); \
       
  1359         if (stringcopy == NULL) \
       
  1360             goto cloneEffect_outOfMemory; \
       
  1361         strcpy(stringcopy, effect->location); \
       
  1362         clone->location = stringcopy; \
       
  1363 
       
  1364     /* Copy errors */
       
  1365     siz = sizeof (MOJOSHADER_error) * effect->error_count;
       
  1366     clone->error_count = effect->error_count;
       
  1367     clone->errors = (MOJOSHADER_error *) m(siz, d);
       
  1368     if (clone->errors == NULL)
       
  1369         goto cloneEffect_outOfMemory;
       
  1370     memset(clone->errors, '\0', siz);
       
  1371     for (i = 0; i < clone->error_count; i++)
       
  1372     {
       
  1373         COPY_STRING(errors[i].error)
       
  1374         COPY_STRING(errors[i].filename)
       
  1375         clone->errors[i].error_position = effect->errors[i].error_position;
       
  1376     } // for
       
  1377 
       
  1378     /* Copy profile string */
       
  1379     COPY_STRING(profile)
       
  1380 
       
  1381     /* Copy parameters */
       
  1382     siz = sizeof (MOJOSHADER_effectParam) * effect->param_count;
       
  1383     clone->param_count = effect->param_count;
       
  1384     clone->params = (MOJOSHADER_effectParam *) m(siz, d);
       
  1385     if (clone->params == NULL)
       
  1386         goto cloneEffect_outOfMemory;
       
  1387     memset(clone->params, '\0', siz);
       
  1388     for (i = 0; i < clone->param_count; i++)
       
  1389     {
       
  1390         copyvalue(&clone->params[i].value, &effect->params[i].value, m, d);
       
  1391 
       
  1392         /* Copy parameter annotations */
       
  1393         siz = sizeof (MOJOSHADER_effectAnnotation) * effect->params[i].annotation_count;
       
  1394         clone->params[i].annotation_count = effect->params[i].annotation_count;
       
  1395         clone->params[i].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
       
  1396         if (clone->params[i].annotations == NULL)
       
  1397             goto cloneEffect_outOfMemory;
       
  1398         memset(clone->params[i].annotations, '\0', siz);
       
  1399         for (j = 0; j < clone->params[i].annotation_count; j++)
       
  1400             copyvalue(&clone->params[i].annotations[j],
       
  1401                       &effect->params[i].annotations[j],
       
  1402                       m, d);
       
  1403     } // for
       
  1404 
       
  1405     /* Copy techniques */
       
  1406     siz = sizeof (MOJOSHADER_effectTechnique) * effect->technique_count;
       
  1407     clone->technique_count = effect->technique_count;
       
  1408     clone->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
       
  1409     if (clone->techniques == NULL)
       
  1410         goto cloneEffect_outOfMemory;
       
  1411     memset(clone->techniques, '\0', siz);
       
  1412     for (i = 0; i < clone->technique_count; i++)
       
  1413     {
       
  1414         COPY_STRING(techniques[i].name)
       
  1415 
       
  1416         /* Copy passes */
       
  1417         siz = sizeof (MOJOSHADER_effectPass) * effect->techniques[i].pass_count;
       
  1418         clone->techniques[i].pass_count = effect->techniques[i].pass_count;
       
  1419         clone->techniques[i].passes = (MOJOSHADER_effectPass *) m(siz, d);
       
  1420         if (clone->techniques[i].passes == NULL)
       
  1421             goto cloneEffect_outOfMemory;
       
  1422         memset(clone->techniques[i].passes, '\0', siz);
       
  1423         for (j = 0; j < clone->techniques[i].pass_count; j++)
       
  1424         {
       
  1425             COPY_STRING(techniques[i].passes[j].name)
       
  1426 
       
  1427             /* Copy pass states */
       
  1428             siz = sizeof (MOJOSHADER_effectState) * effect->techniques[i].passes[j].state_count;
       
  1429             clone->techniques[i].passes[j].state_count = effect->techniques[i].passes[j].state_count;
       
  1430             clone->techniques[i].passes[j].states = (MOJOSHADER_effectState *) m(siz, d);
       
  1431             if (clone->techniques[i].passes[j].states == NULL)
       
  1432                 goto cloneEffect_outOfMemory;
       
  1433             memset(clone->techniques[i].passes[j].states, '\0', siz);
       
  1434             for (k = 0; k < clone->techniques[i].passes[j].state_count; k++)
       
  1435             {
       
  1436                 clone->techniques[i].passes[j].states[k].type = effect->techniques[i].passes[j].states[k].type;
       
  1437                 copyvalue(&clone->techniques[i].passes[j].states[k].value,
       
  1438                           &effect->techniques[i].passes[j].states[k].value,
       
  1439                           m, d);
       
  1440             } // for
       
  1441 
       
  1442             /* Copy pass annotations */
       
  1443             siz = sizeof (MOJOSHADER_effectAnnotation) * effect->techniques[i].passes[j].annotation_count;
       
  1444             clone->techniques[i].passes[j].annotation_count = effect->techniques[i].passes[j].annotation_count;
       
  1445             clone->techniques[i].passes[j].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
       
  1446             if (clone->techniques[i].passes[j].annotations == NULL)
       
  1447                 goto cloneEffect_outOfMemory;
       
  1448             memset(clone->techniques[i].passes[j].annotations, '\0', siz);
       
  1449             for (k = 0; k < clone->techniques[i].passes[j].annotation_count; k++)
       
  1450                 copyvalue(&clone->techniques[i].passes[j].annotations[k],
       
  1451                           &effect->techniques[i].passes[j].annotations[k],
       
  1452                           m, d);
       
  1453         } // for
       
  1454 
       
  1455         /* Copy technique annotations */
       
  1456         siz = sizeof (MOJOSHADER_effectAnnotation) * effect->techniques[i].annotation_count;
       
  1457         clone->techniques[i].annotation_count = effect->techniques[i].annotation_count;
       
  1458         clone->techniques[i].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
       
  1459         if (clone->techniques[i].annotations == NULL)
       
  1460             goto cloneEffect_outOfMemory;
       
  1461         memset(clone->techniques[i].annotations, '\0', siz);
       
  1462         for (j = 0; j < clone->techniques[i].annotation_count; j++)
       
  1463             copyvalue(&clone->techniques[i].annotations[j],
       
  1464                       &effect->techniques[i].annotations[j],
       
  1465                       m, d);
       
  1466     } // for
       
  1467 
       
  1468     /* Copy the current technique/pass */
       
  1469     for (i = 0; i < effect->technique_count; i++)
       
  1470         if (&effect->techniques[i] == effect->current_technique)
       
  1471         {
       
  1472             clone->current_technique = &clone->techniques[i];
       
  1473             break;
       
  1474         } // if
       
  1475     assert(clone->current_technique != NULL);
       
  1476     clone->current_pass = effect->current_pass;
       
  1477     assert(clone->current_pass == -1);
       
  1478 
       
  1479     /* Copy object table */
       
  1480     siz = sizeof (MOJOSHADER_effectObject) * effect->object_count;
       
  1481     clone->object_count = effect->object_count;
       
  1482     clone->objects = (MOJOSHADER_effectObject *) m(siz, d);
       
  1483     if (clone->objects == NULL)
       
  1484         goto cloneEffect_outOfMemory;
       
  1485     memset(clone->objects, '\0', siz);
       
  1486     for (i = 0; i < clone->object_count; i++)
       
  1487     {
       
  1488         clone->objects[i].type = effect->objects[i].type;
       
  1489         if (clone->objects[i].type == MOJOSHADER_SYMTYPE_PIXELSHADER
       
  1490          || clone->objects[i].type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
       
  1491         {
       
  1492             clone->objects[i].shader.technique = effect->objects[i].shader.technique;
       
  1493             clone->objects[i].shader.pass = effect->objects[i].shader.pass;
       
  1494             clone->objects[i].shader.is_preshader = effect->objects[i].shader.is_preshader;
       
  1495             siz = sizeof (uint32) * effect->objects[i].shader.preshader_param_count;
       
  1496             clone->objects[i].shader.preshader_param_count = effect->objects[i].shader.preshader_param_count;
       
  1497             clone->objects[i].shader.preshader_params = (uint32 *) m(siz, d);
       
  1498             memcpy(clone->objects[i].shader.preshader_params,
       
  1499                    effect->objects[i].shader.preshader_params,
       
  1500                    siz);
       
  1501             siz = sizeof (uint32) * effect->objects[i].shader.param_count;
       
  1502             clone->objects[i].shader.param_count = effect->objects[i].shader.param_count;
       
  1503             clone->objects[i].shader.params = (uint32 *) m(siz, d);
       
  1504             memcpy(clone->objects[i].shader.params,
       
  1505                    effect->objects[i].shader.params,
       
  1506                    siz);
       
  1507 
       
  1508             if (clone->objects[i].shader.is_preshader)
       
  1509             {
       
  1510                 clone->objects[i].shader.preshader = copypreshader(effect->objects[i].shader.preshader,
       
  1511                                                                    m, d);
       
  1512                 continue;
       
  1513             } // if
       
  1514 
       
  1515             clone->objects[i].shader.shader = copyparsedata(effect->objects[i].shader.shader,
       
  1516                                                             m, d);
       
  1517 
       
  1518             siz = sizeof (MOJOSHADER_samplerStateRegister) * effect->objects[i].shader.sampler_count;
       
  1519             clone->objects[i].shader.sampler_count = effect->objects[i].shader.sampler_count;
       
  1520             clone->objects[i].shader.samplers = (MOJOSHADER_samplerStateRegister *) m(siz, d);
       
  1521             if (clone->objects[i].shader.samplers == NULL)
       
  1522                 goto cloneEffect_outOfMemory;
       
  1523             curSampler = 0;
       
  1524             for (j = 0; j < clone->objects[i].shader.shader->symbol_count; j++)
       
  1525                 if (clone->objects[i].shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
       
  1526                 {
       
  1527                     clone->objects[i].shader.samplers[curSampler].sampler_name = clone->objects[i].shader.shader->symbols[j].name;
       
  1528                     clone->objects[i].shader.samplers[curSampler].sampler_register = clone->objects[i].shader.shader->symbols[j].register_index;
       
  1529                     clone->objects[i].shader.samplers[curSampler].sampler_state_count = clone->params[clone->objects[i].shader.params[j]].value.value_count;
       
  1530                     clone->objects[i].shader.samplers[curSampler].sampler_states = clone->params[clone->objects[i].shader.params[j]].value.valuesSS;
       
  1531                     curSampler++;
       
  1532                 } // if
       
  1533         } // if
       
  1534         else if (clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER
       
  1535               || clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER1D
       
  1536               || clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER2D
       
  1537               || clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER3D
       
  1538               || clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
       
  1539         {
       
  1540             COPY_STRING(objects[i].mapping.name)
       
  1541         } // else if
       
  1542         else if (clone->objects[i].type == MOJOSHADER_SYMTYPE_STRING)
       
  1543         {
       
  1544             COPY_STRING(objects[i].string.string)
       
  1545         } // else if
       
  1546     } // for
       
  1547 
       
  1548     #undef COPY_STRING
       
  1549 
       
  1550     return clone;
       
  1551 
       
  1552 cloneEffect_outOfMemory:
       
  1553     MOJOSHADER_freeEffect(clone);
       
  1554     return NULL;
       
  1555 } // MOJOSHADER_cloneEffect
       
  1556 
       
  1557 
       
  1558 void MOJOSHADER_effectSetRawValueHandle(const MOJOSHADER_effectParam *parameter,
       
  1559                                         const void *data,
       
  1560                                         const unsigned int offset,
       
  1561                                         const unsigned int len)
       
  1562 {
       
  1563     // !!! FIXME: uint32* case is arbitary, for Win32 -flibit
       
  1564     memcpy((uint32 *) parameter->value.values + offset, data, len);
       
  1565 } // MOJOSHADER_effectSetRawValueHandle
       
  1566 
       
  1567 
       
  1568 void MOJOSHADER_effectSetRawValueName(const MOJOSHADER_effect *effect,
       
  1569                                       const char *name,
       
  1570                                       const void *data,
       
  1571                                       const unsigned int offset,
       
  1572                                       const unsigned int len)
       
  1573 {
       
  1574     int i;
       
  1575     for (i = 0; i < effect->param_count; i++)
       
  1576     {
       
  1577         if (strcmp(name, effect->params[i].value.name) == 0)
       
  1578         {
       
  1579             // !!! FIXME: uint32* case is arbitary, for Win32 -flibit
       
  1580             memcpy((uint32 *) effect->params[i].value.values + offset, data, len);
       
  1581             return;
       
  1582         } // if
       
  1583     } // for
       
  1584     assert(0 && "Effect parameter not found!");
       
  1585 } // MOJOSHADER_effectSetRawValueName
       
  1586 
       
  1587 
       
  1588 const MOJOSHADER_effectTechnique *MOJOSHADER_effectGetCurrentTechnique(const MOJOSHADER_effect *effect)
       
  1589 {
       
  1590     return effect->current_technique;
       
  1591 } // MOJOSHADER_effectGetCurrentTechnique
       
  1592 
       
  1593 
       
  1594 void MOJOSHADER_effectSetTechnique(MOJOSHADER_effect *effect,
       
  1595                                    const MOJOSHADER_effectTechnique *technique)
       
  1596 {
       
  1597     int i;
       
  1598     for (i = 0; i < effect->technique_count; i++)
       
  1599     {
       
  1600         if (technique == &effect->techniques[i])
       
  1601         {
       
  1602             effect->current_technique = technique;
       
  1603             return;
       
  1604         } // if
       
  1605     } // for
       
  1606     assert(0 && "Technique is not part of this effect!");
       
  1607 } // MOJOSHADER_effectSetTechnique
       
  1608 
       
  1609 
       
  1610 const MOJOSHADER_effectTechnique *MOJOSHADER_effectFindNextValidTechnique(const MOJOSHADER_effect *effect,
       
  1611                                                                           const MOJOSHADER_effectTechnique *technique
       
  1612 )
       
  1613 {
       
  1614     int i;
       
  1615     if (technique == NULL)
       
  1616         return &effect->techniques[0];
       
  1617     for (i = 0; i < effect->technique_count; i++)
       
  1618     {
       
  1619         if (technique == &effect->techniques[i])
       
  1620         {
       
  1621             if (i == effect->technique_count - 1)
       
  1622                 return NULL; /* We were passed the last technique! */
       
  1623             return &effect->techniques[i + 1];
       
  1624         } // if
       
  1625     } // for
       
  1626     assert(0 && "Technique is not part of this effect!");
       
  1627 } // MOJOSHADER_effectFindNextValidTechnique
       
  1628 
       
  1629 #endif // MOJOSHADER_EFFECT_SUPPORT
       
  1630 
   624 // end of mojoshader_effects.c ...
  1631 // end of mojoshader_effects.c ...
   625 
  1632