diff options
Diffstat (limited to 'graphics')
-rw-r--r-- | graphics/VectorRenderer.cpp | 2 | ||||
-rw-r--r-- | graphics/VectorRenderer.h | 2 | ||||
-rw-r--r-- | graphics/VectorRendererSpec.cpp | 64 | ||||
-rw-r--r-- | graphics/decoders/bmp.cpp | 12 | ||||
-rw-r--r-- | graphics/decoders/image_decoder.h | 7 | ||||
-rw-r--r-- | graphics/decoders/jpeg.cpp | 4 | ||||
-rw-r--r-- | graphics/decoders/pcx.cpp | 213 | ||||
-rw-r--r-- | graphics/decoders/pcx.h | 68 | ||||
-rw-r--r-- | graphics/decoders/pict.cpp | 14 | ||||
-rw-r--r-- | graphics/decoders/pict.h | 5 | ||||
-rw-r--r-- | graphics/decoders/png.cpp | 1 | ||||
-rw-r--r-- | graphics/decoders/tga.cpp | 427 | ||||
-rw-r--r-- | graphics/decoders/tga.h | 98 | ||||
-rw-r--r-- | graphics/fonts/consolefont.cpp | 2 | ||||
-rw-r--r-- | graphics/fonts/newfont.cpp | 2 | ||||
-rw-r--r-- | graphics/fonts/newfont_big.cpp | 2 | ||||
-rw-r--r-- | graphics/module.mk | 4 | ||||
-rw-r--r-- | graphics/primitives.cpp | 62 | ||||
-rw-r--r-- | graphics/primitives.h | 2 | ||||
-rw-r--r-- | graphics/scaler/aspect.cpp | 62 | ||||
-rw-r--r-- | graphics/sjis.h | 2 | ||||
-rw-r--r-- | graphics/surface.cpp | 11 | ||||
-rw-r--r-- | graphics/surface.h | 16 | ||||
-rw-r--r-- | graphics/yuv_to_rgb.cpp | 188 | ||||
-rw-r--r-- | graphics/yuv_to_rgb.h | 116 |
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 |