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

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