Skip to content

Commit

Permalink
CHEWY: Initial support for game sprites
Browse files Browse the repository at this point in the history
  • Loading branch information
bluegr committed Oct 2, 2016
1 parent 1de9019 commit 94a9427
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 21 deletions.
13 changes: 13 additions & 0 deletions engines/chewy/chewy.cpp
Expand Up @@ -79,22 +79,35 @@ Common::Error ChewyEngine::run() {

//_graphics->playVideo(0);
_graphics->drawImage("episode1.tgp", 0);
_graphics->showCursor();
_graphics->setCursor(0);
//_sound->playSpeech(1);
//_sound->playSound(1);
//_sound->playMusic(2);

// Run a dummy loop
Common::Event event;
uint curCursor = 0;
const uint maxCursors = 41;

while (!shouldQuit()) {
while (g_system->getEventManager()->pollEvent(event)) {
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
g_engine->quitGame();
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_SPACE) || event.type == Common::EVENT_RBUTTONUP) {
curCursor++;
if (curCursor == maxCursors)
curCursor = 0;
_graphics->setCursor(curCursor);
}

if (event.type == Common::EVENT_KEYDOWN && event.kbd.flags & Common::KBD_CTRL && event.kbd.keycode == Common::KEYCODE_d)
_console->attach();
}

_console->onFrame();

g_system->updateScreen();
g_system->delayMillis(10);
}

Expand Down
20 changes: 20 additions & 0 deletions engines/chewy/graphics.cpp
Expand Up @@ -22,6 +22,7 @@

#include "common/system.h"
#include "common/events.h"
#include "graphics/cursorman.h"
#include "graphics/palette.h"

#include "chewy/graphics.h"
Expand Down Expand Up @@ -85,4 +86,23 @@ void Graphics::playVideo(uint num) {
cfoDecoder->close();
}

void Graphics::setCursor(uint num) {
SpriteResource *res = new SpriteResource("cursor.taf");
TAFChunk *cursor = res->getSprite(num);

CursorMan.replaceCursor(cursor->data, cursor->width, cursor->height, 0, 0, 0);

delete[] cursor->data;
delete cursor;
delete res;
}

void Graphics::showCursor() {
CursorMan.showMouse(true);
}

