source: abuse/branches/lol/src/imlib/transimage.cpp @ 732

Last change on this file since 732 was 732, checked in by Sam Hocevar, 8 years ago

build: SDL2 compilation fixes.

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