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

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

imlib: refactor dirty_rect clipping coordiantes so that the upper
bound is no longer inclusive. It will make things easier in the future.

File size: 5.2 KB
RevLine 
[56]1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
[494]4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
[56]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
[512]13#include "common.h"
14
[481]15#include "image.h"
16#include "macs.h"
17#include "filter.h"
[2]18
19extern unsigned char current_background;
20
21filter::filter(palette *from, palette *to)   // creates a conversion filter from one palette to another
22{
23  nc=from->pal_size() > to->pal_size() ? from->pal_size() : to->pal_size();
[129]24  unsigned char *p=fdat=(unsigned char *)malloc(nc);
[2]25  unsigned char *r,*g,*b;
26  r=g=b=(unsigned char *)from->addr();
27  g++;
28  b+=2;
29
30  int dk=to->darkest(1);
[494]31  for (int i=0; i<nc; i++,p++,r+=3,g+=3,b+=3)
[2]32  {
33    *p=to->find_closest(*r,*g,*b);
34
35    // make sure non-blacks don't get remapped to the transparency
36    if ((*r!=0 || *g!=0 || *b!=0) && (to->red(*p)==0 && to->green(*p)==0 && to->blue(*p)==0))
37      *p=dk;
38  }
39
40}
41
42void filter::clear()
43{
44  int i;
[494]45  for (i=0; i<nc; i++)
[2]46    fdat[i]=i;
47}
48
49void filter::max_threshold(int minv, char blank)
50{
51  int i;
52  CONDITION(minv>=0 && minv<nc,"Bad minv");
[494]53  for (i=0; i<minv; i++)
[2]54    fdat[i]=blank;
55}
56
57void filter::min_threshold(int maxv, char blank)
58{
59  int i;
60  CONDITION(maxv>=0 && maxv<nc,"bad maxv value in filter::max_thresh");
[494]61  for (i=nc-1; i>=maxv; i--)
[2]62    fdat[i]=(unsigned) blank;
63}
64
65
66void filter::set(int color_num, char change_to)
67{
68  CONDITION(color_num>=0 && color_num<nc,"Bad colors_num");
69  fdat[color_num]=(unsigned) change_to;
70}
71
72
73filter::filter(int colors)
74{
75  CONDITION(colors>=0 && colors<=256,"bad colors value");
76  nc=colors;
[129]77  fdat=(unsigned char *)malloc(nc);
[2]78  clear();
79}
80
81void filter::apply(image *im)
82{
83  int x,y;
84  unsigned char *c;
85  CONDITION(im,"null image passed in filter::apply\n");
[515]86  im->Lock();
[512]87  for (y=im->Size().y-1; y>=0; y--)
[2]88  {
89    c=im->scan_line(y);
[512]90    for (x=im->Size().x-1; x>=0; x--)
[2]91    {
92      CONDITION((unsigned) c[x]<nc,"not enough filter colors");
93      c[x]=fdat[(unsigned) c[x]];
94    }
95  }
[515]96  im->Unlock();
[2]97}
98
99
100palette *compare_pal;
101
102int color_compare(void *c1, void *c2)
103{
[115]104  long v1,v2;
[2]105  unsigned char r1,g1,b1,r2,g2,b2;
106  compare_pal->get(  *((unsigned char *)c1),r1,g1,b1);
107  compare_pal->get(  *((unsigned char *)c2),r2,g2,b2);
108  v1=(int)r1*(int)r1+(int)g1*(int)g1+(int)b1*(int)b1;
109  v2=(int)r2*(int)r2+(int)g2*(int)g2+(int)b2*(int)b2;
110  if (v1<v2) return -1;
111  else if (v1>v2) return 1;
[115]112  else return 0;
[2]113}
114
115color_filter::color_filter(palette *pal, int color_bits, void (*stat_fun)(int))
[115]116{
[2]117  color_bits=5;      // hard code 5 for now
118  int r,g,b,rv,gv,bv,
119      c=0,i,max=pal->pal_size(),
120      lshift=8-color_bits;
121  unsigned char *pp;
[115]122
[2]123  long dist_sqr,best;
124  int colors=1<<color_bits;
[129]125  color_table=(unsigned char *)malloc(colors*colors*colors);
[494]126  for (r=0; r<colors; r++)
[2]127  {
128    if (stat_fun) stat_fun(r);
[115]129    rv=r<<lshift;
[494]130    for (g=0; g<colors; g++)
[2]131    {
[115]132      gv=g<<lshift;
[494]133      for (b=0; b<colors; b++)
[2]134      {
[124]135    bv=b<<lshift;
[2]136        best=0x7fffffff;
[494]137        for (i=0,pp=(unsigned char *)pal->addr(); i<max; i++)
[115]138        {
[2]139          register long rd=*(pp++)-rv,
140                        gd=*(pp++)-gv,
141                        bd=*(pp++)-bv;
[494]142
[2]143          dist_sqr=(long)rd*rd+(long)bd*bd+(long)gd*gd;
144          if (dist_sqr<best)
145          { best=dist_sqr;
146            c=i;
147          }
148        }
149        color_table[r*colors*colors+g*colors+b]=c;
150      }
151    }
[115]152  }
[2]153}
154
155color_filter::color_filter(spec_entry *e, bFILE *fp)
156{
157  fp->seek(e->offset,0);
[17]158  fp->read_uint16();
[2]159  int colors=32;
[129]160  color_table=(unsigned char *)malloc(colors*colors*colors);
[2]161  fp->read(color_table,colors*colors*colors);
162}
163
164int color_filter::size()
165{
166  int colors=32;
167  return 2+colors*colors*colors;
168}
169
170int color_filter::write(bFILE *fp)
171{
172  int colors=32;
[17]173  fp->write_uint16(colors);
[2]174  return fp->write(color_table,colors*colors*colors)==colors*colors*colors;
175}
176
177
[115]178void filter::put_image(image *screen, image *im, short x, short y,
179                       char transparent)
[2]180{
[518]181    int cx1, cy1, cx2, cy2, x1 = 0, y1 = 0,
182          x2 = im->Size().x, y2 = im->Size().y;
183    screen->GetClip(cx1, cy1, cx2, cy2);
[2]184
[115]185    // see if the image gets clipped off the screen
[518]186    if(x >= cx2 || y >= cy2 || x + (x2 - x1) <= cx1 || y + (y2 - y1) <= cy1)
[115]187        return;
[2]188
[115]189    if(x < cx1)
190    {
191        x1 += (cx1 - x);
192        x = cx1;
193    }
194    if(y < cy1)
195    {
196        y1 += (cy1 - y);
197         y = cy1;
198    }
[2]199
[518]200    if(x + x2 - x1 >= cx2)
[115]201        x2 = cx2 - x + x1;
[2]202
[518]203    if(y + y2 - y1 >= cy2)
[115]204        y2 = cy2 - y + y1;
[2]205
[518]206    if(x1 >= x2 || y1 >= y2)
[115]207        return;
[2]208
[518]209    int xl = x2 - x1;
210    int yl = y2 - y1;
[2]211
[518]212    screen->AddDirty(x, y, x + xl, y + yl);
[2]213
[515]214    screen->Lock();
215    im->Lock();
[2]216
[115]217    uint8_t *pg1 = screen->scan_line(y), *source, *dest;
218    uint8_t *pg2 = im->scan_line(y1);
219    int i;
220    for(int j = 0; j < yl; j++)
221    {
222        for(i = 0, source = &pg2[x1], dest = &pg1[x];
223            i < xl;
[494]224            i++, source++, dest++)
[115]225        {
226            if(!transparent || *source != current_background)
227                *dest=fdat[*source];
228        }
229        pg1 = screen->next_line(y + j, pg1);
230        pg2 = im->next_line(y1 + j, pg2);
231    }
[2]232
[515]233    im->Unlock();
234    screen->Unlock();
[115]235}
[2]236
Note: See TracBrowser for help on using the repository browser.