aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorAlyssa Milburn2012-08-28 15:39:00 +0200
committerAlyssa Milburn2012-08-28 15:54:12 +0200
commit31801137b5c6908edd76f357b3f29b07e9e3be84 (patch)
tree33e973717545ae27da6ba4996d0d8fe1bcd437b3 /graphics
parent35fd91793b34b72624a89f2a76f45bc8e59020d2 (diff)
parent6ab8db638e4a1d547ee67db067b5d6c3d6c940a4 (diff)
downloadscummvm-rg350-31801137b5c6908edd76f357b3f29b07e9e3be84.tar.gz
scummvm-rg350-31801137b5c6908edd76f357b3f29b07e9e3be84.tar.bz2
scummvm-rg350-31801137b5c6908edd76f357b3f29b07e9e3be84.zip
Merge remote-tracking branch 'origin/master' into tony
Conflicts: common/coroutines.cpp common/coroutines.h devtools/create_project/msbuild.cpp devtools/create_project/visualstudio.cpp
Diffstat (limited to 'graphics')
-rw-r--r--graphics/VectorRendererSpec.cpp4
-rw-r--r--graphics/cursorman.cpp20
-rw-r--r--graphics/cursorman.h14
-rw-r--r--graphics/decoders/bmp.cpp41
-rw-r--r--graphics/decoders/bmp.h2
-rw-r--r--graphics/decoders/image_decoder.h8
-rw-r--r--graphics/decoders/pict.cpp26
-rw-r--r--graphics/decoders/pict.h2
-rw-r--r--graphics/decoders/png.cpp571
-rw-r--r--graphics/decoders/png.h77
-rw-r--r--graphics/fontman.cpp36
-rw-r--r--graphics/fontman.h5
-rw-r--r--graphics/fonts/bdf.h2
-rw-r--r--graphics/fonts/ttf.cpp18
-rw-r--r--graphics/fonts/ttf.h4
-rw-r--r--graphics/iff.cpp23
-rw-r--r--graphics/pixelformat.h2
-rw-r--r--graphics/scaler.cpp9
-rw-r--r--graphics/scaler/aspect.cpp10
-rw-r--r--graphics/wincursor.cpp40
-rw-r--r--graphics/wincursor.h42
21 files changed, 352 insertions, 604 deletions
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<PixelType>::
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()
);
}
diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp
index 425714ea34..c818101645 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 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();
_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 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, 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 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();
@@ -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..66e8d1ba56 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 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
@@ -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 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.
@@ -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 void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL);
~Cursor();
};
diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp
index 0d44881d7c..f15d4e2519 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) {
@@ -80,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;
}
@@ -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();
@@ -117,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();
@@ -134,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++) {
@@ -151,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/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..830645d361 100644
--- a/graphics/decoders/image_decoder.h
+++ b/graphics/decoders/image_decoder.h
@@ -75,9 +75,17 @@ 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; }
+
+ /** 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 9963873b54..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;
@@ -361,14 +364,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 +383,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;
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..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) {
+PNGDecoder::PNGDecoder() : _outputSurface(0), _palette(0), _paletteColorCount(0) {
}
PNGDecoder::~PNGDecoder() {
@@ -112,12 +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);
+}
+
+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
@@ -130,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;
-
- // Unpack the compressed buffer
- Common::MemoryReadStream *compData = new Common::MemoryReadStream(_compressedBuffer, _compressedBufferSize, DisposeAfterUse::YES);
- _imageData = Common::wrapCompressedReadStream(compData);
+ png_set_error_fn(pngPtr, NULL, pngError, pngWarning);
+ // TODO: The manual says errors should be handled via setjmp
- // Construct the final image
- constructImage();
+ 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);
- // Close the uncompressed stream, which will also delete the memory stream,
- // and thus the original compressed buffer
- delete _imageData;
+ // Read PNG header
+ png_read_info(pngPtr, infoPtr);
- return true;
-}
+ // 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;
-/**
- * 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 1da0bea1ab..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,61 +52,13 @@ public:
void destroy();
const Graphics::Surface *getSurface() const { return _outputSurface; }
const byte *getPalette() const { return _palette; }
-
+ 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/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<Common::String, const Font *>::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<Common::String, const Font *> _fontMap;
+ Common::Array<const Font *> _ownedFonts;
Common::String _localizedFontName;
};
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) \
diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp
index 7505f7913e..2b1dca1eae 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;
}
@@ -70,6 +66,10 @@ private:
bool _initialized;
};
+void shutdownTTF() {
+ TTFLibrary::destroy();
+}
+
#define g_ttf ::Graphics::TTFLibrary::instance()
TTFLibrary::TTFLibrary() : _library(), _initialized(false) {
@@ -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 7222d6e112..e1464b1f45 100644
--- a/graphics/fonts/ttf.h
+++ b/graphics/fonts/ttf.h
@@ -32,7 +32,9 @@
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();
} // End of namespace 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<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
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;
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<ColorMask, 1>((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
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<CursorItem> cursors;