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

iff.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/iff.h"
00024 
00025 #include "common/iff_container.h"
00026 #include "common/stream.h"
00027 #include "common/util.h"
00028 
00029 namespace Image {
00030 
00031 IFFDecoder::IFFDecoder() {
00032     _surface = 0;
00033     _palette = 0;
00034 
00035     // these 2 properties are not reset by destroy(), so the default is set here.
00036     _numRelevantPlanes = 8;
00037     _pixelPacking = false;
00038 
00039     destroy();
00040 }
00041 
00042 IFFDecoder::~IFFDecoder() {
00043     destroy();
00044 }
00045 
00046 void IFFDecoder::destroy() {
00047     if (_surface) {
00048         _surface->free();
00049         delete _surface;
00050         _surface = 0;
00051     }
00052 
00053     if (_palette) {
00054         delete[] _palette;
00055         _palette = 0;
00056     }
00057 
00058     memset(&_header, 0, sizeof(Header));
00059     _paletteRanges.clear();
00060     _type = TYPE_UNKNOWN;
00061     _paletteColorCount = 0;
00062 }
00063 
00064 bool IFFDecoder::loadStream(Common::SeekableReadStream &stream) {
00065     destroy();
00066 
00067     const uint32 form = stream.readUint32BE();
00068 
00069     if (form != ID_FORM) {
00070         warning("Failed reading IFF-file");
00071         return false;
00072     }
00073 
00074     stream.skip(4);
00075 
00076     const uint32 type = stream.readUint32BE();
00077 
00078     switch (type) {
00079         case ID_ILBM:
00080             _type = TYPE_ILBM;
00081             break;
00082         case ID_PBM:
00083             _type = TYPE_PBM;
00084             break;
00085     }
00086 
00087     if (type == TYPE_UNKNOWN) {
00088         warning("Failed reading IFF-file");
00089         return false;
00090     }
00091 
00092     while (1) {
00093         const uint32 chunkType = stream.readUint32BE();
00094         const uint32 chunkSize = stream.readUint32BE();
00095 
00096         if (stream.eos())
00097             break;
00098 
00099         switch (chunkType) {
00100         case ID_BMHD:
00101             loadHeader(stream);
00102             break;
00103         case ID_CMAP:
00104             loadPalette(stream, chunkSize);
00105             break;
00106         case ID_CRNG:
00107             loadPaletteRange(stream, chunkSize);
00108             break;
00109         case ID_BODY:
00110             loadBitmap(stream);
00111             break;
00112         default:
00113             stream.skip(chunkSize);
00114         }
00115     }
00116 
00117     return true;
00118 }
00119 
00120 void IFFDecoder::loadHeader(Common::SeekableReadStream &stream) {
00121     _header.width = stream.readUint16BE();
00122     _header.height = stream.readUint16BE();
00123     _header.x = stream.readUint16BE();
00124     _header.y = stream.readUint16BE();
00125     _header.numPlanes = stream.readByte();
00126     _header.masking = stream.readByte();
00127     _header.compression = stream.readByte();
00128     _header.flags = stream.readByte();
00129     _header.transparentColor = stream.readUint16BE();
00130     _header.xAspect = stream.readByte();
00131     _header.yAspect = stream.readByte();
00132     _header.pageWidth = stream.readUint16BE();
00133     _header.pageHeight = stream.readUint16BE();
00134 
00135     assert(_header.width >= 1);
00136     assert(_header.height >= 1);
00137     assert(_header.numPlanes >= 1 && _header.numPlanes <= 8 && _header.numPlanes != 7);
00138 }
00139 
00140 void IFFDecoder::loadPalette(Common::SeekableReadStream &stream, const uint32 size) {
00141     _palette = new byte[size];
00142     stream.read(_palette, size);
00143     _paletteColorCount = size / 3;
00144 }
00145 
00146 void IFFDecoder::loadPaletteRange(Common::SeekableReadStream &stream, const uint32 size) {
00147     PaletteRange range;
00148 
00149     range.timer = stream.readSint16BE();
00150     range.step = stream.readSint16BE();
00151     range.flags = stream.readSint16BE();
00152     range.first = stream.readByte();
00153     range.last = stream.readByte();
00154 
00155     _paletteRanges.push_back(range);
00156 }
00157 
00158 void IFFDecoder::loadBitmap(Common::SeekableReadStream &stream) {
00159     _numRelevantPlanes = MIN(_numRelevantPlanes, _header.numPlanes);
00160 
00161     if (_numRelevantPlanes != 1 && _numRelevantPlanes != 2 && _numRelevantPlanes != 4)
00162         _pixelPacking = false;
00163 
00164     uint16 outPitch = _header.width;
00165 
00166     if (_pixelPacking)
00167         outPitch /= (8 / _numRelevantPlanes);
00168 
00169     // FIXME: CLUT8 is not a proper format for packed bitmaps but there is no way to tell it to use 1, 2 or 4 bits per pixel
00170     _surface = new Graphics::Surface();
00171     _surface->create(outPitch, _header.height, Graphics::PixelFormat::createFormatCLUT8());
00172 
00173     if (_type == TYPE_ILBM) {
00174         uint32 scanlinePitch = ((_header.width + 15) >> 4) << 1;
00175         byte *scanlines = new byte[scanlinePitch * _header.numPlanes];
00176         byte *data = (byte *)_surface->getPixels();
00177 
00178         for (uint16 i = 0; i < _header.height; ++i) {
00179             byte *scanline = scanlines;
00180 
00181             for (uint16 j = 0; j < _header.numPlanes; ++j) {
00182                 uint16 outSize = scanlinePitch;
00183 
00184                 if (_header.compression) {
00185                     Common::PackBitsReadStream packStream(stream);
00186                     packStream.read(scanline, outSize);
00187                 } else {
00188                     stream.read(scanline, outSize);
00189                 }
00190 
00191                 scanline += outSize;
00192             }
00193 
00194             packPixels(scanlines, data, scanlinePitch, outPitch);
00195             data += outPitch;
00196         }
00197 
00198         delete[] scanlines;
00199     } else if (_type == TYPE_PBM) {
00200         byte *data = (byte *)_surface->getPixels();
00201         uint32 outSize = _header.width * _header.height;
00202 
00203         if (_header.compression) {
00204             Common::PackBitsReadStream packStream(stream);
00205             packStream.read(data, outSize);
00206         } else {
00207             stream.read(data, outSize);
00208         }
00209     }
00210 }
00211 
00212 void IFFDecoder::packPixels(byte *scanlines, byte *data, const uint16 scanlinePitch, const uint16 outPitch) {
00213     uint32 numPixels = _header.width;
00214 
00215     if (_pixelPacking)
00216         numPixels = outPitch * (8 / _numRelevantPlanes);
00217 
00218     for (uint32 x = 0; x < numPixels; ++x) {
00219         byte *scanline = scanlines;
00220         byte pixel = 0;
00221         byte offset = x >> 3;
00222         byte bit = 0x80 >> (x & 7);
00223 
00224         // first build a pixel by scanning all the usable planes in the input
00225         for (uint32 plane = 0; plane < _numRelevantPlanes; ++plane) {
00226             if (scanline[offset] & bit)
00227                 pixel |= (1 << plane);
00228 
00229             scanline += scanlinePitch;
00230         }
00231 
00232         // then output the pixel according to the requested packing
00233         if (!_pixelPacking)
00234             data[x] = pixel;
00235         else if (_numRelevantPlanes == 1)
00236             data[x / 8] |= (pixel << (x & 7));
00237         else if (_numRelevantPlanes == 2)
00238             data[x / 4] |= (pixel << ((x & 3) << 1));
00239         else if (_numRelevantPlanes == 4)
00240             data[x / 2] |= (pixel << ((x & 1) << 2));
00241     }
00242 }
00243 
00244 } // End of namespace Image


Generated on Sat Feb 16 2019 05:00:54 for ResidualVM by doxygen 1.7.1
curved edge   curved edge