aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/composer/composer.cpp181
-rw-r--r--engines/composer/composer.h13
2 files changed, 177 insertions, 17 deletions
diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp
index b2dcc3b36c..3651a49328 100644
--- a/engines/composer/composer.cpp
+++ b/engines/composer/composer.cpp
@@ -212,7 +212,7 @@ Common::SeekableReadStream *Pipe::getResource(uint32 tag, uint16 id, bool buffer
for (uint i = 0; i < res.entries.size(); i++)
size += res.entries[i].size;
- byte *buffer = new byte[size];
+ byte *buffer = (byte *)malloc(size);
uint32 offset = 0;
for (uint i = 0; i < res.entries.size(); i++) {
_stream->seek(res.entries[i].offset, SEEK_SET);
@@ -397,15 +397,19 @@ void ComposerEngine::processAnimFrame() {
break;
case 4:
if (entry.word10 && (!data || data != entry.word10)) {
- // TODO: erase old sprite
- warning("ignoring anim sprite erase (%d)", entry.word10);
+ debug(4, "anim: erase sprite %d", entry.word10);
+ removeSprite(data, anim->_id);
}
if (data) {
uint16 x = anim->_stream->readUint16LE();
uint16 y = anim->_stream->readUint16LE();
+ Common::Point pos(x, y);
anim->_offset += 4;
- // TODO: sprite change
- warning("ignoring anim sprite draw (%d @ %d,%d)", data, x, y);
+ uint16 animId = anim->_id;
+ if (anim->_state == entry.dword0)
+ animId = 0;
+ debug(4, "anim: draw sprite %d at (relative) %d,%d", data, x, y);
+ addSprite(data, animId, entry.word6, anim->_basePos + pos);
}
break;
default:
@@ -424,6 +428,33 @@ void ComposerEngine::processAnimFrame() {
}
}
+void ComposerEngine::addSprite(uint16 id, uint16 animId, uint16 zorder, const Common::Point &pos) {
+ Sprite sprite;
+ sprite.id = id;
+ sprite.animId = animId;
+ sprite.zorder = zorder;
+ sprite.pos = pos;
+
+ for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) {
+ if (sprite.zorder < i->zorder)
+ continue;
+ _sprites.insert(i, sprite);
+ return;
+ }
+ _sprites.push_back(sprite);
+}
+
+void ComposerEngine::removeSprite(uint16 id, uint16 animId) {
+ for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) {
+ if (i->id != id)
+ continue;
+ if (animId && i->animId != animId)
+ continue;
+ i = _sprites.reverse_erase(i);
+ return;
+ }
+}
+
ComposerEngine::ComposerEngine(OSystem *syst, const ComposerGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
_rnd = new Common::RandomSource("composer");
_audioStream = NULL;
@@ -471,12 +502,6 @@ Common::Error ComposerEngine::run() {
uint frameTime = 1000 / fps;
uint32 lastDrawTime = 0;
while (!shouldQuit()) {
- if (hasResource(ID_BMAP, 1000))
- drawBMAP(1000, 0, 0);
-
- _system->copyRectToScreen((byte *)_surface.pixels, _surface.pitch, 0, 0, _surface.w, _surface.h);
- _system->updateScreen();
-
uint32 thisTime = _system->getMillis();
for (uint i = 0; i < _queuedScripts.size(); i++) {
QueuedScript &script = _queuedScripts[i];
@@ -494,6 +519,15 @@ Common::Error ComposerEngine::run() {
if (lastDrawTime + frameTime <= thisTime) {
lastDrawTime += frameTime;
+ if (hasResource(ID_BMAP, 1000))
+ drawBMAP(1000, 0, 0);
+ for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) {
+ drawBMAP(i->id, i->pos.x, i->pos.y);
+ }
+
+ _system->copyRectToScreen((byte *)_surface.pixels, _surface.pitch, 0, 0, _surface.w, _surface.h);
+ _system->updateScreen();
+
processAnimFrame();
}
@@ -853,19 +887,130 @@ void ComposerEngine::loadCTBL(uint id, uint fadePercent) {
_system->getPaletteManager()->setPalette(buffer, 0, numEntries);
}
-void ComposerEngine::decompressBitmap(uint16 type, Common::SeekableReadStream *stream, byte *buffer, uint32 size) {
+static void decompressSLWM(byte *buffer, Common::SeekableReadStream *stream) {
+ uint bitsLeft = 0;
+ uint16 lastBits;
+ byte currBit;
+ while (true) {
+ if (bitsLeft == 0) { bitsLeft = 16; lastBits = stream->readUint16LE(); }
+ currBit = (lastBits & 1); lastBits >>= 1; bitsLeft--;
+
+ if (currBit) {
+ // single byte
+ *buffer++ = stream->readByte();
+ continue;
+ }
+
+ if (bitsLeft == 0) { bitsLeft = 16; lastBits = stream->readUint16LE(); }
+ currBit = (lastBits & 1); lastBits >>= 1; bitsLeft--;
+
+ uint start;
+ uint count;
+ if (currBit) {
+ uint orMask = stream->readByte();
+ uint in = stream->readByte();
+ count = in & 7;
+ start = ((in & ~7) << 5) | orMask;
+ if (!count) {
+ count = stream->readByte();
+ if (!count)
+ break;
+ count -= 2;
+ }
+ } else {
+ // count encoded in the next two bits
+ count = 0;
+
+ if (bitsLeft == 0) { bitsLeft = 16; lastBits = stream->readUint16LE(); }
+ currBit = (lastBits & 1); lastBits >>= 1; bitsLeft--;
+
+ count = (count << 1) | currBit;
+
+ if (bitsLeft == 0) { bitsLeft = 16; lastBits = stream->readUint16LE(); }
+ currBit = (lastBits & 1); lastBits >>= 1; bitsLeft--;
+
+ count = (count << 1) | currBit;
+
+ start = stream->readByte();
+ }
+
+ count += 2;
+ start++;
+ memcpy(buffer, buffer - start, count);
+ buffer += count;
+ }
+}
+
+void ComposerEngine::decompressBitmap(uint16 type, Common::SeekableReadStream *stream, byte *buffer, uint32 size, uint width, uint height) {
switch (type) {
case kBitmapUncompressed:
assert(stream->size() - (uint)stream->pos() == size);
+ assert(size == width * height);
stream->read(buffer, size);
break;
+ case kBitmapRLESLWM:
+ {
+ uint32 bufSize = stream->readUint32LE();
+ byte *tempBuf = new byte[bufSize];
+ decompressSLWM(tempBuf, stream);
+
+ uint instrPos = tempBuf[0] + 1;
+ instrPos += READ_LE_UINT16(tempBuf + instrPos) + 2;
+ byte *instr = tempBuf + instrPos;
+
+ uint line = 0;
+ while (line++ < height) {
+ uint pixels = 0;
+
+ while (pixels < width) {
+ byte data = *instr++;
+ byte color = tempBuf[(data & 0x7F) + 1];
+ if (!(data & 0x80)) {
+ *buffer++ = color;
+ pixels++;
+ } else {
+ byte count = *instr++;
+ if (!count) {
+ while (pixels++ < width)
+ *buffer++ = color;
+ break;
+ }
+ for (uint i = 0; i < count; i++) {
+ *buffer++ = color;
+ pixels++;
+ }
+ }
+ }
+ }
+ delete[] tempBuf;
+ }
+ break;
+ case kBitmapSLWM:
+ decompressSLWM(buffer, stream);
+ break;
default:
error("decompressBitmap can't handle type %d", type);
}
}
void ComposerEngine::drawBMAP(uint id, uint x, uint y) {
- Common::SeekableReadStream *stream = getResource(ID_BMAP, id);
+ Common::SeekableReadStream *stream = NULL;
+ if (hasResource(ID_BMAP, id))
+ stream = getResource(ID_BMAP, id);
+ else
+ for (Common::List<Pipe *>::iterator k = _pipes.begin(); k != _pipes.end(); k++) {
+ Pipe *pipe = *k;
+ if (!pipe->hasResource(ID_BMAP, id))
+ continue;
+ stream = pipe->getResource(ID_BMAP, id, true);
+ break;
+ }
+
+ if (!stream) {
+ // FIXME
+ warning("couldn't find BMAP %d", id);
+ return;
+ }
uint16 type = stream->readUint16LE();
uint16 height = stream->readUint16LE();
@@ -874,12 +1019,18 @@ void ComposerEngine::drawBMAP(uint id, uint x, uint y) {
debug(1, "BMAP: type %d, width %d, height %d, size %d", type, width, height, size);
byte *buffer = new byte[width * height];
- decompressBitmap(type, stream, buffer, size);
+ decompressBitmap(type, stream, buffer, size, width, height);
+
+ debug(1, "draw at %d,%d", x, y);
// incoming data is BMP-style (bottom-up), so flip it
byte *pixels = (byte *)_surface.pixels;
for (uint j = 0; j < height; j++) {
- memcpy(pixels + (j * width), buffer + (height - j - 1) * width, width);
+ byte *in = buffer + (height - j - 1) * width;
+ byte *out = pixels + ((j + y) * _surface.w) + x;
+ for (uint i = 0; i < width; i++)
+ if (in[i])
+ out[i] = in[i];
}
delete[] buffer;
diff --git a/engines/composer/composer.h b/engines/composer/composer.h
index 5d4233a1ba..e535bfbc6e 100644
--- a/engines/composer/composer.h
+++ b/engines/composer/composer.h
@@ -59,7 +59,11 @@ enum GameType {
class Archive;
class ComposerEngine;
-class Sprite {
+struct Sprite {
+ uint16 id;
+ uint16 animId;
+ uint16 zorder;
+ Common::Point pos;
};
struct AnimationEntry {
@@ -158,6 +162,8 @@ private:
Audio::QueuingAudioStream *_audioStream;
Graphics::Surface _surface;
+ Common::List<Sprite> _sprites;
+
Common::ConfigFile _bookIni;
Common::List<Library> _libraries;
@@ -187,8 +193,11 @@ private:
void playWaveForAnim(uint16 id, bool bufferingOnly);
void processAnimFrame();
+ void addSprite(uint16 id, uint16 animId, uint16 zorder, const Common::Point &pos);
+ void removeSprite(uint16 id, uint16 animId);
+
void loadCTBL(uint id, uint fadePercent);
- void decompressBitmap(uint16 type, Common::SeekableReadStream *stream, byte *buffer, uint32 size);
+ void decompressBitmap(uint16 type, Common::SeekableReadStream *stream, byte *buffer, uint32 size, uint width, uint height);
void drawBMAP(uint id, uint x, uint y);
};