source: abuse/tags/pd/imlib/palette.c @ 49

Last change on this file since 49 was 49, checked in by Sam Hocevar, 11 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 10.4 KB
Line 
1#include "palette.hpp"
2#include "image.hpp"
3#include "macs.hpp"
4#include "dos.h"
5#include "video.hpp"
6#include "filter.hpp"
7#include "jmalloc.hpp"
8#include <math.h>
9
10palette *lastl=NULL;
11
12palette::palette(bFILE *fp)
13{
14  ncolors=fp->read_short();
15  pal=(color *)jmalloc(sizeof(color)*ncolors,"palette");
16  usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
17  set_all_unused();
18  fp->read(pal,sizeof(color)*ncolors);
19  bg=0;
20}
21
22palette::palette(spec_entry *e, bFILE *fp)
23{
24  fp->seek(e->offset,0);
25  ncolors=fp->read_short();
26  pal=(color *)jmalloc(sizeof(color)*ncolors,"palette");
27  usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
28  set_all_unused();
29  fp->read(pal,sizeof(color)*ncolors);
30  bg=0;
31}
32
33int palette::size()
34{
35  return ncolors*sizeof(color)+2;
36}
37
38int palette::write(bFILE *fp)
39{
40  fp->write_short(ncolors);
41  return fp->write(pal,sizeof(color)*ncolors)==ncolors;
42}
43
44int palette::find_closest(unsigned char r, unsigned char g, unsigned char b)
45{
46   unsigned char *cl=(unsigned char *)addr();
47   int c=0,d=0x100000,i,nd;
48   for (i=0;i<256;i++)
49   {
50     nd=((int)r-(int)(*cl))*((int)r-(int)(*cl)); cl++;
51     nd+=((int)g-(int)(*cl))*((int)g-(int)(*cl)); cl++;
52     nd+=((int)b-(int)(*cl))*((int)b-(int)(*cl)); cl++;
53     if (nd<d)
54     { c=i; d=nd; }
55   }
56   return c;
57}
58
59
60int palette::find_closest_non0(unsigned char r, unsigned char g, unsigned char b)
61{
62   unsigned char *cl=(unsigned char *)addr()+3;
63   int c=1,d=0x7fffffff,i,nd;
64   for (i=1;i<256;i++)
65   {
66     nd=((int)r-(int)(*cl))*((int)r-(int)(*cl)); cl++;
67     nd+=((int)g-(int)(*cl))*((int)g-(int)(*cl)); cl++;
68     nd+=((int)b-(int)(*cl))*((int)b-(int)(*cl)); cl++;
69     if (nd<d)
70     { c=i; d=nd; }
71   }
72   return c;
73}
74
75
76int palette::find_color(unsigned char r, unsigned char g, unsigned char b)
77{
78  int i,ub,mask,find;
79  for (i=0,ub=0,mask=128,find=-1;i<ncolors && find<0;i++)
80  {
81    if (usd[ub]&mask)
82      if (r==pal[i].red && b==pal[i].blue && g==pal[i].green)
83        find=i;
84    mask>>=1;
85    if (mask==0)
86    { mask=128; ub++; }
87  }
88  return find;
89}
90
91long palette::getquad(int x)
92{ char entry[4];
93  entry[3]=0;
94  entry[2]=pal[x].red;
95  entry[1]=pal[x].green;
96  entry[0]=pal[x].blue;
97  return *((long *)entry);
98}
99
100
101void palette::black_white()
102{
103  int i;
104  unsigned char r,g,b,gr;
105
106  for (i=0;i<256;i++)
107  {
108    get(i,r,g,b);
109    gr=(unsigned char)((double) r*0.30+(double) g*0.59+(double)b*0.11);
110    set(i,gr,gr,gr);
111  }
112}
113
114void palette::make_black_white()
115{
116  int i,c;
117  set(0,0,0,0);
118  for (i=1;i<ncolors;i++)
119  { c=(int)((double)i/(double)ncolors*(double)255);
120    set(i,c,c,c);
121  }
122}
123
124void palette::set_rgbs()
125{
126  int i,v;
127  CHECK(ncolors==256);
128  for (i=0;i<64;i++)
129  {
130    if (i==0) v=0;
131    else
132    {
133      v=(int) ((double)i+(double)(sqrt(63-i)));
134      v<<=2;
135    }
136
137    set(i,         i,     0,     0);            // reds 0-63
138    set(i+64,      0,     i,     0);
139    set(i+128,     0,     0,     i);       // blues 128-191
140    set(i+128+64,  v,     v,     v);        // whites .. rest
141  }
142  set_all_used();
143}
144
145void palette::set_all_used()
146{
147  int i;
148  for (i=0;i<ncolors;i++) set_used(i);
149}
150
151void palette::set_all_unused()
152{
153  int i;
154  for (i=0;i<ncolors;i++) set_unused(i);
155}
156
157
158palette *palette::copy()
159{
160  palette *p;
161  int i;
162  p=new palette(ncolors);
163  for (i=0;i<ncolors;i++)
164  {
165    if (used(i))
166      p->set_used(i);
167    else p->set_unused(i);
168    p->set(i,red(i),green(i),blue(i));
169  }
170  return p;
171}
172
173void palette::set_used(int color_num)
174{
175  int x,b;
176  CHECK(color_num>=0 && color_num<ncolors);
177  x=color_num/8;
178  b=color_num%8;
179  usd[x]|=(128>>b);
180}
181
182void palette::set_unused(int color_num)
183{
184  int x,b;
185  CHECK(color_num>=0 && color_num<ncolors);
186  x=color_num/8;
187  b=color_num%8;
188  usd[x]&=(0xff^(128>>b));
189}
190
191int palette::used(int color_num)
192{
193  int x,b;
194  CHECK(color_num>=0 && color_num<ncolors);
195  x=color_num/8;
196  b=color_num%8;
197  return (usd[x]&(128>>b));
198}
199
200int palette::add_color(unsigned int r, int unsigned g, int unsigned b, int closest_only)
201{
202  int i,f,u,c;
203  if (!closest_only)
204  {
205    for (i=ncolors-1,f=-1,u=-1;i>=0 && f<0;i--)
206    {
207      if (used(i))
208      {
209        if (pal[i].red==r && pal[i].green==g && pal[i].blue==b)
210        f=i;
211      }
212      else
213        u=i;
214    }
215  } else { f=-1; u=-1; }
216  if (f<0)
217  {
218    if (u>=0)
219    { pal[u].red=r;
220      pal[u].green=g;
221      pal[u].blue=b;
222      set_used(u);
223      f=u;
224    }
225    else
226    {
227      for (i=0,f=0,u=10000;i<ncolors;i++)
228      { c=(pal[i].red-r)*(pal[i].red-r)+
229          (pal[i].green-g)*(pal[i].green-g)+
230          (pal[i].blue-b)*(pal[i].blue-b);
231        if (c<u)
232        { f=i;
233          u=c;
234        }
235      }
236    }
237  }
238  return f;
239}
240
241void palette::defaults()
242{
243  int i;
244  set(0,0,0,0);
245  set_used(0);
246  for (i=1;i<ncolors;i++)
247    set_unused(i);
248  if (ncolors==256)
249    for (i=0;i<ncolors;i++)
250      set(i,RED3(i),GREEN3(i),BLUE2(i));
251  else if (ncolors==16)
252    for (i=0;i<ncolors;i++)
253      set(i,255-i&3,255-(i&4)>>2,255-(i&8)>>3);
254  else
255    for (i=0;i<ncolors;i++)
256      set(i,255-i%3,255-(i+1)%3,255-(i+2)%3);
257}
258
259void palette::shift(int amount)
260{
261  int i;
262  unsigned char m;
263  if (amount<0)
264  {
265
266    m=-amount;
267    for (i=0;i<ncolors*3;i++)
268      ((unsigned char *) pal)[i]>>=m;
269  }
270  else if (amount>0)
271  {
272    m=amount;
273    for (i=0;i<ncolors*3;i++)
274      ((unsigned char *) pal)[i]<<=m;
275  }
276}
277
278
279
280void palette::set(int x, unsigned char red, char unsigned green, char unsigned blue)
281{ CONDITION(x>=0 && x<ncolors,"Pallete::set passed bad x");
282  CONDITION((int)red<=ncolors && (int)green<=ncolors && (int)blue<=ncolors,
283            "pallette::set color values bigger than palette");
284  pal[x].red=red; pal[x].green=green; pal[x].blue=blue;
285}
286
287void palette::get(int x, unsigned char &red, unsigned char &green, unsigned char &blue)
288{ CONDITION(x>=0 && x<ncolors,"Pallete::get passed bad x");
289  red=pal[x].red; green=pal[x].green; blue=pal[x].blue;
290}
291palette::~palette()
292{ if (pal) jfree(pal);
293  if (usd) jfree(usd);
294}
295
296palette::palette(int number_colors)
297{
298  CONDITION(number_colors>0,"palette::constructor - need at least one color!");
299  ncolors=number_colors;
300  bg=0;
301  pal=(color *)jmalloc(ncolors*3,"palette");
302  usd=(unsigned char *)jmalloc(ncolors/8+1,"palette used array");
303  defaults();
304}
305
306
307
308quant_node::~quant_node()
309{
310/*  if (!is_leaf())
311  { for (i=0;i<8;i++)
312      if (children[i])
313      { delete children[i];
314        children[i]=NULL;
315      }
316  } */
317}
318
319
320/*void quant_node::prune()
321{
322  int t,r,g,b;
323  CONDITION(!is_leaf(),"Cannot prune a leaf!");
324  total(t,r,g,b);
325  red=r/t;
326  green=g/t;
327  blue=b/t;
328  be_childish();
329} */
330
331void quant_node::total(int &tnodes, int &tr, int &tg, int &tb)
332{
333  int i;
334  if (is_leaf())
335  { tnodes+=tot;
336    tr+=red*tot;
337    tg+=green*tot;
338    tb+=blue*tot;
339  }
340  else
341  { for (i=0;i<8;i++)
342      if (children[i])
343        children[i]->total(tnodes,tr,tg,tb);
344  }
345}
346
347quant_node::quant_node(int level, quant_node *dad,
348        unsigned char r, unsigned char g, unsigned char b)
349{
350  int i;
351  CONDITION(level<=8,"Tree cannot have more than eight levels");
352  if (level==8)
353    be_childish();
354  else
355    for (i=0;i<8;i++) children[i]=NULL;
356  padre=dad;
357  red=r; green=g; blue=b;
358  tot=0;
359}
360
361quant_palette::quant_palette(int max_colors)
362{ root=NULL; nc=0; mx=max_colors; }
363
364void quant_palette::re_delete(quant_node *who, int lev)  // removes all children from memory
365{ int x;                                  // and recurses down
366  if (who)
367  {
368    if (!who->is_leaf())
369    { for (x=0;x<8;x++)
370        if (who->children[x])
371        {
372          CONDITION(lev<8,"Levl > 7");
373          re_delete(who->children[x],lev+1);
374          level[lev].unlink((linked_node *)who->children[x]);
375          delete who->children[x];
376        }
377    }
378  }
379}
380
381void quant_palette::prune()
382{
383  int pruned,lev,x,r,g,b,t;
384  quant_node *p,*f;
385  for (pruned=0,lev=8;lev>1 && !pruned;lev--)
386  {
387    p=(quant_node *)level[lev-1].first();
388    if (p)
389    { do
390      {
391        f=p->father();
392        for (x=0;x<8 && !pruned;x++)
393          if (f->children[x])
394            if (f->children[x]->next()!=p->next())        // if this son is not me!
395            pruned=1;                   //  I have a brother! stop
396       p=(quant_node *)p->next();
397      } while ((linked_node *) p!=level[lev-1].first() && !pruned);
398    }
399  }
400  CONDITION(lev>0,"could not prune!");
401  t=0; r=0; g=0; b=0;
402  f->total(t,r,g,b);
403  if (t<=1)
404  {
405    t=0; r=0; g=0; b=0;
406    f->total(t,r,g,b);
407  }
408  CONDITION(t>1,"Should be more colors\n");
409  printf("%d Pruned at level %d, r=%d, g=%d, b=%d, total nodes off = %d\n",nc,
410    lev,r/t,g/t,b/t,t);
411  f->set(r/t,g/t,b/t);
412  nc-=t;
413  nc++;
414  re_delete(f,lev);
415  f->be_childish();
416}
417
418void quant_palette::add_color(unsigned char r, unsigned char g, unsigned char b)
419{
420  quant_node **p,*fat;
421  int lev,cn,stop;
422  p=&root;
423  lev=0;
424  stop=0;
425  fat=NULL;
426  if (nc>=mx-1)
427    prune();
428  while (!stop)
429  {
430    lev++;
431    if (!(*p))
432    {
433      if (lev>2 && !fat)
434        printf("h");
435      (*p)=new quant_node(lev,fat);
436      level[lev-1].add_end((linked_node *)(*p));
437    }
438
439    if (!(*p)->is_leaf())
440    {
441      cn=((r&(256>>lev))!=0)<<2;
442      cn+=((g&(256>>lev))!=0)<<1;
443      cn+=((b&(256>>lev))!=0);
444      fat=(*p);
445      p=&((*p)->children[cn]);
446    } else stop=1;
447
448  }
449  (*p)->set(r,g,b);
450  if (!(*p)->tot)
451    nc++;
452  (*p)->tot++;
453}
454
455palette *quant_palette::create_pal()
456{
457  palette *p;
458  int i,x;
459  quant_node *pn;
460  p=new palette(mx);
461  for (x=0,i=7;i>=0;i++)
462    for (pn=(quant_node *)level[i].first();
463         pn!=(quant_node *)level[i].first();pn=(quant_node *)pn->next())
464      if (pn->is_leaf())
465        p->set(x++,pn->red,pn->green,pn->blue);
466  return p;
467}
468
469quant_palette::~quant_palette()
470{
471  if (root)
472  {
473    re_delete(root,1);
474    delete root;
475  }
476}
477
478unsigned char palette::brightest(int all)
479{ unsigned char r,g,b,bri;
480  unsigned i;
481  long brv;
482  brv=0; bri=0;
483
484  for (i=0;i<ncolors;i++)
485  { if (all || used(i))
486    {
487      get(i,r,g,b);
488      if ((long)r*(long)g*(long)b>brv)
489      { brv=(long)r*(long)g*(long)b;
490        bri=i;
491      }
492    }
493  }
494
495  return bri;
496}
497
498unsigned char palette::darkest(int all, int noblack)
499{ unsigned char r,g,b,bri;
500  unsigned i;
501  long brv,x;
502  brv=(long)258*(long)258*(long)258; bri=0;
503
504  for (i=0;i<ncolors;i++)
505  { if (all || used(i))
506    {
507      get(i,r,g,b);
508      x=(long)r*(long)g*(long)b;
509      if (x<brv && (x || !noblack))
510      { brv=(long)r*(long)g*(long)b;
511        bri=i;
512      }
513    }
514  }
515  return bri;
516}
517
518
519
520palette *last_loaded()
521{ return lastl; }
522
523void palette::fade_to(int total_fades, int fade_on, int dest_r, int dest_g, int dest_b)
524{
525  unsigned char *sl=(unsigned char *)addr();
526  int i; 
527  for (i=0;i<ncolors;i++)
528  {
529    *(sl++)=(( dest_r-(int)*sl)*fade_on/total_fades+*sl);
530    *(sl++)=(( dest_g-(int)*sl)*fade_on/total_fades+*sl);
531    *(sl++)=(( dest_b-(int)*sl)*fade_on/total_fades+*sl);   
532  } 
533}
Note: See TracBrowser for help on using the repository browser.