2009-05-26 14:13:08 +00:00
|
|
|
/* Residual - A 3D game interpreter
|
2008-06-13 14:57:47 +00:00
|
|
|
*
|
|
|
|
* Residual 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.
|
|
|
|
|
|
|
|
* 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.
|
|
|
|
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
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"
|
2011-05-09 04:37:51 +08:00
|
|
|
#include "common/zlib.h"
|
|
|
|
#include "common/memstream.h"
|
2008-01-26 11:47:23 +00:00
|
|
|
|
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"
|
|
|
|
#include "engines/grim/gfx_base.h"
|
2011-03-21 05:16:27 +08:00
|
|
|
#include "engines/grim/savegame.h"
|
2011-04-10 11:24:03 +02:00
|
|
|
#include "engines/grim/colormap.h"
|
2004-01-23 11:10:59 +00:00
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
namespace Grim {
|
|
|
|
|
2003-08-15 18:00:22 +00:00
|
|
|
static void decompress_codec3(const char *compressed, char *result);
|
|
|
|
|
2011-03-21 05:16:27 +08:00
|
|
|
Bitmap::Bitmap(const char *fname, const char *data, int len) :
|
|
|
|
Object() {
|
2009-10-17 12:48:23 +00:00
|
|
|
_fname = fname;
|
2011-05-09 04:37:51 +08:00
|
|
|
printf("Trying to load %s\n", fname);
|
2005-07-10 18:57:27 +00:00
|
|
|
if (len < 8 || memcmp(data, "BM F\0\0\0", 8) != 0) {
|
2011-05-09 04:37:51 +08:00
|
|
|
// Should probably just check the filename
|
|
|
|
if(loadTile(fname,data,len)){
|
|
|
|
return;
|
|
|
|
// Everything is fine
|
|
|
|
}
|
|
|
|
else if (gDebugLevel == DEBUG_BITMAPS || gDebugLevel == DEBUG_ERROR || gDebugLevel == DEBUG_ALL)
|
2008-09-28 15:23:15 +00:00
|
|
|
error("Invalid magic loading bitmap");
|
2005-07-10 18:57:27 +00:00
|
|
|
}
|
2004-02-24 08:20:45 +00:00
|
|
|
|
|
|
|
int codec = READ_LE_UINT32(data + 8);
|
2011-03-21 05:16:27 +08:00
|
|
|
// _paletteIncluded = READ_LE_UINT32(data + 12);
|
2004-12-10 07:26:03 +00:00
|
|
|
_numImages = READ_LE_UINT32(data + 16);
|
2004-12-09 23:55:43 +00:00
|
|
|
_x = READ_LE_UINT32(data + 20);
|
|
|
|
_y = READ_LE_UINT32(data + 24);
|
2011-03-21 05:16:27 +08:00
|
|
|
// _transparentColor = READ_LE_UINT32(data + 28);
|
2004-12-09 23:55:43 +00:00
|
|
|
_format = READ_LE_UINT32(data + 32);
|
2011-05-01 03:50:18 +08:00
|
|
|
_bpp = READ_LE_UINT32(data + 36);
|
2011-03-21 05:16:27 +08:00
|
|
|
// _blueBits = READ_LE_UINT32(data + 40);
|
|
|
|
// _greenBits = READ_LE_UINT32(data + 44);
|
|
|
|
// _redBits = READ_LE_UINT32(data + 48);
|
|
|
|
// _blueShift = READ_LE_UINT32(data + 52);
|
|
|
|
// _greenShift = READ_LE_UINT32(data + 56);
|
|
|
|
// _redShift = READ_LE_UINT32(data + 60);
|
2004-12-09 23:55:43 +00:00
|
|
|
_width = READ_LE_UINT32(data + 128);
|
|
|
|
_height = READ_LE_UINT32(data + 132);
|
2004-12-10 07:26:03 +00:00
|
|
|
_currImage = 1;
|
2004-12-09 23:55:43 +00:00
|
|
|
|
2004-12-10 07:26:03 +00:00
|
|
|
_data = new char *[_numImages];
|
2004-02-24 08:20:45 +00:00
|
|
|
int pos = 0x88;
|
2004-12-10 07:26:03 +00:00
|
|
|
for (int i = 0; i < _numImages; i++) {
|
2011-04-30 21:59:49 +02:00
|
|
|
_data[i] = new char[_bpp / 8 * _width * _height];
|
2004-02-24 08:20:45 +00:00
|
|
|
if (codec == 0) {
|
2011-04-30 21:59:49 +02:00
|
|
|
memcpy(_data[i], data + pos, _bpp / 8 * _width * _height);
|
|
|
|
pos += _bpp / 8 * _width * _height + 8;
|
2004-03-21 15:16:57 +00:00
|
|
|
} else if (codec == 3) {
|
2004-12-09 23:55:43 +00:00
|
|
|
int compressed_len = READ_LE_UINT32(data + pos);
|
|
|
|
decompress_codec3(data + pos + 4, _data[i]);
|
|
|
|
pos += compressed_len + 12;
|
2004-02-24 08:20:45 +00:00
|
|
|
}
|
|
|
|
|
2011-05-01 21:05:45 +02:00
|
|
|
#ifdef SCUMM_BIG_ENDIAN
|
2005-01-12 18:06:43 +00:00
|
|
|
if (_format == 1)
|
2004-12-09 23:55:43 +00:00
|
|
|
for (int j = 0; j < _width * _height; ++j) {
|
|
|
|
((uint16 *)_data[i])[j] = SWAP_BYTES_16(((uint16 *)_data[i])[j]);
|
2004-04-14 23:04:33 +00:00
|
|
|
}
|
2004-12-09 23:55:43 +00:00
|
|
|
#endif
|
2005-01-12 18:06:43 +00:00
|
|
|
}
|
|
|
|
|
2004-04-19 09:56:34 +00:00
|
|
|
g_driver->createBitmap(this);
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-05-01 03:50:18 +08:00
|
|
|
Bitmap::Bitmap(const char *data, int w, int h, int bpp, const char *fname) : Object() {
|
2009-10-17 12:48:23 +00:00
|
|
|
_fname = fname;
|
2009-05-25 19:21:58 +00:00
|
|
|
if (gDebugLevel == DEBUG_BITMAPS || gDebugLevel == DEBUG_NORMAL || gDebugLevel == DEBUG_ALL)
|
2009-10-17 12:48:23 +00:00
|
|
|
printf("New bitmap loaded: %s\n", fname);
|
2005-04-08 14:35:13 +00:00
|
|
|
_currImage = 1;
|
|
|
|
_numImages = 1;
|
|
|
|
_x = 0;
|
|
|
|
_y = 0;
|
2009-10-17 12:48:23 +00:00
|
|
|
_width = w;
|
|
|
|
_height = h;
|
2005-08-12 13:51:10 +00:00
|
|
|
_format = 1;
|
|
|
|
_numTex = 0;
|
|
|
|
_texIds = NULL;
|
2011-05-01 03:50:18 +08:00
|
|
|
_bpp = bpp;
|
2005-08-12 13:51:10 +00:00
|
|
|
_hasTransparency = false;
|
2005-04-08 14:35:13 +00:00
|
|
|
_data = new char *[_numImages];
|
2011-04-30 21:59:49 +02:00
|
|
|
_data[0] = new char[_bpp / 8 * _width * _height];
|
|
|
|
memcpy(_data[0], data, _bpp / 8 * _width * _height);
|
2005-04-08 14:35:13 +00:00
|
|
|
g_driver->createBitmap(this);
|
|
|
|
}
|
|
|
|
|
2011-03-21 17:18:04 +01:00
|
|
|
Bitmap::Bitmap() :
|
|
|
|
Object() {
|
|
|
|
_data = NULL;
|
|
|
|
}
|
|
|
|
|
2011-05-09 04:37:51 +08:00
|
|
|
// Helper function for makeBitmapFromTile
|
|
|
|
char* getLine(int lineNum, char* data, unsigned int width,int bpp){
|
|
|
|
return data + (lineNum*(width*bpp));
|
|
|
|
}
|
|
|
|
|
|
|
|
char* makeBitmapFromTile(char** bits,int width, int height, int bpp){
|
|
|
|
bpp = bpp/8;
|
|
|
|
char* fullImage = new char[width*height*bpp];
|
|
|
|
|
|
|
|
const int tWidth = 256*bpp; // All tiles so far are 256 wide
|
|
|
|
const int tWidth2 = 256;
|
|
|
|
|
|
|
|
char* target = fullImage;
|
|
|
|
for(int i=0;i<256;i++){
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
if(i<224){ // Skip blank space
|
|
|
|
target=getLine(223-i,fullImage,width,bpp);
|
|
|
|
|
|
|
|
memcpy(target,getLine(i,bits[3],tWidth2,bpp),tWidth);
|
|
|
|
target += tWidth;
|
|
|
|
|
|
|
|
memcpy(target,getLine(i,bits[4],tWidth2,bpp),tWidth);
|
|
|
|
target += tWidth;
|
|
|
|
|
|
|
|
memcpy(target,getLine(i,bits[2],tWidth2,bpp)+128*bpp,128*bpp);
|
|
|
|
target += tWidth/2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Top half of course
|
|
|
|
|
|
|
|
target = getLine(479-i,fullImage,width,bpp);
|
|
|
|
|
|
|
|
memcpy(target,getLine(i,bits[0],tWidth2,bpp),tWidth);
|
|
|
|
target += tWidth;
|
|
|
|
|
|
|
|
memcpy(target,getLine(i,bits[1],tWidth2,bpp),tWidth);
|
|
|
|
target += tWidth;
|
|
|
|
|
|
|
|
memcpy(target,getLine(i,bits[2],tWidth2,bpp),128*bpp);
|
|
|
|
target += tWidth/2;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return fullImage;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* upconvertto32(char* data, unsigned int width, unsigned int height, int bpp){
|
|
|
|
if(bpp==16){
|
|
|
|
bpp=2;
|
|
|
|
char* newData = new char[width*height*4];
|
|
|
|
char* to = newData;
|
|
|
|
char red=0,green=0,blue=0;
|
|
|
|
for(unsigned int i=0;i<height;i++){
|
|
|
|
for(unsigned int j=0;j<width;j++){
|
|
|
|
char byte2 = data[i*width*bpp+j*2];
|
|
|
|
char byte1 = data[i*width*bpp+j*2+1];
|
|
|
|
// Probably Alpha, then 555.
|
|
|
|
// Red
|
|
|
|
red = (byte1>>2)&31;
|
|
|
|
red = red << 3 | red >> 2;
|
|
|
|
// Green
|
|
|
|
char green1 = (byte1&3);
|
|
|
|
char green2 = (((byte2)>>5)&7);
|
|
|
|
char green3 = green1 << 3 | green2;
|
|
|
|
green = green3 << 3 | green3 >> 2 ;
|
|
|
|
// Blue
|
|
|
|
blue = (byte2)&31;
|
|
|
|
blue = blue << 3 | blue >> 2;
|
|
|
|
// Some more magic to stretch the values
|
|
|
|
*to = red;
|
|
|
|
to++;
|
|
|
|
*to = green;
|
|
|
|
to++;
|
|
|
|
*to = blue;
|
|
|
|
to++;
|
|
|
|
*to = 0;
|
|
|
|
to++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete data;
|
|
|
|
return newData;
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Bitmap::loadTile(const char *filename, const char *data, int len){
|
|
|
|
_x = 0;
|
|
|
|
_y = 0;
|
|
|
|
//warning("Loading TILE: %s",filename);
|
|
|
|
Common::MemoryReadStream stream((const byte *)data, len);
|
|
|
|
Common::SeekableReadStream *o = Common::wrapCompressedReadStream(&stream);
|
|
|
|
|
|
|
|
uint32 id, bmoffset;
|
|
|
|
id = o->readUint32LE();
|
|
|
|
// Should check that we actually HAVE a TIL
|
|
|
|
bmoffset = o->readUint32LE();
|
|
|
|
o->seek(bmoffset + 16);
|
|
|
|
_numImages = o->readUint32LE();
|
|
|
|
if (_numImages < 5)
|
|
|
|
error("Can not handle a tile with less than 5 images");
|
|
|
|
|
|
|
|
_data = new char *[_numImages];
|
|
|
|
|
|
|
|
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;
|
|
|
|
for (int i = 0; i < _numImages; ++i) {
|
|
|
|
_data[i] = new char[size];
|
|
|
|
o->seek(8, SEEK_CUR);
|
|
|
|
o->read(_data[i], size);
|
|
|
|
}
|
|
|
|
char* bMap = makeBitmapFromTile(_data,640,480,_bpp);
|
|
|
|
for (int i = 0; i < _numImages; ++i) {
|
|
|
|
delete [] _data[i];
|
|
|
|
}
|
|
|
|
_data[0] = bMap;
|
|
|
|
_numImages = 1;
|
|
|
|
|
|
|
|
if(_bpp==16){
|
|
|
|
_data[0] = upconvertto32(_data[0],640,480,_bpp);
|
|
|
|
_bpp=32;
|
|
|
|
}
|
|
|
|
_width = 640;
|
|
|
|
_height = 480;
|
|
|
|
_currImage=1;
|
|
|
|
|
|
|
|
g_driver->createBitmap(this);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
Bitmap::~Bitmap() {
|
2008-09-10 11:16:57 +00:00
|
|
|
if (_data) {
|
2006-02-12 16:28:31 +00:00
|
|
|
for (int i = 0; i < _numImages; i++)
|
2008-09-10 11:16:57 +00:00
|
|
|
if (_data[i])
|
2006-02-12 16:28:31 +00:00
|
|
|
delete[] _data[i];
|
2004-12-09 23:55:43 +00:00
|
|
|
|
2006-02-12 16:28:31 +00:00
|
|
|
delete[] _data;
|
|
|
|
_data = NULL;
|
2011-03-21 05:16:27 +08:00
|
|
|
|
|
|
|
g_driver->destroyBitmap(this);
|
2006-02-12 16:28:31 +00:00
|
|
|
}
|
2011-05-08 18:39:28 +02:00
|
|
|
g_grim->killBitmap(this);
|
2003-08-15 18:00:22 +00: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
|
|
|
|
|
|
|
static void decompress_codec3(const char *compressed, char *result) {
|
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;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
GET_BIT;
|
|
|
|
if (bit == 1)
|
|
|
|
*result++ = *compressed++;
|
|
|
|
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)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2004-12-09 23:55:43 +00:00
|
|
|
while (copy_len > 0) {
|
|
|
|
*result = result[copy_offset];
|
|
|
|
result++;
|
|
|
|
copy_len--;
|
2004-02-24 08:20:45 +00:00
|
|
|
}
|
|
|
|
}
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
}
|
2009-05-25 06:49:57 +00:00
|
|
|
|
|
|
|
} // end of namespace Grim
|