diff options
author | Matthew Hoops | 2012-08-26 15:49:45 -0400 |
---|---|---|
committer | Matthew Hoops | 2012-08-26 16:12:25 -0400 |
commit | bb1e60e8b2f3bba06ae3b089097f94ea82a70c8a (patch) | |
tree | a434233367725fbb6dc7072776c312f52254d57f /graphics | |
parent | 7a49b3669a0e18210a2f5409cb35da735f549b11 (diff) | |
parent | 857b92f8ffececa9c1f990d21a6a8d1630199a62 (diff) | |
download | scummvm-rg350-bb1e60e8b2f3bba06ae3b089097f94ea82a70c8a.tar.gz scummvm-rg350-bb1e60e8b2f3bba06ae3b089097f94ea82a70c8a.tar.bz2 scummvm-rg350-bb1e60e8b2f3bba06ae3b089097f94ea82a70c8a.zip |
Merge remote branch 'upstream/master' into pegasus
Conflicts:
AUTHORS
devtools/credits.pl
gui/credits.h
Diffstat (limited to 'graphics')
-rw-r--r-- | graphics/decoders/bmp.cpp | 29 | ||||
-rw-r--r-- | graphics/decoders/image_decoder.h | 3 | ||||
-rw-r--r-- | graphics/decoders/png.cpp | 571 | ||||
-rw-r--r-- | graphics/decoders/png.h | 78 | ||||
-rw-r--r-- | graphics/fonts/ttf.cpp | 10 | ||||
-rw-r--r-- | graphics/fonts/ttf.h | 2 | ||||
-rw-r--r-- | graphics/iff.cpp | 23 |
7 files changed, 201 insertions, 515 deletions
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++) { @@ -153,6 +153,27 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { 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; + } } return true; 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; } diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index 492c69779f..bfaab6dc35 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -20,86 +20,25 @@ * */ +// 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" + +#ifdef USE_PNG +#include <png.h> +#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,14 +51,41 @@ 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 @@ -132,374 +98,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; + } + png_infop infoPtr = png_create_info_struct(pngPtr); + if (!infoPtr) { + png_destroy_read_struct(&pngPtr, NULL, NULL); + delete _stream; + return false; + } + png_infop endInfo = png_create_info_struct(pngPtr); + if (!endInfo) { + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + delete _stream; + return false; } - // We no longer need the file stream, thus close it here - _stream = 0; + png_set_error_fn(pngPtr, NULL, pngError, pngWarning); + // TODO: The manual says errors should be handled via setjmp - // Unpack the compressed buffer - Common::MemoryReadStream *compData = new Common::MemoryReadStream(_compressedBuffer, _compressedBufferSize, DisposeAfterUse::YES); - _imageData = Common::wrapCompressedReadStream(compData); + 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); - // Construct the final image - constructImage(); + // Read PNG header + png_read_info(pngPtr, infoPtr); - // Close the uncompressed stream, which will also delete the memory stream, - // and thus the original compressed buffer - delete _imageData; + // 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; - 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<int16>(b - c); - int16 pb = ABS<int16>(a - c); - int16 pc = ABS<int16>(a + b - c - c); - - if (pa <= MIN<int16>(pb, pc)) - return (byte)a; - else if (pb <= pc) - return (byte)b; - else - return (byte)c; -} + // 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(); -/** - * 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]; + // 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; } - 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; + _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; + } - 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] + _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + png_set_packing(pngPtr); + } else { + _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."); } - break; - default: - error("Unknown line filter"); + 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 + } -} + // 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; -int PNGDecoder::getBytesPerPixel() const { - return (getNumColorChannels() * _header.bitDepth + 7) / 8; -} + 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. -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; + // Allocate row pointer buffer + png_bytep *rowPtr = new png_bytep[height]; + if (!rowPtr) { + error("Could not allocate memory for row pointers."); } - 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; - } - delete[] scanLine; + // Initialize row pointers + for (int i = 0; i < height; i++) + rowPtr[i] = (png_bytep)_outputSurface->getBasePtr(0, i); - constructOutput(unfilteredSurface); - delete[] unfilteredSurface; -} + // Read image data + png_read_image(pngPtr, rowPtr); -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 - - 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); + // Free row pointer buffer + delete[] rowPtr; } - error("Unknown PNG color type"); - return Graphics::PixelFormat(); -} + // Read additional data at the end. + png_read_end(pngPtr, NULL); -void PNGDecoder::constructOutput(const byte *surface) { - _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"); - } - - 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; - } - } - } 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; - } - } -} + // Destroy libpng structures + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); -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"); - } -} + // We no longer need the file stream, thus close it here + _stream = 0; -void PNGDecoder::readTransparencyChunk(uint32 chunkLength) { - _transparentColorSpecified = true; - - 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); - - // 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 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(); 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<Common::IFFChunk &, bool, PBMLoader> 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 |