Ticket #8598: nut-renderer4.diff

File nut-renderer4.diff, 16.3 KB (added by eriktorbjorn, 14 years ago)

Patch against current SVN

  • engines/scumm/smush/smush_font.cpp

     
    3030namespace Scumm {
    3131
    3232SmushFont::SmushFont(ScummEngine *vm, const char *filename, bool use_original_colors, bool new_colors) :
    33         NutRenderer(vm, filename, false),
     33        NutRenderer(vm, filename),
    3434        _color(-1),
    3535        _new_colors(new_colors),
    3636        _original(use_original_colors) {
     
    6565int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) {
    6666        int w = _chars[chr].width;
    6767        int h = _chars[chr].height;
    68         const byte *src = _chars[chr].src;
     68        const byte *src = unpackChar(chr);
    6969        byte *dst = buffer + dst_width * y + x;
    7070
    7171        assert(dst_width == _vm->_screenWidth);
     
    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 != _chars[chr].transparency)
    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 != _chars[chr].transparency) {
    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 != _chars[chr].transparency) {
    105105                                                dst[i] = 0;
    106106                                        }
    107107                                }
  • engines/scumm/charset.cpp

     
    16261626        if (!_fr[id]) {
    16271627                char fontname[11];
    16281628                sprintf(fontname, "font%d.nut", id);
    1629                 _fr[id] = new NutRenderer(_vm, fontname, true);
     1629                _fr[id] = new NutRenderer(_vm, fontname);
    16301630        }
    16311631        _current = _fr[id];
    16321632        assert(_current);
     
    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/insane/insane.cpp

     
    6565                readFileToMem("toranch.flu", &_smush_toranchFlu);
    6666                readFileToMem("minedriv.flu", &_smush_minedrivFlu);
    6767                readFileToMem("minefite.flu", &_smush_minefiteFlu);
    68                 _smush_bensgoggNut = new NutRenderer(_vm, "bensgogg.nut", false);
    69                 _smush_bencutNut = new NutRenderer(_vm, "bencut.nut", false);
     68                _smush_bensgoggNut = new NutRenderer(_vm, "bensgogg.nut");
     69                _smush_bencutNut = new NutRenderer(_vm, "bencut.nut");
    7070        }
    7171
    72         _smush_iconsNut = new NutRenderer(_vm, "icons.nut", false);
    73         _smush_icons2Nut = new NutRenderer(_vm, "icons2.nut", false);
     72        _smush_iconsNut = new NutRenderer(_vm, "icons.nut");
     73        _smush_icons2Nut = new NutRenderer(_vm, "icons2.nut");
    7474}
    7575
    7676Insane::~Insane(void) {
  • 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) :
    3131        _vm(vm),
    32         _bitmapFont(bitmap),
    3332        _numChars(0),
     33        _maxCharSize(0),
     34        _charBuffer(0),
    3435        _decodedData(0) {
    3536        memset(_chars, 0, sizeof(_chars));
    3637        loadFont(filename);
    3738}
    3839
    3940NutRenderer::~NutRenderer() {
     41        delete [] _charBuffer;
    4042        delete [] _decodedData;
    4143}
    4244
     45void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch);
     46
    4347void 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;
    47 
    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         }
     48        smush_decode_codec1(dst, src, 0, 0, width, height, pitch);
     49        for (int i = 0; i < width * height; i++)
     50                _paletteMap[dst[i]] = 1;
    9751}
    9852
    9953void NutRenderer::codec21(byte *dst, const byte *src, int width, int height, int pitch) {
     
    10256                const byte *srcPtrNext = src + 2 + READ_LE_UINT16(src);
    10357                src += 2;
    10458                int len = width;
    105                 byte bit = 0x80;
    10659                do {
    107                         int i;
    10860                        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                         }
     61                        dst += offs;
    12062                        len -= offs;
    12163                        if (len <= 0) {
    12264                                break;
     
    13072                        //  src bytes equal to 255 are replaced by 0 in dst
    13173                        //  src bytes equal to 1 are replaced by a color passed as an argument in the original function
    13274                        //  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;
     75                        for (int i = 0; i < w; i++) {
     76                                _paletteMap[src[i]] = 1;
    14677                        }
     78                        memcpy(dst, src, w);
     79                        dst += w;
    14780                        src += w;
    14881                } while (len > 0);
    14982                dst = dstPtrNext;
     
    181114
    182115        uint32 offset = 0;
    183116        uint32 decodedLength = 0;
    184         for (int l = 0; l < _numChars; l++) {
     117        int l;
     118       
     119        _paletteMap = new byte[256];
     120        for (l = 0; l < 256; l++) {
     121                _paletteMap[l] = 0;
     122        }
     123
     124        for (l = 0; l < _numChars; l++) {
    185125                offset += READ_BE_UINT32(dataSrc + offset + 4) + 16;
    186126                int width = READ_LE_UINT16(dataSrc + offset + 14);
    187127                int height = READ_LE_UINT16(dataSrc + offset + 16);
    188                 if (_bitmapFont) {
    189                         decodedLength += (((width + 7) / 8) * height);
    190                 } else {
    191                         decodedLength += (width * height);
    192                 }
     128                int size = width * height;
     129                decodedLength += size;
     130                if (size > _maxCharSize)
     131                        _maxCharSize = size;
    193132        }
    194133
    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.
     134        debug(1, "NutRenderer::loadFont('%s') - decodedLength = %d", filename, decodedLength);
    198135
    199136        _decodedData = new byte[decodedLength];
    200         memset(_decodedData, 0, decodedLength);
    201 
    202137        byte *decodedPtr = _decodedData;
    203138
    204139        offset = 0;
    205         for (int l = 0; l < _numChars; l++) {
     140        for (l = 0; l < _numChars; l++) {
    206141                offset += READ_BE_UINT32(dataSrc + offset + 4) + 8;
    207142                if (READ_BE_UINT32(dataSrc + offset) != MKID_BE('FRME')) {
    208143                        error("NutRenderer::loadFont(%s) there is no FRME chunk %d (offset %x)", filename, l, offset);
     
    220155                _chars[l].height = READ_LE_UINT16(dataSrc + offset + 16);
    221156                _chars[l].src = decodedPtr;
    222157
    223                 int pitch;
     158                decodedPtr += (_chars[l].width * _chars[l].height);
    224159
    225                 if (_bitmapFont) {
    226                         pitch = (_chars[l].width + 7) / 8;
     160                // If characters have transparency, then bytes just get skipped and
     161                // so there may appear some garbage. That's why we have to fill it
     162                // with a default color first.
     163                if (codec == 44) {
     164                        memset(_chars[l].src, kSmush44TransparentColor, _chars[l].width * _chars[l].height);
     165                        _paletteMap[kSmush44TransparentColor] = 1;
     166                        _chars[l].transparency = kSmush44TransparentColor;
    227167                } else {
    228                         pitch = _chars[l].width;
     168                        memset(_chars[l].src, kDefaultTransparentColor, _chars[l].width * _chars[l].height);
     169                        _paletteMap[kDefaultTransparentColor] = 1;
     170                        _chars[l].transparency = kDefaultTransparentColor;
    229171                }
    230172
    231                 decodedPtr += (pitch * _chars[l].height);
    232 
    233173                const uint8 *fobjptr = dataSrc + offset + 22;
    234174                switch (codec) {
    235175                case 1:
    236                         codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
     176                        codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
    237177                        break;
    238178                case 21:
    239179                case 44:
    240                         codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
     180                        codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
    241181                        break;
    242182                default:
    243183                        error("NutRenderer::loadFont: unknown codec: %d", codec);
    244184                }
    245185        }
    246186
     187        // We have decoded the font. Now let's see if we can re-compress it to
     188        // a more compact format. Start by counting the number of colors.
     189
     190        int numColors = 0;
     191        for (l = 0; l < 256; l++) {
     192                if (_paletteMap[l]) {
     193                        if (numColors < ARRAYSIZE(_palette)) {
     194                                _paletteMap[l] = numColors;
     195                                _palette[numColors] = l;
     196                        }
     197                        numColors++;
     198                }
     199        }
     200
     201        // Now _palette contains all the used colors, and _paletteMap maps the
     202        // real color to the palette index.
     203
     204        if (numColors <= 2)
     205                _bpp = 1;
     206        else if (numColors <= 4)
     207                _bpp = 2;
     208        else if (numColors <= 16)
     209                _bpp = 4;
     210        else
     211                _bpp = 8;
     212
     213        if (_bpp < 8) {
     214                int compressedLength = 0;
     215                for (l = 0; l < 256; l++) {
     216                        compressedLength += (((_bpp * _chars[l].width + 7) / 8) * _chars[l].height);
     217                }
     218
     219                debug(1, "NutRenderer::loadFont('%s') - compressedLength = %d (%d bpp)", filename, compressedLength, _bpp);
     220
     221                byte *compressedData = new byte[compressedLength];
     222                memset(compressedData, 0, compressedLength);
     223
     224                offset = 0;
     225
     226                for (l = 0; l < 256; l++) {
     227                        byte *src = _chars[l].src;
     228                        byte *dst = compressedData + offset;
     229                        int srcPitch = _chars[l].width;
     230                        int dstPitch = (_bpp * _chars[l].width + 7) / 8;
     231
     232                        for (int h = 0; h < _chars[l].height; h++) {
     233                                byte bit = 0x80;
     234                                byte *nextDst = dst + dstPitch;
     235                                for (int w = 0; w < srcPitch; w++) {
     236                                        byte color = _paletteMap[src[w]];
     237                                        for (int i = 0; i < _bpp; i++) {
     238                                                if (color & (1 << i))
     239                                                        *dst |= bit;
     240                                                bit >>= 1;
     241                                        }
     242                                        if (!bit) {
     243                                                bit = 0x80;
     244                                                dst++;
     245                                        }
     246                                }
     247                                src += srcPitch;
     248                                dst = nextDst;
     249                        }
     250                        _chars[l].src = compressedData + offset;
     251                        offset += (dstPitch * _chars[l].height);
     252                }
     253
     254                delete [] _decodedData;
     255                _decodedData = compressedData;
     256
     257                _charBuffer = new byte[_maxCharSize];
     258        }
     259
    247260        delete [] dataSrc;
     261        delete [] _paletteMap;
    248262}
    249263
    250264int NutRenderer::getCharWidth(byte c) const {
     
    267281        return _chars[c].height;
    268282}
    269283
    270 void NutRenderer::drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow) {
     284byte *NutRenderer::unpackChar(byte c) {
     285        if (_bpp == 8)
     286                return _chars[c].src;
    271287
    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.
     288        byte *src = _chars[c].src;
     289        int pitch = (_bpp * _chars[c].width + 7) / 8;
    280290
    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;
     291        for (int ty = 0; ty < _chars[c].height; ty++) {
     292                for (int tx = 0; tx < _chars[c].width; tx++) {
     293                        byte val;
     294                        int offset;
     295                        byte bit;
    285296
    286         if (!showShadow)
    287                 i = 6;
     297                        switch (_bpp) {
     298                        case 1:
     299                                offset = tx / 8;
     300                                bit = 0x80 >> (tx % 8);
     301                                break;
     302                        case 2:
     303                                offset = tx / 4;
     304                                bit = 0x80 >> (2 * (tx % 4));
     305                                break;
     306                        default:
     307                                offset = tx / 2;
     308                                bit = 0x80 >> (4 * (tx % 2));
     309                                break;
     310                        }
    288311
    289         for (; i < 7; i++) {
    290                 x += offsetX[i];
    291                 y += offsetY[i];
    292                 color = cTable[i];
     312                        val = 0;
    293313
    294                 if (c >= 256 && _vm->_useCJKMode)
    295                         draw2byte(s, c, x, y, color);
    296                 else
    297                         drawChar(s, (byte)c, x, y, color);
     314                        for (int i = 0; i < _bpp; i++) {
     315                                if (src[offset] & (bit >> i))
     316                                        val |= (1 << i);
     317                        }
    298318
    299                 x -= offsetX[i];
    300                 y -= offsetY[i];
     319                        _charBuffer[ty * _chars[c].width + tx] = _palette[val];
     320                }
     321                src += pitch;
    301322        }
     323
     324        return _charBuffer;
    302325}
    303326
    304327void NutRenderer::drawFrame(byte *dst, int c, int x, int y) {
    305         assert(!_bitmapFont);
    306 
    307328        const int width = MIN((int)_chars[c].width, _vm->_screenWidth - x);
    308329        const int height = MIN((int)_chars[c].height, _vm->_screenHeight - y);
    309         const byte *src = _chars[c].src;
     330        const byte *src = unpackChar(c);
    310331        const int srcPitch = _chars[c].width;
    311332        byte bits = 0;
    312333
     
    339360        byte *dst = (byte *)s.pixels + y * s.pitch + x;
    340361        const int width = MIN((int)_chars[c].width, s.w - x);
    341362        const int height = MIN((int)_chars[c].height, s.h - y);
    342         const byte *src = _chars[c].src;
    343         int srcPitch;
     363        const byte *src = unpackChar(c);
     364        int srcPitch = _chars[c].width;
    344365
    345         if (_bitmapFont) {
    346                 srcPitch = (_chars[c].width + 7) / 8;
    347         } else {
    348                 srcPitch = _chars[c].width;
    349         }
    350 
    351366        const int minX = x < 0 ? -x : 0;
    352367        const int minY = y < 0 ? -y : 0;
    353368
     
    361376        }
    362377
    363378        for (int ty = minY; ty < height; ty++) {
    364                 int tx;
    365 
    366                 for (tx = minX; tx < width; tx++) {
    367                         if (_bitmapFont) {
    368                                 if (src[tx / 8] & (0x80 >> (tx % 8))) {
     379                for (int tx = minX; tx < width; tx++) {
     380                        if (src[tx] != _chars[c].transparency) {
     381                                if (src[tx] == 1) {
    369382                                        dst[tx] = color;
     383                                } else {
     384                                        dst[tx] = src[tx];
    370385                                }
    371                         } else {
    372                                 if (src[tx] != 0) {
    373                                         dst[tx] = color;
    374                                 }
    375386                        }
    376387                }
    377388                src += srcPitch;
  • 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;
     42        int _maxCharSize;
     43        byte *_charBuffer;
    3744        byte *_decodedData;
     45        byte *_paletteMap;
     46        byte _bpp;
     47        byte _palette[16];
    3848        struct {
    3949                uint16 width;
    4050                uint16 height;
    4151                byte *src;
     52                byte transparency;
    4253        } _chars[256];
    4354
    4455        void codec1(byte *dst, const byte *src, int width, int height, int pitch);
    4556        void codec21(byte *dst, const byte *src, int width, int height, int pitch);
    4657
    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);
    49 
    5058        void loadFont(const char *filename);
     59        byte *unpackChar(byte c);
    5160
    5261public:
    53         NutRenderer(ScummEngine *vm, const char *filename, bool bitmap);
     62        NutRenderer(ScummEngine *vm, const char *filename);
    5463        virtual ~NutRenderer();
    5564        int getNumChars() const { return _numChars; }
    5665
    5766        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);
     67        void drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color);
     68        void draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color);
    5969
    6070        int getCharWidth(byte c) const;
    6171        int getCharHeight(byte c) const;