diff options
author | Alyssa Milburn | 2011-07-17 23:03:51 +0200 |
---|---|---|
committer | Alyssa Milburn | 2011-07-17 23:03:51 +0200 |
commit | 1608d5a2afbb288a8c3a77b5b252eea402f8ad19 (patch) | |
tree | 02e987bd9d2fbf72c02321fefca225dec439fbb0 /engines | |
parent | 85df146ad42c79644d1916a9f2660603a8294d4a (diff) | |
download | scummvm-rg350-1608d5a2afbb288a8c3a77b5b252eea402f8ad19.tar.gz scummvm-rg350-1608d5a2afbb288a8c3a77b5b252eea402f8ad19.tar.bz2 scummvm-rg350-1608d5a2afbb288a8c3a77b5b252eea402f8ad19.zip |
COMPOSER: Various additions/improvements to sprite/mouse code.
Diffstat (limited to 'engines')
-rw-r--r-- | engines/composer/composer.cpp | 359 | ||||
-rw-r--r-- | engines/composer/composer.h | 53 |
2 files changed, 356 insertions, 56 deletions
diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp index accbe7dda5..a4ec9feb97 100644 --- a/engines/composer/composer.cpp +++ b/engines/composer/composer.cpp @@ -133,6 +133,17 @@ enum { kFuncGetSpriteSize = 35029 }; +bool Sprite::contains(const Common::Point &pos) const { + Common::Point adjustedPos = pos - _pos; + + if (adjustedPos.x < 0 || adjustedPos.x >= _surface.w) + return false; + if (adjustedPos.y < 0 || adjustedPos.y >= _surface.h) + return false; + byte *pixels = (byte *)_surface.pixels; + return (pixels[(_surface.h - adjustedPos.y - 1) * _surface.w + adjustedPos.x] == 0); +} + // TODO: params: x, y, event param for done Animation::Animation(Common::SeekableReadStream *stream, uint16 id, Common::Point basePos, uint32 eventParam) : _stream(stream), _id(id), _basePos(basePos), _eventParam(eventParam) { @@ -252,6 +263,68 @@ Common::SeekableReadStream *Pipe::getResource(uint32 tag, uint16 id, bool buffer return new Common::MemoryReadStream(buffer, size, DisposeAfterUse::YES); } +Button::Button(Common::SeekableReadStream *stream, uint16 id) { + _id = id; + + _type = stream->readUint16LE(); + _active = (_type & 0x8000) ? true : false; + _type &= 0xfff; + debug(9, "button: type %d, active %d", _type, _active); + + _zorder = stream->readUint16LE(); + _scriptId = stream->readUint16LE(); + _scriptIdRollOn = stream->readUint16LE(); + _scriptIdRollOff = stream->readUint16LE(); + + stream->skip(4); + + uint16 size = stream->readUint16LE(); + + switch (_type) { + case kButtonRect: + case kButtonEllipse: + if (size != 4) + error("button %d of type %d had %d points, not 4", id, _type, size); + _rect.left = stream->readSint16LE(); + _rect.top = stream->readSint16LE(); + _rect.right = stream->readSint16LE(); + _rect.bottom = stream->readSint16LE(); + debug(9, "button: (%d, %d, %d, %d)", _rect.left, _rect.top, _rect.right, _rect.bottom); + break; + case kButtonSprites: + for (uint i = 0; i < size; i++) { + _spriteIds.push_back(stream->readSint16LE()); + } + break; + default: + error("unknown button type %d", _type); + } + + delete stream; +} + +bool Button::contains(const Common::Point &pos) const { + switch (_type) { + case kButtonRect: + return _rect.contains(pos); + case kButtonEllipse: + if (!_rect.contains(pos)) + return false; + { + int16 a = _rect.height() / 2; + int16 b = _rect.width() / 2; + if (!a || !b) + return false; + Common::Point adjustedPos = pos - Common::Point(_rect.left + a, _rect.top + b); + return ((adjustedPos.x*adjustedPos.x)/a*2 + (adjustedPos.y*adjustedPos.y)/b*2 < 1); + } + case kButtonSprites: + return false; + default: + error("internal error (button type %d)", _type); + } +} + void ComposerEngine::playAnimation(uint16 animId, int16 x, int16 y, int16 eventParam) { // First, we check if this animation is already playing, // and if it is, we sabotage that running one first. @@ -493,22 +566,58 @@ void ComposerEngine::processAnimFrame() { } } -void ComposerEngine::addSprite(uint16 id, uint16 animId, uint16 zorder, const Common::Point &pos) { - // TODO: re-use old sprite - removeSprite(id, animId); +bool ComposerEngine::spriteVisible(uint16 id, uint16 animId) { + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + if (i->_id != id) + continue; + if (i->_animId && animId && (i->_animId != animId)) + continue; + return true; + } + + return false; +} +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; - if (!initSprite(sprite)) { - warning("ignoring addSprite on invalid sprite %d", id); - return; + bool foundSprite = false; + + // re-use old sprite, if any (the BMAP for this id might well have + // changed in the meantime, but the scripts depend on that!) + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + if (i->_id != id) + continue; + if (i->_animId && animId && (i->_animId != animId)) + continue; + + // if the zordering is identical, modify it in-place + if (i->_zorder == zorder) { + i->_animId = animId; + i->_pos = pos; + return; + } + + // otherwise, take a copy and remove it from the list + sprite = *i; + foundSprite = true; + _sprites.erase(i); + break; + } + + sprite._animId = animId; + sprite._zorder = zorder; + sprite._pos = pos; + + if (!foundSprite) { + sprite._id = id; + if (!initSprite(sprite)) { + warning("ignoring addSprite on invalid sprite %d", id); + return; + } } for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { - if (sprite.zorder <= i->zorder) + if (sprite._zorder <= i->_zorder) continue; // insert *before* this sprite _sprites.insert(i, sprite); @@ -519,15 +628,49 @@ void ComposerEngine::addSprite(uint16 id, uint16 animId, uint16 zorder, const Co void ComposerEngine::removeSprite(uint16 id, uint16 animId) { for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { - if (i->id != id) + if (id && i->_id != id) continue; - if (i->animId && animId && (i->animId != animId)) + if (i->_animId && animId && (i->_animId != animId)) continue; - i->surface.free(); + i->_surface.free(); i = _sprites.reverse_erase(i); + if (id) + break; } } +const Sprite *ComposerEngine::getSpriteAtPos(const Common::Point &pos) { + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + if (i->contains(pos)) + return &(*i); + } + + return NULL; +} + +const Button *ComposerEngine::getButtonFor(const Sprite *sprite, const Common::Point &pos) { + for (Common::List<Button>::iterator i = _buttons.begin(); i != _buttons.end(); i++) { + if (!i->_active) + continue; + + if (i->_spriteIds.empty()) { + if (i->contains(pos)) + return &(*i); + continue; + } + + if (!sprite) + continue; + + for (uint j = 0; j < i->_spriteIds.size(); j++) { + if (i->_spriteIds[j] == sprite->_id) + return &(*i); + } + } + + return NULL; +} + ComposerEngine::ComposerEngine(OSystem *syst, const ComposerGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { _rnd = new Common::RandomSource("composer"); _audioStream = NULL; @@ -555,6 +698,11 @@ Common::Error ComposerEngine::run() { _queuedScripts[i]._scriptId = 0; } + _mouseVisible = true; + _mouseEnabled = false; + _mouseSpriteId = 0; + _lastButton = NULL; + _directoriesToStrip = 1; if (!_bookIni.loadFromFile("book.ini")) { _directoriesToStrip = 0; @@ -570,6 +718,7 @@ Common::Error ComposerEngine::run() { height = atoi(getStringFromConfig("Common", "Height").c_str()); initGraphics(width, height, true); _surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + _needsUpdate = true; loadLibrary(0); @@ -607,19 +756,17 @@ Common::Error ComposerEngine::run() { else lastDrawTime += frameTime; - for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { - drawSprite(*i); - } - - _system->copyRectToScreen((byte *)_surface.pixels, _surface.pitch, 0, 0, _surface.w, _surface.h); - _system->updateScreen(); + redraw(); processAnimFrame(); + } else if (_needsUpdate) { + redraw(); } while (_eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_LBUTTONDOWN: + onMouseDown(event.mouse); break; case Common::EVENT_LBUTTONUP: @@ -629,6 +776,7 @@ Common::Error ComposerEngine::run() { break; case Common::EVENT_MOUSEMOVE: + onMouseMove(event.mouse); break; case Common::EVENT_KEYDOWN: @@ -650,7 +798,7 @@ Common::Error ComposerEngine::run() { break; } - runEvent(5, event.kbd.keycode, 0, 0); + onKeyDown(event.kbd.keycode); break; case Common::EVENT_QUIT: @@ -669,6 +817,79 @@ Common::Error ComposerEngine::run() { return Common::kNoError; } +void ComposerEngine::onMouseDown(const Common::Point &pos) { + if (!_mouseEnabled || !_mouseVisible) + return; + + const Sprite *sprite = getSpriteAtPos(pos); + const Button *button = getButtonFor(sprite, pos); + if (!button) + return; + + // TODO: other buttons? + uint16 buttonsDown = 1; // MK_LBUTTON + + uint16 spriteId = sprite ? sprite->_id : 0; + runScript(button->_scriptId, button->_id, buttonsDown, spriteId); +} + +void ComposerEngine::onMouseMove(const Common::Point &pos) { + _lastMousePos = pos; + + if (!_mouseEnabled || !_mouseVisible) + return; + + // TODO: do we need to keep track of this? + uint buttonsDown = 0; + + const Sprite *sprite = getSpriteAtPos(pos); + const Button *button = getButtonFor(sprite, pos); + if (_lastButton != button) { + if (_lastButton) + runScript(_lastButton->_scriptIdRollOff, _lastButton->_id, buttonsDown, 0); + _lastButton = button; + if (_lastButton) + runScript(_lastButton->_scriptIdRollOn, _lastButton->_id, buttonsDown, 0); + } + + if (_mouseSpriteId) { + addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset); + _needsUpdate = true; + } +} + +void ComposerEngine::onKeyDown(uint16 keyCode) { + runEvent(5, keyCode, 0, 0); +} + +void ComposerEngine::setCursor(uint16 id, const Common::Point &offset) { + _mouseOffset = offset; + if (_mouseSpriteId == id) + return; + + if (_mouseSpriteId && _mouseVisible) { + removeSprite(_mouseSpriteId, 0); + } + _mouseSpriteId = id; + if (_mouseSpriteId && _mouseVisible) { + addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset); + } +} + +void ComposerEngine::setCursorVisible(bool visible) { + if (!_mouseSpriteId) + return; + + if (visible && !_mouseVisible) { + _mouseVisible = true; + addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset); + onMouseMove(_lastMousePos); + } else if (!visible && _mouseVisible) { + _mouseVisible = false; + removeSprite(_mouseSpriteId, 0); + } +} + Common::String ComposerEngine::getStringFromConfig(const Common::String §ion, const Common::String &key) { Common::String value; if (!_bookIni.getKey(key, section, value)) @@ -722,6 +943,14 @@ void ComposerEngine::loadLibrary(uint id) { Common::hexdump(buf, stream->size()); delete stream;*/ + Common::Array<uint16> buttonResources = library._archive->getResourceIDList(ID_BUTN); + for (uint i = 0; i < buttonResources.size(); i++) { + uint16 buttonId = buttonResources[i]; + Common::SeekableReadStream *stream = library._archive->getResource(ID_BUTN, buttonId); + Button button(stream, buttonId); + _buttons.push_back(button); + } + // add background sprite, if it exists if (hasResource(ID_BMAP, 1000)) addSprite(1000, 0, 0xffff, Common::Point()); @@ -732,6 +961,9 @@ void ComposerEngine::loadLibrary(uint id) { // Run the startup script. runScript(1000, 0, 0, 0); + _mouseEnabled = true; + onMouseMove(_lastMousePos); + runEvent(3, id, 0, 0); } @@ -750,9 +982,12 @@ void ComposerEngine::unloadLibrary(uint id) { _pipes.clear(); for (Common::List<Sprite>::iterator j = _sprites.begin(); j != _sprites.end(); j++) { - j->surface.free(); + j->_surface.free(); } _sprites.clear(); + _buttons.clear(); + + _lastButton = NULL; _mixer->stopAll(); _audioStream = NULL; @@ -1218,28 +1453,40 @@ int16 ComposerEngine::scriptFuncCall(uint16 id, int16 param1, int16 param2, int1 _queuedScripts[param1]._scriptId = 0; return 0; case kFuncSetCursor: - warning("ignoring kSetCursor(%d, %d, %d)", param1, param2, param3); - // TODO: return old cursor - return 0; + debug(3, "kSetCursor(%d, (%d, %d))", param1, param2, param3); + { + uint16 oldCursor = _mouseSpriteId; + setCursor(param1, Common::Point(param2, param3)); + return oldCursor; + } case kFuncGetCursor: - warning("ignoring kFuncGetCursor()"); - // TODO: return cursor - return 0; + debug(3, "kFuncGetCursor()"); + return _mouseSpriteId; case kFuncShowCursor: - // TODO - warning("ignoring kFuncShowCursor(%d)", param1); + debug(3, "kFuncShowCursor()"); + setCursorVisible(true); return 0; case kFuncHideCursor: - // TODO - warning("ignoring kFuncHideCursor(%d)", param1); + debug(3, "kFuncHideCursor()"); + setCursorVisible(false); return 0; case kFuncActivateButton: - // TODO - warning("ignoring kFuncActivateButton(%d)", param1); + debug(3, "kFuncActivateButton(%d)", param1); + for (Common::List<Button>::iterator i = _buttons.begin(); i != _buttons.end(); i++) { + if (i->_id != param1) + continue; + i->_active = true; + } + onMouseMove(_lastMousePos); return 1; case kFuncDeactivateButton: - // TODO - warning("ignoring kFuncDeactivateButton(%d)", param1); + debug(3, "kFuncDeactivateButton(%d)", param1); + for (Common::List<Button>::iterator i = _buttons.begin(); i != _buttons.end(); i++) { + if (i->_id != param1) + continue; + i->_active = false; + } + onMouseMove(_lastMousePos); return 1; case kFuncNewPage: debug(3, "kFuncNewPage(%d, %d)", param1, param2); @@ -1321,6 +1568,16 @@ int16 ComposerEngine::scriptFuncCall(uint16 id, int16 param1, int16 param2, int1 } } +void ComposerEngine::redraw() { + for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++) { + drawSprite(*i); + } + + _system->copyRectToScreen((byte *)_surface.pixels, _surface.pitch, 0, 0, _surface.w, _surface.h); + _system->updateScreen(); + _needsUpdate = false; +} + void ComposerEngine::loadCTBL(uint id, uint fadePercent) { Common::SeekableReadStream *stream = getResource(ID_CTBL, id); @@ -1497,14 +1754,14 @@ void ComposerEngine::decompressBitmap(uint16 type, Common::SeekableReadStream *s bool ComposerEngine::initSprite(Sprite &sprite) { Common::SeekableReadStream *stream = NULL; - if (hasResource(ID_BMAP, sprite.id)) - stream = getResource(ID_BMAP, sprite.id); + if (hasResource(ID_BMAP, sprite._id)) + stream = getResource(ID_BMAP, sprite._id); else for (Common::List<Pipe *>::iterator k = _pipes.begin(); k != _pipes.end(); k++) { Pipe *pipe = *k; - if (!pipe->hasResource(ID_BMAP, sprite.id)) + if (!pipe->hasResource(ID_BMAP, sprite._id)) continue; - stream = pipe->getResource(ID_BMAP, sprite.id, false); + stream = pipe->getResource(ID_BMAP, sprite._id, false); break; } @@ -1512,14 +1769,16 @@ bool ComposerEngine::initSprite(Sprite &sprite) { return false; uint16 type = stream->readUint16LE(); - uint16 height = stream->readUint16LE(); - uint16 width = stream->readUint16LE(); + int16 height = stream->readSint16LE(); + int16 width = stream->readSint16LE(); uint32 size = stream->readUint32LE(); debug(1, "loading BMAP: type %d, width %d, height %d, size %d", type, width, height, size); - if (width && height) { - sprite.surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - decompressBitmap(type, stream, (byte *)sprite.surface.pixels, size, width, height); + if (width > 0 && height > 0) { + sprite._surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + decompressBitmap(type, stream, (byte *)sprite._surface.pixels, size, width, height); + } else { + warning("ignoring sprite with size %dx%d", width, height); } delete stream; @@ -1527,15 +1786,15 @@ bool ComposerEngine::initSprite(Sprite &sprite) { } void ComposerEngine::drawSprite(const Sprite &sprite) { - int x = sprite.pos.x; - int y = sprite.pos.y; + int x = sprite._pos.x; + int y = sprite._pos.y; // incoming data is BMP-style (bottom-up), so flip it byte *pixels = (byte *)_surface.pixels; - for (uint j = 0; j < sprite.surface.h; j++) { - byte *in = (byte *)sprite.surface.pixels + (sprite.surface.h - j - 1) * sprite.surface.w; + for (int j = 0; j < sprite._surface.h; j++) { + byte *in = (byte *)sprite._surface.pixels + (sprite._surface.h - j - 1) * sprite._surface.w; byte *out = pixels + ((j + y) * _surface.w) + x; - for (uint i = 0; i < sprite.surface.w; i++) + for (uint i = 0; i < sprite._surface.w; i++) if (in[i]) out[i] = in[i]; } diff --git a/engines/composer/composer.h b/engines/composer/composer.h index 8f22174592..4c87a6e6df 100644 --- a/engines/composer/composer.h +++ b/engines/composer/composer.h @@ -60,11 +60,13 @@ class Archive; class ComposerEngine; struct Sprite { - uint16 id; - uint16 animId; - uint16 zorder; - Common::Point pos; - Graphics::Surface surface; + uint16 _id; + uint16 _animId; + uint16 _zorder; + Common::Point _pos; + Graphics::Surface _surface; + + bool contains(const Common::Point &pos) const; }; struct AnimationEntry { @@ -122,9 +124,29 @@ protected: uint32 _offset; }; +enum { + kButtonRect = 0, + kButtonEllipse = 1, + kButtonSprites = 4 +}; + class Button { public: - Button(ComposerEngine *vm, uint16 id); + Button() { } + Button(Common::SeekableReadStream *stream, uint16 id); + + bool contains(const Common::Point &pos) const; + + uint16 _id; + uint16 _type; + uint16 _zorder; + uint16 _scriptId; + uint16 _scriptIdRollOn; + uint16 _scriptIdRollOff; + bool _active; + + Common::Rect _rect; + Common::Array<uint16> _spriteIds; }; struct Library { @@ -170,7 +192,9 @@ private: Audio::SoundHandle _soundHandle; Audio::QueuingAudioStream *_audioStream; + bool _needsUpdate; Graphics::Surface _surface; + Common::List<Button> _buttons; Common::List<Sprite> _sprites; uint _directoriesToStrip; @@ -185,6 +209,19 @@ private: Common::List<Animation *> _anims; Common::List<Pipe *> _pipes; + void onMouseDown(const Common::Point &pos); + void onMouseMove(const Common::Point &pos); + void onKeyDown(uint16 keyCode); + void setCursor(uint16 id, const Common::Point &offset); + void setCursorVisible(bool visible); + + bool _mouseEnabled; + bool _mouseVisible; + Common::Point _lastMousePos; + const Button *_lastButton; + uint16 _mouseSpriteId; + Common::Point _mouseOffset; + Common::String getStringFromConfig(const Common::String §ion, const Common::String &key); Common::String getFilename(const Common::String §ion, uint id); void loadLibrary(uint id); @@ -206,9 +243,13 @@ private: void playWaveForAnim(uint16 id, bool bufferingOnly); void processAnimFrame(); + bool spriteVisible(uint16 id, uint16 animId); void addSprite(uint16 id, uint16 animId, uint16 zorder, const Common::Point &pos); void removeSprite(uint16 id, uint16 animId); + const Sprite *getSpriteAtPos(const Common::Point &pos); + const Button *getButtonFor(const Sprite *sprite, const Common::Point &pos); + void redraw(); void loadCTBL(uint id, uint fadePercent); void decompressBitmap(uint16 type, Common::SeekableReadStream *stream, byte *buffer, uint32 size, uint width, uint height); bool initSprite(Sprite &sprite); |