source: abuse/trunk/src/imlib/timage.cpp @ 530

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

imlib: remove trans_image::put_image_offseted, it's simply a version
of PutImage? that skips the bounds checks. Yaddah yaddah modern hardware
blah.

File size: 11.4 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 "common.h"
14
15#include "timage.h"
16
17image *trans_image::make_image()
18{
19  image *im = new image(m_size);
20
21  im->Lock();
22  uint8_t *d=im->scan_line(0),*dp=m_data,*dline;
23  int y,x;
24  for (y=0; y<m_size.y; y++)
25  {
26    x=0;
27    dline=d;
28    memset(dline,0,m_size.x);
29    while(x<m_size.x)
30    {
31      int skip=*(dp++);
32      dline+=skip;
33      x+=skip;
34      if (x<m_size.x)
35      {
36    int run=*(dp++);
37    memcpy(dline,dp,run);
38    x+=run;
39    dline+=run;
40    dp+=run;
41      }
42    }
43    d=im->next_line(y,d);
44  }
45  im->Unlock();
46  return im;
47}
48
49trans_image::trans_image(image *im, char const *name)
50{
51  int size=0,x,y;
52  uint8_t *sl,*datap,*marker;
53  m_size = im->Size();
54
55  im->Lock();
56
57  // first we must find out how much data to allocate
58  for (y=0; y<im->Size().y; y++)
59  {
60    sl=im->scan_line(y);
61    x=0;
62    while (x<m_size.x)
63    {
64      size++;
65      while (x<m_size.x && *sl==0) { sl++; x++; }
66
67      if (x<m_size.x)
68      {
69        size++;  // byte for the size of the run
70        while (x<m_size.x && (*sl)!=0)
71        {
72      size++;
73      x++;
74      sl++;
75    }
76      }
77    }
78  }
79
80  m_data=(uint8_t *)malloc(size);
81  int ww=im->Size().x,hh=im->Size().y;
82  datap=m_data;
83  if (!datap)
84  { printf("size = %d %d (%d)\n",im->Size().x,im->Size().y,size);  }
85  CONDITION(datap,"malloc error for trans_image::m_data");
86
87  for (y=0; y<hh; y++)  // now actually make the runs
88  {
89    sl=im->scan_line(y);
90    x=0;
91    while (x<ww)
92    {
93      *datap=0;  // start the skip at 0
94      while (x<im->Size().x && (*sl)==0)
95      { sl++; x++; (*datap)++; }
96      datap++;
97
98      if (x<ww)
99      {
100        marker=datap;   // let marker be the run size
101    *marker=0;
102    datap++;    // skip over this spot
103        while (x<im->Size().x && (*sl)!=0)
104        {
105          (*marker)++;
106      (*datap)=*sl;
107          datap++;
108      x++;
109      sl++;
110    }
111      }
112    }
113  }
114  im->Unlock();
115}
116
117trans_image::~trans_image()
118{
119    free(m_data);
120}
121
122void trans_image::put_scan_line(image *screen, int x, int y, int line)   // always transparent
123{
124  int x1, y1, x2, y2;
125  screen->GetClip(x1, y1, x2, y2);
126  if (y + line < y1 || y + line >= y2 || x >= x2 || x + m_size.x - 1 < x1)
127    return; // clipped off completely?
128
129  uint8_t *datap=m_data;
130  int ix;
131  while (line)            // skip scan line data until we get to the line of interest
132  {
133    for (ix=0; ix<m_size.x; )
134    {
135      ix+=*datap;        // skip blank space
136      datap++;
137      if (ix<m_size.x)
138      {
139    int run_length=*datap;     // skip run
140    ix+=run_length;
141    datap+=run_length+1;
142      }
143    }
144    line--;
145    y++;
146  }
147
148
149  // now slam this list of runs to the screen
150  screen->Lock();
151  uint8_t *screen_line=screen->scan_line(y)+x;
152
153  for (ix=0; ix<m_size.x; )
154  {
155    int skip=*datap;              // how much space to skip?
156    datap++;
157    screen_line+=skip;
158    ix+=skip;
159
160    if (ix<m_size.x)
161    {
162      int run_length=*datap;
163      datap++;
164
165      if (x+ix+run_length-1<x1)      // is this run clipped out totally?
166      {
167    datap+=run_length;
168    ix+=run_length;
169    screen_line+=run_length;
170      }
171      else
172      {
173    if (x+ix<x1)                 // is the run clipped partially?
174    {
175      int clip=(x1-(x+ix));
176      datap+=clip;
177      run_length-=clip;
178      screen_line+=clip;
179      ix+=clip;
180    }
181
182    if (x + ix >= x2)                      // clipped totally on the right?
183        {
184          screen->Unlock();
185          return ;                        // we are done, return!
186        }
187    else if (x + ix + run_length > x2)    // partially clipped?
188    {
189      memcpy(screen_line, datap, x + ix + run_length - x2); // slam what we can
190      screen->Unlock();
191      return ;    // and return 'cause we are done with the line
192        } else
193        {
194      memcpy(screen_line,datap,run_length);
195      screen_line+=run_length;
196        datap+=run_length;
197        ix+=run_length;
198        }
199      }
200    }
201  }
202  screen->Unlock();
203}
204
205
206uint8_t *trans_image::ClipToLine(image *screen, int x1, int y1, int x2, int y2,
207                                 int x, int &y, int &ysteps)
208{
209    // check to see if it is totally clipped out first
210    if (y + m_size.y <= y1 || y >= y2 || x >= x2 || x + m_size.x <= x1)
211        return NULL;
212
213    uint8_t *parser = m_data;
214
215    int skiplines = Max(y1 - y, 0); // number of lines to skip
216    ysteps = Min(y2 - y, m_size.y - skiplines); // number of lines to draw
217    y += skiplines; // first line to draw
218
219    while (skiplines--)
220    {
221        for (int ix = 0; ix < m_size.x; )
222        {
223            ix += *parser++; // skip over empty space
224
225            if (ix >= m_size.x)
226                break;
227
228            ix += *parser;
229            parser += *parser + 1; // skip over data
230        }
231    }
232
233    screen->AddDirty(Max(x, x1), y, Min(x + m_size.x, x2), y + m_size.y);
234    return parser;
235}
236
237void trans_image::PutFilled(image *screen, int x, int y, uint8_t color)
238{
239    PutImageGeneric<FILLED>(screen, x, y, color, NULL, 0, 0, NULL, NULL,
240                            0, 1, NULL, NULL, NULL);
241}
242
243template<int N>
244void trans_image::PutImageGeneric(image *screen, int x, int y, uint8_t color,
245                                  image *blend, int bx, int by,
246                                  uint8_t *remap, uint8_t *remap2,
247                                  int amount, int total_frames,
248                                  uint8_t *tint, color_filter *f, palette *pal)
249{
250    int x1, y1, x2, y2;
251    int ysteps, mul = 0;
252
253    screen->GetClip(x1, y1, x2, y2);
254    uint8_t *datap = ClipToLine(screen, x1, y1, x2, y2, x, y, ysteps),
255            *screen_line, *blend_line = NULL, *paddr = NULL;
256    if (!datap)
257        return; // if ClipToLine says nothing to draw, return
258
259    CONDITION(N == BLEND && y >= by && y + ysteps < by + blend->Size().y + 1,
260              "Blend doesn't fit on trans_image");
261
262    if (N == FADE || N == FADE_TINT || N == BLEND)
263        paddr = (uint8_t *)pal->addr();
264
265    if (N == FADE || N == FADE_TINT)
266        mul = (amount << 16) / total_frames;
267    else if (N == BLEND)
268        mul = ((16 - amount) << 16 / 16);
269
270    if (N == PREDATOR)
271        ysteps = Min(ysteps, y2 - 1 - y - 2);
272
273    screen->Lock();
274
275    screen_line = screen->scan_line(y)+x;
276    int sw = screen->Size().x;
277    x1 -= x; x2 -= x;
278
279    for (; ysteps > 0; ysteps--, y++)
280    {
281        if (N == BLEND)
282            blend_line = blend->scan_line(y - by);
283
284        for (int ix = 0; ix < m_size.x; )
285        {
286            // Handle a run of transparent pixels
287            int todo = *datap++;
288
289            // FIXME: implement FILLED mode
290            ix += todo;
291            screen_line += todo;
292
293            if (ix >= m_size.x)
294                break;
295
296            // Handle a run of solid pixels
297            todo = *datap++;
298
299            // Chop left side if necessary, but no more than todo
300            int tochop = Min(todo, Max(x1 - ix, 0));
301
302            ix += tochop;
303            screen_line += tochop;
304            datap += tochop;
305            todo -= tochop;
306
307            // Chop right side if necessary and process the remaining pixels
308            int count = Min(todo, Max(x2 - ix, 0));
309
310            if (N == NORMAL)
311            {
312                memcpy(screen_line, datap, count);
313            }
314            else if (N == COLOR)
315            {
316                memset(screen_line, color, count);
317            }
318            else if (N == PREDATOR)
319            {
320                memcpy(screen_line, screen_line + 2 * m_size.x, count);
321            }
322            else if (N == REMAP)
323            {
324                uint8_t *sl = screen_line, *sl2 = datap;
325                while (count--)
326                    *sl++ = remap[*sl2++];
327            }
328            else if (N == DOUBLE_REMAP)
329            {
330                uint8_t *sl = screen_line, *sl2 = datap;
331                while (count--)
332                    *sl++ = remap2[remap[*sl2++]];
333            }
334            else if (N == FADE || N == FADE_TINT || N == BLEND)
335            {
336                uint8_t *sl = screen_line;
337                uint8_t *sl2 = (N == BLEND) ? blend_line + x + ix - bx : sl;
338                uint8_t *sl3 = datap;
339
340                while (count--)
341                {
342                    uint8_t *p1 = paddr + 3 * *sl2++;
343                    uint8_t *p2 = paddr + 3 * (N == FADE_TINT ? tint[*sl3++] : *sl3++);
344
345                    uint8_t r = ((((int)p1[0] - p2[0]) * mul) >> 16) + p2[0];
346                    uint8_t g = ((((int)p1[1] - p2[1]) * mul) >> 16) + p2[1];
347                    uint8_t b = ((((int)p1[2] - p2[2]) * mul) >> 16) + p2[2];
348
349                    *sl++ = f->lookup_color(r >> 3, g >> 3, b >> 3);
350                }
351            }
352
353            datap += todo;
354            ix += todo;
355            screen_line += todo;
356        }
357        screen_line += sw - m_size.x;
358    }
359    screen->Unlock();
360}
361
362void trans_image::PutImage(image *screen, int x, int y)
363{
364    PutImageGeneric<NORMAL>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
365                            0, 1, NULL, NULL, NULL);
366}
367
368void trans_image::PutRemap(image *screen, int x, int y, uint8_t *remap)
369{
370    PutImageGeneric<REMAP>(screen, x, y, 0, NULL, 0, 0, remap, NULL,
371                           0, 1, NULL, NULL, NULL);
372}
373
374void trans_image::PutDoubleRemap(image *screen, int x, int y,
375                                 uint8_t *remap, uint8_t *remap2)
376{
377    PutImageGeneric<DOUBLE_REMAP>(screen, x, y, 0, NULL, 0, 0, remap, remap2,
378                                  0, 1, NULL, NULL, NULL);
379}
380
381// Used when eg. the player teleports, or in rocket trails
382void trans_image::PutFade(image *screen, int x, int y,
383                          int amount, int total_frames,
384                          color_filter *f, palette *pal)
385{
386    PutImageGeneric<FADE>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
387                          amount, total_frames, NULL, f, pal);
388}
389
390void trans_image::PutFadeTint(image *screen, int x, int y,
391                              int amount, int total_frames,
392                              uint8_t *tint, color_filter *f, palette *pal)
393{
394    PutImageGeneric<FADE_TINT>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
395                               amount, total_frames, tint, f, pal);
396}
397
398void trans_image::PutColor(image *screen, int x, int y, uint8_t color)
399{
400    PutImageGeneric<COLOR>(screen, x, y, color, NULL, 0, 0, NULL, NULL,
401                           0, 1, NULL, NULL, NULL);
402}
403
404// This method is unused but is believed to work.
405// Assumes that the blend image completely covers the transparent image.
406void trans_image::PutBlend(image *screen, int x, int y,
407                           image *blend, int bx, int by,
408                           int amount, color_filter *f, palette *pal)
409{
410    PutImageGeneric<BLEND>(screen, x, y, 0, blend, bx, by, NULL, NULL,
411                           amount, 1, NULL, f, pal);
412}
413
414void trans_image::PutPredator(image *screen, int x, int y)
415{
416    PutImageGeneric<PREDATOR>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
417                              0, 1, NULL, NULL, NULL);
418}
419
420size_t trans_image::MemUsage()
421{
422    uint8_t *d = m_data;
423    size_t t = 0;
424
425    for (int y = 0; y < m_size.y; y++)
426    {
427        for (int x = 0; x < m_size.x; x++)
428        {
429            x += *d; d++; t++;
430
431            if (x >= m_size.x)
432                break;
433
434            int s = *d; d++; t += s + 1; d += s; x += s;
435        }
436    }
437    return t + 4 + 4;
438}
439
Note: See TracBrowser for help on using the repository browser.