aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/VectorRenderer.cpp2
-rw-r--r--graphics/VectorRenderer.h2
-rw-r--r--graphics/VectorRendererSpec.cpp64
-rw-r--r--graphics/decoders/bmp.cpp12
-rw-r--r--graphics/decoders/image_decoder.h7
-rw-r--r--graphics/decoders/jpeg.cpp4
-rw-r--r--graphics/decoders/pcx.cpp213
-rw-r--r--graphics/decoders/pcx.h68
-rw-r--r--graphics/decoders/pict.cpp14
-rw-r--r--graphics/decoders/pict.h5
-rw-r--r--graphics/decoders/png.cpp1
-rw-r--r--graphics/decoders/tga.cpp427
-rw-r--r--graphics/decoders/tga.h98
-rw-r--r--graphics/fonts/consolefont.cpp2
-rw-r--r--graphics/fonts/newfont.cpp2
-rw-r--r--graphics/fonts/newfont_big.cpp2
-rw-r--r--graphics/module.mk4
-rw-r--r--graphics/primitives.cpp62
-rw-r--r--graphics/primitives.h2
-rw-r--r--graphics/scaler/aspect.cpp62
-rw-r--r--graphics/sjis.h2
-rw-r--r--graphics/surface.cpp11
-rw-r--r--graphics/surface.h16
-rw-r--r--graphics/yuv_to_rgb.cpp188
-rw-r--r--graphics/yuv_to_rgb.h116
25 files changed, 1138 insertions, 248 deletions
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<PixelType>(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<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
+ colorFill<PixelType>(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<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
+ colorFill<PixelType>(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<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
+ colorFill<PixelType>(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<typename PixelType>
void VectorRendererSpec<PixelType>::
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<PixelType>(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<PixelType>(ptr_right, ptr_left, color);
break;
case kFillGradient:
- colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, size));
+ colorFill<PixelType>(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 f15d4e2519..bcfd0abbda 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++) {
@@ -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/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/jpeg.cpp b/graphics/decoders/jpeg.cpp
index a871377ca1..08bc1f7a3d 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, Graphics::YUVToRGBManager::kScaleFull, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch);
return _rgbSurface;
}
@@ -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
new file mode 100644
index 0000000000..1250398c73
--- /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..b25166b3d9
--- /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/decoders/pict.cpp b/graphics/decoders/pict.cpp
index 7eddd3b893..d35e5c3064 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);
@@ -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/decoders/pict.h b/graphics/decoders/pict.h
index 417a7c5134..6f0d86c7a1 100644
--- a/graphics/decoders/pict.h
+++ b/graphics/decoders/pict.h
@@ -24,6 +24,7 @@
* @file
* Image decoder used in engines:
* - mohawk
+ * - pegasus
* - sci
*/
@@ -87,9 +88,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);
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;
diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp
new file mode 100644
index 0000000000..c3b9d84055
--- /dev/null
+++ b/graphics/decoders/tga.cpp
@@ -0,0 +1,427 @@
+/* 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) {
+ // 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, /* 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);
+ } 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;
+ 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);
+ } else if (_colorMapEntryLength == 24) {
+ r = tga.readByte();
+ 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 = 0;
+ }
+#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..dfdc5a4da9
--- /dev/null
+++ b/graphics/decoders/tga.h
@@ -0,0 +1,98 @@
+/* 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/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/module.mk b/graphics/module.mk
index 281f904b38..f560d9dc97 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -25,8 +25,10 @@ MODULE_OBJS := \
yuv_to_rgb.o \
decoders/bmp.o \
decoders/jpeg.o \
+ decoders/pcx.o \
decoders/pict.o \
- decoders/png.o
+ decoders/png.o \
+ decoders/tga.o
ifdef USE_SCALERS
MODULE_OBJS += \
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
diff --git a/graphics/scaler/aspect.cpp b/graphics/scaler/aspect.cpp
index f0ae732a40..327e7c5e89 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 <arm_neon.h>
+#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<typename ColorMask>
+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<typename ColorMask, int scale>
-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) {
+#ifdef NEON_ASPECT_CORRECTOR
+ int width4 = width & ~3;
+ interpolate5LineNeon<ColorMask>(dst, srcA, srcB, width4, 7, 1);
+ srcA += width4;
+ srcB += width4;
+ dst += width4;
+ width -= width4;
+#endif
while (width--) {
*dst++ = interpolate16_7_1<ColorMask>(*srcB++, *srcA++);
}
} else {
+#ifdef NEON_ASPECT_CORRECTOR
+ int width4 = width & ~3;
+ interpolate5LineNeon<ColorMask>(dst, srcA, srcB, width4, 5, 3);
+ srcA += width4;
+ srcB += width4;
+ dst += width4;
+ width -= width4;
+#endif
while (width--) {
*dst++ = interpolate16_5_3<ColorMask>(*srcB++, *srcA++);
}
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/surface.cpp b/graphics/surface.cpp
index 1604eaa488..41ae8dcebb 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -50,6 +50,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<byte>, this);
+ else if (format.bytesPerPixel == 2)
+ Graphics::drawThickLine(x0, y0, x1, y1, penX, penY, color, plotPoint<uint16>, this);
+ else if (format.bytesPerPixel == 4)
+ Graphics::drawThickLine(x0, y0, x1, y1, penX, penY, color, plotPoint<uint32>, 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 eaf62f84eb..6c9e464657 100644
--- a/graphics/surface.h
+++ b/graphics/surface.h
@@ -167,10 +167,26 @@ 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.
*
* @param x The start x coordinate of the line.
diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp
index 78903d0cd8..6043315a13 100644
--- a/graphics/yuv_to_rgb.cpp
+++ b/graphics/yuv_to_rgb.cpp
@@ -83,129 +83,127 @@
// 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 {
class YUVToRGBLookup {
public:
- YUVToRGBLookup(Graphics::PixelFormat format);
- ~YUVToRGBLookup();
-
- int16 *_colorTab;
- uint32 *_rgbToPix;
-};
+ YUVToRGBLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale);
-YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format) {
- _colorTab = new int16[4 * 256]; // 2048 bytes
+ Graphics::PixelFormat getFormat() const { return _format; }
+ YUVToRGBManager::LuminanceScale getScale() const { return _scale; }
+ const uint32 *getRGBToPix() const { return _rgbToPix; }
- 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];
+private:
+ Graphics::PixelFormat _format;
+ YUVToRGBManager::LuminanceScale _scale;
+ uint32 _rgbToPix[3 * 768]; // 9216 bytes
+};
- _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];
- int16 CR, CB;
- int 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];
+ }
+ } 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];
+ }
+
+ 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() {
+ _lookup = 0;
+
+ 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];
// Generate the tables for the display surface
- for (i = 0; i < 256; i++) {
+ for (int 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);
+ 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;
}
-
- // Set up entries 0-255 in rgb-to-pixel value tables.
- for (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 (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];
- }
-}
-
-YUVToRGBLookup::~YUVToRGBLookup() {
- delete[] _rgbToPix;
- delete[] _colorTab;
-}
-
-class YUVToRGBManager : public Common::Singleton<YUVToRGBManager> {
-public:
- const YUVToRGBLookup *getLookup(Graphics::PixelFormat format);
-
-private:
- friend class Common::Singleton<SingletonBaseType>;
- YUVToRGBManager();
- ~YUVToRGBManager();
-
- Graphics::PixelFormat _lastFormat;
- YUVToRGBLookup *_lookup;
-};
-
-YUVToRGBManager::YUVToRGBManager() {
- _lookup = 0;
}
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;
}
-} // 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<typename PixelInt>
-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;
- const uint32 *rgbToPix = lookup->_rgbToPix;
+ const uint32 *rgbToPix = lookup->getRGBToPix();
for (int h = 0; h < yHeight; h++) {
for (int w = 0; w < yWidth; w++) {
@@ -229,32 +227,32 @@ 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, 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 = YUVToRGBMan.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)
- convertYUV444ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
+ convertYUV444ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
else
- convertYUV444ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
+ convertYUV444ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
}
template<typename PixelInt>
-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;
- const uint32 *rgbToPix = lookup->_rgbToPix;
+ const uint32 *rgbToPix = lookup->getRGBToPix();
for (int h = 0; h < halfHeight; h++) {
for (int w = 0; w < halfWidth; w++) {
@@ -283,7 +281,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, 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);
@@ -291,13 +289,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, scale);
// Use a templated function to avoid an if check on every pixel
if (dst->format.bytesPerPixel == 2)
- convertYUV420ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
+ convertYUV420ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
else
- convertYUV420ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
+ convertYUV420ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
}
#define READ_QUAD(ptr, prefix) \
@@ -325,13 +323,13 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS
xDiff++
template<typename PixelInt>
-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;
- const uint32 *rgbToPix = lookup->_rgbToPix;
+ const uint32 *rgbToPix = lookup->getRGBToPix();
int quarterWidth = yWidth >> 2;
@@ -368,7 +366,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, 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);
@@ -376,13 +374,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, scale);
// Use a templated function to avoid an if check on every pixel
if (dst->format.bytesPerPixel == 2)
- convertYUV410ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
+ convertYUV410ToRGB<uint16>((byte *)dst->pixels, dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
else
- convertYUV410ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
+ convertYUV410ToRGB<uint32>((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..f785422c5a 100644
--- a/graphics/yuv_to_rgb.h
+++ b/graphics/yuv_to_rgb.h
@@ -32,57 +32,85 @@
#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<YUVToRGBManager> {
+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 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 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
+ * @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, 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
+ * @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, 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
+ *
+ * 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 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
+ * @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, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
+
+private:
+ friend class Common::Singleton<SingletonBaseType>;
+ YUVToRGBManager();
+ ~YUVToRGBManager();
+
+ const YUVToRGBLookup *getLookup(Graphics::PixelFormat format, LuminanceScale scale);
+
+ YUVToRGBLookup *_lookup;
+ int16 _colorTab[4 * 256]; // 2048 bytes
+};
} // End of namespace Graphics
+#define YUVToRGBMan (::Graphics::YUVToRGBManager::instance())
+
#endif