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
RevLine 
[56]1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
[724]4 *  Copyright (c) 2005-2013 Sam Hocevar <sam@hocevar.net>
[56]5 *
6 *  This software was released into the Public Domain. As with most public
[555]7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
[56]9 */
10
[732]11#if HAVE_CONFIG_H
[555]12#   include "config.h"
13#endif
[56]14
[533]15#include <cstdio>
16#include <cstring>
17
[512]18#include "common.h"
19
[724]20#include "imlib/transimage.h"
[2]21
[709]22TransImage::TransImage(AImage *im, char const *name)
[2]23{
[531]24    m_size = im->Size();
[115]25
[531]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    {
[541]55        printf("size = %d %d (%ld bytes)\n", m_size.x, m_size.y, (long)bytes);
[687]56        ASSERT(parser, "malloc error for TransImage::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    }
[2]90}
91
[541]92TransImage::~TransImage()
[527]93{
94    free(m_data);
95}
96
[709]97AImage *TransImage::ToImage()
[531]98{
[709]99    AImage *im = new AImage(m_size);
[531]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
[719]104    PutImage(im, ivec2::zero);
[531]105    return im;
106}
107
[709]108uint8_t *TransImage::ClipToLine(AImage *screen, ivec2 pos1, ivec2 pos2,
[682]109                                ivec2 &pos, int &ysteps)
[2]110{
[520]111    // check to see if it is totally clipped out first
[533]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)
[520]114        return NULL;
[2]115
[527]116    uint8_t *parser = m_data;
[2]117
[533]118    // Number of lines to skip, number of lines to draw, first line to draw
[687]119    int skiplines = lol::max(pos1.y - pos.y, 0);
120    ysteps = lol::min(pos2.y - pos.y, m_size.y - skiplines);
[533]121    pos.y += skiplines;
[2]122
[520]123    while (skiplines--)
124    {
[527]125        for (int ix = 0; ix < m_size.x; )
[520]126        {
127            ix += *parser++; // skip over empty space
[115]128
[527]129            if (ix >= m_size.x)
[520]130                break;
[2]131
[520]132            ix += *parser;
133            parser += *parser + 1; // skip over data
[115]134        }
[2]135    }
[115]136
[687]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));
[520]139    return parser;
[115]140}
[2]141
[528]142template<int N>
[709]143void TransImage::PutImageGeneric(AImage *screen, ivec2 pos, uint8_t color,
144                                 AImage *blend, ivec2 bpos, uint8_t *map,
[541]145                                 uint8_t *map2, int amount, int nframes,
[694]146                                 uint8_t *tint, ColorFilter *f, Palette *pal)
[2]147{
[682]148    ivec2 pos1, pos2;
[528]149    int ysteps, mul = 0;
[2]150
[665]151    screen->GetClip(pos1, pos2);
[532]152
153    if (N == SCANLINE)
154    {
[687]155        pos1.y = lol::max(pos1.y, pos.y + amount);
156        pos2.y = lol::min(pos2.y, pos.y + amount + 1);
[533]157        if (pos1.y >= pos2.y)
[532]158            return;
159    }
160
[533]161    uint8_t *datap = ClipToLine(screen, pos1, pos2, pos, ysteps),
[694]162            *screen_line, *blend_line = NULL;
[528]163    if (!datap)
164        return; // if ClipToLine says nothing to draw, return
[115]165
[687]166    ASSERT(N != BLEND || (pos.y >= bpos.y
[631]167                              && pos.y + ysteps <= bpos.y + blend->Size().y),
[687]168           "blend doesn't fit on TransImage");
[2]169
[528]170    if (N == FADE || N == FADE_TINT)
[541]171        mul = (amount << 16) / nframes;
[528]172    else if (N == BLEND)
173        mul = ((16 - amount) << 16 / 16);
[2]174
[528]175    if (N == PREDATOR)
[687]176        ysteps = lol::min(ysteps, pos2.y - 1 - pos.y - 2);
[2]177
[533]178    screen_line = screen->scan_line(pos.y) + pos.x;
[528]179    int sw = screen->Size().x;
[533]180    pos1.x -= pos.x; pos2.x -= pos.x;
[528]181
[533]182    for (; ysteps > 0; ysteps--, pos.y++)
[2]183    {
[528]184        if (N == BLEND)
[533]185            blend_line = blend->scan_line(pos.y - bpos.y);
[2]186
[528]187        for (int ix = 0; ix < m_size.x; )
[115]188        {
[528]189            // Handle a run of transparent pixels
190            int todo = *datap++;
[2]191
[528]192            // FIXME: implement FILLED mode
193            ix += todo;
194            screen_line += todo;
[2]195
[528]196            if (ix >= m_size.x)
197                break;
[115]198
[528]199            // Handle a run of solid pixels
200            todo = *datap++;
[2]201
[528]202            // Chop left side if necessary, but no more than todo
[687]203            int tochop = lol::min(todo, lol::max(pos1.x - ix, 0));
[2]204
[528]205            ix += tochop;
206            screen_line += tochop;
207            datap += tochop;
208            todo -= tochop;
[2]209
[528]210            // Chop right side if necessary and process the remaining pixels
[687]211            int count = lol::min(todo, lol::max(pos2.x - ix, 0));
[2]212
[532]213            if (N == NORMAL || N == SCANLINE)
[528]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--)
[533]229                    *sl++ = map[*sl2++];
[528]230            }
[532]231            else if (N == REMAP2)
[528]232            {
233                uint8_t *sl = screen_line, *sl2 = datap;
234                while (count--)
[533]235                    *sl++ = map2[map[*sl2++]];
[528]236            }
237            else if (N == FADE || N == FADE_TINT || N == BLEND)
238            {
239                uint8_t *sl = screen_line;
[533]240                uint8_t *sl2 = (N == BLEND) ? blend_line + pos.x + ix - bpos.x
241                                            : sl;
[528]242                uint8_t *sl3 = datap;
[115]243
[528]244                while (count--)
245                {
[694]246                    u8vec3 c1 = pal->GetColor(*sl2++);
247                    u8vec3 c2 = pal->GetColor(N == FADE_TINT ? tint[*sl3++] : *sl3++);
[2]248
[694]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;
[2]252
[694]253                    *sl++ = f->Lookup(u8vec3(r >> 3, g >> 3, b >> 3));
[528]254                }
255            }
[2]256
[528]257            datap += todo;
258            ix += todo;
259            screen_line += todo;
[115]260        }
[528]261        screen_line += sw - m_size.x;
[2]262    }
263}
264
[709]265void TransImage::PutImage(AImage *screen, ivec2 pos)
[528]266{
[719]267    PutImageGeneric<NORMAL>(screen, pos, 0, NULL, ivec2::zero, NULL, NULL,
[528]268                            0, 1, NULL, NULL, NULL);
269}
[2]270
[709]271void TransImage::PutRemap(AImage *screen, ivec2 pos, uint8_t *map)
[528]272{
[719]273    PutImageGeneric<REMAP>(screen, pos, 0, NULL, ivec2::zero, map, NULL,
[528]274                           0, 1, NULL, NULL, NULL);
275}
[2]276
[709]277void TransImage::PutDoubleRemap(AImage *screen, ivec2 pos,
[533]278                            uint8_t *map, uint8_t *map2)
[2]279{
[719]280    PutImageGeneric<REMAP2>(screen, pos, 0, NULL, ivec2::zero, map, map2,
[532]281                            0, 1, NULL, NULL, NULL);
[528]282}
[2]283
[528]284// Used when eg. the player teleports, or in rocket trails
[709]285void TransImage::PutFade(AImage *screen, ivec2 pos, int amount, int nframes,
[694]286                         ColorFilter *f, Palette *pal)
[528]287{
[719]288    PutImageGeneric<FADE>(screen, pos, 0, NULL, ivec2::zero, NULL, NULL,
[541]289                          amount, nframes, NULL, f, pal);
[2]290}
291
[709]292void TransImage::PutFadeTint(AImage *screen, ivec2 pos, int amount, int nframes,
[694]293                             uint8_t *tint, ColorFilter *f, Palette *pal)
[2]294{
[719]295    PutImageGeneric<FADE_TINT>(screen, pos, 0, NULL, ivec2::zero, NULL, NULL,
[541]296                               amount, nframes, tint, f, pal);
[115]297}
[2]298
[709]299void TransImage::PutColor(AImage *screen, ivec2 pos, uint8_t color)
[2]300{
[719]301    PutImageGeneric<COLOR>(screen, pos, color, NULL, ivec2::zero, NULL, NULL,
[528]302                           0, 1, NULL, NULL, NULL);
[2]303}
304
[528]305// This method is unused but is believed to work.
306// Assumes that the blend image completely covers the transparent image.
[709]307void TransImage::PutBlend(AImage *screen, ivec2 pos, AImage *blend, ivec2 bpos,
[694]308                          int amount, ColorFilter *f, Palette *pal)
[2]309{
[533]310    PutImageGeneric<BLEND>(screen, pos, 0, blend, bpos, NULL, NULL,
[528]311                           amount, 1, NULL, f, pal);
[2]312}
313
[709]314void TransImage::PutFilled(AImage *screen, ivec2 pos, uint8_t color)
[532]315{
[719]316    PutImageGeneric<FILLED>(screen, pos, color, NULL, ivec2::zero, NULL, NULL,
[532]317                            0, 1, NULL, NULL, NULL);
318}
319
[709]320void TransImage::PutPredator(AImage *screen, ivec2 pos)
[2]321{
[719]322    PutImageGeneric<PREDATOR>(screen, pos, 0, NULL, ivec2::zero, NULL, NULL,
[528]323                              0, 1, NULL, NULL, NULL);
[2]324}
325
[709]326void TransImage::PutScanLine(AImage *screen, ivec2 pos, int line)
[532]327{
[719]328    PutImageGeneric<SCANLINE>(screen, pos, 0, NULL, ivec2::zero, NULL, NULL,
[532]329                              line, 1, NULL, NULL, NULL);
330}
331
[541]332size_t TransImage::DiskUsage()
[2]333{
[527]334    uint8_t *d = m_data;
[531]335    size_t ret = 0;
[527]336
337    for (int y = 0; y < m_size.y; y++)
[2]338    {
[527]339        for (int x = 0; x < m_size.x; x++)
340        {
[531]341            x += *d++; ret++;
[527]342
343            if (x >= m_size.x)
344                break;
345
[531]346            size_t run = *d++; ret += run + 1; d += run; x += run;
[527]347        }
[2]348    }
[682]349    return ret + sizeof(void *) + sizeof(ivec2);
[2]350}
[527]351
Note: See TracBrowser for help on using the repository browser.