aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorMatthew Hoops2010-05-24 17:18:09 +0000
committerMatthew Hoops2010-05-24 17:18:09 +0000
commitad0eb0b06ef6c715280c21a1c036be5c56a3183a (patch)
treeca9821a5cdf704cf8e8cdfa5f5a22fb8e61d6e22 /graphics
parentafd909d69e461f42b454e8b6ff89cdca145890be (diff)
downloadscummvm-rg350-ad0eb0b06ef6c715280c21a1c036be5c56a3183a.tar.gz
scummvm-rg350-ad0eb0b06ef6c715280c21a1c036be5c56a3183a.tar.bz2
scummvm-rg350-ad0eb0b06ef6c715280c21a1c036be5c56a3183a.zip
Move the PICT code to graphics/ with some updates; needed for SCI1.1 Mac.
svn-id: r49195
Diffstat (limited to 'graphics')
-rw-r--r--graphics/module.mk1
-rw-r--r--graphics/pict.cpp333
-rw-r--r--graphics/pict.h83
3 files changed, 417 insertions, 0 deletions
diff --git a/graphics/module.mk b/graphics/module.mk
index c7f5771420..75e3919370 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -13,6 +13,7 @@ MODULE_OBJS := \
iff.o \
imagedec.o \
jpeg.o \
+ pict.o \
primitives.o \
scaler.o \
scaler/thumbnail_intern.o \
diff --git a/graphics/pict.cpp b/graphics/pict.cpp
new file mode 100644
index 0000000000..f0dd7bbc6f
--- /dev/null
+++ b/graphics/pict.cpp
@@ -0,0 +1,333 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stream.h"
+
+#include "graphics/conversion.h"
+#include "graphics/jpeg.h"
+#include "graphics/pict.h"
+#include "graphics/surface.h"
+
+namespace Graphics {
+
+// The PICT code is based off of the QuickDraw specs:
+// http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-461.html
+// http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-269.html
+
+PictDecoder::PictDecoder(PixelFormat pixelFormat) {
+ _jpeg = new JPEG();
+ _pixelFormat = pixelFormat;
+}
+
+PictDecoder::~PictDecoder() {
+ delete _jpeg;
+}
+
+Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *palette) {
+ assert(stream);
+
+ uint16 fileSize = stream->readUint16BE();
+
+ // If we have no file size here, we probably have a PICT from a file
+ // and not a resource. The other two bytes are the fileSize which we
+ // don't actually need (and already read if from a resource).
+ if (!fileSize)
+ stream->seek(512 + 2);
+
+ _imageRect.top = stream->readUint16BE();
+ _imageRect.left = stream->readUint16BE();
+ _imageRect.bottom = stream->readUint16BE();
+ _imageRect.right = stream->readUint16BE();
+ _imageRect.debugPrint(0, "PICT Rect:");
+
+ Graphics::Surface *image = new Graphics::Surface();
+ image->create(_imageRect.width(), _imageRect.height(), _pixelFormat.bytesPerPixel);
+ _isPaletted = false;
+
+ // NOTE: This is only a subset of the full PICT format.
+ // - Only V2 Images Supported
+ // - CompressedQuickTime (JPEG) compressed data is supported
+ // - DirectBitsRect/PackBitsRect compressed data is supported
+ for (uint32 opNum = 0; !stream->eos() && !stream->err() && stream->pos() < stream->size(); opNum++) {
+ uint16 opcode = stream->readUint16BE();
+ debug(2, "Found PICT opcode %04x", opcode);
+
+ if (opNum == 0 && opcode != 0x0011)
+ error ("Cannot find PICT version opcode");
+ else if (opNum == 1 && opcode != 0x0C00)
+ error ("Cannot find PICT header opcode");
+
+ if (opcode == 0x0000) { // Nop
+ stream->readUint16BE(); // Unknown
+ } else if (opcode == 0x0001) { // Clip
+ // Ignore
+ uint16 clipSize = stream->readUint16BE();
+ stream->seek(clipSize - 2, SEEK_CUR);
+ } else if (opcode == 0x0007) { // PnSize
+ // Ignore
+ stream->readUint16BE();
+ stream->readUint16BE();
+ } else if (opcode == 0x0011) { // VersionOp
+ uint16 version = stream->readUint16BE();
+ if (version != 0x02FF)
+ error ("Unknown PICT version");
+ } else if (opcode == 0x001E) { // DefHilite
+ // Ignore, Contains no Data
+ } else if (opcode == 0x0098) { // PackBitsRect
+ decodeDirectBitsRect(stream, image, true);
+ _isPaletted = true;
+ } else if (opcode == 0x009A) { // DirectBitsRect
+ decodeDirectBitsRect(stream, image, false);
+ } else if (opcode == 0x00A1) { // LongComment
+ stream->readUint16BE();
+ uint16 dataSize = stream->readUint16BE();
+ stream->seek(dataSize, SEEK_CUR);
+ } else if (opcode == 0x00FF) { // OpEndPic
+ stream->readUint16BE();
+ break;
+ } else if (opcode == 0x0C00) { // HeaderOp
+ /* uint16 version = */ stream->readUint16BE();
+ stream->readUint16BE(); // Reserved
+ /* uint32 hRes = */ stream->readUint32BE();
+ /* uint32 vRes = */ stream->readUint32BE();
+ Common::Rect origResRect;
+ origResRect.top = stream->readUint16BE();
+ origResRect.left = stream->readUint16BE();
+ origResRect.bottom = stream->readUint16BE();
+ origResRect.right = stream->readUint16BE();
+ stream->readUint32BE(); // Reserved
+ } else if (opcode == 0x8200) { // CompressedQuickTime
+ decodeCompressedQuickTime(stream, image);
+ break;
+ } else {
+ warning("Unknown PICT opcode %04x", opcode);
+ }
+ }
+
+ // If we got a palette throughout this nonsense, go and grab it
+ if (palette && _isPaletted)
+ memcpy(palette, _palette, 256 * 4);
+
+ return image;
+}
+
+PictDecoder::PixMap PictDecoder::readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr) {
+ PixMap pixMap;
+ pixMap.baseAddr = hasBaseAddr ? stream->readUint32BE() : 0;
+ pixMap.rowBytes = stream->readUint16BE() & 0x3fff;
+ pixMap.bounds.top = stream->readUint16BE();
+ pixMap.bounds.left = stream->readUint16BE();
+ pixMap.bounds.bottom = stream->readUint16BE();
+ pixMap.bounds.right = stream->readUint16BE();
+ pixMap.pmVersion = stream->readUint16BE();
+ pixMap.packType = stream->readUint16BE();
+ pixMap.packSize = stream->readUint32BE();
+ pixMap.hRes = stream->readUint32BE();
+ pixMap.vRes = stream->readUint32BE();
+ pixMap.pixelType = stream->readUint16BE();
+ pixMap.pixelSize = stream->readUint16BE();
+ pixMap.cmpCount = stream->readUint16BE();
+ pixMap.cmpSize = stream->readUint16BE();
+ pixMap.planeBytes = stream->readUint32BE();
+ pixMap.pmTable = stream->readUint32BE();
+ pixMap.pmReserved = stream->readUint32BE();
+ return pixMap;
+}
+
+struct DirectBitsRectData {
+ PictDecoder::PixMap pixMap;
+ Common::Rect srcRect;
+ Common::Rect dstRect;
+ uint16 mode;
+};
+
+void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surface *image, bool hasPalette) {
+ static const PixelFormat directBitsFormat16 = PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
+
+ // Clear the palette
+ memset(_palette, 0, sizeof(_palette));
+
+ DirectBitsRectData directBitsData;
+ directBitsData.pixMap = readPixMap(stream, !hasPalette);
+
+ // Read in the palette if there is one present
+ if (hasPalette) {
+ // See http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-267.html
+ stream->readUint32BE(); // seed
+ stream->readUint16BE(); // flags
+ uint16 colorCount = stream->readUint16BE() + 1;
+
+ for (uint32 i = 0; i < colorCount; i++) {
+ stream->readUint16BE();
+ _palette[i * 4] = stream->readUint16BE() >> 8;
+ _palette[i * 4 + 1] = stream->readUint16BE() >> 8;
+ _palette[i * 4 + 2] = stream->readUint16BE() >> 8;
+ }
+ }
+
+ directBitsData.srcRect.top = stream->readUint16BE();
+ directBitsData.srcRect.left = stream->readUint16BE();
+ directBitsData.srcRect.bottom = stream->readUint16BE();
+ directBitsData.srcRect.right = stream->readUint16BE();
+ directBitsData.dstRect.top = stream->readUint16BE();
+ directBitsData.dstRect.left = stream->readUint16BE();
+ directBitsData.dstRect.bottom = stream->readUint16BE();
+ directBitsData.dstRect.right = stream->readUint16BE();
+ directBitsData.mode = stream->readUint16BE();
+
+ if (directBitsData.pixMap.pixelSize != 8 && directBitsData.pixMap.pixelSize != 16 && directBitsData.pixMap.pixelSize != 32)
+ error("Unhandled DirectBitsRect bitsPerPixel %d", directBitsData.pixMap.pixelSize);
+
+ byte bytesPerPixel = (directBitsData.pixMap.pixelSize == 32) ? 3 : directBitsData.pixMap.pixelSize / 8;
+ byte *buffer = new byte[image->w * image->h * bytesPerPixel];
+
+ // Read in amount of data per row
+ for (uint16 i = 0; i < directBitsData.pixMap.bounds.height(); i++) {
+ // NOTE: Compression 0 is "default". The format in SCI games is packed when 0.
+ // In the future, we may need to have something to set the "default" packing
+ // format, but this is good for now.
+
+ if (directBitsData.pixMap.packType == 1 || directBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte (on 24-bit)
+ // TODO: Finish this. Hasn't been needed (yet).
+ error("Unpacked DirectBitsRect data (padded)");
+ } else if (directBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte (on 24-bit)
+ // TODO: Finish this. Hasn't been needed (yet).
+ error("Unpacked DirectBitsRect data (not padded)");
+ } else if (directBitsData.pixMap.packType == 0 || directBitsData.pixMap.packType > 2) { // Packed
+ uint16 byteCount = (directBitsData.pixMap.rowBytes > 250) ? stream->readUint16BE() : stream->readByte();
+ decodeDirectBitsLine(buffer + i * image->w * bytesPerPixel, directBitsData.pixMap.rowBytes, stream->readStream(byteCount), bytesPerPixel);
+ }
+ }
+
+ if (bytesPerPixel == 1) {
+ // Just copy to the image
+ memcpy(image->pixels, buffer, image->w * image->h);
+ } else if (bytesPerPixel == 2) {
+ // Convert from 16-bit to whatever surface we need
+ for (uint16 y = 0; y < image->h; y++) {
+ for (uint16 x = 0; x < image->w; x++) {
+ byte r = 0, g = 0, b = 0;
+ uint32 color = READ_BE_UINT16(buffer + (y * image->w + x) * bytesPerPixel);
+ directBitsFormat16.colorToRGB(color, r, g, b);
+ if (_pixelFormat.bytesPerPixel == 2)
+ *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ else
+ *((uint32 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+ } else {
+ // Convert from 24-bit (planar!) to whatever surface we need
+ for (uint16 y = 0; y < image->h; y++) {
+ for (uint16 x = 0; x < image->w; x++) {
+ byte r = *(buffer + y * image->w * 3 + x);
+ byte g = *(buffer + y * image->w * 3 + image->w + x);
+ byte b = *(buffer + y * image->w * 3 + image->w * 2 + x);
+ if (_pixelFormat.bytesPerPixel == 2)
+ *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ else
+ *((uint32 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+ }
+
+ delete[] buffer;
+}
+
+void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel) {
+ uint32 dataDecoded = 0;
+ byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1;
+
+ while (data->pos() < data->size() && dataDecoded < length) {
+ byte op = data->readByte();
+
+ if (op & 0x80) {
+ uint32 runSize = (op ^ 255) + 2;
+ uint16 value = (bytesPerDecode == 2) ? data->readUint16BE() : data->readByte();
+
+ for (uint32 i = 0; i < runSize; i++) {
+ if (bytesPerDecode == 2) {
+ WRITE_BE_UINT16(out, value);
+ out += 2;
+ } else
+ *out++ = value;
+ }
+ dataDecoded += runSize * bytesPerDecode;
+ } else {
+ uint32 runSize = (op + 1) * bytesPerDecode;
+ for (uint32 i = 0; i < runSize; i++)
+ *out++ = data->readByte();
+ dataDecoded += runSize;
+ }
+ }
+
+ // HACK: rowBytes is in 32-bit, but the data is 24-bit...
+ if (bytesPerPixel == 3)
+ dataDecoded += length / 4;
+
+ if (length != dataDecoded)
+ warning("Mismatched DirectBits read (%d/%d)", dataDecoded, length);
+
+ delete data;
+}
+
+// Compressed QuickTime details can be found here:
+// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/B-Chapter/2TheImageCompression.html
+// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/F-Chapter/6WorkingwiththeImage.html
+// I'm just ignoring that because Myst ME uses none of that extra stuff. The offset is always the same.
+
+void PictDecoder::decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image) {
+ uint32 dataSize = stream->readUint32BE();
+ uint32 startPos = stream->pos();
+
+ Common::SeekableReadStream *jpegStream = new Common::SeekableSubReadStream(stream, stream->pos() + 156, stream->pos() + dataSize);
+
+ if (!_jpeg->read(jpegStream))
+ error("PictDecoder::decodeCompressedQuickTime(): Could not decode JPEG data");
+
+ Surface *yComponent = _jpeg->getComponent(1);
+ Surface *uComponent = _jpeg->getComponent(2);
+ Surface *vComponent = _jpeg->getComponent(3);
+
+ Surface jpegImage;
+ jpegImage.create(yComponent->w, yComponent->h, _pixelFormat.bytesPerPixel);
+
+ for (uint16 i = 0; i < jpegImage.h; i++) {
+ for (uint16 j = 0; j < jpegImage.w; j++) {
+ byte r = 0, g = 0, b = 0;
+ YUV2RGB(*((byte *)yComponent->getBasePtr(j, i)), *((byte *)uComponent->getBasePtr(j, i)), *((byte *)vComponent->getBasePtr(j, i)), r, g, b);
+ if (_pixelFormat.bytesPerPixel == 2)
+ *((uint16 *)jpegImage.getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
+ else
+ *((uint32 *)jpegImage.getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+
+ image->copyFrom(jpegImage);
+ stream->seek(startPos + dataSize);
+ jpegImage.free();
+ delete jpegStream;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/pict.h b/graphics/pict.h
new file mode 100644
index 0000000000..14fea30125
--- /dev/null
+++ b/graphics/pict.h
@@ -0,0 +1,83 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_PICT_H
+#define GRAPHICS_PICT_H
+
+#include "common/rect.h"
+#include "common/scummsys.h"
+
+#include "graphics/pixelformat.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Graphics {
+
+class JPEG;
+class Surface;
+
+class PictDecoder {
+public:
+ PictDecoder(Graphics::PixelFormat pixelFormat);
+ ~PictDecoder();
+ Surface *decodeImage(Common::SeekableReadStream *stream, byte *palette = 0);
+
+ struct PixMap {
+ uint32 baseAddr;
+ uint16 rowBytes;
+ Common::Rect bounds;
+ uint16 pmVersion;
+ uint16 packType;
+ uint32 packSize;
+ uint32 hRes;
+ uint32 vRes;
+ uint16 pixelType;
+ uint16 pixelSize;
+ uint16 cmpCount;
+ uint16 cmpSize;
+ uint32 planeBytes;
+ uint32 pmTable;
+ uint32 pmReserved;
+ };
+
+ static PixMap readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr = true);
+
+private:
+ Common::Rect _imageRect;
+ PixelFormat _pixelFormat;
+ JPEG *_jpeg;
+ byte _palette[256 * 4];
+ bool _isPaletted;
+
+ void decodeDirectBitsRect(Common::SeekableReadStream *stream, Surface *image, bool hasPalette);
+ void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel);
+ void decodeCompressedQuickTime(Common::SeekableReadStream *stream, Surface *image);
+};
+
+} // End of namespace Graphics
+
+#endif