From 765dbe647cb97cd8a728bd3bbdbf3e8f97718af2 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Fri, 12 Jun 2015 21:23:45 +0200 Subject: SHERLOCK: 3DO: some work on font file loading --- engines/sherlock/animation.cpp | 2 +- engines/sherlock/events.cpp | 2 +- engines/sherlock/fonts.cpp | 34 ++++-- engines/sherlock/image_file.cpp | 129 ++++++++++++++++++++- engines/sherlock/image_file.h | 15 ++- engines/sherlock/people.cpp | 2 +- engines/sherlock/scalpel/scalpel.cpp | 18 +-- .../sherlock/scalpel/scalpel_user_interface.cpp | 4 +- 8 files changed, 181 insertions(+), 25 deletions(-) diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp index 50cb200d0b..bbf7c913b7 100644 --- a/engines/sherlock/animation.cpp +++ b/engines/sherlock/animation.cpp @@ -169,7 +169,7 @@ bool Animation::play3DO(const Common::String &filename, bool intro, int minDelay // Load initial image Common::String graphicsName = "prologue/" + filename + ".3da"; - ImageFile3DO images(graphicsName); + ImageFile3DO images(graphicsName, kImageFile3DOType_Animation); events.wait(minDelay); diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp index 74ed72ed41..297437ed49 100644 --- a/engines/sherlock/events.cpp +++ b/engines/sherlock/events.cpp @@ -59,7 +59,7 @@ void Events::loadCursors(const Common::String &filename) { _cursorImages = new ImageFile(filename); } else { // 3DO - _cursorImages = new ImageFile3DO(filename, true); + _cursorImages = new ImageFile3DO(filename, kImageFile3DOType_RoomFormat); } _cursorId = INVALID_CURSOR; } diff --git a/engines/sherlock/fonts.cpp b/engines/sherlock/fonts.cpp index 57241bfa00..c6657cd580 100644 --- a/engines/sherlock/fonts.cpp +++ b/engines/sherlock/fonts.cpp @@ -45,15 +45,35 @@ void Fonts::free() { void Fonts::setFont(int fontNum) { _fontNumber = fontNum; - if (_platform == Common::kPlatform3DO) - return; - - Common::String fname = Common::String::format("FONT%d.VGS", fontNum + 1); - - // Discard any previous font and read in new one + // Discard previous font delete _font; - _font = new ImageFile(fname); + Common::String fontFilename; + + if (_platform != Common::kPlatform3DO) { + // PC + // use FONT[number].VGS, which is a regular sherlock graphic file + fontFilename = Common::String::format("FONT%d.VGS", fontNum + 1); + + // load font data + _font = new ImageFile(fontFilename); + } else { + // 3DO + switch (fontNum) { + case 0: + case 1: + fontFilename = "helvetica14.font"; + break; + case 2: + fontFilename = "darts.font"; + break; + default: + error("setFont(): unsupported 3DO font number"); + } + // load font data + _font = new ImageFile3DO(fontFilename, kImageFile3DOType_Font); + } + // Iterate through the frames to find the tallest font character _fontHeight = 0; for (uint idx = 0; idx < _font->size(); ++idx) diff --git a/engines/sherlock/image_file.cpp b/engines/sherlock/image_file.cpp index 43d3cf3de2..a42b443e3c 100644 --- a/engines/sherlock/image_file.cpp +++ b/engines/sherlock/image_file.cpp @@ -243,20 +243,41 @@ void ImageFile3DO::setVm(SherlockEngine *vm) { _vm = vm; } -ImageFile3DO::ImageFile3DO(const Common::String &name, bool isRoomDataFormat) { +ImageFile3DO::ImageFile3DO(const Common::String &name, ImageFile3DOType imageFile3DOType) { Common::File *dataStream = new Common::File(); if (!dataStream->open(name)) { error("unable to open %s\n", name.c_str()); } - load(*dataStream, isRoomDataFormat); + switch(imageFile3DOType) { + case kImageFile3DOType_Animation: + loadAnimationFile(*dataStream); + break; + case kImageFile3DOType_Cel: + case kImageFile3DOType_CelAnimation: + load3DOCelFile(*dataStream); + break; + case kImageFile3DOType_RoomFormat: + load3DOCelRoomData(*dataStream); + break; + case kImageFile3DOType_Font: + loadFont(*dataStream); + break; + default: + error("unknown Imagefile-3DO-Type"); + break; + } delete dataStream; } ImageFile3DO::ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData) { - load(stream, isRoomData); + if (!isRoomData) { + load(stream, isRoomData); + } else { + load3DOCelRoomData(stream); + } } ImageFile3DO::~ImageFile3DO() { @@ -775,4 +796,106 @@ void ImageFile3DO::decompress3DOCelFrame(ImageFrame &frame, const byte *dataPtr, } } +// Reads Sherlock Holmes 3DO font file +void ImageFile3DO::loadFont(Common::SeekableReadStream &stream) { + uint32 streamSize = stream.size(); + uint32 header_offsetWidthTable = 0; + uint32 header_offsetBitsTable = 0; + uint32 header_fontHeight = 0; + uint32 header_bytesPerLine = 0; + uint32 header_maxChar = 0; + uint32 header_charCount = 0; + + byte *widthTablePtr = NULL; + uint32 bitsTableSize = 0; + byte *bitsTablePtr = NULL; + + stream.skip(2); // Unknown bytes + stream.skip(2); // Unknown bytes (0x000E) + header_offsetWidthTable = stream.readUint32BE(); + header_offsetBitsTable = stream.readUint32BE(); + stream.skip(4); // Unknown bytes (0x00000004) + header_fontHeight = stream.readUint32BE(); + header_bytesPerLine = stream.readUint32BE(); + header_maxChar = stream.readUint32BE(); + + assert(header_maxChar <= 255); + header_charCount = header_maxChar + 1; + + // Allocate memory for width table + widthTablePtr = new byte[header_charCount]; + + stream.seek(header_offsetWidthTable); + stream.read(widthTablePtr, header_charCount); + + // Allocate memory for the bits + assert(header_offsetBitsTable < streamSize); // Security check + bitsTableSize = streamSize - header_offsetBitsTable; + bitsTablePtr = new byte[bitsTableSize]; + stream.read(bitsTablePtr, bitsTableSize); + + // Now extract all characters + uint16 curChar = 0; + const byte *curBitsLinePtr = bitsTablePtr; + const byte *curBitsPtr = NULL; + byte curBitsLeft = 0; + uint32 curCharHeightLeft = 0; + uint32 curCharWidthLeft = 0; + byte curBits = 0; + + for (curChar = 0; curChar < header_charCount; curChar++) { + // create frame + { + ImageFrame imageFrame; + + imageFrame._width = widthTablePtr[curChar]; + imageFrame._height = header_fontHeight; + imageFrame._paletteBase = 0; + imageFrame._offset.x = 0; + imageFrame._offset.y = 0; + imageFrame._rleEncoded = false; + imageFrame._size = 0; + + // Extract pixels + imageFrame._frame.create(imageFrame._width, imageFrame._height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); + uint16 *dest = (uint16 *)imageFrame._frame.getPixels(); + Common::fill(dest, dest + imageFrame._width * imageFrame._height, 0); + +#if 0 + curCharHeightLeft = header_fontHeight; + while (curCharHeightLeft) { + curCharWidthLeft = widthTablePtr[curChar]; + curBitsPtr = curBitsLinePtr; + curBitsLeft = 8; + + while (curCharWidthLeft) { + curBits = celGetBits(curBitsPtr, 2, curBitsLeft); + switch (curBits) { + case 0: // Transparent + break; + case 1: // regular color + *dest = 0xFFFF; + break; + case 2: // front + //*dest = 0xFFFF; //0x333; + break; + case 3: // shadow + //*dest = 0x1111; + break; + } + dest++; + + curCharWidthLeft--; + } + + curCharHeightLeft--; + curBitsLinePtr += header_bytesPerLine; + } +#endif + + push_back(imageFrame); + } + } +} + } // End of namespace Sherlock diff --git a/engines/sherlock/image_file.h b/engines/sherlock/image_file.h index ddca4b883e..f24e831440 100644 --- a/engines/sherlock/image_file.h +++ b/engines/sherlock/image_file.h @@ -94,6 +94,14 @@ public: static void setVm(SherlockEngine *vm); }; +enum ImageFile3DOType { + kImageFile3DOType_Animation = 0, + kImageFile3DOType_Cel = 1, + kImageFile3DOType_CelAnimation = 2, + kImageFile3DOType_RoomFormat = 3, + kImageFile3DOType_Font = 4 +}; + struct ImageFile3DOPixelLookupTable { uint16 pixelColor[256]; }; @@ -134,8 +142,13 @@ private: */ void loadAnimationFile(Common::SeekableReadStream &stream); + /** + * Load Sherlock Holmes 3DO font file + */ + void loadFont(Common::SeekableReadStream &stream); + public: - ImageFile3DO(const Common::String &name, bool isRoomDataFormat = false); + ImageFile3DO(const Common::String &name, ImageFile3DOType imageFile3DOType); ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData = false); ~ImageFile3DO(); static void setVm(SherlockEngine *vm); diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp index 1a3e8d2d5d..5684a94e9b 100644 --- a/engines/sherlock/people.cpp +++ b/engines/sherlock/people.cpp @@ -286,7 +286,7 @@ bool People::loadWalk() { _data[PLAYER]->_images = new ImageFile("walk.vgs"); } else { // Load walk.anim on 3DO, which is a cel animation file - _data[PLAYER]->_images = new ImageFile3DO("walk.anim"); + _data[PLAYER]->_images = new ImageFile3DO("walk.anim", kImageFile3DOType_CelAnimation); } _data[PLAYER]->setImageFrame(); _data[PLAYER]->_walkLoaded = true; diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp index 02e0f383bc..4fe3b0327c 100644 --- a/engines/sherlock/scalpel/scalpel.cpp +++ b/engines/sherlock/scalpel/scalpel.cpp @@ -531,7 +531,7 @@ bool ScalpelEngine::showOfficeCutscene() { // 3DO variant bool ScalpelEngine::show3DOSplash() { // 3DO EA Splash screen - ImageFile3DO titleImage_3DOSplash("3DOSplash.cel"); + ImageFile3DO titleImage_3DOSplash("3DOSplash.cel", kImageFile3DOType_Cel); _screen->transBlitFrom(titleImage_3DOSplash[0]._frame, Common::Point(0, -20)); bool finished = _events->delay(3000, true); @@ -576,7 +576,7 @@ bool ScalpelEngine::showCityCutscene3DO() { _screen->_backBuffer2.blitFrom(*_screen); // save into backbuffer 2, for restoring later // "London, England" - ImageFile3DO titleImage_London("title2a.cel"); + ImageFile3DO titleImage_London("title2a.cel", kImageFile3DOType_Cel); _screen->_backBuffer1.transBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50)); _screen->fadeIntoScreen3DO(1); @@ -584,7 +584,7 @@ bool ScalpelEngine::showCityCutscene3DO() { if (finished) { // "November, 1888" - ImageFile3DO titleImage_November("title2b.cel"); + ImageFile3DO titleImage_November("title2b.cel", kImageFile3DOType_Cel); _screen->_backBuffer1.transBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100)); _screen->fadeIntoScreen3DO(1); @@ -604,7 +604,7 @@ bool ScalpelEngine::showCityCutscene3DO() { _screen->_backBuffer1.blitFrom(*_screen); // save into backbuffer 1, used for fade // "Sherlock Holmes" (title) - ImageFile3DO titleImage_SherlockHolmesTitle("title1ab.cel"); + ImageFile3DO titleImage_SherlockHolmesTitle("title1ab.cel", kImageFile3DOType_Cel); _screen->_backBuffer1.transBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5)); // Blend in @@ -613,7 +613,7 @@ bool ScalpelEngine::showCityCutscene3DO() { // Title should fade in, Copyright should be displayed a bit after that if (finished) { - ImageFile3DO titleImage_Copyright("title1c.cel"); + ImageFile3DO titleImage_Copyright("title1c.cel", kImageFile3DOType_Cel); _screen->transBlitFrom(titleImage_Copyright[0]._frame, Common::Point(20, 190)); finished = _events->delay(3500, true); @@ -631,7 +631,7 @@ bool ScalpelEngine::showCityCutscene3DO() { if (finished) { // "In the alley behind the Regency Theatre..." - ImageFile3DO titleImage_InTheAlley("title1d.cel"); + ImageFile3DO titleImage_InTheAlley("title1d.cel", kImageFile3DOType_Cel); _screen->_backBuffer1.transBlitFrom(titleImage_InTheAlley[0]._frame, Common::Point(72, 51)); // Fade in @@ -667,7 +667,7 @@ bool ScalpelEngine::showAlleyCutscene3DO() { if (finished) { // Show screaming victim - ImageFile3DO titleImage_ScreamingVictim("scream.cel"); + ImageFile3DO titleImage_ScreamingVictim("scream.cel", kImageFile3DOType_Cel); _screen->clear(); _screen->transBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0)); @@ -698,7 +698,7 @@ bool ScalpelEngine::showAlleyCutscene3DO() { if (finished) { // "Early the following morning on Baker Street..." - ImageFile3DO titleImage_EarlyTheFollowingMorning("title3.cel"); + ImageFile3DO titleImage_EarlyTheFollowingMorning("title3.cel", kImageFile3DOType_Cel); _screen->_backBuffer1.transBlitFrom(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51)); // Fade in @@ -751,7 +751,7 @@ bool ScalpelEngine::showOfficeCutscene3DO() { if (finished) { // Show the note - ImageFile3DO titleImage_CoffeeNote("note.cel"); + ImageFile3DO titleImage_CoffeeNote("note.cel", kImageFile3DOType_Cel); _screen->clear(); _screen->transBlitFrom(titleImage_CoffeeNote[0]._frame, Common::Point(0, 0)); diff --git a/engines/sherlock/scalpel/scalpel_user_interface.cpp b/engines/sherlock/scalpel/scalpel_user_interface.cpp index 80a36fe9cb..739eb5d1bb 100644 --- a/engines/sherlock/scalpel/scalpel_user_interface.cpp +++ b/engines/sherlock/scalpel/scalpel_user_interface.cpp @@ -92,8 +92,8 @@ ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm _controlPanel = new ImageFile("controls.vgs"); } else { // 3DO - _controls = new ImageFile3DO("menu.all", true); - _controlPanel = new ImageFile3DO("controls.vgs", true); + _controls = new ImageFile3DO("menu.all", kImageFile3DOType_RoomFormat); + _controlPanel = new ImageFile3DO("controls.vgs", kImageFile3DOType_RoomFormat); } } else { _controls = nullptr; -- cgit v1.2.3