/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "gr.h" #include "ui.h" #include "key.h" extern void gr_pal_setblock(int start, int stop, void * colors ); typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; #define GAMMA 1.3 #define CUBE(x) ((x)*(x)*(x)) #define SQUARE(x) ((x)*(x)) #define BM_LINEAR 0 #define BM_MODEX 1 #define BM_SVGA 2 #define BM_RGB15 3 //5 bits each r,g,b stored at 16 bits typedef struct { WORD X, Y; WORD Width; WORD Height; WORD Type; WORD Rowsize; DWORD DataPtr; WORD Data[1]; } BITMAP15; typedef struct { WORD X, Y; WORD Width; WORD Height; WORD Type; WORD Rowsize; DWORD DataPtr; BYTE Data[1]; } BITMAP8; extern BITMAP15 * IFF_To_15BPP(char * ifilename); typedef struct { BYTE Red; BYTE Green; BYTE Blue; } RGB; typedef struct { int Lo[3]; int Hi[3]; int NumElements; } BOX; BOX Boxes[256]; // The color boxes that we want to fill RGB ColRegs[256]; // The palette entries that we fill int * RGBCube = NULL; // Used to count the color frequencies in the original image. void *bmd_fade_table; BYTE * AverageTable; BYTE ColorTable[16][256]; BYTE * LookupTable; int Usage[256]; int NumBoxes; int TotalPixels; int TotalPixels1; int AllowedColors = 256; BYTE Gamma32[32]; BYTE Gamma64[32]; int WorstError; BYTE WorstRed, WorstGreen, WorstBlue; char * Filename[25]; BITMAP15 * Image15[25]; BITMAP8 * Image8[25]; int NumImages = 0; char temp[200]; int RequestedColors; void * ReadFile( char * filename, int * length ) { void * FileData; int handle; handle = open( filename, O_RDONLY | O_BINARY ); if (handle == -1 ) { printf( "Unable to open '%s'\n", filename ); exit(1); } *length = filelength( handle ); FileData = (void * )malloc( *length ); if (FileData == NULL ) { close( handle ); printf( "Not enough memory to read in file '%s'\n", filename ); exit(1); } if (read( handle, FileData, *length ) != *length ) { printf( "Error reading in '%s' data.\n", filename ); free( FileData ); close( handle ); exit(1); } close( handle ); return FileData; } void WriteFile( char * filename, void * data, int length ) { int handle; handle = open( filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ); if (handle == -1 ) { printf( "Error opening output file '%s'\n", filename ); exit(1); } if (write( handle, data, length )!=length) { printf( "Error writing output file '%s'\n", filename ); close( handle ); exit(1); } close( handle ); } void InitializeMixer() { int i; printf( "Initializing mixer...\n" ); TotalPixels = 0; if (RGBCube==NULL ) { RGBCube = (int *)malloc(32*32*32*sizeof(int)); if (RGBCube==NULL) exit(1); } for (i=0; i<32768; i++ ) { RGBCube[i] = 0; } for (i=0; i<256; i++ ) Usage[i] = 0; } void FillGamma() { double intensity; int i; int sellevels, pallevels; sellevels = 31; pallevels = 63; Gamma64[0] = 0; for (i=1; i<=sellevels; i++) { intensity = (double)i/(double)sellevels; Gamma64[i] = (BYTE)((pow(intensity, 1.0/GAMMA)*pallevels) + 0.5); } sellevels = 31; pallevels = 31; Gamma32[0] = 0; for (i=1; i<=sellevels; i++) { intensity = (double)i/(double)sellevels; Gamma32[i] = (BYTE)((pow(intensity, 1.0/GAMMA)*pallevels) + 0.5); } } void ScanColorFrequencies( BITMAP15 * buf, char * filename ) { int i; int r, g, b, max; printf( "Factoring in %s's colors...\n", filename ); for (i=0; i< (buf->Width*buf->Height); i++ ) { r = ((buf->Data[i] >> 10) & 31); g = ((buf->Data[i] >> 5) & 31); b = (buf->Data[i] & 31); max = 0; if ( r > max) max = r; if ( g > max) max = g; if ( b > max) max = b; if (max > 0) { RGBCube[ (r<<10)+(g<<5)+b ]++; TotalPixels++; } } } void Shrink( int BoxIndex ) { int axis, aax1, aax2; int ind[3], flag; for (axis=0; axis<3; axis++ ) { switch(axis) { case 0: aax1=1; aax2=2; break; case 1: aax1=0; aax2=2; break; case 2: aax1=0; aax2=1; } flag=0; for (ind[axis]=Boxes[BoxIndex].Lo[axis]; ind[axis]<=Boxes[BoxIndex].Hi[axis]; ind[axis]++ ) { for (ind[aax1]=Boxes[BoxIndex].Lo[aax1]; ind[aax1]<=Boxes[BoxIndex].Hi[aax1]; ind[aax1]++ ) { for (ind[aax2]=Boxes[BoxIndex].Lo[aax2]; ind[aax2]<=Boxes[BoxIndex].Hi[aax2]; ind[aax2]++ ) if (RGBCube[ (ind[0]<<10)+(ind[2]<<5)+ind[1] ] ) { flag = 1; break; } if (flag) break; } if (flag) break; } Boxes[BoxIndex].Lo[axis] = ind[axis]; flag=0; for (ind[axis]=Boxes[BoxIndex].Hi[axis]; ind[axis]+1>=Boxes[BoxIndex].Lo[axis]+1; ind[axis]-- ) { for (ind[aax1]=Boxes[BoxIndex].Hi[aax1]; ind[aax1]+1>=Boxes[BoxIndex].Lo[aax1]+1; ind[aax1]-- ) { for (ind[aax2]=Boxes[BoxIndex].Hi[aax2]; ind[aax2]+1>=Boxes[BoxIndex].Lo[aax2]+1; ind[aax2]-- ) if (RGBCube[ (ind[0]<<10)+(ind[2]<<5)+ind[1] ] ) { flag = 1; break; } if (flag) break; } if (flag) break; } Boxes[BoxIndex].Hi[axis] = ind[axis]; } } int GetGrey( RGB * reg ) { BYTE r, b, g; r = reg->Red/2; g = reg->Green/2; b = reg->Blue/2; return (r+g+b)/3; } void SortPalette() { BYTE t; int i, j, incr, grey1, grey2, t1; incr = AllowedColors / 2; while( incr > 0 ) { for (i=incr; i=0 ) { grey1 = GetGrey( &(ColRegs[j]) ); grey2 = GetGrey( &(ColRegs[j+incr]) ); if (grey1 > grey2 ) { t = ColRegs[j+incr].Red; ColRegs[j+incr].Red=ColRegs[j].Red; ColRegs[j].Red=t; t = ColRegs[j+incr].Green; ColRegs[j+incr].Green=ColRegs[j].Green; ColRegs[j].Green=t; t = ColRegs[j+incr].Blue; ColRegs[j+incr].Blue=ColRegs[j].Blue; ColRegs[j].Blue=t; t1 = Usage[j+incr]; Usage[j+incr]=Usage[j]; Usage[j]=t1; j -= incr; } else break; } } incr = incr / 2; } t = ColRegs[254].Red; ColRegs[254].Red=ColRegs[7].Red; ColRegs[7].Red=t; t = ColRegs[254].Green; ColRegs[254].Green=ColRegs[7].Green; ColRegs[7].Green=t; t = ColRegs[254].Blue; ColRegs[254].Blue=ColRegs[7].Blue; ColRegs[7].Blue=t; t1 = Usage[254]; Usage[254]=Usage[7]; Usage[7]=t1; } void CombinePalettes() { int SelectedBox, c, ind[3], Max, axis, TargetBox, k, aax1, aax2; int LongMax, PlaneSum, ElementSum; int Index,r,b,g; int rsum,bsum,gsum,tmp, i; printf( "Creating a master palette...\n" ); Boxes[0].Lo[0] = 0; Boxes[0].Hi[0] = 31; Boxes[0].Lo[1] = 0; Boxes[0].Hi[1] = 31; Boxes[0].Lo[2] = 0; Boxes[0].Hi[2] = 31; Boxes[0].NumElements = TotalPixels; NumBoxes = 1; Shrink(0); while(NumBoxes < AllowedColors ) { LongMax = 0; SelectedBox = 1000; for (c=0; c LongMax) && ((Boxes[c].Lo[0] != Boxes[c].Hi[0]) || (Boxes[c].Lo[1] != Boxes[c].Hi[1]) || (Boxes[c].Lo[2] != Boxes[c].Hi[2])) ) { LongMax = Boxes[c].NumElements; SelectedBox = c; } } if (SelectedBox == 1000) break; axis = 0; Max = Boxes[SelectedBox].Hi[axis] - Boxes[SelectedBox].Lo[axis]; for (k=1; k<3; k++ ) { if (Max<(c=(Boxes[SelectedBox].Hi[k]-Boxes[SelectedBox].Lo[k]))) { Max = c; axis = k; } } TargetBox = NumBoxes; for (c=0; c Boxes[SelectedBox].NumElements/2) break; } if (ind[axis] == Boxes[SelectedBox].Hi[axis]) { ind[axis]--; ElementSum -= PlaneSum; } for (c=0; c< 3; c++ ) { Boxes[TargetBox].Lo[c] = Boxes[SelectedBox].Lo[c]; Boxes[TargetBox].Hi[c] = Boxes[SelectedBox].Hi[c]; } Boxes[TargetBox].Lo[axis] = ind[axis]+1; Boxes[TargetBox].NumElements = Boxes[SelectedBox].NumElements - ElementSum; Boxes[SelectedBox].Hi[axis] = ind[axis]; Boxes[SelectedBox].NumElements = ElementSum; Shrink(SelectedBox); Shrink(TargetBox); if (TargetBox == NumBoxes ) { NumBoxes++; } } } AllowedColors = NumBoxes; for (Index=0; Index < AllowedColors; Index++ ) { rsum = bsum = gsum = 0; for (r=Boxes[Index].Lo[0]; r<=Boxes[Index].Hi[0]; r++ ) for (b=Boxes[Index].Lo[1]; b<=Boxes[Index].Hi[1]; b++ ) for (g=Boxes[Index].Lo[2]; g<=Boxes[Index].Hi[2]; g++ ) { tmp = RGBCube[ (r<<10)+(g<<5)+b ]; rsum += r*tmp; bsum += b*tmp; gsum += g*tmp; } ColRegs[Index+16].Red = (BYTE)((rsum*2) / Boxes[Index].NumElements); ColRegs[Index+16].Blue = (BYTE)((bsum*2) / Boxes[Index].NumElements); ColRegs[Index+16].Green = (BYTE)((gsum*2) / Boxes[Index].NumElements); } AllowedColors += 16; ColRegs[0].Red = 0; ColRegs[0].Green = 0; ColRegs[0].Blue = 0; ColRegs[1].Red = 0; ColRegs[1].Green = 0; ColRegs[1].Blue =42; ColRegs[2].Red = 0; ColRegs[2].Green =42; ColRegs[2].Blue = 0; ColRegs[3].Red = 0; ColRegs[3].Green =42; ColRegs[3].Blue =42; ColRegs[4].Red = 42; ColRegs[4].Green = 0; ColRegs[4].Blue = 0; ColRegs[5].Red = 42; ColRegs[5].Green = 0; ColRegs[5].Blue =42; ColRegs[6].Red = 42; ColRegs[6].Green =21; ColRegs[6].Blue = 0; ColRegs[7].Red = 42; ColRegs[7].Green =42; ColRegs[7].Blue =42; ColRegs[8].Red = 21; ColRegs[8].Green =21; ColRegs[8].Blue =21; ColRegs[9].Red = 21; ColRegs[9].Green =21; ColRegs[9].Blue =63; ColRegs[10].Red = 21; ColRegs[10].Green =63; ColRegs[10].Blue =21; ColRegs[11].Red = 21; ColRegs[11].Green =63; ColRegs[11].Blue =63; ColRegs[12].Red = 63; ColRegs[12].Green =21; ColRegs[12].Blue =21; ColRegs[13].Red = 63; ColRegs[13].Green =21; ColRegs[13].Blue =63; ColRegs[14].Red = 63; ColRegs[14].Green =63; ColRegs[14].Blue =21; ColRegs[15].Red = 63; ColRegs[15].Green =63; ColRegs[15].Blue =63; } void GammaCorrect() { int i; for (i=0; iWidth*in->Height*2+sizeof(BITMAP15) ); p[3] = '2'; printf( "Writing %s...\n", new ); tmp = malloc( in->Width*in->Height*4 ); if (tmp==NULL) exit(1); for (i=0; i< in->Width*in->Height; i++ ) { tmp[i*4+0] = (in->Data[i]>>10) & 31; tmp[i*4+1] = (in->Data[i]>>5) & 31; tmp[i*4+2] = in->Data[i] & 31; tmp[i*4+3] = 0; } WriteFile( new, tmp, in->Width*in->Height*4 ); free(tmp); } printf( "Reducing colors in %s...\n", filename ); size = in->Height * in->Width; out = (BITMAP8 *)in; out->Rowsize = out->Width; out->Type = BM_LINEAR; out->DataPtr = 0; for (i=0; i< size; i++ ) { if (in->Data[i]==0) out->Data[i] = 255; else { out->Data[i] = LookupTable[ in->Data[i] ]; Usage[ out->Data[i] ]++; } } return out; } void WritePalette() { printf( "Writing palette...\n" ); WriteFile( "PALETTE.TBL", ColRegs, 256*3 ); } BITMAP15 * ReadImage( char * filename ) { printf( "Reading in %s...\n", filename ); return IFF_To_15BPP( filename ); } void PrintUsage() { printf( "Usage: TESTP [-c#] files...\n" ); } void DisplayPalette() { int i, j, k; gr_set_current_canvas(NULL); for (i=0; i=0; j-- ) { i=0; for (y=0; y< Image->Height; y++ ) { for (x=0; x< Image->Width; x++ ) { gr_setcolor( ColorTable[j][Image->Data[i++]] ); gr_rect( x*3, y*3, x*3+3, y*3+3 ); //gr_pixel(x,y); } } key_getch(); } } else { for (j=15; j>=0; j-- ) { if (lt==1) l = LookupTable[((15-j)*2)<<10] << 8; if (lt==2) l = LookupTable[((15-j)*2)<<5] << 8; if (lt==3) l = LookupTable[((15-j)*2)] << 8; i=0; for (y=0; y< Image->Height; y++ ) { for (x=0; x< Image->Width; x++ ) { gr_setcolor( AverageTable[l+Image->Data[i++]] ); gr_rect( x*3, y*3, x*3+3, y*3+3 ); //gr_pixel(x,y); } } key_getch(); } } } void FactorInShades() { int j, i, r, g, b; printf( "Factoring in shades...\n" ); for (j=1; j<=16; j++ ) { for (i=0; i < AllowedColors; i++ ) { r = (j*ColRegs[i].Red)/(16*2); g = (j*ColRegs[i].Green)/(16*2); b = (j*ColRegs[i].Blue)/(16*2); if ((r+g+b)>0) { RGBCube[ (r<<10)+(g<<5)+b ] += (Boxes[i].NumElements*2)/j; TotalPixels+=(Boxes[i].NumElements*2)/j; } } } } void FactorInAlternateLights() { int j, i, r, g, b; printf( "Factoring in alternate lighting...\n" ); for (j=1; j<=16; j++ ) { for (i=0; i < AllowedColors; i++ ) { r = (j*ColRegs[i].Red)/(16*2); g = (j*ColRegs[i].Green)/(16*2); b = (j*ColRegs[i].Blue)/(16*2); r += j; if (r>31) r=31; if ((r+g+b)>0) { RGBCube[ (r<<10)+(g<<5)+b ] += (Boxes[i].NumElements*2)/j; TotalPixels+=(Boxes[i].NumElements*2)/j; } } } for (j=1; j<=16; j++ ) { for (i=0; i < AllowedColors; i++ ) { r = (j*ColRegs[i].Red)/(16*2); g = (j*ColRegs[i].Green)/(16*2); b = (j*ColRegs[i].Blue)/(16*2); g += j; if (g>31) g=31; if ((r+g+b)>0) { RGBCube[ (r<<10)+(g<<5)+b ] += (Boxes[i].NumElements*2)/j; TotalPixels+=(Boxes[i].NumElements*2)/j; } } } for (j=1; j<=16; j++ ) { for (i=0; i < AllowedColors; i++ ) { r = (j*ColRegs[i].Red)/(16*2); g = (j*ColRegs[i].Green)/(16*2); b = (j*ColRegs[i].Blue)/(16*2); b += j; if (b>31) b=31; if ((r+g+b)>0) { RGBCube[ (r<<10)+(g<<5)+b ] += (Boxes[i].NumElements*2)/j; TotalPixels+=(Boxes[i].NumElements*2)/j; } } } } void CalculateLookupTable() { int r, g, b, i; printf( "Creating inverse lookup table...\n" ); LookupTable= (BYTE *)malloc(32768); if (LookupTable==NULL) exit(1); i = 0; for (r=0; r<32; r++ ) for (g=0; g<32; g++ ) for (b=0; b<32; b++ ) LookupTable[i++] = FindColor( r*2, g*2, b*2 ); WriteFile( "IPAL.TBL", LookupTable, 32768 ); } void CalculateShadeTables() { int j, i, r, g, b; printf( "Creating and writing shade lookup tables...\n" ); for (j=1; j<=16; j++ ) { ColorTable[j-1][255] = 255; for (i=0; i < AllowedColors; i++ ) { r = (j*ColRegs[i].Red)/16; g = (j*ColRegs[i].Green)/16; b = (j*ColRegs[i].Blue)/16; if (j<16) ColorTable[j-1][i] = FindColor( r, g, b); else ColorTable[15][i] = i; } } WriteFile( "FADE.TBL", ColorTable, 256*16 ); } void CreateBlendTable() { int i,j,r,g,b, c; printf( "Creating and writing color averaging table...\n" ); AverageTable= (BYTE *)malloc(256*256); if (AverageTable==NULL) exit(1); for (i=0; i<256; i++ ) { for (j=i; j<256; j++ ) { r = (ColRegs[i].Red+ColRegs[j].Red); g = (ColRegs[i].Green+ColRegs[j].Green); b = (ColRegs[i].Blue+ColRegs[j].Blue); if (r>63) r=63; if (g>63) g=63; if (b>63) b=63; c = FindColor( r,g,b ); AverageTable[(i<<8)+j] = c; AverageTable[(j<<8)+i] = c; } } WriteFile( "BLEND.TBL", AverageTable, 256*256 ); } void NormalizePalette() { int i, max; max = 0; for (i=0; i max ) max = ColRegs[i].Red; if (ColRegs[i].Green > max ) max = ColRegs[i].Green; if (ColRegs[i].Blue > max ) max = ColRegs[i].Blue; } //printf( "Max=%d\n", max ); //getch(); for (i=0; i 320) { x = 0; y++; } gr_setcolor( LookupTable[i] ); gr_upixel( x, y ); } } void DoInterface() { int i; int menu1, NumItems1; char * MenuItems[256]; gr_init( SM_640x480V ); gr_init_font( "/miner/fonts/pc8x16.fnt" ); ColRegs[255].Red = 0; ColRegs[255].Blue = 30; ColRegs[255].Green = 0; gr_set_palette(0, 256, (BYTE *)ColRegs ); gr_setcolor(255); gr_rect(0,0,grd_curscreen->sc_w,grd_curscreen->sc_h); ui_init(); for (NumItems1=0; NumItems1pal ); menu1 = 2; while( menu1 != 1 ) { while ( menu1 != NumItems1 ) { ui_mouse_process(); menu1 = PopupMenu( NumItems1, MenuItems ); if (menu1<(NumItems1-2) && (menu1>0) ) { DisplayImage( Image8[menu1-1] ); } if (menu1==(NumItems1-2)) { DisplayIPAL(); } if (menu1==(NumItems1-1)) { DisplayPalette(); } } menu1 = MessageBox( -1, -1, 2, "Exit to DOS?", "Yes", "No" ); } ui_close(); gr_close(); for (i=0; i< AllowedColors; i++ ) { if ((i%20)==0) getch(); printf( "%d %d,%d,%d %d\n", i, ColRegs[i].Red,ColRegs[i].Green,ColRegs[i].Blue, Usage[i] ); } } void ParseCommandLine( int argc, char * argv[] ) { struct find_t find; char * cp; char * cp1; if (argc < 2 ) { PrintUsage(); exit(1); } RequestedColors = 256; argv++; argc--; for (;argc--;argv++) { if ((**argv=='-') || (**argv=='/')) { cp=(*argv)+1; cp1 = cp; switch (*cp++) { case 'c': RequestedColors = atoi( cp ); break; case '?': case 'h': PrintUsage(); exit(1); default: printf( "Unrecognized switch '%s'\n", cp1 ); break; } } else { if( !_dos_findfirst( *argv, 0xffff, &find ) ) { Filename[NumImages++] = strdup( find.name ); while( !_dos_findnext( &find ) ) { Filename[NumImages++] = strdup( find.name ); } } else { printf( "No files matching '%s' were found.\n", *argv ); exit(1); } } } if ( NumImages == 0 ) { printf( "Error: Input files must be specified.\n\n" ); PrintUsage(); exit(1); } if (RequestedColors < 16) RequestedColors = 16; if (RequestedColors > 256) RequestedColors = 256; RequestedColors--; } void WriteBitmaps() { char new[20]; char * p; int i, j; for (j=0; jWidth*Image8[j]->Height+sizeof(BITMAP8) ); } } } void ReduceImages() { int i; for (i=0; i