home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * spr_pal.c *
- * *
- * Makes a sprite consisting of a !Paint style *
- * palette for sprites <= 8 BPP, or for >8 BPP *
- * a sprite with the colours sorted on value *
- * *
- * Supports histogram option for all BPP *
- * *
- * Version 2.12 (08-Mar-1994) *
- * *
- * (C) 1993/4 DEEJ Technology PLC *
- * *
- ************************************************************************/
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include "io.h"
- #include "sprite.h"
- #include "process.h"
- #include "palette.h"
-
- #define SIZE 16 /* palette sprite cell size */
- #define HIST_MAX 1024 /* maximum number of bars in histogram */
- #define HEIGHT_MAX 768 /* maximum height of histogram sprite */
-
- /* globals */
-
- FILE *inf, *outf, *errf;
- int bytes;
- int total;
- char string[256];
-
-
- /*
- * Colour hue
- * 1 256 512 768 1024 1280 1536
- * R Y G C B M R
- * greys are 0
- */
-
- int hue(uint rgb)
- {
- int add;
- int b = (rgb >> 24) &0xFF;
- int g = (rgb >> 16) &0xFF;
- int r = (rgb >> 8) &0xFF;
- int c1 = 0;
- int c2 = 0;
-
- /* exclude grey levels */
-
- if(r==g && r==b) return(0);
-
- /* find one/two dominant components */
-
- if((r>=g && g>=b) || (g>=r && r>=b))
- {
- c1 = r - b;
- c2 = g - b;
- add = 256;
- }
- else
- {
- if((g>=b && b>=r) || (b>=g && g>=r))
- {
- c1 = g - r;
- c2 = b - r;;
- add = 768;
- }
- else
- {
- /* must be */
- /*
- if((b>=r && r>=g) || (r>=b && b>=g))
- */
- {
- c1 = b - g;
- c2 = r - g;
- add = 1280;
- }
- }
- }
-
- /* scale components so largest is full range */
-
- if(c1 > c2)
- {
- c2 = (c2*255)/c1;
- c1 = 255;
- }
- else
- {
- c1 = (c1*255)/c2;
- c2 = 255;
- }
-
- return( ((c2-c1) + add) % 1536 );
- }
-
- /*
- * qsort comparison function for 8-32 BPP pixels
- * and pointers to hist_entry structures (bytes=8)
- */
-
- int compar(const void *vptr1, const void *vptr2)
- {
- static int count = 0;
- uchar *ptr1 = (uchar*)vptr1;
- uchar *ptr2 = (uchar*)vptr2;
-
- uint r,g,b;
- uint val1, val2;
- int int1, int2;
- int hue1, hue2;
-
- switch(bytes)
- {
- case 2:
- val1 = ptr1[0] + (ptr1[1] << 8);
- r = (val1 >> 0) &0x1F; r = (r<<3) | (r>>2);
- g = (val1 >> 5) &0x1F; g = (g<<3) | (g>>2);
- b = (val1 >> 10) &0x1F; b = (b<<3) | (b>>2);
- val1 = (b<<24) | (g<<16) | (r<<8);
-
- val2 = ptr2[0] + (ptr2[1] << 8);
- r = (val2 >> 0) &0x1F; r = (r<<3) | (r>>2);
- g = (val2 >> 5) &0x1F; g = (g<<3) | (g>>2);
- b = (val2 >> 10) &0x1F; b = (b<<3) | (b>>2);
- val2 = (b<<24) | (g<<16) | (r<<8);
- break;
-
- case 4:
- val1 = endian(LE, *(uint*)vptr1);
- val2 = endian(LE, *(uint*)vptr2);
-
- /* convert xxBBGGRR to BBGGRR00 */
-
- val1 = val1<<8;
- val2 = val2<<8;
- break;
-
- case 8:
- val1 = (*((hist_entry**)vptr1))->value;
- val2 = (*((hist_entry**)vptr2))->value;
- break;
- }
-
- if((++count % (total/50))==0) fputc('.',errf);
-
- hue1 = hue(val1);
- hue2 = hue(val2);
-
- if(hue1==hue2)
- {
- int1 = intensity(val1);
- int2 = intensity(val2);
-
- return(int1-int2);
- }
- else
- {
- return(hue1-hue2);
- }
- }
-
- /*
- * Make !Paint style palette sprite
- * with different size but same BPP & palette
- */
-
- void palette_sprite(spr_info_str *spr)
- {
- int X,Y;
- int x1,y1;
- int x2,y2;
- int val;
-
- switch(spr->bpp)
- {
- case 1: X = 2; Y = 1; break;
- case 2: X = 2; Y = 2; break;
- case 4: X = 4; Y = 4; break;
- case 8: X = 16; Y = 16; break;
- }
-
- spr->X = X * SIZE;
- spr->Y = Y * SIZE;
- spr->Xasp = 1;
- spr->Yasp = 1;
-
- fill_info(spr);
- alloc_spr_data(spr);
- memset(spr->spr_data, 0, spr->line_size*spr->Y);
-
- /* make !PAINT type palette grid */
-
- progress_start(string);
-
- for(y1=0; y1<Y; y1++)
- for(x1=0; x1<X; x1++)
- {
- /* palette entry index */
-
- val = y1*Y+x1;
-
- for(y2=1; y2<(SIZE-1); y2++)
- for(x2=1; x2<(SIZE-1); x2++)
- {
- write_pixel_val(spr,x1*SIZE+x2,y1*SIZE+y2,val);
- }
- progress(y1*Y+x1,X*Y);
- }
- write_sprite(spr, outf);
- }
-
- /*
- * Read sprite data and sort to give rougth palette display
- */
-
- void sort_sprite(spr_info_str *spr)
- {
- int x, y;
- int line_size;
- uchar *line;
-
- /* set up globals */
-
- bytes = spr->pix/8; /* bytes per pixel */
- total = spr->X*spr->Y*15; /* approx no. compares */
-
- /* sort cannot handle 3 byte values, so convert to 24/32 BPP */
-
- if(spr->pix == 24)
- {
- line_size = spr->line_size;
- spr->pix = 32;
- fill_info(spr);
- }
-
- alloc_spr_data(spr);
-
- /* cannot read sprite data as is - must remove line padding */
-
- switch(bytes)
- {
- case 2:
- case 4:
- for(y=0; y<spr->Y; y++)
- {
- fread(spr->spr_data + (y*spr->X*bytes),
- spr->line_size, 1, inf);
- }
- break;
-
- case 3:
- /* must be expanded to 32 BPP for sorting */
-
- if((line=malloc(line_size))==0)
- {
- fprintf(stderr,"Unable to allocat line buffer\n");
- exit(1);
- }
-
- for(y=0; y<spr->Y; y++)
- {
- fread(line, line_size, 1, inf);
-
- for(x=0; x<spr->X; x++)
- {
- spr->spr_data[(((y*spr->X)+x)*4)+0] = line[x*3+0];
- spr->spr_data[(((y*spr->X)+x)*4)+1] = line[x*3+1];
- spr->spr_data[(((y*spr->X)+x)*4)+2] = line[x*3+2];
- spr->spr_data[(((y*spr->X)+x)*4)+3] = 0;
- }
- }
- bytes = 4;
- break;
-
- default:
- fprintf(errf,"Sorting not supported for %d BPP\n",spr->bpp);
- exit(2);
- break;
- }
-
- progress_start(string);
-
- qsort((void*)spr->spr_data, spr->X*spr->Y, bytes, compar);
-
- write_sprite_header(spr, outf);
-
- /* write out with line padding */
-
- for(y=0; y<spr->Y; y++)
- {
- fwrite(spr->spr_data + (y * spr->X * bytes),
- spr->line_size, 1, outf);
- }
- }
-
- /*
- * produce a histogram sprite depicting
- * colour use of original sprites data
- */
-
- void histogram_sprite(spr_info_str *spr, hist_info *h)
- {
- hist_entry *entry_ptr;
- hist_entry **index;
- int x, y, x2, y2;
- int xsize, ysize;
- int xstep, ystep, yinc;
- int filter;
- int average;
- uint bg;
- pix_str col;
- pix_str *c;
-
- /* decide on a filter threshold to give < HIST_MAX pixels accross */
-
- filter = 0;
- xsize = h->colours;
-
- if(xsize > HIST_MAX)
- {
- filter = 1;
- xsize = h->more1;
- }
- if(xsize > HIST_MAX)
- {
- filter = 10;
- xsize = h->more10;
- }
- if(xsize > HIST_MAX)
- {
- filter = 100;
- xsize = h->more100;
- }
- if(xsize<h->more_frac && (xsize<256 || h->more_frac<HIST_MAX))
- {
- filter = h->fraction;
- xsize = h->more_frac;
- }
-
- /* if small number of colours increase bar spacing */
-
- if(xsize <= (HIST_MAX/4))
- {
- if(xsize <= (HIST_MAX/8))
- xstep = 4;
- else
- xstep = 2;
- }
- else
- {
- xstep = 1;
- }
-
- /* build index table for sorting from filtered histogram */
-
- if((index=(hist_entry**)malloc(xsize*sizeof(hist_entry_ptr)))==0)
- {
- fprintf(stderr,"Unable to allocate index table\n");
- exit(1);
- }
-
- x = 0;
- average = 0;
- entry_ptr = h->list_head;
-
- while(entry_ptr != 0)
- {
- if(entry_ptr->count > filter)
- {
- index[x++] = entry_ptr;
- average += entry_ptr -> count;
- }
- entry_ptr = entry_ptr->next;
- }
-
- average /= xsize;
-
- /* integrity check */
-
- if(x != xsize)
- {
- fprintf(stderr, "Filtered count disagress with precalculated (%d,%d)\n", x, xsize);
- exit(2);
- }
-
- /*
- * determine Y scale to give height < HEIGHT_MAX
- * use maximum use from histogram and the average use
- * AFTER filtering (rather than value from histogram)
- */
-
- if(h->max_use > average*8)
- {
- ysize = average*8;
- }
- else
- {
- ysize = h->max_use;
- }
- ystep = 1;
-
- if(ysize > HEIGHT_MAX)
- {
- ystep = (ysize + HEIGHT_MAX-1)/HEIGHT_MAX;
- ysize /= ystep;
- }
-
- fprintf(errf,"Filter : %d\n",filter);
- fprintf(errf,"Num of bars : %d\n",xsize);
- fprintf(errf,"Y scale : 1:%d\n",ystep);
-
- spr->X = xsize*xstep;
- spr->Y = ysize;
- spr->Xasp = 1;
- spr->Yasp = 1;
-
- /* sort index table */
- /* set up globals */
- bytes = 8; /* comparison type flag */
- total = xsize*20; /* approx no. compares */
-
- sprintf(string, "Sorting :");
- progress_start(string);
-
- qsort((void*)index, xsize, sizeof(hist_entry_ptr), compar);
-
- progress_finish();
-
- /* make sprite of appropriate size */
-
- fill_info(spr);
- alloc_spr_data(spr);
-
- /* choose background colour and clear sprite */
-
- col.red = 0;
- col.green = 0;
- col.blue = 0;
- c = closest_rgb(spr, &col);
-
- switch(spr->bpp)
- { /* convert colour number to whole byte */
- case 1: bg = c->value * 0xFF; break;
- case 2: bg = c->value * 0x55; break;
- case 4: bg = c->value * 0x11; break;
- case 8: bg = c->value; break;
- default: bg = 0; break;
- }
-
- memset(spr->spr_data, bg, spr->line_size*spr->Y);
-
- /* plot histogram bars on sprite */
-
- sprintf(string,"Generating palette sprite:");
- progress_start(string);
-
- entry_ptr = h->list_head;
-
- for(x=0; x<xsize; x++)
- {
- col.value = index[x]->value;
- col.blue = (col.value >> 24) & 0xFF;
- col.green = (col.value >> 16) & 0xFF;
- col.red = (col.value >> 8) & 0xFF;
-
- c = closest_rgb(spr, &col);
-
- /* correct for background colour bar */
-
- if(c->value == bg)
- {
- col.red = col.red ^ 0xFF;
- col.green = col.green ^ 0xFF;
- col.blue = col.blue ^ 0xFF;
- c = closest_rgb(spr, &col);
- yinc = 2;
- }
- else
- {
- yinc = 1;
- }
-
- x2 = xstep/2 + x*xstep;
-
- if((index[x]->count/ystep) <= 1)
- {
- write_pixel_val(spr, x2, spr->Y-1, c->value);
- }
- else
- {
- y2 = index[x]->count/ystep;
- y2 = y2>=ysize ? ysize-1 : y2;
-
- for(y=0; y<y2; y+=yinc)
- {
- write_pixel_val(spr, x2, spr->Y-y-1, c->value);
- }
- }
-
- progress(x, xsize);
- }
-
- write_sprite(spr, outf);
- }
-
-
- int main(int argc, char **argv)
- {
- BOOL histogram = FALSE;
- hist_info *hist;
- spr_info_str spr;
-
- if(argc>1 && argv[1][0]=='-')
- {
- if(argv[1][1] == 'h')
- {
- histogram = TRUE;
- }
- else
- {
- fprintf(errf,"Unrecognised flag '%s'\n",argv[1]);
- return(1);
- }
- argc--; argv++;
- }
-
- file_args(argc, argv, &inf, &outf, &errf);
-
- /* read sprite from file */
-
- read_sprite_header(&spr, inf);
-
- sprintf(string,"Generating palette sprite:");
-
- if(histogram)
- {
- /* read sprite & build histogram of colour usage */
-
- alloc_spr_data(&spr);
- fread(spr.spr_data, spr.line_size, spr.Y, inf);
-
- hist = build_histogram(&spr);
-
- /* free orginal sprite data and make a histogram image */
-
- free((void*)spr.spr_data);
-
- histogram_sprite(&spr, hist);
- }
- else
- {
- if(spr.bpp <= 8)
- {
- palette_sprite(&spr);
- }
- else
- {
- sort_sprite(&spr);
- }
- }
-
- progress_finish();
-
- fclose(inf);
- fclose(outf);
- fclose(errf);
- }
-