aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Skovlund2011-01-21 18:53:35 +0000
committerLars Skovlund2011-01-21 18:53:35 +0000
commit0e33dd91645bb26c51731cc79b2f142b3883047c (patch)
treefdb5609aaf095594a8a92660115c2369e51494d4
parente55ac4f419db480b1ce87087d7f063aa5297099f (diff)
downloadscummvm-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.cpp4
-rw-r--r--engines/sci/engine/kmisc.cpp4
-rw-r--r--engines/sci/graphics/paint32.cpp4
-rw-r--r--engines/sci/graphics/robot.cpp256
-rw-r--r--engines/sci/graphics/robot.h14
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