2012-01-06 23:29:45 +01:00
|
|
|
/* ResidualVM - A 3D game interpreter
|
2008-06-13 14:57:47 +00:00
|
|
|
*
|
2012-01-06 23:29:45 +01:00
|
|
|
* ResidualVM is the legal property of its developers, whose names
|
2011-04-16 14:12:44 +02:00
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
2008-06-13 14:57:47 +00:00
|
|
|
* file distributed with this source distribution.
|
2006-04-02 14:20:45 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2011-05-09 19:20:47 +02:00
|
|
|
*
|
2006-04-02 14:20:45 +00:00
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
2011-05-09 19:20:47 +02:00
|
|
|
*
|
2006-04-02 14:20:45 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*
|
|
|
|
*/
|
2003-08-15 18:00:22 +00:00
|
|
|
|
2011-05-08 15:38:26 +02:00
|
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
|
|
|
|
|
2008-06-12 12:08:15 +00:00
|
|
|
#include "common/endian.h"
|
2008-01-26 11:47:23 +00:00
|
|
|
|
2012-01-16 17:12:14 +01:00
|
|
|
#include "graphics/colormasks.h"
|
|
|
|
#include "graphics/pixelbuffer.h"
|
|
|
|
|
2011-07-23 15:37:14 +02:00
|
|
|
#include "engines/grim/debug.h"
|
2009-06-18 11:52:26 +00:00
|
|
|
#include "engines/grim/grim.h"
|
2009-05-24 19:13:58 +00:00
|
|
|
#include "engines/grim/bitmap.h"
|
2011-09-07 23:08:59 +02:00
|
|
|
#include "engines/grim/resource.h"
|
2009-05-24 19:13:58 +00:00
|
|
|
#include "engines/grim/gfx_base.h"
|
2004-01-23 11:10:59 +00:00
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
namespace Grim {
|
|
|
|
|
2011-10-29 03:31:05 +08:00
|
|
|
static bool decompress_codec3(const char *compressed, char *result, int maxBytes);
|
2003-08-15 18:00:22 +00:00
|
|
|
|
2011-05-09 19:20:47 +02:00
|
|
|
Common::HashMap<Common::String, BitmapData *> *BitmapData::_bitmaps = NULL;
|
2011-03-21 17:18:04 +01:00
|
|
|
|
2011-05-09 04:37:51 +08:00
|
|
|
// Helper function for makeBitmapFromTile
|
2011-05-09 19:20:47 +02:00
|
|
|
char *getLine(int lineNum, char *data, unsigned int width, int bpp) {
|
2011-05-09 01:16:14 +02:00
|
|
|
return data + (lineNum *(width * bpp));
|
2011-05-09 04:37:51 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 08:06:16 +02:00
|
|
|
#ifdef ENABLE_MONKEY4
|
|
|
|
|
2011-05-09 01:16:14 +02:00
|
|
|
char *makeBitmapFromTile(char **bits, int width, int height, int bpp) {
|
|
|
|
bpp = bpp / 8;
|
|
|
|
char *fullImage = new char[width * height * bpp];
|
2011-05-09 04:37:51 +08:00
|
|
|
|
2011-05-09 01:16:14 +02:00
|
|
|
const int tWidth = 256 * bpp; // All tiles so far are 256 wide
|
2011-05-09 04:37:51 +08:00
|
|
|
const int tWidth2 = 256;
|
|
|
|
|
2011-05-09 01:16:14 +02:00
|
|
|
char *target = fullImage;
|
2011-05-14 17:42:37 -07:00
|
|
|
int line;
|
2011-05-09 01:16:14 +02:00
|
|
|
for (int i = 0; i < 256; i++) {
|
2011-05-09 04:37:51 +08:00
|
|
|
/* This can be modified to actually use the last 32 lines.
|
|
|
|
* We simply put the lower half on line 223 and down to line 32,
|
|
|
|
* then skip the last 32.
|
|
|
|
* While the upper half is put on line 479 and down to line 224.
|
|
|
|
*/
|
2011-05-14 17:42:37 -07:00
|
|
|
|
2011-05-09 01:16:14 +02:00
|
|
|
if (i < 224) { // Skip blank space
|
2011-05-14 17:42:37 -07:00
|
|
|
line = 224 - i;
|
|
|
|
target = getLine(479 - i, fullImage, width, bpp);
|
2011-05-09 04:37:51 +08:00
|
|
|
|
2011-05-14 17:42:37 -07:00
|
|
|
memcpy(target, getLine(line, bits[3], tWidth2, bpp), tWidth);
|
2011-05-09 04:37:51 +08:00
|
|
|
target += tWidth;
|
|
|
|
|
2011-05-14 17:42:37 -07:00
|
|
|
memcpy(target, getLine(line, bits[4], tWidth2, bpp), tWidth);
|
2011-05-09 04:37:51 +08:00
|
|
|
target += tWidth;
|
|
|
|
|
2011-05-14 17:42:37 -07:00
|
|
|
memcpy(target, getLine(line, bits[2], tWidth2, bpp) + 128 * bpp, 128 * bpp);
|
2011-05-09 04:37:51 +08:00
|
|
|
}
|
2011-05-14 17:42:37 -07:00
|
|
|
line = 255 - i;
|
2011-05-09 04:37:51 +08:00
|
|
|
// Top half of course
|
|
|
|
|
2011-05-14 17:42:37 -07:00
|
|
|
target = getLine(line, fullImage, width, bpp);
|
2011-05-09 04:37:51 +08:00
|
|
|
|
2011-05-14 17:42:37 -07:00
|
|
|
memcpy(target, getLine(line, bits[0], tWidth2, bpp), tWidth);
|
2011-05-09 04:37:51 +08:00
|
|
|
target += tWidth;
|
|
|
|
|
2011-05-14 17:42:37 -07:00
|
|
|
memcpy(target, getLine(line, bits[1], tWidth2, bpp), tWidth);
|
2011-05-09 04:37:51 +08:00
|
|
|
target += tWidth;
|
|
|
|
|
2011-05-14 17:42:37 -07:00
|
|
|
memcpy(target, getLine(line, bits[2], tWidth2, bpp), 128 * bpp);
|
2011-05-09 04:37:51 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return fullImage;
|
|
|
|
}
|
|
|
|
|
2011-08-13 08:06:16 +02:00
|
|
|
#endif
|
|
|
|
|
2011-12-17 18:32:31 +01:00
|
|
|
BitmapData *BitmapData::getBitmapData(const Common::String &fname, Common::SeekableReadStream *data) {
|
2011-05-09 19:20:47 +02:00
|
|
|
Common::String str(fname);
|
|
|
|
if (_bitmaps && _bitmaps->contains(str)) {
|
|
|
|
BitmapData *b = (*_bitmaps)[str];
|
|
|
|
++b->_refCount;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2011-12-17 18:32:31 +01:00
|
|
|
BitmapData *b = new BitmapData(fname, data);
|
2011-05-09 19:20:47 +02:00
|
|
|
if (!_bitmaps) {
|
|
|
|
_bitmaps = new Common::HashMap<Common::String, BitmapData *>();
|
|
|
|
}
|
|
|
|
(*_bitmaps)[str] = b;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2011-12-17 18:32:31 +01:00
|
|
|
BitmapData::BitmapData(const Common::String &fname, Common::SeekableReadStream *data) {
|
2011-05-09 19:20:47 +02:00
|
|
|
_fname = fname;
|
|
|
|
_refCount = 1;
|
2012-01-24 20:46:56 +01:00
|
|
|
_data = 0;
|
2011-12-17 18:32:31 +01:00
|
|
|
|
|
|
|
uint32 tag = data->readUint32BE();
|
|
|
|
switch(tag) {
|
|
|
|
case(MKTAG('B','M',' ',' ')): //Grim bitmap
|
|
|
|
loadGrimBm(fname, data);
|
|
|
|
break;
|
2012-01-09 19:24:00 -08:00
|
|
|
case(MKTAG('T','I','L','0')): // MI4 bitmap
|
2011-12-17 18:32:31 +01:00
|
|
|
loadTile(fname, data);
|
|
|
|
break;
|
|
|
|
default:
|
2012-01-14 22:45:00 +01:00
|
|
|
if (!loadTGA(fname, data)) // Try to load as TGA.
|
|
|
|
Debug::error(Debug::Bitmaps, "Invalid magic loading bitmap");
|
2011-12-17 18:32:31 +01:00
|
|
|
break;
|
2011-05-09 19:20:47 +02:00
|
|
|
}
|
2011-12-17 18:32:31 +01:00
|
|
|
}
|
2011-05-09 19:20:47 +02:00
|
|
|
|
2011-12-17 18:32:31 +01:00
|
|
|
|
|
|
|
bool BitmapData::loadGrimBm(const Common::String &fname, Common::SeekableReadStream *data) {
|
|
|
|
uint32 tag2 = data->readUint32BE();
|
|
|
|
if(tag2 != (MKTAG('F','\0','\0','\0')))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int codec = data->readUint32LE();
|
|
|
|
data->readUint32LE(); //_paletteIncluded
|
|
|
|
_numImages = data->readUint32LE();
|
|
|
|
_x = data->readUint32LE();
|
|
|
|
_y = data->readUint32LE();
|
|
|
|
data->readUint32LE(); //_transparentColor
|
|
|
|
_format = data->readUint32LE();
|
|
|
|
_bpp = data->readUint32LE();
|
2012-01-24 21:34:50 +01:00
|
|
|
// uint32 redBits = data->readUint32LE();
|
|
|
|
// uint32 greenBits = data->readUint32LE();
|
|
|
|
// uint32 blueBits = data->readUint32LE();
|
|
|
|
// uint32 redShift = data->readUint32LE();
|
|
|
|
// uint32 greenShift = data->readUint32LE();
|
|
|
|
// uint32 blueShift = data->readUint32LE();
|
|
|
|
|
|
|
|
// Hardcode the format, since the values saved in the files are garbage for some, like "ha_0_elvos.zbm".
|
|
|
|
Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
|
2011-12-17 18:32:31 +01:00
|
|
|
|
|
|
|
data->seek(128, SEEK_SET);
|
|
|
|
_width = data->readUint32LE();
|
|
|
|
_height = data->readUint32LE();
|
2011-05-16 06:14:46 +08:00
|
|
|
_colorFormat = BM_RGB565;
|
2011-11-01 04:21:19 +08:00
|
|
|
_hasTransparency = false;
|
2011-05-09 19:20:47 +02:00
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
_data = new Graphics::PixelBuffer[_numImages];
|
2011-12-17 18:32:31 +01:00
|
|
|
data->seek(0x80, SEEK_SET);
|
2011-05-09 19:20:47 +02:00
|
|
|
for (int i = 0; i < _numImages; i++) {
|
2011-12-17 18:32:31 +01:00
|
|
|
data->seek(8, SEEK_CUR);
|
2012-01-24 19:02:50 +01:00
|
|
|
_data[i].create(pixelFormat, _width * _height, DisposeAfterUse::YES);
|
2011-05-09 19:20:47 +02:00
|
|
|
if (codec == 0) {
|
2011-12-17 18:32:31 +01:00
|
|
|
uint32 dsize = _bpp / 8 * _width * _height;
|
2012-01-24 19:02:50 +01:00
|
|
|
data->read(_data[i].getRawBuffer(), dsize);
|
2011-05-09 19:20:47 +02:00
|
|
|
} else if (codec == 3) {
|
2011-12-17 18:32:31 +01:00
|
|
|
int compressed_len = data->readUint32LE();
|
|
|
|
char *compressed = new char[compressed_len];
|
|
|
|
data->read(compressed, compressed_len);
|
2012-01-24 19:02:50 +01:00
|
|
|
bool success = decompress_codec3(compressed, (char *)_data[i].getRawBuffer(), _bpp / 8 * _width * _height);
|
2011-12-17 18:32:31 +01:00
|
|
|
delete[] compressed;
|
2011-10-29 03:31:05 +08:00
|
|
|
if (!success)
|
|
|
|
warning(".. when loading image %s.\n", fname.c_str());
|
2012-01-24 19:02:50 +01:00
|
|
|
} else
|
2011-10-29 03:31:05 +08:00
|
|
|
Debug::error(Debug::Bitmaps, "Unknown image codec in BitmapData ctor!");
|
2011-05-09 19:20:47 +02:00
|
|
|
|
|
|
|
#ifdef SCUMM_BIG_ENDIAN
|
2012-01-27 18:57:06 +01:00
|
|
|
if (_format == 1) {
|
|
|
|
uint16 *d = _data[i].getRawBuffer();
|
2011-05-09 19:20:47 +02:00
|
|
|
for (int j = 0; j < _width * _height; ++j) {
|
2012-01-27 18:57:06 +01:00
|
|
|
d[j] = SWAP_BYTES_16(d[j]);
|
2011-05-09 19:20:47 +02:00
|
|
|
}
|
2012-01-27 18:57:06 +01:00
|
|
|
}
|
2011-05-09 19:20:47 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-11-01 04:21:19 +08:00
|
|
|
// Initially, no GPU-side textures created. the createBitmap
|
|
|
|
// function will allocate some if necessary (and successful)
|
|
|
|
_numTex = 0;
|
|
|
|
_texIds = NULL;
|
|
|
|
|
2011-05-09 19:20:47 +02:00
|
|
|
g_driver->createBitmap(this);
|
2011-12-17 18:32:31 +01:00
|
|
|
return true;
|
2011-05-09 19:20:47 +02:00
|
|
|
}
|
|
|
|
|
2012-01-24 18:20:33 +01:00
|
|
|
BitmapData::BitmapData(const Graphics::PixelBuffer &buf, int w, int h, const char *fname) {
|
2011-05-09 19:20:47 +02:00
|
|
|
_fname = fname;
|
|
|
|
_refCount = 1;
|
2011-10-07 23:05:20 +02:00
|
|
|
Debug::debug(Debug::Bitmaps, "New bitmap loaded: %s\n", fname);
|
2011-05-09 19:20:47 +02:00
|
|
|
_numImages = 1;
|
|
|
|
_x = 0;
|
|
|
|
_y = 0;
|
|
|
|
_width = w;
|
|
|
|
_height = h;
|
|
|
|
_format = 1;
|
|
|
|
_numTex = 0;
|
|
|
|
_texIds = NULL;
|
2012-01-24 18:20:33 +01:00
|
|
|
_bpp = buf.getFormat().bytesPerPixel * 8;
|
2011-05-09 19:20:47 +02:00
|
|
|
_hasTransparency = false;
|
2011-05-17 17:38:52 +02:00
|
|
|
_colorFormat = BM_RGB565;
|
2012-01-24 19:02:50 +01:00
|
|
|
_data = new Graphics::PixelBuffer[_numImages];
|
|
|
|
_data[0].create(buf.getFormat(), w * h, DisposeAfterUse::YES);
|
|
|
|
_data[0].copyBuffer(0, w * h, buf);
|
2011-05-17 17:38:52 +02:00
|
|
|
|
2011-05-09 19:20:47 +02:00
|
|
|
g_driver->createBitmap(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
BitmapData::BitmapData() :
|
2012-01-09 19:24:00 -08:00
|
|
|
_numImages(0), _width(0), _height(0), _x(0), _y(0), _format(0), _numTex(0),
|
2011-11-01 04:21:19 +08:00
|
|
|
_bpp(0), _colorFormat(0), _texIds(0), _hasTransparency(false), _data(NULL), _refCount(1) {
|
2011-05-09 19:20:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BitmapData::~BitmapData() {
|
|
|
|
if (_data) {
|
2011-05-09 21:53:41 +02:00
|
|
|
delete[] _data;
|
2011-05-09 19:20:47 +02:00
|
|
|
_data = NULL;
|
|
|
|
|
|
|
|
g_driver->destroyBitmap(this);
|
|
|
|
}
|
|
|
|
if (_bitmaps) {
|
|
|
|
if (_bitmaps->contains(_fname)) {
|
|
|
|
_bitmaps->erase(_fname);
|
|
|
|
}
|
|
|
|
if (_bitmaps->empty()) {
|
|
|
|
delete _bitmaps;
|
|
|
|
_bitmaps = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-24 18:20:33 +01:00
|
|
|
|
2012-01-14 13:21:43 +01:00
|
|
|
bool BitmapData::loadTGA(const Common::String &fname, Common::SeekableReadStream *data) {
|
|
|
|
data->seek(0, SEEK_SET);
|
|
|
|
if (data->readByte() != 0) // Verify that description-field is empty
|
|
|
|
return false;
|
|
|
|
data->seek(1, SEEK_CUR);
|
2012-01-24 18:20:33 +01:00
|
|
|
|
2012-01-14 13:21:43 +01:00
|
|
|
int format = data->readByte();
|
|
|
|
if (format != 2)
|
|
|
|
return false;
|
2012-01-24 18:20:33 +01:00
|
|
|
|
2012-01-14 13:21:43 +01:00
|
|
|
data->seek(9, SEEK_CUR);
|
|
|
|
_width = data->readUint16LE();
|
|
|
|
_height = data->readUint16LE();;
|
|
|
|
_format = 1;
|
|
|
|
_x = 0;
|
|
|
|
_y = 0;
|
2012-01-24 18:20:33 +01:00
|
|
|
|
2012-01-14 13:21:43 +01:00
|
|
|
int bpp = data->readByte();
|
2012-01-24 19:02:50 +01:00
|
|
|
Graphics::PixelFormat pixelFormat;
|
2012-01-14 13:21:43 +01:00
|
|
|
if (bpp == 32) {
|
|
|
|
_colorFormat = BM_RGBA;
|
2012-01-24 19:02:50 +01:00
|
|
|
pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
|
2012-01-14 13:21:43 +01:00
|
|
|
_bpp = 4;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2012-01-24 18:20:33 +01:00
|
|
|
|
2012-01-14 22:45:00 +01:00
|
|
|
uint8 desc = data->readByte();
|
|
|
|
uint8 flipped = !(desc & 32);
|
2012-01-14 13:21:43 +01:00
|
|
|
|
|
|
|
if (!(bpp == 24 || bpp == 32)) // Assure we have 24/32 bpp
|
|
|
|
return false;
|
2012-01-24 19:02:50 +01:00
|
|
|
_data = new Graphics::PixelBuffer[1];
|
|
|
|
_data[0].create(pixelFormat, _width * _height, DisposeAfterUse::YES);
|
|
|
|
char *writePtr = (char *)_data[0].getRawBuffer(_width * (_height - 1));
|
2012-01-14 13:21:43 +01:00
|
|
|
|
|
|
|
if (flipped) {
|
|
|
|
for (int i = 0; i < _height; i++) {
|
|
|
|
data->read(writePtr, _width * (bpp / 8));
|
|
|
|
writePtr -= (_width * bpp / 8);
|
|
|
|
}
|
|
|
|
} else {
|
2012-01-24 19:02:50 +01:00
|
|
|
data->read(_data[0].getRawBuffer(), _width * _height * (bpp / 8));
|
2012-01-14 13:21:43 +01:00
|
|
|
}
|
2012-01-24 18:20:33 +01:00
|
|
|
|
2012-01-14 22:45:00 +01:00
|
|
|
uint8 x;
|
2012-01-14 13:21:43 +01:00
|
|
|
for (int i = 0; i < _width * _height * (bpp / 8); i+=4) {
|
2012-01-24 19:02:50 +01:00
|
|
|
byte *b = _data[0].getRawBuffer();
|
|
|
|
x = b[i];
|
|
|
|
b[i] = b[i + 2];
|
|
|
|
b[i + 2] = x;
|
2012-01-14 13:21:43 +01:00
|
|
|
}
|
2012-01-24 18:20:33 +01:00
|
|
|
|
2012-01-14 13:21:43 +01:00
|
|
|
_numImages = 1;
|
|
|
|
g_driver->createBitmap(this);
|
|
|
|
return true;
|
|
|
|
}
|
2011-05-09 19:20:47 +02:00
|
|
|
|
2012-01-09 19:24:00 -08:00
|
|
|
bool BitmapData::loadTile(const Common::String &fname, Common::SeekableReadStream *o) {
|
2011-08-13 08:06:16 +02:00
|
|
|
#ifdef ENABLE_MONKEY4
|
2011-05-09 04:37:51 +08:00
|
|
|
_x = 0;
|
|
|
|
_y = 0;
|
2011-05-14 17:42:37 -07:00
|
|
|
_format = 1;
|
2012-01-09 19:24:00 -08:00
|
|
|
o->seek(0, SEEK_SET);
|
2011-12-30 19:12:50 +01:00
|
|
|
//warning("Loading TILE: %s",fname.c_str());
|
2011-05-09 04:37:51 +08:00
|
|
|
|
|
|
|
uint32 id, bmoffset;
|
|
|
|
id = o->readUint32LE();
|
|
|
|
// Should check that we actually HAVE a TIL
|
|
|
|
bmoffset = o->readUint32LE();
|
|
|
|
o->seek(bmoffset + 16);
|
2011-05-09 01:21:48 +02:00
|
|
|
int numSubImages = o->readUint32LE();
|
|
|
|
if (numSubImages < 5)
|
|
|
|
error("Can not handle a tile with less than 5 sub images");
|
2011-05-09 04:37:51 +08:00
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
char **data = new char *[numSubImages];
|
2011-05-09 04:37:51 +08:00
|
|
|
|
|
|
|
o->seek(16, SEEK_CUR);
|
|
|
|
_bpp = o->readUint32LE();
|
|
|
|
|
|
|
|
o->seek(bmoffset + 128);
|
|
|
|
|
|
|
|
_width = o->readUint32LE();
|
|
|
|
_height = o->readUint32LE();
|
|
|
|
o->seek(-8, SEEK_CUR);
|
|
|
|
|
|
|
|
int size = _bpp / 8 * _width * _height;
|
2011-05-09 01:21:48 +02:00
|
|
|
for (int i = 0; i < numSubImages; ++i) {
|
2012-01-24 19:02:50 +01:00
|
|
|
data[i] = new char[size];
|
2011-05-09 04:37:51 +08:00
|
|
|
o->seek(8, SEEK_CUR);
|
2012-01-24 19:02:50 +01:00
|
|
|
o->read(data[i], size);
|
2011-05-09 04:37:51 +08:00
|
|
|
}
|
2011-05-16 13:16:45 +08:00
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
char *bMap = makeBitmapFromTile(data, 640, 480, _bpp);
|
2011-05-09 01:21:48 +02:00
|
|
|
for (int i = 0; i < numSubImages; ++i) {
|
2012-01-24 19:02:50 +01:00
|
|
|
delete[] data[i];
|
2011-05-09 04:37:51 +08:00
|
|
|
}
|
2012-01-26 07:33:12 +01:00
|
|
|
delete[] data;
|
2012-01-24 19:02:50 +01:00
|
|
|
Graphics::PixelFormat pixelFormat;
|
2011-05-09 01:16:14 +02:00
|
|
|
if (_bpp == 16) {
|
2011-05-16 06:14:46 +08:00
|
|
|
_colorFormat = BM_RGB1555;
|
2012-01-24 19:02:50 +01:00
|
|
|
pixelFormat = Graphics::createPixelFormat<1555>();
|
2011-05-16 07:01:44 +08:00
|
|
|
//convertToColorFormat(0, BM_RGBA);
|
2011-05-16 09:51:06 +02:00
|
|
|
} else {
|
2012-01-24 20:46:56 +01:00
|
|
|
pixelFormat = Graphics::PixelFormat(4, 8,8,8,8, 0, 8, 16, 24);
|
2011-05-16 06:14:46 +08:00
|
|
|
_colorFormat = BM_RGBA;
|
2011-05-09 04:37:51 +08:00
|
|
|
}
|
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
_width = 640;
|
|
|
|
_height = 480;
|
|
|
|
_numImages = 1;
|
2012-01-24 20:46:56 +01:00
|
|
|
_data = new Graphics::PixelBuffer[_numImages];
|
|
|
|
_data[0].create(pixelFormat, _width * _height, DisposeAfterUse::YES);
|
|
|
|
_data[0].set(pixelFormat, (byte *)bMap);
|
2012-01-24 19:02:50 +01:00
|
|
|
|
2011-05-09 04:37:51 +08:00
|
|
|
g_driver->createBitmap(this);
|
2011-08-13 08:06:16 +02:00
|
|
|
#endif // ENABLE_MONKEY4
|
2011-10-29 03:31:05 +08:00
|
|
|
return true;
|
2011-05-09 04:37:51 +08:00
|
|
|
}
|
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
const Graphics::PixelBuffer &BitmapData::getImageData(int num) const {
|
2011-10-29 03:31:05 +08:00
|
|
|
assert(num >= 0);
|
|
|
|
assert(num < _numImages);
|
2011-05-12 11:08:45 +02:00
|
|
|
return _data[num];
|
|
|
|
}
|
|
|
|
|
2011-05-09 19:20:47 +02:00
|
|
|
// Bitmap
|
|
|
|
|
2011-12-17 18:32:31 +01:00
|
|
|
Bitmap::Bitmap(const Common::String &fname, Common::SeekableReadStream *data) :
|
2011-09-12 10:11:02 +08:00
|
|
|
PoolObject<Bitmap, MKTAG('V', 'B', 'U', 'F')>() {
|
2011-12-17 18:32:31 +01:00
|
|
|
_data = BitmapData::getBitmapData(fname, data);
|
2011-05-09 19:20:47 +02:00
|
|
|
_x = _data->_x;
|
|
|
|
_y = _data->_y;
|
|
|
|
_currImage = 1;
|
|
|
|
}
|
|
|
|
|
2012-01-24 18:20:33 +01:00
|
|
|
Bitmap::Bitmap(const Graphics::PixelBuffer &buf, int w, int h, const char *fname) :
|
2011-09-12 10:11:02 +08:00
|
|
|
PoolObject<Bitmap, MKTAG('V', 'B', 'U', 'F')>() {
|
2012-01-24 18:20:33 +01:00
|
|
|
_data = new BitmapData(buf, w, h, fname);
|
2011-05-09 19:20:47 +02:00
|
|
|
_x = _data->_x;
|
|
|
|
_y = _data->_y;
|
|
|
|
_currImage = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bitmap::Bitmap() :
|
2011-09-12 10:11:02 +08:00
|
|
|
PoolObject<Bitmap, MKTAG('V', 'B', 'U', 'F')>() {
|
2011-05-09 19:20:47 +02:00
|
|
|
_data = new BitmapData();
|
|
|
|
}
|
|
|
|
|
2011-09-07 23:08:59 +02:00
|
|
|
void Bitmap::saveState(SaveGame *state) const {
|
|
|
|
state->writeString(getFilename());
|
|
|
|
|
2011-09-18 18:46:20 +02:00
|
|
|
state->writeLESint32(getActiveImage());
|
2011-09-07 23:08:59 +02:00
|
|
|
state->writeLESint32(getX());
|
|
|
|
state->writeLESint32(getY());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bitmap::restoreState(SaveGame *state) {
|
|
|
|
freeData();
|
|
|
|
|
|
|
|
Common::String fname = state->readString();
|
2011-12-21 11:00:08 +01:00
|
|
|
Common::SeekableReadStream *data = g_resourceloader->openNewStreamFile(fname.c_str(), true);
|
2011-12-17 18:32:31 +01:00
|
|
|
_data = BitmapData::getBitmapData(fname, data);
|
2012-01-25 20:35:58 -08:00
|
|
|
delete data;
|
2011-09-07 23:08:59 +02:00
|
|
|
|
|
|
|
_currImage = state->readLESint32();
|
|
|
|
_x = state->readLESint32();
|
|
|
|
_y = state->readLESint32();
|
|
|
|
}
|
|
|
|
|
2004-03-22 11:23:37 +00:00
|
|
|
void Bitmap::draw() const {
|
2004-12-10 07:26:03 +00:00
|
|
|
if (_currImage == 0)
|
2004-03-23 10:38:02 +00:00
|
|
|
return;
|
|
|
|
|
2004-04-19 09:56:34 +00:00
|
|
|
g_driver->drawBitmap(this);
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-09-18 18:46:20 +02:00
|
|
|
void Bitmap::setActiveImage(int n) {
|
2011-10-29 03:31:05 +08:00
|
|
|
assert(n >= 0);
|
2011-07-27 16:30:59 +02:00
|
|
|
if ((n - 1) >= _data->_numImages) {
|
|
|
|
warning("Bitmap::setNumber: no anim image: %d. (%s)", n, _data->_fname.c_str());
|
|
|
|
} else {
|
|
|
|
_currImage = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-07 23:08:59 +02:00
|
|
|
void Bitmap::freeData() {
|
2011-05-09 19:20:47 +02:00
|
|
|
--_data->_refCount;
|
|
|
|
if (_data->_refCount < 1) {
|
|
|
|
delete _data;
|
2011-11-01 04:21:19 +08:00
|
|
|
_data = 0;
|
2006-02-12 16:28:31 +00:00
|
|
|
}
|
2011-09-07 23:08:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Bitmap::~Bitmap() {
|
|
|
|
freeData();
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
2011-05-16 09:51:06 +02:00
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
const Graphics::PixelFormat &Bitmap::getPixelFormat(int num) const {
|
|
|
|
return getData(num).getFormat();
|
2011-05-16 06:14:46 +08:00
|
|
|
}
|
2003-08-15 18:00:22 +00:00
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
void BitmapData::convertToColorFormat(int num, const Graphics::PixelFormat &format) {
|
|
|
|
if (_data[num].getFormat() == format) {
|
2012-01-16 17:12:14 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
Graphics::PixelBuffer dst(format, _width * _height, DisposeAfterUse::NO);
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
for (int i = 0; i < _width * _height; ++i) {
|
|
|
|
if (_data[num].getValueAt(i) == 0xf81f) { //transparency
|
|
|
|
dst.setPixelAt(i, 0xf81f);
|
|
|
|
} else {
|
|
|
|
dst.setPixelAt(i, _data[num]);
|
2012-01-16 17:12:14 +01:00
|
|
|
}
|
|
|
|
}
|
2012-01-24 19:02:50 +01:00
|
|
|
_data[num].free();
|
|
|
|
_data[num] = dst;
|
|
|
|
}
|
2012-01-24 18:20:33 +01:00
|
|
|
|
2012-01-24 19:02:50 +01:00
|
|
|
void BitmapData::convertToColorFormat(const Graphics::PixelFormat &format) {
|
|
|
|
for (int i = 0; i < _numImages; ++i) {
|
|
|
|
convertToColorFormat(i, format);
|
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
}
|
|
|
|
|
2004-02-21 15:36:31 +00:00
|
|
|
#define GET_BIT do { bit = bitstr_value & 1; \
|
2004-02-24 08:20:45 +00:00
|
|
|
bitstr_len--; \
|
|
|
|
bitstr_value >>= 1; \
|
|
|
|
if (bitstr_len == 0) { \
|
|
|
|
bitstr_value = READ_LE_UINT16(compressed); \
|
|
|
|
bitstr_len = 16; \
|
|
|
|
compressed += 2; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
2003-08-15 18:00:22 +00:00
|
|
|
|
2011-10-29 03:31:05 +08:00
|
|
|
static bool decompress_codec3(const char *compressed, char *result, int maxBytes) {
|
2004-02-24 08:20:45 +00:00
|
|
|
int bitstr_value = READ_LE_UINT16(compressed);
|
|
|
|
int bitstr_len = 16;
|
2003-08-15 18:00:22 +00:00
|
|
|
compressed += 2;
|
2004-02-24 08:20:45 +00:00
|
|
|
bool bit;
|
|
|
|
|
2011-10-29 03:31:05 +08:00
|
|
|
int byteIndex = 0;
|
2004-02-24 08:20:45 +00:00
|
|
|
for (;;) {
|
|
|
|
GET_BIT;
|
2011-10-29 03:31:05 +08:00
|
|
|
if (bit == 1) {
|
|
|
|
if (byteIndex >= maxBytes) {
|
|
|
|
warning("Buffer overflow when decoding image: decompress_codec3 walked past the input buffer!");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*result++ = *compressed++;
|
|
|
|
++byteIndex;
|
|
|
|
}
|
2004-02-24 08:20:45 +00:00
|
|
|
else {
|
|
|
|
GET_BIT;
|
|
|
|
int copy_len, copy_offset;
|
|
|
|
if (bit == 0) {
|
|
|
|
GET_BIT;
|
|
|
|
copy_len = 2 * bit;
|
|
|
|
GET_BIT;
|
|
|
|
copy_len += bit + 3;
|
|
|
|
copy_offset = *(uint8 *)(compressed++) - 0x100;
|
|
|
|
} else {
|
2004-12-09 23:55:43 +00:00
|
|
|
copy_offset = (*(uint8 *)(compressed) | (*(uint8 *)(compressed + 1) & 0xf0) << 4) - 0x1000;
|
2004-02-24 08:20:45 +00:00
|
|
|
copy_len = (*(uint8 *)(compressed + 1) & 0xf) + 3;
|
|
|
|
compressed += 2;
|
|
|
|
if (copy_len == 3) {
|
|
|
|
copy_len = *(uint8 *)(compressed++) + 1;
|
|
|
|
if (copy_len == 1)
|
2011-10-29 03:31:05 +08:00
|
|
|
return true;
|
2004-02-24 08:20:45 +00:00
|
|
|
}
|
|
|
|
}
|
2004-12-09 23:55:43 +00:00
|
|
|
while (copy_len > 0) {
|
2011-10-29 03:31:05 +08:00
|
|
|
if (byteIndex >= maxBytes) {
|
|
|
|
warning("Buffer overflow when decoding image: decompress_codec3 walked past the input buffer!");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert(byteIndex + copy_offset >= 0);
|
|
|
|
assert(byteIndex + copy_offset < maxBytes);
|
|
|
|
*result = result[copy_offset];
|
|
|
|
result++;
|
|
|
|
}
|
|
|
|
++byteIndex;
|
2004-12-09 23:55:43 +00:00
|
|
|
copy_len--;
|
2004-02-24 08:20:45 +00:00
|
|
|
}
|
|
|
|
}
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
2011-10-29 03:31:05 +08:00
|
|
|
return true;
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
2009-05-25 06:49:57 +00:00
|
|
|
|
|
|
|
} // end of namespace Grim
|