From 09051449851fea84f094c3a21809c2bc6313e209 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 25 Sep 2011 19:44:20 -0400 Subject: GRAPHICS: Rewrite PictDecoder's opcode handling In preparation for adding support for multiple CompressedQuickTime opcodes --- graphics/pict.cpp | 289 +++++++++++++++++++++++++++++++++++++++--------------- graphics/pict.h | 50 +++++++++- 2 files changed, 256 insertions(+), 83 deletions(-) (limited to 'graphics') diff --git a/graphics/pict.cpp b/graphics/pict.cpp index 80bcb7a71e..f768ecdf3e 100644 --- a/graphics/pict.cpp +++ b/graphics/pict.cpp @@ -45,10 +45,164 @@ PictDecoder::~PictDecoder() { delete _jpeg; } +#define OPCODE(a, b, c) _opcodes.push_back(PICTOpcode(a, &PictDecoder::b, c)) + +void PictDecoder::setupOpcodesCommon() { + OPCODE(0x0000, o_nop, "NOP"); + OPCODE(0x0001, o_clip, "Clip"); + OPCODE(0x0003, o_txFont, "TxFont"); + OPCODE(0x0004, o_txFace, "TxFace"); + OPCODE(0x0007, o_pnSize, "PnSize"); + OPCODE(0x000D, o_txSize, "TxSize"); + OPCODE(0x0010, o_txRatio, "TxRatio"); + OPCODE(0x0011, o_versionOp, "VersionOp"); + OPCODE(0x001E, o_nop, "DefHilite"); + OPCODE(0x0028, o_longText, "LongText"); + OPCODE(0x00A1, o_longComment, "LongComment"); + OPCODE(0x00FF, o_opEndPic, "OpEndPic"); + OPCODE(0x0C00, o_headerOp, "HeaderOp"); +} + +void PictDecoder::setupOpcodesNormal() { + setupOpcodesCommon(); + OPCODE(0x0098, on_packBitsRect, "PackBitsRect"); + OPCODE(0x009A, on_directBitsRect, "DirectBitsRect"); + OPCODE(0x8200, on_compressedQuickTime, "CompressedQuickTime"); +} + +void PictDecoder::setupOpcodesQuickTime() { + setupOpcodesCommon(); + OPCODE(0x0098, oq_packBitsRect, "PackBitsRect"); + OPCODE(0x009A, oq_directBitsRect, "DirectBitsRect"); + OPCODE(0x8200, oq_compressedQuickTime, "CompressedQuickTime"); +} + +#undef OPCODE + +void PictDecoder::o_nop(Common::SeekableReadStream *) { + // Nothing to do +} + +void PictDecoder::o_clip(Common::SeekableReadStream *stream) { + // Ignore + stream->skip(stream->readUint16BE() - 2); +} + +void PictDecoder::o_txFont(Common::SeekableReadStream *stream) { + // Ignore + stream->readUint16BE(); +} + +void PictDecoder::o_txFace(Common::SeekableReadStream *stream) { + // Ignore + stream->readByte(); +} + +void PictDecoder::o_pnSize(Common::SeekableReadStream *stream) { + // Ignore + stream->readUint16BE(); + stream->readUint16BE(); +} + +void PictDecoder::o_txSize(Common::SeekableReadStream *stream) { + // Ignore + stream->readUint16BE(); +} + +void PictDecoder::o_txRatio(Common::SeekableReadStream *stream) { + // Ignore + stream->readUint16BE(); + stream->readUint16BE(); + stream->readUint16BE(); + stream->readUint16BE(); +} + +void PictDecoder::o_versionOp(Common::SeekableReadStream *stream) { + // We only support v2 extended + if (stream->readUint16BE() != 0x02FF) + error("Unknown PICT version"); +} + +void PictDecoder::o_longText(Common::SeekableReadStream *stream) { + // Ignore + stream->readUint16BE(); + stream->readUint16BE(); + stream->skip(stream->readByte()); +} + +void PictDecoder::o_longComment(Common::SeekableReadStream *stream) { + // Ignore + stream->readUint16BE(); + stream->skip(stream->readUint16BE()); +} + +void PictDecoder::o_opEndPic(Common::SeekableReadStream *stream) { + // We've reached the end of the picture + _continueParsing = false; +} + +void PictDecoder::o_headerOp(Common::SeekableReadStream *stream) { + // Read the basic header, but we don't really have to do anything with it + /* uint16 version = */ stream->readUint16BE(); + stream->readUint16BE(); // Reserved + /* uint32 hRes = */ stream->readUint32BE(); + /* uint32 vRes = */ stream->readUint32BE(); + Common::Rect origResRect; + origResRect.top = stream->readUint16BE(); + origResRect.left = stream->readUint16BE(); + origResRect.bottom = stream->readUint16BE(); + origResRect.right = stream->readUint16BE(); + stream->readUint32BE(); // Reserved +} + +void PictDecoder::on_packBitsRect(Common::SeekableReadStream *stream) { + // Unpack data (8bpp or lower) + unpackBitsRect(stream, true); +} + +void PictDecoder::on_directBitsRect(Common::SeekableReadStream *stream) { + // Unpack data (16bpp or higher) + unpackBitsRect(stream, false); +} + +void PictDecoder::on_compressedQuickTime(Common::SeekableReadStream *stream) { + // OK, here's the fun. We get to completely change how QuickDraw draws + // the data in PICT files. + + // Swap out the opcodes to the new ones + _opcodes.clear(); + setupOpcodesQuickTime(); + + // We'll decode the first QuickTime data from here, but the QuickTime-specific + // opcodes will take over from here on out. Normal opcodes, signing off. + decodeCompressedQuickTime(stream); +} + +void PictDecoder::oq_packBitsRect(Common::SeekableReadStream *stream) { + // Skip any data here (8bpp or lower) + skipBitsRect(stream, true); +} + +void PictDecoder::oq_directBitsRect(Common::SeekableReadStream *stream) { + // Skip any data here (16bpp or higher) + skipBitsRect(stream, false); +} + +void PictDecoder::oq_compressedQuickTime(Common::SeekableReadStream *stream) { + // Just pass the data along + decodeCompressedQuickTime(stream); +} + Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *palette) { assert(stream); + // Initialize opcodes to their normal state + _opcodes.clear(); + setupOpcodesNormal(); + _outputSurface = 0; + _continueParsing = true; + memset(_palette, 0, sizeof(_palette)); uint16 fileSize = stream->readUint16BE(); @@ -63,70 +217,41 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale _imageRect.bottom = stream->readUint16BE(); _imageRect.right = stream->readUint16BE(); _imageRect.debugPrint(0, "PICT Rect:"); - _isPaletted = false; // NOTE: This is only a subset of the full PICT format. - // - Only V2 Images Supported + // - Only V2 (Extended) Images Supported // - CompressedQuickTime (JPEG) compressed data is supported // - DirectBitsRect/PackBitsRect compressed data is supported - for (uint32 opNum = 0; !stream->eos() && !stream->err() && stream->pos() < stream->size(); opNum++) { + for (uint32 opNum = 0; !stream->eos() && !stream->err() && stream->pos() < stream->size() && _continueParsing; opNum++) { + // PICT v2 opcodes are two bytes uint16 opcode = stream->readUint16BE(); - debug(2, "Found PICT opcode %04x", opcode); if (opNum == 0 && opcode != 0x0011) - error ("Cannot find PICT version opcode"); + error("Cannot find PICT version opcode"); else if (opNum == 1 && opcode != 0x0C00) - error ("Cannot find PICT header opcode"); - - if (opcode == 0x0000) { // Nop - stream->readUint16BE(); // Unknown - } else if (opcode == 0x0001) { // Clip - // Ignore - uint16 clipSize = stream->readUint16BE(); - stream->seek(clipSize - 2, SEEK_CUR); - } else if (opcode == 0x0007) { // PnSize - // Ignore - stream->readUint16BE(); - stream->readUint16BE(); - } else if (opcode == 0x0011) { // VersionOp - uint16 version = stream->readUint16BE(); - if (version != 0x02FF) - error ("Unknown PICT version"); - } else if (opcode == 0x001E) { // DefHilite - // Ignore, Contains no Data - } else if (opcode == 0x0098) { // PackBitsRect - decodeDirectBitsRect(stream, true); - _isPaletted = true; - } else if (opcode == 0x009A) { // DirectBitsRect - decodeDirectBitsRect(stream, false); - } else if (opcode == 0x00A1) { // LongComment - stream->readUint16BE(); - uint16 dataSize = stream->readUint16BE(); - stream->seek(dataSize, SEEK_CUR); - } else if (opcode == 0x00FF) { // OpEndPic - stream->readUint16BE(); - break; - } else if (opcode == 0x0C00) { // HeaderOp - /* uint16 version = */ stream->readUint16BE(); - stream->readUint16BE(); // Reserved - /* uint32 hRes = */ stream->readUint32BE(); - /* uint32 vRes = */ stream->readUint32BE(); - Common::Rect origResRect; - origResRect.top = stream->readUint16BE(); - origResRect.left = stream->readUint16BE(); - origResRect.bottom = stream->readUint16BE(); - origResRect.right = stream->readUint16BE(); - stream->readUint32BE(); // Reserved - } else if (opcode == 0x8200) { // CompressedQuickTime - decodeCompressedQuickTime(stream); - break; - } else { - warning("Unknown PICT opcode %04x", opcode); + error("Cannot find PICT header opcode"); + + // Since opcodes are word-aligned, we need to mark our starting + // position here. + uint32 startPos = stream->pos(); + + for (uint32 i = 0; i < _opcodes.size(); i++) { + if (_opcodes[i].op == opcode) { + debug(4, "Running PICT opcode %04x '%s'", opcode, _opcodes[i].desc); + (this->*(_opcodes[i].proc))(stream); + break; + } else if (i == _opcodes.size() - 1) { + // Unknown opcode; attempt to continue forward + warning("Unknown PICT opcode %04x", opcode); + } } + + // Align + stream->skip((stream->pos() - startPos) & 1); } // If we got a palette throughout this nonsense, go and grab it - if (palette && _isPaletted) + if (palette) memcpy(palette, _palette, 256 * 3); return _outputSurface; @@ -155,21 +280,18 @@ PictDecoder::PixMap PictDecoder::readPixMap(Common::SeekableReadStream *stream, return pixMap; } -struct DirectBitsRectData { +struct PackBitsRectData { PictDecoder::PixMap pixMap; Common::Rect srcRect; Common::Rect dstRect; uint16 mode; }; -void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, bool hasPalette) { +void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPalette) { static const PixelFormat directBitsFormat16 = PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); - // Clear the palette - memset(_palette, 0, sizeof(_palette)); - - DirectBitsRectData directBitsData; - directBitsData.pixMap = readPixMap(stream, !hasPalette); + PackBitsRectData packBitsData; + packBitsData.pixMap = readPixMap(stream, !hasPalette); // Read in the palette if there is one present if (hasPalette) { @@ -186,47 +308,47 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, bool } } - directBitsData.srcRect.top = stream->readUint16BE(); - directBitsData.srcRect.left = stream->readUint16BE(); - directBitsData.srcRect.bottom = stream->readUint16BE(); - directBitsData.srcRect.right = stream->readUint16BE(); - directBitsData.dstRect.top = stream->readUint16BE(); - directBitsData.dstRect.left = stream->readUint16BE(); - directBitsData.dstRect.bottom = stream->readUint16BE(); - directBitsData.dstRect.right = stream->readUint16BE(); - directBitsData.mode = stream->readUint16BE(); + packBitsData.srcRect.top = stream->readUint16BE(); + packBitsData.srcRect.left = stream->readUint16BE(); + packBitsData.srcRect.bottom = stream->readUint16BE(); + packBitsData.srcRect.right = stream->readUint16BE(); + packBitsData.dstRect.top = stream->readUint16BE(); + packBitsData.dstRect.left = stream->readUint16BE(); + packBitsData.dstRect.bottom = stream->readUint16BE(); + packBitsData.dstRect.right = stream->readUint16BE(); + packBitsData.mode = stream->readUint16BE(); - uint16 width = directBitsData.srcRect.width(); - uint16 height = directBitsData.srcRect.height(); + uint16 width = packBitsData.srcRect.width(); + uint16 height = packBitsData.srcRect.height(); byte bytesPerPixel = 0; - if (directBitsData.pixMap.pixelSize <= 8) + if (packBitsData.pixMap.pixelSize <= 8) bytesPerPixel = 1; - else if (directBitsData.pixMap.pixelSize == 32) + else if (packBitsData.pixMap.pixelSize == 32) bytesPerPixel = 3; else - bytesPerPixel = directBitsData.pixMap.pixelSize / 8; + bytesPerPixel = packBitsData.pixMap.pixelSize / 8; _outputSurface = new Graphics::Surface(); _outputSurface->create(width, height, (bytesPerPixel == 1) ? PixelFormat::createFormatCLUT8() : _pixelFormat); byte *buffer = new byte[width * height * bytesPerPixel]; // Read in amount of data per row - for (uint16 i = 0; i < directBitsData.pixMap.bounds.height(); i++) { + for (uint16 i = 0; i < packBitsData.pixMap.bounds.height(); i++) { // NOTE: Compression 0 is "default". The format in SCI games is packed when 0. // In the future, we may need to have something to set the "default" packing // format, but this is good for now. - if (directBitsData.pixMap.packType == 1 || directBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte (on 24-bit) + if (packBitsData.pixMap.packType == 1 || packBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte (on 24-bit) // TODO: Finish this. Hasn't been needed (yet). error("Unpacked DirectBitsRect data (padded)"); - } else if (directBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte (on 24-bit) + } else if (packBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte (on 24-bit) // TODO: Finish this. Hasn't been needed (yet). error("Unpacked DirectBitsRect data (not padded)"); - } else if (directBitsData.pixMap.packType == 0 || directBitsData.pixMap.packType > 2) { // Packed - uint16 byteCount = (directBitsData.pixMap.rowBytes > 250) ? stream->readUint16BE() : stream->readByte(); - decodeDirectBitsLine(buffer + i * _outputSurface->w * bytesPerPixel, directBitsData.pixMap.rowBytes, stream->readStream(byteCount), directBitsData.pixMap.pixelSize, bytesPerPixel); + } else if (packBitsData.pixMap.packType == 0 || packBitsData.pixMap.packType > 2) { // Packed + uint16 byteCount = (packBitsData.pixMap.rowBytes > 250) ? stream->readUint16BE() : stream->readByte(); + unpackBitsLine(buffer + i * _outputSurface->w * bytesPerPixel, packBitsData.pixMap.rowBytes, stream->readStream(byteCount), packBitsData.pixMap.pixelSize, bytesPerPixel); } } @@ -264,7 +386,7 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, bool delete[] buffer; } -void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel) { +void PictDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel) { uint32 dataDecoded = 0; byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1; @@ -299,11 +421,16 @@ void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::Seekabl dataDecoded += length / 4; if (length != dataDecoded) - warning("Mismatched DirectBits read (%d/%d)", dataDecoded, length); + warning("Mismatched PackBits read (%d/%d)", dataDecoded, length); delete data; } +void PictDecoder::skipBitsRect(Common::SeekableReadStream *stream, bool hasPalette) { + // TODO + error("TODO: PICT-QuickTime mode: skip PackBitsRect/DirectBitsRect"); +} + void PictDecoder::outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel) { switch (bitsPerPixel) { case 1: diff --git a/graphics/pict.h b/graphics/pict.h index 485c88b733..b426c6ee35 100644 --- a/graphics/pict.h +++ b/graphics/pict.h @@ -23,6 +23,7 @@ #ifndef GRAPHICS_PICT_H #define GRAPHICS_PICT_H +#include "common/array.h" #include "common/rect.h" #include "common/scummsys.h" @@ -37,6 +38,8 @@ namespace Graphics { class JPEG; struct Surface; +#define DECLARE_OPCODE(x) void x(Common::SeekableReadStream *stream) + class PictDecoder { public: PictDecoder(Graphics::PixelFormat pixelFormat); @@ -70,13 +73,56 @@ private: byte _palette[256 * 3]; bool _isPaletted; Graphics::Surface *_outputSurface; + bool _continueParsing; - void decodeDirectBitsRect(Common::SeekableReadStream *stream, bool hasPalette); - void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel); + // Utility Functions + void unpackBitsRect(Common::SeekableReadStream *stream, bool hasPalette); + void unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel); + void skipBitsRect(Common::SeekableReadStream *stream, bool hasPalette); void decodeCompressedQuickTime(Common::SeekableReadStream *stream); void outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel); + + // Opcodes + typedef void (PictDecoder::*OpcodeProcPICT)(Common::SeekableReadStream *stream); + struct PICTOpcode { + PICTOpcode() { op = 0; proc = 0; desc = 0; } + PICTOpcode(uint16 o, OpcodeProcPICT p, const char *d) { op = o; proc = p; desc = d; } + uint16 op; + OpcodeProcPICT proc; + const char *desc; + }; + Common::Array _opcodes; + + // Common Opcodes + void setupOpcodesCommon(); + DECLARE_OPCODE(o_nop); + DECLARE_OPCODE(o_clip); + DECLARE_OPCODE(o_txFont); + DECLARE_OPCODE(o_txFace); + DECLARE_OPCODE(o_pnSize); + DECLARE_OPCODE(o_txSize); + DECLARE_OPCODE(o_txRatio); + DECLARE_OPCODE(o_versionOp); + DECLARE_OPCODE(o_longText); + DECLARE_OPCODE(o_longComment); + DECLARE_OPCODE(o_opEndPic); + DECLARE_OPCODE(o_headerOp); + + // Regular-mode Opcodes + void setupOpcodesNormal(); + DECLARE_OPCODE(on_packBitsRect); + DECLARE_OPCODE(on_directBitsRect); + DECLARE_OPCODE(on_compressedQuickTime); + + // QuickTime-mode Opcodes + void setupOpcodesQuickTime(); + DECLARE_OPCODE(oq_packBitsRect); + DECLARE_OPCODE(oq_directBitsRect); + DECLARE_OPCODE(oq_compressedQuickTime); }; +#undef DECLARE_OPCODE + } // End of namespace Graphics #endif -- cgit v1.2.3 From 161b4c9f2ba245249c16401bb0b0099e01b2273f Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 25 Sep 2011 20:17:33 -0400 Subject: GRAPHICS: Properly parse the CompressQuickTime header --- graphics/pict.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'graphics') diff --git a/graphics/pict.cpp b/graphics/pict.cpp index f768ecdf3e..718214cb22 100644 --- a/graphics/pict.cpp +++ b/graphics/pict.cpp @@ -453,13 +453,36 @@ void PictDecoder::outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel) { // Compressed QuickTime details can be found here: // http://developer.apple.com/legacy/mac/library/#documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/B-Chapter/2TheImageCompression.html // http://developer.apple.com/legacy/mac/library/#documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/F-Chapter/6WorkingwiththeImage.html -// I'm just ignoring that because Myst ME uses none of that extra stuff. The offset is always the same. void PictDecoder::decodeCompressedQuickTime(Common::SeekableReadStream *stream) { + // First, read all the fields from the opcode uint32 dataSize = stream->readUint32BE(); uint32 startPos = stream->pos(); - Common::SeekableReadStream *jpegStream = new Common::SeekableSubReadStream(stream, stream->pos() + 156, stream->pos() + dataSize); + /* uint16 version = */ stream->readUint16BE(); + + uint32 matrix[3][3]; + for (uint32 i = 0; i < 3; i++) + for (uint32 j = 0; j < 3; j++) + matrix[i][j] = stream->readUint32BE(); + + uint32 matteSize = stream->readUint32BE(); + stream->skip(8); // matte rect + /* uint16 transferMode = */ stream->readUint16BE(); + stream->skip(8); // src rect + /* uint32 accuracy = */ stream->readUint32BE(); + uint32 maskSize = stream->readUint32BE(); + + stream->skip(matteSize + maskSize); + + // Now we've reached the image descriptor, so read the relevant data from that + uint32 idStart = stream->pos(); + uint32 idSize = stream->readUint32BE(); + stream->skip(40); + uint32 jpegSize = stream->readUint32BE(); + stream->skip(idSize - (stream->pos() - idStart)); + + Common::SeekableReadStream *jpegStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + jpegSize); if (!_jpeg->read(jpegStream)) error("PictDecoder::decodeCompressedQuickTime(): Could not decode JPEG data"); -- cgit v1.2.3 From 8897c17884c846f225f751f4b2838dd0e15c7faa Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 25 Sep 2011 20:55:33 -0400 Subject: GRAPHICS: Add support for multiple CompressedQuickTime calls Several pegasus demos now show up correctly. Yay! :) --- graphics/pict.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 6 deletions(-) (limited to 'graphics') diff --git a/graphics/pict.cpp b/graphics/pict.cpp index 718214cb22..a4cc67f01c 100644 --- a/graphics/pict.cpp +++ b/graphics/pict.cpp @@ -173,6 +173,11 @@ void PictDecoder::on_compressedQuickTime(Common::SeekableReadStream *stream) { _opcodes.clear(); setupOpcodesQuickTime(); + // We set up the surface for JPEG here too + if (!_outputSurface) + _outputSurface = new Graphics::Surface(); + _outputSurface->create(_imageRect.width(), _imageRect.height(), _pixelFormat); + // We'll decode the first QuickTime data from here, but the QuickTime-specific // opcodes will take over from here on out. Normal opcodes, signing off. decodeCompressedQuickTime(stream); @@ -427,8 +432,50 @@ void PictDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadS } void PictDecoder::skipBitsRect(Common::SeekableReadStream *stream, bool hasPalette) { - // TODO - error("TODO: PICT-QuickTime mode: skip PackBitsRect/DirectBitsRect"); + // Step through a PackBitsRect/DirectBitsRect function + + if (!hasPalette) + stream->readUint32BE(); + + uint16 rowBytes = stream->readUint16BE(); + uint16 height = stream->readUint16BE(); + stream->readUint16BE(); + height = stream->readUint16BE() - height; + stream->readUint16BE(); + + uint16 packType; + uint16 pixelSize; + + // Top two bits signify PixMap vs BitMap + if (rowBytes & 0xC000) { + // PixMap + stream->readUint16BE(); + packType = stream->readUint16BE(); + stream->skip(14); + pixelSize = stream->readUint16BE(); + stream->skip(16); + + if (hasPalette) { + stream->readUint32BE(); + stream->readUint16BE(); + stream->skip((stream->readUint16BE() + 1) * 8); + } + + rowBytes &= 0x3FFF; + } else { + // BitMap + packType = 0; + pixelSize = 1; + } + + stream->skip(18); + + for (uint16 i = 0; i < height; i++) { + if (packType == 1 || packType == 2 || rowBytes < 8) + error("Unpacked PackBitsRect data"); + else if (packType == 0 || packType > 2) + stream->skip((rowBytes > 250) ? stream->readUint16BE() : stream->readByte()); + } } void PictDecoder::outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel) { @@ -461,33 +508,42 @@ void PictDecoder::decodeCompressedQuickTime(Common::SeekableReadStream *stream) /* uint16 version = */ stream->readUint16BE(); + // Read in the display matrix uint32 matrix[3][3]; for (uint32 i = 0; i < 3; i++) for (uint32 j = 0; j < 3; j++) matrix[i][j] = stream->readUint32BE(); + // We currently only support offseting images vertically from the matrix + uint16 xOffset = 0; + uint16 yOffset = matrix[2][1] >> 16; + uint32 matteSize = stream->readUint32BE(); stream->skip(8); // matte rect /* uint16 transferMode = */ stream->readUint16BE(); stream->skip(8); // src rect /* uint32 accuracy = */ stream->readUint32BE(); uint32 maskSize = stream->readUint32BE(); - + + // Skip the matte and mask stream->skip(matteSize + maskSize); // Now we've reached the image descriptor, so read the relevant data from that uint32 idStart = stream->pos(); uint32 idSize = stream->readUint32BE(); - stream->skip(40); + stream->skip(40); // miscellaneous stuff uint32 jpegSize = stream->readUint32BE(); - stream->skip(idSize - (stream->pos() - idStart)); + stream->skip(idSize - (stream->pos() - idStart)); // more useless stuff Common::SeekableReadStream *jpegStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + jpegSize); if (!_jpeg->read(jpegStream)) error("PictDecoder::decodeCompressedQuickTime(): Could not decode JPEG data"); - _outputSurface = _jpeg->getSurface(_pixelFormat); + Graphics::Surface *jpegSurface = _jpeg->getSurface(_pixelFormat); + + for (uint16 y = 0; y < jpegSurface->h; y++) + memcpy(_outputSurface->getBasePtr(0 + xOffset, y + yOffset), jpegSurface->getBasePtr(0, y), jpegSurface->w * _pixelFormat.bytesPerPixel); stream->seek(startPos + dataSize); delete jpegStream; -- cgit v1.2.3 From ec67dfae307736a4001bc76a64db47cc7e34f68f Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 30 Sep 2011 12:26:49 -0400 Subject: GRAPHICS: Add support for true 32bpp DirectBits images --- graphics/pict.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'graphics') diff --git a/graphics/pict.cpp b/graphics/pict.cpp index a4cc67f01c..b2d8140a5e 100644 --- a/graphics/pict.cpp +++ b/graphics/pict.cpp @@ -331,7 +331,7 @@ void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPal if (packBitsData.pixMap.pixelSize <= 8) bytesPerPixel = 1; else if (packBitsData.pixMap.pixelSize == 32) - bytesPerPixel = 3; + bytesPerPixel = packBitsData.pixMap.cmpCount; else bytesPerPixel = packBitsData.pixMap.pixelSize / 8; @@ -357,10 +357,12 @@ void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPal } } - if (bytesPerPixel == 1) { + switch (bytesPerPixel) { + case 1: // Just copy to the image memcpy(_outputSurface->pixels, buffer, _outputSurface->w * _outputSurface->h); - } else if (bytesPerPixel == 2) { + break; + case 2: // Convert from 16-bit to whatever surface we need for (uint16 y = 0; y < _outputSurface->h; y++) { for (uint16 x = 0; x < _outputSurface->w; x++) { @@ -373,7 +375,8 @@ void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPal *((uint32 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); } } - } else { + break; + case 3: // Convert from 24-bit (planar!) to whatever surface we need for (uint16 y = 0; y < _outputSurface->h; y++) { for (uint16 x = 0; x < _outputSurface->w; x++) { @@ -386,6 +389,22 @@ void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPal *((uint32 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); } } + break; + case 4: + // Convert from 32-bit (planar!) to whatever surface we need + for (uint16 y = 0; y < _outputSurface->h; y++) { + for (uint16 x = 0; x < _outputSurface->w; x++) { + byte r = *(buffer + y * _outputSurface->w * 4 + x); + byte g = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w + x); + byte b = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 2 + x); + byte a = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 3 + x); + if (_pixelFormat.bytesPerPixel == 2) + *((uint16 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.ARGBToColor(r, g, b, a); + else + *((uint32 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.ARGBToColor(r, g, b, a); + } + } + break; } delete[] buffer; @@ -421,7 +440,7 @@ void PictDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadS } } - // HACK: rowBytes is in 32-bit, but the data is 24-bit... + // HACK: Even if the data is 24-bit, rowBytes is still 32-bit if (bytesPerPixel == 3) dataDecoded += length / 4; -- cgit v1.2.3 From deab5b28753155863062746ef1239535f562fd0b Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 7 Oct 2011 11:11:00 -0400 Subject: GRAPHICS: Fix PICT buffer overflow --- graphics/pict.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/pict.cpp b/graphics/pict.cpp index b2d8140a5e..0f4dcd463f 100644 --- a/graphics/pict.cpp +++ b/graphics/pict.cpp @@ -337,7 +337,11 @@ void PictDecoder::unpackBitsRect(Common::SeekableReadStream *stream, bool hasPal _outputSurface = new Graphics::Surface(); _outputSurface->create(width, height, (bytesPerPixel == 1) ? PixelFormat::createFormatCLUT8() : _pixelFormat); - byte *buffer = new byte[width * height * bytesPerPixel]; + + // Create an temporary buffer, but allocate a bit more than we need to avoid overflow + // (align it to the next highest two-byte packed boundary, which may be more unpacked, + // as m68k and therefore QuickDraw is word-aligned) + byte *buffer = new byte[width * height * bytesPerPixel + (8 * 2 / packBitsData.pixMap.pixelSize)]; // Read in amount of data per row for (uint16 i = 0; i < packBitsData.pixMap.bounds.height(); i++) { -- cgit v1.2.3 From 627684ca73833117425f3fd9d2257efb2157cb3c Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 27 Oct 2011 19:20:02 -0400 Subject: GRAPHICS: Make drawThickLine take a thickness in both x and y directions --- graphics/primitives.cpp | 62 ++++++++++--------------------------------------- graphics/primitives.h | 2 +- 2 files changed, 13 insertions(+), 51 deletions(-) (limited to 'graphics') diff --git a/graphics/primitives.cpp b/graphics/primitives.cpp index 9834af65ba..b88db39f36 100644 --- a/graphics/primitives.cpp +++ b/graphics/primitives.cpp @@ -61,59 +61,21 @@ void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, i } } +void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data) { + assert(penX > 0 && penY > 0); -// FIXME: This is a limited version of thick line drawing -// it draws striped lines at some angles. Better algorithm could -// be found here: -// -// http://homepages.enterprise.net/murphy/thickline/index.html -// -// Feel free to replace it with better implementation -void drawThickLine(int x0, int y0, int x1, int y1, int thickness, int color, void (*plotProc)(int, int, int, void *), void *data) { - const bool steep = ABS(y1 - y0) > ABS(x1 - x0); - - if (steep) { - SWAP(x0, y0); - SWAP(x1, y1); - } - - float dx = x1 - x0; - float dy = y1 - y0; - float d = (float)sqrt(dx * dx + dy * dy); - - if (!d) + // Shortcut + if (penX == 1 && penY == 1) { + drawLine(x0, y0, x1, y1, color, plotProc, data); return; - - int thickX = (int)((float)thickness * dy / d / 2); - int thickY = (int)((float)thickness * dx / d / 2); - - const int delta_x = ABS(x1 - x0); - const int delta_y = ABS(y1 - y0); - const int delta_err = delta_y; - int x = x0; - int y = y0; - int err = 0; - - const int x_step = (x0 < x1) ? 1 : -1; - const int y_step = (y0 < y1) ? 1 : -1; - - if (steep) - drawLine(y - thickY, x + thickX, y + thickY, x - thickX, color, plotProc, data); - else - drawLine(x - thickX, y + thickY, x + thickX, y - thickY, color, plotProc, data); - - while (x != x1) { - x += x_step; - err += delta_err; - if (2 * err > delta_x) { - y += y_step; - err -= delta_x; - } - if (steep) - drawLine(y - thickY, x + thickX, y + thickY, x - thickX, color, plotProc, data); - else - drawLine(x - thickX, y + thickY, x + thickX, y - thickY, color, plotProc, data); } + + // TODO: Optimize this. It currently is a very naive way of handling + // thick lines since quite often it will be drawing to the same pixel + // multiple times. + for (int x = 0; x < penX; x++) + for (int y = 0; y < penY; y++) + drawLine(x0 + x, y0 + y, x1 + x, y1 + y, color, plotProc, data); } } // End of namespace Graphics diff --git a/graphics/primitives.h b/graphics/primitives.h index 0ab2dabcd8..f0780afc2e 100644 --- a/graphics/primitives.h +++ b/graphics/primitives.h @@ -25,7 +25,7 @@ namespace Graphics { void drawLine(int x0, int y0, int x1, int y1, int color, void (*plotProc)(int, int, int, void *), void *data); -void drawThickLine(int x0, int y0, int x1, int y1, int thickness, int color, void (*plotProc)(int, int, int, void *), void *data); +void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, int color, void (*plotProc)(int, int, int, void *), void *data); } // End of namespace Graphics -- cgit v1.2.3 From c2af197edb7719ca4d4ad77d778c135db6149ba4 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 27 Oct 2011 19:20:28 -0400 Subject: GRAPHICS: Add a Surface wrapper for drawThickLine --- graphics/surface.cpp | 11 +++++++++++ graphics/surface.h | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) (limited to 'graphics') diff --git a/graphics/surface.cpp b/graphics/surface.cpp index e0b25f22e9..c1c676ed0b 100644 --- a/graphics/surface.cpp +++ b/graphics/surface.cpp @@ -48,6 +48,17 @@ void Surface::drawLine(int x0, int y0, int x1, int y1, uint32 color) { error("Surface::drawLine: bytesPerPixel must be 1, 2, or 4"); } +void Surface::drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, uint32 color) { + if (format.bytesPerPixel == 1) + Graphics::drawThickLine(x0, y0, x1, y1, penX, penY, color, plotPoint, this); + else if (format.bytesPerPixel == 2) + Graphics::drawThickLine(x0, y0, x1, y1, penX, penY, color, plotPoint, this); + else if (format.bytesPerPixel == 4) + Graphics::drawThickLine(x0, y0, x1, y1, penX, penY, color, plotPoint, this); + else + error("Surface::drawThickLine: bytesPerPixel must be 1, 2, or 4"); +} + void Surface::create(uint16 width, uint16 height, const PixelFormat &f) { free(); diff --git a/graphics/surface.h b/graphics/surface.h index 018a283aad..9d91a601e4 100644 --- a/graphics/surface.h +++ b/graphics/surface.h @@ -142,9 +142,25 @@ struct Surface { * @param x1 The x coordinate of the end point. * @param y1 The y coordinate of the end point. * @param color The color of the line. + * @note This is just a wrapper around Graphics::drawLine */ void drawLine(int x0, int y0, int x1, int y1, uint32 color); + /** + * Draw a thick line. + * + * @param x0 The x coordinate of the start point. + * @param y0 The y coordiante of the start point. + * @param x1 The x coordinate of the end point. + * @param y1 The y coordinate of the end point. + * @param penX The width of the pen (thickness in the x direction) + * @param penY The height of the pen (thickness in the y direction) + * @param color The color of the line. + * @note This is just a wrapper around Graphics::drawThickLine + * @note The x/y coordinates of the start and end points are the upper-left most part of the pen + */ + void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, uint32 color); + /** * Draw a horizontal line. * -- cgit v1.2.3 From fdee01bf04f1d66e4365e39c871c4b00d7b78946 Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Wed, 28 Mar 2012 19:16:52 +0200 Subject: GRAPHICS: Don't try to delete static BDF data. --- graphics/fonts/bdf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/fonts/bdf.h b/graphics/fonts/bdf.h index 5b615cc043..b0166a2095 100644 --- a/graphics/fonts/bdf.h +++ b/graphics/fonts/bdf.h @@ -77,7 +77,7 @@ private: #define DEFINE_FONT(n) \ const BdfFont *n = 0; \ void create_##n() { \ - n = new BdfFont(desc, DisposeAfterUse::YES); \ + n = new BdfFont(desc, DisposeAfterUse::NO); \ } #define FORWARD_DECLARE_FONT(n) \ -- cgit v1.2.3 From 6d3927cd7a6e93452366085e179b156558f78a2b Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Wed, 28 Mar 2012 19:17:13 +0200 Subject: GRAPHICS: Take ownership of fonts passed to FontManager. --- graphics/fontman.cpp | 36 ++++++++++++++++++++++++++++++++++++ graphics/fontman.h | 5 ++++- 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/fontman.cpp b/graphics/fontman.cpp index 8d967d595f..99dd3d664f 100644 --- a/graphics/fontman.cpp +++ b/graphics/fontman.cpp @@ -47,6 +47,13 @@ FontManager::FontManager() { } FontManager::~FontManager() { + for (uint i = 0; i < _ownedFonts.size(); ++i) { + const Font *font = _ownedFonts[i]; + if (font == g_sysfont || font == g_sysfont_big || font == g_consolefont) + continue; + delete font; + } + delete g_sysfont; g_sysfont = 0; delete g_sysfont_big; @@ -90,6 +97,8 @@ bool FontManager::assignFontToName(const Common::String &name, const Font *font) Common::String lowercaseName = name; lowercaseName.toLowercase(); _fontMap[lowercaseName] = font; + if (Common::find(_ownedFonts.begin(), _ownedFonts.end(), font) == _ownedFonts.end()) + _ownedFonts.push_back(font); return true; } @@ -116,8 +125,35 @@ bool FontManager::setFont(FontUsage usage, const BdfFont *font) { void FontManager::removeFontName(const Common::String &name) { Common::String lowercaseName = name; lowercaseName.toLowercase(); + if (!_fontMap.contains(lowercaseName)) + return; + + const Font *font = _fontMap[lowercaseName]; _fontMap.erase(lowercaseName); + // Check if we still have a copy of this font in the map. + bool stillHasFont = false; + for (Common::HashMap::iterator i = _fontMap.begin(); i != _fontMap.end(); ++i) { + if (i->_value != font) + continue; + stillHasFont = true; + break; + } + + if (!stillHasFont) { + // We don't have a copy of the font, so remove it from our list and delete it. + stillHasFont = true; + for (uint i = 0; i < _ownedFonts.size(); ++i) { + if (_ownedFonts[i] != font) + continue; + stillHasFont = false; + _ownedFonts.remove_at(i); + break; + } + assert(!stillHasFont); + delete font; + } + // In case the current localized font is removed, we fall back to the // default font again. if (_localizedFontName == lowercaseName) diff --git a/graphics/fontman.h b/graphics/fontman.h index 42f7d856fa..b06ddea860 100644 --- a/graphics/fontman.h +++ b/graphics/fontman.h @@ -60,7 +60,9 @@ public: const Font *getFontByName(const Common::String &name) const; /** - * Associates a font object with an 'name' + * Associates a font object with an 'name'. + * The FontManager takes ownership of the provided font object + * and will delete it when necesssary. * * @param name the name of the font * @param font the font object @@ -111,6 +113,7 @@ private: ~FontManager(); Common::HashMap _fontMap; + Common::Array _ownedFonts; Common::String _localizedFontName; }; -- cgit v1.2.3 From b470c9af28752a1f360bf8c459ffd8fdcca3e6fb Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Wed, 28 Mar 2012 19:17:53 +0200 Subject: BASE: Free TTFLibrary singleton on shutdown. This uses a helper function because TTFLibrary is internal. --- graphics/fonts/ttf.cpp | 4 ++++ graphics/fonts/ttf.h | 2 ++ 2 files changed, 6 insertions(+) (limited to 'graphics') diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp index 7505f7913e..7f5c616710 100644 --- a/graphics/fonts/ttf.cpp +++ b/graphics/fonts/ttf.cpp @@ -70,6 +70,10 @@ private: bool _initialized; }; +void shutdownTTF() { + TTFLibrary::destroy(); +} + #define g_ttf ::Graphics::TTFLibrary::instance() TTFLibrary::TTFLibrary() : _library(), _initialized(false) { diff --git a/graphics/fonts/ttf.h b/graphics/fonts/ttf.h index 7222d6e112..ec7dbe04ef 100644 --- a/graphics/fonts/ttf.h +++ b/graphics/fonts/ttf.h @@ -34,6 +34,8 @@ namespace Graphics { class Font; Font *loadTTFFont(Common::SeekableReadStream &stream, int size, bool monochrome = false, const uint32 *mapping = 0); +void shutdownTTF(); + } // End of namespace Graphics #endif -- cgit v1.2.3 From e1f95983923ffcb0624eef1fa6cf552eb54fe647 Mon Sep 17 00:00:00 2001 From: D G Turner Date: Mon, 10 Oct 2011 01:54:33 +0100 Subject: GRAPHICS: Add YUV410 to RGB Conversion Functions, required for SVQ1. Thanks to clone2727 for these. --- graphics/yuv_to_rgb.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ graphics/yuv_to_rgb.h | 14 ++++++++++++ 2 files changed, 74 insertions(+) (limited to 'graphics') diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp index ac7f217fee..e0af267106 100644 --- a/graphics/yuv_to_rgb.cpp +++ b/graphics/yuv_to_rgb.cpp @@ -300,4 +300,64 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS convertYUV420ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } +#define OUTPUT_4_PIXEL_COLUMN() \ + PUT_PIXEL(*ySrc, dstPtr); \ + PUT_PIXEL(*(ySrc + yPitch), dstPtr + dstPitch); \ + PUT_PIXEL(*(ySrc + (yPitch << 1)), dstPtr + dstPitch * 2); \ + PUT_PIXEL(*(ySrc + (yPitch * 3)), dstPtr + dstPitch * 3); \ + ySrc++; \ + dstPtr += sizeof(PixelInt) + +template +void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { + int quarterHeight = yHeight >> 2; + int quarterWidth = yWidth >> 2; + + // Keep the tables in pointers here to avoid a dereference on each pixel + const int16 *Cr_r_tab = lookup->_colorTab; + const int16 *Cr_g_tab = Cr_r_tab + 256; + const int16 *Cb_g_tab = Cr_g_tab + 256; + const int16 *Cb_b_tab = Cb_g_tab + 256; + const uint32 *rgbToPix = lookup->_rgbToPix; + + for (int h = 0; h < quarterHeight; h++) { + for (int w = 0; w < quarterWidth; w++) { + register const uint32 *L; + + int16 cr_r = Cr_r_tab[*vSrc]; + int16 crb_g = Cr_g_tab[*vSrc] + Cb_g_tab[*uSrc]; + int16 cb_b = Cb_b_tab[*uSrc]; + ++uSrc; + ++vSrc; + + OUTPUT_4_PIXEL_COLUMN(); + OUTPUT_4_PIXEL_COLUMN(); + OUTPUT_4_PIXEL_COLUMN(); + OUTPUT_4_PIXEL_COLUMN(); + } + + dstPtr += dstPitch * 3; + ySrc += (yPitch << 2) - yWidth; + uSrc += uvPitch - quarterWidth; + vSrc += uvPitch - quarterWidth; + } +} + +void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { + // Sanity checks + assert(dst && dst->pixels); + assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); + assert(ySrc && uSrc && vSrc); + assert((yWidth & 3) == 0); + assert((yHeight & 3) == 0); + + const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format); + + // Use a templated function to avoid an if check on every pixel + if (dst->format.bytesPerPixel == 2) + convertYUV410ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + else + convertYUV410ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); +} + } // End of namespace Graphics diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index 8e025042dc..52ab2ebdfb 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -64,6 +64,20 @@ void convertYUV444ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS */ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); +/** + * Convert a YUV410 image to an RGB surface + * + * @param dst the destination surface + * @param ySrc the source of the y component + * @param uSrc the source of the u component + * @param vSrc the source of the v component + * @param yWidth the width of the y surface (must be divisible by 4) + * @param yHeight the height of the y surface (must be divisible by 4) + * @param yPitch the pitch of the y surface + * @param uvPitch the pitch of the u and v surfaces + */ +void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + } // End of namespace Graphics #endif -- cgit v1.2.3 From db52618833920648b3ced9e2e8a7d692a4aba08f Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 8 Apr 2012 08:58:42 -0400 Subject: GRAPHICS: Add comments on which engines use the decoders --- graphics/decoders/bmp.h | 7 +++++++ graphics/decoders/jpeg.h | 7 +++++++ graphics/decoders/pict.h | 7 +++++++ 3 files changed, 21 insertions(+) (limited to 'graphics') diff --git a/graphics/decoders/bmp.h b/graphics/decoders/bmp.h index e11b12fad6..6360aa81c9 100644 --- a/graphics/decoders/bmp.h +++ b/graphics/decoders/bmp.h @@ -19,6 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** + * @file + * Image decoder used in engines: + * - hugo + * - mohawk + */ + #ifndef GRAPHICS_DECODERS_BMP_H #define GRAPHICS_DECODERS_BMP_H diff --git a/graphics/decoders/jpeg.h b/graphics/decoders/jpeg.h index c566d5ad21..c74aa57ca1 100644 --- a/graphics/decoders/jpeg.h +++ b/graphics/decoders/jpeg.h @@ -20,6 +20,13 @@ * */ +/** + * @file + * Image decoder used in engines: + * - groovie + * - mohawk + */ + #ifndef GRAPHICS_JPEG_H #define GRAPHICS_JPEG_H diff --git a/graphics/decoders/pict.h b/graphics/decoders/pict.h index b1e45a6bc1..1d07df1ab9 100644 --- a/graphics/decoders/pict.h +++ b/graphics/decoders/pict.h @@ -20,6 +20,13 @@ * */ +/** + * @file + * Image decoder used in engines: + * - mohawk + * - sci + */ + #ifndef GRAPHICS_PICT_H #define GRAPHICS_PICT_H -- cgit v1.2.3 From 473a09786d0688e7ab9689be4f6e60172a288cb2 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 14 Apr 2012 17:06:31 -0400 Subject: GRAPHICS: Make YUV410 conversion code use bilinear interpolation SVQ1 no longer looks blocky and now looks a lot closer to what QuickTime outputs --- graphics/yuv_to_rgb.cpp | 65 +++++++++++++++++++++++++++---------------------- graphics/yuv_to_rgb.h | 5 ++++ 2 files changed, 41 insertions(+), 29 deletions(-) (limited to 'graphics') diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp index e0af267106..0abebf99a8 100644 --- a/graphics/yuv_to_rgb.cpp +++ b/graphics/yuv_to_rgb.cpp @@ -300,19 +300,8 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS convertYUV420ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } -#define OUTPUT_4_PIXEL_COLUMN() \ - PUT_PIXEL(*ySrc, dstPtr); \ - PUT_PIXEL(*(ySrc + yPitch), dstPtr + dstPitch); \ - PUT_PIXEL(*(ySrc + (yPitch << 1)), dstPtr + dstPitch * 2); \ - PUT_PIXEL(*(ySrc + (yPitch * 3)), dstPtr + dstPitch * 3); \ - ySrc++; \ - dstPtr += sizeof(PixelInt) - template void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { - int quarterHeight = yHeight >> 2; - int quarterWidth = yWidth >> 2; - // Keep the tables in pointers here to avoid a dereference on each pixel const int16 *Cr_r_tab = lookup->_colorTab; const int16 *Cr_g_tab = Cr_r_tab + 256; @@ -320,26 +309,44 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup const int16 *Cb_b_tab = Cb_g_tab + 256; const uint32 *rgbToPix = lookup->_rgbToPix; - for (int h = 0; h < quarterHeight; h++) { - for (int w = 0; w < quarterWidth; w++) { - register const uint32 *L; - - int16 cr_r = Cr_r_tab[*vSrc]; - int16 crb_g = Cr_g_tab[*vSrc] + Cb_g_tab[*uSrc]; - int16 cb_b = Cb_b_tab[*uSrc]; - ++uSrc; - ++vSrc; - - OUTPUT_4_PIXEL_COLUMN(); - OUTPUT_4_PIXEL_COLUMN(); - OUTPUT_4_PIXEL_COLUMN(); - OUTPUT_4_PIXEL_COLUMN(); + for (int y = 0; y < yHeight; y++) { + for (int x = 0; x < yWidth; x++) { + // Perform bilinear interpolation on the the chroma values + // Based on the algorithm found here: http://tech-algorithm.com/articles/bilinear-image-scaling/ + // Feel free to optimize further + int targetX = x >> 2; + int targetY = y >> 2; + int xDiff = x & 3; + int yDiff = y & 3; + int index = targetY * uvPitch + targetX; + + byte a = uSrc[index]; + byte b = uSrc[index + 1]; + byte c = uSrc[index + uvPitch]; + byte d = uSrc[index + uvPitch + 1]; + + byte u = (a * (4 - xDiff) * (4 - yDiff) + b * xDiff * (4 - yDiff) + + c * yDiff * (4 - xDiff) + d * xDiff * yDiff) >> 4; + + a = vSrc[index]; + b = vSrc[index + 1]; + c = vSrc[index + uvPitch]; + d = vSrc[index + uvPitch + 1]; + + byte v = (a * (4 - xDiff) * (4 - yDiff) + b * xDiff * (4 - yDiff) + + c * yDiff * (4 - xDiff) + d * xDiff * yDiff) >> 4; + + int16 cr_r = Cr_r_tab[v]; + int16 crb_g = Cr_g_tab[v] + Cb_g_tab[u]; + int16 cb_b = Cb_b_tab[u]; + const uint32 *L; + + PUT_PIXEL(ySrc[x], dstPtr); + dstPtr += sizeof(PixelInt); } - dstPtr += dstPitch * 3; - ySrc += (yPitch << 2) - yWidth; - uSrc += uvPitch - quarterWidth; - vSrc += uvPitch - quarterWidth; + dstPtr += dstPitch - yWidth * sizeof(PixelInt); + ySrc += yPitch; } } diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index 52ab2ebdfb..73a2c69d7d 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -67,6 +67,11 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS /** * Convert a YUV410 image to an RGB surface * + * Since the chroma has a very low resolution in 410, we perform bilinear scaling + * on the two chroma planes to produce the image. The chroma planes must have + * at least one extra row that can be read from in order to produce a proper + * image (filled with 0x80). This is required in order to speed up this function. + * * @param dst the destination surface * @param ySrc the source of the y component * @param uSrc the source of the u component -- cgit v1.2.3 From b2de2cf85582fe62b96fcf36006816e16d023511 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 16 Apr 2012 21:33:08 -0400 Subject: GRAPHICS: Improve the YUV410 conversion code speed some more --- graphics/yuv_to_rgb.cpp | 70 +++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 26 deletions(-) (limited to 'graphics') diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp index 0abebf99a8..78903d0cd8 100644 --- a/graphics/yuv_to_rgb.cpp +++ b/graphics/yuv_to_rgb.cpp @@ -300,6 +300,30 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS convertYUV420ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } +#define READ_QUAD(ptr, prefix) \ + byte prefix##A = ptr[index]; \ + byte prefix##B = ptr[index + 1]; \ + byte prefix##C = ptr[index + uvPitch]; \ + byte prefix##D = ptr[index + uvPitch + 1] + +#define DO_INTERPOLATION(out) \ + out = (out##A * (4 - xDiff) * (4 - yDiff) + out##B * xDiff * (4 - yDiff) + \ + out##C * yDiff * (4 - xDiff) + out##D * xDiff * yDiff) >> 4 + +#define DO_YUV410_PIXEL() \ + DO_INTERPOLATION(u); \ + DO_INTERPOLATION(v); \ + \ + cr_r = Cr_r_tab[v]; \ + crb_g = Cr_g_tab[v] + Cb_g_tab[u]; \ + cb_b = Cb_b_tab[u]; \ + \ + PUT_PIXEL(*ySrc, dstPtr); \ + dstPtr += sizeof(PixelInt); \ + \ + ySrc++; \ + xDiff++ + template void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Keep the tables in pointers here to avoid a dereference on each pixel @@ -309,47 +333,41 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup const int16 *Cb_b_tab = Cb_g_tab + 256; const uint32 *rgbToPix = lookup->_rgbToPix; + int quarterWidth = yWidth >> 2; + for (int y = 0; y < yHeight; y++) { - for (int x = 0; x < yWidth; x++) { + for (int x = 0; x < quarterWidth; x++) { // Perform bilinear interpolation on the the chroma values // Based on the algorithm found here: http://tech-algorithm.com/articles/bilinear-image-scaling/ // Feel free to optimize further - int targetX = x >> 2; int targetY = y >> 2; - int xDiff = x & 3; + int xDiff = 0; int yDiff = y & 3; - int index = targetY * uvPitch + targetX; - - byte a = uSrc[index]; - byte b = uSrc[index + 1]; - byte c = uSrc[index + uvPitch]; - byte d = uSrc[index + uvPitch + 1]; - - byte u = (a * (4 - xDiff) * (4 - yDiff) + b * xDiff * (4 - yDiff) + - c * yDiff * (4 - xDiff) + d * xDiff * yDiff) >> 4; - - a = vSrc[index]; - b = vSrc[index + 1]; - c = vSrc[index + uvPitch]; - d = vSrc[index + uvPitch + 1]; + int index = targetY * uvPitch + x; - byte v = (a * (4 - xDiff) * (4 - yDiff) + b * xDiff * (4 - yDiff) + - c * yDiff * (4 - xDiff) + d * xDiff * yDiff) >> 4; + // Declare some variables for the following macros + byte u, v; + int16 cr_r, crb_g, cb_b; + register const uint32 *L; - int16 cr_r = Cr_r_tab[v]; - int16 crb_g = Cr_g_tab[v] + Cb_g_tab[u]; - int16 cb_b = Cb_b_tab[u]; - const uint32 *L; + READ_QUAD(uSrc, u); + READ_QUAD(vSrc, v); - PUT_PIXEL(ySrc[x], dstPtr); - dstPtr += sizeof(PixelInt); + DO_YUV410_PIXEL(); + DO_YUV410_PIXEL(); + DO_YUV410_PIXEL(); + DO_YUV410_PIXEL(); } dstPtr += dstPitch - yWidth * sizeof(PixelInt); - ySrc += yPitch; + ySrc += yPitch - yWidth; } } +#undef READ_QUAD +#undef DO_INTERPOLATION +#undef DO_YUV410_PIXEL + void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); -- cgit v1.2.3 From c5363006edf0744adfd0b48a67389213b8bea9ba Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 19 Apr 2012 11:49:06 -0400 Subject: GRAPHICS: Only accept JPEG CompressedQuickTime PICT opcodes --- graphics/decoders/pict.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/decoders/pict.cpp b/graphics/decoders/pict.cpp index 957342084e..9963873b54 100644 --- a/graphics/decoders/pict.cpp +++ b/graphics/decoders/pict.cpp @@ -541,10 +541,14 @@ void PICTDecoder::decodeCompressedQuickTime(Common::SeekableReadStream &stream) // Now we've reached the image descriptor, so read the relevant data from that uint32 idStart = stream.pos(); uint32 idSize = stream.readUint32BE(); - stream.skip(40); // miscellaneous stuff + uint32 codec = stream.readUint32BE(); + stream.skip(36); // miscellaneous stuff uint32 jpegSize = stream.readUint32BE(); stream.skip(idSize - (stream.pos() - idStart)); // more useless stuff + if (codec != MKTAG('j', 'p', 'e', 'g')) + error("Unhandled CompressedQuickTime format '%s'", tag2str(codec)); + Common::SeekableSubReadStream jpegStream(&stream, stream.pos(), stream.pos() + jpegSize); JPEGDecoder jpeg; -- cgit v1.2.3 From 4d6f2875de900ea41663b99be0f148096561bf5d Mon Sep 17 00:00:00 2001 From: D G Turner Date: Sun, 22 Apr 2012 16:41:30 +0100 Subject: GRAPHICS: Fix BMP getPalette function definition. The BMP decoder getPalette function definition is now identical to the other image format decoders subclassed from ImageDecoder. This also fixes a overloaded virtual warning reported by salty-horse. --- graphics/decoders/bmp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/decoders/bmp.h b/graphics/decoders/bmp.h index 6360aa81c9..8a37538ee1 100644 --- a/graphics/decoders/bmp.h +++ b/graphics/decoders/bmp.h @@ -51,7 +51,7 @@ public: void destroy(); virtual bool loadStream(Common::SeekableReadStream &stream); virtual const Surface *getSurface() const { return _surface; } - virtual const byte *getPalette() { return _palette; } + const byte *getPalette() const { return _palette; } private: Surface *_surface; -- cgit v1.2.3 From 3b212fdb51c4933bbc7eeb827f514cd1e120b3c5 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 3 May 2012 23:25:00 +0200 Subject: GRAPHICS: Remove unused function ftFloor26_6 in ttf.cpp. --- graphics/fonts/ttf.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'graphics') diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp index 7f5c616710..96241e923c 100644 --- a/graphics/fonts/ttf.cpp +++ b/graphics/fonts/ttf.cpp @@ -43,10 +43,6 @@ namespace Graphics { namespace { -inline int ftFloor26_6(FT_Pos x) { - return x / 64; -} - inline int ftCeil26_6(FT_Pos x) { return (x + 63) / 64; } -- cgit v1.2.3 From e5808c740a62cb87a1ceeef7873af3b21e912c73 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 4 May 2012 23:18:28 -0400 Subject: GRAPHICS: Fix 32-bit DirectBits images --- graphics/decoders/pict.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/pict.cpp b/graphics/decoders/pict.cpp index 9963873b54..bdb733a87d 100644 --- a/graphics/decoders/pict.cpp +++ b/graphics/decoders/pict.cpp @@ -361,14 +361,14 @@ void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool hasPal memcpy(_outputSurface->pixels, buffer, _outputSurface->w * _outputSurface->h); break; case 2: - // Convert from 16-bit to whatever surface we need + // We have a 16-bit surface _outputSurface->create(width, height, PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); for (uint16 y = 0; y < _outputSurface->h; y++) for (uint16 x = 0; x < _outputSurface->w; x++) WRITE_UINT16(_outputSurface->getBasePtr(x, y), READ_UINT16(buffer + (y * _outputSurface->w + x) * 2)); break; case 3: - // Convert from 24-bit (planar!) to whatever surface we need + // We have a planar 24-bit surface _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); for (uint16 y = 0; y < _outputSurface->h; y++) { for (uint16 x = 0; x < _outputSurface->w; x++) { @@ -380,15 +380,18 @@ void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool hasPal } break; case 4: - // Convert from 32-bit (planar!) to whatever surface we need + // We have a planar 32-bit surface + // Note that we ignore the alpha channel since it seems to not be correct + // Mac OS X does not ignore it, but then displays it incorrectly. Photoshop + // does ignore it and displays it correctly. _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); for (uint16 y = 0; y < _outputSurface->h; y++) { for (uint16 x = 0; x < _outputSurface->w; x++) { - byte r = *(buffer + y * _outputSurface->w * 4 + x); - byte g = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w + x); - byte b = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 2 + x); - byte a = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 3 + x); - *((uint32 *)_outputSurface->getBasePtr(x, y)) = _outputSurface->format.ARGBToColor(r, g, b, a); + byte a = 0xFF; + byte r = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w + x); + byte g = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 2 + x); + byte b = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 3 + x); + *((uint32 *)_outputSurface->getBasePtr(x, y)) = _outputSurface->format.ARGBToColor(a, r, g, b); } } break; -- cgit v1.2.3 From d789df894552bf73709628f09a0282b462df797e Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 14 May 2012 00:49:10 -0400 Subject: GRAPHICS: Add palette start index and color count functions to ImageDecoder --- graphics/decoders/bmp.cpp | 12 +++++++----- graphics/decoders/bmp.h | 2 ++ graphics/decoders/image_decoder.h | 5 +++++ graphics/decoders/pict.cpp | 7 +++++-- graphics/decoders/pict.h | 2 ++ graphics/decoders/png.cpp | 4 +++- graphics/decoders/png.h | 1 + 7 files changed, 25 insertions(+), 8 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp index 0d44881d7c..5f764e1bd3 100644 --- a/graphics/decoders/bmp.cpp +++ b/graphics/decoders/bmp.cpp @@ -31,6 +31,7 @@ namespace Graphics { BitmapDecoder::BitmapDecoder() { _surface = 0; _palette = 0; + _paletteColorCount = 0; } BitmapDecoder::~BitmapDecoder() { @@ -44,6 +45,7 @@ void BitmapDecoder::destroy() { } delete[] _palette; _palette = 0; + _paletteColorCount = 0; } bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { @@ -95,16 +97,16 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { /* uint32 imageSize = */ stream.readUint32LE(); /* uint32 pixelsPerMeterX = */ stream.readUint32LE(); /* uint32 pixelsPerMeterY = */ stream.readUint32LE(); - uint32 colorsUsed = stream.readUint32LE(); + _paletteColorCount = stream.readUint32LE(); /* uint32 colorsImportant = */ stream.readUint32LE(); - if (colorsUsed == 0) - colorsUsed = 256; + if (_paletteColorCount == 0) + _paletteColorCount = 256; if (bitsPerPixel == 8) { // Read the palette - _palette = new byte[colorsUsed * 3]; - for (uint16 i = 0; i < colorsUsed; i++) { + _palette = new byte[_paletteColorCount * 3]; + for (uint16 i = 0; i < _paletteColorCount; i++) { _palette[i * 3 + 2] = stream.readByte(); _palette[i * 3 + 1] = stream.readByte(); _palette[i * 3 + 0] = stream.readByte(); diff --git a/graphics/decoders/bmp.h b/graphics/decoders/bmp.h index 8a37538ee1..59da682e4d 100644 --- a/graphics/decoders/bmp.h +++ b/graphics/decoders/bmp.h @@ -52,10 +52,12 @@ public: virtual bool loadStream(Common::SeekableReadStream &stream); virtual const Surface *getSurface() const { return _surface; } const byte *getPalette() const { return _palette; } + uint16 getPaletteColorCount() const { return _paletteColorCount; } private: Surface *_surface; byte *_palette; + uint16 _paletteColorCount; }; } // End of namespace Graphics diff --git a/graphics/decoders/image_decoder.h b/graphics/decoders/image_decoder.h index e768f7f9a2..7fa00749ff 100644 --- a/graphics/decoders/image_decoder.h +++ b/graphics/decoders/image_decoder.h @@ -78,6 +78,11 @@ public: * @return the decoded palette, or 0 if no palette is present */ virtual const byte *getPalette() const { return 0; } + + /** Return the starting index of the palette. */ + virtual byte getPaletteStartIndex() const { return 0; } + /** Return the number of colors in the palette. */ + virtual uint16 getPaletteColorCount() const { return 0; } }; } // End of namespace Graphics diff --git a/graphics/decoders/pict.cpp b/graphics/decoders/pict.cpp index bdb733a87d..7eddd3b893 100644 --- a/graphics/decoders/pict.cpp +++ b/graphics/decoders/pict.cpp @@ -38,6 +38,7 @@ namespace Graphics { PICTDecoder::PICTDecoder() { _outputSurface = 0; + _paletteColorCount = 0; } PICTDecoder::~PICTDecoder() { @@ -50,6 +51,8 @@ void PICTDecoder::destroy() { delete _outputSurface; _outputSurface = 0; } + + _paletteColorCount = 0; } #define OPCODE(a, b, c) _opcodes.push_back(PICTOpcode(a, &PICTDecoder::b, c)) @@ -298,9 +301,9 @@ void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool hasPal // See http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-267.html stream.readUint32BE(); // seed stream.readUint16BE(); // flags - uint16 colorCount = stream.readUint16BE() + 1; + _paletteColorCount = stream.readUint16BE() + 1; - for (uint32 i = 0; i < colorCount; i++) { + for (uint32 i = 0; i < _paletteColorCount; i++) { stream.readUint16BE(); _palette[i * 3] = stream.readUint16BE() >> 8; _palette[i * 3 + 1] = stream.readUint16BE() >> 8; diff --git a/graphics/decoders/pict.h b/graphics/decoders/pict.h index 1d07df1ab9..417a7c5134 100644 --- a/graphics/decoders/pict.h +++ b/graphics/decoders/pict.h @@ -57,6 +57,7 @@ public: void destroy(); const Surface *getSurface() const { return _outputSurface; } const byte *getPalette() const { return _palette; } + uint16 getPaletteColorCount() const { return _paletteColorCount; } struct PixMap { uint32 baseAddr; @@ -81,6 +82,7 @@ public: private: Common::Rect _imageRect; byte _palette[256 * 3]; + uint16 _paletteColorCount; Graphics::Surface *_outputSurface; bool _continueParsing; diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index b87b6fdc7a..492c69779f 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -99,7 +99,7 @@ enum PNGFilters { }; PNGDecoder::PNGDecoder() : _compressedBuffer(0), _compressedBufferSize(0), - _transparentColorSpecified(false), _outputSurface(0) { + _transparentColorSpecified(false), _outputSurface(0), _paletteEntries(0) { } PNGDecoder::~PNGDecoder() { @@ -112,6 +112,8 @@ void PNGDecoder::destroy() { delete _outputSurface; _outputSurface = 0; } + + _paletteEntries = 0; } bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { diff --git a/graphics/decoders/png.h b/graphics/decoders/png.h index 1da0bea1ab..ca204f6dd3 100644 --- a/graphics/decoders/png.h +++ b/graphics/decoders/png.h @@ -73,6 +73,7 @@ public: void destroy(); const Graphics::Surface *getSurface() const { return _outputSurface; } const byte *getPalette() const { return _palette; } + uint16 getPaletteColorCount() const { return _paletteEntries; } private: enum PNGColorType { -- cgit v1.2.3 From b253a05454cd4088a70ac1a90589ebf5db85ed5a Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 14 May 2012 00:59:50 -0400 Subject: GRAPHICS: Hide the WinCursor implementation --- graphics/wincursor.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ graphics/wincursor.h | 42 +----------------------------------------- 2 files changed, 41 insertions(+), 41 deletions(-) (limited to 'graphics') diff --git a/graphics/wincursor.cpp b/graphics/wincursor.cpp index 2db72a2874..1d599f7130 100644 --- a/graphics/wincursor.cpp +++ b/graphics/wincursor.cpp @@ -30,6 +30,46 @@ namespace Graphics { +/** A Windows cursor. */ +class WinCursor : public Cursor { +public: + WinCursor(); + ~WinCursor(); + + /** Return the cursor's width. */ + uint16 getWidth() const; + /** Return the cursor's height. */ + uint16 getHeight() const; + /** Return the cursor's hotspot's x coordinate. */ + uint16 getHotspotX() const; + /** Return the cursor's hotspot's y coordinate. */ + uint16 getHotspotY() const; + /** Return the cursor's transparent key. */ + byte getKeyColor() const; + + const byte *getSurface() const { return _surface; } + + const byte *getPalette() const { return _palette; } + byte getPaletteStartIndex() const { return 0; } + uint16 getPaletteCount() const { return 256; } + + /** Read the cursor's data out of a stream. */ + bool readFromStream(Common::SeekableReadStream &stream); + +private: + byte *_surface; + byte _palette[256 * 3]; + + uint16 _width; ///< The cursor's width. + uint16 _height; ///< The cursor's height. + uint16 _hotspotX; ///< The cursor's hotspot's x coordinate. + uint16 _hotspotY; ///< The cursor's hotspot's y coordinate. + byte _keyColor; ///< The cursor's transparent key + + /** Clear the cursor. */ + void clear(); +}; + WinCursor::WinCursor() { _width = 0; _height = 0; diff --git a/graphics/wincursor.h b/graphics/wincursor.h index e6b35dc80c..9e73e3a12f 100644 --- a/graphics/wincursor.h +++ b/graphics/wincursor.h @@ -36,46 +36,6 @@ class SeekableReadStream; namespace Graphics { -/** A Windows cursor. */ -class WinCursor : public Cursor { -public: - WinCursor(); - ~WinCursor(); - - /** Return the cursor's width. */ - uint16 getWidth() const; - /** Return the cursor's height. */ - uint16 getHeight() const; - /** Return the cursor's hotspot's x coordinate. */ - uint16 getHotspotX() const; - /** Return the cursor's hotspot's y coordinate. */ - uint16 getHotspotY() const; - /** Return the cursor's transparent key. */ - byte getKeyColor() const; - - const byte *getSurface() const { return _surface; } - - const byte *getPalette() const { return _palette; } - byte getPaletteStartIndex() const { return 0; } - uint16 getPaletteCount() const { return 256; } - - /** Read the cursor's data out of a stream. */ - bool readFromStream(Common::SeekableReadStream &stream); - -private: - byte *_surface; - byte _palette[256 * 3]; - - uint16 _width; ///< The cursor's width. - uint16 _height; ///< The cursor's height. - uint16 _hotspotX; ///< The cursor's hotspot's x coordinate. - uint16 _hotspotY; ///< The cursor's hotspot's y coordinate. - byte _keyColor; ///< The cursor's transparent key - - /** Clear the cursor. */ - void clear(); -}; - /** * A structure holding an array of cursors from a single Windows Executable cursor group. * @@ -91,7 +51,7 @@ struct WinCursorGroup { struct CursorItem { Common::WinResourceID id; - WinCursor *cursor; + Cursor *cursor; }; Common::Array cursors; -- cgit v1.2.3 From a401f0a19e09d7d00a3ee94d928db82e658b7b48 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 3 Jun 2012 02:02:57 +0200 Subject: ALL: Replace cursorTargetScale in OSystem API with a simple "do not scale" logic. All uses of the old target scale API actually wanted to disallow scaling of the mouse cursor. This commit adapts our API to this and thus simplifies backend implementations. Some backends, most notable the Wii and Android, did some implementation of the cursor target scale, which I didn't adapt yet. I added a TODO for the porters there. --- graphics/cursorman.cpp | 20 ++++++++++---------- graphics/cursorman.h | 14 ++++++++------ 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'graphics') diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp index 425714ea34..825b5c2e19 100644 --- a/graphics/cursorman.cpp +++ b/graphics/cursorman.cpp @@ -55,14 +55,14 @@ bool CursorManager::showMouse(bool visible) { return g_system->showMouse(visible); } -void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) { - Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format); +void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { + Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format); cur->_visible = isVisible(); _cursorStack.push(cur); if (buf) { - g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale, format); + g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format); } } @@ -75,7 +75,7 @@ void CursorManager::popCursor() { if (!_cursorStack.empty()) { cur = _cursorStack.top(); - g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_targetScale, &cur->_format); + g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_dontScale, &cur->_format); } g_system->showMouse(isVisible()); @@ -98,10 +98,10 @@ void CursorManager::popAllCursors() { g_system->showMouse(isVisible()); } -void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) { +void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { if (_cursorStack.empty()) { - pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format); + pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format); return; } @@ -131,7 +131,7 @@ void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, cur->_hotspotX = hotspotX; cur->_hotspotY = hotspotY; cur->_keycolor = keycolor; - cur->_targetScale = targetScale; + cur->_dontScale = dontScale; #ifdef USE_RGB_COLOR if (format) cur->_format = *format; @@ -139,7 +139,7 @@ void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, cur->_format = Graphics::PixelFormat::createFormatCLUT8(); #endif - g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale, format); + g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format); } bool CursorManager::supportsCursorPalettes() { @@ -225,7 +225,7 @@ void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint nu } } -CursorManager::Cursor::Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) { +CursorManager::Cursor::Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { #ifdef USE_RGB_COLOR if (!format) _format = Graphics::PixelFormat::createFormatCLUT8(); @@ -245,7 +245,7 @@ CursorManager::Cursor::Cursor(const byte *data, uint w, uint h, int hotspotX, in _height = h; _hotspotX = hotspotX; _hotspotY = hotspotY; - _targetScale = targetScale; + _dontScale = dontScale; } CursorManager::Cursor::~Cursor() { diff --git a/graphics/cursorman.h b/graphics/cursorman.h index 543a5d0a5c..852109d7e6 100644 --- a/graphics/cursorman.h +++ b/graphics/cursorman.h @@ -63,14 +63,15 @@ public: * @param hotspotY the hotspot Y coordinate * @param keycolor the color value for the transparent color. This may not exceed * the maximum color value as defined by format. - * @param targetScale the scale for which the cursor is designed + * @param dontScale Whether the cursor should never be scaled. An exception are high ppi displays, where the cursor + * would be too small to notice otherwise, these are allowed to scale the cursor anyway. * @param format a pointer to the pixel format which the cursor graphic uses, * CLUT8 will be used if this is NULL or not specified. * @note It is ok for the buffer to be a NULL pointer. It is sometimes * useful to push a "dummy" cursor and modify it later. The * cursor will be added to the stack, but not to the backend. */ - void pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale = 1, const Graphics::PixelFormat *format = NULL); + void pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); /** * Pop a cursor from the stack, and restore the previous one to the @@ -90,11 +91,12 @@ public: * @param hotspotY the hotspot Y coordinate * @param keycolor the color value for the transparent color. This may not exceed * the maximum color value as defined by format. - * @param targetScale the scale for which the cursor is designed + * @param dontScale Whether the cursor should never be scaled. An exception are high ppi displays, where the cursor + * would be too small to notice otherwise, these are allowed to scale the cursor anyway. * @param format a pointer to the pixel format which the cursor graphic uses, * CLUT8 will be used if this is NULL or not specified. */ - void replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale = 1, const Graphics::PixelFormat *format = NULL); + void replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); /** * Pop all of the cursors and cursor palettes from their respective stacks. @@ -175,11 +177,11 @@ private: int _hotspotY; uint32 _keycolor; Graphics::PixelFormat _format; - int _targetScale; + bool _dontScale; uint _size; - Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale = 1, const Graphics::PixelFormat *format = NULL); + Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); ~Cursor(); }; -- cgit v1.2.3 From 0075fa2f98eb3deb4674a4f1af95a84669098d7c Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 12 Jun 2012 04:13:00 +0200 Subject: GRAPHICS: Replace OverlayColor with uint16 in scaler code. Scalers are actually fixed at 2Bpp right now and not at the depth of OverlayColor. --- graphics/scaler.cpp | 9 ++++----- graphics/scaler/aspect.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'graphics') diff --git a/graphics/scaler.cpp b/graphics/scaler.cpp index 9ade0e6c57..b81e8937a8 100644 --- a/graphics/scaler.cpp +++ b/graphics/scaler.cpp @@ -167,12 +167,12 @@ void DestroyScalers(){ void Normal1x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { // Spot the case when it can all be done in 1 hit - if ((srcPitch == sizeof(OverlayColor) * (uint)width) && (dstPitch == sizeof(OverlayColor) * (uint)width)) { - memcpy(dstPtr, srcPtr, sizeof(OverlayColor) * width * height); + if ((srcPitch == sizeof(uint16) * (uint)width) && (dstPitch == sizeof(uint16) * (uint)width)) { + memcpy(dstPtr, srcPtr, sizeof(uint16) * width * height); return; } while (height--) { - memcpy(dstPtr, srcPtr, sizeof(OverlayColor) * width); + memcpy(dstPtr, srcPtr, sizeof(uint16) * width); srcPtr += srcPitch; dstPtr += dstPitch; } @@ -207,11 +207,10 @@ void Normal2x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPit uint8 *r; assert(IS_ALIGNED(dstPtr, 4)); - assert(sizeof(OverlayColor) == 2); while (height--) { r = dstPtr; for (int i = 0; i < width; ++i, r += 4) { - uint32 color = *(((const OverlayColor *)srcPtr) + i); + uint32 color = *(((const uint16 *)srcPtr) + i); color |= color << 16; diff --git a/graphics/scaler/aspect.cpp b/graphics/scaler/aspect.cpp index 7ad37b1ba8..f0ae732a40 100644 --- a/graphics/scaler/aspect.cpp +++ b/graphics/scaler/aspect.cpp @@ -160,14 +160,14 @@ int stretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, i #if ASPECT_MODE == kSuperFastAndUglyAspectMode if (srcPtr == dstPtr) break; - memcpy(dstPtr, srcPtr, sizeof(OverlayColor) * width); + memcpy(dstPtr, srcPtr, sizeof(uint16) * width); #else // Bilinear filter switch (y % 6) { case 0: case 5: if (srcPtr != dstPtr) - memcpy(dstPtr, srcPtr, sizeof(OverlayColor) * width); + memcpy(dstPtr, srcPtr, sizeof(uint16) * width); break; case 1: interpolate5Line((uint16 *)dstPtr, (const uint16 *)(srcPtr - pitch), (const uint16 *)srcPtr, width); @@ -206,13 +206,13 @@ void Normal1xAspectTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, #if ASPECT_MODE == kSuperFastAndUglyAspectMode if ((y % 6) == 5) srcPtr -= srcPitch; - memcpy(dstPtr, srcPtr, sizeof(OverlayColor) * width); + memcpy(dstPtr, srcPtr, sizeof(uint16) * width); #else // Bilinear filter five input lines onto six output lines switch (y % 6) { case 0: // First output line is copied from first input line - memcpy(dstPtr, srcPtr, sizeof(OverlayColor) * width); + memcpy(dstPtr, srcPtr, sizeof(uint16) * width); break; case 1: // Second output line is mixed from first and second input line @@ -233,7 +233,7 @@ void Normal1xAspectTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, case 5: // Sixth (and last) output line is copied from fifth (and last) input line srcPtr -= srcPitch; - memcpy(dstPtr, srcPtr, sizeof(OverlayColor) * width); + memcpy(dstPtr, srcPtr, sizeof(uint16) * width); break; } #endif -- cgit v1.2.3 From e1e1f01b873f0d8ed09abcda37789deb09ba83c5 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 16 Jun 2012 03:14:07 +0200 Subject: GRAPHICS: Let CursorMan's cursor functions take "const void *" buffers. --- graphics/cursorman.cpp | 6 +++--- graphics/cursorman.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'graphics') diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp index 825b5c2e19..c818101645 100644 --- a/graphics/cursorman.cpp +++ b/graphics/cursorman.cpp @@ -55,7 +55,7 @@ bool CursorManager::showMouse(bool visible) { return g_system->showMouse(visible); } -void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { +void CursorManager::pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format); cur->_visible = isVisible(); @@ -98,7 +98,7 @@ void CursorManager::popAllCursors() { g_system->showMouse(isVisible()); } -void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { +void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { if (_cursorStack.empty()) { pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format); @@ -225,7 +225,7 @@ void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint nu } } -CursorManager::Cursor::Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { +CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { #ifdef USE_RGB_COLOR if (!format) _format = Graphics::PixelFormat::createFormatCLUT8(); diff --git a/graphics/cursorman.h b/graphics/cursorman.h index 852109d7e6..66e8d1ba56 100644 --- a/graphics/cursorman.h +++ b/graphics/cursorman.h @@ -71,7 +71,7 @@ public: * useful to push a "dummy" cursor and modify it later. The * cursor will be added to the stack, but not to the backend. */ - void pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); + void pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); /** * Pop a cursor from the stack, and restore the previous one to the @@ -96,7 +96,7 @@ public: * @param format a pointer to the pixel format which the cursor graphic uses, * CLUT8 will be used if this is NULL or not specified. */ - void replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); + void replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); /** * Pop all of the cursors and cursor palettes from their respective stacks. @@ -181,7 +181,7 @@ private: uint _size; - Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); + Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); ~Cursor(); }; -- cgit v1.2.3 From aec9b9e22a9bff54ae3c39bb796bae0f4b4c2d95 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 16 Jun 2012 04:17:14 +0200 Subject: ALL: Let overlay related methods in OSystem take a void * and use a proper pitch values. This is a first step to get rid of OverlayColor, which is a requirement for proper 4Bpp overlay support. --- graphics/VectorRendererSpec.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'graphics') diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index 7817725664..1ed5a3308a 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -422,8 +422,8 @@ void VectorRendererSpec:: copyFrame(OSystem *sys, const Common::Rect &r) { sys->copyRectToOverlay( - (const OverlayColor *)_activeSurface->getBasePtr(r.left, r.top), - _activeSurface->pitch / _activeSurface->format.bytesPerPixel, + _activeSurface->getBasePtr(r.left, r.top), + _activeSurface->pitch, r.left, r.top, r.width(), r.height() ); } -- cgit v1.2.3 From 984e0012d9b96a752b40a008aa1689d43d9a9920 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 15 Jun 2012 23:11:28 -0400 Subject: GRAPHICS: Fix colorToARGB's alpha value when no alpha channel is present --- graphics/pixelformat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/pixelformat.h b/graphics/pixelformat.h index e0cf6ce401..ca4ef11c17 100644 --- a/graphics/pixelformat.h +++ b/graphics/pixelformat.h @@ -97,7 +97,7 @@ struct PixelFormat { } inline void colorToARGB(uint32 color, uint8 &a, uint8 &r, uint8 &g, uint8 &b) const { - a = ((color >> aShift) << aLoss) & 0xFF; + a = (aBits() == 0) ? 0xFF : (((color >> aShift) << aLoss) & 0xFF); r = ((color >> rShift) << rLoss) & 0xFF; g = ((color >> gShift) << gLoss) & 0xFF; b = ((color >> bShift) << bLoss) & 0xFF; -- cgit v1.2.3 From 50a93c2e711f169089f6cfc0e09b82be0cce3210 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 25 Jul 2012 21:07:19 +0200 Subject: GRAPHICS: Small formatting fixes in iff.cpp. --- graphics/iff.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'graphics') diff --git a/graphics/iff.cpp b/graphics/iff.cpp index 7434a6bebc..4011126bd3 100644 --- a/graphics/iff.cpp +++ b/graphics/iff.cpp @@ -68,7 +68,7 @@ void ILBMDecoder::loadBitmap(uint32 mode, byte *buffer, Common::ReadStream *stre Graphics::PackBitsReadStream packStream(*stream); // setup a buffer to hold enough data to build a line in the output - uint32 scanlineWidth = ((_header.width + 15)/16) << 1; + uint32 scanlineWidth = ((_header.width + 15) / 16) << 1; byte *scanline = new byte[scanlineWidth * _header.depth]; for (uint i = 0; i < _header.height; ++i) { @@ -82,7 +82,7 @@ void ILBMDecoder::loadBitmap(uint32 mode, byte *buffer, Common::ReadStream *stre out += outPitch; } - delete []scanline; + delete[] scanline; break; } @@ -121,15 +121,12 @@ void ILBMDecoder::planarToChunky(byte *out, uint32 outPitch, byte *in, uint32 in // then output the pixel according to the requested packing if (!packPlanes) { out[x] = pix; - } else - if (nPlanes == 1) { - out[x/8] |= (pix << (x & 7)); - } else - if (nPlanes == 2) { - out[x/4] |= (pix << ((x & 3) << 1)); - } else - if (nPlanes == 4) { - out[x/2] |= (pix << ((x & 1) << 2)); + } else if (nPlanes == 1) { + out[x / 8] |= (pix << (x & 7)); + } else if (nPlanes == 2) { + out[x / 4] |= (pix << ((x & 3) << 1)); + } else if (nPlanes == 4) { + out[x / 2] |= (pix << ((x & 1) << 2)); } } @@ -187,7 +184,7 @@ struct PBMLoader { _surface = &surface; _colors = colors; Common::IFFParser parser(&input); - Common::Functor1Mem< Common::IFFChunk&, bool, PBMLoader > c(this, &PBMLoader::callback); + Common::Functor1Mem c(this, &PBMLoader::callback); parser.parse(c); } @@ -251,7 +248,7 @@ uint32 PackBitsReadStream::read(void *dataPtr, uint32 dataSize) { for (uint32 j = 0; j < lenW; j++) { *out++ = _input->readByte(); } - for ( ; lenR > lenW; lenR--) { + for (; lenR > lenW; lenR--) { _input->readByte(); } } else { // len > 128 -- cgit v1.2.3 From b4196e48b16c458ef6564a051495525ff5a282f0 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 30 Jul 2012 21:31:14 +0200 Subject: GRAPHICS: Add a DPI parameter to loadTTFFont. Will be used by WME. --- graphics/fonts/ttf.cpp | 10 +++++----- graphics/fonts/ttf.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'graphics') diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp index 96241e923c..2b1dca1eae 100644 --- a/graphics/fonts/ttf.cpp +++ b/graphics/fonts/ttf.cpp @@ -101,7 +101,7 @@ public: TTFFont(); virtual ~TTFFont(); - bool load(Common::SeekableReadStream &stream, int size, bool monochrome, const uint32 *mapping); + bool load(Common::SeekableReadStream &stream, int size, uint dpi, bool monochrome, const uint32 *mapping); virtual int getFontHeight() const; @@ -157,7 +157,7 @@ TTFFont::~TTFFont() { } } -bool TTFFont::load(Common::SeekableReadStream &stream, int size, bool monochrome, const uint32 *mapping) { +bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, bool monochrome, const uint32 *mapping) { if (!g_ttf.isInitialized()) return false; @@ -195,7 +195,7 @@ bool TTFFont::load(Common::SeekableReadStream &stream, int size, bool monochrome // Check whether we have kerning support _hasKerning = (FT_HAS_KERNING(_face) != 0); - if (FT_Set_Char_Size(_face, 0, size * 64, 0, 0)) { + if (FT_Set_Char_Size(_face, 0, size * 64, dpi, dpi)) { delete[] _ttfFile; _ttfFile = 0; @@ -462,10 +462,10 @@ bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) { return true; } -Font *loadTTFFont(Common::SeekableReadStream &stream, int size, bool monochrome, const uint32 *mapping) { +Font *loadTTFFont(Common::SeekableReadStream &stream, int size, uint dpi, bool monochrome, const uint32 *mapping) { TTFFont *font = new TTFFont(); - if (!font->load(stream, size, monochrome, mapping)) { + if (!font->load(stream, size, dpi, monochrome, mapping)) { delete font; return 0; } diff --git a/graphics/fonts/ttf.h b/graphics/fonts/ttf.h index ec7dbe04ef..e1464b1f45 100644 --- a/graphics/fonts/ttf.h +++ b/graphics/fonts/ttf.h @@ -32,7 +32,7 @@ namespace Graphics { class Font; -Font *loadTTFFont(Common::SeekableReadStream &stream, int size, bool monochrome = false, const uint32 *mapping = 0); +Font *loadTTFFont(Common::SeekableReadStream &stream, int size, uint dpi = 0, bool monochrome = false, const uint32 *mapping = 0); void shutdownTTF(); -- cgit v1.2.3 From c839fd50b5ddfcceada8cbbd3046ce219df248a0 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 12 Aug 2012 17:44:23 -0400 Subject: GRAPHICS: Clarify format of the palette in ImageDecoder --- graphics/decoders/image_decoder.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'graphics') diff --git a/graphics/decoders/image_decoder.h b/graphics/decoders/image_decoder.h index 7fa00749ff..830645d361 100644 --- a/graphics/decoders/image_decoder.h +++ b/graphics/decoders/image_decoder.h @@ -75,6 +75,9 @@ public: * until destroy() or loadStream() is called, or until this ImageDecoder's * destructor is called. * + * The palette's format is the same as PaletteManager's palette + * (interleaved RGB values). + * * @return the decoded palette, or 0 if no palette is present */ virtual const byte *getPalette() const { return 0; } -- cgit v1.2.3 From 8982026661c5f64f67cb8565946d25f620dfb73c Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Mon, 13 Aug 2012 00:30:02 +0200 Subject: GRAPHICS: Add support for 32bpp BMPs --- graphics/decoders/bmp.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp index 5f764e1bd3..f15d4e2519 100644 --- a/graphics/decoders/bmp.cpp +++ b/graphics/decoders/bmp.cpp @@ -82,7 +82,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { /* uint16 planes = */ stream.readUint16LE(); uint16 bitsPerPixel = stream.readUint16LE(); - if (bitsPerPixel != 8 && bitsPerPixel != 24) { + if (bitsPerPixel != 8 && bitsPerPixel != 24 && bitsPerPixel != 32) { warning("%dbpp bitmaps not supported", bitsPerPixel); return false; } @@ -119,8 +119,8 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); - // BGRA for 24bpp - if (bitsPerPixel == 24) + // BGRA for 24bpp and 32 bpp + if (bitsPerPixel == 24 || bitsPerPixel == 32) format = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); _surface = new Graphics::Surface(); @@ -136,7 +136,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { stream.read(dst + (height - i - 1) * width, width); stream.skip(extraDataLength); } - } else { + } else if (bitsPerPixel == 24) { byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; for (int32 i = 0; i < height; i++) { @@ -150,6 +150,27 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { dst += format.bytesPerPixel; } + stream.skip(extraDataLength); + dst -= _surface->pitch * 2; + } + } else { // 32 bpp + byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; + + for (int32 i = 0; i < height; i++) { + for (uint32 j = 0; j < width; j++) { + byte b = stream.readByte(); + byte g = stream.readByte(); + byte r = stream.readByte(); + // Ignore the last byte, as in v3 it is unused + // and should thus NOT be used as alpha. + // ref: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376%28v=vs.85%29.aspx + stream.readByte(); + uint32 color = format.RGBToColor(r, g, b); + + *((uint32 *)dst) = color; + dst += format.bytesPerPixel; + } + stream.skip(extraDataLength); dst -= _surface->pitch * 2; } -- cgit v1.2.3 From af05b1b80edfc8674845d6e42c9872fea9eeb381 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Sun, 12 Aug 2012 23:50:25 +0200 Subject: GRAPHICS: Reimplement the PNG-decoder using libpng --- graphics/decoders/png.cpp | 578 +++++++++++++--------------------------------- graphics/decoders/png.h | 78 +------ 2 files changed, 159 insertions(+), 497 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index 492c69779f..f0471899a6 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -19,87 +19,23 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#include "common/scummsys.h" + +#ifdef USE_PNG +#include +#endif #include "graphics/decoders/png.h" #include "graphics/pixelformat.h" #include "graphics/surface.h" -#include "common/endian.h" -#include "common/memstream.h" #include "common/stream.h" -#include "common/types.h" -#include "common/util.h" -#include "common/zlib.h" - -// PNG decoder, based on the W3C specs: -// http://www.w3.org/TR/PNG/ -// Parts of the code have been adapted from LodePNG, by Lode Vandevenne: -// http://members.gamedev.net/lode/projects/LodePNG/ - -/* -LodePNG version 20101211 - -Copyright (c) 2005-2010 Lode Vandevenne - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ namespace Graphics { -enum PNGChunks { - // == Critical chunks ===================================================== - kChunkIHDR = MKTAG('I','H','D','R'), // Image header - kChunkIDAT = MKTAG('I','D','A','T'), // Image data - kChunkPLTE = MKTAG('P','L','T','E'), // Palette - kChunkIEND = MKTAG('I','E','N','D'), // Image trailer - // == Ancillary chunks ==================================================== - kChunktRNS = MKTAG('t','R','N','S') // Transparency - // All of the other ancillary chunks are ignored. They're added here for - // reference only. - // cHRM - Primary chromacities and white point - // gAMA - Image gamma - // iCCP - Embedded ICC profile - // sBIT - Significant bits - // sRGB - Standard RGB color space - // tEXT - Textual data - // sTXt - Compressed textual data - // iTXt - International textual data - // bKGD - Background color - // hIST - Image histogram - // pHYs - Physical pixel dimensions - // sPLT - Suggested palette - // tIME - Image last-modification time -}; - -// Refer to http://www.w3.org/TR/PNG/#9Filters -enum PNGFilters { - kFilterNone = 0, - kFilterSub = 1, - kFilterUp = 2, - kFilterAverage = 3, - kFilterPaeth = 4 -}; - -PNGDecoder::PNGDecoder() : _compressedBuffer(0), _compressedBufferSize(0), - _transparentColorSpecified(false), _outputSurface(0), _paletteEntries(0) { +PNGDecoder::PNGDecoder() : _outputSurface(0), _palette(0), _paletteColorCount(0) { } PNGDecoder::~PNGDecoder() { @@ -112,16 +48,43 @@ void PNGDecoder::destroy() { delete _outputSurface; _outputSurface = 0; } + delete[] _palette; + _palette = NULL; +} + +#ifdef USE_PNG +// libpng-error-handling: +void pngError(png_structp pngptr, png_const_charp errorMsg) { + error("%s", errorMsg); +} - _paletteEntries = 0; +void pngWarning(png_structp pngptr, png_const_charp warningMsg) { + warning("%s", warningMsg); } +// libpng-I/O-helper: +void pngReadFromStream(png_structp pngPtr, png_bytep data, png_size_t length) { + void *readIOptr = png_get_io_ptr(pngPtr); + Common::SeekableReadStream *stream = (Common::SeekableReadStream *)readIOptr; + stream->read(data, length); +} +#endif + +/* + * This code is based on Broken Sword 2.5 engine + * + * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer + * + * Licensed under GNU GPL v2 + * + */ + bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { +#ifdef USE_PNG destroy(); - uint32 chunkLength = 0, chunkType = 0; _stream = &stream; - + // First, check the PNG signature if (_stream->readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) { delete _stream; @@ -132,374 +95,143 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { return false; } - // Start reading chunks till we reach an IEND chunk - while (chunkType != kChunkIEND) { - // The chunk length does not include the type or CRC bytes - chunkLength = _stream->readUint32BE(); - chunkType = _stream->readUint32BE(); - - switch (chunkType) { - case kChunkIHDR: - readHeaderChunk(); - break; - case kChunkIDAT: - if (_compressedBufferSize == 0) { - _compressedBufferSize += chunkLength; - _compressedBuffer = (byte *)malloc(_compressedBufferSize); - _stream->read(_compressedBuffer, chunkLength); - } else { - // Expand the buffer - uint32 prevSize = _compressedBufferSize; - _compressedBufferSize += chunkLength; - byte *tmp = new byte[prevSize]; - memcpy(tmp, _compressedBuffer, prevSize); - free(_compressedBuffer); - _compressedBuffer = (byte *)malloc(_compressedBufferSize); - memcpy(_compressedBuffer, tmp, prevSize); - delete[] tmp; - _stream->read(_compressedBuffer + prevSize, chunkLength); - } - break; - case kChunkPLTE: // only available in indexed PNGs - if (_header.colorType != kIndexed) - error("A palette chunk has been found in a non-indexed PNG file"); - if (chunkLength % 3 != 0) - error("Palette chunk not divisible by 3"); - - _paletteEntries = chunkLength / 3; - _stream->read(_palette, _paletteEntries * 3); - memset(_paletteTransparency, 0xff, sizeof(_paletteTransparency)); - break; - case kChunkIEND: - // End of stream - break; - case kChunktRNS: - readTransparencyChunk(chunkLength); - break; - default: - // Skip the chunk content - _stream->skip(chunkLength); - break; - } - - if (chunkType != kChunkIEND) - _stream->skip(4); // skip the chunk CRC checksum + // The following is based on the guide provided in: + //http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3 + //http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf + // along with the png-loading code used in the sword25-engine. + png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!pngPtr) { + delete _stream; + return false; } - - // We no longer need the file stream, thus close it here - _stream = 0; - - // Unpack the compressed buffer - Common::MemoryReadStream *compData = new Common::MemoryReadStream(_compressedBuffer, _compressedBufferSize, DisposeAfterUse::YES); - _imageData = Common::wrapCompressedReadStream(compData); - - // Construct the final image - constructImage(); - - // Close the uncompressed stream, which will also delete the memory stream, - // and thus the original compressed buffer - delete _imageData; - - return true; -} - -/** - * Paeth predictor, used by PNG filter type 4 - * The parameters are of signed 16-bit integers, but should come - * from unsigned chars. The integers are only needed to make - * the paeth calculation correct. - * - * Taken from lodePNG, with a slight patch: - * http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx - */ -byte PNGDecoder::paethPredictor(int16 a, int16 b, int16 c) { - int16 pa = ABS(b - c); - int16 pb = ABS(a - c); - int16 pc = ABS(a + b - c - c); - - if (pa <= MIN(pb, pc)) - return (byte)a; - else if (pb <= pc) - return (byte)b; - else - return (byte)c; -} - -/** - * Unfilters a filtered PNG scan line. - * PNG filters are defined in: http://www.w3.org/TR/PNG/#9Filters - * Note that filters are always applied to bytes - * - * Taken from lodePNG - */ -void PNGDecoder::unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length) { - uint16 i; - - switch (filterType) { - case kFilterNone: // no change - for (i = 0; i < length; i++) - dest[i] = scanLine[i]; - break; - case kFilterSub: // add the bytes to the left - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + dest[i - byteWidth]; - break; - case kFilterUp: // add the bytes of the above scanline - if (prevLine) { - for (i = 0; i < length; i++) - dest[i] = scanLine[i] + prevLine[i]; - } else { - for (i = 0; i < length; i++) - dest[i] = scanLine[i]; - } - break; - case kFilterAverage: // average value of the left and top left - if (prevLine) { - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i] + prevLine[i] / 2; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + ((dest[i - byteWidth] + prevLine[i]) / 2); - } else { - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + dest[i - byteWidth] / 2; - } - break; - case kFilterPaeth: // Paeth filter: http://www.w3.org/TR/PNG/#9Filter-type-4-Paeth - if (prevLine) { - for(i = 0; i < byteWidth; i++) - dest[i] = (scanLine[i] + prevLine[i]); // paethPredictor(0, prevLine[i], 0) is always prevLine[i] - for(i = byteWidth; i < length; i++) - dest[i] = (scanLine[i] + paethPredictor(dest[i - byteWidth], prevLine[i], prevLine[i - byteWidth])); - } else { - for(i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for(i = byteWidth; i < length; i++) - dest[i] = (scanLine[i] + dest[i - byteWidth]); // paethPredictor(dest[i - byteWidth], 0, 0) is always dest[i - byteWidth] - } - break; - default: - error("Unknown line filter"); + png_infop infoPtr = png_create_info_struct(pngPtr); + if (!infoPtr) { + png_destroy_read_struct(&pngPtr, NULL, NULL); + delete _stream; + return false; } - -} - -int PNGDecoder::getBytesPerPixel() const { - return (getNumColorChannels() * _header.bitDepth + 7) / 8; -} - -void PNGDecoder::constructImage() { - assert (_header.bitDepth != 0); - - int bytesPerPixel = getBytesPerPixel(); - int pitch = bytesPerPixel * _header.width; - byte *unfilteredSurface = new byte[pitch * _header.height]; - byte *dest = unfilteredSurface; - uint16 scanLineWidth = (_header.width * getNumColorChannels() * _header.bitDepth + 7) / 8; - byte *scanLine = new byte[scanLineWidth]; - byte *prevLine = 0; - - switch(_header.interlaceType) { - case kNonInterlaced: - for (uint16 y = 0; y < _header.height; y++) { - byte filterType = _imageData->readByte(); - _imageData->read(scanLine, scanLineWidth); - unfilterScanLine(dest, scanLine, prevLine, bytesPerPixel, filterType, scanLineWidth); - prevLine = dest; - dest += pitch; - } - break; - case kInterlaced: - // Theoretically, this shouldn't be needed, as interlacing is only - // useful for web images. Interlaced PNG images require more complex - // handling, so unless having support for such images is needed, there - // is no reason to add support for them. - error("TODO: Support for interlaced PNG images"); - break; + png_infop endInfo = png_create_info_struct(pngPtr); + if (!endInfo) { + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + delete _stream; + return false; } - delete[] scanLine; + png_set_error_fn(pngPtr, NULL, pngError, pngWarning); + // TODO: The manual says errors should be handled via setjmp - constructOutput(unfilteredSurface); - delete[] unfilteredSurface; -} + png_set_read_fn(pngPtr, _stream, pngReadFromStream); + png_set_crc_action(pngPtr, PNG_CRC_DEFAULT, PNG_CRC_WARN_USE); + // We already verified the PNG-header + png_set_sig_bytes(pngPtr, 8); -Graphics::PixelFormat PNGDecoder::findPixelFormat() const { - // Try to find the best pixel format based on what we have here - // Which is basically 8bpp for paletted non-transparent - // and 32bpp for everything else + // Read PNG header + png_read_info(pngPtr, infoPtr); - switch (_header.colorType) { - case kIndexed: - if (!_transparentColorSpecified) - return Graphics::PixelFormat::createFormatCLUT8(); - // fall through - case kGrayScale: - case kTrueColor: - case kGrayScaleWithAlpha: - case kTrueColorWithAlpha: - // We'll go with standard RGBA 32-bit - return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); - } - - error("Unknown PNG color type"); - return Graphics::PixelFormat(); -} + // No handling for unknown chunks yet. + int bitDepth, colorType, width, height, interlaceType; + png_uint_32 w, h; + png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, &interlaceType, NULL, NULL); + width = w; + height = h; -void PNGDecoder::constructOutput(const byte *surface) { + // Allocate memory for the final image data. + // To keep memory framentation low this happens before allocating memory for temporary image data. _outputSurface = new Graphics::Surface(); - _outputSurface->create(_header.width, _header.height, findPixelFormat()); - const byte *src = surface; - byte a = 0xFF; - int bytesPerPixel = getBytesPerPixel(); - - if (_header.colorType != kIndexed) { - if (_header.colorType == kTrueColor || - _header.colorType == kTrueColorWithAlpha) { - if (bytesPerPixel != 3 && bytesPerPixel != 4) - error("Unsupported truecolor PNG format"); - } else if (_header.colorType == kGrayScale || - _header.colorType == kGrayScaleWithAlpha) { - if (bytesPerPixel != 1 && bytesPerPixel != 2) - error("Unsupported grayscale PNG format"); + // Images of all color formats except PNG_COLOR_TYPE_PALETTE + // will be transformed into ARGB images + if (colorType == PNG_COLOR_TYPE_PALETTE && !png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { + int numPalette = 0; + png_colorp palette = NULL; + uint32 success = png_get_PLTE(pngPtr, infoPtr, &palette, &numPalette); + if (success != PNG_INFO_PLTE) { + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + return false; } - - for (uint16 i = 0; i < _outputSurface->h; i++) { - for (uint16 j = 0; j < _outputSurface->w; j++) { - uint32 result = 0; - - switch (bytesPerPixel) { - case 1: // Grayscale - if (_transparentColorSpecified) - a = (src[0] == _transparentColor[0]) ? 0 : 0xFF; - result = _outputSurface->format.ARGBToColor(a, src[0], src[0], src[0]); - break; - case 2: // Grayscale + alpha - result = _outputSurface->format.ARGBToColor(src[1], src[0], src[0], src[0]); - break; - case 3: // RGB - if (_transparentColorSpecified) { - bool isTransparentColor = (src[0] == _transparentColor[0] && - src[1] == _transparentColor[1] && - src[2] == _transparentColor[2]); - a = isTransparentColor ? 0 : 0xFF; - } - - result = _outputSurface->format.ARGBToColor(a, src[0], src[1], src[2]); - break; - case 4: // RGBA - result = _outputSurface->format.ARGBToColor(src[3], src[0], src[1], src[2]); - break; - } - - *((uint32 *)_outputSurface->getBasePtr(j, i)) = result; - src += bytesPerPixel; - } + _paletteColorCount = numPalette; + _palette = new byte[_paletteColorCount * 3]; + for (int i = 0; i < _paletteColorCount; i++) { + _palette[(i * 3)] = palette[i].red; + _palette[(i * 3) + 1] = palette[i].green; + _palette[(i * 3) + 2] = palette[i].blue; + } + _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + png_set_packing(pngPtr); } else { - uint32 mask = (0xff >> (8 - _header.bitDepth)) << (8 - _header.bitDepth); - - // Convert the indexed surface to the target pixel format - for (uint16 i = 0; i < _outputSurface->h; i++) { - int data = 0; - int bitCount = 8; - const byte *src1 = src; - - for (uint16 j = 0; j < _outputSurface->w; j++) { - if (bitCount == 8) { - data = *src; - src++; - } - - byte index = (data & mask) >> (8 - _header.bitDepth); - data = (data << _header.bitDepth) & 0xff; - bitCount -= _header.bitDepth; - - if (bitCount == 0) - bitCount = 8; - - if (_transparentColorSpecified) { - byte r = _palette[index * 3 + 0]; - byte g = _palette[index * 3 + 1]; - byte b = _palette[index * 3 + 2]; - a = _paletteTransparency[index]; - *((uint32 *)_outputSurface->getBasePtr(j, i)) = _outputSurface->format.ARGBToColor(a, r, g, b); - } else { - *((byte *)_outputSurface->getBasePtr(j, i)) = index; - } - } - - src = src1 + _outputSurface->w; + _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); + if (!_outputSurface->pixels) { + error("Could not allocate memory for output image."); } - } -} + if (bitDepth == 16) + png_set_strip_16(pngPtr); + if (bitDepth < 8) + png_set_expand(pngPtr); + if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) + png_set_expand(pngPtr); + if (colorType == PNG_COLOR_TYPE_GRAY || + colorType == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(pngPtr); + + // PNGs are Big-Endian: +#ifdef SCUMM_LITTLE_ENDIAN + png_set_bgr(pngPtr); + png_set_swap_alpha(pngPtr); + if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) + png_set_filler(pngPtr, 0xff, PNG_FILLER_BEFORE); +#else + if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) + png_set_filler(pngPtr, 0xff, PNG_FILLER_AFTER); +#endif -void PNGDecoder::readHeaderChunk() { - _header.width = _stream->readUint32BE(); - _header.height = _stream->readUint32BE(); - _header.bitDepth = _stream->readByte(); - if (_header.bitDepth > 8) - error("Only PNGs with a bit depth of 1-8 bits are supported (i.e. PNG24)"); - _header.colorType = (PNGColorType)_stream->readByte(); - _header.compressionMethod = _stream->readByte(); - // Compression methods: http://www.w3.org/TR/PNG/#10Compression - // Only compression method 0 (deflate) is documented and supported - if (_header.compressionMethod != 0) - error("Unknown PNG compression method: %d", _header.compressionMethod); - _header.filterMethod = _stream->readByte(); - // Filter methods: http://www.w3.org/TR/PNG/#9Filters - // Only filter method 0 is documented and supported - if (_header.filterMethod != 0) - error("Unknown PNG filter method: %d", _header.filterMethod); - _header.interlaceType = (PNGInterlaceType)_stream->readByte(); -} - -byte PNGDecoder::getNumColorChannels() const { - switch (_header.colorType) { - case kGrayScale: - return 1; // Gray - case kTrueColor: - return 3; // RGB - case kIndexed: - return 1; // Indexed - case kGrayScaleWithAlpha: - return 2; // Gray + Alpha - case kTrueColorWithAlpha: - return 4; // RGBA - default: - error("Unknown color type"); } -} + + // After the transformations have been registered, the image data is read again. + png_read_update_info(pngPtr, infoPtr); + png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); + width = w; + height = h; + + if (interlaceType == PNG_INTERLACE_NONE) { + // PNGs without interlacing can simply be read row by row. + for (int i = 0; i < height; i++) { + png_read_row(pngPtr, (png_bytep)_outputSurface->getBasePtr(0, i), NULL); + } + } else { + // PNGs with interlacing require us to allocate an auxillary + // buffer with pointers to all row starts. + + // Allocate row pointer buffer + png_bytep *rowPtr = new png_bytep[height]; + if (!rowPtr) { + error("Could not allocate memory for row pointers."); + } + + // Initialize row pointers + for (int i = 0; i < height; i++) + rowPtr[i] = (png_bytep)_outputSurface->getBasePtr(0, i); + + // Read image data + png_read_image(pngPtr, rowPtr); + + // Free row pointer buffer + delete[] rowPtr; + } + + // Read additional data at the end. + png_read_end(pngPtr, NULL); -void PNGDecoder::readTransparencyChunk(uint32 chunkLength) { - _transparentColorSpecified = true; + // Destroy libpng structures + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - switch(_header.colorType) { - case kGrayScale: - _transparentColor[0] = _stream->readUint16BE(); - _transparentColor[1] = _transparentColor[0]; - _transparentColor[2] = _transparentColor[0]; - break; - case kTrueColor: - _transparentColor[0] = _stream->readUint16BE(); - _transparentColor[1] = _stream->readUint16BE(); - _transparentColor[2] = _stream->readUint16BE(); - break; - case kIndexed: - _stream->read(_paletteTransparency, chunkLength); + // We no longer need the file stream, thus close it here + _stream = 0; - // A transparency chunk may have less entries - // than the palette entries. The remaining ones - // are unmodified (set to 255). Check here: - // http://www.w3.org/TR/PNG/#11tRNS - break; - default: - error("Transparency chunk found in a PNG that has a separate transparency channel"); - } + return true; +#else + return false; +#endif } } // End of Graphics namespace diff --git a/graphics/decoders/png.h b/graphics/decoders/png.h index ca204f6dd3..e52ddabd7d 100644 --- a/graphics/decoders/png.h +++ b/graphics/decoders/png.h @@ -24,33 +24,12 @@ * PNG decoder used in engines: * - sword25 * Dependencies: - * - zlib + * - libpng */ #ifndef GRAPHICS_PNG_H #define GRAPHICS_PNG_H -// PNG decoder, based on the W3C specs: -// http://www.w3.org/TR/PNG/ -// Parts of the code have been adapted from LodePNG, by Lode Vandevenne: -// http://members.gamedev.net/lode/projects/LodePNG/ - -// All the numbers are BE: http://www.w3.org/TR/PNG/#7Integers-and-byte-order - -// Note: At the moment, this decoder only supports non-interlaced images, and -// does not support truecolor/grayscale images with 16bit depth. -// -// Theoretically, interlaced images shouldn't be needed for games, as -// interlacing is only useful for images in websites. -// -// PNG images with 16bit depth (i.e. 48bit images) are quite rare, and can -// theoretically contain more than 16.7 millions of colors (the so-called "deep -// color" representation). In essence, each of the R, G, B and A components in -// them is specified with 2 bytes, instead of 1. However, the PNG specification -// always refers to color components with 1 byte each, so this part of the spec -// is a bit unclear. For now, these won't be supported, until a suitable sample -// is found. - #include "common/scummsys.h" #include "common/textconsole.h" #include "graphics/decoders/image_decoder.h" @@ -73,62 +52,13 @@ public: void destroy(); const Graphics::Surface *getSurface() const { return _outputSurface; } const byte *getPalette() const { return _palette; } - uint16 getPaletteColorCount() const { return _paletteEntries; } - + uint16 getPaletteColorCount() const { return _paletteColorCount; } private: - enum PNGColorType { - kGrayScale = 0, // bit depths: 1, 2, 4, 8, 16 - kTrueColor = 2, // bit depths: 8, 16 - kIndexed = 3, // bit depths: 1, 2, 4, 8 - kGrayScaleWithAlpha = 4, // bit depths: 8, 16 - kTrueColorWithAlpha = 6 // bit depths: 8, 16 - }; - - enum PNGInterlaceType { - kNonInterlaced = 0, - kInterlaced = 1 - }; - - struct PNGHeader { - uint32 width; - uint32 height; - byte bitDepth; - PNGColorType colorType; - byte compressionMethod; - byte filterMethod; - PNGInterlaceType interlaceType; - }; - - void readHeaderChunk(); - byte getNumColorChannels() const; - - void readPaletteChunk(); - void readTransparencyChunk(uint32 chunkLength); - - void constructImage(); - void unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length); - byte paethPredictor(int16 a, int16 b, int16 c); - - // The original file stream Common::SeekableReadStream *_stream; - // The unzipped image data stream - Common::SeekableReadStream *_imageData; - - PNGHeader _header; - - byte _palette[256 * 3]; // RGB - byte _paletteTransparency[256]; - uint16 _paletteEntries; - uint16 _transparentColor[3]; - bool _transparentColorSpecified; - - byte *_compressedBuffer; - uint32 _compressedBufferSize; + byte *_palette; + uint16 _paletteColorCount; Graphics::Surface *_outputSurface; - Graphics::PixelFormat findPixelFormat() const; - int getBytesPerPixel() const; - void constructOutput(const byte *surface); }; } // End of namespace Graphics -- cgit v1.2.3 From 5df8c99768205ad6e2380dbc7cbc838e4ab5cc85 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 21 Aug 2012 02:17:45 +0200 Subject: GPRAHICS: Slight cleanup in png.cpp. This adds an explanation why we use FORBIDDEN_SYMBOL_ALLOW_ALL and removes some trailing whitespaces. --- graphics/decoders/png.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index f0471899a6..bfaab6dc35 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -19,6 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ + +// Since we need to work with libpng here, we need to allow all symbols +// to avoid compilation issues. #define FORBIDDEN_SYMBOL_ALLOW_ALL #include "common/scummsys.h" @@ -84,7 +87,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { destroy(); _stream = &stream; - + // First, check the PNG signature if (_stream->readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) { delete _stream; @@ -155,7 +158,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { _palette[(i * 3)] = palette[i].red; _palette[(i * 3) + 1] = palette[i].green; _palette[(i * 3) + 2] = palette[i].blue; - + } _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); png_set_packing(pngPtr); @@ -173,7 +176,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(pngPtr); - + // PNGs are Big-Endian: #ifdef SCUMM_LITTLE_ENDIAN png_set_bgr(pngPtr); @@ -186,7 +189,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { #endif } - + // After the transformations have been registered, the image data is read again. png_read_update_info(pngPtr, infoPtr); png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); @@ -201,24 +204,24 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { } else { // PNGs with interlacing require us to allocate an auxillary // buffer with pointers to all row starts. - + // Allocate row pointer buffer png_bytep *rowPtr = new png_bytep[height]; if (!rowPtr) { error("Could not allocate memory for row pointers."); } - + // Initialize row pointers for (int i = 0; i < height; i++) rowPtr[i] = (png_bytep)_outputSurface->getBasePtr(0, i); - + // Read image data png_read_image(pngPtr, rowPtr); - + // Free row pointer buffer delete[] rowPtr; } - + // Read additional data at the end. png_read_end(pngPtr, NULL); -- cgit v1.2.3 From 05d24e892c15a0bc2a8a923927125098704f42db Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 03:35:54 +0200 Subject: GRAPHICS: Clean up crossBlit a bit. --- graphics/conversion.cpp | 57 +++++++++++++++++++++++++------------------------ graphics/conversion.h | 6 ++++-- 2 files changed, 33 insertions(+), 30 deletions(-) (limited to 'graphics') diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index 713a06ea74..705f672a93 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -27,8 +27,10 @@ namespace Graphics { // TODO: YUV to RGB conversion function // Function to blit a rect from one color format to another -bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, - int w, int h, const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) { +bool crossBlit(byte *dst, const byte *src, + const uint dstPitch, const uint srcPitch, + const uint w, const uint h, + const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) { // Error out if conversion is impossible if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1) || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel) @@ -37,32 +39,31 @@ bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, // Don't perform unnecessary conversion if (srcFmt == dstFmt) { - if (dst == src) - return true; - if (dstpitch == srcpitch && ((w * dstFmt.bytesPerPixel) == dstpitch)) { - memcpy(dst,src,dstpitch * h); - return true; - } else { - for (int i = 0; i < h; i++) { - memcpy(dst,src,w * dstFmt.bytesPerPixel); - dst += dstpitch; - src += srcpitch; + if (dst != src) { + if (dstPitch == srcPitch && ((w * dstFmt.bytesPerPixel) == dstPitch)) { + memcpy(dst, src, dstPitch * h); + } else { + for (uint i = 0; i < h; ++i) { + memcpy(dst, src, w * dstFmt.bytesPerPixel); + dst += dstPitch; + src += srcPitch; + } } - return true; } + + return true; } // Faster, but larger, to provide optimized handling for each case. - int srcDelta, dstDelta; - srcDelta = (srcpitch - w * srcFmt.bytesPerPixel); - dstDelta = (dstpitch - w * dstFmt.bytesPerPixel); + const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel); + const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel); // TODO: optimized cases for dstDelta of 0 uint8 r, g, b, a; if (dstFmt.bytesPerPixel == 2) { uint16 color; - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++, src += 2, dst += 2) { + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x, src += 2, dst += 2) { color = *(const uint16 *)src; srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); @@ -78,8 +79,8 @@ bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, col++; #endif if (srcFmt.bytesPerPixel == 2) { - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++, src += 2, dst += 3) { + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x, src += 2, dst += 3) { color = *(const uint16 *)src; srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); @@ -89,8 +90,8 @@ bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, dst += dstDelta; } } else { - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++, src += 3, dst += 3) { + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x, src += 3, dst += 3) { memcpy(col, src, 3); srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); @@ -103,8 +104,8 @@ bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, } else if (dstFmt.bytesPerPixel == 4) { uint32 color; if (srcFmt.bytesPerPixel == 2) { - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++, src += 2, dst += 4) { + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x, src += 2, dst += 4) { color = *(const uint16 *)src; srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); @@ -118,8 +119,8 @@ bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, #ifdef SCUMM_BIG_ENDIAN col++; #endif - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++, src += 2, dst += 4) { + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x, src += 2, dst += 4) { memcpy(col, src, 3); srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); @@ -129,8 +130,8 @@ bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, dst += dstDelta; } } else { - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++, src += 4, dst += 4) { + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x, src += 4, dst += 4) { color = *(const uint32 *)src; srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); diff --git a/graphics/conversion.h b/graphics/conversion.h index 6babc763e2..c25f413fab 100644 --- a/graphics/conversion.h +++ b/graphics/conversion.h @@ -66,8 +66,10 @@ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) { * destination format have the same bytedepth. * */ -bool crossBlit(byte *dst, const byte *src, int dstpitch, int srcpitch, - int w, int h, const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt); +bool crossBlit(byte *dst, const byte *src, + const uint dstPitch, const uint srcPitch, + const uint w, const uint h, + const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt); } // End of namespace Graphics -- cgit v1.2.3 From ea1bcaad3380132356adb567826e74e587c389cd Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 04:53:10 +0200 Subject: GRAPHICS: Refactor crossBlit logic into a template. --- graphics/conversion.cpp | 62 +++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) (limited to 'graphics') diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index 705f672a93..7b6bda30a4 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -26,6 +26,29 @@ namespace Graphics { // TODO: YUV to RGB conversion function +namespace { + +template +FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const uint h, + const PixelFormat &srcFmt, const PixelFormat &dstFmt, + const uint srcDelta, const uint dstDelta) { + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x) { + uint32 color = *(const SrcColor *)src; + byte a, r, g, b; + srcFmt.colorToARGB(color, a, r, g, b); + color = dstFmt.ARGBToColor(a, r, g, b); + *(DstColor *)dst = color; + src += sizeof(SrcColor); + dst += sizeof(DstColor); + } + src += srcDelta; + dst += dstDelta; + } +} + +} // End of anonymous namespace + // Function to blit a rect from one color format to another bool crossBlit(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, @@ -59,21 +82,11 @@ bool crossBlit(byte *dst, const byte *src, const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel); // TODO: optimized cases for dstDelta of 0 - uint8 r, g, b, a; if (dstFmt.bytesPerPixel == 2) { - uint16 color; - for (uint y = 0; y < h; ++y) { - for (uint x = 0; x < w; ++x, src += 2, dst += 2) { - color = *(const uint16 *)src; - srcFmt.colorToARGB(color, a, r, g, b); - color = dstFmt.ARGBToColor(a, r, g, b); - *(uint16 *)dst = color; - } - src += srcDelta; - dst += dstDelta; - } + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else if (dstFmt.bytesPerPixel == 3) { uint32 color; + uint8 r, g, b, a; uint8 *col = (uint8 *) &color; #ifdef SCUMM_BIG_ENDIAN col++; @@ -102,19 +115,11 @@ bool crossBlit(byte *dst, const byte *src, } } } else if (dstFmt.bytesPerPixel == 4) { - uint32 color; if (srcFmt.bytesPerPixel == 2) { - for (uint y = 0; y < h; ++y) { - for (uint x = 0; x < w; ++x, src += 2, dst += 4) { - color = *(const uint16 *)src; - srcFmt.colorToARGB(color, a, r, g, b); - color = dstFmt.ARGBToColor(a, r, g, b); - *(uint32 *)dst = color; - } - src += srcDelta; - dst += dstDelta; - } + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else if (srcFmt.bytesPerPixel == 3) { + uint32 color; + byte r, g, b, a; uint8 *col = (uint8 *)&color; #ifdef SCUMM_BIG_ENDIAN col++; @@ -130,16 +135,7 @@ bool crossBlit(byte *dst, const byte *src, dst += dstDelta; } } else { - for (uint y = 0; y < h; ++y) { - for (uint x = 0; x < w; ++x, src += 4, dst += 4) { - color = *(const uint32 *)src; - srcFmt.colorToARGB(color, a, r, g, b); - color = dstFmt.ARGBToColor(a, r, g, b); - *(uint32 *)dst = color; - } - src += srcDelta; - dst += dstDelta; - } + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } } else { return false; -- cgit v1.2.3 From a0f46e9396861b9eb4ab8adebcbc4739e44b9716 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 04:53:37 +0200 Subject: GRAPHICS: Remove 3Bpp destination support in crossBlit. --- graphics/conversion.cpp | 31 +------------------------------ graphics/conversion.h | 1 + 2 files changed, 2 insertions(+), 30 deletions(-) (limited to 'graphics') diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index 7b6bda30a4..84f9bcbb9c 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -56,6 +56,7 @@ bool crossBlit(byte *dst, const byte *src, const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) { // Error out if conversion is impossible if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1) + || (dstFmt.bytesPerPixel == 3) || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel) || (srcFmt.bytesPerPixel > dstFmt.bytesPerPixel)) return false; @@ -84,36 +85,6 @@ bool crossBlit(byte *dst, const byte *src, // TODO: optimized cases for dstDelta of 0 if (dstFmt.bytesPerPixel == 2) { crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); - } else if (dstFmt.bytesPerPixel == 3) { - uint32 color; - uint8 r, g, b, a; - uint8 *col = (uint8 *) &color; -#ifdef SCUMM_BIG_ENDIAN - col++; -#endif - if (srcFmt.bytesPerPixel == 2) { - for (uint y = 0; y < h; ++y) { - for (uint x = 0; x < w; ++x, src += 2, dst += 3) { - color = *(const uint16 *)src; - srcFmt.colorToARGB(color, a, r, g, b); - color = dstFmt.ARGBToColor(a, r, g, b); - memcpy(dst, col, 3); - } - src += srcDelta; - dst += dstDelta; - } - } else { - for (uint y = 0; y < h; ++y) { - for (uint x = 0; x < w; ++x, src += 3, dst += 3) { - memcpy(col, src, 3); - srcFmt.colorToARGB(color, a, r, g, b); - color = dstFmt.ARGBToColor(a, r, g, b); - memcpy(dst, col, 3); - } - src += srcDelta; - dst += dstDelta; - } - } } else if (dstFmt.bytesPerPixel == 4) { if (srcFmt.bytesPerPixel == 2) { crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); diff --git a/graphics/conversion.h b/graphics/conversion.h index c25f413fab..8fcb6ba12d 100644 --- a/graphics/conversion.h +++ b/graphics/conversion.h @@ -59,6 +59,7 @@ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) { * @return true if conversion completes successfully, * false if there is an error. * + * @note Blitting to a 3Bpp destination is not supported * @note This implementation currently arbitrarily requires that the * destination's format have at least as high a bytedepth as * the source's. -- cgit v1.2.3 From 3a55adbf5eaf2d80b48de4ff680452996cc3d1a8 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 05:09:19 +0200 Subject: GRAPHICS: Fix a bug in crossBlit with 3Bpp source. Formerly it added 2 to the source pixel pointer instead of 3. --- graphics/conversion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index 84f9bcbb9c..db99679d41 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -96,7 +96,7 @@ bool crossBlit(byte *dst, const byte *src, col++; #endif for (uint y = 0; y < h; ++y) { - for (uint x = 0; x < w; ++x, src += 2, dst += 4) { + for (uint x = 0; x < w; ++x, src += 3, dst += 4) { memcpy(col, src, 3); srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); -- cgit v1.2.3 From 0d78d46a0e82af81681727a94e01ff5f309887fa Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 05:12:31 +0200 Subject: GRAPHICS: Remove crossBlit's dstBpp >= srcBpp limitation. --- graphics/conversion.cpp | 54 ++++++++++++++++++++++++++++++++----------------- graphics/conversion.h | 3 --- 2 files changed, 35 insertions(+), 22 deletions(-) (limited to 'graphics') diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index db99679d41..ece1f759d9 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -22,6 +22,8 @@ #include "graphics/conversion.h" #include "graphics/pixelformat.h" +#include "common/endian.h" + namespace Graphics { // TODO: YUV to RGB conversion function @@ -47,6 +49,30 @@ FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const } } +template +FORCEINLINE void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint w, const uint h, + const PixelFormat &srcFmt, const PixelFormat &dstFmt, + const uint srcDelta, const uint dstDelta) { + uint32 color; + byte r, g, b, a; + uint8 *col = (uint8 *)&color; +#ifdef SCUMM_BIG_ENDIAN + col++; +#endif + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x) { + memcpy(col, src, 3); + srcFmt.colorToARGB(color, a, r, g, b); + color = dstFmt.ARGBToColor(a, r, g, b); + *(DstColor *)dst = color; + src += 3; + dst += sizeof(DstColor); + } + src += srcDelta; + dst += dstDelta; + } +} + } // End of anonymous namespace // Function to blit a rect from one color format to another @@ -57,8 +83,7 @@ bool crossBlit(byte *dst, const byte *src, // Error out if conversion is impossible if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 3) - || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel) - || (srcFmt.bytesPerPixel > dstFmt.bytesPerPixel)) + || (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel)) return false; // Don't perform unnecessary conversion @@ -84,27 +109,18 @@ bool crossBlit(byte *dst, const byte *src, // TODO: optimized cases for dstDelta of 0 if (dstFmt.bytesPerPixel == 2) { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + if (srcFmt.bytesPerPixel == 2) { + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + } else if (srcFmt.bytesPerPixel == 3) { + crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + } else { + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + } } else if (dstFmt.bytesPerPixel == 4) { if (srcFmt.bytesPerPixel == 2) { crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else if (srcFmt.bytesPerPixel == 3) { - uint32 color; - byte r, g, b, a; - uint8 *col = (uint8 *)&color; -#ifdef SCUMM_BIG_ENDIAN - col++; -#endif - for (uint y = 0; y < h; ++y) { - for (uint x = 0; x < w; ++x, src += 3, dst += 4) { - memcpy(col, src, 3); - srcFmt.colorToARGB(color, a, r, g, b); - color = dstFmt.ARGBToColor(a, r, g, b); - *(uint32 *)dst = color; - } - src += srcDelta; - dst += dstDelta; - } + crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else { crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } diff --git a/graphics/conversion.h b/graphics/conversion.h index 8fcb6ba12d..0dce3cf279 100644 --- a/graphics/conversion.h +++ b/graphics/conversion.h @@ -60,9 +60,6 @@ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) { * false if there is an error. * * @note Blitting to a 3Bpp destination is not supported - * @note This implementation currently arbitrarily requires that the - * destination's format have at least as high a bytedepth as - * the source's. * @note This can convert a rectangle in place, if the source and * destination format have the same bytedepth. * -- cgit v1.2.3 From a92a509ac844fdad796748848d1143b27547173f Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 05:35:20 +0200 Subject: GRAPHICS: Allow in-place conversion with any color formats in crossBlit. --- graphics/conversion.cpp | 70 ++++++++++++++++++++++++++++++++++++++----------- graphics/conversion.h | 9 ++++--- 2 files changed, 60 insertions(+), 19 deletions(-) (limited to 'graphics') diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index ece1f759d9..27a44f4ed5 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -30,7 +30,7 @@ namespace Graphics { namespace { -template +template FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const uint h, const PixelFormat &srcFmt, const PixelFormat &dstFmt, const uint srcDelta, const uint dstDelta) { @@ -41,15 +41,27 @@ FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); *(DstColor *)dst = color; - src += sizeof(SrcColor); - dst += sizeof(DstColor); + + if (backward) { + src -= sizeof(SrcColor); + dst -= sizeof(DstColor); + } else { + src += sizeof(SrcColor); + dst += sizeof(DstColor); + } + } + + if (backward) { + src -= srcDelta; + dst -= dstDelta; + } else { + src += srcDelta; + dst += dstDelta; } - src += srcDelta; - dst += dstDelta; } } -template +template FORCEINLINE void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint w, const uint h, const PixelFormat &srcFmt, const PixelFormat &dstFmt, const uint srcDelta, const uint dstDelta) { @@ -65,11 +77,23 @@ FORCEINLINE void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint srcFmt.colorToARGB(color, a, r, g, b); color = dstFmt.ARGBToColor(a, r, g, b); *(DstColor *)dst = color; - src += 3; - dst += sizeof(DstColor); + + if (backward) { + src -= 3; + dst -= sizeof(DstColor); + } else { + src += 3; + dst += sizeof(DstColor); + } + } + + if (backward) { + src -= srcDelta; + dst -= dstDelta; + } else { + src += srcDelta; + dst += dstDelta; } - src += srcDelta; - dst += dstDelta; } } @@ -110,19 +134,33 @@ bool crossBlit(byte *dst, const byte *src, // TODO: optimized cases for dstDelta of 0 if (dstFmt.bytesPerPixel == 2) { if (srcFmt.bytesPerPixel == 2) { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else if (srcFmt.bytesPerPixel == 3) { - crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } } else if (dstFmt.bytesPerPixel == 4) { if (srcFmt.bytesPerPixel == 2) { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + // We need to blit the surface from bottom right to top left here. + // This is neeeded, because when we convert to the same memory + // buffer copying the surface from top left to bottom right would + // overwrite the source, since we have more bits per destination + // color than per source color. + dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel; + src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel; + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else if (srcFmt.bytesPerPixel == 3) { - crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + // We need to blit the surface from bottom right to top left here. + // This is neeeded, because when we convert to the same memory + // buffer copying the surface from top left to bottom right would + // overwrite the source, since we have more bits per destination + // color than per source color. + dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel; + src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel; + crossBlitLogic3BppSource(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } else { - crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); + crossBlitLogic(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta); } } else { return false; diff --git a/graphics/conversion.h b/graphics/conversion.h index 0dce3cf279..28e64a94fb 100644 --- a/graphics/conversion.h +++ b/graphics/conversion.h @@ -60,9 +60,12 @@ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) { * false if there is an error. * * @note Blitting to a 3Bpp destination is not supported - * @note This can convert a rectangle in place, if the source and - * destination format have the same bytedepth. - * + * @note This can convert a surface in place, regardless of the + * source and destination format, as long as there is enough + * space for the destination. The dstPitch / srcPitch ratio + * must at least equal the dstBpp / srcBpp ratio for + * dstPitch >= srcPitch and at most dstBpp / srcBpp for + * dstPitch < srcPitch though. */ bool crossBlit(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, -- cgit v1.2.3 From e8cf0adf95217d4eedec526df960a8cdd46cc28f Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 05:40:09 +0200 Subject: GRAPHICS: Slight cleanup in crossBlit code. --- graphics/conversion.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'graphics') diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index 27a44f4ed5..fec1d240e2 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -36,11 +36,10 @@ FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const const uint srcDelta, const uint dstDelta) { for (uint y = 0; y < h; ++y) { for (uint x = 0; x < w; ++x) { - uint32 color = *(const SrcColor *)src; + const uint32 color = *(const SrcColor *)src; byte a, r, g, b; srcFmt.colorToARGB(color, a, r, g, b); - color = dstFmt.ARGBToColor(a, r, g, b); - *(DstColor *)dst = color; + *(DstColor *)dst = dstFmt.ARGBToColor(a, r, g, b); if (backward) { src -= sizeof(SrcColor); @@ -75,8 +74,7 @@ FORCEINLINE void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint for (uint x = 0; x < w; ++x) { memcpy(col, src, 3); srcFmt.colorToARGB(color, a, r, g, b); - color = dstFmt.ARGBToColor(a, r, g, b); - *(DstColor *)dst = color; + *(DstColor *)dst = dstFmt.ARGBToColor(a, r, g, b); if (backward) { src -= 3; -- cgit v1.2.3 From eeb39592599815875a736fdbef67204c2036e935 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 14 Jul 2012 06:03:04 +0200 Subject: GRAPHICS: Add an in-place Surface PixelFormat conversion. --- graphics/surface.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ graphics/surface.h | 14 +++++++++++ 2 files changed, 81 insertions(+) (limited to 'graphics') diff --git a/graphics/surface.cpp b/graphics/surface.cpp index c0f1046eae..1604eaa488 100644 --- a/graphics/surface.cpp +++ b/graphics/surface.cpp @@ -26,6 +26,7 @@ #include "common/textconsole.h" #include "graphics/primitives.h" #include "graphics/surface.h" +#include "graphics/conversion.h" namespace Graphics { @@ -271,6 +272,72 @@ void Surface::move(int dx, int dy, int height) { } } +void Surface::convertToInPlace(const PixelFormat &dstFormat, const byte *palette) { + // Do not convert to the same format and ignore empty surfaces. + if (format == dstFormat || pixels == 0) { + return; + } + + if (format.bytesPerPixel == 0 || format.bytesPerPixel > 4) + error("Surface::convertToInPlace(): Can only convert from 1Bpp, 2Bpp, 3Bpp, and 4Bpp"); + + if (dstFormat.bytesPerPixel != 2 && dstFormat.bytesPerPixel != 4) + error("Surface::convertToInPlace(): Can only convert to 2Bpp and 4Bpp"); + + // In case the surface data needs more space allocate it. + if (dstFormat.bytesPerPixel > format.bytesPerPixel) { + void *const newPixels = realloc(pixels, w * h * dstFormat.bytesPerPixel); + if (!newPixels) { + error("Surface::convertToInPlace(): Out of memory"); + } + pixels = newPixels; + } + + // We take advantage of the fact that pitch is always w * format.bytesPerPixel. + // This is assured by the logic of Surface::create. + + // We need to handle 1 Bpp surfaces special here. + if (format.bytesPerPixel == 1) { + assert(palette); + + for (int y = h; y > 0; --y) { + const byte *srcRow = (const byte *)pixels + y * pitch - 1; + byte *dstRow = (byte *)pixels + y * w * dstFormat.bytesPerPixel - dstFormat.bytesPerPixel; + + for (int x = 0; x < w; x++) { + byte index = *srcRow--; + byte r = palette[index * 3]; + byte g = palette[index * 3 + 1]; + byte b = palette[index * 3 + 2]; + + uint32 color = dstFormat.RGBToColor(r, g, b); + + if (dstFormat.bytesPerPixel == 2) + *((uint16 *)dstRow) = color; + else + *((uint32 *)dstRow) = color; + + dstRow -= dstFormat.bytesPerPixel; + } + } + } else { + crossBlit((byte *)pixels, (const byte *)pixels, w * dstFormat.bytesPerPixel, pitch, w, h, dstFormat, format); + } + + // In case the surface data got smaller, free up some memory. + if (dstFormat.bytesPerPixel < format.bytesPerPixel) { + void *const newPixels = realloc(pixels, w * h * dstFormat.bytesPerPixel); + if (!newPixels) { + error("Surface::convertToInPlace(): Freeing memory failed"); + } + pixels = newPixels; + } + + // Update the surface specific data. + format = dstFormat; + pitch = w * dstFormat.bytesPerPixel; +} + Graphics::Surface *Surface::convertTo(const PixelFormat &dstFormat, const byte *palette) const { assert(pixels); diff --git a/graphics/surface.h b/graphics/surface.h index eb8d1ac42e..eaf62f84eb 100644 --- a/graphics/surface.h +++ b/graphics/surface.h @@ -134,6 +134,20 @@ struct Surface { */ void copyFrom(const Surface &surf); + /** + * Convert the data to another pixel format. + * + * This works in-place. This means it will not create an additional buffer + * for the conversion process. The value of pixels might change though. + * + * Note that you should only use this, when you created the Surface data via + * create! Otherwise this function has undefined behavior. + * + * @param dstFormat The desired format + * @param palette The palette (in RGB888), if the source format has a Bpp of 1 + */ + void convertToInPlace(const PixelFormat &dstFormat, const byte *palette = 0); + /** * Convert the data to another pixel format. * -- cgit v1.2.3 From 47a7df2d0f9be2c13648a18c9de7b81e77e5d7fe Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Mon, 13 Aug 2012 00:09:42 +0200 Subject: GRAPHICS: Add in a TGA-decoder --- graphics/decoders/tga.cpp | 419 ++++++++++++++++++++++++++++++++++++++++++++++ graphics/decoders/tga.h | 100 +++++++++++ graphics/module.mk | 3 +- 3 files changed, 521 insertions(+), 1 deletion(-) create mode 100644 graphics/decoders/tga.cpp create mode 100644 graphics/decoders/tga.h (limited to 'graphics') diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp new file mode 100644 index 0000000000..7d214a6f24 --- /dev/null +++ b/graphics/decoders/tga.cpp @@ -0,0 +1,419 @@ +/* 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. + */ + +/* Based on code from xoreos https://github.com/DrMcCoy/xoreos/ + * relicensed under GPLv2+ with permission from DrMcCoy and clone2727 + */ + +#include "common/util.h" +#include "common/stream.h" +#include "common/textconsole.h" +#include "common/error.h" + +#include "graphics/decoders/tga.h" + +namespace Graphics { + +TGADecoder::TGADecoder() { + _colorMapSize = 0; + _colorMapOrigin = 0; + _colorMapLength = 0; + _colorMapEntryLength = 0; + _colorMap = NULL; +} + +TGADecoder::~TGADecoder() { + destroy(); +} + +void TGADecoder::destroy() { + _surface.free(); + delete[] _colorMap; +} + +bool TGADecoder::loadStream(Common::SeekableReadStream &tga) { + byte imageType, pixelDepth; + bool success; + success = readHeader(tga, imageType, pixelDepth); + if (success) { + switch (imageType) { + case TYPE_BW: + case TYPE_TRUECOLOR: + success = readData(tga, imageType, pixelDepth); + break; + case TYPE_RLE_BW: + case TYPE_RLE_TRUECOLOR: + case TYPE_RLE_CMAP: + success = readDataRLE(tga, imageType, pixelDepth); + break; + case TYPE_CMAP: + success = readDataColorMapped(tga, imageType, pixelDepth); + break; + default: + success = false; + break; + } + } + if (tga.err() || !success) { + warning("Failed reading TGA-file"); + return false; + } + return success; +} + +bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth) { + if (!tga.seek(0)) { + warning("Failed reading TGA-file"); + return false; + } + + // TGAs have an optional "id" string in the header + uint32 idLength = tga.readByte(); + + // Number of colors in the color map / palette + int hasColorMap = tga.readByte(); + + // Image type. See header for numeric constants + imageType = tga.readByte(); + + switch (imageType) { + case TYPE_CMAP: + case TYPE_TRUECOLOR: + case TYPE_BW: + case TYPE_RLE_CMAP: + case TYPE_RLE_TRUECOLOR: + case TYPE_RLE_BW: + break; + default: + warning("Unsupported image type: %d", imageType); + return false; + } + + // Color map specifications + if (hasColorMap == 0) { + tga.skip(5); + } else { + _colorMapOrigin = tga.readUint16LE(); + _colorMapLength = tga.readUint16LE(); + _colorMapEntryLength = tga.readByte(); + } + // Origin-defintions + tga.skip(2 + 2); + + // Image dimensions + _surface.w = tga.readUint16LE(); + _surface.h = tga.readUint16LE(); + + // Bits per pixel + pixelDepth = tga.readByte(); + _surface.format.bytesPerPixel = pixelDepth / 8; + + // Image descriptor + byte imgDesc = tga.readByte(); + int attributeBits = imgDesc & 0x0F; + assert((imgDesc & 0x10) == 0); + _originTop = (imgDesc & 0x20); + + // Interleaving is not handled at this point + //int interleave = (imgDesc & 0xC); + if (imageType == TYPE_CMAP || imageType == TYPE_RLE_CMAP) { + if (pixelDepth == 8) { + _format = PixelFormat::createFormatCLUT8(); + } else { + warning("Unsupported index-depth: %d", pixelDepth); + return false; + } + } else if (imageType == TYPE_TRUECOLOR || imageType == TYPE_RLE_TRUECOLOR) { + if (pixelDepth == 24) { + _format = PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0); + } else if (pixelDepth == 32) { + _format = PixelFormat(4, 8, 8, 8, attributeBits, 16, 8, 0, 24); + } else if (pixelDepth == 16 && imageType == TYPE_TRUECOLOR) { + // 16bpp TGA is ARGB1555 + _format = PixelFormat(2, 5, 5, 5, attributeBits, 10, 5, 0, 15); + } else { + warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth); + return false; + } + } else if (imageType == TYPE_BW || TYPE_RLE_BW) { + if (pixelDepth == 8) { + _format = PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0); + } else { + warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth); + return false; + } + + } else { + warning("Unsupported image type: %d", imageType); + return false; + } + + // Skip the id string + tga.skip(idLength); + + if (hasColorMap) { + return readColorMap(tga, imageType, pixelDepth); + } + return true; +} + +bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + _colorMap = new byte[3 * _colorMapLength]; + for (int i = 0; i < _colorMapLength * 3; i += 3) { + byte r, g, b, a; + if (_colorMapEntryLength == 32) { + PixelFormat format(4, 8, 8, 8, 0, 16, 8, 0, 24); + uint32 color = tga.readUint32LE(); + format.colorToARGB(color, a, r, g, b); + } else if (_colorMapEntryLength == 24) { + r = tga.readByte(); + g = tga.readByte(); + b = tga.readByte(); + } else if (_colorMapEntryLength == 16) { + PixelFormat format(2, 5, 5, 5, 0, 10, 5, 0, 15); + uint16 color = tga.readUint16LE(); + format.colorToARGB(color, a, r, g, b); + } +#ifdef SCUMM_LITTLE_ENDIAN + _colorMap[i] = r; + _colorMap[i + 1] = g; + _colorMap[i + 2] = b; +#else + _colorMap[i] = b; + _colorMap[i + 1] = g; + _colorMap[i + 2] = r; +#endif + } + return true; +} + +// Additional information found from http://paulbourke.net/dataformats/tga/ +// With some details from the link referenced in the header. +bool TGADecoder::readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + // TrueColor + if (imageType == TYPE_TRUECOLOR) { + _surface.create(_surface.w, _surface.h, _format); + + if (pixelDepth == 16) { + for (int i = 0; i < _surface.h; i++) { + uint16 *dst; + if (!_originTop) { + dst = (uint16 *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (uint16 *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + *dst++ = tga.readUint16LE(); + } + } + } else if (pixelDepth == 32) { + for (int i = 0; i < _surface.h; i++) { + uint32 *dst; + if (!_originTop) { + dst = (uint32 *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (uint32 *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + *dst++ = tga.readUint32LE(); + } + } + } else if (pixelDepth == 24) { + for (int i = 0; i < _surface.h; i++) { + byte *dst; + if (!_originTop) { + dst = (byte *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (byte *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); +#ifdef SCUMM_LITTLE_ENDIAN + *dst++ = r; + *dst++ = g; + *dst++ = b; +#else + *dst++ = b; + *dst++ = g; + *dst++ = r; +#endif + } + } + } + // Black/White + } else if (imageType == TYPE_BW) { + _surface.create(_surface.w, _surface.h, _format); + + byte *data = (byte *)_surface.pixels; + uint32 count = _surface.w * _surface.h; + + while (count-- > 0) { + byte g = tga.readByte(); + *data++ = g; + *data++ = g; + *data++ = g; + *data++ = g; + } + } + return true; +} + +bool TGADecoder::readDataColorMapped(Common::SeekableReadStream &tga, byte imageType, byte indexDepth) { + // Color-mapped + if (imageType == TYPE_CMAP) { + _surface.create(_surface.w, _surface.h, _format); + if (indexDepth == 8) { + for (int i = 0; i < _surface.h; i++) { + byte *dst; + if (!_originTop) { + dst = (byte *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (byte *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + byte index = tga.readByte(); + *dst++ = index; + } + } + } else if (indexDepth == 16) { + warning("16 bit indexes not supported"); + return false; + } + } else { + return false; + } + return true; +} + +bool TGADecoder::readDataRLE(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + // RLE-TrueColor / RLE-Black/White + if (imageType == TYPE_RLE_TRUECOLOR || imageType == TYPE_RLE_BW || imageType == TYPE_RLE_CMAP) { + _surface.create(_surface.w, _surface.h, _format); + uint32 count = _surface.w * _surface.h; + byte *data = (byte *)_surface.pixels; + + while (count > 0) { + uint32 header = tga.readByte(); + byte type = (header & 0x80) >> 7; + uint32 rleCount = (header & 0x7F) + 1; + + // RLE-packet + if (type == 1) { + if (pixelDepth == 32 && imageType == TYPE_RLE_TRUECOLOR) { + uint32 color = tga.readUint32LE(); + while (rleCount-- > 0) { + *((uint32 *)data) = color; + data += 4; + count--; + } + } else if (pixelDepth == 24 && imageType == TYPE_RLE_TRUECOLOR) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); + while (rleCount-- > 0) { +#ifdef SCUMM_LITTLE_ENDIAN + *data++ = r; + *data++ = g; + *data++ = b; +#else + *data++ = b; + *data++ = g; + *data++ = r; +#endif + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_BW) { + byte color = tga.readByte(); + while (rleCount-- > 0) { + *data++ = color; + *data++ = color; + *data++ = color; + *data++ = color; + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_CMAP) { + byte index = tga.readByte(); + while (rleCount-- > 0) { + *data++ = index; + count--; + } + } else { + warning("Unhandled pixel-depth for image-type 10"); + return false; + } + // Raw-packet + } else if (type == 0) { + if (pixelDepth == 32 && imageType == TYPE_RLE_TRUECOLOR) { + while (rleCount-- > 0) { + uint32 color = tga.readUint32LE(); + *((uint32 *)data) = color; + data += 4; + count--; + } + } else if (pixelDepth == 24 && imageType == TYPE_RLE_TRUECOLOR) { + while (rleCount-- > 0) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); +#ifdef SCUMM_LITTLE_ENDIAN + *data++ = r; + *data++ = g; + *data++ = b; +#else + *data++ = b; + *data++ = g; + *data++ = r; +#endif + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_BW) { + while (rleCount-- > 0) { + byte color = tga.readByte(); + *data++ = color; + *data++ = color; + *data++ = color; + *data++ = color; + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_CMAP) { + while (rleCount-- > 0) { + byte index = tga.readByte(); + *data++ = index; + count--; + } + } else { + warning("Unhandled pixel-depth for image-type 10"); + return false; + } + } else { + warning("Unknown header for RLE-packet %d", type); + return false; + } + } + } else { + return false; + } + return true; +} + +} // End of namespace Graphics diff --git a/graphics/decoders/tga.h b/graphics/decoders/tga.h new file mode 100644 index 0000000000..e8dd2b8411 --- /dev/null +++ b/graphics/decoders/tga.h @@ -0,0 +1,100 @@ +/* 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. + */ + +/* Based on code from eos https://github.com/DrMcCoy/xoreos/ + * relicensed under GPLv2+ with permission from DrMcCoy and clone2727 + */ + +/* + * TGA decoder used in engines: + * - none + */ + +#ifndef GRAPHICS_DECODERS_TGA_H +#define GRAPHICS_DECODERS_TGA_H + +#include "graphics/surface.h" +#include "graphics/decoders/image_decoder.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { + +/** TarGa image-decoder + * The following variations of TGA are supported: + * - Type 1 - Color-mapped images in 16/24/32 bpp with 8 bit indexes + * - Type 2 - 16/24/32 bpp Top AND Bottom origined. + * - Type 3 - Black/White images, 8bpp. + * - Type 9 - RLE-encoded color-mapped images. (8 bit indexes only) + * - Type 10 - RLE-encoded TrueColor, 24/32bpp. + * - Type 11 - RLE-encoded Black/White, 8bpp. + * + * No images are returned with a palette, instead they are converted + * to 16 bpp for Type 1, or 32 bpp for Black/White-images. + */ +class TGADecoder : public ImageDecoder { +public: + TGADecoder(); + virtual ~TGADecoder(); + virtual void destroy(); + virtual const Surface *getSurface() const { + return &_surface; + }; + virtual const byte *getPalette() const { return _colorMap; } + virtual uint16 getPaletteColorCount() const { return _colorMapLength; } + virtual bool loadStream(Common::SeekableReadStream &stream); +private: + // Format-spec from: + //http://www.ludorg.net/amnesia/TGA_File_Format_Spec.html + enum { + TYPE_CMAP = 1, + TYPE_TRUECOLOR = 2, + TYPE_BW = 3, + TYPE_RLE_CMAP = 9, + TYPE_RLE_TRUECOLOR = 10, + TYPE_RLE_BW = 11 + }; + + // Color-map: + bool _colorMapSize; + byte *_colorMap; + int16 _colorMapOrigin; + int16 _colorMapLength; + byte _colorMapEntryLength; + + // Origin may be at the top, or bottom + bool _originTop; + + PixelFormat _format; + Surface _surface; + // Loading helpers + bool readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth); + bool readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); + bool readDataColorMapped(Common::SeekableReadStream &tga, byte imageType, byte indexDepth); + bool readDataRLE(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); + bool readColorMap(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); +}; + +} // End of namespace Graphics + +#endif // GRAPHICS_DECODERS_TGA_H diff --git a/graphics/module.mk b/graphics/module.mk index 281f904b38..e67efd2cf5 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -26,7 +26,8 @@ MODULE_OBJS := \ decoders/bmp.o \ decoders/jpeg.o \ decoders/pict.o \ - decoders/png.o + decoders/png.o \ + decoders/tga.o ifdef USE_SCALERS MODULE_OBJS += \ -- cgit v1.2.3 From f189d8a541647506498b19a2b66138b6171000a3 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 29 Aug 2012 15:58:55 +0200 Subject: GRAPHICS: Remove extra semicolon. --- graphics/decoders/tga.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/decoders/tga.h b/graphics/decoders/tga.h index e8dd2b8411..8149014a24 100644 --- a/graphics/decoders/tga.h +++ b/graphics/decoders/tga.h @@ -59,7 +59,7 @@ public: virtual void destroy(); virtual const Surface *getSurface() const { return &_surface; - }; + } virtual const byte *getPalette() const { return _colorMap; } virtual uint16 getPaletteColorCount() const { return _colorMapLength; } virtual bool loadStream(Common::SeekableReadStream &stream); -- cgit v1.2.3 From f87154def8c54722c8068e9ee9130c30ab393537 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 29 Aug 2012 15:59:15 +0200 Subject: GRAPHICS: Slight formatting change for consistency. --- graphics/decoders/tga.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/tga.h b/graphics/decoders/tga.h index 8149014a24..dfdc5a4da9 100644 --- a/graphics/decoders/tga.h +++ b/graphics/decoders/tga.h @@ -57,9 +57,7 @@ public: TGADecoder(); virtual ~TGADecoder(); virtual void destroy(); - virtual const Surface *getSurface() const { - return &_surface; - } + virtual const Surface *getSurface() const { return &_surface; } virtual const byte *getPalette() const { return _colorMap; } virtual uint16 getPaletteColorCount() const { return _colorMapLength; } virtual bool loadStream(Common::SeekableReadStream &stream); -- cgit v1.2.3 From 3b4d713ba114a692354f2a9dc68d7b9c3cfe5560 Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Thu, 30 Aug 2012 18:13:00 +0200 Subject: GRAPHICS: Undefined behaviour/warnings removal in the TGA decoder --- graphics/decoders/tga.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'graphics') diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp index 7d214a6f24..c27cd2b20b 100644 --- a/graphics/decoders/tga.cpp +++ b/graphics/decoders/tga.cpp @@ -191,6 +191,9 @@ bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, b PixelFormat format(2, 5, 5, 5, 0, 10, 5, 0, 15); uint16 color = tga.readUint16LE(); format.colorToARGB(color, a, r, g, b); + } else { + warning("Unsupported image type: %d", imageType); + r = g = b = a = 0; } #ifdef SCUMM_LITTLE_ENDIAN _colorMap[i] = r; -- cgit v1.2.3 From 10a947a0be80ea8c5c88bd3493a5057b1223ce45 Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Thu, 30 Aug 2012 18:32:27 +0200 Subject: GRAPHICS: Scope reduction of the sometimes unused alpha component in TGADecoder::readHeader --- graphics/decoders/tga.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp index c27cd2b20b..0b2318e127 100644 --- a/graphics/decoders/tga.cpp +++ b/graphics/decoders/tga.cpp @@ -178,8 +178,9 @@ bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, by bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { _colorMap = new byte[3 * _colorMapLength]; for (int i = 0; i < _colorMapLength * 3; i += 3) { - byte r, g, b, a; + byte r, g, b; if (_colorMapEntryLength == 32) { + byte a; PixelFormat format(4, 8, 8, 8, 0, 16, 8, 0, 24); uint32 color = tga.readUint32LE(); format.colorToARGB(color, a, r, g, b); @@ -188,12 +189,13 @@ bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, b g = tga.readByte(); b = tga.readByte(); } else if (_colorMapEntryLength == 16) { + byte a; PixelFormat format(2, 5, 5, 5, 0, 10, 5, 0, 15); uint16 color = tga.readUint16LE(); format.colorToARGB(color, a, r, g, b); } else { warning("Unsupported image type: %d", imageType); - r = g = b = a = 0; + r = g = b = 0; } #ifdef SCUMM_LITTLE_ENDIAN _colorMap[i] = r; -- cgit v1.2.3 From 2f9b1b67b08f1b70cd95795aaf7816ca7f991649 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 31 Aug 2012 22:26:02 -0400 Subject: ALL: Mark off some things as used by Pegasus --- graphics/decoders/pict.h | 1 + 1 file changed, 1 insertion(+) (limited to 'graphics') diff --git a/graphics/decoders/pict.h b/graphics/decoders/pict.h index 417a7c5134..7497e3963f 100644 --- a/graphics/decoders/pict.h +++ b/graphics/decoders/pict.h @@ -24,6 +24,7 @@ * @file * Image decoder used in engines: * - mohawk + * - pegasus * - sci */ -- cgit v1.2.3 From 5f6a98cb5ba373a19e82d17718a0077f40305f9d Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Mon, 3 Sep 2012 01:32:50 +0200 Subject: SCALER: No need to inline interpolate5Line, it just bloats stretch200To240 for nothing --- graphics/scaler/aspect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/scaler/aspect.cpp b/graphics/scaler/aspect.cpp index f0ae732a40..2f06b2e4f6 100644 --- a/graphics/scaler/aspect.cpp +++ b/graphics/scaler/aspect.cpp @@ -56,7 +56,7 @@ static inline void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint1 #if ASPECT_MODE == kVeryFastAndGoodAspectMode template -static inline void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width) { +static void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width) { if (scale == 1) { while (width--) { *dst++ = interpolate16_7_1(*srcB++, *srcA++); -- cgit v1.2.3 From 1f11ce6df2491e51c713278b6bfc6464a9aef965 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 6 Sep 2012 01:34:20 +0300 Subject: PNG: call png_set_interlace_handling() before calling png_read_update_info() This matches the documentation, information from the PNG bug tracker and the behavior of example decoders off the net. It fixes warnings thrown from the PNG decoder --- graphics/decoders/png.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'graphics') diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index bfaab6dc35..4f917b44b1 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -191,6 +191,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { } // After the transformations have been registered, the image data is read again. + png_set_interlace_handling(pngPtr); png_read_update_info(pngPtr, infoPtr); png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); width = w; -- cgit v1.2.3 From ed2be9d873cb69d2f06f38665342082e4ec157d0 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 9 Sep 2012 17:20:07 -0400 Subject: GRAPHICS: Fix ImageDecoder inconsistency with getPalette() Per LordHoto's suggestion --- graphics/decoders/image_decoder.h | 7 ++++++- graphics/decoders/pict.cpp | 12 ++++++------ graphics/decoders/pict.h | 4 ++-- 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/image_decoder.h b/graphics/decoders/image_decoder.h index 830645d361..49e31c6e3a 100644 --- a/graphics/decoders/image_decoder.h +++ b/graphics/decoders/image_decoder.h @@ -78,10 +78,15 @@ public: * The palette's format is the same as PaletteManager's palette * (interleaved RGB values). * - * @return the decoded palette, or 0 if no palette is present + * @return the decoded palette, or undefined if no palette is present */ virtual const byte *getPalette() const { return 0; } + /** + * Query if the decoded image has a palette. + */ + virtual bool hasPalette() const { return getPaletteColorCount() != 0; } + /** Return the starting index of the palette. */ virtual byte getPaletteStartIndex() const { return 0; } /** Return the number of colors in the palette. */ diff --git a/graphics/decoders/pict.cpp b/graphics/decoders/pict.cpp index 7eddd3b893..9e619df208 100644 --- a/graphics/decoders/pict.cpp +++ b/graphics/decoders/pict.cpp @@ -292,12 +292,12 @@ struct PackBitsRectData { uint16 mode; }; -void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool hasPalette) { +void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool withPalette) { PackBitsRectData packBitsData; - packBitsData.pixMap = readPixMap(stream, !hasPalette); + packBitsData.pixMap = readPixMap(stream, !withPalette); // Read in the palette if there is one present - if (hasPalette) { + if (withPalette) { // See http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-267.html stream.readUint32BE(); // seed stream.readUint16BE(); // flags @@ -469,10 +469,10 @@ void PICTDecoder::outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel) { } } -void PICTDecoder::skipBitsRect(Common::SeekableReadStream &stream, bool hasPalette) { +void PICTDecoder::skipBitsRect(Common::SeekableReadStream &stream, bool withPalette) { // Step through a PackBitsRect/DirectBitsRect function - if (!hasPalette) + if (!withPalette) stream.readUint32BE(); uint16 rowBytes = stream.readUint16BE(); @@ -492,7 +492,7 @@ void PICTDecoder::skipBitsRect(Common::SeekableReadStream &stream, bool hasPalet stream.readUint16BE(); // pixelSize stream.skip(16); - if (hasPalette) { + if (withPalette) { stream.readUint32BE(); stream.readUint16BE(); stream.skip((stream.readUint16BE() + 1) * 8); diff --git a/graphics/decoders/pict.h b/graphics/decoders/pict.h index 417a7c5134..fa352e653c 100644 --- a/graphics/decoders/pict.h +++ b/graphics/decoders/pict.h @@ -87,9 +87,9 @@ private: bool _continueParsing; // Utility Functions - void unpackBitsRect(Common::SeekableReadStream &stream, bool hasPalette); + void unpackBitsRect(Common::SeekableReadStream &stream, bool withPalette); void unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *stream, byte bitsPerPixel, byte bytesPerPixel); - void skipBitsRect(Common::SeekableReadStream &stream, bool hasPalette); + void skipBitsRect(Common::SeekableReadStream &stream, bool withPalette); void decodeCompressedQuickTime(Common::SeekableReadStream &stream); void outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel); -- cgit v1.2.3 From ccccb392b55ee64130ac87aa5737321a943ee628 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 13 Sep 2012 01:49:29 +0300 Subject: GRAPHICS: Add a common PCX image decoder --- graphics/decoders/pcx.cpp | 213 ++++++++++++++++++++++++++++++++++++++++++++++ graphics/decoders/pcx.h | 68 +++++++++++++++ graphics/module.mk | 1 + 3 files changed, 282 insertions(+) create mode 100644 graphics/decoders/pcx.cpp create mode 100644 graphics/decoders/pcx.h (limited to 'graphics') diff --git a/graphics/decoders/pcx.cpp b/graphics/decoders/pcx.cpp new file mode 100644 index 0000000000..f5c1c24bb0 --- /dev/null +++ b/graphics/decoders/pcx.cpp @@ -0,0 +1,213 @@ +/* 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. + */ + +#include "common/stream.h" +#include "common/textconsole.h" + +#include "graphics/pixelformat.h" +#include "graphics/surface.h" +#include "graphics/decoders/pcx.h" + +/** + * Based on the PCX specs: + * http://www.fileformat.info/format/pcx/spec/a10e75307b3a4cc49c3bbe6db4c41fa2/view.htm + * and the PCX decoder of FFmpeg (libavcodec/pcx.c): + * http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/pcx.c + */ + +namespace Graphics { + +PCXDecoder::PCXDecoder() { + _surface = 0; + _palette = 0; + _paletteColorCount = 0; +} + +PCXDecoder::~PCXDecoder() { + destroy(); +} + +void PCXDecoder::destroy() { + if (_surface) { + _surface->free(); + delete _surface; + _surface = 0; + } + + delete[] _palette; + _palette = 0; + _paletteColorCount = 0; +} + +bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) { + destroy(); + + if (stream.readByte() != 0x0a) // ZSoft PCX + return false; + + byte version = stream.readByte(); // 0 - 5 + if (version > 5) + return false; + + bool compressed = stream.readByte(); // encoding, 1 = run length encoding + byte bitsPerPixel = stream.readByte(); // 1, 2, 4 or 8 + + // Window + uint16 xMin = stream.readUint16LE(); + uint16 yMin = stream.readUint16LE(); + uint16 xMax = stream.readUint16LE(); + uint16 yMax = stream.readUint16LE(); + + uint16 width = xMax - xMin + 1; + uint16 height = yMax - yMin + 1; + + if (xMax < xMin || yMax < yMin) { + warning("Invalid PCX image dimensions"); + return false; + } + + stream.skip(4); // HDpi, VDpi + + // Read the EGA palette (colormap) + _palette = new byte[16 * 3]; + for (uint16 i = 0; i < 16; i++) { + _palette[i * 3 + 0] = stream.readByte(); + _palette[i * 3 + 1] = stream.readByte(); + _palette[i * 3 + 2] = stream.readByte(); + } + + if (stream.readByte() != 0) // reserved, should be set to 0 + return false; + + byte nPlanes = stream.readByte(); + uint16 bytesPerLine = stream.readUint16LE(); + uint16 bytesPerscanLine = nPlanes * bytesPerLine; + + if (bytesPerscanLine < width * bitsPerPixel * nPlanes / 8) { + warning("PCX data is corrupted"); + return false; + } + + stream.skip(60); // PaletteInfo, HscreenSize, VscreenSize, Filler + + _surface = new Graphics::Surface(); + + byte *scanLine = new byte[bytesPerscanLine]; + byte *dst; + int x, y; + + if (nPlanes == 3 && bitsPerPixel == 8) { // 24bpp + Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); + _surface->create(width, height, format); + dst = (byte *)_surface->pixels; + _paletteColorCount = 0; + + for (y = 0; y < height; y++) { + decodeRLE(stream, scanLine, bytesPerscanLine, compressed); + + for (x = 0; x < width; x++) { + byte b = scanLine[x]; + byte g = scanLine[x + bytesPerLine]; + byte r = scanLine[x + (bytesPerLine << 1)]; + uint32 color = format.RGBToColor(r, g, b); + + *((uint32 *)dst) = color; + dst += format.bytesPerPixel; + } + } + } else if (nPlanes == 1 && bitsPerPixel == 8) { // 8bpp indexed + _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + dst = (byte *)_surface->pixels; + _paletteColorCount = 16; + + for (y = 0; y < height; y++, dst += _surface->pitch) { + decodeRLE(stream, scanLine, bytesPerscanLine, compressed); + memcpy(dst, scanLine, width); + } + + if (version == 5) { + if (stream.readByte() != 12) { + warning("Expected a palette after the PCX image data"); + delete[] scanLine; + return false; + } + + // Read the VGA palette + delete[] _palette; + _palette = new byte[256 * 3]; + for (uint16 i = 0; i < 256; i++) { + _palette[i * 3 + 0] = stream.readByte(); + _palette[i * 3 + 1] = stream.readByte(); + _palette[i * 3 + 2] = stream.readByte(); + } + + _paletteColorCount = 256; + } + } else if ((nPlanes == 2 || nPlanes == 3 || nPlanes == 4) && bitsPerPixel == 1) { // planar, 4, 8 or 16 colors + _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + dst = (byte *)_surface->pixels; + _paletteColorCount = 16; + + for (y = 0; y < height; y++, dst += _surface->pitch) { + decodeRLE(stream, scanLine, bytesPerscanLine, compressed); + + for (x = 0; x < width; x++) { + int m = 0x80 >> (x & 7), v = 0; + for (int i = nPlanes - 1; i >= 0; i--) { + v <<= 1; + v += (scanLine[i * bytesPerLine + (x >> 3)] & m) == 0 ? 0 : 1; + } + dst[x] = v; + } + } + } else { + // Known unsupported case: 1 plane and bpp < 8 (1, 2 or 4) + warning("Invalid PCX file (%d planes, %d bpp)", nPlanes, bitsPerPixel); + delete[] scanLine; + return false; + } + + delete[] scanLine; + + return true; +} + +void PCXDecoder::decodeRLE(Common::SeekableReadStream &stream, byte *dst, uint32 bytesPerscanLine, bool compressed) { + uint32 i = 0; + byte run, value; + + if (compressed) { + while (i < bytesPerscanLine) { + run = 1; + value = stream.readByte(); + if (value >= 0xc0) { + run = value & 0x3f; + value = stream.readByte(); + } + while (i < bytesPerscanLine && run--) + dst[i++] = value; + } + } else { + stream.read(dst, bytesPerscanLine); + } +} + +} // End of namespace Graphics diff --git a/graphics/decoders/pcx.h b/graphics/decoders/pcx.h new file mode 100644 index 0000000000..bcff754a2d --- /dev/null +++ b/graphics/decoders/pcx.h @@ -0,0 +1,68 @@ +/* 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. + */ + +/** + * PCX decoder used in engines: + * - dreamweb + * - hugo + * - queen + * - tucker + */ + +#ifndef GRAPHICS_DECODERS_PCX_H +#define GRAPHICS_DECODERS_PCX_H + +#include "common/scummsys.h" +#include "common/str.h" +#include "graphics/decoders/image_decoder.h" + +namespace Common{ +class SeekableReadStream; +} + +namespace Graphics { + +struct PixelFormat; +struct Surface; + +class PCXDecoder : public ImageDecoder { +public: + PCXDecoder(); + virtual ~PCXDecoder(); + + // ImageDecoder API + void destroy(); + virtual bool loadStream(Common::SeekableReadStream &stream); + virtual const Surface *getSurface() const { return _surface; } + const byte *getPalette() const { return _palette; } + uint16 getPaletteColorCount() const { return _paletteColorCount; } + +private: + void decodeRLE(Common::SeekableReadStream &stream, byte *dst, uint32 bytesPerScanline, bool compressed); + + Surface *_surface; + byte *_palette; + uint16 _paletteColorCount; +}; + +} // End of namespace Graphics + +#endif diff --git a/graphics/module.mk b/graphics/module.mk index e67efd2cf5..f560d9dc97 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -25,6 +25,7 @@ MODULE_OBJS := \ yuv_to_rgb.o \ decoders/bmp.o \ decoders/jpeg.o \ + decoders/pcx.o \ decoders/pict.o \ decoders/png.o \ decoders/tga.o -- cgit v1.2.3 From cffda7710c7c0ba720797dbb025048e21e821708 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Sat, 15 Sep 2012 17:57:08 +0200 Subject: GRAPHICS: Force alphaBits to 8 for 32bpp TGAs for now --- graphics/decoders/tga.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp index 0b2318e127..0c07770d75 100644 --- a/graphics/decoders/tga.cpp +++ b/graphics/decoders/tga.cpp @@ -145,7 +145,10 @@ bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, by if (pixelDepth == 24) { _format = PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0); } else if (pixelDepth == 32) { - _format = PixelFormat(4, 8, 8, 8, attributeBits, 16, 8, 0, 24); + // HACK: According to the spec, attributeBits should determine the amount + // of alpha-bits, however, as the game files that use this decoder seems + // to ignore that fact, we force the amount to 8 for 32bpp files for now. + _format = PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); } else if (pixelDepth == 16 && imageType == TYPE_TRUECOLOR) { // 16bpp TGA is ARGB1555 _format = PixelFormat(2, 5, 5, 5, attributeBits, 10, 5, 0, 15); -- cgit v1.2.3 From 25aa19b2721e2f776d75219272217106817c95b3 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Sat, 15 Sep 2012 18:08:34 +0200 Subject: GRAPHICS: Reinsert attributeBits as a comment to the TGA-decoder --- graphics/decoders/tga.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics') diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp index 0c07770d75..c3b9d84055 100644 --- a/graphics/decoders/tga.cpp +++ b/graphics/decoders/tga.cpp @@ -148,7 +148,7 @@ bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, by // HACK: According to the spec, attributeBits should determine the amount // of alpha-bits, however, as the game files that use this decoder seems // to ignore that fact, we force the amount to 8 for 32bpp files for now. - _format = PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); + _format = PixelFormat(4, 8, 8, 8, /* attributeBits */ 8, 16, 8, 0, 24); } else if (pixelDepth == 16 && imageType == TYPE_TRUECOLOR) { // 16bpp TGA is ARGB1555 _format = PixelFormat(2, 5, 5, 5, attributeBits, 10, 5, 0, 15); -- cgit v1.2.3 From 7759f47607ac9e24295ced6383943692568ec038 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 17 Sep 2012 12:35:17 -0400 Subject: GRAPHICS: Fix BMP palette color count with bpp != 8 --- graphics/decoders/bmp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp index f15d4e2519..0d2165643d 100644 --- a/graphics/decoders/bmp.cpp +++ b/graphics/decoders/bmp.cpp @@ -100,10 +100,10 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { _paletteColorCount = stream.readUint32LE(); /* uint32 colorsImportant = */ stream.readUint32LE(); - if (_paletteColorCount == 0) - _paletteColorCount = 256; - if (bitsPerPixel == 8) { + if (_paletteColorCount == 0) + _paletteColorCount = 256; + // Read the palette _palette = new byte[_paletteColorCount * 3]; for (uint16 i = 0; i < _paletteColorCount; i++) { -- cgit v1.2.3 From 4c02e1974298de32b0c6aa70dfe729089241d8ea Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Mon, 3 Sep 2012 11:04:33 +0200 Subject: SCALER: Neon code for aspect correction for OpenPandora It gains 35% on the first function of the profiling on Indy IV It is now nearly memory-bound (~10%) so it might not be needed to schedule the code better than this --- graphics/scaler/aspect.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'graphics') diff --git a/graphics/scaler/aspect.cpp b/graphics/scaler/aspect.cpp index 2f06b2e4f6..429640fdbd 100644 --- a/graphics/scaler/aspect.cpp +++ b/graphics/scaler/aspect.cpp @@ -23,6 +23,13 @@ #include "graphics/scaler/intern.h" #include "graphics/scaler/aspect.h" +#ifdef OPENPANDORA +#define NEON_ASPECT_CORRECTOR +#endif + +#ifdef NEON_ASPECT_CORRECTOR +#include +#endif #define kSuperFastAndUglyAspectMode 0 // No interpolation at all, but super-fast #define kVeryFastAndGoodAspectMode 1 // Good quality with very good speed @@ -55,13 +62,66 @@ static inline void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint1 #if ASPECT_MODE == kVeryFastAndGoodAspectMode +#ifdef NEON_ASPECT_CORRECTOR + +template +static void interpolate5LineNeon(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width, int k1, int k2) { + uint16x4_t kRedBlueMask_4 = vdup_n_u16(ColorMask::kRedBlueMask); + uint16x4_t kGreenMask_4 = vdup_n_u16(ColorMask::kGreenMask); + uint16x4_t k1_4 = vdup_n_u16(k1); + uint16x4_t k2_4 = vdup_n_u16(k2); + while (width >= 4) { + uint16x4_t srcA_4 = vld1_u16(srcA); + uint16x4_t srcB_4 = vld1_u16(srcB); + uint16x4_t p1_4 = srcB_4; + uint16x4_t p2_4 = srcA_4; + + uint16x4_t p1_rb_4 = vand_u16(p1_4, kRedBlueMask_4); + uint16x4_t p1_g_4 = vand_u16(p1_4, kGreenMask_4); + uint16x4_t p2_rb_4 = vand_u16(p2_4, kRedBlueMask_4); + uint16x4_t p2_g_4 = vand_u16(p2_4, kGreenMask_4); + + uint32x4_t tmp_rb_4 = vshrq_n_u32(vmlal_u16(vmull_u16(p2_rb_4, k2_4), p1_rb_4, k1_4), 3); + uint32x4_t tmp_g_4 = vshrq_n_u32(vmlal_u16(vmull_u16(p2_g_4, k2_4), p1_g_4, k1_4), 3); + uint16x4_t p_rb_4 = vmovn_u32(tmp_rb_4); + p_rb_4 = vand_u16(p_rb_4, kRedBlueMask_4); + uint16x4_t p_g_4 = vmovn_u32(tmp_g_4); + p_g_4 = vand_u16(p_g_4, kGreenMask_4); + + uint16x4_t result_4 = p_rb_4 | p_g_4; + vst1_u16(dst, result_4); + + dst += 4; + srcA += 4; + srcB += 4; + width -= 4; + } +} +#endif + template static void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width) { if (scale == 1) { +#ifdef NEON_ASPECT_CORRECTOR + int width4 = width & ~3; + interpolate5LineNeon(dst, srcA, srcB, width4, 7, 1); + srcA += width4; + srcB += width4; + dst += width4; + width -= width4; +#endif while (width--) { *dst++ = interpolate16_7_1(*srcB++, *srcA++); } } else { + #ifdef NEON_ASPECT_CORRECTOR + int width4 = width & ~3; + interpolate5LineNeon(dst, srcA, srcB, width4, 5, 3); + srcA += width4; + srcB += width4; + dst += width4; + width -= width4; +#endif while (width--) { *dst++ = interpolate16_5_3(*srcB++, *srcA++); } -- cgit v1.2.3 From 893a2b37ff651e69699879932fe70895a28951fa Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 17 Sep 2012 12:54:08 -0400 Subject: GRAPHICS: Rework YUV->RGB code a bit --- graphics/decoders/jpeg.cpp | 2 +- graphics/yuv_to_rgb.cpp | 112 +++++++++++++++++---------------------------- graphics/yuv_to_rgb.h | 107 +++++++++++++++++++++++++------------------ 3 files changed, 106 insertions(+), 115 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/jpeg.cpp b/graphics/decoders/jpeg.cpp index a871377ca1..77ca316c6d 100644 --- a/graphics/decoders/jpeg.cpp +++ b/graphics/decoders/jpeg.cpp @@ -81,7 +81,7 @@ const Surface *JPEGDecoder::getSurface() const { const Graphics::Surface *uComponent = getComponent(2); const Graphics::Surface *vComponent = getComponent(3); - convertYUV444ToRGB(_rgbSurface, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); + YUVToRGBMan.convert444(_rgbSurface, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); return _rgbSurface; } diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp index 78903d0cd8..1afd0d295b 100644 --- a/graphics/yuv_to_rgb.cpp +++ b/graphics/yuv_to_rgb.cpp @@ -83,10 +83,12 @@ // BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, // SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -#include "common/scummsys.h" -#include "common/singleton.h" - #include "graphics/surface.h" +#include "graphics/yuv_to_rgb.h" + +namespace Common { +DECLARE_SINGLETON(Graphics::YUVToRGBManager); +} namespace Graphics { @@ -95,42 +97,18 @@ public: YUVToRGBLookup(Graphics::PixelFormat format); ~YUVToRGBLookup(); - int16 *_colorTab; uint32 *_rgbToPix; }; YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format) { - _colorTab = new int16[4 * 256]; // 2048 bytes - - int16 *Cr_r_tab = &_colorTab[0 * 256]; - int16 *Cr_g_tab = &_colorTab[1 * 256]; - int16 *Cb_g_tab = &_colorTab[2 * 256]; - int16 *Cb_b_tab = &_colorTab[3 * 256]; - _rgbToPix = new uint32[3 * 768]; // 9216 bytes uint32 *r_2_pix_alloc = &_rgbToPix[0 * 768]; uint32 *g_2_pix_alloc = &_rgbToPix[1 * 768]; uint32 *b_2_pix_alloc = &_rgbToPix[2 * 768]; - int16 CR, CB; - int i; - - // Generate the tables for the display surface - - for (i = 0; i < 256; i++) { - // Gamma correction (luminescence table) and chroma correction - // would be done here. See the Berkeley mpeg_play sources. - - CR = CB = (i - 128); - Cr_r_tab[i] = (int16) ( (0.419 / 0.299) * CR) + 0 * 768 + 256; - Cr_g_tab[i] = (int16) (-(0.299 / 0.419) * CR) + 1 * 768 + 256; - Cb_g_tab[i] = (int16) (-(0.114 / 0.331) * CB); - Cb_b_tab[i] = (int16) ( (0.587 / 0.331) * CB) + 2 * 768 + 256; - } - // Set up entries 0-255 in rgb-to-pixel value tables. - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { r_2_pix_alloc[i + 256] = format.RGBToColor(i, 0, 0); g_2_pix_alloc[i + 256] = format.RGBToColor(0, i, 0); b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, i); @@ -138,7 +116,7 @@ YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format) { // Spread out the values we have to the rest of the array so that we do // not need to check for overflow. - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { r_2_pix_alloc[i] = r_2_pix_alloc[256]; r_2_pix_alloc[i + 512] = r_2_pix_alloc[511]; g_2_pix_alloc[i] = g_2_pix_alloc[256]; @@ -150,24 +128,28 @@ YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format) { YUVToRGBLookup::~YUVToRGBLookup() { delete[] _rgbToPix; - delete[] _colorTab; } -class YUVToRGBManager : public Common::Singleton { -public: - const YUVToRGBLookup *getLookup(Graphics::PixelFormat format); +YUVToRGBManager::YUVToRGBManager() { + _lookup = 0; -private: - friend class Common::Singleton; - YUVToRGBManager(); - ~YUVToRGBManager(); + int16 *Cr_r_tab = &_colorTab[0 * 256]; + int16 *Cr_g_tab = &_colorTab[1 * 256]; + int16 *Cb_g_tab = &_colorTab[2 * 256]; + int16 *Cb_b_tab = &_colorTab[3 * 256]; - Graphics::PixelFormat _lastFormat; - YUVToRGBLookup *_lookup; -}; + // Generate the tables for the display surface -YUVToRGBManager::YUVToRGBManager() { - _lookup = 0; + for (int i = 0; i < 256; i++) { + // Gamma correction (luminescence table) and chroma correction + // would be done here. See the Berkeley mpeg_play sources. + + int16 CR = (i - 128), CB = CR; + Cr_r_tab[i] = (int16) ( (0.419 / 0.299) * CR) + 0 * 768 + 256; + Cr_g_tab[i] = (int16) (-(0.299 / 0.419) * CR) + 1 * 768 + 256; + Cb_g_tab[i] = (int16) (-(0.114 / 0.331) * CB); + Cb_b_tab[i] = (int16) ( (0.587 / 0.331) * CB) + 2 * 768 + 256; + } } YUVToRGBManager::~YUVToRGBManager() { @@ -184,24 +166,14 @@ const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format) { return _lookup; } -} // End of namespace Graphics - -namespace Common { -DECLARE_SINGLETON(Graphics::YUVToRGBManager); -} - -#define YUVToRGBMan (Graphics::YUVToRGBManager::instance()) - -namespace Graphics { - #define PUT_PIXEL(s, d) \ L = &rgbToPix[(s)]; \ *((PixelInt *)(d)) = (L[cr_r] | L[crb_g] | L[cb_b]) template -void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Keep the tables in pointers here to avoid a dereference on each pixel - const int16 *Cr_r_tab = lookup->_colorTab; + const int16 *Cr_r_tab = colorTab; const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; @@ -229,28 +201,28 @@ void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup } } -void convertYUV444ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert444(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); assert(ySrc && uSrc && vSrc); - const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) - convertYUV444ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV444ToRGB((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); else - convertYUV444ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV444ToRGB((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } template -void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { int halfHeight = yHeight >> 1; int halfWidth = yWidth >> 1; // Keep the tables in pointers here to avoid a dereference on each pixel - const int16 *Cr_r_tab = lookup->_colorTab; + const int16 *Cr_r_tab = colorTab; const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; @@ -283,7 +255,7 @@ void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup } } -void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert420(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); @@ -291,13 +263,13 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS assert((yWidth & 1) == 0); assert((yHeight & 1) == 0); - const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) - convertYUV420ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV420ToRGB((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); else - convertYUV420ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV420ToRGB((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } #define READ_QUAD(ptr, prefix) \ @@ -325,9 +297,9 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS xDiff++ template -void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Keep the tables in pointers here to avoid a dereference on each pixel - const int16 *Cr_r_tab = lookup->_colorTab; + const int16 *Cr_r_tab = colorTab; const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; @@ -368,7 +340,7 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup #undef DO_INTERPOLATION #undef DO_YUV410_PIXEL -void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert410(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); @@ -376,13 +348,13 @@ void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS assert((yWidth & 3) == 0); assert((yHeight & 3) == 0); - const YUVToRGBLookup *lookup = YUVToRGBMan.getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) - convertYUV410ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV410ToRGB((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); else - convertYUV410ToRGB((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); + convertYUV410ToRGB((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch); } } // End of namespace Graphics diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index 73a2c69d7d..3af3fe87e4 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -32,57 +32,76 @@ #define GRAPHICS_YUV_TO_RGB_H #include "common/scummsys.h" +#include "common/singleton.h" #include "graphics/surface.h" namespace Graphics { -/** - * Convert a YUV444 image to an RGB surface - * - * @param dst the destination surface - * @param ySrc the source of the y component - * @param uSrc the source of the u component - * @param vSrc the source of the v component - * @param yWidth the width of the y surface - * @param yHeight the height of the y surface - * @param yPitch the pitch of the y surface - * @param uvPitch the pitch of the u and v surfaces - */ -void convertYUV444ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); +class YUVToRGBLookup; -/** - * Convert a YUV420 image to an RGB surface - * - * @param dst the destination surface - * @param ySrc the source of the y component - * @param uSrc the source of the u component - * @param vSrc the source of the v component - * @param yWidth the width of the y surface (must be divisible by 2) - * @param yHeight the height of the y surface (must be divisible by 2) - * @param yPitch the pitch of the y surface - * @param uvPitch the pitch of the u and v surfaces - */ -void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); +class YUVToRGBManager : public Common::Singleton { +public: + /** + * Convert a YUV444 image to an RGB surface + * + * @param dst the destination surface + * @param ySrc the source of the y component + * @param uSrc the source of the u component + * @param vSrc the source of the v component + * @param yWidth the width of the y surface + * @param yHeight the height of the y surface + * @param yPitch the pitch of the y surface + * @param uvPitch the pitch of the u and v surfaces + */ + void convert444(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); -/** - * Convert a YUV410 image to an RGB surface - * - * Since the chroma has a very low resolution in 410, we perform bilinear scaling - * on the two chroma planes to produce the image. The chroma planes must have - * at least one extra row that can be read from in order to produce a proper - * image (filled with 0x80). This is required in order to speed up this function. - * - * @param dst the destination surface - * @param ySrc the source of the y component - * @param uSrc the source of the u component - * @param vSrc the source of the v component - * @param yWidth the width of the y surface (must be divisible by 4) - * @param yHeight the height of the y surface (must be divisible by 4) - * @param yPitch the pitch of the y surface - * @param uvPitch the pitch of the u and v surfaces - */ -void convertYUV410ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + /** + * Convert a YUV420 image to an RGB surface + * + * @param dst the destination surface + * @param ySrc the source of the y component + * @param uSrc the source of the u component + * @param vSrc the source of the v component + * @param yWidth the width of the y surface (must be divisible by 2) + * @param yHeight the height of the y surface (must be divisible by 2) + * @param yPitch the pitch of the y surface + * @param uvPitch the pitch of the u and v surfaces + */ + void convert420(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + + /** + * Convert a YUV410 image to an RGB surface + * + * Since the chroma has a very low resolution in 410, we perform bilinear scaling + * on the two chroma planes to produce the image. The chroma planes must have + * at least one extra row that can be read from in order to produce a proper + * image (filled with 0x80). This is required in order to speed up this function. + * + * @param dst the destination surface + * @param ySrc the source of the y component + * @param uSrc the source of the u component + * @param vSrc the source of the v component + * @param yWidth the width of the y surface (must be divisible by 4) + * @param yHeight the height of the y surface (must be divisible by 4) + * @param yPitch the pitch of the y surface + * @param uvPitch the pitch of the u and v surfaces + */ + void convert410(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + +private: + friend class Common::Singleton; + YUVToRGBManager(); + ~YUVToRGBManager(); + + const YUVToRGBLookup *getLookup(Graphics::PixelFormat format); + + Graphics::PixelFormat _lastFormat; + YUVToRGBLookup *_lookup; + int16 _colorTab[4 * 256]; // 2048 bytes +}; } // End of namespace Graphics +#define YUVToRGBMan (::Graphics::YUVToRGBManager::instance()) + #endif -- cgit v1.2.3 From 09269fce8c61b8193b25266b681c7849a6ad058d Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 18 Sep 2012 15:54:45 -0400 Subject: GRAPHICS: Implement different luminance ranges Bink and Theora are now much improved --- graphics/decoders/jpeg.cpp | 2 +- graphics/yuv_to_rgb.cpp | 100 ++++++++++++++++++++++++++++----------------- graphics/yuv_to_rgb.h | 18 +++++--- 3 files changed, 77 insertions(+), 43 deletions(-) (limited to 'graphics') diff --git a/graphics/decoders/jpeg.cpp b/graphics/decoders/jpeg.cpp index 77ca316c6d..748275b84b 100644 --- a/graphics/decoders/jpeg.cpp +++ b/graphics/decoders/jpeg.cpp @@ -81,7 +81,7 @@ const Surface *JPEGDecoder::getSurface() const { const Graphics::Surface *uComponent = getComponent(2); const Graphics::Surface *vComponent = getComponent(3); - YUVToRGBMan.convert444(_rgbSurface, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); + YUVToRGBMan.convert444(_rgbSurface, Graphics::YUVToRGBManager::kScaleFull, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); return _rgbSurface; } diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp index 1afd0d295b..6043315a13 100644 --- a/graphics/yuv_to_rgb.cpp +++ b/graphics/yuv_to_rgb.cpp @@ -94,40 +94,67 @@ namespace Graphics { class YUVToRGBLookup { public: - YUVToRGBLookup(Graphics::PixelFormat format); - ~YUVToRGBLookup(); + YUVToRGBLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale); - uint32 *_rgbToPix; + Graphics::PixelFormat getFormat() const { return _format; } + YUVToRGBManager::LuminanceScale getScale() const { return _scale; } + const uint32 *getRGBToPix() const { return _rgbToPix; } + +private: + Graphics::PixelFormat _format; + YUVToRGBManager::LuminanceScale _scale; + uint32 _rgbToPix[3 * 768]; // 9216 bytes }; -YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format) { - _rgbToPix = new uint32[3 * 768]; // 9216 bytes +YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale) { + _format = format; + _scale = scale; uint32 *r_2_pix_alloc = &_rgbToPix[0 * 768]; uint32 *g_2_pix_alloc = &_rgbToPix[1 * 768]; uint32 *b_2_pix_alloc = &_rgbToPix[2 * 768]; - // Set up entries 0-255 in rgb-to-pixel value tables. - for (int i = 0; i < 256; i++) { - r_2_pix_alloc[i + 256] = format.RGBToColor(i, 0, 0); - g_2_pix_alloc[i + 256] = format.RGBToColor(0, i, 0); - b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, i); - } + if (scale == YUVToRGBManager::kScaleFull) { + // Set up entries 0-255 in rgb-to-pixel value tables. + for (int i = 0; i < 256; i++) { + r_2_pix_alloc[i + 256] = format.RGBToColor(i, 0, 0); + g_2_pix_alloc[i + 256] = format.RGBToColor(0, i, 0); + b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, i); + } - // Spread out the values we have to the rest of the array so that we do - // not need to check for overflow. - for (int i = 0; i < 256; i++) { - r_2_pix_alloc[i] = r_2_pix_alloc[256]; - r_2_pix_alloc[i + 512] = r_2_pix_alloc[511]; - g_2_pix_alloc[i] = g_2_pix_alloc[256]; - g_2_pix_alloc[i + 512] = g_2_pix_alloc[511]; - b_2_pix_alloc[i] = b_2_pix_alloc[256]; - b_2_pix_alloc[i + 512] = b_2_pix_alloc[511]; - } -} + // Spread out the values we have to the rest of the array so that we do + // not need to check for overflow. + for (int i = 0; i < 256; i++) { + r_2_pix_alloc[i] = r_2_pix_alloc[256]; + r_2_pix_alloc[i + 512] = r_2_pix_alloc[511]; + g_2_pix_alloc[i] = g_2_pix_alloc[256]; + g_2_pix_alloc[i + 512] = g_2_pix_alloc[511]; + b_2_pix_alloc[i] = b_2_pix_alloc[256]; + b_2_pix_alloc[i + 512] = b_2_pix_alloc[511]; + } + } else { + // Set up entries 16-235 in rgb-to-pixel value tables + for (int i = 16; i < 236; i++) { + int scaledValue = (i - 16) * 255 / 219; + r_2_pix_alloc[i + 256] = format.RGBToColor(scaledValue, 0, 0); + g_2_pix_alloc[i + 256] = format.RGBToColor(0, scaledValue, 0); + b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, scaledValue); + } + + // Spread out the values we have to the rest of the array so that we do + // not need to check for overflow. We have to do it here in two steps. + for (int i = 0; i < 256 + 16; i++) { + r_2_pix_alloc[i] = r_2_pix_alloc[256 + 16]; + g_2_pix_alloc[i] = g_2_pix_alloc[256 + 16]; + b_2_pix_alloc[i] = b_2_pix_alloc[256 + 16]; + } -YUVToRGBLookup::~YUVToRGBLookup() { - delete[] _rgbToPix; + for (int i = 256 + 236; i < 768; i++) { + r_2_pix_alloc[i] = r_2_pix_alloc[256 + 236 - 1]; + g_2_pix_alloc[i] = g_2_pix_alloc[256 + 236 - 1]; + b_2_pix_alloc[i] = b_2_pix_alloc[256 + 236 - 1]; + } + } } YUVToRGBManager::YUVToRGBManager() { @@ -156,13 +183,12 @@ YUVToRGBManager::~YUVToRGBManager() { delete _lookup; } -const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format) { - if (_lastFormat == format) +const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale) { + if (_lookup && _lookup->getFormat() == format && _lookup->getScale() == scale) return _lookup; delete _lookup; - _lookup = new YUVToRGBLookup(format); - _lastFormat = format; + _lookup = new YUVToRGBLookup(format, scale); return _lookup; } @@ -177,7 +203,7 @@ void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; - const uint32 *rgbToPix = lookup->_rgbToPix; + const uint32 *rgbToPix = lookup->getRGBToPix(); for (int h = 0; h < yHeight; h++) { for (int w = 0; w < yWidth; w++) { @@ -201,13 +227,13 @@ void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup } } -void YUVToRGBManager::convert444(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert444(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); assert(ySrc && uSrc && vSrc); - const YUVToRGBLookup *lookup = getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format, scale); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) @@ -226,7 +252,7 @@ void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; - const uint32 *rgbToPix = lookup->_rgbToPix; + const uint32 *rgbToPix = lookup->getRGBToPix(); for (int h = 0; h < halfHeight; h++) { for (int w = 0; w < halfWidth; w++) { @@ -255,7 +281,7 @@ void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup } } -void YUVToRGBManager::convert420(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert420(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); @@ -263,7 +289,7 @@ void YUVToRGBManager::convert420(Graphics::Surface *dst, const byte *ySrc, const assert((yWidth & 1) == 0); assert((yHeight & 1) == 0); - const YUVToRGBLookup *lookup = getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format, scale); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) @@ -303,7 +329,7 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; - const uint32 *rgbToPix = lookup->_rgbToPix; + const uint32 *rgbToPix = lookup->getRGBToPix(); int quarterWidth = yWidth >> 2; @@ -340,7 +366,7 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup #undef DO_INTERPOLATION #undef DO_YUV410_PIXEL -void YUVToRGBManager::convert410(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert410(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); @@ -348,7 +374,7 @@ void YUVToRGBManager::convert410(Graphics::Surface *dst, const byte *ySrc, const assert((yWidth & 3) == 0); assert((yHeight & 3) == 0); - const YUVToRGBLookup *lookup = getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format, scale); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index 3af3fe87e4..68a0449d2c 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -41,10 +41,17 @@ class YUVToRGBLookup; class YUVToRGBManager : public Common::Singleton { public: + /** The scale of the luminance values */ + enum LuminanceScale { + kScaleFull, /** Luminance values range from [0, 255] */ + kScaleITU /** Luminance values range from [16, 235], the range from ITU-R BT.601 */ + }; + /** * Convert a YUV444 image to an RGB surface * * @param dst the destination surface + * @param scale the scale of the luminance values * @param ySrc the source of the y component * @param uSrc the source of the u component * @param vSrc the source of the v component @@ -53,12 +60,13 @@ public: * @param yPitch the pitch of the y surface * @param uvPitch the pitch of the u and v surfaces */ - void convert444(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + void convert444(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); /** * Convert a YUV420 image to an RGB surface * * @param dst the destination surface + * @param scale the scale of the luminance values * @param ySrc the source of the y component * @param uSrc the source of the u component * @param vSrc the source of the v component @@ -67,7 +75,7 @@ public: * @param yPitch the pitch of the y surface * @param uvPitch the pitch of the u and v surfaces */ - void convert420(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + void convert420(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); /** * Convert a YUV410 image to an RGB surface @@ -78,6 +86,7 @@ public: * image (filled with 0x80). This is required in order to speed up this function. * * @param dst the destination surface + * @param scale the scale of the luminance values * @param ySrc the source of the y component * @param uSrc the source of the u component * @param vSrc the source of the v component @@ -86,16 +95,15 @@ public: * @param yPitch the pitch of the y surface * @param uvPitch the pitch of the u and v surfaces */ - void convert410(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + void convert410(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); private: friend class Common::Singleton; YUVToRGBManager(); ~YUVToRGBManager(); - const YUVToRGBLookup *getLookup(Graphics::PixelFormat format); + const YUVToRGBLookup *getLookup(Graphics::PixelFormat format, LuminanceScale scale); - Graphics::PixelFormat _lastFormat; YUVToRGBLookup *_lookup; int16 _colorTab[4 * 256]; // 2048 bytes }; -- cgit v1.2.3 From 0677871ea94356e0a4a224840de691c05c05e8c5 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 19 Sep 2012 16:00:27 -0400 Subject: GRAPHICS: Update YUV410 conversion docs --- graphics/yuv_to_rgb.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'graphics') diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index 68a0449d2c..0e832be0ec 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -82,8 +82,9 @@ public: * * Since the chroma has a very low resolution in 410, we perform bilinear scaling * on the two chroma planes to produce the image. The chroma planes must have - * at least one extra row that can be read from in order to produce a proper - * image (filled with 0x80). This is required in order to speed up this function. + * at least one extra row and one extra column that can be read from in order to + * produce a proper image. It is suggested that you fill these in with the previous + * row and column's data. This is required in order to speed up this function. * * @param dst the destination surface * @param scale the scale of the luminance values -- cgit v1.2.3 From dc6b98f64c131bdc4b1962f4a1552bc6e97fb29a Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 25 Sep 2012 15:16:54 +0200 Subject: GRAPHICS: Slight formatting fixes in aspect.cpp. --- graphics/scaler/aspect.cpp | 62 +++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'graphics') diff --git a/graphics/scaler/aspect.cpp b/graphics/scaler/aspect.cpp index 429640fdbd..327e7c5e89 100644 --- a/graphics/scaler/aspect.cpp +++ b/graphics/scaler/aspect.cpp @@ -66,36 +66,36 @@ static inline void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint1 template static void interpolate5LineNeon(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int width, int k1, int k2) { - uint16x4_t kRedBlueMask_4 = vdup_n_u16(ColorMask::kRedBlueMask); - uint16x4_t kGreenMask_4 = vdup_n_u16(ColorMask::kGreenMask); - uint16x4_t k1_4 = vdup_n_u16(k1); - uint16x4_t k2_4 = vdup_n_u16(k2); - while (width >= 4) { - uint16x4_t srcA_4 = vld1_u16(srcA); - uint16x4_t srcB_4 = vld1_u16(srcB); - uint16x4_t p1_4 = srcB_4; - uint16x4_t p2_4 = srcA_4; - - uint16x4_t p1_rb_4 = vand_u16(p1_4, kRedBlueMask_4); - uint16x4_t p1_g_4 = vand_u16(p1_4, kGreenMask_4); - uint16x4_t p2_rb_4 = vand_u16(p2_4, kRedBlueMask_4); - uint16x4_t p2_g_4 = vand_u16(p2_4, kGreenMask_4); - - uint32x4_t tmp_rb_4 = vshrq_n_u32(vmlal_u16(vmull_u16(p2_rb_4, k2_4), p1_rb_4, k1_4), 3); - uint32x4_t tmp_g_4 = vshrq_n_u32(vmlal_u16(vmull_u16(p2_g_4, k2_4), p1_g_4, k1_4), 3); - uint16x4_t p_rb_4 = vmovn_u32(tmp_rb_4); - p_rb_4 = vand_u16(p_rb_4, kRedBlueMask_4); - uint16x4_t p_g_4 = vmovn_u32(tmp_g_4); - p_g_4 = vand_u16(p_g_4, kGreenMask_4); - - uint16x4_t result_4 = p_rb_4 | p_g_4; - vst1_u16(dst, result_4); - - dst += 4; - srcA += 4; - srcB += 4; - width -= 4; - } + uint16x4_t kRedBlueMask_4 = vdup_n_u16(ColorMask::kRedBlueMask); + uint16x4_t kGreenMask_4 = vdup_n_u16(ColorMask::kGreenMask); + uint16x4_t k1_4 = vdup_n_u16(k1); + uint16x4_t k2_4 = vdup_n_u16(k2); + while (width >= 4) { + uint16x4_t srcA_4 = vld1_u16(srcA); + uint16x4_t srcB_4 = vld1_u16(srcB); + uint16x4_t p1_4 = srcB_4; + uint16x4_t p2_4 = srcA_4; + + uint16x4_t p1_rb_4 = vand_u16(p1_4, kRedBlueMask_4); + uint16x4_t p1_g_4 = vand_u16(p1_4, kGreenMask_4); + uint16x4_t p2_rb_4 = vand_u16(p2_4, kRedBlueMask_4); + uint16x4_t p2_g_4 = vand_u16(p2_4, kGreenMask_4); + + uint32x4_t tmp_rb_4 = vshrq_n_u32(vmlal_u16(vmull_u16(p2_rb_4, k2_4), p1_rb_4, k1_4), 3); + uint32x4_t tmp_g_4 = vshrq_n_u32(vmlal_u16(vmull_u16(p2_g_4, k2_4), p1_g_4, k1_4), 3); + uint16x4_t p_rb_4 = vmovn_u32(tmp_rb_4); + p_rb_4 = vand_u16(p_rb_4, kRedBlueMask_4); + uint16x4_t p_g_4 = vmovn_u32(tmp_g_4); + p_g_4 = vand_u16(p_g_4, kGreenMask_4); + + uint16x4_t result_4 = p_rb_4 | p_g_4; + vst1_u16(dst, result_4); + + dst += 4; + srcA += 4; + srcB += 4; + width -= 4; + } } #endif @@ -114,7 +114,7 @@ static void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint16 *srcB *dst++ = interpolate16_7_1(*srcB++, *srcA++); } } else { - #ifdef NEON_ASPECT_CORRECTOR +#ifdef NEON_ASPECT_CORRECTOR int width4 = width & ~3; interpolate5LineNeon(dst, srcA, srcB, width4, 5, 3); srcA += width4; -- cgit v1.2.3 From 89abab97e3124fa25eb4c7d3e8b38501747a8d17 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 26 Sep 2012 04:17:31 +0200 Subject: JANITORIAL: Remove trailing whitespaces. Powered by: git ls-files "*.cpp" "*.h" "*.m" "*.mm" | xargs sed -i -e 's/[ \t]*$//' --- graphics/VectorRenderer.cpp | 2 +- graphics/VectorRenderer.h | 2 +- graphics/VectorRendererSpec.cpp | 64 ++++++++++++++++++++--------------------- graphics/decoders/bmp.cpp | 6 ++-- graphics/decoders/jpeg.cpp | 2 +- graphics/decoders/pcx.cpp | 34 +++++++++++----------- graphics/decoders/pcx.h | 2 +- graphics/decoders/pict.cpp | 2 +- graphics/fonts/consolefont.cpp | 2 +- graphics/fonts/newfont.cpp | 2 +- graphics/fonts/newfont_big.cpp | 2 +- graphics/sjis.h | 2 +- graphics/yuv_to_rgb.h | 2 +- 13 files changed, 62 insertions(+), 62 deletions(-) (limited to 'graphics') diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp index 30ef9eeeeb..f426dd8c41 100644 --- a/graphics/VectorRenderer.cpp +++ b/graphics/VectorRenderer.cpp @@ -80,7 +80,7 @@ void VectorRenderer::stepGetPositions(const DrawStep &step, const Common::Rect & case Graphics::DrawStep::kVectorAlignManual: if (step.x >= 0) in_x = area.left + step.x + step.padding.left; - else + else in_x = area.left + area.width() + step.x + step.padding.left; // value relative to the opposite corner. break; diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h index e98f4aa761..0467cac946 100644 --- a/graphics/VectorRenderer.h +++ b/graphics/VectorRenderer.h @@ -55,7 +55,7 @@ struct DrawStep { bool autoWidth, autoHeight; int16 x, y, w, h; /**< width, height and position, if not measured automatically. negative values mean counting from the opposite direction */ - + Common::Rect padding; enum VectorAlignment { diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index 1ed5a3308a..6a3ee306a5 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -369,12 +369,12 @@ gradientFill(PixelType *ptr, int width, int x, int y) { int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize; // Dithering: - // +--+ +--+ +--+ +--+ - // | | | | | *| | *| - // | | | *| |* | |**| - // +--+ +--+ +--+ +--+ + // +--+ +--+ +--+ +--+ + // | | | | | *| | *| + // | | | *| |* | |**| + // +--+ +--+ +--+ +--+ // 0 1 2 3 - if (grad == 0 || + if (grad == 0 || _gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change stripSize < 2) { // the stip is small colorFill(ptr, ptr + width, _gradCache[curGrad]); @@ -873,7 +873,7 @@ drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) { case kTriangleDown: drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode); break; - + case kTriangleLeft: case kTriangleRight: case kTriangleAuto: @@ -1206,14 +1206,14 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color pitch = -pitch; y1 += h; } - + PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1); PixelType *floor = ptr_right - 1; PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1); int x2 = x1 + w / 2; int y2 = y1 + h; - + #if FIXED_POINT int dx = (x2 - x1) << 8; int dy = (y2 - y1) << 8; @@ -1227,7 +1227,7 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color #endif while (floor++ != ptr_left) blendPixelPtr(floor, color, 50); - + #if FIXED_POINT int gradient = (dy << 8) / dx; int intery = (y1 << 8) + gradient; @@ -1250,7 +1250,7 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color ptr_right += pitch; intery += gradient; - + switch (fill_m) { case kFillDisabled: *ptr_left = *ptr_right = color; @@ -1262,16 +1262,16 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color blendPixelPtr(ptr_left, color, rfpart(intery)); break; case kFillGradient: - colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h)); + colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h)); blendPixelPtr(ptr_right, color, rfpart(intery)); blendPixelPtr(ptr_left, color, rfpart(intery)); break; } } - + return; } - + #if FIXED_POINT if (abs(dx) < abs(dy)) { #else @@ -1280,7 +1280,7 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color ptr_left--; while (floor++ != ptr_left) blendPixelPtr(floor, color, 50); - + #if FIXED_POINT int gradient = (dx << 8) / (dy + 0x100); int interx = (x1 << 8) + gradient; @@ -1303,7 +1303,7 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color ptr_right += pitch; interx += gradient; - + switch (fill_m) { case kFillDisabled: *ptr_left = *ptr_right = color; @@ -1315,18 +1315,18 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color blendPixelPtr(ptr_left, color, rfpart(interx)); break; case kFillGradient: - colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h)); + colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h)); blendPixelPtr(ptr_right, color, rfpart(interx)); blendPixelPtr(ptr_left, color, rfpart(interx)); break; } } - + return; } - + ptr_left--; - + while (floor++ != ptr_left) blendPixelPtr(floor, color, 50); @@ -1341,12 +1341,12 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color for (int y = y1 + 1; y < y2; y++) { ptr_right++; ptr_left--; - + ptr_left += pitch; ptr_right += pitch; interx += gradient; - + switch (fill_m) { case kFillDisabled: *ptr_left = *ptr_right = color; @@ -1358,13 +1358,13 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color blendPixelPtr(ptr_left, color, rfpart(interx)); break; case kFillGradient: - colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h)); + colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h)); blendPixelPtr(ptr_right, color, rfpart(interx)); blendPixelPtr(ptr_left, color, rfpart(interx)); break; } } - + } /** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */ @@ -1372,12 +1372,12 @@ template void VectorRendererSpec:: drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) { int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; - + if (!inverted) { pitch = -pitch; y1 += size; } - + int gradient_h = 0; PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1); PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + size, y1); @@ -1388,9 +1388,9 @@ drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, Vecto int signX = x1 < x2 ? 1 : -1; int signY = y1 < y2 ? 1 : -1; int error = deltaX - deltaY; - + colorFill(ptr_right, ptr_left, color); - + while (1) { switch (fill_m) { case kFillDisabled: @@ -1401,22 +1401,22 @@ drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, Vecto colorFill(ptr_right, ptr_left, color); break; case kFillGradient: - colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, size)); + colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, size)); break; } - + if (x1 == x2 && y1 == y2) break; - + int error2 = error * 2; - + if (error2 > -deltaY) { error -= deltaY; x1 += signX; ptr_right += signX; ptr_left += -signX; } - + if (error2 < deltaX) { error += deltaX; y1 += signY; diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp index 0d2165643d..bcfd0abbda 100644 --- a/graphics/decoders/bmp.cpp +++ b/graphics/decoders/bmp.cpp @@ -155,7 +155,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { } } else { // 32 bpp byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; - + for (int32 i = 0; i < height; i++) { for (uint32 j = 0; j < width; j++) { byte b = stream.readByte(); @@ -166,11 +166,11 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { // ref: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376%28v=vs.85%29.aspx stream.readByte(); uint32 color = format.RGBToColor(r, g, b); - + *((uint32 *)dst) = color; dst += format.bytesPerPixel; } - + stream.skip(extraDataLength); dst -= _surface->pitch * 2; } diff --git a/graphics/decoders/jpeg.cpp b/graphics/decoders/jpeg.cpp index 748275b84b..08bc1f7a3d 100644 --- a/graphics/decoders/jpeg.cpp +++ b/graphics/decoders/jpeg.cpp @@ -452,7 +452,7 @@ bool JPEGDecoder::readSOS() { _bitsNumber = 0; for (byte i = 0; i < _numScanComp; i++) - _scanComp[i]->DCpredictor = 0; + _scanComp[i]->DCpredictor = 0; } } } diff --git a/graphics/decoders/pcx.cpp b/graphics/decoders/pcx.cpp index f5c1c24bb0..1250398c73 100644 --- a/graphics/decoders/pcx.cpp +++ b/graphics/decoders/pcx.cpp @@ -59,33 +59,33 @@ void PCXDecoder::destroy() { bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) { destroy(); - + if (stream.readByte() != 0x0a) // ZSoft PCX return false; - + byte version = stream.readByte(); // 0 - 5 if (version > 5) return false; - + bool compressed = stream.readByte(); // encoding, 1 = run length encoding byte bitsPerPixel = stream.readByte(); // 1, 2, 4 or 8 - + // Window uint16 xMin = stream.readUint16LE(); uint16 yMin = stream.readUint16LE(); uint16 xMax = stream.readUint16LE(); uint16 yMax = stream.readUint16LE(); - + uint16 width = xMax - xMin + 1; uint16 height = yMax - yMin + 1; - + if (xMax < xMin || yMax < yMin) { warning("Invalid PCX image dimensions"); return false; } - + stream.skip(4); // HDpi, VDpi - + // Read the EGA palette (colormap) _palette = new byte[16 * 3]; for (uint16 i = 0; i < 16; i++) { @@ -96,24 +96,24 @@ bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) { if (stream.readByte() != 0) // reserved, should be set to 0 return false; - + byte nPlanes = stream.readByte(); uint16 bytesPerLine = stream.readUint16LE(); uint16 bytesPerscanLine = nPlanes * bytesPerLine; - + if (bytesPerscanLine < width * bitsPerPixel * nPlanes / 8) { warning("PCX data is corrupted"); return false; } - + stream.skip(60); // PaletteInfo, HscreenSize, VscreenSize, Filler - + _surface = new Graphics::Surface(); - + byte *scanLine = new byte[bytesPerscanLine]; byte *dst; int x, y; - + if (nPlanes == 3 && bitsPerPixel == 8) { // 24bpp Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); _surface->create(width, height, format); @@ -142,14 +142,14 @@ bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) { decodeRLE(stream, scanLine, bytesPerscanLine, compressed); memcpy(dst, scanLine, width); } - + if (version == 5) { if (stream.readByte() != 12) { warning("Expected a palette after the PCX image data"); delete[] scanLine; return false; } - + // Read the VGA palette delete[] _palette; _palette = new byte[256 * 3]; @@ -186,7 +186,7 @@ bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) { } delete[] scanLine; - + return true; } diff --git a/graphics/decoders/pcx.h b/graphics/decoders/pcx.h index bcff754a2d..b25166b3d9 100644 --- a/graphics/decoders/pcx.h +++ b/graphics/decoders/pcx.h @@ -57,7 +57,7 @@ public: private: void decodeRLE(Common::SeekableReadStream &stream, byte *dst, uint32 bytesPerScanline, bool compressed); - + Surface *_surface; byte *_palette; uint16 _paletteColorCount; diff --git a/graphics/decoders/pict.cpp b/graphics/decoders/pict.cpp index 9e619df208..d35e5c3064 100644 --- a/graphics/decoders/pict.cpp +++ b/graphics/decoders/pict.cpp @@ -543,7 +543,7 @@ void PICTDecoder::decodeCompressedQuickTime(Common::SeekableReadStream &stream) // Skip the matte and mask stream.skip(matteSize + maskSize); - + // Now we've reached the image descriptor, so read the relevant data from that uint32 idStart = stream.pos(); uint32 idSize = stream.readUint32BE(); diff --git a/graphics/fonts/consolefont.cpp b/graphics/fonts/consolefont.cpp index 8244d75fc2..748aa08a5c 100644 --- a/graphics/fonts/consolefont.cpp +++ b/graphics/fonts/consolefont.cpp @@ -1,7 +1,7 @@ // Generated by convbdf on Fri Jan 6 14:32:21 2012 #include "graphics/fonts/bdf.h" -// Font information: +// Font information: // Name: -Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-1 // Size: 5x8 // Box: 5 8 0 -1 diff --git a/graphics/fonts/newfont.cpp b/graphics/fonts/newfont.cpp index 10af1efb0c..4922e24676 100644 --- a/graphics/fonts/newfont.cpp +++ b/graphics/fonts/newfont.cpp @@ -1,7 +1,7 @@ // Generated by convbdf on Fri Jan 6 14:33:07 2012 #include "graphics/fonts/bdf.h" -// Font information: +// Font information: // Name: -Schumacher-Clean-Medium-R-Normal--12-120-75-75-C-60-ISO8859-1 // Size: 6x12 // Box: 6 12 0 -3 diff --git a/graphics/fonts/newfont_big.cpp b/graphics/fonts/newfont_big.cpp index 0e61068ade..550d6dbfa9 100644 --- a/graphics/fonts/newfont_big.cpp +++ b/graphics/fonts/newfont_big.cpp @@ -1,7 +1,7 @@ // Generated by convbdf on Fri Jan 6 14:33:14 2012 #include "graphics/fonts/bdf.h" -// Font information: +// Font information: // Name: -Adobe-Helvetica-Bold-R-Normal--12-120-75-75-P-70-ISO8859-1 // Size: 13x14 // Box: 13 15 -1 -3 diff --git a/graphics/sjis.h b/graphics/sjis.h index 2d05005fc3..928332f712 100644 --- a/graphics/sjis.h +++ b/graphics/sjis.h @@ -169,7 +169,7 @@ protected: bool _flippedMode; int _fontWidth, _fontHeight; uint8 _bitPosNewLineMask; - + bool isASCII(uint16 ch) const; virtual const uint8 *getCharData(uint16 c) const = 0; diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index 0e832be0ec..f785422c5a 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -78,7 +78,7 @@ public: void convert420(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); /** - * Convert a YUV410 image to an RGB surface + * Convert a YUV410 image to an RGB surface * * Since the chroma has a very low resolution in 410, we perform bilinear scaling * on the two chroma planes to produce the image. The chroma planes must have -- cgit v1.2.3 From a5bce746354aa5711f06de7abac442995ae0d956 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 9 Oct 2012 23:32:51 +0200 Subject: GRAPHICS: Fix compilation of conversion.cpp on motomagx. Using plain "inline" instead of "FORCEINLINE" allows the compiler to continue even when it fails to inline crossBlitLogic/crossBlitLogic3BppSource. The impact of other systems now not inlining the functions anymore is hopefully small enough to not cause any problems. --- graphics/conversion.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'graphics') diff --git a/graphics/conversion.cpp b/graphics/conversion.cpp index fec1d240e2..2da8b6f0ce 100644 --- a/graphics/conversion.cpp +++ b/graphics/conversion.cpp @@ -31,9 +31,9 @@ namespace Graphics { namespace { template -FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const uint h, - const PixelFormat &srcFmt, const PixelFormat &dstFmt, - const uint srcDelta, const uint dstDelta) { +inline void crossBlitLogic(byte *dst, const byte *src, const uint w, const uint h, + const PixelFormat &srcFmt, const PixelFormat &dstFmt, + const uint srcDelta, const uint dstDelta) { for (uint y = 0; y < h; ++y) { for (uint x = 0; x < w; ++x) { const uint32 color = *(const SrcColor *)src; @@ -61,9 +61,9 @@ FORCEINLINE void crossBlitLogic(byte *dst, const byte *src, const uint w, const } template -FORCEINLINE void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint w, const uint h, - const PixelFormat &srcFmt, const PixelFormat &dstFmt, - const uint srcDelta, const uint dstDelta) { +inline void crossBlitLogic3BppSource(byte *dst, const byte *src, const uint w, const uint h, + const PixelFormat &srcFmt, const PixelFormat &dstFmt, + const uint srcDelta, const uint dstDelta) { uint32 color; byte r, g, b, a; uint8 *col = (uint8 *)&color; -- cgit v1.2.3