void Graphics::hideCursor() {
CursorMan.showMouse(false);
}

} // End of namespace Chewy
3 changes: 3 additions & 0 deletions engines/chewy/graphics.h
Expand Up @@ -34,6 +34,9 @@ class Graphics {

void drawImage(Common::String filename, int imageNum);
void playVideo(uint num);
void setCursor(uint num);
void showCursor();
void hideCursor();
private:

};
Expand Down
105 changes: 87 additions & 18 deletions engines/chewy/resource.cpp
Expand Up @@ -50,18 +50,23 @@ Resource::Resource(Common::String filename) {
const uint32 headerGeneric = MKTAG('N', 'G', 'S', '\0');
const uint32 headerTxtDec = MKTAG('T', 'C', 'F', '\0');
const uint32 headerTxtEnc = MKTAG('T', 'C', 'F', '\1');
const uint32 headerSprite = MKTAG('T', 'A', 'F', '\0');

_stream.open(filename);

uint32 header = _stream.readUint32BE();
bool isText = header == headerTxtDec || header == headerTxtEnc;
bool isText = (header == headerTxtDec || header == headerTxtEnc);
bool isSprite = (header == headerSprite);

if (header != headerGeneric && !isText)
if (header != headerGeneric && !isSprite && !isText)
error("Invalid resource - %s", filename.c_str());

if (isText) {
_resType = kResourceTCF;
_encrypted = (header == headerTxtEnc);
} else if (isSprite) {
initSprite(filename);
return;
} else {
_resType = (ResourceType)_stream.readUint16LE();
_encrypted = false;
Expand Down Expand Up @@ -112,6 +117,83 @@ byte *Resource::getChunkData(uint num) {
return data;
}

void Resource::initSprite(Common::String filename) {
uint16 screenMode;;
uint32 nextSpriteOffset;

// TAF (sprite) resources are much different than the rest, so we have a
// separate initializer for them here

_resType = kResourceTAF;
_encrypted = false;
screenMode = _stream.readUint16LE();
_chunkCount = _stream.readUint16LE();
_stream.skip(4); // total size of all sprites
_stream.skip(3 * 256); // palette
nextSpriteOffset = _stream.readUint32LE();
_stream.skip(2 + 1); // correction table, padding
if ((int32)nextSpriteOffset != _stream.pos())
error("Invalid sprite resource - %s", filename.c_str());

for (uint i = 0; i < _chunkCount; i++) {
Chunk cur;

cur.pos = _stream.pos();
cur.type = kResourceTAF;

_stream.skip(2 + 2 + 2); // compression flag, width, height
uint32 nextSpriteOffset = _stream.readUint32LE();
uint32 spriteImageOffset = _stream.readUint32LE();
_stream.skip(1); // padding

if ((int32)spriteImageOffset != _stream.pos())
error("Invalid sprite resource - %s", filename.c_str());

cur.size = nextSpriteOffset - cur.pos - 15; // 15 = sizeof(TAFChunk)

_stream.skip(cur.size);
_chunkList.push_back(cur);
}
}

void Resource::unpackRLE(byte *buffer, uint32 compressedSize, uint32 uncompressedSize) {
// Compressed images are packed using a very simple RLE compression
byte count;
byte value;
uint32 outPos = 0;

for (uint i = 0; i < (compressedSize) / 2 && outPos < uncompressedSize; i++) {
count = _stream.readByte();
value = _stream.readByte();
for (byte j = 0; j < count; j++) {
buffer[outPos++] = value;
}
}
}

TAFChunk *SpriteResource::getSprite(uint num) {
assert(num < _chunkList.size());

Chunk *chunk = &_chunkList[num];
TAFChunk *taf = new TAFChunk();

_stream.seek(chunk->pos, SEEK_SET);

taf->compressionFlag = _stream.readUint16LE();
taf->width = _stream.readUint16LE();
taf->height = _stream.readUint16LE();
_stream.skip(4 + 4 + 1); // nextSpriteOffset, spriteImageOffset, padding

taf->data = new byte[taf->width * taf->height];

if (!taf->compressionFlag)
_stream.read(taf->data, chunk->size);
else
unpackRLE(taf->data, chunk->size, taf->width * taf->height);

return taf;
}

TBFChunk *BackgroundResource::getImage(uint num) {
assert(num < _chunkList.size());

Expand All @@ -133,23 +215,10 @@ TBFChunk *BackgroundResource::getImage(uint num) {

tbf->data = new byte[tbf->size];

if (!tbf->compressionFlag) {
if (!tbf->compressionFlag)
_stream.read(tbf->data, chunk->size);
}
else {
// Compressed images are packed using a very simple RLE compression
byte count;
byte value;
uint32 outPos = 0;

for (uint i = 0; i < (chunk->size) / 2 && outPos < tbf->size; i++) {
count = _stream.readByte();
value = _stream.readByte();
for (byte j = 0; j < count; j++) {
tbf->data[outPos++] = value;
}
}
}
else
unpackRLE(tbf->data, chunk->size, tbf->size);

return tbf;
}
Expand Down
38 changes: 35 additions & 3 deletions engines/chewy/resource.h
Expand Up @@ -65,9 +65,6 @@ enum ResourceType {
kResourceTCF = 26 // error messages, used in err/err_e.tcf (English) and err/err_d.tcf (German)
};

// 4 + 2 + 2 + 4 + 2 + 2 + 768 = 784 bytes
#define TBF_CHUNK_HEADER_SIZE 784

// Generic chunk header
struct Chunk {
uint32 size;
Expand All @@ -89,6 +86,30 @@ struct TBFChunk {
byte *data;
};

// TAF (sprite) chunk header
/*struct TAFHeader {
// TAF chunk header
// ID (TAF, followed by a zero)
uint16 screenMode;
uint16 spriteCount;
uint32 size; // total size (width * height) of all sprites
byte palette[3 * 256];
uint32 nextSpriteOffset;
uint16 correctionTable;
// 1 byte padding
};*/

// TAF (sprite) image data chunk header - 15 bytes
struct TAFChunk {
uint16 compressionFlag;
uint16 width;
uint16 height;
// 4 bytes next sprite offset
// 4 bytes sprite image offset
// 1 byte padding
byte *data;
};

// Sound chunk header
struct SoundChunk {
uint32 size;
Expand Down Expand Up @@ -125,6 +146,9 @@ class Resource {
virtual byte *getChunkData(uint num);

protected:
void initSprite(Common::String filename);
void unpackRLE(byte *buffer, uint32 compressedSize, uint32 uncompressedSize);

Common::File _stream;
uint16 _chunkCount;
ResourceType _resType;
Expand All @@ -133,6 +157,14 @@ class Resource {
ChunkList _chunkList;
};

class SpriteResource : public Resource {
public:
SpriteResource(Common::String filename) : Resource(filename) {}
~SpriteResource() {}

TAFChunk *getSprite(uint num);
};

class BackgroundResource : public Resource {
public:
BackgroundResource(Common::String filename) : Resource(filename) {}
Expand Down

0 comments on commit 94a9427

Please sign in to comment.