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

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

imlib: rename trans_image to TImage. The code is now clean enough.

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