Ticket #8598: nut-renderer2.diff
File nut-renderer2.diff, 13.7 KB (added by , 17 years ago) |
---|
-
engines/scumm/smush/smush_font.cpp
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 != kDefaultTransparentColor) 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 != kSmush44TransparentColor) { 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 != kDefaultTransparentColor) { 105 105 dst[i] = 0; 106 106 } 107 107 } -
engines/scumm/charset.cpp
1650 1650 if (chr == '@') 1651 1651 return; 1652 1652 1653 shadow.left = _left - 1;1654 shadow.top = _top - 1;1653 shadow.left = _left; 1654 shadow.top = _top; 1655 1655 1656 // Note that the character is drawn with a shadow, so it is slightly1657 // larger than the advertised dimensions. See drawShadowChar() for1658 // details.1659 1660 1656 if (_firstChar) { 1661 1657 _str.left = (shadow.left >= 0) ? shadow.left : 0; 1662 1658 _str.top = (shadow.top >= 0) ? shadow.top : 0; … … 1671 1667 if (chr >= 256 && _vm->_useCJKMode) 1672 1668 width = _vm->_2byteWidth; 1673 1669 1674 shadow.right = _left + width + 2;1675 shadow.bottom = _top + height + 2;1670 shadow.right = _left + width; 1671 shadow.bottom = _top + height; 1676 1672 1677 1673 Graphics::Surface s; 1678 1674 if (!ignoreCharsetMask) { … … 1690 1686 drawTop -= _vm->_screenTop; 1691 1687 } 1692 1688 1693 _current->drawShadowChar(s, chr, _left, drawTop, _color, _curId != 3); 1689 if (chr >= 256 && _vm->_useCJKMode) 1690 _current->draw2byte(s, chr, _left, drawTop, _color); 1691 else 1692 _current->drawChar(s, (byte)chr, _left, drawTop, _color); 1694 1693 _vm->markRectAsDirty(kMainVirtScreen, shadow); 1695 1694 1696 1695 if (_str.left > _left) -
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, bool compress) : 31 31 _vm(vm), 32 _bitmapFont(bitmap),33 32 _numChars(0), 34 33 _decodedData(0) { 35 34 memset(_chars, 0, sizeof(_chars)); 36 loadFont(filename );35 loadFont(filename, compress); 37 36 } 38 37 39 38 NutRenderer::~NutRenderer() { … … 48 47 for (h = 0; h < height; h++) { 49 48 size_line = READ_LE_UINT16(src); 50 49 src += 2; 51 byte bit = 0x80;52 50 byte *dstPtrNext = dst + pitch; 53 51 while (size_line > 0) { 54 52 code = *src++; … … 56 54 length = (code >> 1) + 1; 57 55 if (code & 1) { 58 56 val = *src++; 57 _paletteMap[val] = 1; 59 58 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 } 59 if (val) 60 memset(dst, val, length); 61 dst += length; 75 62 } else { 76 63 size_line -= length; 77 64 while (length--) { 78 65 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 } 66 _paletteMap[val] = 1; 67 if (val) 68 *dst = val; 69 dst++; 92 70 } 93 71 } 94 72 } … … 102 80 const byte *srcPtrNext = src + 2 + READ_LE_UINT16(src); 103 81 src += 2; 104 82 int len = width; 105 byte bit = 0x80;106 83 do { 107 int i;108 84 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 } 85 dst += offs; 120 86 len -= offs; 121 87 if (len <= 0) { 122 88 break; … … 130 96 // src bytes equal to 255 are replaced by 0 in dst 131 97 // src bytes equal to 1 are replaced by a color passed as an argument in the original function 132 98 // 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; 99 for (int i = 0; i < w; i++) { 100 _paletteMap[src[i]] = 1; 146 101 } 102 memcpy(dst, src, w); 103 dst += w; 147 104 src += w; 148 105 } while (len > 0); 149 106 dst = dstPtrNext; … … 151 108 } 152 109 } 153 110 154 void NutRenderer::loadFont(const char *filename ) {111 void NutRenderer::loadFont(const char *filename, bool compress) { 155 112 ScummFile file; 156 113 _vm->openFile(file, filename); 157 114 if (!file.isOpen()) { … … 181 138 182 139 uint32 offset = 0; 183 140 uint32 decodedLength = 0; 184 for (int l = 0; l < _numChars; l++) { 141 int l; 142 143 _paletteMap = new byte[256]; 144 for (l = 0; l < 256; l++) { 145 _paletteMap[l] = 0; 146 } 147 148 for (l = 0; l < _numChars; l++) { 185 149 offset += READ_BE_UINT32(dataSrc + offset + 4) + 16; 186 150 int width = READ_LE_UINT16(dataSrc + offset + 14); 187 151 int height = READ_LE_UINT16(dataSrc + offset + 16); 188 if (_bitmapFont) { 189 decodedLength += (((width + 7) / 8) * height); 190 } else { 191 decodedLength += (width * height); 192 } 152 decodedLength += (width * height); 193 153 } 194 154 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. 155 debug(1, "NutRenderer::loadFont('%s') - decodedLength = %d", filename, decodedLength); 198 156 199 157 _decodedData = new byte[decodedLength]; 200 memset(_decodedData, 0, decodedLength);201 202 158 byte *decodedPtr = _decodedData; 203 159 204 160 offset = 0; 205 for ( intl = 0; l < _numChars; l++) {161 for (l = 0; l < _numChars; l++) { 206 162 offset += READ_BE_UINT32(dataSrc + offset + 4) + 8; 207 163 if (READ_BE_UINT32(dataSrc + offset) != MKID_BE('FRME')) { 208 164 error("NutRenderer::loadFont(%s) there is no FRME chunk %d (offset %x)", filename, l, offset); … … 220 176 _chars[l].height = READ_LE_UINT16(dataSrc + offset + 16); 221 177 _chars[l].src = decodedPtr; 222 178 223 int pitch;179 decodedPtr += (_chars[l].width * _chars[l].height); 224 180 225 if (_bitmapFont) { 226 pitch = (_chars[l].width + 7) / 8; 181 // If characters have transparency, then bytes just get skipped and 182 // so there may appear some garbage. That's why we have to fill it 183 // with a default color first. 184 if (codec == 44) { 185 memset(_chars[l].src, kSmush44TransparentColor, _chars[l].width * _chars[l].height); 186 _paletteMap[kSmush44TransparentColor] = 1; 227 187 } else { 228 pitch = _chars[l].width; 188 memset(_chars[l].src, kDefaultTransparentColor, _chars[l].width * _chars[l].height); 189 _paletteMap[kDefaultTransparentColor] = 1; 229 190 } 230 191 231 decodedPtr += (pitch * _chars[l].height);232 233 192 const uint8 *fobjptr = dataSrc + offset + 22; 234 193 switch (codec) { 235 194 case 1: 236 codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);195 codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width); 237 196 break; 238 197 case 21: 239 198 case 44: 240 codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);199 codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width); 241 200 break; 242 201 default: 243 202 error("NutRenderer::loadFont: unknown codec: %d", codec); 244 203 } 245 204 } 246 205 206 if (compress) { 207 int numColors = 0; 208 for (l = 0; l < 256; l++) { 209 if (_paletteMap[l]) { 210 if (numColors < ARRAYSIZE(_palette)) { 211 _paletteMap[l] = numColors; 212 _palette[numColors] = l; 213 } 214 numColors++; 215 } 216 } 217 218 // Now _palette contains all the used colors, and _paletteMap 219 // maps the real color to the palette index. 220 221 if (numColors <= 2) 222 _bpp = 1; 223 else if (numColors <= 4) 224 _bpp = 2; 225 else if (numColors <= 16) 226 _bpp = 4; 227 else 228 _bpp = 8; 229 230 if (_bpp < 8) { 231 int compressedLength = 0; 232 for (l = 0; l < 256; l++) { 233 compressedLength += (((_bpp * _chars[l].width + 7) / 8) * _chars[l].height); 234 } 235 236 debug(1, "NutRenderer::loadFont('%s') - compressedLength = %d (%d bpp)", filename, compressedLength, _bpp); 237 238 byte *compressedData = new byte[compressedLength]; 239 memset(compressedData, 0, compressedLength); 240 241 offset = 0; 242 243 for (l = 0; l < 256; l++) { 244 byte *src = _chars[l].src; 245 byte *dst = compressedData + offset; 246 int srcPitch = _chars[l].width; 247 int dstPitch = (_bpp * _chars[l].width + 7) / 8; 248 249 for (int h = 0; h < _chars[l].height; h++) { 250 byte bit = 0x80; 251 byte *nextDst = dst + dstPitch; 252 for (int w = 0; w < srcPitch; w++) { 253 byte color = _paletteMap[src[w]]; 254 for (int i = 0; i < _bpp; i++) { 255 if (color & (1 << i)) 256 *dst |= bit; 257 bit >>= 1; 258 } 259 if (!bit) { 260 bit = 0x80; 261 dst++; 262 } 263 } 264 src += srcPitch; 265 dst = nextDst; 266 } 267 _chars[l].src = compressedData + offset; 268 offset += (dstPitch * _chars[l].height); 269 } 270 271 delete [] _decodedData; 272 _decodedData = compressedData; 273 } else 274 _bpp = 8; 275 276 } 277 247 278 delete [] dataSrc; 279 delete [] _paletteMap; 248 280 } 249 281 250 282 int NutRenderer::getCharWidth(byte c) const { … … 267 299 return _chars[c].height; 268 300 } 269 301 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 black273 // for the shadow, and once in the right color and position. This way we274 // achieve the exact look as the original CMI had.275 // However, this is not how the original engine handled it. Char glyphs276 // were compressed with codec 44. In the decoding routine, transparent277 // pixels are skipped. Other pixels are just filled with the decoded color278 // which can be equal to 0 (==shadow), 1 (==char color) or another value279 // (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 else297 drawChar(s, (byte)c, x, y, color);298 299 x -= offsetX[i];300 y -= offsetY[i];301 }302 }303 304 302 void NutRenderer::drawFrame(byte *dst, int c, int x, int y) { 305 assert(!_bitmapFont);306 307 303 const int width = MIN((int)_chars[c].width, _vm->_screenWidth - x); 308 304 const int height = MIN((int)_chars[c].height, _vm->_screenHeight - y); 309 305 const byte *src = _chars[c].src; … … 340 336 const int width = MIN((int)_chars[c].width, s.w - x); 341 337 const int height = MIN((int)_chars[c].height, s.h - y); 342 338 const byte *src = _chars[c].src; 343 int srcPitch ;339 int srcPitch = (_bpp * _chars[c].width + 7) / 8; 344 340 345 if (_bitmapFont) {346 srcPitch = (_chars[c].width + 7) / 8;347 } else {348 srcPitch = _chars[c].width;349 }350 351 341 const int minX = x < 0 ? -x : 0; 352 342 const int minY = y < 0 ? -y : 0; 353 343 … … 361 351 } 362 352 363 353 for (int ty = minY; ty < height; ty++) { 364 int tx; 354 for (int tx = minX; tx < width; tx++) { 355 byte val; 365 356 366 for (tx = minX; tx < width; tx++) { 367 if (_bitmapFont) { 368 if (src[tx / 8] & (0x80 >> (tx % 8))) { 369 dst[tx] = color; 357 if (_bpp < 8) { 358 int offset; 359 byte bit; 360 361 switch (_bpp) { 362 case 1: 363 offset = tx / 8; 364 bit = 0x80 >> (tx % 8); 365 break; 366 case 2: 367 offset = tx / 4; 368 bit = 0x80 >> (2 * (tx % 4)); 369 break; 370 default: 371 offset = tx / 2; 372 bit = 0x80 >> (4 * (tx % 2)); 373 break; 370 374 } 375 376 val = 0; 377 378 for (int i = 0; i < _bpp; i++) { 379 if (src[offset] & (bit >> i)) 380 val |= (1 << i); 381 } 382 383 val = _palette[val]; 371 384 } else { 372 if (src[tx] != 0) { 385 val = src[tx]; 386 } 387 388 if (val != kSmush44TransparentColor) { 389 if (val == 1) { 373 390 dst[tx] = color; 391 } else { 392 dst[tx] = val; 374 393 } 375 394 } 376 395 } -
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; 37 42 byte *_decodedData; 43 byte *_paletteMap; 44 byte _bpp; 45 byte _palette[16]; 38 46 struct { 39 47 uint16 width; 40 48 uint16 height; … … 44 52 void codec1(byte *dst, const byte *src, int width, int height, int pitch); 45 53 void codec21(byte *dst, const byte *src, int width, int height, int pitch); 46 54 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); 55 void loadFont(const char *filename, bool compress); 49 56 50 void loadFont(const char *filename);51 52 57 public: 53 NutRenderer(ScummEngine *vm, const char *filename, bool bitmap);58 NutRenderer(ScummEngine *vm, const char *filename, bool compress); 54 59 virtual ~NutRenderer(); 55 60 int getNumChars() const { return _numChars; } 56 61 57 62 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); 63 void drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color); 64 void draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color); 59 65 60 66 int getCharWidth(byte c) const; 61 67 int getCharHeight(byte c) const;