aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp/plush/MAT.C
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Winamp/plush/MAT.C')
-rw-r--r--Src/Winamp/plush/MAT.C453
1 files changed, 453 insertions, 0 deletions
diff --git a/Src/Winamp/plush/MAT.C b/Src/Winamp/plush/MAT.C
new file mode 100644
index 00000000..801e8d34
--- /dev/null
+++ b/Src/Winamp/plush/MAT.C
@@ -0,0 +1,453 @@
+/******************************************************************************
+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);
+}