ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

pict.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "image/pict.h"
00024 #include "image/codecs/codec.h"
00025 
00026 #include "common/debug.h"
00027 #include "common/endian.h"
00028 #include "common/stream.h"
00029 #include "common/substream.h"
00030 #include "common/textconsole.h"
00031 #include "graphics/surface.h"
00032 
00033 namespace Image {
00034 
00035 // The PICT code is based off of the QuickDraw specs:
00036 // http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-461.html
00037 // http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-269.html
00038 
00039 PICTDecoder::PICTDecoder() {
00040     _outputSurface = 0;
00041     _paletteColorCount = 0;
00042 }
00043 
00044 PICTDecoder::~PICTDecoder() {
00045     destroy();
00046 }
00047 
00048 void PICTDecoder::destroy() {
00049     if (_outputSurface) {
00050         _outputSurface->free();
00051         delete _outputSurface;
00052         _outputSurface = 0;
00053     }
00054 
00055     _paletteColorCount = 0;
00056 }
00057 
00058 #define OPCODE(a, b, c) _opcodes.push_back(PICTOpcode(a, &PICTDecoder::b, c))
00059 
00060 void PICTDecoder::setupOpcodesCommon() {
00061     OPCODE(0x0000, o_nop, "NOP");
00062     OPCODE(0x0001, o_clip, "Clip");
00063     OPCODE(0x0003, o_txFont, "TxFont");
00064     OPCODE(0x0004, o_txFace, "TxFace");
00065     OPCODE(0x0007, o_pnSize, "PnSize");
00066     OPCODE(0x000D, o_txSize, "TxSize");
00067     OPCODE(0x0010, o_txRatio, "TxRatio");
00068     OPCODE(0x0011, o_versionOp, "VersionOp");
00069     OPCODE(0x001E, o_nop, "DefHilite");
00070     OPCODE(0x0028, o_longText, "LongText");
00071     OPCODE(0x00A1, o_longComment, "LongComment");
00072     OPCODE(0x00FF, o_opEndPic, "OpEndPic");
00073     OPCODE(0x0C00, o_headerOp, "HeaderOp");
00074 }
00075 
00076 void PICTDecoder::setupOpcodesNormal() {
00077     setupOpcodesCommon();
00078     OPCODE(0x0090, on_bitsRect, "BitsRect");
00079     OPCODE(0x0098, on_packBitsRect, "PackBitsRect");
00080     OPCODE(0x009A, on_directBitsRect, "DirectBitsRect");
00081     OPCODE(0x8200, on_compressedQuickTime, "CompressedQuickTime");
00082 }
00083 
00084 void PICTDecoder::setupOpcodesQuickTime() {
00085     setupOpcodesCommon();
00086     OPCODE(0x0098, oq_packBitsRect, "PackBitsRect");
00087     OPCODE(0x009A, oq_directBitsRect, "DirectBitsRect");
00088     OPCODE(0x8200, oq_compressedQuickTime, "CompressedQuickTime");
00089 }
00090 
00091 #undef OPCODE
00092 
00093 void PICTDecoder::o_nop(Common::SeekableReadStream &) {
00094     // Nothing to do
00095 }
00096 
00097 void PICTDecoder::o_clip(Common::SeekableReadStream &stream) {
00098     // Ignore
00099     stream.skip(stream.readUint16BE() - 2);
00100 }
00101 
00102 void PICTDecoder::o_txFont(Common::SeekableReadStream &stream) {
00103     // Ignore
00104     stream.readUint16BE();
00105 }
00106 
00107 void PICTDecoder::o_txFace(Common::SeekableReadStream &stream) {
00108     // Ignore
00109     stream.readByte();
00110 }
00111 
00112 void PICTDecoder::o_pnSize(Common::SeekableReadStream &stream) {
00113     // Ignore
00114     stream.readUint16BE();
00115     stream.readUint16BE();
00116 }
00117 
00118 void PICTDecoder::o_txSize(Common::SeekableReadStream &stream) {
00119     // Ignore
00120     stream.readUint16BE();
00121 }
00122 
00123 void PICTDecoder::o_txRatio(Common::SeekableReadStream &stream) {
00124     // Ignore
00125     stream.readUint16BE();
00126     stream.readUint16BE();
00127     stream.readUint16BE();
00128     stream.readUint16BE();
00129 }
00130 
00131 void PICTDecoder::o_versionOp(Common::SeekableReadStream &stream) {
00132     // We only support v2 extended
00133     if (stream.readUint16BE() != 0x02FF)
00134         error("Unknown PICT version");
00135 }
00136 
00137 void PICTDecoder::o_longText(Common::SeekableReadStream &stream) {
00138     // Ignore
00139     stream.readUint16BE();
00140     stream.readUint16BE();
00141     stream.skip(stream.readByte());
00142 }
00143 
00144 void PICTDecoder::o_longComment(Common::SeekableReadStream &stream) {
00145     // Ignore
00146     stream.readUint16BE();
00147     stream.skip(stream.readUint16BE());
00148 }
00149 
00150 void PICTDecoder::o_opEndPic(Common::SeekableReadStream &stream) {
00151     // We've reached the end of the picture
00152     _continueParsing = false;
00153 }
00154 
00155 void PICTDecoder::o_headerOp(Common::SeekableReadStream &stream) {
00156     // Read the basic header, but we don't really have to do anything with it
00157     /* uint16 version = */ stream.readUint16BE();
00158     stream.readUint16BE(); // Reserved
00159     /* uint32 hRes = */ stream.readUint32BE();
00160     /* uint32 vRes = */ stream.readUint32BE();
00161     Common::Rect origResRect;
00162     origResRect.top = stream.readUint16BE();
00163     origResRect.left = stream.readUint16BE();
00164     origResRect.bottom = stream.readUint16BE();
00165     origResRect.right = stream.readUint16BE();
00166     stream.readUint32BE(); // Reserved
00167 }
00168 
00169 void PICTDecoder::on_bitsRect(Common::SeekableReadStream &stream) {
00170     // Copy unpacked data with clipped rectangle (8bpp or lower)
00171     unpackBitsRect(stream, true);
00172 }
00173 
00174 void PICTDecoder::on_packBitsRect(Common::SeekableReadStream &stream) {
00175     // Unpack data (8bpp or lower)
00176     unpackBitsRect(stream, true);
00177 }
00178 
00179 void PICTDecoder::on_directBitsRect(Common::SeekableReadStream &stream) {
00180     // Unpack data (16bpp or higher)
00181     unpackBitsRect(stream, false);
00182 }
00183 
00184 void PICTDecoder::on_compressedQuickTime(Common::SeekableReadStream &stream) {
00185     // OK, here's the fun. We get to completely change how QuickDraw draws
00186     // the data in PICT files.
00187 
00188     // Swap out the opcodes to the new ones
00189     _opcodes.clear();
00190     setupOpcodesQuickTime();
00191 
00192     // We'll decode the first QuickTime data from here, but the QuickTime-specific
00193     // opcodes will take over from here on out. Normal opcodes, signing off.
00194     decodeCompressedQuickTime(stream);
00195 }
00196 
00197 void PICTDecoder::oq_packBitsRect(Common::SeekableReadStream &stream) {
00198     // Skip any data here (8bpp or lower)
00199     skipBitsRect(stream, true);
00200 }
00201 
00202 void PICTDecoder::oq_directBitsRect(Common::SeekableReadStream &stream) {
00203     // Skip any data here (16bpp or higher)
00204     skipBitsRect(stream, false);
00205 }
00206 
00207 void PICTDecoder::oq_compressedQuickTime(Common::SeekableReadStream &stream) {
00208     // Just pass the data along
00209     decodeCompressedQuickTime(stream);
00210 }
00211 
00212 bool PICTDecoder::loadStream(Common::SeekableReadStream &stream) {
00213     destroy();
00214 
00215     // Initialize opcodes to their normal state
00216     _opcodes.clear();
00217     setupOpcodesNormal();
00218 
00219     _continueParsing = true;
00220     memset(_palette, 0, sizeof(_palette));
00221 
00222     uint16 fileSize = stream.readUint16BE();
00223 
00224     // If we have no file size here, we probably have a PICT from a file
00225     // and not a resource. The other two bytes are the fileSize which we
00226     // don't actually need (and already read if from a resource).
00227     if (!fileSize)
00228         stream.seek(512 + 2);
00229 
00230     _imageRect.top = stream.readUint16BE();
00231     _imageRect.left = stream.readUint16BE();
00232     _imageRect.bottom = stream.readUint16BE();
00233     _imageRect.right = stream.readUint16BE();
00234     _imageRect.debugPrint(0, "PICT Rect:");
00235 
00236     // NOTE: This is only a subset of the full PICT format.
00237     //     - Only V2 (Extended) Images Supported
00238     //     - CompressedQuickTime compressed data is supported
00239     //     - DirectBitsRect/PackBitsRect compressed data is supported
00240     for (uint32 opNum = 0; !stream.eos() && !stream.err() && stream.pos() < stream.size() && _continueParsing; opNum++) {
00241         // PICT v2 opcodes are two bytes
00242         uint16 opcode = stream.readUint16BE();
00243 
00244         if (opNum == 0 && opcode != 0x0011) {
00245             warning("Cannot find PICT version opcode");
00246             return false;
00247         } else if (opNum == 1 && opcode != 0x0C00) {
00248             warning("Cannot find PICT header opcode");
00249             return false;
00250         }
00251 
00252         // Since opcodes are word-aligned, we need to mark our starting
00253         // position here.
00254         uint32 startPos = stream.pos();
00255 
00256         for (uint32 i = 0; i < _opcodes.size(); i++) {
00257             if (_opcodes[i].op == opcode) {
00258                 debug(4, "Running PICT opcode %04x '%s'", opcode, _opcodes[i].desc);
00259                 (this->*(_opcodes[i].proc))(stream);
00260                 break;
00261             } else if (i == _opcodes.size() - 1) {
00262                 // Unknown opcode; attempt to continue forward
00263                 warning("Unknown PICT opcode %04x", opcode);
00264             }
00265         }
00266 
00267         // Align
00268         stream.skip((stream.pos() - startPos) & 1);
00269     }
00270 
00271     return _outputSurface;
00272 }
00273 
00274 PICTDecoder::PixMap PICTDecoder::readPixMap(Common::SeekableReadStream &stream, bool hasBaseAddr) {
00275     PixMap pixMap;
00276     pixMap.baseAddr = hasBaseAddr ? stream.readUint32BE() : 0;
00277     pixMap.rowBytes = stream.readUint16BE() & 0x3fff;
00278     pixMap.bounds.top = stream.readUint16BE();
00279     pixMap.bounds.left = stream.readUint16BE();
00280     pixMap.bounds.bottom = stream.readUint16BE();
00281     pixMap.bounds.right = stream.readUint16BE();
00282     pixMap.pmVersion = stream.readUint16BE();
00283     pixMap.packType = stream.readUint16BE();
00284     pixMap.packSize = stream.readUint32BE();
00285     pixMap.hRes = stream.readUint32BE();
00286     pixMap.vRes = stream.readUint32BE();
00287     pixMap.pixelType = stream.readUint16BE();
00288     pixMap.pixelSize = stream.readUint16BE();
00289     pixMap.cmpCount = stream.readUint16BE();
00290     pixMap.cmpSize = stream.readUint16BE();
00291     pixMap.planeBytes = stream.readUint32BE();
00292     pixMap.pmTable = stream.readUint32BE();
00293     pixMap.pmReserved = stream.readUint32BE();
00294     return pixMap;
00295 }
00296 
00297 struct PackBitsRectData {
00298     PICTDecoder::PixMap pixMap;
00299     Common::Rect srcRect;
00300     Common::Rect dstRect;
00301     uint16 mode;
00302 };
00303 
00304 void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool withPalette) {
00305     PackBitsRectData packBitsData;
00306     packBitsData.pixMap = readPixMap(stream, !withPalette);
00307 
00308     // Read in the palette if there is one present
00309     if (withPalette) {
00310         // See http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-267.html
00311         stream.readUint32BE(); // seed
00312         stream.readUint16BE(); // flags
00313         _paletteColorCount = stream.readUint16BE() + 1;
00314 
00315         for (uint32 i = 0; i < _paletteColorCount; i++) {
00316             stream.readUint16BE();
00317             _palette[i * 3] = stream.readUint16BE() >> 8;
00318             _palette[i * 3 + 1] = stream.readUint16BE() >> 8;
00319             _palette[i * 3 + 2] = stream.readUint16BE() >> 8;
00320         }
00321     }
00322 
00323     packBitsData.srcRect.top = stream.readUint16BE();
00324     packBitsData.srcRect.left = stream.readUint16BE();
00325     packBitsData.srcRect.bottom = stream.readUint16BE();
00326     packBitsData.srcRect.right = stream.readUint16BE();
00327     packBitsData.dstRect.top = stream.readUint16BE();
00328     packBitsData.dstRect.left = stream.readUint16BE();
00329     packBitsData.dstRect.bottom = stream.readUint16BE();
00330     packBitsData.dstRect.right = stream.readUint16BE();
00331     packBitsData.mode = stream.readUint16BE();
00332 
00333     uint16 width = packBitsData.srcRect.width();
00334     uint16 height = packBitsData.srcRect.height();
00335 
00336     byte bytesPerPixel = 0;
00337 
00338     if (packBitsData.pixMap.pixelSize <= 8)
00339         bytesPerPixel = 1;
00340     else if (packBitsData.pixMap.pixelSize == 32)
00341         bytesPerPixel = packBitsData.pixMap.cmpCount;
00342     else
00343         bytesPerPixel = packBitsData.pixMap.pixelSize / 8;
00344 
00345     // Ensure we have enough space in the buffer to hold an entire line's worth of pixels
00346     uint32 lineSize = MAX<int>(width * bytesPerPixel + (8 * 2 / packBitsData.pixMap.pixelSize), packBitsData.pixMap.rowBytes);
00347     byte *buffer = new byte[lineSize * height];
00348 
00349     memset(buffer, 0, lineSize * height);
00350 
00351     // Read in amount of data per row
00352     for (uint16 i = 0; i < packBitsData.pixMap.bounds.height(); i++) {
00353         // NOTE: Compression 0 is "default". The format in SCI games is packed when 0
00354         // unless rowBytes is less than 8 in which case the pict can't be packed,
00355         // such as the shovel inventory icon in FPFP Mac. (bug #7059)
00356         // In the future, we may need to have something to set the "default" packing
00357         // format, but this is good for now.
00358 
00359         if (packBitsData.pixMap.packType == 1 || packBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte (on 24-bit)
00360             // only support 1 bpp for now as there is currently only one known
00361             //  SCI pict that requires any unpacked support.
00362             if (bytesPerPixel == 1 && packBitsData.pixMap.pixelSize == 8) {
00363                 stream.read(&buffer[i * width], width);
00364                 if (width < packBitsData.pixMap.rowBytes) {
00365                     // skip padding and/or clipped bytes
00366                     stream.seek(packBitsData.pixMap.rowBytes - width, SEEK_CUR);
00367                 }
00368             } else {
00369                 // TODO: Finish this. Hasn't been needed (yet).
00370                 error("Unpacked DirectBitsRect data (padded) with bytes per pixel: %d and pixel size: %d", bytesPerPixel, packBitsData.pixMap.pixelSize);
00371             }
00372         } else if (packBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte (on 24-bit)
00373             // TODO: Finish this. Hasn't been needed (yet).
00374             error("Unpacked DirectBitsRect data (not padded)");
00375         } else if (packBitsData.pixMap.packType == 0 || packBitsData.pixMap.packType > 2) { // Packed
00376             uint16 byteCount = (packBitsData.pixMap.rowBytes > 250) ? stream.readUint16BE() : stream.readByte();
00377             unpackBitsLine(buffer + i * width * bytesPerPixel, packBitsData.pixMap.rowBytes, stream.readStream(byteCount), packBitsData.pixMap.pixelSize, bytesPerPixel);
00378         }
00379     }
00380 
00381     _outputSurface = new Graphics::Surface();
00382 
00383     switch (bytesPerPixel) {
00384     case 1:
00385         // Just copy to the image
00386         _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
00387         memcpy(_outputSurface->getPixels(), buffer, _outputSurface->w * _outputSurface->h);
00388         break;
00389     case 2:
00390         // We have a 16-bit surface
00391         _outputSurface->create(width, height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
00392         for (uint16 y = 0; y < _outputSurface->h; y++)
00393             for (uint16 x = 0; x < _outputSurface->w; x++)
00394                 WRITE_UINT16(_outputSurface->getBasePtr(x, y), READ_UINT16(buffer + (y * _outputSurface->w + x) * 2));
00395         break;
00396     case 3:
00397         // We have a planar 24-bit surface
00398         _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
00399         for (uint16 y = 0; y < _outputSurface->h; y++) {
00400             for (uint16 x = 0; x < _outputSurface->w; x++) {
00401                 byte r = *(buffer + y * _outputSurface->w * 3 + x);
00402                 byte g = *(buffer + y * _outputSurface->w * 3 + _outputSurface->w + x);
00403                 byte b = *(buffer + y * _outputSurface->w * 3 + _outputSurface->w * 2 + x);
00404                 *((uint32 *)_outputSurface->getBasePtr(x, y)) = _outputSurface->format.RGBToColor(r, g, b);
00405             }
00406         }
00407         break;
00408     case 4:
00409         // We have a planar 32-bit surface
00410         // Note that we ignore the alpha channel since it seems to not be correct
00411         // Mac OS X does not ignore it, but then displays it incorrectly. Photoshop
00412         // does ignore it and displays it correctly.
00413         _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
00414         for (uint16 y = 0; y < _outputSurface->h; y++) {
00415             for (uint16 x = 0; x < _outputSurface->w; x++) {
00416                 byte a = 0xFF;
00417                 byte r = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w + x);
00418                 byte g = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 2 + x);
00419                 byte b = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 3 + x);
00420                 *((uint32 *)_outputSurface->getBasePtr(x, y)) = _outputSurface->format.ARGBToColor(a, r, g, b);
00421             }
00422         }
00423         break;
00424     }
00425 
00426     delete[] buffer;
00427 }
00428 
00429 void PICTDecoder::unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel) {
00430     uint32 dataDecoded = 0;
00431     byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1;
00432 
00433     while (data->pos() < data->size() && dataDecoded < length) {
00434         byte op = data->readByte();
00435 
00436         if (op & 0x80) {
00437             uint32 runSize = (op ^ 255) + 2;
00438             uint16 value = (bytesPerDecode == 2) ? data->readUint16BE() : data->readByte();
00439 
00440             for (uint32 i = 0; i < runSize; i++) {
00441                 if (bytesPerDecode == 2) {
00442                     WRITE_UINT16(out, value);
00443                     out += 2;
00444                 } else {
00445                     outputPixelBuffer(out, value, bitsPerPixel);
00446                 }
00447             }
00448             dataDecoded += runSize * bytesPerDecode;
00449         } else {
00450             uint32 runSize = op + 1;
00451 
00452             if (bytesPerDecode == 1) {
00453                 for (uint32 i = 0; i < runSize; i++)
00454                     outputPixelBuffer(out, data->readByte(), bitsPerPixel);
00455             } else {
00456                 for (uint32 i = 0; i < runSize; i++) {
00457                     WRITE_UINT16(out, data->readUint16BE());
00458                     out += 2;
00459                 }
00460             }
00461 
00462             dataDecoded += runSize * bytesPerDecode;
00463         }
00464     }
00465 
00466     // HACK: Even if the data is 24-bit, rowBytes is still 32-bit
00467     if (bytesPerPixel == 3)
00468         dataDecoded += length / 4;
00469 
00470     if (length != dataDecoded)
00471         warning("Mismatched PackBits read (%d/%d)", dataDecoded, length);
00472 
00473     delete data;
00474 }
00475 
00476 void PICTDecoder::outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel) {
00477     switch (bitsPerPixel) {
00478     case 1:
00479         for (int i = 7; i >= 0; i--)
00480             *out++ = (value >> i) & 1;
00481         break;
00482     case 2:
00483         for (int i = 6; i >= 0; i -= 2)
00484             *out++ = (value >> i) & 3;
00485         break;
00486     case 4:
00487         *out++ = (value >> 4) & 0xf;
00488         *out++ = value & 0xf;
00489         break;
00490     default:
00491         *out++ = value;
00492     }
00493 }
00494 
00495 void PICTDecoder::skipBitsRect(Common::SeekableReadStream &stream, bool withPalette) {
00496     // Step through a PackBitsRect/DirectBitsRect function
00497 
00498     if (!withPalette)
00499         stream.readUint32BE();
00500 
00501     uint16 rowBytes = stream.readUint16BE();
00502     uint16 height = stream.readUint16BE();
00503     stream.readUint16BE();
00504     height = stream.readUint16BE() - height;
00505     stream.readUint16BE();
00506 
00507     uint16 packType;
00508 
00509     // Top two bits signify PixMap vs BitMap
00510     if (rowBytes & 0xC000) {
00511         // PixMap
00512         stream.readUint16BE();
00513         packType = stream.readUint16BE();
00514         stream.skip(14);
00515         stream.readUint16BE(); // pixelSize
00516         stream.skip(16);
00517 
00518         if (withPalette) {
00519             stream.readUint32BE();
00520             stream.readUint16BE();
00521             stream.skip((stream.readUint16BE() + 1) * 8);
00522         }
00523 
00524         rowBytes &= 0x3FFF;
00525     } else {
00526         // BitMap
00527         packType = 0;
00528     }
00529 
00530     stream.skip(18);
00531 
00532     for (uint16 i = 0; i < height; i++) {
00533         if (packType == 1 || packType == 2 || rowBytes < 8)
00534             error("Unpacked PackBitsRect data");
00535         else if (packType == 0 || packType > 2)
00536             stream.skip((rowBytes > 250) ? stream.readUint16BE() : stream.readByte());
00537     }
00538 }
00539 
00540 // Compressed QuickTime details can be found here:
00541 // http://developer.apple.com/legacy/mac/library/#documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/B-Chapter/2TheImageCompression.html
00542 // http://developer.apple.com/legacy/mac/library/#documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/F-Chapter/6WorkingwiththeImage.html
00543 void PICTDecoder::decodeCompressedQuickTime(Common::SeekableReadStream &stream) {
00544     // First, read all the fields from the opcode
00545     uint32 dataSize = stream.readUint32BE();
00546     uint32 startPos = stream.pos();
00547 
00548     /* uint16 version = */ stream.readUint16BE();
00549 
00550     // Read in the display matrix
00551     uint32 matrix[3][3];
00552     for (uint32 i = 0; i < 3; i++)
00553         for (uint32 j = 0; j < 3; j++)
00554             matrix[i][j] = stream.readUint32BE();
00555 
00556     // We currently only support offseting images vertically from the matrix
00557     uint16 xOffset = 0;
00558     uint16 yOffset = matrix[2][1] >> 16;
00559 
00560     uint32 matteSize = stream.readUint32BE();
00561     stream.skip(8); // matte rect
00562     /* uint16 transferMode = */ stream.readUint16BE();
00563     stream.skip(8); // src rect
00564     /* uint32 accuracy = */ stream.readUint32BE();
00565     uint32 maskSize = stream.readUint32BE();
00566 
00567     // Skip the matte and mask
00568     stream.skip(matteSize + maskSize);
00569 
00570     // Now we've reached the image descriptor, so read the relevant data from that
00571     uint32 idStart = stream.pos();
00572     uint32 idSize = stream.readUint32BE();
00573     uint32 codecTag = stream.readUint32BE();
00574     stream.skip(24); // miscellaneous stuff
00575     uint16 width = stream.readUint16BE();
00576     uint16 height = stream.readUint16BE();
00577     stream.skip(8); // resolution, dpi
00578     uint32 imageSize = stream.readUint32BE();
00579     stream.skip(34);
00580     uint16 bitsPerPixel = stream.readUint16BE();
00581     stream.skip(idSize - (stream.pos() - idStart)); // more useless stuff
00582 
00583     Common::SeekableSubReadStream imageStream(&stream, stream.pos(), stream.pos() + imageSize);
00584 
00585     Codec *codec = createQuickTimeCodec(codecTag, width, height, bitsPerPixel);
00586     if (!codec)
00587         error("Unhandled CompressedQuickTime format");
00588 
00589     const Graphics::Surface *surface = codec->decodeFrame(imageStream);
00590 
00591     if (!surface)
00592         error("PICTDecoder::decodeCompressedQuickTime(): Could not decode data");
00593 
00594     if (!_outputSurface) {
00595         _outputSurface = new Graphics::Surface();
00596         _outputSurface->create(_imageRect.width(), _imageRect.height(), surface->format);
00597     }
00598     assert(_outputSurface->format == surface->format);
00599 
00600     Common::Rect outputRect(surface->w, surface->h);
00601     outputRect.translate(xOffset, yOffset);
00602     outputRect.clip(_imageRect);
00603 
00604     for (uint16 y = 0; y < outputRect.height(); y++)
00605         memcpy(_outputSurface->getBasePtr(outputRect.left, y + outputRect.top), surface->getBasePtr(0, y), outputRect.width() * surface->format.bytesPerPixel);
00606 
00607     stream.seek(startPos + dataSize);
00608     delete codec;
00609 }
00610 
00611 } // End of namespace Image


Generated on Sat Jul 20 2019 05:01:03 for ResidualVM by doxygen 1.7.1
curved edge   curved edge