aboutsummaryrefslogtreecommitdiff
path: root/image
diff options
context:
space:
mode:
Diffstat (limited to 'image')
-rw-r--r--image/codecs/cinepak.cpp559
-rw-r--r--image/codecs/cinepak.h20
-rw-r--r--image/codecs/cinepak_tables.h780
-rw-r--r--image/codecs/codec.cpp148
-rw-r--r--image/codecs/codec.h29
-rw-r--r--image/codecs/qtrle.cpp164
-rw-r--r--image/codecs/qtrle.h15
-rw-r--r--image/codecs/rpza.cpp270
-rw-r--r--image/codecs/rpza.h14
9 files changed, 1823 insertions, 176 deletions
diff --git a/image/codecs/cinepak.cpp b/image/codecs/cinepak.cpp
index 8464aa3889..4e858921ee 100644
--- a/image/codecs/cinepak.cpp
+++ b/image/codecs/cinepak.cpp
@@ -21,6 +21,7 @@
*/
#include "image/codecs/cinepak.h"
+#include "image/codecs/cinepak_tables.h"
#include "common/debug.h"
#include "common/stream.h"
@@ -34,23 +35,328 @@
namespace Image {
-#define PUT_PIXEL(offset, lum, u, v) \
- if (_pixelFormat.bytesPerPixel != 1) { \
- byte r = _clipTable[lum + (v << 1)]; \
- byte g = _clipTable[lum - (u >> 1) - v]; \
- byte b = _clipTable[lum + (u << 1)]; \
- \
- if (_pixelFormat.bytesPerPixel == 2) \
- *((uint16 *)_curFrame.surface->getPixels() + offset) = _pixelFormat.RGBToColor(r, g, b); \
- else \
- *((uint32 *)_curFrame.surface->getPixels() + offset) = _pixelFormat.RGBToColor(r, g, b); \
- } else \
- *((byte *)_curFrame.surface->getPixels() + offset) = lum
-
-CinepakDecoder::CinepakDecoder(int bitsPerPixel) : Codec() {
- _curFrame.surface = NULL;
- _curFrame.strips = NULL;
+namespace {
+
+inline void convertYUVToRGB(const byte *clipTable, byte y, int8 u, int8 v, byte &r, byte &g, byte &b) {
+ r = clipTable[y + (v << 1)];
+ g = clipTable[y - (u >> 1) - v];
+ b = clipTable[y + (u << 1)];
+}
+
+inline uint32 convertYUVToColor(const byte *clipTable, const Graphics::PixelFormat &format, byte y, byte u, byte v) {
+ byte r, g, b;
+ convertYUVToRGB(clipTable, y, u, v, r, g, b);
+ return format.RGBToColor(r, g, b);
+}
+
+inline uint16 createDitherTableIndex(const byte *clipTable, byte y, int8 u, int8 v) {
+ byte r, g, b;
+ convertYUVToRGB(clipTable, y, u, v, r, g, b);
+ return ((r & 0xF8) << 6) |
+ ((g & 0xF8) << 1) |
+ ((b & 0xF0) >> 4);
+}
+
+/**
+ * Put a raw pixel to the destination surface
+ */
+template<typename PixelInt>
+inline void putPixelRaw(PixelInt *dst, const byte *clipTable, const Graphics::PixelFormat &format, byte y, byte u, byte v) {
+ *dst = convertYUVToColor(clipTable, format, y, u, v);
+}
+
+/**
+ * Specialized putPixelRaw for palettized 8bpp output
+ */
+template<>
+inline void putPixelRaw(byte *dst, const byte *clipTable, const Graphics::PixelFormat &format, byte y, byte u, byte v) {
+ *dst = y;
+}
+
+/**
+ * The default codebook converter: raw output.
+ */
+struct CodebookConverterRaw {
+ template<typename PixelInt>
+ static inline void decodeBlock1(byte codebookIndex, const CinepakStrip &strip, PixelInt *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
+ const CinepakCodebook &codebook = strip.v1_codebook[codebookIndex];
+ putPixelRaw(rows[0] + 0, clipTable, format, codebook.y[0], codebook.u, codebook.v);
+ putPixelRaw(rows[0] + 1, clipTable, format, codebook.y[0], codebook.u, codebook.v);
+ putPixelRaw(rows[1] + 0, clipTable, format, codebook.y[0], codebook.u, codebook.v);
+ putPixelRaw(rows[1] + 1, clipTable, format, codebook.y[0], codebook.u, codebook.v);
+
+ putPixelRaw(rows[0] + 2, clipTable, format, codebook.y[1], codebook.u, codebook.v);
+ putPixelRaw(rows[0] + 3, clipTable, format, codebook.y[1], codebook.u, codebook.v);
+ putPixelRaw(rows[1] + 2, clipTable, format, codebook.y[1], codebook.u, codebook.v);
+ putPixelRaw(rows[1] + 3, clipTable, format, codebook.y[1], codebook.u, codebook.v);
+
+ putPixelRaw(rows[2] + 0, clipTable, format, codebook.y[2], codebook.u, codebook.v);
+ putPixelRaw(rows[2] + 1, clipTable, format, codebook.y[2], codebook.u, codebook.v);
+ putPixelRaw(rows[3] + 0, clipTable, format, codebook.y[2], codebook.u, codebook.v);
+ putPixelRaw(rows[3] + 1, clipTable, format, codebook.y[2], codebook.u, codebook.v);
+
+ putPixelRaw(rows[2] + 2, clipTable, format, codebook.y[3], codebook.u, codebook.v);
+ putPixelRaw(rows[2] + 3, clipTable, format, codebook.y[3], codebook.u, codebook.v);
+ putPixelRaw(rows[3] + 2, clipTable, format, codebook.y[3], codebook.u, codebook.v);
+ putPixelRaw(rows[3] + 3, clipTable, format, codebook.y[3], codebook.u, codebook.v);
+ }
+
+ template<typename PixelInt>
+ static inline void decodeBlock4(const byte (&codebookIndex)[4], const CinepakStrip &strip, PixelInt *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
+ const CinepakCodebook &codebook1 = strip.v4_codebook[codebookIndex[0]];
+ putPixelRaw(rows[0] + 0, clipTable, format, codebook1.y[0], codebook1.u, codebook1.v);
+ putPixelRaw(rows[0] + 1, clipTable, format, codebook1.y[1], codebook1.u, codebook1.v);
+ putPixelRaw(rows[1] + 0, clipTable, format, codebook1.y[2], codebook1.u, codebook1.v);
+ putPixelRaw(rows[1] + 1, clipTable, format, codebook1.y[3], codebook1.u, codebook1.v);
+
+ const CinepakCodebook &codebook2 = strip.v4_codebook[codebookIndex[1]];
+ putPixelRaw(rows[0] + 2, clipTable, format, codebook2.y[0], codebook2.u, codebook2.v);
+ putPixelRaw(rows[0] + 3, clipTable, format, codebook2.y[1], codebook2.u, codebook2.v);
+ putPixelRaw(rows[1] + 2, clipTable, format, codebook2.y[2], codebook2.u, codebook2.v);
+ putPixelRaw(rows[1] + 3, clipTable, format, codebook2.y[3], codebook2.u, codebook2.v);
+
+ const CinepakCodebook &codebook3 = strip.v4_codebook[codebookIndex[2]];
+ putPixelRaw(rows[2] + 0, clipTable, format, codebook3.y[0], codebook3.u, codebook3.v);
+ putPixelRaw(rows[2] + 1, clipTable, format, codebook3.y[1], codebook3.u, codebook3.v);
+ putPixelRaw(rows[3] + 0, clipTable, format, codebook3.y[2], codebook3.u, codebook3.v);
+ putPixelRaw(rows[3] + 1, clipTable, format, codebook3.y[3], codebook3.u, codebook3.v);
+
+ const CinepakCodebook &codebook4 = strip.v4_codebook[codebookIndex[3]];
+ putPixelRaw(rows[2] + 2, clipTable, format, codebook4.y[0], codebook4.u, codebook4.v);
+ putPixelRaw(rows[2] + 3, clipTable, format, codebook4.y[1], codebook4.u, codebook4.v);
+ putPixelRaw(rows[3] + 2, clipTable, format, codebook4.y[2], codebook4.u, codebook4.v);
+ putPixelRaw(rows[3] + 3, clipTable, format, codebook4.y[3], codebook4.u, codebook4.v);
+ }
+};
+
+/**
+ * Codebook converter that dithers in VFW-style
+ */
+struct CodebookConverterDitherVFW {
+ static inline void decodeBlock1(byte codebookIndex, const CinepakStrip &strip, byte *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
+ const CinepakCodebook &codebook = strip.v1_codebook[codebookIndex];
+ byte blockBuffer[16];
+ ditherCodebookSmooth(codebook, blockBuffer, colorMap);
+ rows[0][0] = blockBuffer[0];
+ rows[0][1] = blockBuffer[1];
+ rows[0][2] = blockBuffer[2];
+ rows[0][3] = blockBuffer[3];
+ rows[1][0] = blockBuffer[4];
+ rows[1][1] = blockBuffer[5];
+ rows[1][2] = blockBuffer[6];
+ rows[1][3] = blockBuffer[7];
+ rows[2][0] = blockBuffer[8];
+ rows[2][1] = blockBuffer[9];
+ rows[2][2] = blockBuffer[10];
+ rows[2][3] = blockBuffer[11];
+ rows[3][0] = blockBuffer[12];
+ rows[3][1] = blockBuffer[13];
+ rows[3][2] = blockBuffer[14];
+ rows[3][3] = blockBuffer[15];
+ }
+
+ static inline void decodeBlock4(const byte (&codebookIndex)[4], const CinepakStrip &strip, byte *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
+ byte blockBuffer[16];
+ ditherCodebookDetail(strip.v4_codebook[codebookIndex[0]], blockBuffer, colorMap);
+ rows[0][0] = blockBuffer[0];
+ rows[0][1] = blockBuffer[1];
+ rows[1][0] = blockBuffer[4];
+ rows[1][1] = blockBuffer[5];
+
+ ditherCodebookDetail(strip.v4_codebook[codebookIndex[1]], blockBuffer, colorMap);
+ rows[0][2] = blockBuffer[2];
+ rows[0][3] = blockBuffer[3];
+ rows[1][2] = blockBuffer[6];
+ rows[1][3] = blockBuffer[7];
+
+ ditherCodebookDetail(strip.v4_codebook[codebookIndex[2]], blockBuffer, colorMap);
+ rows[2][0] = blockBuffer[8];
+ rows[2][1] = blockBuffer[9];
+ rows[3][0] = blockBuffer[12];
+ rows[3][1] = blockBuffer[13];
+
+ ditherCodebookDetail(strip.v4_codebook[codebookIndex[3]], blockBuffer, colorMap);
+ rows[2][2] = blockBuffer[10];
+ rows[2][3] = blockBuffer[11];
+ rows[3][2] = blockBuffer[14];
+ rows[3][3] = blockBuffer[15];
+ }
+
+private:
+ static inline void ditherCodebookDetail(const CinepakCodebook &codebook, byte *dst, const byte *colorMap) {
+ int uLookup = (byte)codebook.u * 2;
+ int vLookup = (byte)codebook.v * 2;
+ uint32 uv1 = s_uLookup[uLookup] | s_vLookup[vLookup];
+ uint32 uv2 = s_uLookup[uLookup + 1] | s_vLookup[vLookup + 1];
+
+ int yLookup1 = codebook.y[0] * 2;
+ int yLookup2 = codebook.y[1] * 2;
+ int yLookup3 = codebook.y[2] * 2;
+ int yLookup4 = codebook.y[3] * 2;
+
+ uint32 pixelGroup1 = uv2 | s_yLookup[yLookup1 + 1];
+ uint32 pixelGroup2 = uv2 | s_yLookup[yLookup2 + 1];
+ uint32 pixelGroup3 = uv1 | s_yLookup[yLookup3];
+ uint32 pixelGroup4 = uv1 | s_yLookup[yLookup4];
+ uint32 pixelGroup5 = uv1 | s_yLookup[yLookup1];
+ uint32 pixelGroup6 = uv1 | s_yLookup[yLookup2];
+ uint32 pixelGroup7 = uv2 | s_yLookup[yLookup3 + 1];
+ uint32 pixelGroup8 = uv2 | s_yLookup[yLookup4 + 1];
+
+ dst[0] = getRGBLookupEntry(colorMap, pixelGroup1 & 0xFFFF);
+ dst[1] = getRGBLookupEntry(colorMap, pixelGroup2 >> 16);
+ dst[2] = getRGBLookupEntry(colorMap, pixelGroup5 & 0xFFFF);
+ dst[3] = getRGBLookupEntry(colorMap, pixelGroup6 >> 16);
+ dst[4] = getRGBLookupEntry(colorMap, pixelGroup3 & 0xFFFF);
+ dst[5] = getRGBLookupEntry(colorMap, pixelGroup4 >> 16);
+ dst[6] = getRGBLookupEntry(colorMap, pixelGroup7 & 0xFFFF);
+ dst[7] = getRGBLookupEntry(colorMap, pixelGroup8 >> 16);
+ dst[8] = getRGBLookupEntry(colorMap, pixelGroup1 >> 16);
+ dst[9] = getRGBLookupEntry(colorMap, pixelGroup6 & 0xFFFF);
+ dst[10] = getRGBLookupEntry(colorMap, pixelGroup5 >> 16);
+ dst[11] = getRGBLookupEntry(colorMap, pixelGroup2 & 0xFFFF);
+ dst[12] = getRGBLookupEntry(colorMap, pixelGroup3 >> 16);
+ dst[13] = getRGBLookupEntry(colorMap, pixelGroup8 & 0xFFFF);
+ dst[14] = getRGBLookupEntry(colorMap, pixelGroup7 >> 16);
+ dst[15] = getRGBLookupEntry(colorMap, pixelGroup4 & 0xFFFF);
+ }
+
+ static inline void ditherCodebookSmooth(const CinepakCodebook &codebook, byte *dst, const byte *colorMap) {
+ int uLookup = (byte)codebook.u * 2;
+ int vLookup = (byte)codebook.v * 2;
+ uint32 uv1 = s_uLookup[uLookup] | s_vLookup[vLookup];
+ uint32 uv2 = s_uLookup[uLookup + 1] | s_vLookup[vLookup + 1];
+
+ int yLookup1 = codebook.y[0] * 2;
+ int yLookup2 = codebook.y[1] * 2;
+ int yLookup3 = codebook.y[2] * 2;
+ int yLookup4 = codebook.y[3] * 2;
+
+ uint32 pixelGroup1 = uv2 | s_yLookup[yLookup1 + 1];
+ uint32 pixelGroup2 = uv1 | s_yLookup[yLookup2];
+ uint32 pixelGroup3 = uv1 | s_yLookup[yLookup1];
+ uint32 pixelGroup4 = uv2 | s_yLookup[yLookup2 + 1];
+ uint32 pixelGroup5 = uv2 | s_yLookup[yLookup3 + 1];
+ uint32 pixelGroup6 = uv1 | s_yLookup[yLookup3];
+ uint32 pixelGroup7 = uv1 | s_yLookup[yLookup4];
+ uint32 pixelGroup8 = uv2 | s_yLookup[yLookup4 + 1];
+
+ dst[0] = getRGBLookupEntry(colorMap, pixelGroup1 & 0xFFFF);
+ dst[1] = getRGBLookupEntry(colorMap, pixelGroup1 >> 16);
+ dst[2] = getRGBLookupEntry(colorMap, pixelGroup2 & 0xFFFF);
+ dst[3] = getRGBLookupEntry(colorMap, pixelGroup2 >> 16);
+ dst[4] = getRGBLookupEntry(colorMap, pixelGroup3 & 0xFFFF);
+ dst[5] = getRGBLookupEntry(colorMap, pixelGroup3 >> 16);
+ dst[6] = getRGBLookupEntry(colorMap, pixelGroup4 & 0xFFFF);
+ dst[7] = getRGBLookupEntry(colorMap, pixelGroup4 >> 16);
+ dst[8] = getRGBLookupEntry(colorMap, pixelGroup5 >> 16);
+ dst[9] = getRGBLookupEntry(colorMap, pixelGroup6 & 0xFFFF);
+ dst[10] = getRGBLookupEntry(colorMap, pixelGroup7 >> 16);
+ dst[11] = getRGBLookupEntry(colorMap, pixelGroup8 & 0xFFFF);
+ dst[12] = getRGBLookupEntry(colorMap, pixelGroup6 >> 16);
+ dst[13] = getRGBLookupEntry(colorMap, pixelGroup5 & 0xFFFF);
+ dst[14] = getRGBLookupEntry(colorMap, pixelGroup8 >> 16);
+ dst[15] = getRGBLookupEntry(colorMap, pixelGroup7 & 0xFFFF);
+ }
+
+ static inline byte getRGBLookupEntry(const byte *colorMap, uint16 index) {
+ return colorMap[s_defaultPaletteLookup[CLIP<int>(index, 0, 1024)]];
+ }
+};
+
+/**
+ * Codebook converter that dithers in QT-style
+ */
+struct CodebookConverterDitherQT {
+ static inline void decodeBlock1(byte codebookIndex, const CinepakStrip &strip, byte *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
+ const byte *colorPtr = strip.v1_dither + (codebookIndex << 2);
+ WRITE_UINT32(rows[0], READ_UINT32(colorPtr));
+ WRITE_UINT32(rows[1], READ_UINT32(colorPtr + 1024));
+ WRITE_UINT32(rows[2], READ_UINT32(colorPtr + 2048));
+ WRITE_UINT32(rows[3], READ_UINT32(colorPtr + 3072));
+ }
+
+ static inline void decodeBlock4(const byte (&codebookIndex)[4], const CinepakStrip &strip, byte *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
+ const byte *colorPtr = strip.v4_dither + (codebookIndex[0] << 2);
+ WRITE_UINT16(rows[0] + 0, READ_UINT16(colorPtr + 0));
+ WRITE_UINT16(rows[1] + 0, READ_UINT16(colorPtr + 2));
+
+ colorPtr = strip.v4_dither + (codebookIndex[1] << 2);
+ WRITE_UINT16(rows[0] + 2, READ_UINT16(colorPtr + 1024));
+ WRITE_UINT16(rows[1] + 2, READ_UINT16(colorPtr + 1026));
+
+ colorPtr = strip.v4_dither + (codebookIndex[2] << 2);
+ WRITE_UINT16(rows[2] + 0, READ_UINT16(colorPtr + 2048));
+ WRITE_UINT16(rows[3] + 0, READ_UINT16(colorPtr + 2050));
+
+ colorPtr = strip.v4_dither + (codebookIndex[3] << 2);
+ WRITE_UINT16(rows[2] + 2, READ_UINT16(colorPtr + 3072));
+ WRITE_UINT16(rows[3] + 2, READ_UINT16(colorPtr + 3074));
+ }
+};
+
+template<typename PixelInt, typename CodebookConverter>
+void decodeVectorsTmpl(CinepakFrame &frame, const byte *clipTable, const byte *colorMap, Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize) {
+ uint32 flag = 0, mask = 0;
+ PixelInt *iy[4];
+ int32 startPos = stream.pos();
+
+ for (uint16 y = frame.strips[strip].rect.top; y < frame.strips[strip].rect.bottom; y += 4) {
+ iy[0] = (PixelInt *)frame.surface->getBasePtr(frame.strips[strip].rect.left, + y);
+ iy[1] = iy[0] + frame.width;
+ iy[2] = iy[1] + frame.width;
+ iy[3] = iy[2] + frame.width;
+
+ for (uint16 x = frame.strips[strip].rect.left; x < frame.strips[strip].rect.right; x += 4) {
+ if ((chunkID & 0x01) && !(mask >>= 1)) {
+ if ((stream.pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ flag = stream.readUint32BE();
+ mask = 0x80000000;
+ }
+
+ if (!(chunkID & 0x01) || (flag & mask)) {
+ if (!(chunkID & 0x02) && !(mask >>= 1)) {
+ if ((stream.pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ flag = stream.readUint32BE();
+ mask = 0x80000000;
+ }
+
+ if ((chunkID & 0x02) || (~flag & mask)) {
+ if ((stream.pos() - startPos + 1) > (int32)chunkSize)
+ return;
+
+ // Get the codebook
+ byte codebook = stream.readByte();
+ CodebookConverter::decodeBlock1(codebook, frame.strips[strip], iy, clipTable, colorMap, frame.surface->format);
+ } else if (flag & mask) {
+ if ((stream.pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ byte codebook[4];
+ stream.read(codebook, 4);
+ CodebookConverter::decodeBlock4(codebook, frame.strips[strip], iy, clipTable, colorMap, frame.surface->format);
+ }
+ }
+
+ for (byte i = 0; i < 4; i++)
+ iy[i] += 4;
+ }
+ }
+}
+
+} // End of anonymous namespace
+
+CinepakDecoder::CinepakDecoder(int bitsPerPixel) : Codec(), _bitsPerPixel(bitsPerPixel) {
+ _curFrame.surface = 0;
+ _curFrame.strips = 0;
_y = 0;
+ _colorMap = 0;
+ _ditherPalette = 0;
+ _ditherType = kDitherTypeUnknown;
if (bitsPerPixel == 8) {
_pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
@@ -86,6 +392,9 @@ CinepakDecoder::~CinepakDecoder() {
delete[] _curFrame.strips;
delete[] _clipTableBuf;
+
+ delete[] _colorMap;
+ delete[] _ditherPalette;
}
const Graphics::Surface *CinepakDecoder::decodeFrame(Common::SeekableReadStream &stream) {
@@ -96,7 +405,7 @@ const Graphics::Surface *CinepakDecoder::decodeFrame(Common::SeekableReadStream
_curFrame.height = stream.readUint16BE();
_curFrame.stripCount = stream.readUint16BE();
- if (_curFrame.strips == NULL)
+ if (!_curFrame.strips)
_curFrame.strips = new CinepakStrip[_curFrame.stripCount];
debug(4, "Cinepak Frame: Width = %d, Height = %d, Strip Count = %d", _curFrame.width, _curFrame.height, _curFrame.stripCount);
@@ -120,10 +429,15 @@ const Graphics::Surface *CinepakDecoder::decodeFrame(Common::SeekableReadStream
for (uint16 i = 0; i < _curFrame.stripCount; i++) {
if (i > 0 && !(_curFrame.flags & 1)) { // Use codebooks from last strip
+
for (uint16 j = 0; j < 256; j++) {
_curFrame.strips[i].v1_codebook[j] = _curFrame.strips[i - 1].v1_codebook[j];
_curFrame.strips[i].v4_codebook[j] = _curFrame.strips[i - 1].v4_codebook[j];
}
+
+ // Copy the QuickTime dither tables
+ memcpy(_curFrame.strips[i].v1_dither, _curFrame.strips[i - 1].v1_dither, 256 * 4 * 4 * 4);
+ memcpy(_curFrame.strips[i].v4_dither, _curFrame.strips[i - 1].v4_dither, 256 * 4 * 4 * 4);
}
_curFrame.strips[i].id = stream.readUint16BE();
@@ -166,7 +480,10 @@ const Graphics::Surface *CinepakDecoder::decodeFrame(Common::SeekableReadStream
case 0x30:
case 0x31:
case 0x32:
- decodeVectors(stream, i, chunkID, chunkSize);
+ if (_ditherPalette)
+ ditherVectors(stream, i, chunkID, chunkSize);
+ else
+ decodeVectors(stream, i, chunkID, chunkSize);
break;
default:
warning("Unknown Cinepak chunk ID %02x", chunkID);
@@ -203,8 +520,7 @@ void CinepakDecoder::loadCodebook(Common::SeekableReadStream &stream, uint16 str
if ((stream.pos() - startPos + n) > (int32)chunkSize)
break;
- for (byte j = 0; j < 4; j++)
- codebook[i].y[j] = stream.readByte();
+ stream.read(codebook[i].y, 4);
if (n == 6) {
codebook[i].u = stream.readSByte();
@@ -216,99 +532,150 @@ void CinepakDecoder::loadCodebook(Common::SeekableReadStream &stream, uint16 str
codebook[i].u = 0;
codebook[i].v = 0;
}
+
+ // Dither the codebook if we're dithering for QuickTime
+ if (_ditherType == kDitherTypeQT)
+ ditherCodebookQT(strip, codebookType, i);
}
}
}
+void CinepakDecoder::ditherCodebookQT(uint16 strip, byte codebookType, uint16 codebookIndex) {
+ if (codebookType == 1) {
+ const CinepakCodebook &codebook = _curFrame.strips[strip].v1_codebook[codebookIndex];
+ byte *output = _curFrame.strips[strip].v1_dither + (codebookIndex << 2);
+
+ byte *ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[0], codebook.u, codebook.v);
+ output[0x000] = ditherEntry[0x0000];
+ output[0x001] = ditherEntry[0x4000];
+ output[0x400] = ditherEntry[0xC000];
+ output[0x401] = ditherEntry[0x0000];
+
+ ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[1], codebook.u, codebook.v);
+ output[0x002] = ditherEntry[0x8000];
+ output[0x003] = ditherEntry[0xC000];
+ output[0x402] = ditherEntry[0x4000];
+ output[0x403] = ditherEntry[0x8000];
+
+ ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[2], codebook.u, codebook.v);
+ output[0x800] = ditherEntry[0x4000];
+ output[0x801] = ditherEntry[0x8000];
+ output[0xC00] = ditherEntry[0x8000];
+ output[0xC01] = ditherEntry[0xC000];
+
+ ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[3], codebook.u, codebook.v);
+ output[0x802] = ditherEntry[0xC000];
+ output[0x803] = ditherEntry[0x0000];
+ output[0xC02] = ditherEntry[0x0000];
+ output[0xC03] = ditherEntry[0x4000];
+ } else {
+ const CinepakCodebook &codebook = _curFrame.strips[strip].v4_codebook[codebookIndex];
+ byte *output = _curFrame.strips[strip].v4_dither + (codebookIndex << 2);
+
+ byte *ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[0], codebook.u, codebook.v);
+ output[0x000] = ditherEntry[0x0000];
+ output[0x400] = ditherEntry[0x8000];
+ output[0x800] = ditherEntry[0x4000];
+ output[0xC00] = ditherEntry[0xC000];
+
+ ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[1], codebook.u, codebook.v);
+ output[0x001] = ditherEntry[0x4000];
+ output[0x401] = ditherEntry[0xC000];
+ output[0x801] = ditherEntry[0x8000];
+ output[0xC01] = ditherEntry[0x0000];
+
+ ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[2], codebook.u, codebook.v);
+ output[0x002] = ditherEntry[0xC000];
+ output[0x402] = ditherEntry[0x4000];
+ output[0x802] = ditherEntry[0x8000];
+ output[0xC02] = ditherEntry[0x0000];
+
+ ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[3], codebook.u, codebook.v);
+ output[0x003] = ditherEntry[0x0000];
+ output[0x403] = ditherEntry[0x8000];
+ output[0x803] = ditherEntry[0xC000];
+ output[0xC03] = ditherEntry[0x4000];
+ }
+}
+
void CinepakDecoder::decodeVectors(Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize) {
- uint32 flag = 0, mask = 0;
- uint32 iy[4];
- int32 startPos = stream.pos();
+ if (_curFrame.surface->format.bytesPerPixel == 1) {
+ decodeVectorsTmpl<byte, CodebookConverterRaw>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
+ } else if (_curFrame.surface->format.bytesPerPixel == 2) {
+ decodeVectorsTmpl<uint16, CodebookConverterRaw>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
+ } else if (_curFrame.surface->format.bytesPerPixel == 4) {
+ decodeVectorsTmpl<uint32, CodebookConverterRaw>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
+ }
+}
- for (uint16 y = _curFrame.strips[strip].rect.top; y < _curFrame.strips[strip].rect.bottom; y += 4) {
- iy[0] = _curFrame.strips[strip].rect.left + y * _curFrame.width;
- iy[1] = iy[0] + _curFrame.width;
- iy[2] = iy[1] + _curFrame.width;
- iy[3] = iy[2] + _curFrame.width;
+bool CinepakDecoder::canDither(DitherType type) const {
+ return (type == kDitherTypeVFW || type == kDitherTypeQT) && _bitsPerPixel == 24;
+}
- for (uint16 x = _curFrame.strips[strip].rect.left; x < _curFrame.strips[strip].rect.right; x += 4) {
- if ((chunkID & 0x01) && !(mask >>= 1)) {
- if ((stream.pos() - startPos + 4) > (int32)chunkSize)
- return;
+void CinepakDecoder::setDither(DitherType type, const byte *palette) {
+ assert(canDither(type));
- flag = stream.readUint32BE();
- mask = 0x80000000;
- }
+ delete[] _colorMap;
+ delete[] _ditherPalette;
- if (!(chunkID & 0x01) || (flag & mask)) {
- if (!(chunkID & 0x02) && !(mask >>= 1)) {
- if ((stream.pos() - startPos + 4) > (int32)chunkSize)
- return;
+ _ditherPalette = new byte[256 * 3];
+ memcpy(_ditherPalette, palette, 256 * 3);
- flag = stream.readUint32BE();
- mask = 0x80000000;
- }
+ _dirtyPalette = true;
+ _pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
+ _ditherType = type;
- if ((chunkID & 0x02) || (~flag & mask)) {
- if ((stream.pos() - startPos + 1) > (int32)chunkSize)
- return;
+ if (type == kDitherTypeVFW) {
+ _colorMap = new byte[221];
- // Get the codebook
- CinepakCodebook codebook = _curFrame.strips[strip].v1_codebook[stream.readByte()];
-
- PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 1, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 1, codebook.y[0], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[0] + 2, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 2, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 3, codebook.y[1], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[2] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 1, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 1, codebook.y[2], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[2] + 2, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 3, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 2, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
- } else if (flag & mask) {
- if ((stream.pos() - startPos + 4) > (int32)chunkSize)
- return;
+ for (int i = 0; i < 221; i++)
+ _colorMap[i] = findNearestRGB(i);
+ } else {
+ // Generate QuickTime dither table
+ // 4 blocks of 0x4000 bytes (RGB554 lookup)
+ _colorMap = createQuickTimeDitherTable(palette, 256);
+ }
+}
+
+byte CinepakDecoder::findNearestRGB(int index) const {
+ int r = s_defaultPalette[index * 3];
+ int g = s_defaultPalette[index * 3 + 1];
+ int b = s_defaultPalette[index * 3 + 2];
+
+ byte result = 0;
+ int diff = 0x7FFFFFFF;
+
+ for (int i = 0; i < 256; i++) {
+ int bDiff = b - (int)_ditherPalette[i * 3 + 2];
+ int curDiffB = diff - (bDiff * bDiff);
+
+ if (curDiffB > 0) {
+ int gDiff = g - (int)_ditherPalette[i * 3 + 1];
+ int curDiffG = curDiffB - (gDiff * gDiff);
+
+ if (curDiffG > 0) {
+ int rDiff = r - (int)_ditherPalette[i * 3];
+ int curDiffR = curDiffG - (rDiff * rDiff);
- CinepakCodebook codebook = _curFrame.strips[strip].v4_codebook[stream.readByte()];
- PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 1, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 1, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream.readByte()];
- PUT_PIXEL(iy[0] + 2, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 2, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 3, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream.readByte()];
- PUT_PIXEL(iy[2] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 1, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 1, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream.readByte()];
- PUT_PIXEL(iy[2] + 2, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 2, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
+ if (curDiffR > 0) {
+ diff -= curDiffR;
+ result = i;
+
+ if (diff == 0)
+ break;
}
}
-
- for (byte i = 0; i < 4; i++)
- iy[i] += 4;
}
}
+
+ return result;
+}
+
+void CinepakDecoder::ditherVectors(Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize) {
+ if (_ditherType == kDitherTypeVFW)
+ decodeVectorsTmpl<byte, CodebookConverterDitherVFW>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
+ else
+ decodeVectorsTmpl<byte, CodebookConverterDitherQT>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
}
} // End of namespace Image
diff --git a/image/codecs/cinepak.h b/image/codecs/cinepak.h
index e9cd437730..4efb1191cc 100644
--- a/image/codecs/cinepak.h
+++ b/image/codecs/cinepak.h
@@ -46,6 +46,7 @@ struct CinepakStrip {
uint16 length;
Common::Rect rect;
CinepakCodebook v1_codebook[256], v4_codebook[256];
+ byte v1_dither[256 * 4 * 4 * 4], v4_dither[256 * 4 * 4 * 4];
};
struct CinepakFrame {
@@ -63,6 +64,9 @@ struct CinepakFrame {
* Cinepak decoder.
*
* Used by BMP/AVI and PICT/QuickTime.
+ *
+ * Used in engines:
+ * - sherlock
*/
class CinepakDecoder : public Codec {
public:
@@ -72,14 +76,30 @@ public:
const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
+ bool containsPalette() const { return _ditherPalette != 0; }
+ const byte *getPalette() { _dirtyPalette = false; return _ditherPalette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+ bool canDither(DitherType type) const;
+ void setDither(DitherType type, const byte *palette);
+
private:
CinepakFrame _curFrame;
int32 _y;
+ int _bitsPerPixel;
Graphics::PixelFormat _pixelFormat;
byte *_clipTable, *_clipTableBuf;
+ byte *_ditherPalette;
+ bool _dirtyPalette;
+ byte *_colorMap;
+ DitherType _ditherType;
+
void loadCodebook(Common::SeekableReadStream &stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize);
void decodeVectors(Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize);
+
+ byte findNearestRGB(int index) const;
+ void ditherVectors(Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize);
+ void ditherCodebookQT(uint16 strip, byte codebookType, uint16 codebookIndex);
};
} // End of namespace Image
diff --git a/image/codecs/cinepak_tables.h b/image/codecs/cinepak_tables.h
new file mode 100644
index 0000000000..03131cec22
--- /dev/null
+++ b/image/codecs/cinepak_tables.h
@@ -0,0 +1,780 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef IMAGE_CODECS_CINEPAK_TABLES_H
+#define IMAGE_CODECS_CINEPAK_TABLES_H
+
+#include "common/scummsys.h"
+
+namespace Image {
+
+static const byte s_defaultPaletteLookup[1024] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
+ 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x07,
+ 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x07,
+ 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x07,
+ 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x09, 0x0A, 0x07, 0x07, 0x07,
+ 0x0B, 0x0B, 0x0B, 0x0C, 0x0D, 0x0D, 0x0D, 0x07,
+ 0x0E, 0x0E, 0x0E, 0x0F, 0x0D, 0x0D, 0x0D, 0x0D,
+ 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x0D, 0x0D,
+ 0x12, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16,
+ 0x12, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16,
+ 0x12, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16,
+ 0x12, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16,
+ 0x17, 0x17, 0x17, 0x18, 0x19, 0x1A, 0x16, 0x16,
+ 0x1B, 0x1B, 0x1B, 0x1C, 0x1D, 0x1E, 0x1E, 0x1E,
+ 0x1F, 0x1F, 0x1F, 0x20, 0x21, 0x1E, 0x1E, 0x1E,
+ 0x22, 0x22, 0x22, 0x23, 0x24, 0x24, 0x24, 0x1E,
+ 0x25, 0x25, 0x25, 0x26, 0x27, 0x28, 0x29, 0x29,
+ 0x25, 0x25, 0x25, 0x26, 0x27, 0x28, 0x29, 0x29,
+ 0x25, 0x25, 0x25, 0x26, 0x27, 0x28, 0x29, 0x29,
+ 0x25, 0x25, 0x25, 0x26, 0x27, 0x28, 0x29, 0x29,
+ 0x2A, 0x2A, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2E,
+ 0x2F, 0x2F, 0x2F, 0x30, 0x31, 0x32, 0x2E, 0x2E,
+ 0x33, 0x33, 0x33, 0x34, 0x35, 0x36, 0x36, 0x36,
+ 0x33, 0x33, 0x33, 0x34, 0x35, 0x36, 0x36, 0x36,
+ 0x37, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B,
+ 0x37, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B,
+ 0x37, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B,
+ 0x3C, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x40, 0x40,
+ 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x45, 0x45,
+ 0x46, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4A, 0x4A,
+ 0x4B, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x4F, 0x4F,
+ 0x4B, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x4F, 0x4F,
+ 0x50, 0x50, 0x51, 0x52, 0x53, 0x54, 0x54, 0x54,
+ 0x50, 0x50, 0x51, 0x52, 0x53, 0x54, 0x54, 0x54,
+ 0x50, 0x50, 0x51, 0x52, 0x53, 0x54, 0x54, 0x54,
+ 0x55, 0x55, 0x56, 0x57, 0x58, 0x59, 0x59, 0x59,
+ 0x5A, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5E, 0x5E,
+ 0x5F, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x63, 0x63,
+ 0x64, 0x64, 0x65, 0x66, 0x67, 0x68, 0x68, 0x68,
+ 0x64, 0x64, 0x65, 0x66, 0x67, 0x68, 0x68, 0x68,
+ 0x69, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6D, 0x6D,
+ 0x69, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6D, 0x6D,
+ 0x69, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6D, 0x6D,
+ 0x6E, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x72, 0x72,
+ 0x73, 0x73, 0x74, 0x75, 0x76, 0x77, 0x77, 0x77,
+ 0x78, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7C, 0x7C,
+ 0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x81, 0x81,
+ 0x7D, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x81, 0x81,
+ 0x82, 0x82, 0x83, 0x84, 0x85, 0x86, 0x86, 0x86,
+ 0x82, 0x82, 0x83, 0x84, 0x85, 0x86, 0x86, 0x86,
+ 0x87, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8B, 0x8B,
+ 0x8C, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x90, 0x90,
+ 0x91, 0x91, 0x92, 0x93, 0x94, 0x95, 0x95, 0x95,
+ 0x96, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9A, 0x9A,
+ 0x96, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9A, 0x9A,
+ 0x96, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9A, 0x9A,
+ 0x9B, 0x9B, 0x9B, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9E, 0x9B, 0x9B, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9E, 0x9E, 0x9F, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA6, 0xA6, 0xA7, 0xA8, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAE, 0xAE, 0xAE, 0xAF, 0xB0, 0xB0, 0xB0, 0xB0,
+ 0xAE, 0xAE, 0xAE, 0xAF, 0xB0, 0xB0, 0xB0, 0xB0,
+ 0xB4, 0xB1, 0xB1, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB4, 0xB4, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7,
+ 0xB8, 0xB8, 0xB9, 0xBA, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBC, 0xBC, 0xBD, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBC, 0xBC, 0xBD, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBC, 0xBC, 0xBD, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xC2, 0xC0, 0xC0, 0xC0, 0xC1, 0xC1, 0xC1, 0xC1,
+ 0xC2, 0xC2, 0xC0, 0xC0, 0xC1, 0xC1, 0xC1, 0xC1,
+ 0xC2, 0xC2, 0xC2, 0xC3, 0xC4, 0xC4, 0xC4, 0xC4,
+ 0xC8, 0xC5, 0xC5, 0xC6, 0xC7, 0xC7, 0xC7, 0xC7,
+ 0xC8, 0xC8, 0xC9, 0xCA, 0xCB, 0xCB, 0xCB, 0xCB,
+ 0xCC, 0xCC, 0xCD, 0xCE, 0xCF, 0xCF, 0xCF, 0xCF,
+ 0xCC, 0xCC, 0xCD, 0xCE, 0xCF, 0xCF, 0xCF, 0xCF,
+ 0xCC, 0xCC, 0xCD, 0xCE, 0xCF, 0xCF, 0xCF, 0xCF,
+ 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0,
+ 0xD2, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0,
+ 0xD2, 0xD2, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1,
+ 0xD2, 0xD2, 0xD2, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3,
+ 0xD4, 0xD4, 0xD4, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5,
+ 0xD4, 0xD4, 0xD4, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5,
+ 0xD4, 0xD4, 0xD4, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5,
+ 0xD4, 0xD4, 0xD4, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5,
+ 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6,
+ 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6,
+ 0xD8, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6,
+ 0xD8, 0xD8, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7,
+ 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
+ 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
+ 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
+ 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
+ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
+ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
+ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
+ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC
+};
+
+static const byte s_defaultPalette[221 * 3] = {
+ 0x02, 0x02, 0x02,
+ 0x19, 0x19, 0x19,
+ 0x47, 0x02, 0x19,
+ 0x19, 0x0D, 0x47,
+ 0x00, 0x51, 0x00,
+ 0x2E, 0x3A, 0x00,
+ 0x5C, 0x23, 0x00,
+ 0x8F, 0x0A, 0x00,
+ 0x00, 0x45, 0x2E,
+ 0x2E, 0x2E, 0x2E,
+ 0x5C, 0x17, 0x2E,
+ 0x00, 0x3A, 0x5C,
+ 0x2E, 0x23, 0x5C,
+ 0x5C, 0x0C, 0x5C,
+ 0x00, 0x2C, 0x95,
+ 0x2E, 0x15, 0x95,
+ 0x00, 0x1A, 0xDC,
+ 0x2E, 0x03, 0xDC,
+ 0x15, 0x66, 0x15,
+ 0x43, 0x4F, 0x15,
+ 0x71, 0x38, 0x15,
+ 0xA4, 0x1E, 0x15,
+ 0xDB, 0x02, 0x15,
+ 0x15, 0x5A, 0x43,
+ 0x43, 0x43, 0x43,
+ 0x71, 0x2C, 0x43,
+ 0xA4, 0x13, 0x43,
+ 0x15, 0x4F, 0x71,
+ 0x43, 0x38, 0x71,
+ 0x71, 0x21, 0x71,
+ 0xA4, 0x07, 0x71,
+ 0x15, 0x40, 0xAA,
+ 0x43, 0x29, 0xAA,
+ 0x71, 0x12, 0xAA,
+ 0x15, 0x2F, 0xF1,
+ 0x43, 0x18, 0xF1,
+ 0x71, 0x01, 0xF1,
+ 0x29, 0x79, 0x29,
+ 0x57, 0x62, 0x29,
+ 0x85, 0x4B, 0x29,
+ 0xB7, 0x32, 0x29,
+ 0xEF, 0x16, 0x29,
+ 0x29, 0x6E, 0x57,
+ 0x57, 0x57, 0x57,
+ 0x85, 0x40, 0x57,
+ 0xB7, 0x27, 0x57,
+ 0xEF, 0x0B, 0x57,
+ 0x29, 0x62, 0x85,
+ 0x57, 0x4B, 0x85,
+ 0x85, 0x34, 0x85,
+ 0xB7, 0x1B, 0x85,
+ 0x29, 0x54, 0xBE,
+ 0x57, 0x3D, 0xBE,
+ 0x85, 0x26, 0xBE,
+ 0xB7, 0x0D, 0xBE,
+ 0x03, 0xB5, 0x09,
+ 0x3C, 0x99, 0x09,
+ 0x6A, 0x82, 0x09,
+ 0x98, 0x6B, 0x09,
+ 0xCA, 0x51, 0x09,
+ 0x03, 0xA9, 0x3C,
+ 0x3C, 0x8C, 0x3C,
+ 0x6A, 0x75, 0x3C,
+ 0x98, 0x5E, 0x3C,
+ 0xCA, 0x45, 0x3C,
+ 0x03, 0x9D, 0x6A,
+ 0x3C, 0x81, 0x6A,
+ 0x6A, 0x6A, 0x6A,
+ 0x98, 0x53, 0x6A,
+ 0xCA, 0x39, 0x6A,
+ 0x03, 0x92, 0x98,
+ 0x3C, 0x75, 0x98,
+ 0x6A, 0x5E, 0x98,
+ 0x98, 0x47, 0x98,
+ 0xCA, 0x2E, 0x98,
+ 0x03, 0x83, 0xD1,
+ 0x3C, 0x67, 0xD1,
+ 0x6A, 0x50, 0xD1,
+ 0x98, 0x39, 0xD1,
+ 0xCA, 0x20, 0xD1,
+ 0x14, 0xC7, 0x1B,
+ 0x4D, 0xAB, 0x1B,
+ 0x7B, 0x94, 0x1B,
+ 0xA9, 0x7D, 0x1B,
+ 0xDC, 0x63, 0x1B,
+ 0x14, 0xBA, 0x4D,
+ 0x4D, 0x9E, 0x4D,
+ 0x7B, 0x87, 0x4D,
+ 0xA9, 0x70, 0x4D,
+ 0xDC, 0x57, 0x4D,
+ 0x14, 0xAF, 0x7B,
+ 0x4D, 0x92, 0x7B,
+ 0x7B, 0x7B, 0x7B,
+ 0xA9, 0x64, 0x7B,
+ 0xDC, 0x4B, 0x7B,
+ 0x14, 0xA3, 0xA9,
+ 0x4D, 0x87, 0xA9,
+ 0x7B, 0x70, 0xA9,
+ 0xA9, 0x59, 0xA9,
+ 0xDC, 0x40, 0xA9,
+ 0x14, 0x95, 0xE2,
+ 0x4D, 0x79, 0xE2,
+ 0x7B, 0x62, 0xE2,
+ 0xA9, 0x4B, 0xE2,
+ 0xDC, 0x31, 0xE2,
+ 0x25, 0xD8, 0x2C,
+ 0x5E, 0xBB, 0x2C,
+ 0x8C, 0xA4, 0x2C,
+ 0xBA, 0x8D, 0x2C,
+ 0xED, 0x74, 0x2C,
+ 0x25, 0xCB, 0x5E,
+ 0x5E, 0xAF, 0x5E,
+ 0x8C, 0x98, 0x5E,
+ 0xBA, 0x81, 0x5E,
+ 0xED, 0x67, 0x5E,
+ 0x25, 0xC0, 0x8C,
+ 0x5E, 0xA3, 0x8C,
+ 0x8C, 0x8C, 0x8C,
+ 0xBA, 0x75, 0x8C,
+ 0xED, 0x5C, 0x8C,
+ 0x25, 0xB4, 0xBA,
+ 0x5E, 0x98, 0xBA,
+ 0x8C, 0x81, 0xBA,
+ 0xBA, 0x6A, 0xBA,
+ 0xED, 0x50, 0xBA,
+ 0x25, 0xA6, 0xF3,
+ 0x5E, 0x8A, 0xF3,
+ 0x8C, 0x73, 0xF3,
+ 0xBA, 0x5C, 0xF3,
+ 0xED, 0x42, 0xF3,
+ 0x35, 0xF6, 0x04,
+ 0x6E, 0xD9, 0x04,
+ 0x9C, 0xC2, 0x04,
+ 0xCA, 0xAB, 0x04,
+ 0xFD, 0x92, 0x04,
+ 0x35, 0xE8, 0x3C,
+ 0x6E, 0xCB, 0x3C,
+ 0x9C, 0xB4, 0x3C,
+ 0xCA, 0x9D, 0x3C,
+ 0xFD, 0x84, 0x3C,
+ 0x35, 0xDB, 0x6E,
+ 0x6E, 0xBF, 0x6E,
+ 0x9C, 0xA8, 0x6E,
+ 0xCA, 0x91, 0x6E,
+ 0xFD, 0x78, 0x6E,
+ 0x35, 0xD0, 0x9C,
+ 0x6E, 0xB3, 0x9C,
+ 0x9C, 0x9C, 0x9C,
+ 0xCA, 0x85, 0x9C,
+ 0xFD, 0x6C, 0x9C,
+ 0x35, 0xC4, 0xCA,
+ 0x6E, 0xA8, 0xCA,
+ 0x9C, 0x91, 0xCA,
+ 0xCA, 0x7A, 0xCA,
+ 0xFD, 0x61, 0xCA,
+ 0x7E, 0xE9, 0x13,
+ 0xAC, 0xD2, 0x13,
+ 0xDA, 0xBB, 0x13,
+ 0x45, 0xF7, 0x4B,
+ 0x7E, 0xDB, 0x4B,
+ 0xAC, 0xC4, 0x4B,
+ 0xDA, 0xAD, 0x4B,
+ 0x45, 0xEB, 0x7E,
+ 0x7E, 0xCE, 0x7E,
+ 0xAC, 0xB7, 0x7E,
+ 0xDA, 0xA0, 0x7E,
+ 0x45, 0xDF, 0xAC,
+ 0x7E, 0xC3, 0xAC,
+ 0xAC, 0xAC, 0xAC,
+ 0xDA, 0x95, 0xAC,
+ 0x45, 0xD4, 0xDA,
+ 0x7E, 0xB7, 0xDA,
+ 0xAC, 0xA0, 0xDA,
+ 0xDA, 0x89, 0xDA,
+ 0x8C, 0xF7, 0x22,
+ 0xBA, 0xE0, 0x22,
+ 0xE8, 0xC9, 0x22,
+ 0x8C, 0xE9, 0x59,
+ 0xBA, 0xD2, 0x59,
+ 0xE8, 0xBB, 0x59,
+ 0x53, 0xF9, 0x8C,
+ 0x8C, 0xDD, 0x8C,
+ 0xBA, 0xC6, 0x8C,
+ 0xE8, 0xAF, 0x8C,
+ 0x53, 0xEE, 0xBA,
+ 0x8C, 0xD1, 0xBA,
+ 0xBA, 0xBA, 0xBA,
+ 0xE8, 0xA3, 0xBA,
+ 0x53, 0xE2, 0xE8,
+ 0x8C, 0xC6, 0xE8,
+ 0xBA, 0xAF, 0xE8,
+ 0xE8, 0x98, 0xE8,
+ 0xC8, 0xEE, 0x30,
+ 0xF6, 0xD7, 0x30,
+ 0x9A, 0xF7, 0x67,
+ 0xC8, 0xE0, 0x67,
+ 0xF6, 0xC9, 0x67,
+ 0x9A, 0xEA, 0x9A,
+ 0xC8, 0xD3, 0x9A,
+ 0xF6, 0xBC, 0x9A,
+ 0x61, 0xFB, 0xC8,
+ 0x9A, 0xDF, 0xC8,
+ 0xC8, 0xC8, 0xC8,
+ 0xF6, 0xB1, 0xC8,
+ 0x61, 0xF0, 0xF6,
+ 0x9A, 0xD3, 0xF6,
+ 0xC8, 0xBC, 0xF6,
+ 0xF6, 0xA5, 0xF6,
+ 0xD5, 0xFB, 0x3D,
+ 0xD5, 0xED, 0x74,
+ 0xA7, 0xF7, 0xA7,
+ 0xD5, 0xE0, 0xA7,
+ 0xA7, 0xEC, 0xD5,
+ 0xD5, 0xD5, 0xD5,
+ 0xE1, 0xFA, 0x81,
+ 0xE1, 0xED, 0xB3,
+ 0xB3, 0xF8, 0xE1,
+ 0xE1, 0xE1, 0xE1,
+ 0xED, 0xF9, 0xBF,
+ 0xED, 0xED, 0xED,
+ 0xF8, 0xF8, 0xF8
+};
+
+static const uint32 s_yLookup[512] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000040, 0x00000000, 0x00000040, 0x00000000,
+ 0x00000040, 0x00000000, 0x00000040, 0x00000000,
+ 0x00000040, 0x00000000, 0x00000040, 0x00000040,
+ 0x00000040, 0x00000040, 0x00000040, 0x00000040,
+ 0x00000040, 0x00000040, 0x00400040, 0x00000040,
+ 0x00400040, 0x00000040, 0x00400040, 0x00000040,
+ 0x00400040, 0x00000040, 0x00400040, 0x00000040,
+ 0x00400040, 0x00400040, 0x00400040, 0x00400040,
+ 0x00400040, 0x00400040, 0x00400040, 0x00400040,
+ 0x00400040, 0x00400040, 0x00400040, 0x00400040,
+ 0x00400040, 0x00400040, 0x00400040, 0x00400040,
+ 0x00400040, 0x00400040, 0x00400080, 0x00400040,
+ 0x00400080, 0x00400040, 0x00400080, 0x00400040,
+ 0x00400080, 0x00400040, 0x00400080, 0x00400080,
+ 0x00400080, 0x00400080, 0x00400080, 0x00400080,
+ 0x00400080, 0x00400080, 0x00400080, 0x00400080,
+ 0x00800080, 0x00400080, 0x00800080, 0x00400080,
+ 0x00800080, 0x00400080, 0x00800080, 0x00400080,
+ 0x00800080, 0x00800080, 0x00800080, 0x00800080,
+ 0x00800080, 0x00800080, 0x00800080, 0x00800080,
+ 0x00800080, 0x00800080, 0x00800080, 0x00800080,
+ 0x00800080, 0x00800080, 0x00800080, 0x00800080,
+ 0x00800080, 0x00800080, 0x008000C0, 0x00800080,
+ 0x008000C0, 0x00800080, 0x008000C0, 0x00800080,
+ 0x008000C0, 0x00800080, 0x008000C0, 0x008000C0,
+ 0x008000C0, 0x008000C0, 0x008000C0, 0x008000C0,
+ 0x008000C0, 0x008000C0, 0x00C000C0, 0x008000C0,
+ 0x00C000C0, 0x008000C0, 0x00C000C0, 0x008000C0,
+ 0x00C000C0, 0x008000C0, 0x00C000C0, 0x00C000C0,
+ 0x00C000C0, 0x00C000C0, 0x00C000C0, 0x00C000C0,
+ 0x00C000C0, 0x00C000C0, 0x00C000C0, 0x00C000C0,
+ 0x00C000C0, 0x00C000C0, 0x00C000C0, 0x00C000C0,
+ 0x00C000C0, 0x00C000C0, 0x00C00100, 0x00C000C0,
+ 0x00C00100, 0x00C000C0, 0x00C00100, 0x00C000C0,
+ 0x00C00100, 0x00C000C0, 0x00C00100, 0x00C00100,
+ 0x00C00100, 0x00C00100, 0x00C00100, 0x00C00100,
+ 0x00C00100, 0x00C00100, 0x01000100, 0x00C00100,
+ 0x01000100, 0x00C00100, 0x01000100, 0x00C00100,
+ 0x01000100, 0x00C00100, 0x01000100, 0x01000100,
+ 0x01000100, 0x01000100, 0x01000100, 0x01000100,
+ 0x01000100, 0x01000100, 0x01000100, 0x01000100,
+ 0x01000100, 0x01000100, 0x01000100, 0x01000100,
+ 0x01000100, 0x01000100, 0x01000140, 0x01000100,
+ 0x01000140, 0x01000100, 0x01000140, 0x01000100,
+ 0x01000140, 0x01000140, 0x01000140, 0x01000140,
+ 0x01000140, 0x01000140, 0x01000140, 0x01000140,
+ 0x01400140, 0x01000140, 0x01400140, 0x01000140,
+ 0x01400140, 0x01000140, 0x01400140, 0x01000140,
+ 0x01400140, 0x01400140, 0x01400140, 0x01400140,
+ 0x01400140, 0x01400140, 0x01400140, 0x01400140,
+ 0x01400140, 0x01400140, 0x01400140, 0x01400140,
+ 0x01400140, 0x01400140, 0x01400180, 0x01400140,
+ 0x01400180, 0x01400140, 0x01400180, 0x01400140,
+ 0x01400180, 0x01400140, 0x01400180, 0x01400180,
+ 0x01400180, 0x01400180, 0x01400180, 0x01400180,
+ 0x01800180, 0x01400180, 0x01800180, 0x01400180,
+ 0x01800180, 0x01400180, 0x01800180, 0x01400180,
+ 0x01800180, 0x01800180, 0x01800180, 0x01800180,
+ 0x01800180, 0x01800180, 0x01800180, 0x01800180,
+ 0x01800180, 0x01800180, 0x01800180, 0x01800180,
+ 0x01800180, 0x01800180, 0x018001C0, 0x01800180,
+ 0x018001C0, 0x01800180, 0x018001C0, 0x01800180,
+ 0x018001C0, 0x018001C0, 0x018001C0, 0x018001C0,
+ 0x018001C0, 0x018001C0, 0x018001C0, 0x018001C0,
+ 0x01C001C0, 0x018001C0, 0x01C001C0, 0x018001C0,
+ 0x01C001C0, 0x018001C0, 0x01C001C0, 0x01C001C0,
+ 0x01C001C0, 0x01C001C0, 0x01C001C0, 0x01C001C0,
+ 0x01C001C0, 0x01C001C0, 0x01C001C0, 0x01C001C0,
+ 0x01C001C0, 0x01C001C0, 0x01C00200, 0x01C001C0,
+ 0x01C00200, 0x01C001C0, 0x01C00200, 0x01C001C0,
+ 0x01C00200, 0x01C001C0, 0x01C00200, 0x01C00200,
+ 0x01C00200, 0x01C00200, 0x01C00200, 0x01C00200,
+ 0x02000200, 0x01C00200, 0x02000200, 0x01C00200,
+ 0x02000200, 0x01C00200, 0x02000200, 0x02000200,
+ 0x02000200, 0x02000200, 0x02000200, 0x02000200,
+ 0x02000200, 0x02000200, 0x02000200, 0x02000200,
+ 0x02000200, 0x02000200, 0x02000240, 0x02000200,
+ 0x02000240, 0x02000200, 0x02000240, 0x02000200,
+ 0x02000240, 0x02000240, 0x02000240, 0x02000240,
+ 0x02000240, 0x02000240, 0x02400240, 0x02000240,
+ 0x02400240, 0x02000240, 0x02400240, 0x02000240,
+ 0x02400240, 0x02000240, 0x02400240, 0x02400240,
+ 0x02400240, 0x02400240, 0x02400240, 0x02400240,
+ 0x02400240, 0x02400240, 0x02400240, 0x02400240,
+ 0x02400280, 0x02400240, 0x02400280, 0x02400240,
+ 0x02400280, 0x02400240, 0x02400280, 0x02400280,
+ 0x02400280, 0x02400280, 0x02400280, 0x02400280,
+ 0x02800280, 0x02400280, 0x02800280, 0x02400280,
+ 0x02800280, 0x02400280, 0x02800280, 0x02800280,
+ 0x02800280, 0x02800280, 0x02800280, 0x02800280,
+ 0x02800280, 0x02800280, 0x02800280, 0x02800280,
+ 0x02800280, 0x02800280, 0x028002C0, 0x02800280,
+ 0x028002C0, 0x02800280, 0x028002C0, 0x02800280,
+ 0x028002C0, 0x028002C0, 0x028002C0, 0x028002C0,
+ 0x02C002C0, 0x028002C0, 0x02C002C0, 0x028002C0,
+ 0x02C002C0, 0x028002C0, 0x02C002C0, 0x02C002C0,
+ 0x02C002C0, 0x02C002C0, 0x02C002C0, 0x02C002C0,
+ 0x02C002C0, 0x02C002C0, 0x02C002C0, 0x02C002C0,
+ 0x02C00300, 0x02C002C0, 0x02C00300, 0x02C002C0,
+ 0x02C00300, 0x02C002C0, 0x02C00300, 0x02C00300,
+ 0x02C00300, 0x02C00300, 0x02C00300, 0x02C00300,
+ 0x03000300, 0x02C00300, 0x03000300, 0x02C00300,
+ 0x03000300, 0x03000300, 0x03000300, 0x03000300,
+ 0x03000300, 0x03000300, 0x03000300, 0x03000300,
+ 0x03000300, 0x03000300, 0x03000340, 0x03000300,
+ 0x03000340, 0x03000300, 0x03000340, 0x03000300,
+ 0x03000340, 0x03000340, 0x03000340, 0x03000340,
+ 0x03400340, 0x03000340, 0x03400340, 0x03000340,
+ 0x03400340, 0x03000340, 0x03400340, 0x03400340,
+ 0x03400340, 0x03400340, 0x03400340, 0x03400340,
+ 0x03400340, 0x03400340, 0x03400340, 0x03400340,
+ 0x03400380, 0x03400340, 0x03400380, 0x03400340,
+ 0x03400380, 0x03400380, 0x03400380, 0x03400380,
+ 0x03800380, 0x03400380, 0x03800380, 0x03400380,
+ 0x03800380, 0x03400380, 0x03800380, 0x03800380,
+ 0x03800380, 0x03800380, 0x03800380, 0x03800380,
+ 0x03800380, 0x03800380, 0x038003C0, 0x03800380,
+ 0x038003C0, 0x03800380, 0x038003C0, 0x03800380,
+ 0x038003C0, 0x038003C0, 0x038003C0, 0x038003C0,
+ 0x03C003C0, 0x038003C0, 0x03C003C0, 0x038003C0,
+ 0x03C003C0, 0x03C003C0, 0x03C003C0, 0x03C003C0,
+ 0x03C003C0, 0x03C003C0, 0x03C003C0, 0x03C003C0,
+ 0x03C003C0, 0x03C003C0, 0x03C003C0, 0x03C003C0,
+ 0x03C003C0, 0x03C003C0, 0x03C003C0, 0x03C003C0,
+ 0x03C003C0, 0x03C003C0, 0x03C003C0, 0x03C003C0
+};
+
+static const uint32 s_uLookup[512] = {
+ 0x00200020, 0x00200020, 0x00200020, 0x00200020,
+ 0x00200020, 0x00200020, 0x00200020, 0x00200020,
+ 0x00200020, 0x00200020, 0x00280020, 0x00200020,
+ 0x00280020, 0x00200020, 0x00280020, 0x00200020,
+ 0x00280020, 0x00200020, 0x00280020, 0x00280020,
+ 0x00280020, 0x00280020, 0x00280020, 0x00280020,
+ 0x00280020, 0x00280020, 0x00280020, 0x00280020,
+ 0x00280020, 0x00280028, 0x00280020, 0x00280028,
+ 0x00280020, 0x00280028, 0x00280020, 0x00280028,
+ 0x00280028, 0x00280028, 0x00280028, 0x00280028,
+ 0x00280028, 0x00280028, 0x00280028, 0x00280028,
+ 0x00280028, 0x00280028, 0x00280028, 0x00280028,
+ 0x00280028, 0x00280028, 0x00280028, 0x00280028,
+ 0x00280028, 0x00280028, 0x00280028, 0x00280028,
+ 0x00280028, 0x00280028, 0x00300028, 0x00280028,
+ 0x00300028, 0x00280028, 0x00300028, 0x00280028,
+ 0x00300028, 0x00280028, 0x00300028, 0x00280028,
+ 0x00300028, 0x00300028, 0x00300028, 0x00300028,
+ 0x00300028, 0x00300028, 0x00300028, 0x00300028,
+ 0x00300028, 0x00300028, 0x00300028, 0x00300028,
+ 0x00300028, 0x00300030, 0x00300028, 0x00300030,
+ 0x00300028, 0x00300030, 0x00300028, 0x00300030,
+ 0x00300028, 0x00300030, 0x00300028, 0x00300030,
+ 0x00300030, 0x00300030, 0x00300030, 0x00300030,
+ 0x00300030, 0x00300030, 0x00300030, 0x00300030,
+ 0x00300030, 0x00300030, 0x00300030, 0x00300030,
+ 0x00300030, 0x00300030, 0x00300030, 0x00300030,
+ 0x00300030, 0x00300030, 0x00300030, 0x00300030,
+ 0x00300030, 0x00300030, 0x00300030, 0x00300030,
+ 0x00300030, 0x00300030, 0x00380030, 0x00300030,
+ 0x00380030, 0x00300030, 0x00380030, 0x00300030,
+ 0x00380030, 0x00300030, 0x00380030, 0x00300030,
+ 0x00380030, 0x00300030, 0x00380030, 0x00300030,
+ 0x00380030, 0x00380030, 0x00380030, 0x00380030,
+ 0x00380030, 0x00380030, 0x00380030, 0x00380030,
+ 0x00380030, 0x00380030, 0x00380030, 0x00380030,
+ 0x00380030, 0x00380030, 0x00380030, 0x00380038,
+ 0x00380030, 0x00380038, 0x00380030, 0x00380038,
+ 0x00380030, 0x00380038, 0x00380030, 0x00380038,
+ 0x00380030, 0x00380038, 0x00380030, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00380038, 0x00380038, 0x00380038, 0x00380038,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00080000, 0x00000000,
+ 0x00080000, 0x00000000, 0x00080000, 0x00000000,
+ 0x00080000, 0x00000000, 0x00080000, 0x00000000,
+ 0x00080000, 0x00000000, 0x00080000, 0x00000000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080008, 0x00080000, 0x00080008,
+ 0x00080000, 0x00080008, 0x00080000, 0x00080008,
+ 0x00080000, 0x00080008, 0x00080000, 0x00080008,
+ 0x00080008, 0x00080008, 0x00080008, 0x00080008,
+ 0x00080008, 0x00080008, 0x00080008, 0x00080008,
+ 0x00080008, 0x00080008, 0x00080008, 0x00080008,
+ 0x00080008, 0x00080008, 0x00080008, 0x00080008,
+ 0x00080008, 0x00080008, 0x00080008, 0x00080008,
+ 0x00080008, 0x00080008, 0x00100008, 0x00080008,
+ 0x00100008, 0x00080008, 0x00100008, 0x00080008,
+ 0x00100008, 0x00080008, 0x00100008, 0x00080008,
+ 0x00100008, 0x00080008, 0x00100008, 0x00100008,
+ 0x00100008, 0x00100008, 0x00100008, 0x00100008,
+ 0x00100008, 0x00100008, 0x00100008, 0x00100008,
+ 0x00100008, 0x00100008, 0x00100008, 0x00100010,
+ 0x00100008, 0x00100010, 0x00100008, 0x00100010,
+ 0x00100008, 0x00100010, 0x00100008, 0x00100010,
+ 0x00100010, 0x00100010, 0x00100010, 0x00100010,
+ 0x00100010, 0x00100010, 0x00100010, 0x00100010,
+ 0x00100010, 0x00100010, 0x00100010, 0x00100010,
+ 0x00100010, 0x00100010, 0x00100010, 0x00100010,
+ 0x00100010, 0x00100010, 0x00100010, 0x00100010,
+ 0x00100010, 0x00100010, 0x00180010, 0x00100010,
+ 0x00180010, 0x00100010, 0x00180010, 0x00100010,
+ 0x00180010, 0x00100010, 0x00180010, 0x00100010,
+ 0x00180010, 0x00180010, 0x00180010, 0x00180010,
+ 0x00180010, 0x00180010, 0x00180010, 0x00180010,
+ 0x00180010, 0x00180010, 0x00180010, 0x00180018,
+ 0x00180010, 0x00180018, 0x00180010, 0x00180018,
+ 0x00180010, 0x00180018, 0x00180010, 0x00180018,
+ 0x00180018, 0x00180018, 0x00180018, 0x00180018,
+ 0x00180018, 0x00180018, 0x00180018, 0x00180018,
+ 0x00180018, 0x00180018, 0x00180018, 0x00180018,
+ 0x00180018, 0x00180018, 0x00180018, 0x00180018,
+ 0x00180018, 0x00180018, 0x00180018, 0x00180018,
+ 0x00200018, 0x00180018, 0x00200018, 0x00180018,
+ 0x00200018, 0x00180018, 0x00200018, 0x00180018,
+ 0x00200018, 0x00200018, 0x00200018, 0x00200018,
+ 0x00200018, 0x00200018, 0x00200018, 0x00200018,
+ 0x00200018, 0x00200018, 0x00200018, 0x00200020,
+ 0x00200018, 0x00200020, 0x00200018, 0x00200020,
+ 0x00200018, 0x00200020, 0x00200020, 0x00200020,
+ 0x00200020, 0x00200020, 0x00200020, 0x00200020,
+ 0x00200020, 0x00200020, 0x00200020, 0x00200020
+};
+
+static const uint32 s_vLookup[512] = {
+ 0x00030003, 0x00030003, 0x00030003, 0x00030003,
+ 0x00030003, 0x00030003, 0x00030003, 0x00030003,
+ 0x00030003, 0x00030003, 0x00030003, 0x00030004,
+ 0x00030003, 0x00030004, 0x00030003, 0x00030004,
+ 0x00030003, 0x00030004, 0x00030004, 0x00030004,
+ 0x00030004, 0x00030004, 0x00030004, 0x00030004,
+ 0x00030004, 0x00030004, 0x00030004, 0x00030004,
+ 0x00030004, 0x00040004, 0x00030004, 0x00040004,
+ 0x00030004, 0x00040004, 0x00030004, 0x00040004,
+ 0x00040004, 0x00040004, 0x00040004, 0x00040004,
+ 0x00040004, 0x00040004, 0x00040004, 0x00040004,
+ 0x00040004, 0x00040004, 0x00040004, 0x00040004,
+ 0x00040004, 0x00040004, 0x00040004, 0x00040004,
+ 0x00040004, 0x00040004, 0x00040004, 0x00040004,
+ 0x00040004, 0x00040005, 0x00040004, 0x00040005,
+ 0x00040004, 0x00040005, 0x00040004, 0x00040005,
+ 0x00040004, 0x00040005, 0x00040005, 0x00040005,
+ 0x00040005, 0x00040005, 0x00040005, 0x00040005,
+ 0x00040005, 0x00040005, 0x00040005, 0x00040005,
+ 0x00040005, 0x00050005, 0x00040005, 0x00050005,
+ 0x00040005, 0x00050005, 0x00040005, 0x00050005,
+ 0x00040005, 0x00050005, 0x00050005, 0x00050005,
+ 0x00050005, 0x00050005, 0x00050005, 0x00050005,
+ 0x00050005, 0x00050005, 0x00050005, 0x00050005,
+ 0x00050005, 0x00050005, 0x00050005, 0x00050005,
+ 0x00050005, 0x00050005, 0x00050005, 0x00050005,
+ 0x00050005, 0x00050005, 0x00050005, 0x00050005,
+ 0x00050005, 0x00050006, 0x00050005, 0x00050006,
+ 0x00050005, 0x00050006, 0x00050005, 0x00050006,
+ 0x00050005, 0x00050006, 0x00050006, 0x00050006,
+ 0x00050006, 0x00050006, 0x00050006, 0x00050006,
+ 0x00050006, 0x00050006, 0x00050006, 0x00050006,
+ 0x00050006, 0x00050006, 0x00050006, 0x00060006,
+ 0x00050006, 0x00060006, 0x00050006, 0x00060006,
+ 0x00050006, 0x00060006, 0x00050006, 0x00060006,
+ 0x00050006, 0x00060006, 0x00060006, 0x00060006,
+ 0x00060006, 0x00060006, 0x00060006, 0x00060006,
+ 0x00060006, 0x00060006, 0x00060006, 0x00060006,
+ 0x00060006, 0x00060006, 0x00060006, 0x00060006,
+ 0x00060006, 0x00060006, 0x00060006, 0x00060006,
+ 0x00060006, 0x00060006, 0x00060006, 0x00060006,
+ 0x00060006, 0x00060007, 0x00060006, 0x00060007,
+ 0x00060006, 0x00060007, 0x00060006, 0x00060007,
+ 0x00060006, 0x00060007, 0x00060006, 0x00060007,
+ 0x00060007, 0x00060007, 0x00060007, 0x00060007,
+ 0x00060007, 0x00060007, 0x00060007, 0x00060007,
+ 0x00060007, 0x00060007, 0x00060007, 0x00060007,
+ 0x00060007, 0x00070007, 0x00060007, 0x00070007,
+ 0x00060007, 0x00070007, 0x00060007, 0x00070007,
+ 0x00060007, 0x00070007, 0x00060007, 0x00070007,
+ 0x00060007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00070007, 0x00070007, 0x00070007, 0x00070007,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+ 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+ 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+ 0x00000000, 0x00000001, 0x00000001, 0x00000001,
+ 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+ 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+ 0x00000001, 0x00000001, 0x00000001, 0x00000001,
+ 0x00000001, 0x00010001, 0x00000001, 0x00010001,
+ 0x00000001, 0x00010001, 0x00000001, 0x00010001,
+ 0x00000001, 0x00010001, 0x00000001, 0x00010001,
+ 0x00000001, 0x00010001, 0x00010001, 0x00010001,
+ 0x00010001, 0x00010001, 0x00010001, 0x00010001,
+ 0x00010001, 0x00010001, 0x00010001, 0x00010001,
+ 0x00010001, 0x00010001, 0x00010001, 0x00010001,
+ 0x00010001, 0x00010001, 0x00010001, 0x00010001,
+ 0x00010001, 0x00010001, 0x00010001, 0x00010001,
+ 0x00010001, 0x00010001, 0x00010001, 0x00010001,
+ 0x00010001, 0x00010002, 0x00010001, 0x00010002,
+ 0x00010001, 0x00010002, 0x00010001, 0x00010002,
+ 0x00010001, 0x00010002, 0x00010001, 0x00010002,
+ 0x00010002, 0x00010002, 0x00010002, 0x00010002,
+ 0x00010002, 0x00010002, 0x00010002, 0x00010002,
+ 0x00010002, 0x00010002, 0x00010002, 0x00010002,
+ 0x00010002, 0x00020002, 0x00010002, 0x00020002,
+ 0x00010002, 0x00020002, 0x00010002, 0x00020002,
+ 0x00010002, 0x00020002, 0x00020002, 0x00020002,
+ 0x00020002, 0x00020002, 0x00020002, 0x00020002,
+ 0x00020002, 0x00020002, 0x00020002, 0x00020002,
+ 0x00020002, 0x00020002, 0x00020002, 0x00020002,
+ 0x00020002, 0x00020002, 0x00020002, 0x00020002,
+ 0x00020002, 0x00020002, 0x00020002, 0x00020002,
+ 0x00020002, 0x00020003, 0x00020002, 0x00020003,
+ 0x00020002, 0x00020003, 0x00020002, 0x00020003,
+ 0x00020003, 0x00020003, 0x00020003, 0x00020003,
+ 0x00020003, 0x00020003, 0x00020003, 0x00020003,
+ 0x00020003, 0x00020003, 0x00020003, 0x00030003,
+ 0x00020003, 0x00030003, 0x00020003, 0x00030003,
+ 0x00020003, 0x00030003, 0x00030003, 0x00030003,
+ 0x00030003, 0x00030003, 0x00030003, 0x00030003,
+ 0x00030003, 0x00030003, 0x00030003, 0x00030003
+};
+
+} // End of namespace Image
+
+#endif
diff --git a/image/codecs/codec.cpp b/image/codecs/codec.cpp
index 6b0c7ebcfb..398e9c562c 100644
--- a/image/codecs/codec.cpp
+++ b/image/codecs/codec.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "common/list.h"
#include "common/scummsys.h"
#include "image/codecs/codec.h"
@@ -44,6 +45,153 @@
namespace Image {
+namespace {
+
+/**
+ * Add a color to the QuickTime dither table check queue if it hasn't already been found.
+ */
+inline void addColorToQueue(uint16 color, uint16 index, byte *checkBuffer, Common::List<uint16> &checkQueue) {
+ if ((READ_UINT16(checkBuffer + color * 2) & 0xFF) == 0) {
+ // Previously unfound color
+ WRITE_UINT16(checkBuffer + color * 2, index);
+ checkQueue.push_back(color);
+ }
+}
+
+inline byte adjustColorRange(byte currentColor, byte correctColor, byte palColor) {
+ return CLIP<int>(currentColor - palColor + correctColor, 0, 255);
+}
+
+inline uint16 makeQuickTimeDitherColor(byte r, byte g, byte b) {
+ // RGB554
+ return ((r & 0xF8) << 6) | ((g & 0xF8) << 1) | (b >> 4);
+}
+
+} // End of anonymous namespace
+
+byte *Codec::createQuickTimeDitherTable(const byte *palette, uint colorCount) {
+ byte *buf = new byte[0x10000];
+ memset(buf, 0, 0x10000);
+
+ Common::List<uint16> checkQueue;
+
+ bool foundBlack = false;
+ bool foundWhite = false;
+
+ const byte *palPtr = palette;
+
+ // See what colors we have, and add them to the queue to check
+ for (uint i = 0; i < colorCount; i++) {
+ byte r = *palPtr++;
+ byte g = *palPtr++;
+ byte b = *palPtr++;
+ uint16 n = (i << 8) | 1;
+ uint16 col = makeQuickTimeDitherColor(r, g, b);
+
+ if (col == 0) {
+ // Special case for close-to-black
+ // The original did more here, but it effectively discarded the value
+ // due to a poor if-check (whole 16-bit value instead of lower 8-bits).
+ WRITE_UINT16(buf, n);
+ foundBlack = true;
+ } else if (col == 0x3FFF) {
+ // Special case for close-to-white
+ // The original did more here, but it effectively discarded the value
+ // due to a poor if-check (whole 16-bit value instead of lower 8-bits).
+ WRITE_UINT16(buf + 0x7FFE, n);
+ foundWhite = true;
+ } else {
+ // Previously unfound color
+ addColorToQueue(col, n, buf, checkQueue);
+ }
+ }
+
+ // More special handling for white
+ if (foundWhite)
+ checkQueue.push_front(0x3FFF);
+
+ // More special handling for black
+ if (foundBlack)
+ checkQueue.push_front(0);
+
+ // Go through the list of colors we have and match up similar colors
+ // to fill in the table as best as we can.
+ while (!checkQueue.empty()) {
+ uint16 col = checkQueue.front();
+ checkQueue.pop_front();
+ uint16 index = READ_UINT16(buf + col * 2);
+
+ uint32 x = col << 4;
+ if ((x & 0xFF) < 0xF0)
+ addColorToQueue((x + 0x10) >> 4, index, buf, checkQueue);
+ if ((x & 0xFF) >= 0x10)
+ addColorToQueue((x - 0x10) >> 4, index, buf, checkQueue);
+
+ uint32 y = col << 7;
+ if ((y & 0xFF00) < 0xF800)
+ addColorToQueue((y + 0x800) >> 7, index, buf, checkQueue);
+ if ((y & 0xFF00) >= 0x800)
+ addColorToQueue((y - 0x800) >> 7, index, buf, checkQueue);
+
+ uint32 z = col << 2;
+ if ((z & 0xFF00) < 0xF800)
+ addColorToQueue((z + 0x800) >> 2, index, buf, checkQueue);
+ if ((z & 0xFF00) >= 0x800)
+ addColorToQueue((z - 0x800) >> 2, index, buf, checkQueue);
+ }
+
+ // Contract the table back to just palette entries
+ for (int i = 0; i < 0x4000; i++)
+ buf[i] = READ_UINT16(buf + i * 2) >> 8;
+
+ // Now go through and distribute the error to three more pixels
+ byte *bufPtr = buf;
+ for (uint realR = 0; realR < 0x100; realR += 8) {
+ for (uint realG = 0; realG < 0x100; realG += 8) {
+ for (uint realB = 0; realB < 0x100; realB += 16) {
+ byte palIndex = *bufPtr;
+ byte r = realR;
+ byte g = realG;
+ byte b = realB;
+
+ byte palR = palette[palIndex * 3] & 0xF8;
+ byte palG = palette[palIndex * 3 + 1] & 0xF8;
+ byte palB = palette[palIndex * 3 + 2] & 0xF0;
+
+ r = adjustColorRange(r, realR, palR);
+ g = adjustColorRange(g, realG, palG);
+ b = adjustColorRange(b, realB, palB);
+ palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
+ bufPtr[0x4000] = palIndex;
+
+ palR = palette[palIndex * 3] & 0xF8;
+ palG = palette[palIndex * 3 + 1] & 0xF8;
+ palB = palette[palIndex * 3 + 2] & 0xF0;
+
+ r = adjustColorRange(r, realR, palR);
+ g = adjustColorRange(g, realG, palG);
+ b = adjustColorRange(b, realB, palB);
+ palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
+ bufPtr[0x8000] = palIndex;
+
+ palR = palette[palIndex * 3] & 0xF8;
+ palG = palette[palIndex * 3 + 1] & 0xF8;
+ palB = palette[palIndex * 3 + 2] & 0xF0;
+
+ r = adjustColorRange(r, realR, palR);
+ g = adjustColorRange(g, realG, palG);
+ b = adjustColorRange(b, realB, palB);
+ palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
+ bufPtr[0xC000] = palIndex;
+
+ bufPtr++;
+ }
+ }
+ }
+
+ return buf;
+}
+
Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel) {
switch (tag) {
case SWAP_CONSTANT_32(0):
diff --git a/image/codecs/codec.h b/image/codecs/codec.h
index d87758e65e..5c072132d3 100644
--- a/image/codecs/codec.h
+++ b/image/codecs/codec.h
@@ -59,6 +59,20 @@ public:
virtual ~Codec() {}
/**
+ * A type of dithering.
+ */
+ enum DitherType {
+ /** Unknown */
+ kDitherTypeUnknown,
+
+ /** Video for Windows dithering */
+ kDitherTypeVFW,
+
+ /** QuickTime dithering */
+ kDitherTypeQT
+ };
+
+ /**
* Decode the frame for the given data and return a pointer to a surface
* containing the decoded frame.
*
@@ -86,6 +100,21 @@ public:
* Does the codec have a dirty palette?
*/
virtual bool hasDirtyPalette() const { return false; }
+
+ /**
+ * Can the codec dither down to 8bpp?
+ */
+ virtual bool canDither(DitherType type) const { return false; }
+
+ /**
+ * Activate dithering mode with a palette
+ */
+ virtual void setDither(DitherType type, const byte *palette) {}
+
+ /**
+ * Create a dither table, as used by QuickTime codecs.
+ */
+ static byte *createQuickTimeDitherTable(const byte *palette, uint colorCount);
};
/**
diff --git a/image/codecs/qtrle.cpp b/image/codecs/qtrle.cpp
index 94744efa5a..8a83cfa2bd 100644
--- a/image/codecs/qtrle.cpp
+++ b/image/codecs/qtrle.cpp
@@ -37,27 +37,45 @@ namespace Image {
QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Codec() {
_bitsPerPixel = bitsPerPixel;
+ _ditherPalette = 0;
+ _width = width;
+ _height = height;
+ _surface = 0;
+ _dirtyPalette = false;
+ _colorMap = 0;
// We need to ensure the width is a multiple of 4
+ _paddedWidth = width;
uint16 wMod = width % 4;
if (wMod != 0)
- width += 4 - wMod;
+ _paddedWidth += 4 - wMod;
+}
- _surface = new Graphics::Surface();
- _surface->create(width, height, getPixelFormat());
+QTRLEDecoder::~QTRLEDecoder() {
+ if (_surface) {
+ _surface->free();
+ delete _surface;
+ }
+
+ delete[] _colorMap;
+ delete[] _ditherPalette;
}
#define CHECK_STREAM_PTR(n) \
- if ((stream.pos() + n) > stream.size()) { \
- warning("QTRLE Problem: stream out of bounds (%d > %d)", stream.pos() + n, stream.size()); \
- return; \
- }
+ do { \
+ if ((stream.pos() + n) > stream.size()) { \
+ warning("QTRLE Problem: stream out of bounds (%d > %d)", stream.pos() + n, stream.size()); \
+ return; \
+ } \
+ } while (0)
#define CHECK_PIXEL_PTR(n) \
- if ((int32)pixelPtr + n > _surface->w * _surface->h) { \
- warning("QTRLE Problem: pixel ptr = %d, pixel limit = %d", pixelPtr + n, _surface->w * _surface->h); \
- return; \
- } \
+ do { \
+ if ((int32)pixelPtr + n > (int)_paddedWidth * _surface->h) { \
+ warning("QTRLE Problem: pixel ptr = %d, pixel limit = %d", pixelPtr + n, _paddedWidth * _surface->h); \
+ return; \
+ } \
+ } while (0)
void QTRLEDecoder::decode1(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange) {
uint32 pixelPtr = 0;
@@ -73,7 +91,7 @@ void QTRLEDecoder::decode1(Common::SeekableReadStream &stream, uint32 rowPtr, ui
if (skip & 0x80) {
linesToChange--;
- rowPtr += _surface->w;
+ rowPtr += _paddedWidth;
pixelPtr = rowPtr + 2 * (skip & 0x7f);
} else
pixelPtr += 2 * skip;
@@ -159,7 +177,7 @@ void QTRLEDecoder::decode2_4(Common::SeekableReadStream &stream, uint32 rowPtr,
}
}
- rowPtr += _surface->w;
+ rowPtr += _paddedWidth;
}
}
@@ -204,7 +222,7 @@ void QTRLEDecoder::decode8(Common::SeekableReadStream &stream, uint32 rowPtr, ui
}
}
- rowPtr += _surface->w;
+ rowPtr += _paddedWidth;
}
}
@@ -242,7 +260,7 @@ void QTRLEDecoder::decode16(Common::SeekableReadStream &stream, uint32 rowPtr, u
}
}
- rowPtr += _surface->w;
+ rowPtr += _paddedWidth;
}
}
@@ -288,7 +306,72 @@ void QTRLEDecoder::decode24(Common::SeekableReadStream &stream, uint32 rowPtr, u
}
}
- rowPtr += _surface->w;
+ rowPtr += _paddedWidth;
+ }
+}
+
+namespace {
+
+inline uint16 readDitherColor24(Common::ReadStream &stream) {
+ uint16 color = (stream.readByte() & 0xF8) << 6;
+ color |= (stream.readByte() & 0xF8) << 1;
+ color |= stream.readByte() >> 4;
+ return color;
+}
+
+} // End of anonymous namespace
+
+void QTRLEDecoder::dither24(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ byte *output = (byte *)_surface->getPixels();
+
+ static const uint16 colorTableOffsets[] = { 0x0000, 0xC000, 0x4000, 0x8000 };
+
+ // clone2727 thinks this should be startLine & 3, but the original definitely
+ // isn't doing this. Unless startLine & 3 is always 0? Kinda defeats the
+ // purpose of the compression then.
+ byte curColorTableOffset = 0;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+
+ byte rowOffset = stream.readByte() - 1;
+ pixelPtr = rowPtr + rowOffset;
+ uint16 colorTableOffset = colorTableOffsets[curColorTableOffset] + (rowOffset << 14);
+
+ for (int8 rleCode = stream.readSByte(); rleCode != -1; rleCode = stream.readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += stream.readByte() - 1;
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ CHECK_STREAM_PTR(3);
+ CHECK_PIXEL_PTR(rleCode);
+
+ uint16 color = readDitherColor24(stream);
+
+ while (rleCode--) {
+ output[pixelPtr++] = _colorMap[colorTableOffset + color];
+ colorTableOffset += 0x4000;
+ }
+ } else {
+ CHECK_STREAM_PTR(rleCode * 3);
+ CHECK_PIXEL_PTR(rleCode);
+
+ // copy pixels directly to output
+ while (rleCode--) {
+ uint16 color = readDitherColor24(stream);
+ output[pixelPtr++] = _colorMap[colorTableOffset + color];
+ colorTableOffset += 0x4000;
+ }
+ }
+ }
+
+ rowPtr += _paddedWidth;
+ curColorTableOffset = (curColorTableOffset + 1) & 3;
}
}
@@ -336,13 +419,16 @@ void QTRLEDecoder::decode32(Common::SeekableReadStream &stream, uint32 rowPtr, u
}
}
- rowPtr += _surface->w;
+ rowPtr += _paddedWidth;
}
}
const Graphics::Surface *QTRLEDecoder::decodeFrame(Common::SeekableReadStream &stream) {
+ if (!_surface)
+ createSurface();
+
uint16 startLine = 0;
- uint16 height = _surface->h;
+ uint16 height = _height;
// check if this frame is even supposed to change
if (stream.size() < 8)
@@ -365,7 +451,7 @@ const Graphics::Surface *QTRLEDecoder::decodeFrame(Common::SeekableReadStream &s
stream.readUint16BE(); // Unknown
}
- uint32 rowPtr = _surface->w * startLine;
+ uint32 rowPtr = _paddedWidth * startLine;
switch (_bitsPerPixel) {
case 1:
@@ -388,7 +474,10 @@ const Graphics::Surface *QTRLEDecoder::decodeFrame(Common::SeekableReadStream &s
decode16(stream, rowPtr, height);
break;
case 24:
- decode24(stream, rowPtr, height);
+ if (_ditherPalette)
+ dither24(stream, rowPtr, height);
+ else
+ decode24(stream, rowPtr, height);
break;
case 32:
decode32(stream, rowPtr, height);
@@ -400,12 +489,10 @@ const Graphics::Surface *QTRLEDecoder::decodeFrame(Common::SeekableReadStream &s
return _surface;
}
-QTRLEDecoder::~QTRLEDecoder() {
- _surface->free();
- delete _surface;
-}
-
Graphics::PixelFormat QTRLEDecoder::getPixelFormat() const {
+ if (_ditherPalette)
+ return Graphics::PixelFormat::createFormatCLUT8();
+
switch (_bitsPerPixel) {
case 1:
case 33:
@@ -428,4 +515,31 @@ Graphics::PixelFormat QTRLEDecoder::getPixelFormat() const {
return Graphics::PixelFormat();
}
+bool QTRLEDecoder::canDither(DitherType type) const {
+ // Only 24-bit dithering is implemented at the moment
+ return type == kDitherTypeQT && _bitsPerPixel == 24;
+}
+
+void QTRLEDecoder::setDither(DitherType type, const byte *palette) {
+ assert(canDither(type));
+
+ _ditherPalette = new byte[256 * 3];
+ memcpy(_ditherPalette, palette, 256 * 3);
+ _dirtyPalette = true;
+
+ delete[] _colorMap;
+ _colorMap = createQuickTimeDitherTable(palette, 256);
+}
+
+void QTRLEDecoder::createSurface() {
+ if (_surface) {
+ _surface->free();
+ delete _surface;
+ }
+
+ _surface = new Graphics::Surface();
+ _surface->create(_paddedWidth, _height, getPixelFormat());
+ _surface->w = _width;
+}
+
} // End of namespace Image
diff --git a/image/codecs/qtrle.h b/image/codecs/qtrle.h
index b44a46c3e2..e345fbeedf 100644
--- a/image/codecs/qtrle.h
+++ b/image/codecs/qtrle.h
@@ -41,16 +41,29 @@ public:
const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
Graphics::PixelFormat getPixelFormat() const;
+ bool containsPalette() const { return _ditherPalette != 0; }
+ const byte *getPalette() { _dirtyPalette = false; return _ditherPalette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+ bool canDither(DitherType type) const;
+ void setDither(DitherType type, const byte *palette);
+
private:
byte _bitsPerPixel;
-
Graphics::Surface *_surface;
+ uint16 _width, _height;
+ uint32 _paddedWidth;
+ byte *_ditherPalette;
+ bool _dirtyPalette;
+ byte *_colorMap;
+
+ void createSurface();
void decode1(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange);
void decode2_4(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange, byte bpp);
void decode8(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange);
void decode16(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange);
void decode24(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange);
+ void dither24(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange);
void decode32(Common::SeekableReadStream &stream, uint32 rowPtr, uint32 linesToChange);
};
diff --git a/image/codecs/rpza.cpp b/image/codecs/rpza.cpp
index 5aeee7c90b..8d648e1cc1 100644
--- a/image/codecs/rpza.cpp
+++ b/image/codecs/rpza.cpp
@@ -32,43 +32,185 @@
namespace Image {
RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Codec() {
- // We need to increase the surface size to a multiple of 4
- uint16 wMod = width % 4;
- if (wMod != 0)
- width += 4 - wMod;
-
- _surface = new Graphics::Surface();
- _surface->create(width, height, getPixelFormat());
+ _format = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
+ _ditherPalette = 0;
+ _dirtyPalette = false;
+ _colorMap = 0;
+ _width = width;
+ _height = height;
+ _blockWidth = (width + 3) / 4;
+ _blockHeight = (height + 3) / 4;
+ _surface = 0;
}
RPZADecoder::~RPZADecoder() {
- _surface->free();
- delete _surface;
+ if (_surface) {
+ _surface->free();
+ delete _surface;
+ }
+
+ delete[] _ditherPalette;
}
#define ADVANCE_BLOCK() \
- pixelPtr += 4; \
- if (pixelPtr >= _surface->w) { \
- pixelPtr = 0; \
- rowPtr += _surface->w * 4; \
+ blockPtr += 4; \
+ if (blockPtr >= endPtr) { \
+ blockPtr += pitch * 3; \
+ endPtr = blockPtr + pitch; \
} \
totalBlocks--; \
if (totalBlocks < 0) \
error("rpza block counter just went negative (this should not happen)") \
-#define PUT_PIXEL(color) \
- if ((int32)blockPtr < _surface->w * _surface->h) \
- WRITE_UINT16((uint16 *)_surface->getPixels() + blockPtr, color); \
- blockPtr++
+struct BlockDecoderRaw {
+ static inline void drawFillBlock(uint16 *blockPtr, uint16 pitch, uint16 color, const byte *colorMap) {
+ blockPtr[0] = color;
+ blockPtr[1] = color;
+ blockPtr[2] = color;
+ blockPtr[3] = color;
+ blockPtr += pitch;
+ blockPtr[0] = color;
+ blockPtr[1] = color;
+ blockPtr[2] = color;
+ blockPtr[3] = color;
+ blockPtr += pitch;
+ blockPtr[0] = color;
+ blockPtr[1] = color;
+ blockPtr[2] = color;
+ blockPtr[3] = color;
+ blockPtr += pitch;
+ blockPtr[0] = color;
+ blockPtr[1] = color;
+ blockPtr[2] = color;
+ blockPtr[3] = color;
+ }
-const Graphics::Surface *RPZADecoder::decodeFrame(Common::SeekableReadStream &stream) {
+ static inline void drawRawBlock(uint16 *blockPtr, uint16 pitch, const uint16 (&colors)[16], const byte *colorMap) {
+ blockPtr[0] = colors[0];
+ blockPtr[1] = colors[1];
+ blockPtr[2] = colors[2];
+ blockPtr[3] = colors[3];
+ blockPtr += pitch;
+ blockPtr[0] = colors[4];
+ blockPtr[1] = colors[5];
+ blockPtr[2] = colors[6];
+ blockPtr[3] = colors[7];
+ blockPtr += pitch;
+ blockPtr[0] = colors[8];
+ blockPtr[1] = colors[9];
+ blockPtr[2] = colors[10];
+ blockPtr[3] = colors[11];
+ blockPtr += pitch;
+ blockPtr[0] = colors[12];
+ blockPtr[1] = colors[13];
+ blockPtr[2] = colors[14];
+ blockPtr[3] = colors[15];
+ }
+
+ static inline void drawBlendBlock(uint16 *blockPtr, uint16 pitch, const uint16 (&colors)[4], const byte (&indexes)[4], const byte *colorMap) {
+ blockPtr[0] = colors[(indexes[0] >> 6) & 0x03];
+ blockPtr[1] = colors[(indexes[0] >> 4) & 0x03];
+ blockPtr[2] = colors[(indexes[0] >> 2) & 0x03];
+ blockPtr[3] = colors[(indexes[0] >> 0) & 0x03];
+ blockPtr += pitch;
+ blockPtr[0] = colors[(indexes[1] >> 6) & 0x03];
+ blockPtr[1] = colors[(indexes[1] >> 4) & 0x03];
+ blockPtr[2] = colors[(indexes[1] >> 2) & 0x03];
+ blockPtr[3] = colors[(indexes[1] >> 0) & 0x03];
+ blockPtr += pitch;
+ blockPtr[0] = colors[(indexes[2] >> 6) & 0x03];
+ blockPtr[1] = colors[(indexes[2] >> 4) & 0x03];
+ blockPtr[2] = colors[(indexes[2] >> 2) & 0x03];
+ blockPtr[3] = colors[(indexes[2] >> 0) & 0x03];
+ blockPtr += pitch;
+ blockPtr[0] = colors[(indexes[3] >> 6) & 0x03];
+ blockPtr[1] = colors[(indexes[3] >> 4) & 0x03];
+ blockPtr[2] = colors[(indexes[3] >> 2) & 0x03];
+ blockPtr[3] = colors[(indexes[3] >> 0) & 0x03];
+ }
+};
+
+struct BlockDecoderDither {
+ static inline void drawFillBlock(byte *blockPtr, uint16 pitch, uint16 color, const byte *colorMap) {
+ const byte *mapOffset = colorMap + (color >> 1);
+ byte pixel1 = mapOffset[0x0000];
+ byte pixel2 = mapOffset[0x4000];
+ byte pixel3 = mapOffset[0x8000];
+ byte pixel4 = mapOffset[0xC000];
+
+ blockPtr[0] = pixel1;
+ blockPtr[1] = pixel2;
+ blockPtr[2] = pixel3;
+ blockPtr[3] = pixel4;
+ blockPtr += pitch;
+ blockPtr[0] = pixel4;
+ blockPtr[1] = pixel1;
+ blockPtr[2] = pixel2;
+ blockPtr[3] = pixel3;
+ blockPtr += pitch;
+ blockPtr[0] = pixel2;
+ blockPtr[1] = pixel3;
+ blockPtr[2] = pixel4;
+ blockPtr[3] = pixel1;
+ blockPtr += pitch;
+ blockPtr[0] = pixel3;
+ blockPtr[1] = pixel4;
+ blockPtr[2] = pixel1;
+ blockPtr[3] = pixel2;
+ }
+
+ static inline void drawRawBlock(byte *blockPtr, uint16 pitch, const uint16 (&colors)[16], const byte *colorMap) {
+ blockPtr[0] = colorMap[(colors[0] >> 1) + 0x0000];
+ blockPtr[1] = colorMap[(colors[1] >> 1) + 0x4000];
+ blockPtr[2] = colorMap[(colors[2] >> 1) + 0x8000];
+ blockPtr[3] = colorMap[(colors[3] >> 1) + 0xC000];
+ blockPtr += pitch;
+ blockPtr[0] = colorMap[(colors[4] >> 1) + 0xC000];
+ blockPtr[1] = colorMap[(colors[5] >> 1) + 0x0000];
+ blockPtr[2] = colorMap[(colors[6] >> 1) + 0x4000];
+ blockPtr[3] = colorMap[(colors[7] >> 1) + 0x8000];
+ blockPtr += pitch;
+ blockPtr[0] = colorMap[(colors[8] >> 1) + 0x4000];
+ blockPtr[1] = colorMap[(colors[9] >> 1) + 0x8000];
+ blockPtr[2] = colorMap[(colors[10] >> 1) + 0xC000];
+ blockPtr[3] = colorMap[(colors[11] >> 1) + 0x0000];
+ blockPtr += pitch;
+ blockPtr[0] = colorMap[(colors[12] >> 1) + 0x8000];
+ blockPtr[1] = colorMap[(colors[13] >> 1) + 0xC000];
+ blockPtr[2] = colorMap[(colors[14] >> 1) + 0x0000];
+ blockPtr[3] = colorMap[(colors[15] >> 1) + 0x4000];
+ }
+
+ static inline void drawBlendBlock(byte *blockPtr, uint16 pitch, const uint16 (&colors)[4], const byte (&indexes)[4], const byte *colorMap) {
+ blockPtr[0] = colorMap[(colors[(indexes[0] >> 6) & 0x03] >> 1) + 0x0000];
+ blockPtr[1] = colorMap[(colors[(indexes[0] >> 4) & 0x03] >> 1) + 0x4000];
+ blockPtr[2] = colorMap[(colors[(indexes[0] >> 2) & 0x03] >> 1) + 0x8000];
+ blockPtr[3] = colorMap[(colors[(indexes[0] >> 0) & 0x03] >> 1) + 0xC000];
+ blockPtr += pitch;
+ blockPtr[0] = colorMap[(colors[(indexes[1] >> 6) & 0x03] >> 1) + 0xC000];
+ blockPtr[1] = colorMap[(colors[(indexes[1] >> 4) & 0x03] >> 1) + 0x0000];
+ blockPtr[2] = colorMap[(colors[(indexes[1] >> 2) & 0x03] >> 1) + 0x4000];
+ blockPtr[3] = colorMap[(colors[(indexes[1] >> 0) & 0x03] >> 1) + 0x8000];
+ blockPtr += pitch;
+ blockPtr[0] = colorMap[(colors[(indexes[2] >> 6) & 0x03] >> 1) + 0x4000];
+ blockPtr[1] = colorMap[(colors[(indexes[2] >> 4) & 0x03] >> 1) + 0x8000];
+ blockPtr[2] = colorMap[(colors[(indexes[2] >> 2) & 0x03] >> 1) + 0xC000];
+ blockPtr[3] = colorMap[(colors[(indexes[2] >> 0) & 0x03] >> 1) + 0x0000];
+ blockPtr += pitch;
+ blockPtr[0] = colorMap[(colors[(indexes[3] >> 6) & 0x03] >> 1) + 0x8000];
+ blockPtr[1] = colorMap[(colors[(indexes[3] >> 4) & 0x03] >> 1) + 0xC000];
+ blockPtr[2] = colorMap[(colors[(indexes[3] >> 2) & 0x03] >> 1) + 0x0000];
+ blockPtr[3] = colorMap[(colors[(indexes[3] >> 0) & 0x03] >> 1) + 0x4000];
+ }
+};
+
+template<typename PixelInt, typename BlockDecoder>
+static inline void decodeFrameTmpl(Common::SeekableReadStream &stream, PixelInt *ptr, uint16 pitch, uint16 blockWidth, uint16 blockHeight, const byte *colorMap) {
uint16 colorA = 0, colorB = 0;
uint16 color4[4];
- uint32 rowPtr = 0;
- uint32 pixelPtr = 0;
- uint32 blockPtr = 0;
- uint32 rowInc = _surface->w - 4;
+ PixelInt *blockPtr = ptr;
+ PixelInt *endPtr = ptr + pitch;
uint16 ta;
uint16 tb;
@@ -88,7 +230,7 @@ const Graphics::Surface *RPZADecoder::decodeFrame(Common::SeekableReadStream &st
}
// Number of 4x4 blocks in frame
- int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
+ int32 totalBlocks = blockWidth * blockHeight;
// Process chunk data
while ((uint32)stream.pos() < chunkSize) {
@@ -117,14 +259,9 @@ const Graphics::Surface *RPZADecoder::decodeFrame(Common::SeekableReadStream &st
break;
case 0xa0: // Fill blocks with one color
colorA = stream.readUint16BE();
+
while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++) {
- PUT_PIXEL(colorA);
- }
- blockPtr += rowInc;
- }
+ BlockDecoder::drawFillBlock(blockPtr, pitch, colorA, colorMap);
ADVANCE_BLOCK();
}
break;
@@ -136,10 +273,10 @@ const Graphics::Surface *RPZADecoder::decodeFrame(Common::SeekableReadStream &st
colorB = stream.readUint16BE();
// Sort out the colors
- color4[0] = colorB;
+ color4[0] = colorB & 0x7FFF;
color4[1] = 0;
color4[2] = 0;
- color4[3] = colorA;
+ color4[3] = colorA & 0x7FFF;
// Red components
ta = (colorA >> 10) & 0x1F;
@@ -160,42 +297,69 @@ const Graphics::Surface *RPZADecoder::decodeFrame(Common::SeekableReadStream &st
color4[2] |= ((21 * ta + 11 * tb) >> 5);
while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- byte index = stream.readByte();
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++) {
- byte idx = (index >> (2 * (3 - pixel_x))) & 0x03;
- PUT_PIXEL(color4[idx]);
- }
- blockPtr += rowInc;
- }
+ byte indexes[4];
+ stream.read(indexes, 4);
+
+ BlockDecoder::drawBlendBlock(blockPtr, pitch, color4, indexes, colorMap);
ADVANCE_BLOCK();
}
break;
// Fill block with 16 colors
- case 0x00:
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++) {
- // We already have color of upper left pixel
- if (pixel_y != 0 || pixel_x != 0)
- colorA = stream.readUint16BE();
-
- PUT_PIXEL(colorA);
- }
- blockPtr += rowInc;
- }
+ case 0x00: {
+ uint16 colors[16];
+ colors[0] = colorA;
+
+ for (int i = 0; i < 15; i++)
+ colors[i + 1] = stream.readUint16BE();
+
+ BlockDecoder::drawRawBlock(blockPtr, pitch, colors, colorMap);
ADVANCE_BLOCK();
break;
+ }
// Unknown opcode
default:
error("Unknown opcode %02x in rpza chunk", opcode);
}
}
+}
+
+const Graphics::Surface *RPZADecoder::decodeFrame(Common::SeekableReadStream &stream) {
+ if (!_surface) {
+ _surface = new Graphics::Surface();
+
+ // Allocate enough space in the surface for the blocks
+ _surface->create(_blockWidth * 4, _blockHeight * 4, getPixelFormat());
+
+ // Adjust width/height to be the right ones
+ _surface->w = _width;
+ _surface->h = _height;
+ }
+
+ if (_colorMap)
+ decodeFrameTmpl<byte, BlockDecoderDither>(stream, (byte *)_surface->getPixels(), _surface->pitch, _blockWidth, _blockHeight, _colorMap);
+ else
+ decodeFrameTmpl<uint16, BlockDecoderRaw>(stream, (uint16 *)_surface->getPixels(), _surface->pitch / 2, _blockWidth, _blockHeight, _colorMap);
return _surface;
}
+bool RPZADecoder::canDither(DitherType type) const {
+ return type == kDitherTypeQT;
+}
+
+void RPZADecoder::setDither(DitherType type, const byte *palette) {
+ assert(canDither(type));
+
+ _ditherPalette = new byte[256 * 3];
+ memcpy(_ditherPalette, palette, 256 * 3);
+
+ _dirtyPalette = true;
+ _format = Graphics::PixelFormat::createFormatCLUT8();
+
+ delete[] _colorMap;
+ _colorMap = createQuickTimeDitherTable(palette, 256);
+}
+
} // End of namespace Image
diff --git a/image/codecs/rpza.h b/image/codecs/rpza.h
index d1dbbdb676..d62b385330 100644
--- a/image/codecs/rpza.h
+++ b/image/codecs/rpza.h
@@ -39,10 +39,22 @@ public:
~RPZADecoder();
const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
- Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); }
+ Graphics::PixelFormat getPixelFormat() const { return _format; }
+
+ bool containsPalette() const { return _ditherPalette != 0; }
+ const byte *getPalette() { _dirtyPalette = false; return _ditherPalette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+ bool canDither(DitherType type) const;
+ void setDither(DitherType type, const byte *palette);
private:
+ Graphics::PixelFormat _format;
Graphics::Surface *_surface;
+ byte *_ditherPalette;
+ bool _dirtyPalette;
+ byte *_colorMap;
+ uint16 _width, _height;
+ uint16 _blockWidth, _blockHeight;
};
} // End of namespace Image