Skip to content

Commit

Permalink
SHERLOCK: 3DO: support images inside room files
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Kiewitz committed Jun 11, 2015
1 parent 7ff3336 commit 9ce2cbc
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 19 deletions.
95 changes: 91 additions & 4 deletions engines/sherlock/image_file.cpp
Expand Up @@ -255,8 +255,8 @@ ImageFile3DO::ImageFile3DO(const Common::String &name) {
delete dataStream;
}

ImageFile3DO::ImageFile3DO(Common::SeekableReadStream &stream, bool roomData) {
load(stream, false);
ImageFile3DO::ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData) {
load(stream, isRoomData);
}

ImageFile3DO::~ImageFile3DO() {
Expand All @@ -265,9 +265,15 @@ ImageFile3DO::~ImageFile3DO() {
// (*this)[idx]._frame.free();
}

void ImageFile3DO::load(Common::SeekableReadStream &stream, bool roomData) {
uint32 headerId = stream.readUint32BE();
void ImageFile3DO::load(Common::SeekableReadStream &stream, bool isRoomData) {
uint32 headerId = 0;

if (isRoomData) {
load3DOCelRoomData(stream);
return;
}

headerId = stream.readUint32BE();
assert(!stream.eos());

// Seek back to the start
Expand Down Expand Up @@ -522,6 +528,87 @@ void ImageFile3DO::load3DOCelFile(Common::SeekableReadStream &stream) {
}
}

// Reads 3DO .cel data (room file format)
void ImageFile3DO::load3DOCelRoomData(Common::SeekableReadStream &stream) {
int streamSize = stream.size();
uint16 roomDataHeader_size = 0;

ImageFrame imageFrame;

// CCB chunk (cel control block)
uint32 ccbFlags = 0;
bool ccbFlags_compressed = false;
uint16 ccbPPMP0 = 0;
uint16 ccbPPMP1 = 0;
uint32 ccbPRE0 = 0;
byte ccbPRE0_bitsPerPixel = 0;
uint32 ccbPRE1 = 0;
uint32 ccbWidth = 0;
uint32 ccbHeight = 0;
// cel data
uint32 celDataSize = 0;
byte *celDataPtr = NULL;

while (stream.pos() < streamSize) {
ImageFrame frame;

// 3DO sherlock holmes room data header
stream.skip(4); // Possibly UINT16 width, UINT16 height?!?!
roomDataHeader_size = stream.readUint16BE();
stream.skip(2); // seems to be filler

// 3DO raw cel control block
ccbFlags = stream.readUint32BE();
stream.skip(3 * 4); // skip over 3 pointer fields, which are used in memory only by 3DO hardware
stream.skip(8 * 4); // skip over 8 offset fields
ccbPPMP0 = stream.readUint16BE();
ccbPPMP1 = stream.readUint16BE();
ccbPRE0 = stream.readUint32BE();
ccbPRE1 = stream.readUint32BE();
ccbWidth = stream.readUint32BE();
ccbHeight = stream.readUint32BE();

if (ccbFlags & 0x200) // bit 9
ccbFlags_compressed = true;

// PRE0 first 3 bits define how many bits per encoded pixel are used
ccbPRE0_bitsPerPixel = imagefile3DO_cel_bitsPerPixelLookupTable[ccbPRE0 & 0x07];
if (!ccbPRE0_bitsPerPixel)
error("load3DOCelRoomData: Invalid CCB PRE0 bits per pixel");

if (ccbPRE0_bitsPerPixel != 16) {
// We currently support 16-bits per pixel in here
error("load3DOCelRoomData: bits per pixel < 16?!?!?");
}

// cel data follows
assert(roomDataHeader_size > 68);
// size field does not include the 8 byte header
celDataSize = roomDataHeader_size - 68;

// read data into memory
celDataPtr = new byte[celDataSize];

stream.read(celDataPtr, celDataSize);

// Set up frame
imageFrame._width = ccbWidth;
imageFrame._height = ccbHeight;
imageFrame._paletteBase = 0;
imageFrame._offset.x = 0;
imageFrame._offset.y = 0;
imageFrame._rleEncoded = ccbFlags_compressed;
imageFrame._size = 0;

// Decompress/copy this frame
decompress3DOCelFrame(imageFrame, celDataPtr, celDataSize, ccbPRE0_bitsPerPixel, NULL);

delete[] celDataPtr;

push_back(imageFrame);
}
}

static uint16 imagefile3DO_cel_bitsMask[17] = {
0,
0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
Expand Down
9 changes: 7 additions & 2 deletions engines/sherlock/image_file.h
Expand Up @@ -105,7 +105,7 @@ class ImageFile3DO : public ImageFile { // Common::Array<ImageFrame> {
/**
* Load the data of the sprite
*/
void load(Common::SeekableReadStream &stream, bool animImages);
void load(Common::SeekableReadStream &stream, bool isRoomData);

/**
* convert pixel RGB values from RGB555 to RGB565
Expand All @@ -117,6 +117,11 @@ class ImageFile3DO : public ImageFile { // Common::Array<ImageFrame> {
*/
void load3DOCelFile(Common::SeekableReadStream &stream);

/**
* Load 3DO cel data (room file format)
*/
void load3DOCelRoomData(Common::SeekableReadStream &stream);

inline uint16 celGetBits(const byte *&dataPtr, byte bitCount, byte &dataBitsLeft);

/**
Expand All @@ -131,7 +136,7 @@ class ImageFile3DO : public ImageFile { // Common::Array<ImageFrame> {

public:
ImageFile3DO(const Common::String &name);
ImageFile3DO(Common::SeekableReadStream &stream, bool roomData = false);
ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData = false);
~ImageFile3DO();
static void setVm(SherlockEngine *vm);
};
Expand Down
19 changes: 6 additions & 13 deletions engines/sherlock/scene.cpp
Expand Up @@ -656,21 +656,14 @@ bool Scene::loadScene(const Common::String &filename) {
_images[idx + 1]._filesize = bgInfo[idx]._filesize;
_images[idx + 1]._maxFrames = bgInfo[idx]._maxFrames;

// Read the image data
// It seems it's a 8 byte header per frame
// followed by a copy of the cel header
// which is then followed by cel data
// TODO
warning("image %d, maxFrames %d", idx, bgInfo[idx]._maxFrames);
warning("size %d", bgInfo[idx]._filesize);
// Read image data into memory
Common::SeekableReadStream *imageStream = roomStream->readStream(bgInfo[idx]._filesize);

// Read in the image data
//Common::SeekableReadStream *imageStream = roomStream->readStream(bgInfo[idx]._filesize);
// Load image data into an ImageFile array as room file data
// which is basically a fixed header, followed by a raw cel header, followed by regular cel data
_images[idx + 1]._images = new ImageFile3DO(*imageStream, true);

//_images[idx + 1]._images = new ImageFile(*imageStream);

//delete imageStream;
warning("end");
delete imageStream;
}

// === BGSHAPES === Set up the bgShapes
Expand Down

0 comments on commit 9ce2cbc

Please sign in to comment.