This is xanim_cmap.c in view mode; [Download] [Up]
/*
* xanim_cmap.c
*
* Copyright (C) 1992,1993,1994 by Mark Podlipec.
* All rights reserved.
*
* This software may be freely copied, modified and redistributed without
* fee for non-commerical purposes provided that this copyright notice is
* preserved intact on all copies and modified copies.
*
* There is no warranty or other guarantee of fitness of this software.
* It is provided solely "as is". The author(s) disclaim(s) all
* responsibility and liability with respect to this software's usage
* or its effect upon hardware or computer systems.
*
*/
#include "xanim.h"
extern XA_CHDR *xa_chdr_first;
/*
extern XColor defs[256];
extern Display *theDisp;
extern Colormap theCmap;
*/
extern ULONG cmap_use_combsort;
static XA_CHDR *cmap_332_chdr = 0;
static XA_CHDR *cmap_gray_chdr = 0;
static double cmap_332_gamma = 0.0;
static double cmap_gray_gamma = 0.0;
static double cmap_cur_gamma = 0.0;
/* TBD move to xanim.h */
#define GAMMA_MIN 0.0001
#define CMAP_ABS(x) (((x)<0)?(-(x)):(x))
#define CMAP_SQR(x) ((x) * (x))
ULONG cmap_scale[17] = { 65535, 65535, 21845, 9362,
4369, 2114, 1040, 516,
257, 128, 64, 32,
16, 8, 4, 2, 1};
ColorReg find_cmap[256];
ColorReg *cur_find_cmap = 0;
ULONG find_red[256],find_green[256],find_blue[256];
/* Box structure for Median Cut algorithm */
typedef struct CMAP_Box_Struct
{
struct CMAP_Box_Struct *next;
LONG rmin,rmax,gmin,gmax,bmin,bmax;
ULONG last_sort;
ULONG *clist;
ULONG clist_len;
} CMAP_Box;
#define CMAP_MEDIAN_NONE 0
#define CMAP_MEDIAN_RED 1
#define CMAP_MEDIAN_GREEN 2
#define CMAP_MEDIAN_BLUE 3
int ColorComp();
int CMAP_CList_Compare();
LONG CMAP_Find_Closest();
LONG CMAP_Find_Exact();
LONG CMAP_CHDR_Match();
void CMAP_Remap_CHDRs();
void CMAP_Remap_CHDR();
void CMAP_Compact_Box();
LONG CMAP_Split_Box();
void CMAP_Histogram_CHDR();
void CMAP_CMAP_From_Clist();
void CMAP_CList_CombSort();
void CMAP_CList_CombSort_Red();
void CMAP_CList_CombSort_Green();
void CMAP_CList_CombSort_Blue();
ULONG CMAP_Gamma_Adjust();
void CMAP_Shrink_CHDR();
void CMAP_Map_To_One();
LONG CMAP_Median_Cut();
CMAP_Box *CMAP_Get_Box();
void CMAP_Find_Box_Color();
LONG CMAP_Median_Compare_Red();
LONG CMAP_Median_Compare_Green();
LONG CMAP_Median_Compare_Blue();
LONG CMAP_Split_Box();
XA_CHDR *ACT_Get_CHDR();
XA_CHDR *ACT_Get_CMAP();
XA_CHDR *CMAP_Create_CHDR_From_True();
#if XJUNK
void X11_Get_Colormap();
void X11_Make_Nice_CHDR();
#endif
/*
*
*/
int ColorComp(c1,c2)
ColorReg *c1,*c2;
{
long val1,val2;
val1 = (3 * c1->red) + (4 * c1->green) + (2 * c1->blue);
val2 = (3 * c2->red) + (4 * c2->green) + (2 * c2->blue);
if (val1 != val2) return( val2 - val1 );
else if (c1->green != c2->green) return( c2->green - c1->green );
else if (c1->red != c2->red ) return( c2->red - c1->red );
else return( c2->blue - c1->blue );
}
/*
*
*/
LONG CMAP_Find_Closest(t_cmap,csize,r,g,b,rbits,gbits,bbits,color_flag)
ColorReg *t_cmap;
ULONG csize;
LONG r,g,b;
ULONG rbits,gbits,bbits;
ULONG color_flag;
{
register ULONG i,min_diff;
register LONG cmap_entry;
if (color_flag == FALSE)
{
register LONG gray;
gray = 11 * (r * cmap_scale[rbits]);
gray += 16 * (g * cmap_scale[gbits]);
gray += 5 * (b * cmap_scale[bbits]);
gray >>= 5;
cmap_entry = 0;
for(i=0; i<csize; i++)
{
register ULONG diff;
diff = CMAP_ABS(gray - (LONG)(t_cmap[i].gray));
if (i == 0) min_diff = diff;
if (diff == 0) return(i);
if (diff < min_diff) {min_diff = diff; cmap_entry = i;}
}
return(cmap_entry);
}
else
{
if (cur_find_cmap != t_cmap)
{
if (cur_find_cmap == 0)
{
for(i=0;i<256;i++)
{
find_red[i] = 11 * i * i;
find_green[i] = 16 * i * i;
find_blue[i] = 5 * i * i;
}
}
for(i=0;i<csize;i++)
{
find_cmap[i].red = t_cmap[i].red >> 8;
find_cmap[i].green = t_cmap[i].green >> 8;
find_cmap[i].blue = t_cmap[i].blue >> 8;
}
cur_find_cmap = t_cmap;
}
if (rbits < 16) r *= cmap_scale[rbits];
if (gbits < 16) g *= cmap_scale[gbits];
if (bbits < 16) b *= cmap_scale[bbits];
r >>= 8; g >>= 8; b >>= 8;
cmap_entry = 0;
for(i=0; i<csize; i++)
{
register ULONG diff;
diff = find_red[ CMAP_ABS(r - (LONG)(find_cmap[i].red)) ];
diff += find_green[ CMAP_ABS(g - (LONG)(find_cmap[i].green))];
diff += find_blue[ CMAP_ABS(b - (LONG)(find_cmap[i].blue)) ];
if (i == 0) min_diff = diff;
if (diff == 0) return(i);
if (diff < min_diff) {min_diff = diff; cmap_entry = i;}
}
return(cmap_entry);
}
}
/*
* return index of exact match.
* return -1 if no match found.
*/
LONG CMAP_Find_Exact(cmap,coff,csize,r,g,b,gray)
ColorReg *cmap;
ULONG coff,csize;
USHORT r,g,b,gray;
{
register LONG i,match;
match = -1;
i = csize;
if (x11_display_type & XA_X11_GRAY)
{
while( (i > coff) && (match < 0) )
{ i--; if (gray == cmap[i].gray) match = i; }
}
else
{
while( (i > coff) && (match < 0) )
{ i--;
if ( (r == cmap[i].red)
&& (g == cmap[i].green)
&& (b == cmap[i].blue) ) match = i;
}
}
return(match);
}
/*
*
*/
LONG CMAP_CHDR_Match(chdr1,chdr2)
XA_CHDR *chdr1,*chdr2;
{
ColorReg *cmap1,*cmap2;
ULONG i;
if (chdr1 == chdr2) return(TRUE);
if ( (chdr1->csize != chdr2->csize)
|| (chdr1->coff != chdr2->coff ) ) return(FALSE);
cmap1 = chdr1->cmap;
cmap2 = chdr2->cmap;
for(i=0; i < chdr1->csize; i++)
{
if ( (cmap1[i].red != cmap2[i].red)
|| (cmap1[i].green != cmap2[i].green)
|| (cmap1[i].blue != cmap2[i].blue) ) return(FALSE);
}
return(TRUE);
}
/*
*
*/
int CMAP_CList_Compare(c1,c2)
register LONG *c1,*c2;
{
return( (*c1) - (*c2) );
}
void
CMAP_BitMask_CList(clist,cnum,bits)
ULONG *clist,cnum,bits;
{
ULONG i,r_mask;
if ( (bits==0) || (bits>=9) ) TheEnd1("CMAP_BitMask_CList: bad bits");
r_mask = ((0x01 << bits) - 1);
r_mask <<= 8 - bits;
r_mask = (r_mask << 16) | (r_mask << 8) | r_mask;
for(i=0;i<cnum;i++) *clist++ &= r_mask;
}
ULONG CMAP_Compress_CList(clist,cnum)
ULONG *clist,cnum;
{
register ULONG i,j,data;
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Compress_CList: start %ld c %ld\n",
cnum,cmap_use_combsort);
if (cnum == 1) return(cnum);
/* sort color list */
if (cmap_use_combsort == TRUE) CMAP_CList_CombSort(clist,cnum);
else qsort(clist,cnum,sizeof(ULONG),CMAP_CList_Compare);
/* eliminate identical entries */
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Compress_CList: sort done %ld\n",cnum);
data = clist[0]; j = 1;
for(i=1; i<cnum; i++)
{
if (data != clist[i])
{
data = clist[i];
clist[j] = data; j++;
}
}
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Compress_CList: done %ld\n",j);
return(j);
}
/*
* return the total number of colors in all of the current chdr's
* also return the largest csize in max_csize if not NULL.
*/
ULONG CMAP_Color_Count(chdr,max_csize)
XA_CHDR *chdr;
ULONG *max_csize;
{
ULONG cnt,max_size;
cnt = max_size = 0;
while(chdr)
{
if (chdr->csize > max_size) max_size = chdr->csize;
cnt += chdr->csize;
chdr = chdr->next; }
if (max_csize != 0) *max_csize = max_size;
return(cnt);
}
ULONG CMAP_Make_Clist(chdr,clist)
XA_CHDR *chdr;
ULONG **clist;
{
ULONG *clst,clist_len,c_i;
/* count colors in chdr's */
clist_len = CMAP_Color_Count(chdr,0);
/* allocate room for list of all colors */
clst = (ULONG *)malloc(clist_len * sizeof(ULONG));
if (clst == 0) TheEnd1("CMAP_Make_Clist: malloc err\n");
c_i = 0;
while(chdr)
{
ColorReg *cmap;
ULONG i,csize,*hist,stat_size;
csize = chdr->csize;
cmap = chdr->cmap;
if (cmap_hist_flag == TRUE)
{
hist = (ULONG *)malloc(csize * sizeof(ULONG));
if (hist == 0) TheEnd1("CMAP_Manipulate_CHDRS: hist malloc err\n");
for(i=0;i<csize;i++) hist[i] = 0;
CMAP_Histogram_CHDR(chdr,hist,csize,chdr->moff);
stat_size = c_i;
} else hist = 0;
for(i=0; i<chdr->csize; i++)
{
if ( (cmap_hist_flag == FALSE)
|| ((cmap_hist_flag == TRUE) && hist[i]) )
{
/* note: cmap's are full 16 bits and clist is 0 r g b, 8 bits each*/
clst[c_i] = (cmap[i].red & 0xff00) << 8;
clst[c_i] |= cmap[i].green & 0xff00;
clst[c_i] |= (cmap[i].blue & 0xff00) >> 8;
c_i++;
}
}
if (hist) { FREE(hist,0x201); hist=0;}
if (cmap_hist_flag == TRUE)
{
DEBUG_LEVEL2
fprintf(stderr," csize %lx afta hist %ld\n",
chdr->csize,(c_i - stat_size) );
}
chdr = chdr->next;
}
*clist = clst;
return(c_i);
}
void
CMAP_Map_To_One()
{
XA_CHDR *new_chdr;
ULONG *clist,clist_len,i,wanted_csize;
ULONG actual_csize;
/* NOTE: clist is malloc'd in CMAP_Make_Clist */
clist_len = CMAP_Make_Clist(xa_chdr_start,&clist);
DEBUG_LEVEL2
fprintf(stderr,"CMAP_Map_To_One: start csize = %ld\n",clist_len);
wanted_csize = x11_cmap_size;
{
ULONG bits;
bits = 7;
while ( (clist_len >= wanted_csize) && (bits >= cmap_median_bits) )
{
CMAP_BitMask_CList(clist,clist_len,bits);
clist_len = CMAP_Compress_CList(clist,clist_len);
DEBUG_LEVEL2
fprintf(stderr,"CMAP_Map_To_One: bit %ld csize = %ld\n",bits,clist_len);
bits--;
}
if (clist_len < wanted_csize) wanted_csize = clist_len;
}
new_chdr = ACT_Get_CHDR(1,wanted_csize,0,wanted_csize,0,TRUE,TRUE);
if (clist_len > wanted_csize)
{
actual_csize = CMAP_Median_Cut(new_chdr->cmap,
clist,clist_len,wanted_csize);
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Median_Cut: csize %ld\n",actual_csize);
}
else
{
CMAP_CMAP_From_Clist(new_chdr->cmap,clist,clist_len);
actual_csize = clist_len;
DEBUG_LEVEL2 fprintf(stderr,"CMAP_CList: csize %ld\n",actual_csize);
}
FREE(clist,0x202); clist=0;
new_chdr->csize = actual_csize;
new_chdr->coff = x11_cmap_size - actual_csize;
new_chdr->msize = actual_csize;
new_chdr->moff = x11_cmap_size - actual_csize;
for(i=0; i<new_chdr->msize; i++) new_chdr->map[i] = i + new_chdr->moff;
#if XJUNK
if (cmap_play_nice == TRUE) X11_Make_Nice_CHDR(new_chdr);
#endif
CMAP_Remap_CHDRs(new_chdr);
xa_chdr_first = new_chdr;
}
void
CMAP_Shrink_CHDR(old_chdr,new_csize)
XA_CHDR *old_chdr;
ULONG new_csize;
{
XA_CHDR *new_chdr;
ULONG *clist,clist_len,i,wanted_csize;
ULONG actual_csize;
/* NOTE: clist is malloc'd in CMAP_Make_Clist */
clist_len = CMAP_Make_Clist(xa_chdr_start,&clist);
DEBUG_LEVEL2
fprintf(stderr,"CMAP_Shrink_CHDR: start csize = %ld\n",clist_len);
wanted_csize = new_csize;
{
ULONG bits;
bits = 7;
while ( (clist_len >= wanted_csize) && (bits >= cmap_median_bits) )
{
CMAP_BitMask_CList(clist,clist_len,bits);
clist_len = CMAP_Compress_CList(clist,clist_len);
DEBUG_LEVEL2
fprintf(stderr,"CMAP_Map_To_One: bit %ld csize = %ld\n",bits,clist_len);
bits--;
}
if (clist_len < wanted_csize) wanted_csize = clist_len;
}
new_chdr = ACT_Get_CHDR(1,wanted_csize,0,wanted_csize,0,TRUE,TRUE);
if (clist_len > wanted_csize)
{
actual_csize = CMAP_Median_Cut(new_chdr->cmap,
clist,clist_len,wanted_csize);
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Median_Cut: csize %ld\n",actual_csize);
}
else
{
CMAP_CMAP_From_Clist(new_chdr->cmap,clist,clist_len);
actual_csize = clist_len;
DEBUG_LEVEL2 fprintf(stderr,"CMAP_CList: csize %ld\n",actual_csize);
}
FREE(clist,0x202); clist=0;
new_chdr->csize = actual_csize;
new_chdr->coff = x11_cmap_size - actual_csize;
new_chdr->msize = actual_csize;
new_chdr->moff = x11_cmap_size - actual_csize;
for(i=0; i<new_chdr->msize; i++) new_chdr->map[i] = i + new_chdr->moff;
CMAP_Remap_CHDRs(new_chdr);
}
void
CMAP_Manipulate_CHDRS()
{
xa_chdr_first = xa_chdr_start;
if ( (x11_display_type & XA_X11_STATIC)
|| (x11_display_type & XA_X11_TRUE) )
{
XA_CHDR *fixed_chdr;
fixed_chdr = ACT_Get_CHDR(1,x11_cmap_size,0,x11_cmap_size,0,TRUE,TRUE);
#if XJUNK
X11_Get_Colormap(fixed_chdr);
#else
error("Could not get colormap.\n");
#endif
xa_chdr_first = fixed_chdr;
CMAP_Remap_CHDRs(fixed_chdr);
return;
}
else if ( (cmap_play_nice == TRUE) || (cmap_map_to_one_flag == TRUE)
|| (cmap_color_func == 4) )
{
CMAP_Map_To_One();
return;
}
else if (cmap_map_to_1st_flag == TRUE)
{
CMAP_Remap_CHDRs(xa_chdr_start);
return;
}
else if (x11_display_type != XA_MONOCHROME)
{ /* Check for CMAPs > x11_cmap_size */
ULONG flag;
XA_CHDR *tmp_chdr;
flag = 0;
tmp_chdr = xa_chdr_start;
while(tmp_chdr != 0)
{
if (tmp_chdr->csize > x11_cmap_size)
{
CMAP_Shrink_CHDR(tmp_chdr,x11_cmap_size);
if (flag == 0) xa_chdr_first = tmp_chdr->new_chdr;
}
tmp_chdr = tmp_chdr->next;
flag = 1;
}
}
}
void
CMAP_Remap_CHDR(new_chdr,old_chdr)
XA_CHDR *new_chdr,*old_chdr;
{
ColorReg *new_cmap,*old_cmap;
ULONG *tmp_map,*old_map;
ULONG new_csize,new_coff,old_csize,old_coff;
ULONG new_moff,old_msize,old_moff;
ULONG i,cflag;
old_cmap = old_chdr->cmap;
old_csize = old_chdr->csize;
old_coff = old_chdr->coff;
old_map = old_chdr->map;
old_msize = old_chdr->msize;
old_moff = old_chdr->moff;
new_csize = new_chdr->csize;
new_coff = new_chdr->coff;
new_cmap = new_chdr->cmap;
new_moff = new_chdr->moff;
tmp_map = (ULONG *)malloc(old_msize * sizeof(ULONG));
if (tmp_map == 0) TheEnd1("CMAP_Remap_CHDR: map malloc err\n");
cflag = (x11_display_type & XA_X11_COLOR)?TRUE:FALSE;
for(i=0; i < old_msize; i++)
{
ULONG j,match;
j = i + old_moff - old_coff; /* get cmap entry for this pixel */
if (x11_display_type & XA_X11_TRUE)
{
tmp_map[i] = X11_Get_True_Color(
old_cmap[j].red,old_cmap[j].green,old_cmap[j].blue,16);
}
else
{
match = CMAP_Find_Closest( new_cmap,new_csize,
old_cmap[j].red, old_cmap[j].green, old_cmap[j].blue,16,16,16,cflag);
tmp_map[i] = match + new_coff; /* new pixel value */
}
}
old_chdr->new_chdr = new_chdr;
FREE(old_chdr->map,0x203);
old_chdr->map = tmp_map;
}
void
CMAP_Remap_CHDRs(the_chdr)
XA_CHDR *the_chdr;
{
XA_CHDR *tmp_chdr;
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Remap_CHDRs to %lx\n",(ULONG)the_chdr);
tmp_chdr = xa_chdr_start;
while(tmp_chdr)
{
if (CMAP_CHDR_Match(the_chdr,tmp_chdr) == FALSE)
CMAP_Remap_CHDR(the_chdr,tmp_chdr);
tmp_chdr = tmp_chdr->next;
}
}
void
CMAP_CMAP_From_Clist(cmap_out,clist,clist_len)
ColorReg *cmap_out;
ULONG *clist,clist_len;
{
register ULONG i,r,g,b;
for(i=0;i<clist_len;i++)
{
r = (clist[i] >> 16) & 0xff;
g = (clist[i] >> 8) & 0xff;
b = clist[i] & 0xff;
cmap_out[i].red = (USHORT)(r * 257);
cmap_out[i].green = (USHORT)(g * 257);
cmap_out[i].blue = (USHORT)(b * 257);
cmap_out[i].gray =
(USHORT)( (((r * 11) + (g * 16) + (b * 5) ) >> 5) * 257 );
}
}
CMAP_Box *CMAP_Get_Box()
{
CMAP_Box *tmp;
tmp = (CMAP_Box *)malloc(sizeof(CMAP_Box));
if (tmp == 0) TheEnd1("CMAP_Get_Box: malloc err\n");
return(tmp);
}
LONG CMAP_Median_Cut(cmap_out,clist,clist_len,wanted_clen)
ColorReg *cmap_out;
ULONG *clist,clist_len,wanted_clen;
{
CMAP_Box *start_box,*box;
ULONG i,cur_box_num;
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Median_Cut: starting\n");
/* make first box */
start_box = CMAP_Get_Box();
start_box->clist = clist;
start_box->clist_len = clist_len;
start_box->next = 0;
CMAP_Compact_Box(start_box);
cur_box_num = 1;
while(cur_box_num < wanted_clen)
{
ULONG box_i,box_num;
/* loop through current boxes and split in half */
box_i = 0;
box_num = cur_box_num;
box = start_box;
while( box && (cur_box_num < wanted_clen) && (box_i < box_num) )
{
if ( CMAP_Split_Box(box) == TRUE )
{
cur_box_num++;
box = box->next; /* move past new box */
}
box_i++;
box = box->next;
}
if (box_num == cur_box_num) break; /* no boxes split */
}
box = start_box;
for(i=0; i<cur_box_num; i++)
{
if (box)
{
CMAP_Find_Box_Color(&cmap_out[i],box);
box = box->next;
}
else fprintf(stderr,"CMAP_Median_Cut: box/box_num mismatch\n");
}
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Median_Cut: done\n");
return(cur_box_num);
}
void
CMAP_Compact_Box(box)
CMAP_Box *box;
{
LONG i;
DEBUG_LEVEL3 fprintf(stderr,"Compacting Box %lx\n",(ULONG)box);
/* 256 is max+1 in 8 bit r,g,b */
box->rmin = box->gmin = box->bmin = 256;
box->rmax = box->gmax = box->bmax = -1;
for(i=0; i<box->clist_len; i++)
{
register LONG r,g,b;
b = box->clist[i];
r = (b >> 16) & 0xff;
g = (b >> 8) & 0xff;
b &= 0xff;
if (r < box->rmin) box->rmin = r;
if (g < box->gmin) box->gmin = g;
if (b < box->bmin) box->bmin = b;
if (r > box->rmax) box->rmax = r;
if (g > box->gmax) box->gmax = g;
if (b > box->bmax) box->bmax = b;
}
}
LONG CMAP_Median_Compare_Red(c1,c2)
register LONG *c1,*c2;
{
return( ((*c1) & 0xff0000) - ((*c2) & 0xff0000) );
}
LONG CMAP_Median_Compare_Green(c1,c2)
register LONG *c1,*c2;
{
return( ((*c1) & 0xff00) - ((*c2) & 0xff00) );
}
LONG CMAP_Median_Compare_Blue(c1,c2)
register LONG *c1,*c2;
{
return( ((*c1) & 0xff) - ((*c2) & 0xff) );
}
LONG CMAP_Split_Box(box)
CMAP_Box *box;
{
CMAP_Box *newbox;
register LONG sort_type,rdif,gdif,bdif;
rdif = box->rmax - box->rmin;
gdif = box->gmax - box->gmin;
bdif = box->bmax - box->bmin;
if (box->clist_len <= 1) return(FALSE);
if ((rdif >= gdif) && (rdif >= bdif)) sort_type = CMAP_MEDIAN_RED;
else if ((gdif >= rdif) && (gdif >= bdif)) sort_type = CMAP_MEDIAN_GREEN;
else sort_type = CMAP_MEDIAN_BLUE;
if (box->last_sort != sort_type)
{
if (cmap_use_combsort == TRUE)
switch(sort_type)
{
case CMAP_MEDIAN_RED:
CMAP_CList_CombSort_Red(box->clist,box->clist_len); break;
case CMAP_MEDIAN_GREEN:
CMAP_CList_CombSort_Green(box->clist,box->clist_len); break;
default:
CMAP_CList_CombSort_Blue(box->clist,box->clist_len); break;
}
else
switch(sort_type)
{
case CMAP_MEDIAN_RED: qsort(box->clist,box->clist_len,
sizeof(LONG),CMAP_Median_Compare_Red); break;
case CMAP_MEDIAN_GREEN: qsort(box->clist,box->clist_len,
sizeof(LONG),CMAP_Median_Compare_Green); break;
default: qsort(box->clist,box->clist_len,
sizeof(LONG),CMAP_Median_Compare_Blue); break;
}
box->last_sort = sort_type;
}
newbox = CMAP_Get_Box();
newbox->next = box->next;
box->next = newbox;
/* split color list */
newbox->clist_len = box->clist_len / 2;
box->clist_len -= newbox->clist_len;
newbox->clist = &box->clist[box->clist_len];
newbox->last_sort = sort_type;
CMAP_Compact_Box(box);
CMAP_Compact_Box(newbox);
return(TRUE);
}
/*
* Assumes 8 bits per color component
*/
void
CMAP_Find_Box_Color(creg,box)
ColorReg *creg;
CMAP_Box *box;
{
register LONG i;
register ULONG r,g,b,sum;
DEBUG_LEVEL3 fprintf(stderr," box has %ld\n",box->clist_len);
if (cmap_median_type == CMAP_MEDIAN_SUM)
{
r=0; g=0; b=0; sum=0;
for(i=0; i<box->clist_len; i++)
{
register ULONG tcol;
tcol = box->clist[i];
r += (tcol >> 16) & 0xff;
g += (tcol >> 8) & 0xff;
b += tcol & 0xff;
}
sum = box->clist_len;
r /= sum; g /= sum; b /= sum;
}
else
{
r = (box->rmin + box->rmax) >> 1;
g = (box->gmin + box->gmax) >> 1;
b = (box->bmin + box->bmax) >> 1;
}
creg->red = r * 257;
creg->green = g * 257;
creg->blue = b * 257;
creg->gray = (((r * 11) + (g * 16) + (b * 5) ) >> 5) * 257;
}
void
CMAP_Histogram_CHDR(chdr,hist,csize,moff)
XA_CHDR *chdr;
ULONG *hist,csize,moff;
{
XA_ACTION *act;
DEBUG_LEVEL2 fprintf(stderr,"Histogram for %lx\n",(ULONG)chdr);
act = chdr->acts;
while(act)
{
switch(act->type)
{
case ACT_DISP:
case ACT_MAPPED:
{
register UBYTE *p;
register ULONG psize;
ACT_MAPPED_HDR *map_hdr;
DEBUG_LEVEL2 fprintf(stderr," hist'ing act %lx\n",(ULONG)act);
map_hdr = (ACT_MAPPED_HDR *)act->data;
psize = map_hdr->xsize * map_hdr->ysize;
p = map_hdr->data;
if (p)
{
if (moff) while(psize--) hist[ (*p++)-moff ]++;
else while(psize--) hist[ *p++ ]++;
}
}
break;
/*
case ACT_SETTER:
{
register UBYTE *p;
register ULONG psize;
ACT_MAPPED_HDR *map_hdr;
ACT_SETTER_HDR *setter_hdr;
XA_ACTION *back_act;
DEBUG_LEVEL2 fprintf(stderr," hist'ing setter act %lx\n",act);
setter_hdr = (ACT_SETTER_HDR *)act->data;
back_act = setter_hdr->back;
if (back_act)
{
map_hdr = (ACT_MAPPED_HDR *)back_act->data;
psize = map_hdr->xsize * map_hdr->ysize;
DEBUG_LEVEL2 fprintf(stderr,"psize = %ld\n",psize);
p = map_hdr->data;
if (p)
{
if (moff) while(psize--) hist[ (*p++)-moff ]++;
else while(psize--) hist[ *p++ ]++;
}
}
}
break;
*/
} /* end of switch */
act = act->next_same_chdr;
} /* end of while */
}
void CMAP_Expand_Maps()
{
XA_CHDR *tmp_chdr;
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Expand_Maps\n");
tmp_chdr = xa_chdr_start;
while(tmp_chdr)
{
register ULONG i,msize,d,*map;
msize = tmp_chdr->msize;
map = tmp_chdr->map;
if (map)
for(i=0;i<msize;i++)
{
d = map[i] & 0xff;
map[i] = (d<<24) | (d<<16) | (d<<8) | d;
}
tmp_chdr = tmp_chdr->next;
}
}
void
CMAP_Cache_Init()
{
cmap_cache_bits = cmap_median_bits;
if (cmap_cache_bits > CMAP_CACHE_MAX_BITS)
cmap_cache_bits = CMAP_CACHE_MAX_BITS;
cmap_cache_size = 0x01 << (cmap_cache_bits * 3);
cmap_cache = (USHORT *)malloc(cmap_cache_size * sizeof(USHORT));
cmap_cache_bmask = ( (0x01 << cmap_cache_bits) - 1) << 8;
cmap_cache_gmask = cmap_cache_bmask << cmap_cache_bits;
cmap_cache_rmask = cmap_cache_gmask << cmap_cache_bits;
if (cmap_cache == 0) TheEnd1("CMAP_CACHE: malloc err");
cmap_cache_chdr = 0;
DEBUG_LEVEL3 fprintf(stderr,"cache mask's %lx %lx %lx\n",
cmap_cache_rmask,cmap_cache_gmask,cmap_cache_bmask);
}
/*
* Set CMAP cache to all 0xffff's. Since CMAP's are currently limited
* to 256 in size, this is a non-valid value.
*/
void
CMAP_Cache_Clear()
{
register USHORT *tp;
register ULONG i;
tp = cmap_cache; i = cmap_cache_size;
while(i--) *tp++ = 0xffff;
}
ULONG CMAP_Get_Or_Mask(cmap_size)
ULONG cmap_size; /* number of colors in anim cmap */
{
ULONG or_mask,imagec;
/* if image is getting remapped then this doesn't matter */
if ( (cmap_play_nice == TRUE)
|| (x11_display_type & XA_X11_TRUE)
|| (x11_display_type & XA_X11_STATIC)
|| (x11_display_type == XA_MONOCHROME) ) return(0);
if (cmap_size >= x11_cmap_size) return(0); /* needs to be quant'd */
/* find largest power of 2 <= display's cmap size */
or_mask = 0x01;
while(or_mask <= x11_cmap_size) or_mask <<= 1;
or_mask >>=1;
/* round cmap_size up to nearest power of two */
imagec = 0x01;
while(imagec <= cmap_size) imagec <<= 1;
imagec >>=1;
if (imagec >= or_mask) return(0);
return(or_mask - imagec);
}
/*
*
* affects global variables
* iff_r_shift
* iff_g_shift
* iff_b_shift
* iff_r_mask
* iff_g_mask
* iff_b_mask
*
* Creates 332 CHDR if doesn't exist.
* copies cmap of 332 CHDR into given cmap.
* sets csize to 332 CHDR size.
*
*/
XA_CHDR *CMAP_Create_332(cmap,csize)
ColorReg *cmap;
ULONG *csize;
{
ULONG i,size;
if ( (cmap_332_chdr == 0) || (cmap_cur_gamma != cmap_332_gamma) )
{
ULONG r_bits,g_bits,b_bits,last,disp_bits;
ULONG r_scale,g_scale,b_scale;
if (x11_display_type == XA_MONOCHROME) { size = 256; disp_bits = 8; }
else
{
size = 0x01; disp_bits = 0;
while(size <= x11_cmap_size) { size <<= 1; disp_bits++; }
size >>=1; disp_bits--;
}
r_bits = 3; g_bits = 3; b_bits = 3; last = 2;
while( (r_bits + g_bits + b_bits) > disp_bits)
{
switch(last)
{
case 0: g_bits--; last++; break;
case 1: r_bits--; last++; break;
default: b_bits--; last=0; break;
}
}
xa_b_shift = 16 - b_bits;
xa_b_mask = ((0x01 << b_bits) - 1) << (16 - b_bits);
xa_g_shift = xa_b_shift - g_bits;
xa_g_mask = ((0x01 << g_bits) - 1) << (16 - g_bits);
xa_r_shift = xa_g_shift - r_bits;
xa_r_mask = ((0x01 << r_bits) - 1) << (16 - r_bits);
DEBUG_LEVEL3
{
fprintf(stderr,"CMAP_Create_332: %ld: %ld %ld %ld\n",
disp_bits,r_bits,g_bits,b_bits);
fprintf(stderr,"CMAP_Create_332: masks: %lx %lx %lx\n",
xa_r_mask,xa_g_mask,xa_b_mask);
fprintf(stderr,"CMAP_Create_332: shifts: %lx %lx %lx\n",
xa_r_shift,xa_g_shift,xa_b_shift);
}
i = r_bits + g_bits + b_bits;
*csize = size = 0x01 << i;
r_scale = cmap_scale[r_bits];
g_scale = cmap_scale[g_bits];
b_scale = cmap_scale[b_bits];
{
register ULONG rmsk,gmsk,bmsk,rshft,gshft;
gshft = b_bits; rshft = b_bits + g_bits;
bmsk = (0x01 << b_bits) - 1;
gmsk = ((0x01 << g_bits) - 1) << gshft;
rmsk = ((0x01 << r_bits) - 1) << rshft;
for(i=0;i<size;i++)
{
ULONG r,g,b;
cmap[i].red = r = ( (i & rmsk) >> rshft ) * r_scale;
cmap[i].green = g = ( (i & gmsk) >> gshft ) * g_scale;
cmap[i].blue = b = ( i & bmsk ) * b_scale;
cmap[i].gray = ((r * 11) + (g * 16) + (b * 5)) >> 5;
}
}
cmap_332_chdr = ACT_Get_CMAP(cmap,size,0,size,0,16,16,16);
cmap_332_gamma = cmap_cur_gamma;
} /* end of create cmap_332_chdr */
else
{
ColorReg *cmap332;
*csize = size = cmap_332_chdr->csize;
cmap332 = cmap_332_chdr->cmap;
for(i=0;i<size;i++)
{
cmap[i].red = cmap332[i].red;
cmap[i].green = cmap332[i].green;
cmap[i].blue = cmap332[i].blue;
cmap[i].gray = cmap332[i].gray;
}
}
return(cmap_332_chdr);
}
XA_CHDR *CMAP_Create_Gray(cmap,csize)
ColorReg *cmap;
ULONG *csize;
{
ULONG i,size;
if ( (cmap_gray_chdr == 0) || (cmap_cur_gamma != cmap_gray_gamma) )
{
ULONG disp_bits;
ULONG g_scale;
/* find number of bits in display or use 256 if monochrome */
if (x11_display_type == XA_MONOCHROME) { disp_bits = 8; size = 256; }
else
{
size = 0x01; disp_bits = 0;
while(size <= x11_cmap_size) { size <<= 1; disp_bits++; }
size >>=1; disp_bits--;
}
xa_gray_bits = disp_bits;
xa_gray_shift = 16 - disp_bits;
DEBUG_LEVEL3 fprintf(stderr,"Gray: bits %ld shift %ld\n",
disp_bits,xa_gray_shift);
g_scale = cmap_scale[disp_bits];
*csize = size;
for(i=0;i<size;i++) cmap[i].red = cmap[i].green = cmap[i].blue
= cmap[i].gray = i * g_scale;
cmap_gray_chdr = ACT_Get_CMAP(cmap,size,0,size,0,16,16,16);
cmap_gray_gamma = cmap_cur_gamma;
}
else
{
*csize = size = cmap_gray_chdr->csize;
for(i=0;i<size;i++) cmap[i].red = cmap[i].green = cmap[i].blue
= cmap_gray_chdr->cmap[i].gray;
}
return(cmap_gray_chdr);
}
/*
*
*
*/
XA_CHDR *CMAP_Create_CHDR_From_True(ipic,rbits,gbits,bbits,
width,height,cmap,csize)
UBYTE *ipic;
ULONG rbits,gbits,bbits;
ULONG width,height;
ColorReg *cmap;
ULONG *csize;
{
XA_CHDR *new_chdr;
ULONG *clist,clist_len,wanted_csize;
register ULONG i,rshift,gshift,bshift;
/* NOTE: should make sure 2^(rbits+gbits+bbits) is < (width*height) */
/* optimize for space if so */
if ( (rbits > 8) | (gbits > 8) | (bbits > 8) )
TheEnd1("CMAP_Create_CHDR_From_True: bits > 24 err");
clist_len = width * height;
clist = (ULONG *) malloc( clist_len * sizeof(ULONG) );
if (clist == 0) TheEnd1("CMAP_Create_CHDR_From_True: malloc err");
rshift = 24 - rbits;
gshift = 16 - gbits;
bshift = 8 - bbits;
for(i=0; i < clist_len; i++)
{
register ULONG r,g,b;
r = (ULONG)(*ipic++);
g = (ULONG)(*ipic++);
b = (ULONG)(*ipic++);
clist[i] = (r << rshift) | (g << gshift) | (b << bshift);
}
wanted_csize = x11_cmap_size;
DEBUG_LEVEL2 fprintf(stderr,"TRUE_CHDR: cnum = %ld wanted =%ld\n",
clist_len,wanted_csize);
CMAP_BitMask_CList(clist,clist_len,cmap_median_bits);
clist_len = CMAP_Compress_CList(clist,clist_len);
DEBUG_LEVEL2 fprintf(stderr,"TRUE_CHDR: compress cnum = %ld\n",clist_len);
if (clist_len < wanted_csize) wanted_csize = clist_len;
new_chdr = ACT_Get_CHDR(1,wanted_csize,0,wanted_csize,0,TRUE,TRUE);
if (clist_len > wanted_csize)
{
wanted_csize =
CMAP_Median_Cut(new_chdr->cmap,clist,clist_len,wanted_csize);
DEBUG_LEVEL2 fprintf(stderr,"TRUE_CHDR: median cnum = %ld\n",wanted_csize);
}
else
{
wanted_csize = clist_len;
CMAP_CMAP_From_Clist(new_chdr->cmap,clist,clist_len);
}
FREE(clist,0x204); clist=0;
*csize = wanted_csize;
for(i=0;i<wanted_csize;i++) cmap[i] = new_chdr->cmap[i];
new_chdr->csize = wanted_csize;
new_chdr->coff = x11_cmap_size - wanted_csize;
new_chdr->msize = wanted_csize;
new_chdr->moff = x11_cmap_size - wanted_csize;
for(i=0; i<new_chdr->msize; i++) new_chdr->map[i] = i + new_chdr->moff;
return(new_chdr);
}
void CMAP_CList_CombSort(clist,cnum)
ULONG *clist,cnum;
{
register ULONG ShrinkFactor,gap,i,temp,finished;
ShrinkFactor = 13; gap = cnum;
do
{
finished = 1; gap = (gap * 10) / ShrinkFactor;
if (gap < 1) gap = 1;
if ( (gap==9) | (gap == 10) ) gap = 11;
for(i=0; i < (cnum - gap); i++)
{
if (clist[i] < clist[i+gap])
{
temp = clist[i]; clist[i] = clist[i+gap];
clist[i+gap] = temp;
finished = 0;
}
}
} while( !finished || (gap > 1) );
}
void CMAP_CList_CombSort_Red(clist,cnum)
ULONG *clist,cnum;
{
register ULONG ShrinkFactor,gap,i,temp,finished;
ShrinkFactor = 13; gap = cnum;
do
{
finished = 1; gap = (gap * 10) / ShrinkFactor;
if (gap < 1) gap = 1;
if ( (gap==9) | (gap == 10) ) gap = 11;
for(i=0; i < (cnum - gap); i++)
{
if ( (clist[i] & 0xff0000) < (clist[i+gap] & 0xff0000) )
{
temp = clist[i]; clist[i] = clist[i+gap];
clist[i+gap] = temp;
finished = 0;
}
}
} while( !finished || (gap > 1) );
}
void CMAP_CList_CombSort_Green(clist,cnum)
ULONG *clist,cnum;
{
register ULONG ShrinkFactor,gap,i,temp,finished;
ShrinkFactor = 13; gap = cnum;
do
{
finished = 1; gap = (gap * 10) / ShrinkFactor;
if (gap < 1) gap = 1;
if ( (gap==9) | (gap == 10) ) gap = 11;
for(i=0; i < (cnum - gap); i++)
{
if ( (clist[i] & 0xff00) < (clist[i+gap] & 0xff00) )
{
temp = clist[i]; clist[i] = clist[i+gap];
clist[i+gap] = temp;
finished = 0;
}
}
} while( !finished || (gap > 1) );
}
void CMAP_CList_CombSort_Blue(clist,cnum)
ULONG *clist,cnum;
{
register ULONG ShrinkFactor,gap,i,temp,finished;
ShrinkFactor = 13; gap = cnum;
do
{
finished = 1; gap = (gap * 10) / ShrinkFactor;
if (gap < 1) gap = 1;
if ( (gap==9) | (gap == 10) ) gap = 11;
for(i=0; i < (cnum - gap); i++)
{
if ( (clist[i] & 0xff) < (clist[i+gap] & 0xff) )
{
temp = clist[i]; clist[i] = clist[i+gap];
clist[i+gap] = temp;
finished = 0;
}
}
} while( !finished || (gap > 1) );
}
ULONG CMAP_Gamma_Adjust(gamma_adj,disp_gamma,anim_gamma)
USHORT *gamma_adj;
double disp_gamma,anim_gamma;
{
register ULONG i;
double pow(),t64k,d;
DEBUG_LEVEL2 fprintf(stderr,"CMAP_Gamma_Adjust\n");
if (disp_gamma < GAMMA_MIN) disp_gamma = 1.0;
if (anim_gamma < GAMMA_MIN) anim_gamma = 1.0;
cmap_cur_gamma = anim_gamma/disp_gamma;
t64k = (double)(65535.0);
for(i=0;i<256;i++)
{
d = (double)(i * 257)/t64k;
gamma_adj[i] = (USHORT)(0.5 + t64k * pow(d, cmap_cur_gamma));
}
if (disp_gamma == anim_gamma) return(FALSE);
else return(TRUE);
}
/*
*
* affects global variables
* iff_r_shift
* iff_g_shift
* iff_b_shift
* iff_r_mask
* iff_g_mask
* iff_b_mask
*
* Creates 422 CHDR if doesn't exist.
* copies cmap of 422 CHDR into given cmap.
* sets csize to 422 CHDR size.
*
*/
XA_CHDR *CMAP_Create_422(cmap,csize)
ColorReg *cmap;
ULONG *csize;
{
ULONG i,size;
ULONG r_bits,g_bits,b_bits,last,disp_bits;
ULONG r_scale,g_scale,b_scale;
XA_CHDR *chdr_422;
if (x11_display_type == XA_MONOCHROME) { size = 256; disp_bits = 8; }
else
{
size = 0x01; disp_bits = 0;
while(size <= x11_cmap_size) { size <<= 1; disp_bits++; }
size >>=1; disp_bits--;
}
r_bits = 4; g_bits = 2; b_bits = 2; last = 0;
while( (r_bits + g_bits + b_bits) > disp_bits)
{
switch(last)
{
case 0: g_bits--; last++; break;
case 1: r_bits--; last++; break;
default: b_bits--; last=0; break;
}
}
xa_b_shift = 16 - b_bits;
xa_b_mask = ((0x01 << b_bits) - 1) << (16 - b_bits);
xa_g_shift = xa_b_shift - g_bits;
xa_g_mask = ((0x01 << g_bits) - 1) << (16 - g_bits);
xa_r_shift = xa_g_shift - r_bits;
xa_r_mask = ((0x01 << r_bits) - 1) << (16 - r_bits);
i = r_bits + g_bits + b_bits;
*csize = size = 0x01 << i;
r_scale = cmap_scale[r_bits];
g_scale = cmap_scale[g_bits];
b_scale = cmap_scale[b_bits];
{
register ULONG rmsk,gmsk,bmsk,rshft,gshft;
gshft = b_bits; rshft = b_bits + g_bits;
bmsk = (0x01 << b_bits) - 1;
gmsk = ((0x01 << g_bits) - 1) << gshft;
rmsk = ((0x01 << r_bits) - 1) << rshft;
for(i=0;i<size;i++)
{
ULONG r,g,b;
cmap[i].red = r = ( (i & rmsk) >> rshft ) * r_scale;
cmap[i].green = g = ( (i & gmsk) >> gshft ) * g_scale;
cmap[i].blue = b = ( i & bmsk ) * b_scale;
cmap[i].gray = ((r * 11) + (g * 16) + (b * 5)) >> 5;
}
}
chdr_422 = ACT_Get_CMAP(cmap,size,0,size,0,16,16,16);
return(chdr_422);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.