Ticket #8598: nut-renderer4.diff
File nut-renderer4.diff, 16.3 KB (added by , 18 years ago) |
---|
-
engines/scumm/smush/smush_font.cpp
30 30 namespace Scumm { 31 31 32 32 SmushFont::SmushFont(ScummEngine *vm, const char *filename, bool use_original_colors, bool new_colors) : 33 NutRenderer(vm, filename , false),33 NutRenderer(vm, filename), 34 34 _color(-1), 35 35 _new_colors(new_colors), 36 36 _original(use_original_colors) { … … 65 65 int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) { 66 66 int w = _chars[chr].width; 67 67 int h = _chars[chr].height; 68 const byte *src = _chars[chr].src;68 const byte *src = unpackChar(chr); 69 69 byte *dst = buffer + dst_width * y + x; 70 70 71 71 assert(dst_width == _vm->_screenWidth); … … 74 74 for (int j = 0; j < h; j++) { 75 75 for (int i = 0; i < w; i++) { 76 76 int8 value = *src++; 77 if (value )77 if (value != _chars[chr].transparency) 78 78 dst[i] = value; 79 79 } 80 80 dst += dst_width; … … 89 89 dst[i] = 0xFF; 90 90 } else if (value == -31) { 91 91 dst[i] = 0; 92 } else if (value ) {92 } else if (value != _chars[chr].transparency) { 93 93 dst[i] = value; 94 94 } 95 95 } … … 101 101 int8 value = *src++; 102 102 if (value == 1) { 103 103 dst[i] = color; 104 } else if (value ) {104 } else if (value != _chars[chr].transparency) { 105 105 dst[i] = 0; 106 106 } 107 107 } -
engines/scumm/charset.cpp
1626 1626 if (!_fr[id]) { 1627 1627 char fontname[11]; 1628 1628 sprintf(fontname, "font%d.nut", id); 1629 _fr[id] = new NutRenderer(_vm, fontname , true);1629 _fr[id] = new NutRenderer(_vm, fontname); 1630 1630 } 1631 1631 _current = _fr[id]; 1632 1632 assert(_current); … … 1655 1655 if (chr == '@') 1656 1656 return; 1657 1657 1658 shadow.left = _left - 1;1659 shadow.top = _top - 1;1658 shadow.left = _left; 1659 shadow.top = _top; 1660 1660 1661 // Note that the character is drawn with a shadow, so it is slightly1662 // larger than the advertised dimensions. See drawShadowChar() for1663 // details.1664 1665 1661 if (_firstChar) { 1666 1662 _str.left = (shadow.left >= 0) ? shadow.left : 0; 1667 1663 _str.top = (shadow.top >= 0) ? shadow.top : 0; … … 1676 1672 if (chr >= 256 && _vm->_useCJKMode) 1677 1673 width = _vm->_2byteWidth; 1678 1674 1679 shadow.right = _left + width + 2;1680 shadow.bottom = _top + height + 2;1675 shadow.right = _left + width; 1676 shadow.bottom = _top + height; 1681 1677 1682 1678 Graphics::Surface s; 1683 1679 if (!ignoreCharsetMask) { … … 1695 1691 drawTop -= _vm->_screenTop; 1696 1692 } 1697 1693 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); 1699 1698 _vm->markRectAsDirty(kMainVirtScreen, shadow); 1700 1699 1701 1700 if (_str.left > _left) -
engines/scumm/insane/insane.cpp
65 65 readFileToMem("toranch.flu", &_smush_toranchFlu); 66 66 readFileToMem("minedriv.flu", &_smush_minedrivFlu); 67 67 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"); 70 70 } 71 71 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"); 74 74 } 75 75 76 76 Insane::~Insane(void) { -
engines/scumm/nut_renderer.cpp
27 27 28 28 namespace Scumm { 29 29 30 NutRenderer::NutRenderer(ScummEngine *vm, const char *filename , bool bitmap) :30 NutRenderer::NutRenderer(ScummEngine *vm, const char *filename) : 31 31 _vm(vm), 32 _bitmapFont(bitmap),33 32 _numChars(0), 33 _maxCharSize(0), 34 _charBuffer(0), 34 35 _decodedData(0) { 35 36 memset(_chars, 0, sizeof(_chars)); 36 37 loadFont(filename); 37 38 } 38 39 39 40 NutRenderer::~NutRenderer() { 41 delete [] _charBuffer; 40 42 delete [] _decodedData; 41 43 } 42 44 45 void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch); 46 43 47 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; 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; 97 51 } 98 52 99 53 void NutRenderer::codec21(byte *dst, const byte *src, int width, int height, int pitch) { … … 102 56 const byte *srcPtrNext = src + 2 + READ_LE_UINT16(src); 103 57 src += 2; 104 58 int len = width; 105 byte bit = 0x80;106 59 do { 107 int i;108 60 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; 120 62 len -= offs; 121 63 if (len <= 0) { 122 64 break; … … 130 72 // src bytes equal to 255 are replaced by 0 in dst 131 73 // src bytes equal to 1 are replaced by a color passed as an argument in the original function 132 74 // 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; 146 77 } 78 memcpy(dst, src, w); 79 dst += w; 147 80 src += w; 148 81 } while (len > 0); 149 82 dst = dstPtrNext; … … 181 114 182 115 uint32 offset = 0; 183 116 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++) { 185 125 offset += READ_BE_UINT32(dataSrc + offset + 4) + 16; 186 126 int width = READ_LE_UINT16(dataSrc + offset + 14); 187 127 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; 193 132 } 194 133 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); 198 135 199 136 _decodedData = new byte[decodedLength]; 200 memset(_decodedData, 0, decodedLength);201 202 137 byte *decodedPtr = _decodedData; 203 138 204 139 offset = 0; 205 for ( intl = 0; l < _numChars; l++) {140 for (l = 0; l < _numChars; l++) { 206 141 offset += READ_BE_UINT32(dataSrc + offset + 4) + 8; 207 142 if (READ_BE_UINT32(dataSrc + offset) != MKID_BE('FRME')) { 208 143 error("NutRenderer::loadFont(%s) there is no FRME chunk %d (offset %x)", filename, l, offset); … … 220 155 _chars[l].height = READ_LE_UINT16(dataSrc + offset + 16); 221 156 _chars[l].src = decodedPtr; 222 157 223 int pitch;158 decodedPtr += (_chars[l].width * _chars[l].height); 224 159 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; 227 167 } 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; 229 171 } 230 172 231 decodedPtr += (pitch * _chars[l].height);232 233 173 const uint8 *fobjptr = dataSrc + offset + 22; 234 174 switch (codec) { 235 175 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); 237 177 break; 238 178 case 21: 239 179 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); 241 181 break; 242 182 default: 243 183 error("NutRenderer::loadFont: unknown codec: %d", codec); 244 184 } 245 185 } 246 186 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 247 260 delete [] dataSrc; 261 delete [] _paletteMap; 248 262 } 249 263 250 264 int NutRenderer::getCharWidth(byte c) const { … … 267 281 return _chars[c].height; 268 282 } 269 283 270 void NutRenderer::drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow) { 284 byte *NutRenderer::unpackChar(byte c) { 285 if (_bpp == 8) 286 return _chars[c].src; 271 287 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; 280 290 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; 285 296 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 } 288 311 289 for (; i < 7; i++) { 290 x += offsetX[i]; 291 y += offsetY[i]; 292 color = cTable[i]; 312 val = 0; 293 313 294 if (c >= 256 && _vm->_useCJKMode)295 draw2byte(s, c, x, y, color);296 else297 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 } 298 318 299 x -= offsetX[i]; 300 y -= offsetY[i]; 319 _charBuffer[ty * _chars[c].width + tx] = _palette[val]; 320 } 321 src += pitch; 301 322 } 323 324 return _charBuffer; 302 325 } 303 326 304 327 void NutRenderer::drawFrame(byte *dst, int c, int x, int y) { 305 assert(!_bitmapFont);306 307 328 const int width = MIN((int)_chars[c].width, _vm->_screenWidth - x); 308 329 const int height = MIN((int)_chars[c].height, _vm->_screenHeight - y); 309 const byte *src = _chars[c].src;330 const byte *src = unpackChar(c); 310 331 const int srcPitch = _chars[c].width; 311 332 byte bits = 0; 312 333 … … 339 360 byte *dst = (byte *)s.pixels + y * s.pitch + x; 340 361 const int width = MIN((int)_chars[c].width, s.w - x); 341 362 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; 344 365 345 if (_bitmapFont) {346 srcPitch = (_chars[c].width + 7) / 8;347 } else {348 srcPitch = _chars[c].width;349 }350 351 366 const int minX = x < 0 ? -x : 0; 352 367 const int minY = y < 0 ? -y : 0; 353 368 … … 361 376 } 362 377 363 378 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) { 369 382 dst[tx] = color; 383 } else { 384 dst[tx] = src[tx]; 370 385 } 371 } else {372 if (src[tx] != 0) {373 dst[tx] = color;374 }375 386 } 376 387 } 377 388 src += srcPitch; -
engines/scumm/nut_renderer.h
31 31 32 32 class NutRenderer { 33 33 protected: 34 35 enum { 36 kDefaultTransparentColor = 0, 37 kSmush44TransparentColor = 2 38 }; 39 34 40 ScummEngine *_vm; 35 bool _bitmapFont;36 41 int _numChars; 42 int _maxCharSize; 43 byte *_charBuffer; 37 44 byte *_decodedData; 45 byte *_paletteMap; 46 byte _bpp; 47 byte _palette[16]; 38 48 struct { 39 49 uint16 width; 40 50 uint16 height; 41 51 byte *src; 52 byte transparency; 42 53 } _chars[256]; 43 54 44 55 void codec1(byte *dst, const byte *src, int width, int height, int pitch); 45 56 void codec21(byte *dst, const byte *src, int width, int height, int pitch); 46 57 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 50 58 void loadFont(const char *filename); 59 byte *unpackChar(byte c); 51 60 52 61 public: 53 NutRenderer(ScummEngine *vm, const char *filename , bool bitmap);62 NutRenderer(ScummEngine *vm, const char *filename); 54 63 virtual ~NutRenderer(); 55 64 int getNumChars() const { return _numChars; } 56 65 57 66 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); 59 69 60 70 int getCharWidth(byte c) const; 61 71 int getCharHeight(byte c) const;