diff options
author | vanfanel | 2015-11-11 17:56:12 +0100 |
---|---|---|
committer | vanfanel | 2015-11-11 17:56:12 +0100 |
commit | 99739a13fe844c807d3cdd87e67e207e888fd48a (patch) | |
tree | 6afbf4763326277efbf528f0bb9e587bf7a01788 /image/codecs/rpza.cpp | |
parent | 37e157a11c3fc731dfdcf6ec6b6a5a448550219b (diff) | |
parent | 7e44493fe8877a3c6a65f83b9ed84a5f59169005 (diff) | |
download | scummvm-rg350-99739a13fe844c807d3cdd87e67e207e888fd48a.tar.gz scummvm-rg350-99739a13fe844c807d3cdd87e67e207e888fd48a.tar.bz2 scummvm-rg350-99739a13fe844c807d3cdd87e67e207e888fd48a.zip |
Merge branch 'master' into dispmanx
Diffstat (limited to 'image/codecs/rpza.cpp')
-rw-r--r-- | image/codecs/rpza.cpp | 270 |
1 files changed, 217 insertions, 53 deletions
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 |