diff options
author | Lars Skovlund | 2011-01-21 18:53:35 +0000 |
---|---|---|
committer | Lars Skovlund | 2011-01-21 18:53:35 +0000 |
commit | 0e33dd91645bb26c51731cc79b2f142b3883047c (patch) | |
tree | fdb5609aaf095594a8a92660115c2369e51494d4 | |
parent | e55ac4f419db480b1ce87087d7f063aa5297099f (diff) | |
download | scummvm-rg350-0e33dd91645bb26c51731cc79b2f142b3883047c.tar.gz scummvm-rg350-0e33dd91645bb26c51731cc79b2f142b3883047c.tar.bz2 scummvm-rg350-0e33dd91645bb26c51731cc79b2f142b3883047c.zip |
SCI: Partial robot support, currently disabled since it does not run
asynchronously as it should.
svn-id: r55382
-rw-r--r-- | engines/sci/engine/kgraphics.cpp | 4 | ||||
-rw-r--r-- | engines/sci/engine/kmisc.cpp | 4 | ||||
-rw-r--r-- | engines/sci/graphics/paint32.cpp | 4 | ||||
-rw-r--r-- | engines/sci/graphics/robot.cpp | 256 | ||||
-rw-r--r-- | engines/sci/graphics/robot.h | 14 |
5 files changed, 197 insertions, 85 deletions
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 184b56317f..855c6a25c0 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -1407,8 +1407,8 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { int16 x = argv[4].toUint16(); int16 y = argv[5].toUint16(); warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y); - GfxRobot *test = new GfxRobot(g_sci->getResMan(), g_sci->_gfxScreen, id); - test->draw(); + GfxRobot *test = new GfxRobot(g_sci->getResMan(), g_sci->_gfxScreen, g_sci->_gfxPalette, id); + test->draw(x,y); delete test; } diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 60a2fea481..d4ca3286e2 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -32,6 +32,7 @@ #include "sci/engine/kernel.h" #include "sci/engine/gc.h" #include "sci/graphics/maciconbar.h" +#include "sci/console.h" namespace Sci { @@ -177,8 +178,7 @@ reg_t kFlushResources(EngineState *s, int argc, reg_t *argv) { reg_t kSetDebug(EngineState *s, int argc, reg_t *argv) { debug("Debug mode activated"); - g_sci->_debugState.seeking = kDebugSeekNothing; - g_sci->_debugState.runningStep = 0; + g_sci->getDebugger()->attach(); return s->r_acc; } diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp index 9b24da413b..a2cf1c73ad 100644 --- a/engines/sci/graphics/paint32.cpp +++ b/engines/sci/graphics/paint32.cpp @@ -81,8 +81,8 @@ void GfxPaint32::kernelGraphDrawLine(Common::Point startPoint, Common::Point end } void GfxPaint32::debugDrawRobot(GuiResourceId robotId) { - GfxRobot *test = new GfxRobot(g_sci->getResMan(), _screen, robotId); - test->draw(); + GfxRobot *test = new GfxRobot(g_sci->getResMan(), _screen, _palette, robotId); + test->draw(0,0); delete test; } diff --git a/engines/sci/graphics/robot.cpp b/engines/sci/graphics/robot.cpp index 9e2d68e4ed..6ee2e53a88 100644 --- a/engines/sci/graphics/robot.cpp +++ b/engines/sci/graphics/robot.cpp @@ -27,6 +27,7 @@ #include "sci/engine/state.h" #include "sci/graphics/screen.h" #include "sci/graphics/robot.h" +#include "sci/graphics/palette.h" #include "sci/sound/audio.h" #include "graphics/surface.h" @@ -36,6 +37,7 @@ #include "common/file.h" #include "common/system.h" +#include "common/memstream.h" namespace Sci { @@ -55,45 +57,59 @@ namespace Sci { // around the screen and go behind other objects. (...) #ifdef ENABLE_SCI32 -GfxRobot::GfxRobot(ResourceManager *resMan, GfxScreen *screen, GuiResourceId resourceId) - : _resMan(resMan), _screen(screen), _resourceId(resourceId) { +GfxRobot::GfxRobot(ResourceManager *resMan, GfxScreen *screen, GfxPalette *palette, GuiResourceId resourceId) + : _resMan(resMan), _screen(screen), _palette(palette), _resourceId(resourceId) { assert(resourceId != -1); initData(resourceId); } GfxRobot::~GfxRobot() { delete[] _resourceData; + delete[] _imageStart; + delete[] _audioStart; + delete[] _audioLen; } void GfxRobot::initData(GuiResourceId resourceId) { char fileName[10]; + uint32 fileSize; + sprintf(fileName, "%d.rbt", resourceId); Common::File robotFile; if (robotFile.open(fileName)) { _resourceData = new byte[robotFile.size()]; robotFile.read(_resourceData, robotFile.size()); + fileSize = robotFile.size(); robotFile.close(); } else { warning("Unable to open robot file %s", fileName); return; } - // The RBT video starts with a SOL audio file, followed by - // video data which is appended after it - _frameCount = READ_LE_UINT16(_resourceData + 14); - // For some weird reason, the audio size seems to ALWAYS - // be 0xB000, padded with 0x20 and 0x00 at the end - _audioSize = READ_LE_UINT16(_resourceData + 15); + + // There is another value in the header, at offset 0x12, which + // equals this value plus 14 (audio header size) in the cases + // I've seen so far. Dunno which one to use, really. + _audioSize = READ_LE_UINT16(_resourceData + 60); //_frameSize = READ_LE_UINT32(_resourceData + 34); _hasSound = (_resourceData[25] != 0); + _palOffset = 60; + if (_hasSound) + _palOffset += READ_LE_UINT32(_resourceData + 60) + 14; + + getFrameOffsets(); + assert(_imageStart[_frameCount] == fileSize); + debug("Robot %d, %d frames, sound: %s\n", resourceId, _frameCount, _hasSound ? "yes" : "no"); } -void GfxRobot::draw() { +void GfxRobot::draw(int x, int y) { + + return; /* TODO: Remove once done */ // Play the audio of the robot file (for debugging) #if 0 if (_hasSound) { @@ -103,83 +119,169 @@ void GfxRobot::draw() { } #endif - return; // TODO: Remove once done + byte *paletteData = _hasSound ? + _resourceData + 60 + 14 + _audioSize : + _resourceData + 60; + uint16 paletteSize = READ_LE_UINT16(_resourceData + 16); - byte *frameData = _resourceData + _audioSize; - uint16 frameWidth, frameHeight; - uint16 maskBlockSize, frameBlockSize; + Palette resourcePal; - // TODO: Palette! Where is it? -#if 0 - byte dummyPal[256 * 4]; - for (int i = 0; i < 256; i++) { - dummyPal[i * 4 + 0] = i; - dummyPal[i * 4 + 1] = i; - dummyPal[i * 4 + 2] = i; - dummyPal[i * 4 + 3] = 0; + byte robotPal[256 * 4]; + byte savePal[256 * 4]; + int startIndex = READ_LE_UINT16(paletteData + 25); + int colorCount = READ_LE_UINT16(paletteData + 29); + + warning("%d palette entries starting at %d", colorCount, startIndex); + + _palette->createFromData(paletteData, paletteSize, &resourcePal); + + for (int i = 0; i < 256; ++i) + { + savePal[i*4] = _palette->_sysPalette.colors[i].r; + savePal[i*4+1] = _palette->_sysPalette.colors[i].g; + savePal[i*4+2] = _palette->_sysPalette.colors[i].b; + savePal[i*4+3] = 0; } - memset(dummyPal, 255, 256 * 4); - g_system->setPalette(dummyPal, 0, 256); -#endif + + memcpy(robotPal, savePal, sizeof(savePal)); - // Both the frame and the mask data are uncompressed - // TODO: How are the rectangle dimensions calculated from the block sizes? - - Graphics::Surface *screen; - for (uint16 frame = 0; frame < _frameCount; frame++) { - // Read 20 byte header - // First 4 bytes are always 01 00 7f 64 - assert(*(frameData + 0) == 0x01); - assert(*(frameData + 1) == 0x00); - assert(*(frameData + 2) == 0x7f); - assert(*(frameData + 3) == 0x64); - frameWidth = READ_LE_UINT16(frameData + 4); - frameHeight = READ_LE_UINT16(frameData + 6); - // 4 bytes, always 0 - assert(*(frameData + 8) == 0x00); - assert(*(frameData + 9) == 0x00); - assert(*(frameData + 10) == 0x00); - assert(*(frameData + 11) == 0x00); - // 2 bytes: a small number (x, perhaps? But it doesn't match with the movie dimensions shown by SV...) - // 2 bytes: a small number (y, perhaps? But it doesn't match with the movie dimensions shown by SV...) - // 2 bytes: a small number, 1 or 2 (type, perhaps?) - maskBlockSize = READ_LE_UINT16(frameData + 16); - assert(*(frameData + 18) == 0x01 || *(frameData + 18) == 0x02); - assert(*(frameData + 20) == 0x00); - frameData += 20; - - // Process mask(?) data - // FIXME: This isn't correct, we need to use copyRectToScreen() instead - // (but we need to figure out the rectangle dimensions, see TODO above) - screen = g_system->lockScreen(); - memcpy(frameData, screen->pixels, maskBlockSize); - g_system->unlockScreen(); - g_system->updateScreen(); - // Sleep for a second - g_sci->sleep(1000); - warning("Mask %d", frame); - - frameData += maskBlockSize; - - // Read 12 byte frame data header - frameBlockSize = READ_LE_UINT16(frameData + 8); - frameData += 12; - - // Process frame(?) data - // FIXME: This isn't correct, we need to use copyRectToScreen() instead - // (but we need to figure out the rectangle dimensions, see TODO above) - screen = g_system->lockScreen(); - memcpy(frameData, screen->pixels, frameBlockSize); - g_system->unlockScreen(); + for (int i = 0; i < colorCount; ++i) + { + int index = i + startIndex; + robotPal[index*4] = resourcePal.colors[i].r; + robotPal[index*4+1] = resourcePal.colors[i].g; + robotPal[index*4+2] = resourcePal.colors[i].b; + robotPal[index*4+3] = 0; + } + + g_system->setPalette(robotPal, 0, 256); + + for (int i = 0; i < _frameCount; ++i) { + int width, height; + + byte *pixels = assembleVideoFrame(i); + getFrameDimensions(i, width, height); + g_system->copyRectToScreen(pixels, width, x, y, width, (int) (height * getFrameScaleFactor(i))); g_system->updateScreen(); - // Sleep for a second - g_sci->sleep(1000); - warning("Frame %d", frame); + g_system->delayMillis(100); + } + + g_system->setPalette(savePal, 0, 256); +} + +void GfxRobot::getFrameOffsets() { + int *audioEnd = new int[_frameCount]; + int *videoEnd = new int[_frameCount]; - frameData += frameBlockSize; + for (int i = 0; i < _frameCount; ++i) { + videoEnd[i] = READ_LE_UINT16(_resourceData + _palOffset + 1200 + i * 2); + audioEnd[i] = READ_LE_UINT16(_resourceData + _palOffset + 1200 + _frameCount * 2 + i * 2); } + int frameDataOffset = _palOffset + 0x4b0 + 0x400 + 0x200 + _frameCount * 4; + + // Pad to nearest 2 kilobytes + if (frameDataOffset & 0x7ff) + frameDataOffset = (frameDataOffset & ~0x7ff)+0x800; + + _imageStart = new uint32[_frameCount+1]; + _audioStart = new uint32[_frameCount]; + _audioLen = new uint32[_frameCount]; + + _imageStart[0] = frameDataOffset; + + // Plus one so we can assert on this in the calling routine + // The last one should point to end-of-file, unless I'm misunderstanding something + for (int i = 1; i < _frameCount + 1; ++i) + _imageStart[i] = _imageStart[i-1] + audioEnd[i-1]; + for (int i = 0; i < _frameCount; ++i) + _audioStart[i] = _imageStart[i] + videoEnd[i-1]; + for (int i = 0; i < _frameCount; ++i) + _audioLen[i] = _imageStart[i+1] - _audioStart[i]; + + delete[] audioEnd; + delete[] videoEnd; +} + +byte *GfxRobot::assembleVideoFrame(int frame) { + byte *videoData = _resourceData + _imageStart[frame]; + int frameWidth = READ_LE_UINT16(videoData + 4); + int frameHeight = READ_LE_UINT16(videoData + 6); + int frameFragments = READ_LE_UINT16(videoData + 18); + + int decompressedSize = 0; + + DecompressorLZS lzs; + + videoData = _resourceData + _imageStart[frame] + 24; + + for (int i = 0; i < frameFragments; ++i) { + int fragmentCompressed = READ_LE_UINT32(videoData); + int fragmentUncompressed = READ_LE_UINT32(videoData + 4); + + decompressedSize += fragmentUncompressed; + videoData += 10 + fragmentCompressed; + } + + assert(decompressedSize == (frameWidth * frameHeight) * getFrameScaleFactor(frame)); + + byte *output = new byte[decompressedSize]; + int assemblePtr = 0; + + videoData = _resourceData + _imageStart[frame] + 24; + + for (int i = 0; i < frameFragments; ++i) { + int fragmentCompressed = READ_LE_UINT32(videoData); + int fragmentUncompressed = READ_LE_UINT32(videoData + 4); + uint16 compressionType = READ_LE_UINT16(videoData + 8); + + switch (compressionType) { + case 0: { + Common::MemoryReadStream compressedFrame(videoData + 10, fragmentCompressed, DisposeAfterUse::NO); + + lzs.unpack(&compressedFrame, output + assemblePtr, fragmentCompressed, fragmentUncompressed); + assemblePtr += fragmentUncompressed; + break; + } + case 2: // Untested + memcpy(output + assemblePtr, videoData + 10, fragmentCompressed); + assemblePtr += fragmentUncompressed; + break; + } + + videoData += 10 + fragmentCompressed; + } + + assert(assemblePtr == decompressedSize); + + return output; +} + +void GfxRobot::getFrameDimensions(int frame, int &width, int &height) { + byte *videoData = _resourceData + _imageStart[frame]; + + width = READ_LE_UINT16(videoData + 4); + height = READ_LE_UINT16(videoData + 6); +} + +void GfxRobot::getFrameRect(int frame, Common::Rect &rect) { + byte *videoData = _resourceData + _imageStart[frame]; + + int x = READ_LE_UINT16(videoData + 8); + int y = READ_LE_UINT16(videoData + 10); + int w = READ_LE_UINT16(videoData + 12); + int h = READ_LE_UINT16(videoData + 14); + + rect = Common::Rect(x, y, x + w, y + h); +} + +float GfxRobot::getFrameScaleFactor(int frame) { + byte *videoData = _resourceData + _imageStart[frame]; + byte percentage = videoData[3]; + + return (float) percentage/100.0; } + #endif } // End of namespace Sci diff --git a/engines/sci/graphics/robot.h b/engines/sci/graphics/robot.h index 8c7937bb39..c1c57a4596 100644 --- a/engines/sci/graphics/robot.h +++ b/engines/sci/graphics/robot.h @@ -33,16 +33,22 @@ namespace Sci { #ifdef ENABLE_SCI32 class GfxRobot { public: - GfxRobot(ResourceManager *resMan, GfxScreen *screen, GuiResourceId resourceId); + GfxRobot(ResourceManager *resMan, GfxScreen *screen, GfxPalette *palette, GuiResourceId resourceId); ~GfxRobot(); - void draw(); + void draw(int x, int y); private: void initData(GuiResourceId resourceId); + void getFrameOffsets(); + byte *assembleVideoFrame(int frame); + void getFrameDimensions(int frame, int &width, int &height); + void getFrameRect(int frame, Common::Rect &rect); // Not sure what to use this for yet + float getFrameScaleFactor(int frame); // Scale factor?? More like custom height, but why use a percentage for it? ResourceManager *_resMan; GfxScreen *_screen; + GfxPalette *_palette; GuiResourceId _resourceId; byte *_resourceData; @@ -53,6 +59,10 @@ private: uint32 _frameSize; // is width * height (pixelCount) uint16 _audioSize; bool _hasSound; + uint32 _palOffset; + uint32 *_imageStart; + uint32 *_audioStart; + uint32 *_audioLen; }; #endif |