source: abuse/trunk/src/imlib/palette.cpp @ 481

Last change on this file since 481 was 481, checked in by Sam Hocevar, 11 years ago

Fuck the history, I'm renaming all .hpp files to .h for my own sanity.

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