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

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

imlib: reimplement trans_image::put_scan_line so that it uses the
common template for all blitting functions.

File size: 9.9 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
17trans_image::trans_image(image *im, char const *name)
18{
19    m_size = im->Size();
20
21    im->Lock();
22
23    // First find out how much data to allocate
24    size_t bytes = 0;
25    for (int y = 0; y < m_size.y; y++)
26    {
27        uint8_t *parser = im->scan_line(y);
28        for (int x = 0; x < m_size.x; )
29        {
30            bytes++;
31            while (x < m_size.x && *parser == 0)
32            {
33                parser++; x++;
34            }
35
36            if (x >= m_size.x)
37                break;
38
39            bytes++;  // byte for the size of the run
40            while (x < m_size.x && *parser != 0)
41            {
42                bytes++;
43                x++;
44                parser++;
45            }
46        }
47    }
48
49    uint8_t *parser = m_data = (uint8_t *)malloc(bytes);
50    if (!parser)
51    {
52        printf("size = %d %d (%d bytes)\n",im->Size().x,im->Size().y,bytes);
53        CONDITION(parser, "malloc error for trans_image::m_data");
54    }
55
56    // Now fill the RLE transparency image
57    for (int y = 0; y < m_size.y; y++)
58    {
59        uint8_t *sl = im->scan_line(y);
60
61        for (int x = 0; x < m_size.x; )
62        {
63            uint8_t len = 0;
64            while (x + len < m_size.x && sl[len] == 0)
65                len++;
66
67            *parser++ = len;
68            x += len;
69            sl += len;
70
71            if (x >= m_size.x)
72                break;
73
74            len = 0;
75            while (x + len < m_size.x && sl[len] != 0)
76            {
77                parser[len + 1] = sl[len];
78                len++;
79            }
80
81            *parser++ = len;
82            parser += len;
83            x += len;
84            sl += len;
85        }
86    }
87    im->Unlock();
88}
89
90trans_image::~trans_image()
91{
92    free(m_data);
93}
94
95image *trans_image::ToImage()
96{
97    image *im = new image(m_size);
98
99    // FIXME: this is required until FILLED mode is fixed
100    im->Lock();
101    memset(im->scan_line(0), 0, m_size.x * m_size.y);
102    im->Unlock();
103
104    PutImage(im, 0, 0);
105    return im;
106}
107
108uint8_t *trans_image::ClipToLine(image *screen, int x1, int y1, int x2, int y2,
109                                 int x, int &y, int &ysteps)
110{
111    // check to see if it is totally clipped out first
112    if (y + m_size.y <= y1 || y >= y2 || x >= x2 || x + m_size.x <= x1)
113        return NULL;
114
115    uint8_t *parser = m_data;
116
117    int skiplines = Max(y1 - y, 0); // number of lines to skip
118    ysteps = Min(y2 - y, m_size.y - skiplines); // number of lines to draw
119    y += skiplines; // first line to draw
120
121    while (skiplines--)
122    {
123        for (int ix = 0; ix < m_size.x; )
124        {
125            ix += *parser++; // skip over empty space
126
127            if (ix >= m_size.x)
128                break;
129
130            ix += *parser;
131            parser += *parser + 1; // skip over data
132        }
133    }
134
135    screen->AddDirty(Max(x, x1), y, Min(x + m_size.x, x2), y + m_size.y);
136    return parser;
137}
138
139template<int N>
140void trans_image::PutImageGeneric(image *screen, int x, int y, uint8_t color,
141                                  image *blend, int bx, int by,
142                                  uint8_t *remap, uint8_t *remap2,
143                                  int amount, int total_frames,
144                                  uint8_t *tint, color_filter *f, palette *pal)
145{
146    int x1, y1, x2, y2;
147    int ysteps, mul = 0;
148
149    screen->GetClip(x1, y1, x2, y2);
150
151    if (N == SCANLINE)
152    {
153        y1 = Max(y1, y + amount);
154        y2 = Min(y2, y + amount + 1);
155        if (y1 >= y2)
156            return;
157    }
158
159    uint8_t *datap = ClipToLine(screen, x1, y1, x2, y2, x, y, ysteps),
160            *screen_line, *blend_line = NULL, *paddr = NULL;
161    if (!datap)
162        return; // if ClipToLine says nothing to draw, return
163
164    CONDITION(N == BLEND && y >= by && y + ysteps < by + blend->Size().y + 1,
165              "Blend doesn't fit on trans_image");
166
167    if (N == FADE || N == FADE_TINT || N == BLEND)
168        paddr = (uint8_t *)pal->addr();
169
170    if (N == FADE || N == FADE_TINT)
171        mul = (amount << 16) / total_frames;
172    else if (N == BLEND)
173        mul = ((16 - amount) << 16 / 16);
174
175    if (N == PREDATOR)
176        ysteps = Min(ysteps, y2 - 1 - y - 2);
177
178    screen->Lock();
179
180    screen_line = screen->scan_line(y) + x;
181    int sw = screen->Size().x;
182    x1 -= x; x2 -= x;
183
184    for (; ysteps > 0; ysteps--, y++)
185    {
186        if (N == BLEND)
187            blend_line = blend->scan_line(y - by);
188
189        for (int ix = 0; ix < m_size.x; )
190        {
191            // Handle a run of transparent pixels
192            int todo = *datap++;
193
194            // FIXME: implement FILLED mode
195            ix += todo;
196            screen_line += todo;
197
198            if (ix >= m_size.x)
199                break;
200
201            // Handle a run of solid pixels
202            todo = *datap++;
203
204            // Chop left side if necessary, but no more than todo
205            int tochop = Min(todo, Max(x1 - ix, 0));
206
207            ix += tochop;
208            screen_line += tochop;
209            datap += tochop;
210            todo -= tochop;
211
212            // Chop right side if necessary and process the remaining pixels
213            int count = Min(todo, Max(x2 - ix, 0));
214
215            if (N == NORMAL || N == SCANLINE)
216            {
217                memcpy(screen_line, datap, count);
218            }
219            else if (N == COLOR)
220            {
221                memset(screen_line, color, count);
222            }
223            else if (N == PREDATOR)
224            {
225                memcpy(screen_line, screen_line + 2 * m_size.x, count);
226            }
227            else if (N == REMAP)
228            {
229                uint8_t *sl = screen_line, *sl2 = datap;
230                while (count--)
231                    *sl++ = remap[*sl2++];
232            }
233            else if (N == REMAP2)
234            {
235                uint8_t *sl = screen_line, *sl2 = datap;
236                while (count--)
237                    *sl++ = remap2[remap[*sl2++]];
238            }
239            else if (N == FADE || N == FADE_TINT || N == BLEND)
240            {
241                uint8_t *sl = screen_line;
242                uint8_t *sl2 = (N == BLEND) ? blend_line + x + ix - bx : sl;
243                uint8_t *sl3 = datap;
244
245                while (count--)
246                {
247                    uint8_t *p1 = paddr + 3 * *sl2++;
248                    uint8_t *p2 = paddr + 3 * (N == FADE_TINT ? tint[*sl3++] : *sl3++);
249
250                    uint8_t r = ((((int)p1[0] - p2[0]) * mul) >> 16) + p2[0];
251                    uint8_t g = ((((int)p1[1] - p2[1]) * mul) >> 16) + p2[1];
252                    uint8_t b = ((((int)p1[2] - p2[2]) * mul) >> 16) + p2[2];
253
254                    *sl++ = f->lookup_color(r >> 3, g >> 3, b >> 3);
255                }
256            }
257
258            datap += todo;
259            ix += todo;
260            screen_line += todo;
261        }
262        screen_line += sw - m_size.x;
263    }
264    screen->Unlock();
265}
266
267void trans_image::PutImage(image *screen, int x, int y)
268{
269    PutImageGeneric<NORMAL>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
270                            0, 1, NULL, NULL, NULL);
271}
272
273void trans_image::PutRemap(image *screen, int x, int y, uint8_t *remap)
274{
275    PutImageGeneric<REMAP>(screen, x, y, 0, NULL, 0, 0, remap, NULL,
276                           0, 1, NULL, NULL, NULL);
277}
278
279void trans_image::PutDoubleRemap(image *screen, int x, int y,
280                                 uint8_t *remap, uint8_t *remap2)
281{
282    PutImageGeneric<REMAP2>(screen, x, y, 0, NULL, 0, 0, remap, remap2,
283                            0, 1, NULL, NULL, NULL);
284}
285
286// Used when eg. the player teleports, or in rocket trails
287void trans_image::PutFade(image *screen, int x, int y,
288                          int amount, int total_frames,
289                          color_filter *f, palette *pal)
290{
291    PutImageGeneric<FADE>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
292                          amount, total_frames, NULL, f, pal);
293}
294
295void trans_image::PutFadeTint(image *screen, int x, int y,
296                              int amount, int total_frames,
297                              uint8_t *tint, color_filter *f, palette *pal)
298{
299    PutImageGeneric<FADE_TINT>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
300                               amount, total_frames, tint, f, pal);
301}
302
303void trans_image::PutColor(image *screen, int x, int y, uint8_t color)
304{
305    PutImageGeneric<COLOR>(screen, x, y, color, NULL, 0, 0, NULL, NULL,
306                           0, 1, NULL, NULL, NULL);
307}
308
309// This method is unused but is believed to work.
310// Assumes that the blend image completely covers the transparent image.
311void trans_image::PutBlend(image *screen, int x, int y,
312                           image *blend, int bx, int by,
313                           int amount, color_filter *f, palette *pal)
314{
315    PutImageGeneric<BLEND>(screen, x, y, 0, blend, bx, by, NULL, NULL,
316                           amount, 1, NULL, f, pal);
317}
318
319void trans_image::PutFilled(image *screen, int x, int y, uint8_t color)
320{
321    PutImageGeneric<FILLED>(screen, x, y, color, NULL, 0, 0, NULL, NULL,
322                            0, 1, NULL, NULL, NULL);
323}
324
325void trans_image::PutPredator(image *screen, int x, int y)
326{
327    PutImageGeneric<PREDATOR>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
328                              0, 1, NULL, NULL, NULL);
329}
330
331void trans_image::PutScanLine(image *screen, int x, int y, int line)
332{
333    PutImageGeneric<SCANLINE>(screen, x, y, 0, NULL, 0, 0, NULL, NULL,
334                              line, 1, NULL, NULL, NULL);
335}
336
337size_t trans_image::MemUsage()
338{
339    uint8_t *d = m_data;
340    size_t ret = 0;
341
342    for (int y = 0; y < m_size.y; y++)
343    {
344        for (int x = 0; x < m_size.x; x++)
345        {
346            x += *d++; ret++;
347
348            if (x >= m_size.x)
349                break;
350
351            size_t run = *d++; ret += run + 1; d += run; x += run;
352        }
353    }
354    return ret + sizeof(void *) + sizeof(vec2i);
355}
356
Note: See TracBrowser for help on using the repository browser.