source: abuse/tags/pd/macabuse/imlib/palette.c @ 604

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