aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hoops2014-09-05 00:30:05 -0400
committerMatthew Hoops2015-04-11 14:36:58 -0400
commit1271fbde8f30fdf2d0664bb1e3382928380f9aa9 (patch)
tree764793a36fde23c809ea6e5991bbfd8905702734
parentc402d9a9594e5a2b38f834578b010d5cf9bb771e (diff)
downloadscummvm-rg350-1271fbde8f30fdf2d0664bb1e3382928380f9aa9.tar.gz
scummvm-rg350-1271fbde8f30fdf2d0664bb1e3382928380f9aa9.tar.bz2
scummvm-rg350-1271fbde8f30fdf2d0664bb1e3382928380f9aa9.zip
IMAGE: Add support for QuickTime dithered Cinepak
-rw-r--r--image/codecs/cinepak.cpp124
-rw-r--r--image/codecs/cinepak.h3
2 files changed, 118 insertions, 9 deletions
diff --git a/image/codecs/cinepak.cpp b/image/codecs/cinepak.cpp
index f43c952c2c..32f6be2cd5 100644
--- a/image/codecs/cinepak.cpp
+++ b/image/codecs/cinepak.cpp
@@ -264,6 +264,37 @@ private:
}
};
+/**
+ * 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;
@@ -306,8 +337,7 @@ void decodeVectorsTmpl(CinepakFrame &frame, const byte *clipTable, const byte *c
return;
byte codebook[4];
- for (byte i = 0; i < 4; i++)
- codebook[i] = stream.readByte();
+ stream.read(codebook, 4);
CodebookConverter::decodeBlock4(codebook, frame.strips[strip], iy, clipTable, colorMap, frame.surface->format);
}
}
@@ -326,6 +356,7 @@ CinepakDecoder::CinepakDecoder(int bitsPerPixel) : Codec(), _bitsPerPixel(bitsPe
_y = 0;
_colorMap = 0;
_ditherPalette = 0;
+ _ditherType = kDitherTypeUnknown;
if (bitsPerPixel == 8) {
_pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
@@ -398,9 +429,12 @@ 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];
+ 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);
}
}
@@ -484,8 +518,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();
@@ -497,10 +530,72 @@ 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) {
if (_curFrame.surface->format.bytesPerPixel == 1) {
decodeVectorsTmpl<byte, CodebookConverterRaw>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
@@ -512,7 +607,7 @@ void CinepakDecoder::decodeVectors(Common::SeekableReadStream &stream, uint16 st
}
bool CinepakDecoder::canDither(DitherType type) const {
- return type == kDitherTypeVFW && _bitsPerPixel == 24;
+ return (type == kDitherTypeVFW || type == kDitherTypeQT) && _bitsPerPixel == 24;
}
void CinepakDecoder::setDither(DitherType type, const byte *palette) {
@@ -526,10 +621,18 @@ void CinepakDecoder::setDither(DitherType type, const byte *palette) {
_dirtyPalette = true;
_pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
- _colorMap = new byte[221];
+ _ditherType = type;
+
+ if (type == kDitherTypeVFW) {
+ _colorMap = new byte[221];
- for (int i = 0; i < 221; i++)
- _colorMap[i] = findNearestRGB(i);
+ 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 {
@@ -567,7 +670,10 @@ byte CinepakDecoder::findNearestRGB(int index) const {
}
void CinepakDecoder::ditherVectors(Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize) {
- decodeVectorsTmpl<byte, CodebookConverterDitherVFW>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, 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 02c09b6ddb..dc8172ea0f 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 {
@@ -89,12 +90,14 @@ private:
bool _dirtyPalette;
byte *_rgbLookup;
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