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         case TYPE_UNKNOWN:
00086         default:
00087             _type = TYPE_UNKNOWN;
00088             break;
00089     }
00090 
00091     if (type == TYPE_UNKNOWN) {
00092         warning("Failed reading IFF-file");
00093         return false;
00094     }
00095 
00096     while (1) {
00097         const uint32 chunkType = stream.readUint32BE();
00098         const uint32 chunkSize = stream.readUint32BE();
00099 
00100         if (stream.eos())
00101             break;
00102 
00103         switch (chunkType) {
00104         case ID_BMHD:
00105             loadHeader(stream);
00106             break;
00107         case ID_CMAP:
00108             loadPalette(stream, chunkSize);
00109             break;
00110         case ID_CRNG:
00111             loadPaletteRange(stream, chunkSize);
00112             break;
00113         case ID_BODY:
00114             loadBitmap(stream);
00115             break;
00116         default:
00117             stream.skip(chunkSize);
00118         }
00119     }
00120 
00121     return true;
00122 }
00123 
00124 void IFFDecoder::loadHeader(Common::SeekableReadStream &stream) {
00125     _header.width = stream.readUint16BE();
00126     _header.height = stream.readUint16BE();
00127     _header.x = stream.readUint16BE();
00128     _header.y = stream.readUint16BE();
00129     _header.numPlanes = stream.readByte();
00130     _header.masking = stream.readByte();
00131     _header.compression = stream.readByte();
00132     _header.flags = stream.readByte();
00133     _header.transparentColor = stream.readUint16BE();
00134     _header.xAspect = stream.readByte();
00135     _header.yAspect = stream.readByte();
00136     _header.pageWidth = stream.readUint16BE();
00137     _header.pageHeight = stream.readUint16BE();
00138 
00139     assert(_header.width >= 1);
00140     assert(_header.height >= 1);
00141     assert(_header.numPlanes >= 1 && _header.numPlanes <= 8 && _header.numPlanes != 7);
00142 }
00143 
00144 void IFFDecoder::loadPalette(Common::SeekableReadStream &stream, const uint32 size) {
00145     _palette = new byte[size];
00146     stream.read(_palette, size);
00147     _paletteColorCount = size / 3;
00148 }
00149 
00150 void IFFDecoder::loadPaletteRange(Common::SeekableReadStream &stream, const uint32 size) {
00151     PaletteRange range;
00152 
00153     range.timer = stream.readSint16BE();
00154     range.step = stream.readSint16BE();
00155     range.flags = stream.readSint16BE();
00156     range.first = stream.readByte();
00157     range.last = stream.readByte();
00158 
00159     _paletteRanges.push_back(range);
00160 }
00161 
00162 void IFFDecoder::loadBitmap(Common::SeekableReadStream &stream) {
00163     _numRelevantPlanes = MIN(_numRelevantPlanes, _header.numPlanes);
00164 
00165     if (_numRelevantPlanes != 1 && _numRelevantPlanes != 2 && _numRelevantPlanes != 4)
00166         _pixelPacking = false;
00167 
00168     uint16 outPitch = _header.width;
00169 
00170     if (_pixelPacking)
00171         outPitch /= (8 / _numRelevantPlanes);
00172 
00173     // 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
00174     _surface = new Graphics::Surface();
00175     _surface->create(outPitch, _header.height, Graphics::PixelFormat::createFormatCLUT8());
00176 
00177     if (_type == TYPE_ILBM) {
00178         uint32 scanlinePitch = ((_header.width + 15) >> 4) << 1;
00179         byte *scanlines = new byte[scanlinePitch * _header.numPlanes];
00180         byte *data = (byte *)_surface->getPixels();
00181 
00182         for (uint16 i = 0; i < _header.height; ++i) {
00183             byte *scanline = scanlines;
00184 
00185             for (uint16 j = 0; j < _header.numPlanes; ++j) {
00186                 uint16 outSize = scanlinePitch;
00187 
00188                 if (_header.compression) {
00189                     Common::PackBitsReadStream packStream(stream);
00190                     packStream.read(scanline, outSize);
00191                 } else {
00192                     stream.read(scanline, outSize);
00193                 }
00194 
00195                 scanline += outSize;
00196             }
00197 
00198             packPixels(scanlines, data, scanlinePitch, outPitch);
00199             data += outPitch;
00200         }
00201 
00202         delete[] scanlines;
00203     } else if (_type == TYPE_PBM) {
00204         byte *data = (byte *)_surface->getPixels();
00205         uint32 outSize = _header.width * _header.height;
00206 
00207         if (_header.compression) {
00208             Common::PackBitsReadStream packStream(stream);
00209             packStream.read(data, outSize);
00210         } else {
00211             stream.read(data, outSize);
00212         }
00213     }
00214 }
00215 
00216 void IFFDecoder::packPixels(byte *scanlines, byte *data, const uint16 scanlinePitch, const uint16 outPitch) {
00217     uint32 numPixels = _header.width;
00218 
00219     if (_pixelPacking)
00220         numPixels = outPitch * (8 / _numRelevantPlanes);
00221 
00222     for (uint32 x = 0; x < numPixels; ++x) {
00223         byte *scanline = scanlines;
00224         byte pixel = 0;
00225         byte offset = x >> 3;
00226         byte bit = 0x80 >> (x & 7);
00227 
00228         // first build a pixel by scanning all the usable planes in the input
00229         for (uint32 plane = 0; plane < _numRelevantPlanes; ++plane) {
00230             if (scanline[offset] & bit)
00231                 pixel |= (1 << plane);
00232 
00233             scanline += scanlinePitch;
00234         }
00235 
00236         // then output the pixel according to the requested packing
00237         if (!_pixelPacking)
00238             data[x] = pixel;
00239         else if (_numRelevantPlanes == 1)
00240             data[x / 8] |= (pixel << (x & 7));
00241         else if (_numRelevantPlanes == 2)
00242             data[x / 4] |= (pixel << ((x & 3) << 1));
00243         else if (_numRelevantPlanes == 4)
00244             data[x / 2] |= (pixel << ((x & 1) << 2));
00245     }
00246 }
00247 
00248 } // End of namespace Image


Generated on Sat May 23 2020 05:00:45 for ResidualVM by doxygen 1.7.1
curved edge   curved edge