Ticket #8598: nut-renderer3.diff

File nut-renderer3.diff, 14.2 KB (added by eriktorbjorn, 14 years ago)

Patch against current SVN

  • engines/scumm/smush/smush_font.cpp

     
    7474                for (int j = 0; j < h; j++) {
    7575                        for (int i = 0; i < w; i++) {
    7676                                int8 value = *src++;
    77                                 if (value)
     77                                if (value != kDefaultTransparentColor)
    7878                                        dst[i] = value;
    7979                        }
    8080                        dst += dst_width;
     
    8989                                                dst[i] = 0xFF;
    9090                                        } else if (value == -31) {
    9191                                                dst[i] = 0;
    92                                         } else if (value) {
     92                                        } else if (value != kSmush44TransparentColor) {
    9393                                                dst[i] = value;
    9494                                        }
    9595                                }
     
    101101                                        int8 value = *src++;
    102102                                        if (value == 1) {
    103103                                                dst[i] = color;
    104                                         } else if (value) {
     104                                        } else if (value != kDefaultTransparentColor) {
    105105                                                dst[i] = 0;
    106106                                        }
    107107                                }
  • engines/scumm/charset.cpp

     
    16551655        if (chr == '@')
    16561656                return;
    16571657
    1658         shadow.left = _left - 1;
    1659         shadow.top = _top - 1;
     1658        shadow.left = _left;
     1659        shadow.top = _top;
    16601660
    1661         // Note that the character is drawn with a shadow, so it is slightly
    1662         // larger than the advertised dimensions. See drawShadowChar() for
    1663         // details.
    1664 
    16651661        if (_firstChar) {
    16661662                _str.left = (shadow.left >= 0) ? shadow.left : 0;
    16671663                _str.top = (shadow.top >= 0) ? shadow.top : 0;
     
    16761672        if (chr >= 256 && _vm->_useCJKMode)
    16771673                width = _vm->_2byteWidth;
    16781674
    1679         shadow.right = _left + width + 2;
    1680         shadow.bottom = _top + height + 2;
     1675        shadow.right = _left + width;
     1676        shadow.bottom = _top + height;
    16811677
    16821678        Graphics::Surface s;
    16831679        if (!ignoreCharsetMask) {
     
    16951691                drawTop -= _vm->_screenTop;
    16961692        }
    16971693
    1698         _current->drawShadowChar(s, chr, _left, drawTop, _color, _curId != 3);
     1694        if (chr >= 256 && _vm->_useCJKMode)
     1695                _current->draw2byte(s, chr, _left, drawTop, _color);
     1696        else
     1697                _current->drawChar(s, (byte)chr, _left, drawTop, _color);
    16991698        _vm->markRectAsDirty(kMainVirtScreen, shadow);
    17001699
    17011700        if (_str.left > _left)
  • engines/scumm/nut_renderer.cpp

     
    2727
    2828namespace Scumm {
    2929
    30 NutRenderer::NutRenderer(ScummEngine *vm, const char *filename, bool bitmap) :
     30NutRenderer::NutRenderer(ScummEngine *vm, const char *filename, bool compress) :
    3131        _vm(vm),
    32         _bitmapFont(bitmap),
    3332        _numChars(0),
    3433        _decodedData(0) {
    3534        memset(_chars, 0, sizeof(_chars));
    36         loadFont(filename);
     35        loadFont(filename, compress);
    3736}
    3837
    3938NutRenderer::~NutRenderer() {
    4039        delete [] _decodedData;
    4140}
    4241
    43 void NutRenderer::codec1(byte *dst, const byte *src, int width, int height, int pitch) {
    44         byte val, code;
    45         int32 length;
    46         int h = height, size_line;
     42void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch);
    4743
    48         for (h = 0; h < height; h++) {
    49                 size_line = READ_LE_UINT16(src);
    50                 src += 2;
    51                 byte bit = 0x80;
    52                 byte *dstPtrNext = dst + pitch;
    53                 while (size_line > 0) {
    54                         code = *src++;
    55                         size_line--;
    56                         length = (code >> 1) + 1;
    57                         if (code & 1) {
    58                                 val = *src++;
    59                                 size_line--;
    60                                 if (_bitmapFont) {
    61                                         for (int i = 0; i < length; i++) {
    62                                                 if (val)
    63                                                         *dst |= bit;
    64                                                 bit >>= 1;
    65                                                 if (!bit) {
    66                                                         bit = 0x80;
    67                                                         dst++;
    68                                                 }
    69                                         }
    70                                 } else {
    71                                         if (val)
    72                                                 memset(dst, val, length);
    73                                         dst += length;
    74                                 }
    75                         } else {
    76                                 size_line -= length;
    77                                 while (length--) {
    78                                         val = *src++;
    79                                         if (_bitmapFont) {
    80                                                 if (val)
    81                                                         *dst |= bit;
    82                                                 bit >>= 1;
    83                                                 if (!bit) {
    84                                                         bit = 0x80;
    85                                                         dst++;
    86                                                 }
    87                                         } else {
    88                                                 if (val)
    89                                                         *dst = val;
    90                                                 dst++;
    91                                         }
    92                                 }
    93                         }
    94                 }
    95                 dst = dstPtrNext;
    96         }
     44void NutRenderer::codec1(byte *dst, const byte *src, int width, int height, int pitch) {
     45        smush_decode_codec1(dst, src, 0, 0, width, height, pitch);
    9746}
    9847
    9948void NutRenderer::codec21(byte *dst, const byte *src, int width, int height, int pitch) {
     
    10251                const byte *srcPtrNext = src + 2 + READ_LE_UINT16(src);
    10352                src += 2;
    10453                int len = width;
    105                 byte bit = 0x80;
    10654                do {
    107                         int i;
    10855                        int offs = READ_LE_UINT16(src); src += 2;
    109                         if (_bitmapFont) {
    110                                 for (i = 0; i < offs; i++) {
    111                                         bit >>= 1;
    112                                         if (!bit) {
    113                                                 bit = 0x80;
    114                                                 dst++;
    115                                         }
    116                                 }
    117                         } else {
    118                                 dst += offs;
    119                         }
     56                        dst += offs;
    12057                        len -= offs;
    12158                        if (len <= 0) {
    12259                                break;
     
    13067                        //  src bytes equal to 255 are replaced by 0 in dst
    13168                        //  src bytes equal to 1 are replaced by a color passed as an argument in the original function
    13269                        //  other src bytes values are copied as-is
    133                         if (_bitmapFont) {
    134                                 for (i = 0; i < w; i++) {
    135                                         if (src[i])
    136                                                 *dst |= bit;
    137                                         bit >>= 1;
    138                                         if (!bit) {
    139                                                 bit = 0x80;
    140                                                 dst++;
    141                                         }
    142                                 }
    143                         } else {
    144                                 memcpy(dst, src, w);
    145                                 dst += w;
     70                        for (int i = 0; i < w; i++) {
     71                                _paletteMap[src[i]] = 1;
    14672                        }
     73                        memcpy(dst, src, w);
     74                        dst += w;
    14775                        src += w;
    14876                } while (len > 0);
    14977                dst = dstPtrNext;
     
    15179        }
    15280}
    15381
    154 void NutRenderer::loadFont(const char *filename) {
     82void NutRenderer::loadFont(const char *filename, bool compress) {
    15583        ScummFile file;
    15684        _vm->openFile(file, filename);
    15785        if (!file.isOpen()) {
     
    181109
    182110        uint32 offset = 0;
    183111        uint32 decodedLength = 0;
    184         for (int l = 0; l < _numChars; l++) {
     112        int l;
     113       
     114        _paletteMap = new byte[256];
     115        for (l = 0; l < 256; l++) {
     116                _paletteMap[l] = 0;
     117        }
     118
     119        for (l = 0; l < _numChars; l++) {
    185120                offset += READ_BE_UINT32(dataSrc + offset + 4) + 16;
    186121                int width = READ_LE_UINT16(dataSrc + offset + 14);
    187122                int height = READ_LE_UINT16(dataSrc + offset + 16);
    188                 if (_bitmapFont) {
    189                         decodedLength += (((width + 7) / 8) * height);
    190                 } else {
    191                         decodedLength += (width * height);
    192                 }
     123                decodedLength += (width * height);
    193124        }
    194125
    195         // If characters have transparency, then bytes just get skipped and
    196         // so there may appear some garbage. That's why we have to fill it
    197         // with zeroes first.
     126        debug(1, "NutRenderer::loadFont('%s') - decodedLength = %d", filename, decodedLength);
    198127
    199128        _decodedData = new byte[decodedLength];
    200         memset(_decodedData, 0, decodedLength);
    201 
    202129        byte *decodedPtr = _decodedData;
    203130
    204131        offset = 0;
    205         for (int l = 0; l < _numChars; l++) {
     132        for (l = 0; l < _numChars; l++) {
    206133                offset += READ_BE_UINT32(dataSrc + offset + 4) + 8;
    207134                if (READ_BE_UINT32(dataSrc + offset) != MKID_BE('FRME')) {
    208135                        error("NutRenderer::loadFont(%s) there is no FRME chunk %d (offset %x)", filename, l, offset);
     
    220147                _chars[l].height = READ_LE_UINT16(dataSrc + offset + 16);
    221148                _chars[l].src = decodedPtr;
    222149
    223                 int pitch;
     150                decodedPtr += (_chars[l].width * _chars[l].height);
    224151
    225                 if (_bitmapFont) {
    226                         pitch = (_chars[l].width + 7) / 8;
     152                // If characters have transparency, then bytes just get skipped and
     153                // so there may appear some garbage. That's why we have to fill it
     154                // with a default color first.
     155                if (codec == 44) {
     156                        memset(_chars[l].src, kSmush44TransparentColor, _chars[l].width * _chars[l].height);
     157                        _paletteMap[kSmush44TransparentColor] = 1;
     158                        _chars[l].transparency = kSmush44TransparentColor;
    227159                } else {
    228                         pitch = _chars[l].width;
     160                        memset(_chars[l].src, kDefaultTransparentColor, _chars[l].width * _chars[l].height);
     161                        _paletteMap[kDefaultTransparentColor] = 1;
     162                        _chars[l].transparency = kDefaultTransparentColor;
    229163                }
    230164
    231                 decodedPtr += (pitch * _chars[l].height);
    232 
    233165                const uint8 *fobjptr = dataSrc + offset + 22;
    234166                switch (codec) {
    235167                case 1:
    236                         codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
     168                        codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
    237169                        break;
    238170                case 21:
    239171                case 44:
    240                         codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
     172                        codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
    241173                        break;
    242174                default:
    243175                        error("NutRenderer::loadFont: unknown codec: %d", codec);
    244176                }
    245177        }
    246178
     179        if (compress) {
     180                int numColors = 0;
     181                for (l = 0; l < 256; l++) {
     182                        if (_paletteMap[l]) {
     183                                if (numColors < ARRAYSIZE(_palette)) {
     184                                        _paletteMap[l] = numColors;
     185                                        _palette[numColors] = l;
     186                                }
     187                                numColors++;
     188                        }
     189                }
     190
     191                // Now _palette contains all the used colors, and _paletteMap
     192                // maps the real color to the palette index.
     193
     194                if (numColors <= 2)
     195                        _bpp = 1;
     196                else if (numColors <= 4)
     197                        _bpp = 2;
     198                else if (numColors <= 16)
     199                        _bpp = 4;
     200                else
     201                        _bpp = 8;
     202
     203                if (_bpp < 8) {
     204                        int compressedLength = 0;
     205                        for (l = 0; l < 256; l++) {
     206                                compressedLength += (((_bpp * _chars[l].width + 7) / 8) * _chars[l].height);
     207                        }
     208
     209                        debug(1, "NutRenderer::loadFont('%s') - compressedLength = %d (%d bpp)", filename, compressedLength, _bpp);
     210
     211                        byte *compressedData = new byte[compressedLength];
     212                        memset(compressedData, 0, compressedLength);
     213
     214                        offset = 0;
     215
     216                        for (l = 0; l < 256; l++) {
     217                                byte *src = _chars[l].src;
     218                                byte *dst = compressedData + offset;
     219                                int srcPitch = _chars[l].width;
     220                                int dstPitch = (_bpp * _chars[l].width + 7) / 8;
     221
     222                                for (int h = 0; h < _chars[l].height; h++) {
     223                                        byte bit = 0x80;
     224                                        byte *nextDst = dst + dstPitch;
     225                                        for (int w = 0; w < srcPitch; w++) {
     226                                                byte color = _paletteMap[src[w]];
     227                                                for (int i = 0; i < _bpp; i++) {
     228                                                        if (color & (1 << i))
     229                                                                *dst |= bit;
     230                                                        bit >>= 1;
     231                                                }
     232                                                if (!bit) {
     233                                                        bit = 0x80;
     234                                                        dst++;
     235                                                }
     236                                        }
     237                                        src += srcPitch;
     238                                        dst = nextDst;
     239                                }
     240                                _chars[l].src = compressedData + offset;
     241                                offset += (dstPitch * _chars[l].height);
     242                        }
     243
     244                        delete [] _decodedData;
     245                        _decodedData = compressedData;
     246                } else
     247                        _bpp = 8;
     248                       
     249        }
     250
    247251        delete [] dataSrc;
     252        delete [] _paletteMap;
    248253}
    249254
    250255int NutRenderer::getCharWidth(byte c) const {
     
    267272        return _chars[c].height;
    268273}
    269274
    270 void NutRenderer::drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow) {
    271 
    272         // We draw the character a total of 7 times: 6 times shifted and in black
    273         // for the shadow, and once in the right color and position. This way we
    274         // achieve the exact look as the original CMI had.
    275         // However, this is not how the original engine handled it. Char glyphs
    276         // were compressed with codec 44. In the decoding routine, transparent
    277         // pixels are skipped. Other pixels are just filled with the decoded color
    278         // which can be equal to 0 (==shadow), 1 (==char color) or another value
    279         // (255, 224) which is just copied as-is in the destination buffer.
    280 
    281         static const int offsetX[7] = { -1,  0, 1, 0, 1, 2, 0 };
    282         static const int offsetY[7] = {  0, -1, 0, 1, 2, 1, 0 };
    283         const int cTable[7] = { 0, 0, 0, 0, 0, 0, color };
    284         int i = 0;
    285 
    286         if (!showShadow)
    287                 i = 6;
    288 
    289         for (; i < 7; i++) {
    290                 x += offsetX[i];
    291                 y += offsetY[i];
    292                 color = cTable[i];
    293 
    294                 if (c >= 256 && _vm->_useCJKMode)
    295                         draw2byte(s, c, x, y, color);
    296                 else
    297                         drawChar(s, (byte)c, x, y, color);
    298 
    299                 x -= offsetX[i];
    300                 y -= offsetY[i];
    301         }
    302 }
    303 
    304275void NutRenderer::drawFrame(byte *dst, int c, int x, int y) {
    305         assert(!_bitmapFont);
    306 
    307276        const int width = MIN((int)_chars[c].width, _vm->_screenWidth - x);
    308277        const int height = MIN((int)_chars[c].height, _vm->_screenHeight - y);
    309278        const byte *src = _chars[c].src;
     
    340309        const int width = MIN((int)_chars[c].width, s.w - x);
    341310        const int height = MIN((int)_chars[c].height, s.h - y);
    342311        const byte *src = _chars[c].src;
    343         int srcPitch;
     312        int srcPitch = (_bpp * _chars[c].width + 7) / 8;
    344313
    345         if (_bitmapFont) {
    346                 srcPitch = (_chars[c].width + 7) / 8;
    347         } else {
    348                 srcPitch = _chars[c].width;
    349         }
    350 
    351314        const int minX = x < 0 ? -x : 0;
    352315        const int minY = y < 0 ? -y : 0;
    353316
     
    361324        }
    362325
    363326        for (int ty = minY; ty < height; ty++) {
    364                 int tx;
     327                for (int tx = minX; tx < width; tx++) {
     328                        byte val;
    365329
    366                 for (tx = minX; tx < width; tx++) {
    367                         if (_bitmapFont) {
    368                                 if (src[tx / 8] & (0x80 >> (tx % 8))) {
    369                                         dst[tx] = color;
     330                        if (_bpp < 8) {
     331                                int offset;
     332                                byte bit;
     333
     334                                switch (_bpp) {
     335                                case 1:
     336                                        offset = tx / 8;
     337                                        bit = 0x80 >> (tx % 8);
     338                                        break;
     339                                case 2:
     340                                        offset = tx / 4;
     341                                        bit = 0x80 >> (2 * (tx % 4));
     342                                        break;
     343                                default:
     344                                        offset = tx / 2;
     345                                        bit = 0x80 >> (4 * (tx % 2));
     346                                        break;
    370347                                }
     348
     349                                val = 0;
     350
     351                                for (int i = 0; i < _bpp; i++) {
     352                                        if (src[offset] & (bit >> i))
     353                                                val |= (1 << i);
     354                                }
     355
     356                                val = _palette[val];
    371357                        } else {
    372                                 if (src[tx] != 0) {
     358                                val = src[tx];
     359                        }
     360
     361                        if (val != _chars[c].transparency) {
     362                                if (val == 1) {
    373363                                        dst[tx] = color;
     364                                } else {
     365                                        dst[tx] = val;
    374366                                }
    375367                        }
    376368                }
  • engines/scumm/nut_renderer.h

     
    3131
    3232class NutRenderer {
    3333protected:
     34
     35        enum {
     36                kDefaultTransparentColor = 0,
     37                kSmush44TransparentColor = 2
     38        };
     39
    3440        ScummEngine *_vm;
    35         bool _bitmapFont;
    3641        int _numChars;
    3742        byte *_decodedData;
     43        byte *_paletteMap;
     44        byte _bpp;
     45        byte _palette[16];
    3846        struct {
    3947                uint16 width;
    4048                uint16 height;
    4149                byte *src;
     50                byte transparency;
    4251        } _chars[256];
    4352
    4453        void codec1(byte *dst, const byte *src, int width, int height, int pitch);
    4554        void codec21(byte *dst, const byte *src, int width, int height, int pitch);
    4655
    47         void drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color);
    48         void draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color);
     56        void loadFont(const char *filename, bool compress);
    4957
    50         void loadFont(const char *filename);
    51 
    5258public:
    53         NutRenderer(ScummEngine *vm, const char *filename, bool bitmap);
     59        NutRenderer(ScummEngine *vm, const char *filename, bool compress);
    5460        virtual ~NutRenderer();
    5561        int getNumChars() const { return _numChars; }
    5662
    5763        void drawFrame(byte *dst, int c, int x, int y);
    58         void drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow);
     64        void drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color);
     65        void draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color);
    5966
    6067        int getCharWidth(byte c) const;
    6168        int getCharHeight(byte c) const;