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

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