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

Last change on this file since 162 was 162, checked in by Sam Hocevar, 13 years ago

Fix numerous compiler warnings.

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.hpp"
15#include "image.hpp"
16#include "macs.hpp"
17#include "video.hpp"
18#include "filter.hpp"
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{ char entry[4];
103  entry[3]=0;
104  entry[2]=pal[x].red;
105  entry[1]=pal[x].green;
106  entry[0]=pal[x].blue;
107  return *((uint32_t *)entry);
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.