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

Last change on this file since 518 was 512, checked in by Sam Hocevar, 12 years ago

imlib: use vec2i for image::size and unroll all necessary changes
everywhere else in the code.

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