/************************************************************/ /* */ /* changes - */ /* 10/31/89 ver 1.02 - allow for new maxcol and maxrow */ /* integers at front of temp file. They are */ /* scanned off & ignored, for now */ /* */ /************************************************************/ #include #include #include #include #include #include #include #include "display.h" #define VERSION "\nDISPLAY v1.02 (IBM MCGA/VGA)\nCopyright (C) 1989 J. Lowery. All rights reserved.\n\n" struct { int curr; int fp; } ifil[10]; static int numfiles = 0; static int colorstats[TMPCOLORS][2]; static int image[MAXCOL]; static char fname[40],outname[40],str[40]; static int usedColors; static int giffile; /* 'ofil' must be accessable to gif output functions in another module */ int ofil; /* buffer for a single scan line */ static scanlinetype line; /* GIF header mode byte definitions */ #define GLOBALCOLORMAP 0x80 #define COLORRES ((DEPTH-1) << 4) #define BITSPERPIXEL (BITS-1) /* * the following structures are odd lengths and mix byte- and * word-length objects, so MUST be packed on 1-byte boundaries, * or file operations break. */ #pragma pack(1) struct { char signature[6]; int screenWidth; int screenHeight; byte mode; byte background; byte empty; } gifHeader = { "GIF87a", MAXCOL, MAXROW, GLOBALCOLORMAP | COLORRES | BITSPERPIXEL, 0, 0 }; struct { char separator; int imageLeft; int imageTop; int imageWidth; int imageHeight; byte mode; byte codeSize; /* this is actually part of the image data stream */ } imageHeader = { ',', 0, 0, MAXCOL, MAXROW, BITSPERPIXEL, BITS }; /* back to normal structure packing */ #pragma pack() /* * display write error, wait for operator acknowledge, * reset video & return. This is used while video is in 320x200 * mode. */ int writeError() { close( ofil ); /* close the file */ _settextposition( 16, 0 ); printf("Write error in file %s\n", outname); printf("Press any key to exit..."); while (!kbhit()) ; getch(); return( TRUE ); } int gifHdr() /* create a GIF file from screen */ { byte colorValue[3]; /* a single rgb triplet */ int i; /* write the header information */ if (write(ofil, (char *)&gifHeader, sizeof(gifHeader)) != sizeof(gifHeader)) return( writeError() ); /* write the global color map */ for (i=0; i> 4); /* blue */ colorValue[1] = ((long)(colorstats[i][0] & 0x00F0) ); /* green */ colorValue[0] = ((long)(colorstats[i][0] & 0x000F) << 4 ); /* red */ } else { colorValue[0] = 0; colorValue[1] = 0; colorValue[2] = 0; } if (write( ofil, colorValue, sizeof(colorValue)) != sizeof(colorValue)) return( writeError() ); } /* write the image descriptor */ if (write(ofil, (char *)&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader)) return( writeError() ); return(0); /* header complete, return ok */ } char terminal[2] = { 0, ';' }; /* image terminator sequence */ int gifClose() { if (gifFlush()) return(TRUE); if (write( ofil, terminal, sizeof( terminal )) != sizeof( terminal )) return( writeError() ); close( ofil ); return(FALSE); /* no error */ } /* reset video mode, print error message and exit */ void error( msg ) char *msg; { _setvideomode( _DEFAULTMODE ); printf( "ERROR: %s\n", msg ); exit( -1 ); } /* print error message and exit. Used in 80-column text mode */ void usageExit( msg ) char *msg; { if (msg) printf("ERROR: %s\n",msg); printf("\nUsage: raydsp [-g outfile] infile [infile [...]] \n"); printf("\nWhere: -g Creates GIF file from screen display"); printf("\n outfile GIF output file name."); printf("\n infile Input DBW_Render .TMP file.\n"); printf("\nDisplays a DBW_Render output file, and optionally "); printf("\nconverts it to Compuserve (tm) GIF format.\n\n"); exit(-1); } read_scanline(pass,row) int pass,row; { int i,j,x,val,good; if (pass < 2) { if ((row % 50) == 0) printf("\nRow: %4d ",row); printf("."); fflush(stdout); } good = 0; for (i = 0; i < numfiles && good == 0; i++) { while (ifil[i].curr < row) { if (read(ifil[i].fp,(char *)&ifil[i].curr,sizeof(int))!=sizeof(int)) { ifil[i].curr = 9999; continue; } if (read(ifil[i].fp,(char *)line,sizeof(scanlinetype))!=sizeof(scanlinetype)) { ifil[i].curr = 9999; continue; } if (ifil[i].curr == row) { good = 1; break; } } } /* couldn't find this scan line in any file */ if (good == 0) return(0); x = 0; for (i = 0; i < WPSL; i++) { for (j = 0; j < PPW; j++) { /*--- TMP file has red, green, then blue nibbles. Palette needs them as blue (MSB), green, red (LSB) ----------*/ val = ( ((line[RED ][i] >> (BPP * j)) & (MAXGRAY-1)) /* red */ + (((line[GREEN][i] >> (BPP * j)) & (MAXGRAY-1)) << BPP) /* green */ + (((line[BLUE ][i] >> (BPP * j)) & (MAXGRAY-1)) << (BPP*2))); /* blue */ val %= TMPCOLORS; if (pass == 1) /* histogram count on pass 1 */ { if (colorstats[val][1] < 32767) colorstats[val][1]++; } else image[x++] = val; } } return(1); } /* * find the darkest color in colorstats[], and make it * colorstats[0], for use as a border color */ getBackground() { /* scan the color table for minimal distance to r,g,b = {0,0,0} */ int i, j; short best, dist; short t0, t1; for ( i=0, best=0, dist=32000; i < usedColors; i++) { j = distance( colorstats[i][0], 0 ); if ( j < dist) { best = i; dist = j; } } /* colorstats[0] gets darkest color for background */ t0 = colorstats[ best ][ 0 ]; t1 = colorstats[ best ][ 1 ]; colorstats[ best ][ 0 ] = colorstats[ 0 ][ 0 ]; colorstats[ best ][ 1 ] = colorstats[ 0 ][ 1 ]; colorstats[ 0 ][ 0 ] = t0; colorstats[ 0 ][ 1 ] = t1; } main(argc,argv) int argc; char **argv; { short i, j, k; short xRes, yRes; short gap; short t0, t1, prgb, crgb, cpix, ppix, maxdis; char *s; char errmsg[80]; printf(VERSION); fname[0] = '\0'; for (i=1; i 9) usageExit("too many input files supplied (9 max.)"); strcpy( str, argv[i] ); /* filename into our temp buf */ if ( strchr( str, '.' ) == NULL ) /* if no filetype */ strcat( str, ".TMP" ); /* ..provide one */ ifil[numfiles].fp = open(str,O_RDONLY | O_BINARY,0); if (ifil[numfiles].fp == -1) { printf("ERROR: Can't find input file '%s'.",str); continue; } else { /* * read and check the row, col spec * if not 320x200, bail out. */ if ( read(ifil[numfiles].fp, (char *)&xRes, sizeof( short )) != sizeof( short ) || read(ifil[numfiles].fp, (char *)&yRes, sizeof( short )) != sizeof( short ) ) { printf("ERROR: Can't read file '%s' - ignored.\n",str); continue; } if ( xRes != 320 || yRes != 200 ) { printf("ERROR: %s is not a 320x200 MCGA data file - ignored\n",str); continue; } } ifil[numfiles].curr = -9999; numfiles++; } } if (numfiles == 0) usageExit( "no valid input file(s) specified." ); if ( giffile && outname[0] == '\0' ) usageExit( "no GIF output filename specified." ); if (giffile) { /* check to see if output file exists */ ofil = open(outname, O_RDONLY); close( ofil ); if (ofil != -1) /* yes, warn them */ { printf("Output file \"%s\" exists. Replace it (y/N)? ",outname); if (toupper(getch()) != 'Y') exit( -1 ); /* no further message, just exit */ } /* now, open it for real... */ ofil = open(outname, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE ); if (ofil == -1) error( "can't create output file." ); printf("\n"); } printf("Building a color histogram:\n"); for (i = 0; i < TMPCOLORS; i++) { colorstats[i][0] = i; colorstats[i][1] = 0; } /* read through the input file list, building the color table */ for (i = 0; i < MAXROW; i++ ) read_scanline(1,i); printf("\n"); /* reset the input file list */ for (i = 0; i < numfiles; i++) { lseek(ifil[i].fp,(long)(2*sizeof(int)),0); ifil[i].curr = -9999; } /* * we now sort the color table in descending order * of quantity of pixels of each color */ for (gap = TMPCOLORS/2; gap > 0; gap /=2) { for (i = gap; i < TMPCOLORS; i++) { for (j = i-gap; j >= 0 && colorstats[j][1] < colorstats[j+gap][1]; j -= gap) { t0 = colorstats[j][0]; t1 = colorstats[j][1]; colorstats[j][0] = colorstats[j+gap][0]; colorstats[j][1] = colorstats[j+gap][1]; colorstats[j+gap][0]= t0; colorstats[j+gap][1]= t1; } } } /* count colors with a population > 0 */ for (usedColors = 0 ; usedColors < TMPCOLORS && colorstats[usedColors][1] > 0; usedColors++) ; /* debug ---------------- printf("post-sort - Colors:population \n\t"); for (i = 0; i < usedColors; i++) { printf("%03x:%05d ",colorstats[i][0],colorstats[i][1]); if ((i % 7) == 7) printf("\n\t"); } printf("Press any key to continue..."); while (!kbhit()) ; getch(); -------------- debug */ if (usedColors == 0) { error( "\nInput file error, no color data." ); } else if (usedColors < COLORS) { printf("\n%d colors used\n",usedColors); } else { printf("\nMapping %d colors into %d\n", usedColors, COLORS); for (maxdis = 2; maxdis < (TMPCOLORS/4); maxdis *= 2) { for (i=usedColors/2; i < usedColors; i++) { for (j = 0; j < i; j++) { if (distance(colorstats[i][0],colorstats[j][0]) < maxdis) { /* delete colorstat[i][] */ for (k=i+1; k> BPP) & (MAXGRAY-1); cb = (*crgb >> (BPP*2)) & (MAXGRAY-1); /* look for an exact match in the color table (or minimal distance) */ for (i=0; i < usedColors; i++) { if (colorstats[i][0] == *crgb) return (i); if (i == 0) { best = 0; dist = distance(colorstats[i][0],*crgb); } else if ((j=distance(colorstats[i][0],*crgb)) < dist) { best = i; dist = j; } } /* do a best absolute */ *crgb = colorstats[best][0]; return(best); } int distance(argb, brgb) int argb, brgb; { short b,g,r; /* set up for comparisons */ r = argb & (MAXGRAY-1); g = (argb >> BPP) & (MAXGRAY-1); b = (argb >> (BPP*2)) & (MAXGRAY-1); r -= brgb & (MAXGRAY-1); g -= (brgb >> BPP) & (MAXGRAY-1); b -= (brgb >> (BPP*2)) & (MAXGRAY-1); return((int)(r*r + g*g + b*b)); }