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

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

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

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