123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- /******************************************************************************
- Plush Version 1.2
- mat.c
- Material Control
- Copyright (c) 1996-2000, Justin Frankel
- ******************************************************************************/
- #include "plush.h"
- static void _plGenerateSinglePalette(pl_Mat *);
- static void _plGeneratePhongPalette(pl_Mat *);
- static void _plGenerateTextureEnvPalette(pl_Mat *);
- static void _plGenerateTexturePalette(pl_Mat *, pl_Texture *);
- static void _plGeneratePhongTexturePalette(pl_Mat *, pl_Texture *);
- static void _plGeneratePhongTransparentPalette(pl_Mat *m);
- static void _plGenerateTransparentPalette(pl_Mat *);
- static void _plSetMaterialPutFace(pl_Mat *m);
- static void _plMatSetupTransparent(pl_Mat *m, pl_uChar *pal);
- pl_Mat *plMatCreate() {
- pl_Mat *m;
- m = (pl_Mat *) malloc(sizeof(pl_Mat));
- if (!m) return 0;
- memset(m,0,sizeof(pl_Mat));
- m->EnvScaling = 1.0f;
- m->TexScaling = 1.0f;
- m->Ambient[0] = m->Ambient[1] = m->Ambient[2] = 0;
- m->Diffuse[0] = m->Diffuse[1] = m->Diffuse[2] = 128;
- m->Specular[0] = m->Specular[1] = m->Specular[2] = 128;
- m->Shininess = 4;
- m->NumGradients = 32;
- m->FadeDist = 1000.0;
- m->zBufferable = 1;
- return m;
- }
- void plMatDelete(pl_Mat *m) {
- if (m) {
- if (m->_ReMapTable) free(m->_ReMapTable);
- if (m->_RequestedColors) free(m->_RequestedColors);
- if (m->_AddTable) free(m->_AddTable);
- free(m);
- }
- }
- void plMatInit(pl_Mat *m) {
- if (m->Shininess < 1) m->Shininess = 1;
- m->_ft = ((m->Environment ? PL_FILL_ENVIRONMENT : 0) |
- (m->Texture ? PL_FILL_TEXTURE : 0));
- m->_st = m->ShadeType;
- if (m->Transparent) m->_ft = PL_FILL_TRANSPARENT;
- if (m->_ft == (PL_FILL_TEXTURE|PL_FILL_ENVIRONMENT))
- m->_st = PL_SHADE_NONE;
- if (m->_ft == PL_FILL_SOLID) {
- if (m->_st == PL_SHADE_NONE) _plGenerateSinglePalette(m);
- else _plGeneratePhongPalette(m);
- } else if (m->_ft == PL_FILL_TEXTURE) {
- if (m->_st == PL_SHADE_NONE)
- _plGenerateTexturePalette(m,m->Texture);
- else _plGeneratePhongTexturePalette(m,m->Texture);
- } else if (m->_ft == PL_FILL_ENVIRONMENT) {
- if (m->_st == PL_SHADE_NONE)
- _plGenerateTexturePalette(m,m->Environment);
- else _plGeneratePhongTexturePalette(m,m->Environment);
- } else if (m->_ft == (PL_FILL_ENVIRONMENT|PL_FILL_TEXTURE))
- _plGenerateTextureEnvPalette(m);
- else if (m->_ft == PL_FILL_TRANSPARENT) {
- if (m->_st == PL_SHADE_NONE) _plGenerateTransparentPalette(m);
- else _plGeneratePhongTransparentPalette(m);
- }
- _plSetMaterialPutFace(m);
- }
- static void _plMatSetupTransparent(pl_Mat *m, pl_uChar *pal) {
- pl_uInt x, intensity;
- if (m->Transparent)
- {
- if (m->_AddTable) free(m->_AddTable);
- m->_AddTable = (pl_uInt16 *) malloc(256*sizeof(pl_uInt16));
- for (x = 0; x < 256; x ++) {
- intensity = *pal++;
- intensity += *pal++;
- intensity += *pal++;
- m->_AddTable[x] = ((intensity*(m->_ColorsUsed-m->_tsfact))/768);
- }
- }
- }
- void plMatMapToPal(pl_Mat *m, pl_uChar *pal, pl_sInt pstart, pl_sInt pend) {
- pl_sInt32 j, r, g, b, bestdiff, r2, g2, b2;
- pl_sInt bestpos,k;
- pl_uInt32 i;
- pl_uChar *p;
- if (!m->_RequestedColors) plMatInit(m);
- if (!m->_RequestedColors) return;
- if (m->_ReMapTable) free(m->_ReMapTable);
- m->_ReMapTable = (pl_uChar *) malloc(m->_ColorsUsed);
- for (i = 0; i < m->_ColorsUsed; i ++) {
- bestdiff = 1000000000;
- bestpos = pstart;
- r = m->_RequestedColors[i*3];
- g = m->_RequestedColors[i*3+1];
- b = m->_RequestedColors[i*3+2];
- p = pal + pstart*3;
- for (k = pstart; k <= (pl_sInt)pend; k ++) {
- r2 = p[0] - r;
- g2 = p[1] - g;
- b2 = p[2] - b;
- p += 3;
- j = r2*r2+g2*g2+b2*b2;
- if (j < bestdiff) {
- bestdiff = j;
- bestpos = k;
- }
- }
- m->_ReMapTable[i] = bestpos;
- }
- _plMatSetupTransparent(m,pal);
- }
- static void _plGenerateSinglePalette(pl_Mat *m) {
- m->_ColorsUsed = 1;
- if (m->_RequestedColors) free(m->_RequestedColors);
- m->_RequestedColors = (pl_uChar *) malloc(3);
- m->_RequestedColors[0] = plMin(plMax(m->Ambient[0],0),255);
- m->_RequestedColors[1] = plMin(plMax(m->Ambient[1],0),255);
- m->_RequestedColors[2] = plMin(plMax(m->Ambient[2],0),255);
- }
- static void _plGeneratePhongPalette(pl_Mat *m) {
- pl_uInt i = m->NumGradients, x;
- pl_sInt c;
- pl_uChar *pal;
- double a, da, ca, cb;
- m->_ColorsUsed = m->NumGradients;
- if (m->_RequestedColors) free(m->_RequestedColors);
- pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
- a = PL_PI/2.0;
- if (m->NumGradients > 1) da = -PL_PI/((m->NumGradients-1)<<1);
- else da=0.0;
- do {
- if (m->NumGradients == 1) ca = 1;
- else {
- ca = cos((double) a);
- a += da;
- }
- cb = pow((double) ca, (double) m->Shininess);
- for (x = 0; x < 3; x ++) {
- c = (pl_sInt) ((cb*m->Specular[x])+(ca*m->Diffuse[x])+m->Ambient[x]);
- *(pal++) = plMax(0,plMin(c,255));
- }
- } while (--i);
- }
- static void _plGenerateTextureEnvPalette(pl_Mat *m) {
- pl_sInt c;
- pl_uInt whichlevel,whichindex;
- pl_uChar *texpal, *envpal, *pal;
- m->_ColorsUsed = m->Texture->NumColors*m->Environment->NumColors;
- if (m->_RequestedColors) free(m->_RequestedColors);
- pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
- envpal = m->Environment->PaletteData;
- if (m->_AddTable) free(m->_AddTable);
- m->_AddTable = (pl_uInt16 *) malloc(m->Environment->NumColors*sizeof(pl_uInt16));
- for (whichlevel = 0; whichlevel < m->Environment->NumColors; whichlevel++) {
- texpal = m->Texture->PaletteData;
- switch (m->TexEnvMode)
- {
- case PL_TEXENV_MUL: // multiply
- for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
- *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[0])>>8);
- *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[1])>>8);
- *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) * (pl_sInt) envpal[2])>>8);
- }
- break;
- case PL_TEXENV_AVG: // average
- for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
- *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[0])>>1);
- *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[1])>>1);
- *pal++ = (pl_uChar) (((pl_sInt) (*texpal++) + (pl_sInt) envpal[2])>>1);
- }
- break;
- case PL_TEXENV_TEXMINUSENV: // tex-env
- for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
- c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
- c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
- c = (pl_sInt) (*texpal++) - (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
- }
- break;
- case PL_TEXENV_ENVMINUSTEX: // env-tex
- for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
- c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
- c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
- c = -(pl_sInt) (*texpal++) - (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
- }
- break;
- case PL_TEXENV_MIN:
- for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
- *pal++ = plMin(texpal[0],envpal[0]);
- *pal++ = plMin(texpal[1],envpal[1]);
- *pal++ = plMin(texpal[2],envpal[2]);
- texpal+=3;
- }
- break;
- case PL_TEXENV_MAX:
- break;
- for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
- *pal++ = plMax(texpal[0],envpal[0]);
- *pal++ = plMax(texpal[1],envpal[1]);
- *pal++ = plMax(texpal[2],envpal[2]);
- texpal+=3;
- }
- default: // add
- for (whichindex = 0; whichindex < m->Texture->NumColors; whichindex++) {
- c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[0]; *pal++ = plMax(0,plMin(255,c));
- c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[1]; *pal++ = plMax(0,plMin(255,c));
- c = (pl_sInt) (*texpal++) + (pl_sInt) envpal[2]; *pal++ = plMax(0,plMin(255,c));
- }
- break;
- }
- envpal += 3;
- m->_AddTable[whichlevel] = whichlevel*m->Texture->NumColors;
- }
- }
- static void _plGenerateTexturePalette(pl_Mat *m, pl_Texture *t) {
- pl_uChar *ppal, *pal;
- pl_sInt c, i, x;
- m->_ColorsUsed = t->NumColors;
- if (m->_RequestedColors) free(m->_RequestedColors);
- pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
- ppal = t->PaletteData;
- i = t->NumColors;
- do {
- for (x = 0; x < 3; x ++) {
- c = m->Ambient[x] + *ppal++;
- *(pal++) = plMax(0,plMin(c,255));
- }
- } while (--i);
- }
- static void _plGeneratePhongTexturePalette(pl_Mat *m, pl_Texture *t) {
- double a, ca, da, cb;
- pl_uInt16 *addtable;
- pl_uChar *ppal, *pal;
- pl_sInt c, i, i2, x;
- pl_uInt num_shades;
- if (t->NumColors) num_shades = (m->NumGradients / t->NumColors);
- else num_shades=1;
- if (!num_shades) num_shades = 1;
- m->_ColorsUsed = num_shades*t->NumColors;
- if (m->_RequestedColors) free(m->_RequestedColors);
- pal = m->_RequestedColors = (pl_uChar *) malloc(m->_ColorsUsed*3);
- a = PL_PI/2.0;
- if (num_shades>1) da = (-PL_PI/2.0)/(num_shades-1);
- else da=0.0;
- i2 = num_shades;
- do {
- ppal = t->PaletteData;
- ca = cos((double) a);
- a += da;
- cb = pow(ca, (double) m->Shininess);
- i = t->NumColors;
- do {
- for (x = 0; x < 3; x ++) {
- c = (pl_sInt) ((cb*m->Specular[x])+(ca*m->Diffuse[x])+m->Ambient[x] + *ppal++);
- *(pal++) = plMax(0,plMin(c,255));
- }
- } while (--i);
- } while (--i2);
- ca = 0;
- if (m->_AddTable) free(m->_AddTable);
- m->_AddTable = (pl_uInt16 *) malloc(256*sizeof(pl_uInt16));
- addtable = m->_AddTable;
- i = 256;
- do {
- a = sin(ca) * num_shades;
- ca += PL_PI/512.0;
- *addtable++ = ((pl_sInt) a)*t->NumColors;
- } while (--i);
- }
- static void _plGeneratePhongTransparentPalette(pl_Mat *m) {
- m->_tsfact = (pl_sInt) (m->NumGradients*(1.0/(1+m->Transparent)));
- _plGeneratePhongPalette(m);
- }
- static void _plGenerateTransparentPalette(pl_Mat *m) {
- m->_tsfact = 0;
- _plGeneratePhongPalette(m);
- }
- static void _plSetMaterialPutFace(pl_Mat *m) {
- m->_PutFace = 0;
- switch (m->_ft) {
- case PL_FILL_TRANSPARENT: switch(m->_st) {
- case PL_SHADE_NONE: case PL_SHADE_FLAT:
- case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
- m->_PutFace = plPF_TransF;
- break;
- case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
- case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
- m->_PutFace = plPF_TransG;
- break;
- }
- break;
- case PL_FILL_SOLID: switch(m->_st) {
- case PL_SHADE_NONE: case PL_SHADE_FLAT:
- case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
- m->_PutFace = plPF_SolidF;
- break;
- case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
- case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
- m->_PutFace = plPF_SolidG;
- break;
- }
- break;
- case PL_FILL_ENVIRONMENT:
- case PL_FILL_TEXTURE:
- if (m->PerspectiveCorrect) switch (m->_st) {
- case PL_SHADE_NONE: case PL_SHADE_FLAT:
- case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
- m->_PutFace = plPF_PTexF;
- break;
- case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
- case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
- m->_PutFace = plPF_PTexG;
- break;
- }
- else switch (m->_st) {
- case PL_SHADE_NONE: case PL_SHADE_FLAT:
- case PL_SHADE_FLAT_DISTANCE: case PL_SHADE_FLAT_DISTANCE|PL_SHADE_FLAT:
- m->_PutFace = plPF_TexF;
- break;
- case PL_SHADE_GOURAUD: case PL_SHADE_GOURAUD_DISTANCE:
- case PL_SHADE_GOURAUD|PL_SHADE_GOURAUD_DISTANCE:
- m->_PutFace = plPF_TexG;
- break;
- }
- break;
- case PL_FILL_TEXTURE|PL_FILL_ENVIRONMENT:
- m->_PutFace = plPF_TexEnv;
- break;
- }
- }
- typedef struct __ct {
- pl_uChar r,g,b;
- pl_Bool visited;
- struct __ct *next;
- } _ct;
- static int mdist(_ct *a, _ct *b) {
- 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));
- }
- void plMatMakeOptPal(pl_uChar *p, pl_sInt pstart,
- pl_sInt pend, pl_Mat **materials, pl_sInt nmats) {
- pl_uChar *allColors = 0;
- pl_sInt numColors = 0, nc, x;
- pl_sInt len = pend + 1 - pstart;
- pl_sInt32 current, newnext, bestdist, thisdist;
- _ct *colorBlock, *best, *cp;
- for (x = 0; x < nmats; x ++) {
- if (materials[x]) {
- if (!materials[x]->_RequestedColors) plMatInit(materials[x]);
- if (materials[x]->_RequestedColors) numColors+=materials[x]->_ColorsUsed;
- }
- }
- if (!numColors) return;
- allColors=(pl_uChar*)malloc(numColors*3);
- numColors=0;
- for (x = 0; x < nmats; x ++) {
- if (materials[x]) {
- if (materials[x]->_RequestedColors)
- memcpy(allColors + (numColors*3), materials[x]->_RequestedColors,
- materials[x]->_ColorsUsed*3);
- numColors += materials[x]->_ColorsUsed;
- }
- }
- if (numColors <= len) {
- memcpy(p+pstart*3,allColors,numColors*3);
- free(allColors);
- return;
- }
- colorBlock = (_ct *) malloc(sizeof(_ct)*numColors);
- for (x = 0; x < numColors; x++) {
- colorBlock[x].r = allColors[x*3];
- colorBlock[x].g = allColors[x*3+1];
- colorBlock[x].b = allColors[x*3+2];
- colorBlock[x].visited = 0;
- colorBlock[x].next = 0;
- }
- free(allColors);
- /* Build a list, starting at color 0 */
- current = 0;
- nc = numColors;
- do {
- newnext = -1;
- bestdist = 300000000;
- colorBlock[current].visited = 1;
- for (x = 0; x < nc; x ++) {
- if (!colorBlock[x].visited) {
- thisdist = mdist(colorBlock + x, colorBlock + current);
- if (thisdist < 5) { colorBlock[x].visited = 1; numColors--; }
- else if (thisdist < bestdist) { bestdist = thisdist; newnext = x; }
- }
- }
- if (newnext != -1) {
- colorBlock[current].next = colorBlock + newnext;
- current = newnext;
- }
- } while (newnext != -1);
- colorBlock[current].next = 0; /* terminate the list */
- /* we now have a linked list starting at colorBlock, which is each one and
- it's closest neighbor */
- while (numColors > len) {
- bestdist = mdist(colorBlock,colorBlock->next);
- for (best = cp = colorBlock; cp->next; cp = cp->next) {
- if (bestdist > (thisdist = mdist(cp,cp->next))) {
- best = cp;
- bestdist = thisdist;
- }
- }
- best->r = ((int) best->r + (int) best->next->r)>>1;
- best->g = ((int) best->g + (int) best->next->g)>>1;
- best->b = ((int) best->b + (int) best->next->b)>>1;
- best->next = best->next->next;
- numColors--;
- }
- x = pstart*3;
- for (cp = colorBlock; cp; cp = cp->next) {
- p[x++] = cp->r;
- p[x++] = cp->g;
- p[x++] = cp->b;
- }
- free(colorBlock);
- }
|