From 94a942755e745bc3553b3d8cc83e533688d867fa Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 26 Sep 2016 13:19:37 +0300 Subject: CHEWY: Initial support for game sprites --- engines/chewy/chewy.cpp | 13 ++++++ engines/chewy/graphics.cpp | 20 +++++++++ engines/chewy/graphics.h | 3 ++ engines/chewy/resource.cpp | 105 +++++++++++++++++++++++++++++++++++++-------- engines/chewy/resource.h | 38 ++++++++++++++-- 5 files changed, 158 insertions(+), 21 deletions(-) diff --git a/engines/chewy/chewy.cpp b/engines/chewy/chewy.cpp index e5dd7ec265..94cbee4559 100644 --- a/engines/chewy/chewy.cpp +++ b/engines/chewy/chewy.cpp @@ -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); } diff --git a/engines/chewy/graphics.cpp b/engines/chewy/graphics.cpp index fda46a3e7a..84e6002dc9 100644 --- a/engines/chewy/graphics.cpp +++ b/engines/chewy/graphics.cpp @@ -22,6 +22,7 @@ #include "common/system.h" #include "common/events.h" +#include "graphics/cursorman.h" #include "graphics/palette.h" #include "chewy/graphics.h" @@ -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 diff --git a/engines/chewy/graphics.h b/engines/chewy/graphics.h index c7d303d2a2..64c4255324 100644 --- a/engines/chewy/graphics.h +++ b/engines/chewy/graphics.h @@ -34,6 +34,9 @@ public: void drawImage(Common::String filename, int imageNum); void playVideo(uint num); + void setCursor(uint num); + void showCursor(); + void hideCursor(); private: }; diff --git a/engines/chewy/resource.cpp b/engines/chewy/resource.cpp index 23ac5c2ef2..13bd9d2e97 100644 --- a/engines/chewy/resource.cpp +++ b/engines/chewy/resource.cpp @@ -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; @@ -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()); @@ -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; } diff --git a/engines/chewy/resource.h b/engines/chewy/resource.h index d9665ceb4a..b869840975 100644 --- a/engines/chewy/resource.h +++ b/engines/chewy/resource.h @@ -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; @@ -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; @@ -125,6 +146,9 @@ public: 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; @@ -133,6 +157,14 @@ protected: 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) {} -- cgit v1.2.3