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

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

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

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