MAT.C 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /******************************************************************************
  2. Plush Version 1.2
  3. mat.c
  4. Material Control
  5. Copyright (c) 1996-2000, Justin Frankel
  6. ******************************************************************************/
  7. #include "plush.h"
  8. static void _plGenerateSinglePalette(pl_Mat *);
  9. static void _plGeneratePhongPalette(pl_Mat *);
  10. static void _plGenerateTextureEnvPalette(pl_Mat *);
  11. static void _plGenerateTexturePalette(pl_Mat *, pl_Texture *);
  12. static void _plGeneratePhongTexturePalette(pl_Mat *, pl_Texture *);
  13. static void _plGeneratePhongTransparentPalette(pl_Mat *m);
  14. static void _plGenerateTransparentPalette(pl_Mat *);
  15. static void _plSetMaterialPutFace(pl_Mat *m);
  16. static void _plMatSetupTransparent(pl_Mat *m, pl_uChar *pal);
  17. pl_Mat *plMatCreate() {
  18. pl_Mat *m;
  19. m = (pl_Mat *) malloc(sizeof(pl_Mat));
  20. if (!m) return 0;
  21. memset(m,0,sizeof(pl_Mat));
  22. m->EnvScaling = 1.0f;
  23. m->TexScaling = 1.0f;
  24. m->Ambient[0] = m->Ambient[1] = m->Ambient[2] = 0;
  25. m->Diffuse[0] = m->Diffuse[1] = m->Diffuse[2] = 128;
  26. m->Specular[0] = m->Specular[1] = m->Specular[2] = 128;
  27. m->Shininess = 4;
  28. m->NumGradients = 32;
  29. m->FadeDist = 1000.0;
  30. m->zBufferable = 1;
  31. return m;
  32. }
  33. void plMatDelete(pl_Mat *m) {
  34. if (m) {
  35. if (m->_ReMapTable) free(m->_ReMapTable);
  36. if (m->_RequestedColors) free(m->_RequestedColors);
  37. if (m->_AddTable) free(m->_AddTable);
  38. free(m);
  39. }
  40. }
  41. void plMatInit(pl_Mat *m) {
  42. if (m->Shininess < 1) m->Shininess = 1;
  43. m->_ft = ((m->Environment ? PL_FILL_ENVIRONMENT : 0) |
  44. (m->Texture ? PL_FILL_TEXTURE : 0));
  45. m->_st = m->ShadeType;
  46. if (m->Transparent) m->_ft = PL_FILL_TRANSPARENT;
  47. if (m->_ft == (PL_FILL_TEXTURE|PL_FILL_ENVIRONMENT))
  48. m->_st = PL_SHADE_NONE;
  49. if (m->_ft == PL_FILL_SOLID) {
  50. if (m->_st == PL_SHADE_NONE) _plGenerateSinglePalette(m);
  51. else _plGeneratePhongPalette(m);
  52. } else if (m->_ft == PL_FILL_TEXTURE) {
  53. if (m->_st == PL_SHADE_NONE)
  54. _plGenerateTexturePalette(m,m->Texture);
  55. else _plGeneratePhongTexturePalette(m,m->Texture);
  56. } else if (m->_ft == PL_FILL_ENVIRONMENT) {
  57. if (m->_st == PL_SHADE_NONE)
  58. _plGenerateTexturePalette(m,m->Environment);
  59. else _plGeneratePhongTexturePalette(m,m->Environment);
  60. } else if (m->_ft == (PL_FILL_ENVIRONMENT|PL_FILL_TEXTURE))
  61. _plGenerateTextureEnvPalette(m);
  62. else if (m->_ft == PL_FILL_TRANSPARENT) {
  63. if (m->_st == PL_SHADE_NONE) _plGenerateTransparentPalette(m);
  64. else _plGeneratePhongTransparentPalette(m);
  65. }
  66. _plSetMaterialPutFace(m);
  67. }
  68. static void _plMatSetupTransparent(pl_Mat *m, pl_uChar *pal) {
  69. pl_uInt x, intensity;
  70. if (m->Transparent)
  71. {
  72. if (m->_AddTable) free(m->_AddTable);
  73. m->_AddTable = (pl_uInt16 *) malloc(256*sizeof(pl_uInt16));
  74. for (x = 0; x < 256; x ++) {
  75. intensity = *pal++;
  76. intensity += *pal++;
  77. intensity += *pal++;
  78. m->_AddTable[x] = ((intensity*(m->_ColorsUsed-m->_tsfact))/768);
  79. }
  80. }
  81. }
  82. void plMatMapToPal(pl_Mat *m, pl_uChar *pal, pl_sInt pstart, pl_sInt pend) {
  83. pl_sInt32 j, r, g, b, bestdiff, r2, g2, b2;
  84. pl_sInt bestpos,k;
  85. pl_uInt32 i;
  86. pl_uChar *p;
  87. if (!m->_RequestedColors) plMatInit(m);
  88. if (!m->_RequestedColors) return;
  89. if (m->_ReMapTable) free(m->_ReMapTable);
  90. m->_ReMapTable = (pl_uChar *) malloc(m->_ColorsUsed);
  91. for (i = 0; i < m->_ColorsUsed; i ++) {
  92. bestdiff = 1000000000;
  93. bestpos = pstart;
  94. r = m->_RequestedColors[i*3];
  95. g = m->_RequestedColors[i*3+1];
  96. b = m->_RequestedColors[i*3+2];
  97. p = pal + pstart*3;
  98. for (k = pstart; k <= (pl_sInt)pend; k ++) {
  99. r2 = p[0] - r;
  100. g2 = p[1] - g;
  101. b2 = p[2] - b;
  102. p += 3;
  103. j = r2*r2+g2*g2+b2*b2;
  104. if (j < bestdiff) {
  105. bestdiff = j;
  106. bestpos = k;
  107. }
  108. }
  109. m->_ReMapTable[i] = bestpos;
  110. }
  111. _plMatSetupTransparent(m,pal);
  112. }
  113. static void _plGenerateSinglePalette(pl_Mat *m) {
  114. m->_ColorsUsed = 1;
  115. if (m->_RequestedColors) free(m->_RequestedColors);
  116. m->_RequestedColors = (pl_uChar *) malloc(3);
  117. m->_RequestedColors[0] = plMin(plMax(m->Ambient[0],0),255);
  118. m->_RequestedColors[1] = plMin(plMax(m->Ambient[1],0),255);
  119. m->_RequestedColors[2] = plMin(plMax(m->Ambient[2],0),255);
  120. }
  121. static void _plGeneratePhongPalette(pl_Mat *m) {
  122. pl_uInt i = m->NumGradients, x;
  123. pl_sInt c;
  124. pl_uChar *pal;
  125. double a, da, ca, cb;
  126. m->_ColorsUsed = m->NumGradients;
  127. if (m->_RequestedColors) free(m->_RequestedColors);
  128. pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
  129. a = PL_PI/2.0;
  130. if (m->NumGradients > 1) da = -PL_PI/((m->NumGradients-1)<<1);
  131. else da=0.0;
  132. do {
  133. if (m->NumGradients == 1) ca = 1;
  134. else {
  135. ca = cos((double) a);
  136. a += da;
  137. }
  138. cb = pow((double) ca, (double) m->Shininess);
  139. for (x = 0; x < 3; x ++) {
  140. c = (pl_sInt) ((cb*m->Specular[x])+(ca*m->Diffuse[x])+m->Ambient[x]);
  141. *(pal++) = plMax(0,plMin(c,255));
  142. }
  143. } while (--i);
  144. }
  145. static void _plGenerateTextureEnvPalette(pl_Mat *m) {
  146. pl_sInt c;
  147. pl_uInt whichlevel,whichindex;
  148. pl_uChar *texpal, *envpal, *pal;
  149. m->_ColorsUsed = m->Texture->NumColors*m->Environment->NumColors;
  150. if (m->_RequestedColors) free(m->_RequestedColors);
  151. pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
  152. envpal = m->Environment->PaletteData;
  153. if (m->_AddTable) free(m->_AddTable);
  154. m->_AddTable = (pl_uInt16 *) malloc(m->Environment->NumColors*sizeof(pl_uInt16));
  155. for (whichlevel = 0; whichlevel < m->Environment->NumColors; whichlevel++) {
  156. texpal = m->Texture->PaletteData;
  157. switch (m->TexEnvMode)
  158. {
  159. case PL_TEXENV_MUL: // multiply
  160. for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
  161. *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[0])>>8);
  162. *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[1])>>8);
  163. *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[2])>>8);
  164. }
  165. break;
  166. case PL_TEXENV_AVG: // average
  167. for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
  168. *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[0])>>1);
  169. *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[1])>>1);
  170. *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[2])>>1);
  171. }
  172. break;
  173. case PL_TEXENV_TEXMINUSENV: // tex-env
  174. for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
  175. c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
  176. c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
  177. c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
  178. }
  179. break;
  180. case PL_TEXENV_ENVMINUSTEX: // env-tex
  181. for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
  182. c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
  183. c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
  184. c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
  185. }
  186. break;
  187. case PL_TEXENV_MIN:
  188. for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
  189. *pal++ = plMin(texpal[0],envpal[0]);
  190. *pal++ = plMin(texpal[1],envpal[1]);
  191. *pal++ = plMin(texpal[2],envpal[2]);
  192. texpal+=3;
  193. }
  194. break;
  195. case PL_TEXENV_MAX:
  196. break;
  197. for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
  198. *pal++ = plMax(texpal[0],envpal[0]);
  199. *pal++ = plMax(texpal[1],envpal[1]);
  200. *pal++ = plMax(texpal[2],envpal[2]);
  201. texpal+=3;
  202. }
  203. default: // add
  204. for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
  205. c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
  206. c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
  207. c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
  208. }
  209. break;
  210. }
  211. envpal += 3;
  212. m->_AddTable[whichlevel] = whichlevel*m->Texture->NumColors;
  213. }
  214. }
  215. static void _plGenerateTexturePalette(pl_Mat *m, pl_Texture *t) {
  216. pl_uChar *ppal, *pal;
  217. pl_sInt c, i, x;
  218. m->_ColorsUsed = t->NumColors;
  219. if (m->_RequestedColors) free(m->_RequestedColors);
  220. pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
  221. ppal = t->PaletteData;
  222. i = t->NumColors;
  223. do {
  224. for (x = 0; x < 3; x ++) {
  225. c = m->Ambient[x] + *ppal++;
  226. *(pal++) = plMax(0,plMin(c,255));
  227. }
  228. } while (--i);
  229. }
  230. static void _plGeneratePhongTexturePalette(pl_Mat *m, pl_Texture *t) {
  231. double a, ca, da, cb;
  232. pl_uInt16 *addtable;
  233. pl_uChar *ppal, *pal;
  234. pl_sInt c, i, i2, x;
  235. pl_uInt num_shades;
  236. if (t->NumColors) num_shades = (m->NumGradients / t->NumColors);
  237. else num_shades=1;
  238. if (!num_shades) num_shades = 1;
  239. m->_ColorsUsed = num_shades*t->NumColors;
  240. if (m->_RequestedColors) free(m->_RequestedColors);
  241. pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
  242. a = PL_PI/2.0;
  243. if (num_shades>1) da = (-PL_PI/2.0)/(num_shades-1);
  244. else da=0.0;
  245. i2 = num_shades;
  246. do {
  247. ppal = t->PaletteData;
  248. ca = cos((double) a);
  249. a += da;
  250. cb = pow(ca, (double) m->Shininess);
  251. i = t->NumColors;
  252. do {
  253. for (x = 0; x < 3; x ++) {
  254. c = (pl_sInt) ((cb*m->Specular[x])+(ca*m->Diffuse[x])+m->Ambient[x] + *ppal++);
  255. *(pal++) = plMax(0,plMin(c,255));
  256. }
  257. } while (--i);
  258. } while (--i2);
  259. ca = 0;
  260. if (m->_AddTable) free(m->_AddTable);
  261. m->_AddTable = (pl_uInt16 *) malloc(256*sizeof(pl_uInt16));
  262. addtable = m->_AddTable;
  263. i = 256;
  264. do {
  265. a = sin(ca) * num_shades;
  266. ca += PL_PI/512.0;
  267. *addtable++ = ((pl_sInt) a)*t->NumColors;
  268. } while (--i);
  269. }
  270. static void _plGeneratePhongTransparentPalette(pl_Mat *m) {
  271. m->_tsfact = (pl_sInt) (m->NumGradients*(1.0/(1+m->Transparent)));
  272. _plGeneratePhongPalette(m);
  273. }
  274. static void _plGenerateTransparentPalette(pl_Mat *m) {
  275. m->_tsfact = 0;
  276. _plGeneratePhongPalette(m);
  277. }
  278. static void _plSetMaterialPutFace(pl_Mat *m) {
  279. m->_PutFace = 0;
  280. switch (m->_ft) {
  281. case PL_FILL_TRANSPARENT: switch(m->_st) {
  282. case PL_SHADE_NONE: case PL_SHADE_FLAT:
  283. case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
  284. m->_PutFace = plPF_TransF;
  285. break;
  286. case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
  287. case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
  288. m->_PutFace = plPF_TransG;
  289. break;
  290. }
  291. break;
  292. case PL_FILL_SOLID: switch(m->_st) {
  293. case PL_SHADE_NONE: case PL_SHADE_FLAT:
  294. case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
  295. m->_PutFace = plPF_SolidF;
  296. break;
  297. case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
  298. case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
  299. m->_PutFace = plPF_SolidG;
  300. break;
  301. }
  302. break;
  303. case PL_FILL_ENVIRONMENT:
  304. case PL_FILL_TEXTURE:
  305. if (m->PerspectiveCorrect) switch (m->_st) {
  306. case PL_SHADE_NONE: case PL_SHADE_FLAT:
  307. case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
  308. m->_PutFace = plPF_PTexF;
  309. break;
  310. case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
  311. case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
  312. m->_PutFace = plPF_PTexG;
  313. break;
  314. }
  315. else switch (m->_st) {
  316. case PL_SHADE_NONE: case PL_SHADE_FLAT:
  317. case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
  318. m->_PutFace = plPF_TexF;
  319. break;
  320. case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
  321. case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
  322. m->_PutFace = plPF_TexG;
  323. break;
  324. }
  325. break;
  326. case PL_FILL_TEXTURE|PL_FILL_ENVIRONMENT:
  327. m->_PutFace = plPF_TexEnv;
  328. break;
  329. }
  330. }
  331. typedef struct __ct {
  332. pl_uChar r,g,b;
  333. pl_Bool visited;
  334. struct __ct *next;
  335. } _ct;
  336. static int mdist(_ct *a, _ct *b) {
  337. return ((a->r-b->r)*(a->r-b->r)+(a->g-b->g)*(a->g-b->g)+(a->b-b->b)*(a->b-b->b));
  338. }
  339. void plMatMakeOptPal(pl_uChar *p, pl_sInt pstart,
  340. pl_sInt pend, pl_Mat **materials, pl_sInt nmats) {
  341. pl_uChar *allColors = 0;
  342. pl_sInt numColors = 0, nc, x;
  343. pl_sInt len = pend + 1 - pstart;
  344. pl_sInt32 current, newnext, bestdist, thisdist;
  345. _ct *colorBlock, *best, *cp;
  346. for (x = 0; x < nmats; x ++) {
  347. if (materials[x]) {
  348. if (!materials[x]->_RequestedColors) plMatInit(materials[x]);
  349. if (materials[x]->_RequestedColors) numColors+=materials[x]->_ColorsUsed;
  350. }
  351. }
  352. if (!numColors) return;
  353. allColors=(pl_uChar*)malloc(numColors*3);
  354. numColors=0;
  355. for (x = 0; x < nmats; x ++) {
  356. if (materials[x]) {
  357. if (materials[x]->_RequestedColors)
  358. memcpy(allColors + (numColors*3), materials[x]->_RequestedColors,
  359. materials[x]->_ColorsUsed*3);
  360. numColors += materials[x]->_ColorsUsed;
  361. }
  362. }
  363. if (numColors <= len) {
  364. memcpy(p+pstart*3,allColors,numColors*3);
  365. free(allColors);
  366. return;
  367. }
  368. colorBlock = (_ct *) malloc(sizeof(_ct)*numColors);
  369. for (x = 0; x < numColors; x++) {
  370. colorBlock[x].r = allColors[x*3];
  371. colorBlock[x].g = allColors[x*3+1];
  372. colorBlock[x].b = allColors[x*3+2];
  373. colorBlock[x].visited = 0;
  374. colorBlock[x].next = 0;
  375. }
  376. free(allColors);
  377. /* Build a list, starting at color 0 */
  378. current = 0;
  379. nc = numColors;
  380. do {
  381. newnext = -1;
  382. bestdist = 300000000;
  383. colorBlock[current].visited = 1;
  384. for (x = 0; x < nc; x ++) {
  385. if (!colorBlock[x].visited) {
  386. thisdist = mdist(colorBlock + x, colorBlock + current);
  387. if (thisdist < 5) { colorBlock[x].visited = 1; numColors--; }
  388. else if (thisdist < bestdist) { bestdist = thisdist; newnext = x; }
  389. }
  390. }
  391. if (newnext != -1) {
  392. colorBlock[current].next = colorBlock + newnext;
  393. current = newnext;
  394. }
  395. } while (newnext != -1);
  396. colorBlock[current].next = 0; /* terminate the list */
  397. /* we now have a linked list starting at colorBlock, which is each one and
  398. it's closest neighbor */
  399. while (numColors > len) {
  400. bestdist = mdist(colorBlock,colorBlock->next);
  401. for (best = cp = colorBlock; cp->next; cp = cp->next) {
  402. if (bestdist > (thisdist = mdist(cp,cp->next))) {
  403. best = cp;
  404. bestdist = thisdist;
  405. }
  406. }
  407. best->r = ((int) best->r + (int) best->next->r)>>1;
  408. best->g = ((int) best->g + (int) best->next->g)>>1;
  409. best->b = ((int) best->b + (int) best->next->b)>>1;
  410. best->next = best->next->next;
  411. numColors--;
  412. }
  413. x = pstart*3;
  414. for (cp = colorBlock; cp; cp = cp->next) {
  415. p[x++] = cp->r;
  416. p[x++] = cp->g;
  417. p[x++] = cp->b;
  418. }
  419. free(colorBlock);
  420. }