diff options
-rw-r--r-- | engines/mads/assets.cpp | 9 | ||||
-rw-r--r-- | engines/mads/assets.h | 9 | ||||
-rw-r--r-- | engines/mads/dialogs.cpp | 30 | ||||
-rw-r--r-- | engines/mads/events.cpp | 2 | ||||
-rw-r--r-- | engines/mads/events.h | 2 | ||||
-rw-r--r-- | engines/mads/mads.cpp | 10 | ||||
-rw-r--r-- | engines/mads/mads.h | 2 | ||||
-rw-r--r-- | engines/mads/messages.cpp | 49 | ||||
-rw-r--r-- | engines/mads/messages.h | 10 | ||||
-rw-r--r-- | engines/mads/module.mk | 2 | ||||
-rw-r--r-- | engines/mads/msprite.cpp | 107 | ||||
-rw-r--r-- | engines/mads/msurface.cpp | 2 | ||||
-rw-r--r-- | engines/mads/scene.cpp | 7 | ||||
-rw-r--r-- | engines/mads/scene.h | 1 | ||||
-rw-r--r-- | engines/mads/scene_data.cpp | 165 | ||||
-rw-r--r-- | engines/mads/scene_data.h | 99 | ||||
-rw-r--r-- | engines/mads/sprites.cpp | 239 | ||||
-rw-r--r-- | engines/mads/sprites.h (renamed from engines/mads/msprite.h) | 89 |
18 files changed, 464 insertions, 370 deletions
diff --git a/engines/mads/assets.cpp b/engines/mads/assets.cpp index c968afc311..ebedeb8141 100644 --- a/engines/mads/assets.cpp +++ b/engines/mads/assets.cpp @@ -163,6 +163,15 @@ void SpriteAsset::drawScaled(int frameNumber, MSurface &depthSurface, MSurface & warning("TODO: SpriteAsset::drawScaled"); } +void SpriteAsset::draw(MSurface *surface, int frameNumber, const Common::Point &pt) { + error("TODO: draw"); +} + +void SpriteAsset::depthDraw(MSurface *surface, MSurface *depthSurface, int frameNumber, + const Common::Point &pt, int depth) { + error("TODO: depthDraw"); +} + /*------------------------------------------------------------------------*/ SpriteSetCharInfo::SpriteSetCharInfo(Common::SeekableReadStream *s) { diff --git a/engines/mads/assets.h b/engines/mads/assets.h index 7a6939b222..30676a1d7e 100644 --- a/engines/mads/assets.h +++ b/engines/mads/assets.h @@ -25,14 +25,16 @@ #include "common/scummsys.h" #include "common/array.h" -#include "mads/msprite.h" #include "mads/palette.h" -#include "mads/msprite.h" namespace MADS { #define SPRITE_SET_CHAR_INFO 4 +class MADSEngine; +class MSprite; +class MSurface; + struct SpriteAssetFrame { uint32 _stream; Common::Rect _bounds; @@ -100,6 +102,9 @@ public: void drawScaled(int frameNumber, MSurface &depthSurface, MSurface &destSurface, int scale, int depth, const Common::Point &pos); + void draw(MSurface *surface, int frameNumber, const Common::Point &pt); + void depthDraw(MSurface *surface, MSurface *depthSurface, int frameNumber, + const Common::Point &pt, int depth); }; } // End of namespace MADS diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp index e4c7682a38..d159d48ace 100644 --- a/engines/mads/dialogs.cpp +++ b/engines/mads/dialogs.cpp @@ -34,7 +34,7 @@ Dialog::Dialog(MADSEngine *vm): _vm(vm), _savedSurface(nullptr), } Dialog::~Dialog() { - restore(_vm->_screen); + restore(&_vm->_screen); } @@ -55,21 +55,21 @@ void Dialog::restore(MSurface *s) { void Dialog::draw() { // Save the screen portion the dialog will overlap - save(_vm->_screen); + save(&_vm->_screen); // Draw the dialog // Fill entire content of dialog - _vm->_screen->fillRect(Common::Rect(_position.x, _position.y, + _vm->_screen.fillRect(Common::Rect(_position.x, _position.y, _position.x + _width, _position.y + _height), TEXTDIALOG_BACKGROUND); // Draw the outer edge lines - _vm->_screen->hLine(_position.x + 1, _position.y + _height - 2, + _vm->_screen.hLine(_position.x + 1, _position.y + _height - 2, _position.x + _width - 2, TEXTDIALOG_EDGE); - _vm->_screen->hLine(_position.x, _position.y + _height - 1, + _vm->_screen.hLine(_position.x, _position.y + _height - 1, _position.x + _width - 1, TEXTDIALOG_EDGE); - _vm->_screen->vLine(_position.x + _width - 2, _position.y + 2, + _vm->_screen.vLine(_position.x + _width - 2, _position.y + 2, _position.y + _height - 2, TEXTDIALOG_EDGE); - _vm->_screen->vLine(_position.x + _width - 1, _position.y + 1, + _vm->_screen.vLine(_position.x + _width - 1, _position.y + 1, _position.y + _height - 1, TEXTDIALOG_EDGE); // Draw the gravelly dialog content @@ -82,7 +82,7 @@ void Dialog::drawContent(const Common::Rect &r, int seed, byte color1, byte colo uint16 currSeed = seed ? seed : 0xB78E; for (int yp = 0; yp < r.height(); ++yp) { - byte *destP = _vm->_screen->getBasePtr(r.left, r.top + yp); + byte *destP = _vm->_screen.getBasePtr(r.left, r.top + yp); for (int xp = 0; xp < r.width(); ++xp) { uint16 seedAdjust = currSeed; @@ -246,10 +246,10 @@ void TextDialog::draw() { if (_position.y == -1) _position.y = 100 - (_height / 2); - if ((_position.x + _width) > _vm->_screen->getWidth()) - _position.x = _vm->_screen->getWidth() - (_position.x + _width); - if ((_position.y + _height) > _vm->_screen->getHeight()) - _position.y = _vm->_screen->getHeight() - (_position.y + _height); + if ((_position.x + _width) > _vm->_screen.getWidth()) + _position.x = _vm->_screen.getWidth() - (_position.x + _width); + if ((_position.y + _height) > _vm->_screen.getHeight()) + _position.y = _vm->_screen.getHeight() - (_position.y + _height); // Draw the underlying dialog Dialog::draw(); @@ -259,7 +259,7 @@ void TextDialog::draw() { for (int lineNum = 0; lineNum < _numLines; ++lineNum) { if (_lineXp[lineNum] == -1) { // Draw a line across the entire dialog - _vm->_screen->hLine(_position.x + 2, + _vm->_screen.hLine(_position.x + 2, lineYp + (_vm->_font->getHeight() + 1) / 2, _position.x + _width - 4, TEXTDIALOG_BLACK); } else { @@ -269,13 +269,13 @@ void TextDialog::draw() { if (_lineXp[lineNum] & 0x40) ++yp; - _vm->_font->writeString(_vm->_screen, _lines[lineNum], + _vm->_font->writeString(&_vm->_screen, _lines[lineNum], Common::Point(xp, yp), 0, 1); if (_lineXp[lineNum] & 0x80) { // Draw an underline under the text int lineWidth = _vm->_font->getWidth(_lines[lineNum], 1); - _vm->_screen->hLine(xp, yp + _vm->_font->getHeight(), xp + lineWidth, + _vm->_screen.hLine(xp, yp + _vm->_font->getHeight(), xp + lineWidth, TEXTDIALOG_BLACK); } } diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp index 1acb081d8a..7fa31d7616 100644 --- a/engines/mads/events.cpp +++ b/engines/mads/events.cpp @@ -148,7 +148,7 @@ void EventsManager::checkForNextFrameCounter() { _vm->_debugger->onFrame(); // Display the frame - _vm->_screen->updateScreen(); + _vm->_screen.updateScreen(); // Signal the ScummVM debugger _vm->_debugger->onFrame(); diff --git a/engines/mads/events.h b/engines/mads/events.h index add8fc34c0..f30e588bb4 100644 --- a/engines/mads/events.h +++ b/engines/mads/events.h @@ -24,8 +24,8 @@ #define MADS_EVENTS_H #include "common/scummsys.h" -#include "mads/msprite.h" #include "mads/assets.h" +#include "mads/sprites.h" namespace MADS { diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index e9fbf918c4..fd2aebaecf 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -27,10 +27,10 @@ #include "engines/util.h" #include "mads/mads.h" #include "mads/graphics.h" +#include "mads/msurface.h" #include "mads/resources.h" #include "mads/sound.h" -#include "mads/msurface.h" -#include "mads/msprite.h" +#include "mads/sprites.h" namespace MADS { @@ -50,7 +50,6 @@ MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) : _game = nullptr; _palette = nullptr; _resources = nullptr; - _screen = nullptr; _sound = nullptr; _userInterface = nullptr; } @@ -63,7 +62,6 @@ MADSEngine::~MADSEngine() { delete _game; delete _palette; delete _resources; - delete _screen; delete _sound; delete _userInterface; } @@ -84,13 +82,13 @@ void MADSEngine::initialise() { _events = new EventsManager(this); _palette = new Palette(this); _font = new Font(this); - _screen = new MSurface(g_system->getWidth(), g_system->getHeight()); + _screen.setSize(g_system->getWidth(), g_system->getHeight()); _sound = new SoundManager(this, _mixer); _userInterface = UserInterface::init(this); _game = Game::init(this); _events->loadCursors("*CURSOR.SS"); - _screen->empty(); + _screen.empty(); } Common::Error MADSEngine::run() { diff --git a/engines/mads/mads.h b/engines/mads/mads.h index 2d85236d8d..0d5e16ac47 100644 --- a/engines/mads/mads.h +++ b/engines/mads/mads.h @@ -97,7 +97,7 @@ public: Game *_game; Palette *_palette; Resources *_resources; - MSurface *_screen; + MSurface _screen; SoundManager *_sound; UserInterface *_userInterface; bool _easyMouse; diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp index cc618c4b76..3b6663e71d 100644 --- a/engines/mads/messages.cpp +++ b/engines/mads/messages.cpp @@ -301,13 +301,13 @@ TextDisplayList::TextDisplayList(MADSEngine *vm) : _vm(vm) { TextDisplay rec; rec._active = false; rec._expire = 0; - _entries.push_back(rec); + push_back(rec); } } void TextDisplayList::clear() { for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) - _entries[i]._active = false; + (*this)[i]._active = false; } int TextDisplayList::add(int xp, int yp, uint fontColor, int charSpacing, @@ -315,20 +315,21 @@ int TextDisplayList::add(int xp, int yp, uint fontColor, int charSpacing, int usedSlot = -1; for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) { - if (!_entries[idx]._active) { + TextDisplay &td = (*this)[idx]; + if (!td._active) { usedSlot = idx; - _entries[idx]._bounds.left = xp; - _entries[idx]._bounds.top = yp; - _entries[idx]._font = font; - _entries[idx]._msg = msg; - _entries[idx]._bounds.setWidth(font->getWidth(msg, charSpacing)); - _entries[idx]._bounds.setHeight(font->getHeight()); - _entries[idx]._color1 = fontColor & 0xff; - _entries[idx]._color2 = fontColor >> 8; - _entries[idx]._spacing = charSpacing; - _entries[idx]._expire = 1; - _entries[idx]._active = true; + td._bounds.left = xp; + td._bounds.top = yp; + td._font = font; + td._msg = msg; + td._bounds.setWidth(font->getWidth(msg, charSpacing)); + td._bounds.setHeight(font->getHeight()); + td._color1 = fontColor & 0xff; + td._color2 = fontColor >> 8; + td._spacing = charSpacing; + td._expire = 1; + td._active = true; break; } } @@ -340,11 +341,11 @@ void TextDisplayList::setDirtyAreas() { Scene &scene = _vm->_game->_scene; for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) { - if ((_entries[idx]._expire >= 0) || !_entries[idx]._active) + if (((*this)[idx]._expire >= 0) || !(*this)[idx]._active) scene._dirtyAreas[dirtyIdx]._active = false; else { scene._dirtyAreas[dirtyIdx]._textActive = true; - scene._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]); + scene._dirtyAreas[dirtyIdx].setTextDisplay(&(*this)[idx]); } } } @@ -353,9 +354,9 @@ void TextDisplayList::setDirtyAreas2() { Scene &scene = _vm->_game->_scene; for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) { - if (_entries[idx]._active && (_entries[idx]._expire >= 0)) { - scene._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]); - scene._dirtyAreas[dirtyIdx]._textActive = (_entries[idx]._expire <= 0) ? 0 : 1; + if ((*this)[idx]._active && ((*this)[idx]._expire >= 0)) { + scene._dirtyAreas[dirtyIdx].setTextDisplay(&(*this)[idx]); + scene._dirtyAreas[dirtyIdx]._textActive = ((*this)[idx]._expire <= 0) ? 0 : 1; } } } @@ -375,16 +376,16 @@ void TextDisplayList::draw(MSurface *view) { } void TextDisplayList::cleanUp() { - for (uint idx = 0; idx < _entries.size(); ++idx) { - if (_entries[idx]._expire < 0) { - _entries[idx]._active = false; - _entries[idx]._expire = 0; + for (uint idx = 0; idx < size(); ++idx) { + if ((*this)[idx]._expire < 0) { + (*this)[idx]._active = false; + (*this)[idx]._expire = 0; } } } void TextDisplayList::expire(int idx) { - _entries[idx]._expire = -1; + (*this)[idx]._expire = -1; } } // End of namespace MADS diff --git a/engines/mads/messages.h b/engines/mads/messages.h index 6967755cdd..1357b98d03 100644 --- a/engines/mads/messages.h +++ b/engines/mads/messages.h @@ -105,10 +105,9 @@ public: #define TEXT_DISPLAY_SIZE 40 -class TextDisplayList { +class TextDisplayList: public Common::Array<TextDisplay> { private: MADSEngine *_vm; - Common::Array<TextDisplay> _entries; /** * Determine dirty areas for active text areas @@ -118,13 +117,6 @@ public: TextDisplayList(MADSEngine *vm); /** - * Item operator - */ - TextDisplay &operator[](int idx) { - return _entries[idx]; - } - - /** * Expire a given text display entry */ void expire(int idx); diff --git a/engines/mads/module.mk b/engines/mads/module.mk index 36d0c49ff7..2bff5b782e 100644 --- a/engines/mads/module.mk +++ b/engines/mads/module.mk @@ -20,7 +20,6 @@ MODULE_OBJS := \ graphics.o \ mads.o \ messages.o \ - msprite.o \ msurface.o \ palette.o \ player.o \ @@ -29,6 +28,7 @@ MODULE_OBJS := \ scene_data.o \ sequence.o \ sound.o \ + sprites.o \ user_interface.o # This module can be built as a plugin diff --git a/engines/mads/msprite.cpp b/engines/mads/msprite.cpp deleted file mode 100644 index 279192fbdc..0000000000 --- a/engines/mads/msprite.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "common/scummsys.h" -#include "engines/util.h" -#include "graphics/palette.h" -#include "mads/mads.h" -#include "mads/msurface.h" -#include "mads/msprite.h" - -namespace MADS { - -enum { - kEndOfLine = 0, - kEndOfSprite = 1, - kMarker = 2 -}; - -MSprite::MSprite(): MSurface() { - _encoding = 0; -} - -MSprite::MSprite(Common::SeekableReadStream *source, const Common::Point &offset, - int widthVal, int heightVal, bool decodeRle, uint8 encodingVal) - : MSurface(widthVal, heightVal), - _encoding(encodingVal), _offset(offset) { - - // Load the sprite data - loadSprite(source); -} - -MSprite::~MSprite() { -} - - -// TODO: The sprite outlines (pixel value 0xFD) are not shown -void MSprite::loadSprite(Common::SeekableReadStream *source) { - byte *outp, *lineStart; - bool newLine = false; - - outp = getData(); - lineStart = getData(); - - while (1) { - byte cmd1, cmd2, count, pixel; - - if (newLine) { - outp = lineStart + getWidth(); - lineStart = outp; - newLine = false; - } - - cmd1 = source->readByte(); - - if (cmd1 == 0xFC) - break; - else if (cmd1 == 0xFF) - newLine = true; - else if (cmd1 == 0xFD) { - while (!newLine) { - count = source->readByte(); - if (count == 0xFF) { - newLine = true; - } else { - pixel = source->readByte(); - while (count--) - *outp++ = (pixel == 0xFD) ? 0 : pixel; - } - } - } else { - while (!newLine) { - cmd2 = source->readByte(); - if (cmd2 == 0xFF) { - newLine = true; - } else if (cmd2 == 0xFE) { - count = source->readByte(); - pixel = source->readByte(); - while (count--) - *outp++ = (pixel == 0xFD) ? 0 : pixel; - } else { - *outp++ = (cmd2 == 0xFD) ? 0 : cmd2; - } - } - } - } -} - -} // End of namespace MADS diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp index ca75a50bde..bb9b3089df 100644 --- a/engines/mads/msurface.cpp +++ b/engines/mads/msurface.cpp @@ -24,9 +24,9 @@ #include "mads/compression.h" #include "mads/graphics.h" #include "mads/mads.h" -#include "mads/msprite.h" #include "mads/msurface.h" #include "mads/resources.h" +#include "mads/sprites.h" namespace MADS { diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index db252a95a4..994f58230e 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -424,7 +424,14 @@ void Scene::doFrame() { } void Scene::drawElements(bool transitionFlag, bool surfaceFlag) { + // Draw any background objects + _spriteSlots.drawBackground(); + // Merge any identified dirty areas + _dirtyAreas.merge(1, _dirtyAreas.size()); + + // Copy dirty areas to the main display surface + _dirtyAreas.copy(&_vm->_screen, &_backgroundSurface, _posAdjust); } void Scene::leftClick() { diff --git a/engines/mads/scene.h b/engines/mads/scene.h index 483ecae23c..c466f97c02 100644 --- a/engines/mads/scene.h +++ b/engines/mads/scene.h @@ -32,6 +32,7 @@ #include "mads/scene_data.h" #include "mads/animation.h" #include "mads/sequence.h" +#include "mads/sprites.h" namespace MADS { diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp index 46ef2c3058..371fa43501 100644 --- a/engines/mads/scene_data.cpp +++ b/engines/mads/scene_data.cpp @@ -138,76 +138,7 @@ void ScreenObjects::proc1() { /*------------------------------------------------------------------------*/ -SpriteSlot::SpriteSlot() { - _spriteType = ST_NONE; - _seqIndex = 0; - _spritesIndex = 0; - _frameNumber = 0; - _depth = 0; - _scale = 0; -} - -SpriteSlot::SpriteSlot(SpriteType type, int seqIndex) { - _spriteType = type; - _seqIndex = seqIndex; - _spritesIndex = 0; - _frameNumber = 0; - _depth = 0; - _scale = 0; -} - -/*------------------------------------------------------------------------*/ - -void SpriteSlots::clear(bool flag) { - _vm->_game->_scene._textDisplay.clear(); - - if (flag) - _vm->_game->_scene._sprites.clear(); - - Common::Array<SpriteSlot>::clear(); - push_back(SpriteSlot(ST_FULL_SCREEN_REFRESH, -1)); -} - -/** - * Releases any sprites used by the player - */ -void SpriteSlots::releasePlayerSprites() { - Player &player = _vm->_game->_player; - - if (player._spritesLoaded && player._numSprites > 0) { - int spriteEnd = player._spritesStart + player._numSprites - 1; - do { - deleteEntry(spriteEnd); - } while (--spriteEnd >= player._spritesStart); - } -} - -void SpriteSlots::deleteEntry(int index) { - remove_at(index); -} - -void SpriteSlots::fullRefresh(bool clearAll) { - if (clearAll) - Common::Array<SpriteSlot>::clear(); - - push_back(SpriteSlot(ST_FULL_SCREEN_REFRESH, -1)); -} - -/*------------------------------------------------------------------------*/ - -int SpriteSets::add(SpriteAsset *asset, int idx) { - if (!idx) - idx = size(); - - if (idx >= (int)(size() + 1)) - resize(idx + 1); - delete (*this)[idx]; - (*this)[idx] = asset; - - return idx; -} - -/*------------------------------------------------------------------------*/ +MADSEngine *DirtyArea::_vm = nullptr; void DirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) { if (_bounds.left % 2) { @@ -246,73 +177,75 @@ void DirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) { _active = true; } -/*------------------------------------------------------------------------*/ - -DirtyAreas::DirtyAreas(MADSEngine *vm) : _vm(vm) { - for (int i = 0; i < DIRTY_AREAS_SIZE; ++i) { - DirtyArea rec; - rec._active = false; - _entries.push_back(rec); - } -} -void DirtyAreas::setSpriteSlot(int dirtyIdx, const SpriteSlot &spriteSlot) { +void DirtyArea::setSpriteSlot(const SpriteSlot *spriteSlot) { int width, height; - DirtyArea &dirtyArea = _entries[dirtyIdx]; Scene &scene = _vm->_game->_scene; - if (spriteSlot._spriteType == ST_FULL_SCREEN_REFRESH) { + if (spriteSlot->_spriteType == ST_FULL_SCREEN_REFRESH) { // Special entry to refresh the entire screen - dirtyArea._bounds.left = 0; - dirtyArea._bounds.top = 0; + _bounds.left = 0; + _bounds.top = 0; width = MADS_SCREEN_WIDTH; height = MADS_SCENE_HEIGHT; } else { // Standard sprite slots - dirtyArea._bounds.left = spriteSlot._position.x - scene._posAdjust.x; - dirtyArea._bounds.top = spriteSlot._position.y - scene._posAdjust.y; + _bounds.left = spriteSlot->_position.x - scene._posAdjust.x; + _bounds.top = spriteSlot->_position.y - scene._posAdjust.y; - SpriteAsset &spriteSet = scene._spriteSlots.getSprite(spriteSlot._spritesIndex); - MSprite *frame = spriteSet.getFrame(((spriteSlot._frameNumber & 0x7fff) - 1) & 0x7f); + SpriteAsset &spriteSet = scene._spriteSlots.getSprite(spriteSlot->_spritesIndex); + MSprite *frame = spriteSet.getFrame(((spriteSlot->_frameNumber & 0x7fff) - 1) & 0x7f); - if (spriteSlot._scale == -1) { - width = frame->getWidth(); - height = frame->getHeight(); - } else { - width = frame->getWidth() * spriteSlot._scale / 100; - height = frame->getHeight() * spriteSlot._scale / 100; + if (spriteSlot->_scale == -1) { + width = frame->w; + height = frame->h; + } + else { + width = frame->w * spriteSlot->_scale / 100; + height = frame->h * spriteSlot->_scale / 100; - dirtyArea._bounds.left -= width / 2; - dirtyArea._bounds.top += -(height - 1); + _bounds.left -= width / 2; + _bounds.top += -(height - 1); } } - dirtyArea.setArea(width, height, MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT); + setArea(width, height, MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT); } -void DirtyAreas::setTextDisplay(int dirtyIdx, const TextDisplay &textDisplay) { - DirtyArea &dirtyArea = _entries[dirtyIdx]; - dirtyArea._bounds.left = textDisplay._bounds.left; - dirtyArea._bounds.top = textDisplay._bounds.top; +void DirtyArea::setTextDisplay(const TextDisplay *textDisplay) { + _bounds.left = textDisplay->_bounds.left; + _bounds.top = textDisplay->_bounds.top; - dirtyArea.setArea(textDisplay._bounds.width(), textDisplay._bounds.height(), + setArea(textDisplay->_bounds.width(), textDisplay->_bounds.height(), MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT); } +/*------------------------------------------------------------------------*/ + +DirtyAreas::DirtyAreas(MADSEngine *vm) : _vm(vm) { + DirtyArea::_vm = vm; + + for (int i = 0; i < DIRTY_AREAS_SIZE; ++i) { + DirtyArea rec; + rec._active = false; + push_back(rec); + } +} + void DirtyAreas::merge(int startIndex, int count) { error("TODO: DirtyAreas::merge"); if (startIndex >= count) return; for (int outerCtr = startIndex - 1, idx = 0; idx < count; ++outerCtr, ++idx) { - if (!_entries[outerCtr]._active) + if (!(*this)[outerCtr]._active) continue; for (int innerCtr = outerCtr + 1; innerCtr < count; ++innerCtr) { - if (!_entries[innerCtr]._active || !intersects(outerCtr, innerCtr)) + if (!(*this)[innerCtr]._active || !intersects(outerCtr, innerCtr)) continue; - if (_entries[outerCtr]._textActive && _entries[innerCtr]._textActive) + if ((*this)[outerCtr]._textActive && (*this)[innerCtr]._textActive) mergeAreas(outerCtr, innerCtr); } } @@ -322,12 +255,12 @@ void DirtyAreas::merge(int startIndex, int count) { * Returns true if two dirty areas intersect */ bool DirtyAreas::intersects(int idx1, int idx2) { - return _entries[idx1]._bounds2.intersects(_entries[idx2]._bounds2); + return (*this)[idx1]._bounds2.intersects((*this)[idx2]._bounds2); } void DirtyAreas::mergeAreas(int idx1, int idx2) { - DirtyArea &da1 = _entries[idx1]; - DirtyArea &da2 = _entries[idx2]; + DirtyArea &da1 = (*this)[idx1]; + DirtyArea &da2 = (*this)[idx2]; da1._bounds.extend(da2._bounds); @@ -341,20 +274,22 @@ void DirtyAreas::mergeAreas(int idx1, int idx2) { } void DirtyAreas::copy(MSurface *dest, MSurface *src, const Common::Point &posAdjust) { - for (uint i = 0; i < _entries.size(); ++i) { - const Common::Rect &srcBounds = _entries[i]._bounds; + for (uint i = 0; i < size(); ++i) { + const Common::Rect &srcBounds = (*this)[i]._bounds; Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y, srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y); - if (_entries[i]._active && _entries[i]._bounds.isValidRect()) - src->copyTo(dest, bounds, Common::Point(_entries[i]._bounds.left, _entries[i]._bounds.top)); + if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) { + src->copyTo(dest, bounds, Common::Point((*this)[i]._bounds.left, + (*this)[i]._bounds.top)); + } } } -void DirtyAreas::clear() { - for (uint i = 0; i < _entries.size(); ++i) - _entries[i]._active = false; +void DirtyAreas::reset() { + for (uint i = 0; i < size(); ++i) + (*this)[i]._active = false; } /*------------------------------------------------------------------------*/ diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h index 522cd178d0..15371e405f 100644 --- a/engines/mads/scene_data.h +++ b/engines/mads/scene_data.h @@ -38,6 +38,7 @@ namespace MADS { class MADSEngine; class Scene; +class SpriteSlot; #define MADS_INTERFACE_HEIGHT 44 #define MADS_SCENE_HEIGHT 156 @@ -58,11 +59,6 @@ enum Layer { LAYER_GUI = 19 }; -enum SpriteType { - ST_NONE = 0, ST_FOREGROUND = 1, ST_BACKGROUND = -4, - ST_FULL_SCREEN_REFRESH = -2, ST_EXPIRED = -1 -}; - class VerbInit { public: int _id; @@ -117,72 +113,6 @@ public: void check(bool scanFlag); }; -class SpriteSlotSubset { -public: - int _spritesIndex; - int _frameNumber; - Common::Point _position; - int _depth; - int _scale; -}; - -class SpriteSlot: public SpriteSlotSubset { -public: - SpriteType _spriteType; - int _seqIndex; -public: - SpriteSlot(); - SpriteSlot(SpriteType type, int seqIndex); -}; - -class SpriteSlots: public Common::Array<SpriteSlot> { -private: - MADSEngine *_vm; -public: - SpriteSlots(MADSEngine *vm): _vm(vm) {} - - /** - * Clears any pending slot data and schedules a full screen refresh. - * @param flag Also reset sprite list - */ - void clear(bool flag); - - /** - * Delete any sprites used by the player - */ - void releasePlayerSprites(); - - /** - * Delete a sprite entry - * @param index Specifies the index in the array - */ - void deleteEntry(int index); - - /** - * Adds a full screen refresh to the sprite slots - */ - void fullRefresh(bool clearAll = false); - - SpriteAsset &getSprite(int idx) { - error("TODO"); - } - void deleteTimer(int idx) { - warning("TODO: SpriteSlots::deleteTimer"); - } - int getIndex() { - warning("TODO: SpriteSlots::indexOf"); - return -1; - } -}; - -class SpriteSets: public Common::Array<SpriteAsset *> { -public: - /** - * Add a sprite asset to the list - */ - int add(SpriteAsset *asset, int idx = 0); -}; - class DynamicHotspot { public: bool _active; @@ -235,6 +165,9 @@ public: }; class DirtyArea { +private: + static MADSEngine *_vm; + friend class DirtyAreas; public: Common::Rect _bounds; Common::Rect _bounds2; @@ -242,25 +175,23 @@ public: bool _active; DirtyArea() { _active = false; } + void setArea(int width, int height, int maxWidth, int maxHeight); + + void setSpriteSlot(const SpriteSlot *spriteSlot); + + /** + * Set up a dirty area for a text display + */ + void setTextDisplay(const TextDisplay *textDisplay); }; -class DirtyAreas { +class DirtyAreas: public Common::Array<DirtyArea> { private: MADSEngine *_vm; - Common::Array<DirtyArea> _entries; public: DirtyAreas(MADSEngine *vm); - - DirtyArea &operator[](uint idx) { - assert(idx < _entries.size()); - return _entries[idx]; - } - - void setSpriteSlot(int dirtyIdx, const SpriteSlot &spriteSlot); - - void setTextDisplay(int dirtyIdx, const TextDisplay &textDisplay); - + /** * Merge together any designated dirty areas that overlap * @param startIndex 1-based starting dirty area starting index @@ -271,7 +202,7 @@ public: bool intersects(int idx1, int idx2); void mergeAreas(int idx1, int idx2); void copy(MSurface *dest, MSurface *src, const Common::Point &posAdjust); - void clear(); + void reset(); }; class SceneLogic { diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp new file mode 100644 index 0000000000..3cba6989b1 --- /dev/null +++ b/engines/mads/sprites.cpp @@ -0,0 +1,239 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "engines/util.h" +#include "graphics/palette.h" +#include "mads/mads.h" +#include "mads/graphics.h" +#include "mads/msurface.h" +#include "mads/sprites.h" + +namespace MADS { + +enum { + kEndOfLine = 0, + kEndOfSprite = 1, + kMarker = 2 +}; + +MSprite::MSprite(): MSurface() { + _encoding = 0; +} + +MSprite::MSprite(Common::SeekableReadStream *source, const Common::Point &offset, + int widthVal, int heightVal, bool decodeRle, uint8 encodingVal) + : MSurface(widthVal, heightVal), + _encoding(encodingVal), _offset(offset) { + + // Load the sprite data + loadSprite(source); +} + +MSprite::~MSprite() { +} + + +// TODO: The sprite outlines (pixel value 0xFD) are not shown +void MSprite::loadSprite(Common::SeekableReadStream *source) { + byte *outp, *lineStart; + bool newLine = false; + + outp = getData(); + lineStart = getData(); + + while (1) { + byte cmd1, cmd2, count, pixel; + + if (newLine) { + outp = lineStart + getWidth(); + lineStart = outp; + newLine = false; + } + + cmd1 = source->readByte(); + + if (cmd1 == 0xFC) + break; + else if (cmd1 == 0xFF) + newLine = true; + else if (cmd1 == 0xFD) { + while (!newLine) { + count = source->readByte(); + if (count == 0xFF) { + newLine = true; + } else { + pixel = source->readByte(); + while (count--) + *outp++ = (pixel == 0xFD) ? 0 : pixel; + } + } + } else { + while (!newLine) { + cmd2 = source->readByte(); + if (cmd2 == 0xFF) { + newLine = true; + } else if (cmd2 == 0xFE) { + count = source->readByte(); + pixel = source->readByte(); + while (count--) + *outp++ = (pixel == 0xFD) ? 0 : pixel; + } else { + *outp++ = (cmd2 == 0xFD) ? 0 : cmd2; + } + } + } + } +} + +/*------------------------------------------------------------------------*/ + +MADSEngine *SpriteSlot::_vm = nullptr; + +SpriteSlot::SpriteSlot() { + _spriteType = ST_NONE; + _seqIndex = 0; + _spritesIndex = 0; + _frameNumber = 0; + _depth = 0; + _scale = 0; +} + +SpriteSlot::SpriteSlot(SpriteType type, int seqIndex) { + _spriteType = type; + _seqIndex = seqIndex; + _spritesIndex = 0; + _frameNumber = 0; + _depth = 0; + _scale = 0; +} + +/*------------------------------------------------------------------------*/ + +SpriteSlots::SpriteSlots(MADSEngine *vm) : _vm(vm) { + SpriteSlot::_vm = vm; +} + +void SpriteSlots::clear(bool flag) { + _vm->_game->_scene._textDisplay.clear(); + + if (flag) + _vm->_game->_scene._sprites.clear(); + + Common::Array<SpriteSlot>::clear(); + push_back(SpriteSlot(ST_FULL_SCREEN_REFRESH, -1)); +} + +/** +* Releases any sprites used by the player +*/ +void SpriteSlots::releasePlayerSprites() { + Player &player = _vm->_game->_player; + + if (player._spritesLoaded && player._numSprites > 0) { + int spriteEnd = player._spritesStart + player._numSprites - 1; + do { + deleteEntry(spriteEnd); + } while (--spriteEnd >= player._spritesStart); + } +} + +void SpriteSlots::deleteEntry(int index) { + remove_at(index); +} + +void SpriteSlots::fullRefresh(bool clearAll) { + if (clearAll) + Common::Array<SpriteSlot>::clear(); + + push_back(SpriteSlot(ST_FULL_SCREEN_REFRESH, -1)); +} + +void SpriteSlots::drawBackground() { + Scene &scene = _vm->_game->_scene; + + // Initial draw loop for any active sprites in the background + for (uint i = 0; i < scene._spriteSlots.size(); ++i) { + if (scene._spriteSlots[i]._spriteType >= ST_NONE) { + scene._dirtyAreas[i]._active = false; + } + else { + scene._dirtyAreas[i]._active = true; + scene._dirtyAreas[i].setSpriteSlot(&scene._spriteSlots[i]); + + SpriteAsset *asset = scene._sprites[scene._spriteSlots[i]._spritesIndex]; + MSprite *frame = asset->getFrame(scene._spriteSlots[i]._frameNumber); + + if (scene._spriteSlots[i]._spriteType == ST_BACKGROUND) { + Common::Point pt = scene._spriteSlots[i]._position; + if (scene._spriteSlots[i]._scale != -1) { + // Adjust the drawing position + pt.x -= frame->w / 2; + pt.y -= frame->h / 2; + } + + if (scene._spriteSlots[i]._depth <= 1) { + asset->draw(&scene._backgroundSurface, scene._spriteSlots[i]._frameNumber, pt); + } + else if (scene._depthStyle == 0) { + asset->depthDraw(&scene._backgroundSurface, &scene._depthSurface, scene._spriteSlots[i]._frameNumber, + pt, scene._spriteSlots[i]._depth); + } else { + error("Unsupported depth style"); + } + } + } + } + + // Mark any remaning dirty areas as inactive + for (uint i = scene._spriteSlots.size(); i < 50; ++i) + scene._dirtyAreas[i]._active = false; + + // Flag any active text display + for (uint i = 50; i < scene._textDisplay.size(); ++i) { + TextDisplay &textDisplay = scene._textDisplay[i - 50]; + if (scene._textDisplay[i]._expire >= 0 || !textDisplay._active) { + scene._dirtyAreas[i]._active = false; + } else { + scene._dirtyAreas[i]._active = true; + scene._dirtyAreas[i].setTextDisplay(&textDisplay); + } + } +} + +/*------------------------------------------------------------------------*/ + +int SpriteSets::add(SpriteAsset *asset, int idx) { + if (!idx) + idx = size(); + + if (idx >= (int)(size() + 1)) + resize(idx + 1); + delete (*this)[idx]; + (*this)[idx] = asset; + + return idx; +} + +/*------------------------------------------------------------------------*/ + +} // End of namespace MADS diff --git a/engines/mads/msprite.h b/engines/mads/sprites.h index f2194dab08..6b131105dc 100644 --- a/engines/mads/msprite.h +++ b/engines/mads/sprites.h @@ -20,14 +20,21 @@ * */ -#ifndef MADS_MSPRITE_H -#define MADS_MSPRITE_H +#ifndef MADS_SPRITES_H +#define MADS_SPRITES_H #include "common/scummsys.h" +#include "common/array.h" +#include "mads/assets.h" #include "mads/msurface.h" namespace MADS { +enum SpriteType { + ST_NONE = 0, ST_FOREGROUND = 1, ST_BACKGROUND = -4, + ST_FULL_SCREEN_REFRESH = -2, ST_EXPIRED = -1 +}; + class MADSEngine; struct BGR8 { @@ -109,6 +116,82 @@ public: uint8 _encoding; }; +class SpriteSlotSubset { +public: + int _spritesIndex; + int _frameNumber; + Common::Point _position; + int _depth; + int _scale; +}; + +class SpriteSlot : public SpriteSlotSubset { +private: + static MADSEngine *_vm; + friend class SpriteSlots; +public: + SpriteType _spriteType; + int _seqIndex; +public: + SpriteSlot(); + SpriteSlot(SpriteType type, int seqIndex); + + void setup(int dirtyAreaIndex); +}; + +class SpriteSlots : public Common::Array<SpriteSlot> { +private: + MADSEngine *_vm; +public: + SpriteSlots(MADSEngine *vm); + + /** + * Clears any pending slot data and schedules a full screen refresh. + * @param flag Also reset sprite list + */ + void clear(bool flag); + + /** + * Delete any sprites used by the player + */ + void releasePlayerSprites(); + + /** + * Delete a sprite entry + * @param index Specifies the index in the array + */ + void deleteEntry(int index); + + /** + * Adds a full screen refresh to the sprite slots + */ + void fullRefresh(bool clearAll = false); + + SpriteAsset &getSprite(int idx) { + error("TODO"); + } + void deleteTimer(int idx) { + warning("TODO: SpriteSlots::deleteTimer"); + } + int getIndex() { + warning("TODO: SpriteSlots::indexOf"); + return -1; + } + + /** + * Draw any sprites into the background of the scene + */ + void drawBackground(); +}; + +class SpriteSets : public Common::Array<SpriteAsset *> { +public: + /** + * Add a sprite asset to the list + */ + int add(SpriteAsset *asset, int idx = 0); +}; + } // End of namespace MADS -#endif /* MADS_MSPRITE_H */ +#endif /* MADS_SPRITES_H */ |