mojoshader_effects.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. /**
  2. * MojoShader; generate shader programs from bytecode of compiled
  3. * Direct3D shaders.
  4. *
  5. * Please see the file LICENSE.txt in the source's root directory.
  6. *
  7. * This file written by Ryan C. Gordon.
  8. */
  9. #define __MOJOSHADER_INTERNAL__ 1
  10. #include "mojoshader_internal.h"
  11. #include <math.h>
  12. #if SUPPORT_PRESHADERS
  13. void MOJOSHADER_runPreshader(const MOJOSHADER_preshader *preshader,
  14. const float *inregs, float *outregs)
  15. {
  16. // this is fairly straightforward, as there aren't any branching
  17. // opcodes in the preshader instruction set (at the moment, at least).
  18. const int scalarstart = (int) MOJOSHADER_PRESHADEROP_SCALAR_OPS;
  19. double *temps = NULL;
  20. if (preshader->temp_count > 0)
  21. {
  22. temps = (double *) alloca(sizeof (double) * preshader->temp_count);
  23. memset(temps, '\0', sizeof (double) * preshader->temp_count);
  24. } // if
  25. double dst[4] = { 0, 0, 0, 0 };
  26. double src[3][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
  27. const double *src0 = &src[0][0];
  28. const double *src1 = &src[1][0];
  29. const double *src2 = &src[2][0];
  30. MOJOSHADER_preshaderInstruction *inst = preshader->instructions;
  31. int instit;
  32. for (instit = 0; instit < preshader->instruction_count; instit++, inst++)
  33. {
  34. const MOJOSHADER_preshaderOperand *operand = inst->operands;
  35. const int elems = inst->element_count;
  36. const int elemsbytes = sizeof (double) * elems;
  37. const int isscalarop = (inst->opcode >= scalarstart);
  38. assert(elems >= 0);
  39. assert(elems <= 4);
  40. // load up our operands...
  41. int opiter, elemiter;
  42. for (opiter = 0; opiter < inst->operand_count-1; opiter++, operand++)
  43. {
  44. const int isscalar = ((isscalarop) && (opiter == 0));
  45. const unsigned int index = operand->index;
  46. switch (operand->type)
  47. {
  48. case MOJOSHADER_PRESHADEROPERAND_LITERAL:
  49. {
  50. const double *lit = &preshader->literals[index];
  51. assert((index + elems) <= preshader->literal_count);
  52. if (!isscalar)
  53. memcpy(&src[opiter][0], lit, elemsbytes);
  54. else
  55. {
  56. const double val = *lit;
  57. for (elemiter = 0; elemiter < elems; elemiter++)
  58. src[opiter][elemiter] = val;
  59. } // else
  60. break;
  61. } // case
  62. case MOJOSHADER_PRESHADEROPERAND_INPUT:
  63. if (isscalar)
  64. src[opiter][0] = inregs[index];
  65. else
  66. {
  67. int cpy;
  68. for (cpy = 0; cpy < elems; cpy++)
  69. src[opiter][cpy] = inregs[index+cpy];
  70. } // else
  71. break;
  72. case MOJOSHADER_PRESHADEROPERAND_OUTPUT:
  73. if (isscalar)
  74. src[opiter][0] = outregs[index];
  75. else
  76. {
  77. int cpy;
  78. for (cpy = 0; cpy < elems; cpy++)
  79. src[opiter][cpy] = outregs[index+cpy];
  80. } // else
  81. break;
  82. case MOJOSHADER_PRESHADEROPERAND_TEMP:
  83. if (temps != NULL)
  84. {
  85. if (isscalar)
  86. src[opiter][0] = temps[index];
  87. else
  88. memcpy(src[opiter], temps + index, elemsbytes);
  89. } // if
  90. break;
  91. default:
  92. assert(0 && "unexpected preshader operand type.");
  93. return;
  94. } // switch
  95. } // for
  96. // run the actual instruction, store result to dst.
  97. int i;
  98. switch (inst->opcode)
  99. {
  100. #define OPCODE_CASE(op, val) \
  101. case MOJOSHADER_PRESHADEROP_##op: \
  102. for (i = 0; i < elems; i++) { dst[i] = val; } \
  103. break;
  104. //OPCODE_CASE(NOP, 0.0) // not a real instruction.
  105. OPCODE_CASE(MOV, src0[i])
  106. OPCODE_CASE(NEG, -src0[i])
  107. OPCODE_CASE(RCP, 1.0 / src0[i])
  108. OPCODE_CASE(FRC, src0[i] - floor(src0[i]))
  109. OPCODE_CASE(EXP, exp(src0[i]))
  110. OPCODE_CASE(LOG, log(src0[i]))
  111. OPCODE_CASE(RSQ, 1.0 / sqrt(src0[i]))
  112. OPCODE_CASE(SIN, sin(src0[i]))
  113. OPCODE_CASE(COS, cos(src0[i]))
  114. OPCODE_CASE(ASIN, asin(src0[i]))
  115. OPCODE_CASE(ACOS, acos(src0[i]))
  116. OPCODE_CASE(ATAN, atan(src0[i]))
  117. OPCODE_CASE(MIN, (src0[i] < src1[i]) ? src0[i] : src1[i])
  118. OPCODE_CASE(MAX, (src0[i] > src1[i]) ? src0[i] : src1[i])
  119. OPCODE_CASE(LT, (src0[i] < src1[i]) ? 1.0 : 0.0)
  120. OPCODE_CASE(GE, (src0[i] >= src1[i]) ? 1.0 : 0.0)
  121. OPCODE_CASE(ADD, src0[i] + src1[i])
  122. OPCODE_CASE(MUL, src0[i] * src1[i])
  123. OPCODE_CASE(ATAN2, atan2(src0[i], src1[i]))
  124. OPCODE_CASE(DIV, src0[i] / src1[i])
  125. OPCODE_CASE(CMP, (src0[i] >= 0.0) ? src1[i] : src2[i])
  126. //OPCODE_CASE(NOISE, ???) // !!! FIXME: don't know what this does
  127. //OPCODE_CASE(MOVC, ???) // !!! FIXME: don't know what this does
  128. OPCODE_CASE(MIN_SCALAR, (src0[0] < src1[i]) ? src0[0] : src1[i])
  129. OPCODE_CASE(MAX_SCALAR, (src0[0] > src1[i]) ? src0[0] : src1[i])
  130. OPCODE_CASE(LT_SCALAR, (src0[0] < src1[i]) ? 1.0 : 0.0)
  131. OPCODE_CASE(GE_SCALAR, (src0[0] >= src1[i]) ? 1.0 : 0.0)
  132. OPCODE_CASE(ADD_SCALAR, src0[0] + src1[i])
  133. OPCODE_CASE(MUL_SCALAR, src0[0] * src1[i])
  134. OPCODE_CASE(ATAN2_SCALAR, atan2(src0[0], src1[i]))
  135. OPCODE_CASE(DIV_SCALAR, src0[0] / src1[i])
  136. //OPCODE_CASE(DOT_SCALAR) // !!! FIXME: isn't this just a MUL?
  137. //OPCODE_CASE(NOISE_SCALAR, ???) // !!! FIXME: ?
  138. #undef OPCODE_CASE
  139. case MOJOSHADER_PRESHADEROP_DOT:
  140. {
  141. double final = 0.0;
  142. for (i = 0; i < elems; i++)
  143. final += src0[i] * src1[i];
  144. for (i = 0; i < elems; i++)
  145. dst[i] = final; // !!! FIXME: is this right?
  146. } // case
  147. default:
  148. assert(0 && "Unhandled preshader opcode!");
  149. break;
  150. } // switch
  151. // Figure out where dst wants to be stored.
  152. if (operand->type == MOJOSHADER_PRESHADEROPERAND_TEMP)
  153. {
  154. assert(preshader->temp_count >=
  155. operand->index + (elemsbytes / sizeof (double)));
  156. memcpy(temps + operand->index, dst, elemsbytes);
  157. } // if
  158. else
  159. {
  160. assert(operand->type == MOJOSHADER_PRESHADEROPERAND_OUTPUT);
  161. for (i = 0; i < elems; i++)
  162. outregs[operand->index + i] = (float) dst[i];
  163. } // else
  164. } // for
  165. } // MOJOSHADER_runPreshader
  166. #endif
  167. static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
  168. 1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  169. };
  170. static uint32 readui32(const uint8 **_ptr, uint32 *_len)
  171. {
  172. uint32 retval = 0;
  173. if (*_len < sizeof (retval))
  174. *_len = 0;
  175. else
  176. {
  177. const uint32 *ptr = (const uint32 *) *_ptr;
  178. retval = SWAP32(*ptr);
  179. *_ptr += sizeof (retval);
  180. *_len -= sizeof (retval);
  181. } // else
  182. return retval;
  183. } // readui32
  184. // !!! FIXME: this is sort of a big, ugly function.
  185. const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
  186. const unsigned char *buf,
  187. const unsigned int _len,
  188. const MOJOSHADER_swizzle *swiz,
  189. const unsigned int swizcount,
  190. const MOJOSHADER_samplerMap *smap,
  191. const unsigned int smapcount,
  192. MOJOSHADER_malloc m,
  193. MOJOSHADER_free f,
  194. void *d)
  195. {
  196. if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
  197. return &MOJOSHADER_out_of_mem_effect; // supply both or neither.
  198. if (m == NULL) m = MOJOSHADER_internal_malloc;
  199. if (f == NULL) f = MOJOSHADER_internal_free;
  200. MOJOSHADER_effect *retval = (MOJOSHADER_effect *)m(sizeof (MOJOSHADER_effect), d);
  201. if (retval == NULL)
  202. return &MOJOSHADER_out_of_mem_effect; // supply both or neither.
  203. memset(retval, '\0', sizeof (*retval));
  204. retval->malloc = m;
  205. retval->free = f;
  206. retval->malloc_data = d;
  207. const uint8 *ptr = (const uint8 *) buf;
  208. uint32 len = (uint32) _len;
  209. size_t siz = 0;
  210. int i, j, k;
  211. if (len < 8)
  212. goto parseEffect_unexpectedEOF;
  213. const uint8 *base = NULL;
  214. if (readui32(&ptr, &len) != 0xFEFF0901) // !!! FIXME: is this always magic?
  215. goto parseEffect_notAnEffectsFile;
  216. else
  217. {
  218. const uint32 offset = readui32(&ptr, &len);
  219. base = ptr;
  220. //printf("base offset == %u\n", offset);
  221. if (offset > len)
  222. goto parseEffect_unexpectedEOF;
  223. ptr += offset;
  224. len -= offset;
  225. } // else
  226. // params...
  227. if (len < 16)
  228. goto parseEffect_unexpectedEOF;
  229. const uint32 numparams = readui32(&ptr, &len);
  230. const uint32 numtechniques = readui32(&ptr, &len);
  231. readui32(&ptr, &len); // !!! FIXME: there are 8 unknown bytes here. Annotations?
  232. /*const uint32 numobjects = */ readui32(&ptr, &len);
  233. if (numparams > 0)
  234. {
  235. siz = sizeof (MOJOSHADER_effectParam) * numparams;
  236. retval->params = (MOJOSHADER_effectParam *) m(siz, d);
  237. if (retval->params == NULL)
  238. goto parseEffect_outOfMemory;
  239. memset(retval->params, '\0', siz);
  240. retval->param_count = numparams;
  241. for (i = 0; i < numparams; i++)
  242. {
  243. if (len < 16)
  244. goto parseEffect_unexpectedEOF;
  245. const uint32 typeoffset = readui32(&ptr, &len);
  246. /*const uint32 valoffset =*/ readui32(&ptr, &len);
  247. /*const uint32 flags =*/ readui32(&ptr, &len);
  248. const uint32 numannos = readui32(&ptr, &len);
  249. for (j = 0; j < numannos; j++)
  250. {
  251. if (len < 8)
  252. goto parseEffect_unexpectedEOF;
  253. // !!! FIXME: parse annotations.
  254. readui32(&ptr, &len);
  255. readui32(&ptr, &len);
  256. } // for
  257. const uint8 *typeptr = base + typeoffset;
  258. unsigned int typelen = 9999999; // !!! FIXME
  259. /*const uint32 paramtype =*/ readui32(&typeptr, &typelen);
  260. /*const uint32 paramclass =*/ readui32(&typeptr, &typelen);
  261. const uint32 paramname = readui32(&typeptr, &typelen);
  262. const uint32 paramsemantic = readui32(&typeptr, &typelen);
  263. // !!! FIXME: sanity checks!
  264. const char *namestr = ((const char *) base) + paramname;
  265. const char *semstr = ((const char *) base) + paramsemantic;
  266. uint32 len;
  267. char *strptr;
  268. len = *((const uint32 *) namestr);
  269. strptr = (char *) m(len + 1, d);
  270. memcpy(strptr, namestr + 4, len);
  271. strptr[len] = '\0';
  272. retval->params[i].name = strptr;
  273. len = *((const uint32 *) semstr);
  274. strptr = (char *) m(len + 1, d);
  275. memcpy(strptr, semstr + 4, len);
  276. strptr[len] = '\0';
  277. retval->params[i].semantic = strptr;
  278. } // for
  279. } // if
  280. uint32 numshaders = 0; // we'll calculate this later.
  281. // techniques...
  282. if (numtechniques > 0)
  283. {
  284. siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
  285. retval->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
  286. if (retval->techniques == NULL)
  287. goto parseEffect_outOfMemory;
  288. memset(retval->techniques, '\0', siz);
  289. retval->technique_count = numtechniques;
  290. for (i = 0; i < numtechniques; i++)
  291. {
  292. if (len < 12)
  293. goto parseEffect_unexpectedEOF;
  294. MOJOSHADER_effectTechnique *technique = &retval->techniques[i];
  295. const uint32 nameoffset = readui32(&ptr, &len);
  296. const uint32 numannos = readui32(&ptr, &len);
  297. const uint32 numpasses = readui32(&ptr, &len);
  298. if (nameoffset >= _len)
  299. goto parseEffect_unexpectedEOF;
  300. if (numannos > 0)
  301. {
  302. // !!! FIXME: expose these to the caller?
  303. for (j = 0; j < numannos; j++)
  304. {
  305. if (len < 8)
  306. goto parseEffect_unexpectedEOF;
  307. readui32(&ptr, &len); // typedef offset
  308. readui32(&ptr, &len); // value offset
  309. } // for
  310. } // if
  311. // !!! FIXME: verify this doesn't go past EOF looking for a null.
  312. {
  313. const char *namestr = ((char *) base) + nameoffset;
  314. uint32 len = *((const uint32 *) namestr);
  315. char *strptr = (char *) m(len + 1, d);
  316. memcpy(strptr, namestr + 4, len);
  317. strptr[len] = '\0';
  318. technique->name = strptr;
  319. }
  320. if (numpasses > 0)
  321. {
  322. technique->pass_count = numpasses;
  323. siz = sizeof (MOJOSHADER_effectPass) * numpasses;
  324. technique->passes = (MOJOSHADER_effectPass *) m(siz, d);
  325. if (technique->passes == NULL)
  326. goto parseEffect_outOfMemory;
  327. memset(technique->passes, '\0', siz);
  328. for (j = 0; j < numpasses; j++)
  329. {
  330. if (len < 12)
  331. goto parseEffect_unexpectedEOF;
  332. MOJOSHADER_effectPass *pass = &technique->passes[j];
  333. const uint32 passnameoffset = readui32(&ptr, &len);
  334. const uint32 numannos = readui32(&ptr, &len);
  335. const uint32 numstates = readui32(&ptr, &len);
  336. if (passnameoffset >= _len)
  337. goto parseEffect_unexpectedEOF;
  338. // !!! FIXME: verify this doesn't go past EOF looking for a null.
  339. {
  340. const char *namestr = ((char *) base) + passnameoffset;
  341. uint32 len = *((const uint32 *) namestr);
  342. char *strptr = (char *) m(len + 1, d);
  343. memcpy(strptr, namestr + 4, len);
  344. strptr[len] = '\0';
  345. pass->name = strptr;
  346. }
  347. if (numannos > 0)
  348. {
  349. for (k = 0; k < numannos; k++)
  350. {
  351. if (len < 8)
  352. goto parseEffect_unexpectedEOF;
  353. // !!! FIXME: do something with this.
  354. readui32(&ptr, &len);
  355. readui32(&ptr, &len);
  356. } // for
  357. } // if
  358. if (numstates > 0)
  359. {
  360. pass->state_count = numstates;
  361. siz = sizeof (MOJOSHADER_effectState) * numstates;
  362. pass->states = (MOJOSHADER_effectState *) m(siz, d);
  363. if (pass->states == NULL)
  364. goto parseEffect_outOfMemory;
  365. memset(pass->states, '\0', siz);
  366. for (k = 0; k < numstates; k++)
  367. {
  368. if (len < 16)
  369. goto parseEffect_unexpectedEOF;
  370. MOJOSHADER_effectState *state = &pass->states[k];
  371. const uint32 type = readui32(&ptr, &len);
  372. readui32(&ptr, &len); // !!! FIXME: don't know what this field does.
  373. /*const uint32 offsetend = */ readui32(&ptr, &len);
  374. /*const uint32 offsetstart = */ readui32(&ptr, &len);
  375. state->type = type;
  376. if ((type == 0x92) || (type == 0x93))
  377. numshaders++;
  378. } // for
  379. } // if
  380. } // for
  381. } // if
  382. } // for
  383. } // if
  384. // textures...
  385. if (len < 8)
  386. goto parseEffect_unexpectedEOF;
  387. const int numtextures = readui32(&ptr, &len);
  388. const int numobjects = readui32(&ptr, &len); // !!! FIXME: "objects" for lack of a better word.
  389. if (numtextures > 0)
  390. {
  391. siz = sizeof (MOJOSHADER_effectTexture) * numtextures;
  392. retval->textures = (MOJOSHADER_effectTexture *)m(siz, d);
  393. if (retval->textures == NULL)
  394. goto parseEffect_outOfMemory;
  395. memset(retval->textures, '\0', siz);
  396. for (i = 0; i < numtextures; i++)
  397. {
  398. if (len < 8)
  399. goto parseEffect_unexpectedEOF;
  400. MOJOSHADER_effectTexture *texture = &retval->textures[i];
  401. const uint32 texparam = readui32(&ptr, &len);
  402. const uint32 texsize = readui32(&ptr, &len);
  403. // apparently texsize will pad out to 32 bits.
  404. const uint32 readsize = (((texsize + 3) / 4) * 4);
  405. if (len < readsize)
  406. goto parseEffect_unexpectedEOF;
  407. texture->param = texparam;
  408. char *str = (char *)m(texsize + 1, d);
  409. if (str == NULL)
  410. goto parseEffect_outOfMemory;
  411. memcpy(str, ptr, texsize);
  412. str[texsize] = '\0';
  413. texture->name = str;
  414. ptr += readsize;
  415. len -= readsize;
  416. } // for
  417. } // if
  418. // shaders...
  419. if (numshaders > 0)
  420. {
  421. siz = sizeof (MOJOSHADER_effectShader) * numshaders;
  422. retval->shaders = (MOJOSHADER_effectShader *) m(siz, d);
  423. if (retval->shaders == NULL)
  424. goto parseEffect_outOfMemory;
  425. memset(retval->shaders, '\0', siz);
  426. retval->shader_count = numshaders;
  427. // !!! FIXME: I wonder if we should pull these from offsets and not
  428. // !!! FIXME: count on them all being in a line like this.
  429. for (i = 0; i < numshaders; i++)
  430. {
  431. if (len < 24)
  432. goto parseEffect_unexpectedEOF;
  433. MOJOSHADER_effectShader *shader = &retval->shaders[i];
  434. const uint32 technique = readui32(&ptr, &len);
  435. const uint32 pass = readui32(&ptr, &len);
  436. readui32(&ptr, &len); // !!! FIXME: don't know what this does.
  437. readui32(&ptr, &len); // !!! FIXME: don't know what this does (vertex/pixel/geometry?)
  438. readui32(&ptr, &len); // !!! FIXME: don't know what this does.
  439. const uint32 shadersize = readui32(&ptr, &len);
  440. if (len < shadersize)
  441. goto parseEffect_unexpectedEOF;
  442. shader->technique = technique;
  443. shader->pass = pass;
  444. shader->shader = MOJOSHADER_parse(profile, ptr, shadersize,
  445. swiz, swizcount, smap, smapcount,
  446. m, f, d);
  447. // !!! FIXME: check for errors.
  448. ptr += shadersize;
  449. len -= shadersize;
  450. } // for
  451. } // if
  452. // !!! FIXME: we parse this, but don't expose the data, yet.
  453. // mappings ...
  454. assert(numshaders <= numobjects);
  455. const uint32 nummappings = numobjects - numshaders;
  456. if (nummappings > 0)
  457. {
  458. for (i = 0; i < nummappings; i++)
  459. {
  460. if (len < 24)
  461. goto parseEffect_unexpectedEOF;
  462. /*const uint32 magic = */ readui32(&ptr, &len);
  463. /*const uint32 index = */ readui32(&ptr, &len);
  464. readui32(&ptr, &len); // !!! FIXME: what is this field?
  465. readui32(&ptr, &len); // !!! FIXME: what is this field?
  466. /*const uint32 type = */ readui32(&ptr, &len);
  467. const uint32 mapsize = readui32(&ptr, &len);
  468. if (mapsize > 0)
  469. {
  470. const uint32 readsize = (((mapsize + 3) / 4) * 4);
  471. if (len < readsize)
  472. goto parseEffect_unexpectedEOF;
  473. } // if
  474. } // for
  475. } // if
  476. retval->profile = (char *) m(strlen(profile) + 1, d);
  477. if (retval->profile == NULL)
  478. goto parseEffect_outOfMemory;
  479. strcpy((char *) retval->profile, profile);
  480. return retval;
  481. // !!! FIXME: do something with this.
  482. parseEffect_notAnEffectsFile:
  483. parseEffect_unexpectedEOF:
  484. parseEffect_outOfMemory:
  485. MOJOSHADER_freeEffect(retval);
  486. return &MOJOSHADER_out_of_mem_effect;
  487. } // MOJOSHADER_parseEffect
  488. void MOJOSHADER_freeEffect(const MOJOSHADER_effect *_effect)
  489. {
  490. MOJOSHADER_effect *effect = (MOJOSHADER_effect *) _effect;
  491. if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
  492. return; // no-op.
  493. MOJOSHADER_free f = effect->free;
  494. void *d = effect->malloc_data;
  495. int i, j;
  496. for (i = 0; i < effect->error_count; i++)
  497. {
  498. f((void *) effect->errors[i].error, d);
  499. f((void *) effect->errors[i].filename, d);
  500. } // for
  501. f((void *) effect->errors, d);
  502. f((void *) effect->profile, d);
  503. for (i = 0; i < effect->param_count; i++)
  504. {
  505. f((void *) effect->params[i].name, d);
  506. f((void *) effect->params[i].semantic, d);
  507. } // for
  508. f(effect->params, d);
  509. for (i = 0; i < effect->technique_count; i++)
  510. {
  511. MOJOSHADER_effectTechnique *technique = &effect->techniques[i];
  512. f((void *) technique->name, d);
  513. for (j = 0; j < technique->pass_count; j++)
  514. {
  515. f((void *) technique->passes[j].name, d);
  516. f(technique->passes[j].states, d);
  517. } // for
  518. f(technique->passes, d);
  519. } // for
  520. f(effect->techniques, d);
  521. for (i = 0; i < effect->texture_count; i++)
  522. f((void *) effect->textures[i].name, d);
  523. f(effect->textures, d);
  524. for (i = 0; i < effect->shader_count; i++)
  525. MOJOSHADER_freeParseData(effect->shaders[i].shader);
  526. f(effect->shaders, d);
  527. f(effect, d);
  528. } // MOJOSHADER_freeEffect
  529. // end of mojoshader_effects.c ...