diff options
author | Paul Gilbert | 2014-03-05 20:45:02 -0500 |
---|---|---|
committer | Paul Gilbert | 2014-03-05 20:45:02 -0500 |
commit | a0e955d8d327afa83ad96fe1ce765eeba0ce561f (patch) | |
tree | 78d3f66c37bf7a8f51ef438b66cab4b45665ec29 | |
parent | d98f890029936dfa8139cf8dce4756ec92bc2568 (diff) | |
download | scummvm-rg350-a0e955d8d327afa83ad96fe1ce765eeba0ce561f.tar.gz scummvm-rg350-a0e955d8d327afa83ad96fe1ce765eeba0ce561f.tar.bz2 scummvm-rg350-a0e955d8d327afa83ad96fe1ce765eeba0ce561f.zip |
MADS: More Animation class implementation
-rw-r--r-- | engines/mads/animation.cpp | 255 | ||||
-rw-r--r-- | engines/mads/animation.h | 54 | ||||
-rw-r--r-- | engines/mads/msurface.cpp | 67 | ||||
-rw-r--r-- | engines/mads/msurface.h | 12 | ||||
-rw-r--r-- | engines/mads/palette.cpp | 9 | ||||
-rw-r--r-- | engines/mads/palette.h | 5 | ||||
-rw-r--r-- | engines/mads/sprites.cpp | 14 | ||||
-rw-r--r-- | engines/mads/sprites.h | 2 |
8 files changed, 382 insertions, 36 deletions
diff --git a/engines/mads/animation.cpp b/engines/mads/animation.cpp index c97d707f39..d0c7d3079b 100644 --- a/engines/mads/animation.cpp +++ b/engines/mads/animation.cpp @@ -27,7 +27,7 @@ namespace MADS { -AAHeader::AAHeader(Common::SeekableReadStream *f) { +void AAHeader::load(Common::SeekableReadStream *f) { _spriteSetsCount = f->readUint16LE(); _miscEntriesCount = f->readUint16LE(); _frameEntriesCount = f->readUint16LE(); @@ -40,7 +40,7 @@ AAHeader::AAHeader(Common::SeekableReadStream *f) { _roomNumber = f->readUint16LE(); f->skip(2); _manualFlag = f->readUint16LE() != 0; - _spriteListIndex = f->readUint16LE(); + _spritesIndex = f->readUint16LE(); _scrollPosition.x = f->readSint16LE(); _scrollPosition.y = f->readSint16LE(); _scrollTicks = f->readUint32LE(); @@ -184,33 +184,33 @@ void Animation::load(MSurface &depthSurface, InterfaceSurface &interfaceSurface, MadsPack madsPack(&f); Common::SeekableReadStream *stream = madsPack.getItemStream(0); - AAHeader aaHeader(stream); + _header.load(stream); delete stream; - if (aaHeader._animMode == 4) + if (_header._animMode == 4) flags |= 0x4000; if (flags & 0x100) { - loadInterface(interfaceSurface, depthSurface, aaHeader, flags, palAnimData, sceneInfo); + loadInterface(interfaceSurface, depthSurface, _header, flags, palAnimData, sceneInfo); } if (flags & 0x200) { // No data - aaHeader._messagesCount = 0; - aaHeader._frameEntriesCount = 0; - aaHeader._miscEntriesCount = 0; + _header._messagesCount = 0; + _header._frameEntriesCount = 0; + _header._miscEntriesCount = 0; } // Initialize the reference list _spriteListIndexes.clear(); - for (int i = 0; i < aaHeader._spriteSetsCount; ++i) + for (int i = 0; i < _header._spriteSetsCount; ++i) _spriteListIndexes.push_back(-1); _messages.clear(); - if (aaHeader._messagesCount > 0) { + if (_header._messagesCount > 0) { // Chunk 2: Following is a list of any messages for the animation Common::SeekableReadStream *msgStream = madsPack.getItemStream(1); - for (int i = 0; i < aaHeader._messagesCount; ++i) { + for (int i = 0; i < _header._messagesCount; ++i) { AnimMessage rec; rec.load(msgStream); _messages.push_back(rec); @@ -220,11 +220,11 @@ void Animation::load(MSurface &depthSurface, InterfaceSurface &interfaceSurface, } _frameEntries.clear(); - if (aaHeader._frameEntriesCount > 0) { + if (_header._frameEntriesCount > 0) { // Chunk 3: animation frame info Common::SeekableReadStream *frameStream = madsPack.getItemStream(2); - for (int i = 0; i < aaHeader._frameEntriesCount; i++) { + for (int i = 0; i < _header._frameEntriesCount; i++) { AnimFrameEntry rec; rec.load(frameStream); _frameEntries.push_back(rec); @@ -234,11 +234,11 @@ void Animation::load(MSurface &depthSurface, InterfaceSurface &interfaceSurface, } _miscEntries.clear(); - if (aaHeader._miscEntriesCount > 0) { + if (_header._miscEntriesCount > 0) { // Chunk 4: Misc Data Common::SeekableReadStream *miscStream = madsPack.getItemStream(3); - for (int i = 0; i < aaHeader._miscEntriesCount; ++i) { + for (int i = 0; i < _header._miscEntriesCount; ++i) { AnimMiscEntry rec; rec.load(miscStream); _miscEntries.push_back(rec); @@ -249,8 +249,8 @@ void Animation::load(MSurface &depthSurface, InterfaceSurface &interfaceSurface, // If the animation specifies a font, then load it for access delete _font; - if (aaHeader._flags & ANIM_CUSTOM_FONT) { - Common::String fontName = "*" + aaHeader._fontResource; + if (_header._flags & ANIM_CUSTOM_FONT) { + Common::String fontName = "*" + _header._fontResource; _font = _vm->_font->getFont(fontName.c_str()); } else { _font = nullptr; @@ -260,28 +260,28 @@ void Animation::load(MSurface &depthSurface, InterfaceSurface &interfaceSurface, for (uint i = 0; i < _spriteSets.size(); ++i) delete _spriteSets[i]; _spriteSets.clear(); - _spriteSets.resize(aaHeader._spriteSetsCount); + _spriteSets.resize(_header._spriteSetsCount); - for (int i = 0; i < aaHeader._spriteSetsCount; ++i) { - if (aaHeader._manualFlag && (i == aaHeader._spriteListIndex)) { + for (int i = 0; i < _header._spriteSetsCount; ++i) { + if (_header._manualFlag && (i == _header._spritesIndex)) { // Skip over field, since it's manually loaded _spriteSets[i] = nullptr; } else { - _spriteSets[i] = new SpriteAsset(_vm, aaHeader._spriteSetNames[i], flags); + _spriteSets[i] = new SpriteAsset(_vm, _header._spriteSetNames[i], flags); } } - if (aaHeader._manualFlag) { - Common::String resName = "*" + aaHeader._spriteSetNames[aaHeader._spriteListIndex]; + if (_header._manualFlag) { + Common::String resName = "*" + _header._spriteSetNames[_header._spritesIndex]; SpriteAsset *sprites = new SpriteAsset(_vm, resName, flags); - _spriteSets[aaHeader._spriteListIndex] = sprites; + _spriteSets[_header._spritesIndex] = sprites; - _spriteListIndexes[aaHeader._spriteListIndex] = _scene->_sprites.add(sprites); + _spriteListIndexes[_header._spritesIndex] = _scene->_sprites.add(sprites); } // TODO: List var_420/var_422 population that seems to overwrite other structures? - if (aaHeader._animMode == 4) { + if (_header._animMode == 4) { // Remaps the sprite list indexes for frames to the loaded sprite list indexes for (uint i = 0; i < _frameEntries.size(); ++i) { int spriteListIndex = _frameEntries[i]._spriteSlot._spritesIndex; @@ -298,6 +298,33 @@ void Animation::load(MSurface &depthSurface, InterfaceSurface &interfaceSurface, f.close(); } +void Animation::loadFrame(int frameNumber) { + Scene &scene = _vm->_game->_scene; + if (_skipLoad) + return; + + Common::Point pt; + int listIndex = _spriteListIndexes[_header._spritesIndex]; + SpriteAsset &spriteSet = scene._spriteSlots.getSprite(listIndex); + + if (_unkIndex < 0) { + MSurface *frame = spriteSet.getFrame(0); + pt.x = frame->getBounds().left; + pt.y = frame->getBounds().top; + } else { + pt.x = _unkList[_unkIndex].x; + pt.y = _unkList[_unkIndex].y; + _unkIndex = 1 - _unkIndex; + } + + if (drawFrame(spriteSet, pt, frameNumber)) + error("proc1 failure"); +} + +bool Animation::drawFrame(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber) { + return 0; +} + void Animation::loadInterface(InterfaceSurface &interfaceSurface, MSurface &depthSurface, AAHeader &header, int flags, Common::Array<RGB4> *palAnimData, SceneInfo *sceneInfo) { _scene->_depthStyle = 0; @@ -323,8 +350,182 @@ void Animation::loadInterface(InterfaceSurface &interfaceSurface, MSurface &dept } } +bool Animation::hasScroll() const { + return (_header._scrollPosition.x != 0) || (_header._scrollPosition.x != 0); +} + void Animation::update() { - warning("TODO: Animation::update"); + Scene &scene = _vm->_game->_scene; + + if (_header._manualFlag) { + int spriteListIndex = _spriteListIndexes[_header._spritesIndex]; + int newIndex = -1; + + for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) { + if (_frameEntries[idx]._frameNumber > _currentFrame) + break; + if (_frameEntries[idx]._spriteSlot._spritesIndex == spriteListIndex) + newIndex = _frameEntries[idx]._spriteSlot._frameNumber; + } + + if (newIndex >= 0) + loadFrame(newIndex); + } + + // If it's not time for the next frame, then exit + if (_vm->_events->_currentTimer < _nextFrameTimer) + return; + + for (uint idx = 0; idx < scene._spriteSlots.size(); ++idx) { + if (scene._spriteSlots[idx]._seqIndex >= 0x80) + scene._spriteSlots[idx]._spriteType = ST_EXPIRED; + } + + // Validate the current frame + if (_currentFrame >= (int)_miscEntries.size()) { + // Is the animation allowed to be repeated? + if (_resetFlag) { + _currentFrame = 0; + _oldFrameEntry = 0; + } else { + _freeFlag = true; + return; + } + } + + // Handle executing any sound command for this frame + AnimMiscEntry &misc = _miscEntries[_currentFrame]; + if (misc._soundId) + _vm->_sound->command(misc._soundId); + + // Handle any screen scrolling + if (hasScroll()) { + scene._backgroundSurface.scrollX(_header._scrollPosition.x); + scene._backgroundSurface.scrollY(_header._scrollPosition.y); + scene._spriteSlots.fullRefresh(); + } + + // Handle any offset adjustment for sprites as of this frame + bool paChanged = false; + if (scene._posAdjust.x != misc._posAdjust.x) { + scene._posAdjust.x = misc._posAdjust.x; + paChanged = true; + } + if (scene._posAdjust.y != misc._posAdjust.y) { + scene._posAdjust.y = misc._posAdjust.y; + paChanged = true; + } + + int newIndex = -1; + if (paChanged) { + newIndex = scene._spriteSlots.getIndex(); + scene._spriteSlots[newIndex]._seqIndex = -1; + scene._spriteSlots[newIndex]._spriteType = ST_FULL_SCREEN_REFRESH; + } + + // Main frame animation loop - frames get animated by being placed, as necessary, into the + // main sprite slot array + while ((uint)_oldFrameEntry < _frameEntries.size()) { + if (_frameEntries[_oldFrameEntry]._frameNumber > _currentFrame) + break; + else if (_frameEntries[_oldFrameEntry]._frameNumber == _currentFrame) { + // Found the correct frame + int spriteSlotIndex = 0; + int index = 0; + + for (;;) { + if ((spriteSlotIndex == 0) && (index < (int)scene._spriteSlots.size())) { + int seqIndex = _frameEntries[_oldFrameEntry]._seqIndex - scene._spriteSlots[index]._seqIndex; + if (seqIndex == 0x80) { + if (scene._spriteSlots[index] == _frameEntries[_oldFrameEntry]._spriteSlot) { + scene._spriteSlots[index]._spriteType = ST_NONE; + spriteSlotIndex = -1; + } + } + ++index; + continue; + } + + if (spriteSlotIndex == 0) { + int slotIndex = scene._spriteSlots.getIndex(); + SpriteSlot &slot = scene._spriteSlots[slotIndex]; + slot.copy(_frameEntries[_oldFrameEntry]._spriteSlot); + slot._seqIndex = _frameEntries[_oldFrameEntry]._seqIndex + 0x80; + + SpriteAsset &spriteSet = scene._spriteSlots.getSprite( + scene._spriteSlots[slotIndex]._spritesIndex); + slot._spriteType = spriteSet.isBackground() ? ST_BACKGROUND : ST_FOREGROUND; + } + break; + } + } + + ++_oldFrameEntry; + } + + // Handle the display of any messages + for (uint idx = 0; idx < _messages.size(); ++idx) { + if (_messages[idx]._kernelMsgIndex >= 0) { + // Handle currently active message + if ((_currentFrame < _messages[idx]._startFrame) || (_currentFrame > _messages[idx]._endFrame)) { + scene._kernelMessages.remove(_messages[idx]._kernelMsgIndex); + _messages[idx]._kernelMsgIndex = -1; + --_messageCtr; + } + } else if ((_currentFrame >= _messages[idx]._startFrame) && (_currentFrame <= _messages[idx]._endFrame)) { + // Start displaying the message + AnimMessage &me = _messages[idx]; + + // The color index to use is dependant on how many messages are currently on-screen + uint8 colIndex; + switch (_messageCtr) { + case 1: + colIndex = 252; + break; + case 2: + colIndex = 16; + break; + default: + colIndex = 250; + break; + } + + _vm->_palette->setEntry(colIndex, me._rgb1[0], me._rgb1[1], me._rgb1[2]); + _vm->_palette->setEntry(colIndex + 1, me._rgb2[0], me._rgb2[1], me._rgb2[2]); + + // Add a kernel message to display the given text + me._kernelMsgIndex = scene._kernelMessages.add(me._pos, colIndex * 0x101 + 0x100, + 0, 0, INDEFINITE_TIMEOUT, me._msg); + assert(me._kernelMsgIndex >= 0); + ++_messageCtr; + } + } + + // Move to the next frame + _currentFrame++; + if (_currentFrame >= (int)_miscEntries.size()) { + // Animation is complete + if (_abortTimers != 0) { + _vm->_game->_abortTimers = _abortTimers; + _vm->_game->_abortTimersMode = _abortMode; + + if (_abortMode != ABORTMODE_1) { + // Copy the noun list + scene._action._action = _actionNouns; + } + } + } + + int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1); + _nextFrameTimer = _vm->_events->_currentTimer + _miscEntries[frameNum]._numTicks; +} + +void Animation::setCurrentFrame(int frameNumber) { + _currentFrame = frameNumber; + _oldFrameEntry = 0; + _freeFlag = false; + + _nextScrollTimer = _nextFrameTimer = _vm->_events->_currentTimer; } } // End of namespace MADS diff --git a/engines/mads/animation.h b/engines/mads/animation.h index 9498483fb6..8df7b37439 100644 --- a/engines/mads/animation.h +++ b/engines/mads/animation.h @@ -90,7 +90,7 @@ public: int _animMode; int _roomNumber; bool _manualFlag; - int _spriteListIndex; + int _spritesIndex; Common::Point _scrollPosition; uint32 _scrollTicks; Common::String _interfaceFile; @@ -104,28 +104,57 @@ public: /** * Loads the data for a animation file header */ - AAHeader(Common::SeekableReadStream *f); + void load(Common::SeekableReadStream *f); }; class Animation { private: MADSEngine *_vm; Scene *_scene; + AAHeader _header; - void loadInterface(InterfaceSurface &interfaceSurface, MSurface &depthSurface, - AAHeader &header, int flags, Common::Array<RGB4> *palAnimData, SceneInfo *sceneInfo); -protected: - Animation(MADSEngine *vm, Scene *scene); -public: - static Animation *init(MADSEngine *vm, Scene *scene); -public: Common::Array<int> _spriteListIndexes; Common::Array<AnimMessage> _messages; Common::Array<AnimFrameEntry> _frameEntries; Common::Array<AnimMiscEntry> _miscEntries; Common::Array<SpriteAsset *> _spriteSets; Font *_font; + + int _currentFrame, _oldFrameEntry; bool _resetFlag; + bool _freeFlag; + bool _skipLoad; + int _unkIndex; + Common::Point _unkList[2]; + uint32 _nextFrameTimer; + uint32 _nextScrollTimer; + int _messageCtr; + int _abortTimers; + AbortTimerMode _abortMode; + ActionDetails _actionNouns; + + /** + * Load data for a given frame + * @param frameNumber Frame number + */ + void loadFrame(int frameNumber); + + bool drawFrame(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber); + + /** + * Load the user interface display for an animation + */ + void loadInterface(InterfaceSurface &interfaceSurface, MSurface &depthSurface, + AAHeader &header, int flags, Common::Array<RGB4> *palAnimData, SceneInfo *sceneInfo); + + /** + * Returns true if there is a scroll required + */ + bool hasScroll() const; +protected: + Animation(MADSEngine *vm, Scene *scene); +public: + static Animation *init(MADSEngine *vm, Scene *scene); public: /* * Destructor @@ -147,6 +176,13 @@ public: * Update the animation */ void update(); + + virtual void setCurrentFrame(int frameNumber); + virtual int getCurrentFrame() const { return _currentFrame; } + + bool freeFlag() const { return _freeFlag; } + bool getAnimMode() const { return _header._animMode; } + int roomNumber() const { return _header._roomNumber; } }; } // End of namespace MADS diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp index aed00f5553..754fea851d 100644 --- a/engines/mads/msurface.cpp +++ b/engines/mads/msurface.cpp @@ -406,6 +406,73 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth, } } +void MSurface::scrollX(int xAmount) { + if (xAmount == 0) + return; + + byte buffer[80]; + int direction = (xAmount > 0) ? -1 : 1; + int xSize = ABS(xAmount); + assert(xSize <= 80); + + byte *srcP = getBasePtr(0, 0); + + for (int y = 0; y < this->h; ++y, srcP += pitch) { + if (direction < 0) { + // Copy area to be overwritten + Common::copy(srcP, srcP + xSize, &buffer[0]); + // Shift the remainder of the line over the given area + Common::copy(srcP + xSize, srcP + this->w, srcP); + // Move buffered area to the end of the line + Common::copy(&buffer[0], &buffer[xSize], srcP + this->w - xSize); + } + else { + // Copy area to be overwritten + Common::copy_backward(srcP + this->w - xSize, srcP + this->w, &buffer[80]); + // Shift the remainder of the line over the given area + Common::copy_backward(srcP, srcP + this->w - xSize, srcP + this->w); + // Move buffered area to the start of the line + Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize); + } + } +} + +void MSurface::scrollY(int yAmount) { + if (yAmount == 0) + return; + + int direction = (yAmount > 0) ? 1 : -1; + int ySize = ABS(yAmount); + assert(ySize < (this->h / 2)); + assert(this->w == pitch); + + int blockSize = ySize * this->w; + byte *tempData = new byte[blockSize]; + byte *pixelsP = getBasePtr(0, 0); + + if (direction > 0) { + // Buffer the lines to be overwritten + byte *srcP = (byte *)getBasePtr(0, this->h - ySize); + Common::copy(srcP, srcP + (pitch * ySize), tempData); + // Vertically shift all the lines + Common::copy_backward(pixelsP, pixelsP + (pitch * (this->h - ySize)), + pixelsP + (pitch * this->h)); + // Transfer the buffered lines top the top of the screen + Common::copy(tempData, tempData + blockSize, pixelsP); + } + else { + // Buffer the lines to be overwritten + Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData); + // Vertically shift all the lines + Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * this->h), pixelsP); + // Transfer the buffered lines to the bottom of the screen + Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (this->h - ySize))); + } + + delete[] tempData; +} + + void MSurface::translate(Common::Array<RGB6> &palette) { for (int y = 0; y < this->h; ++y) { byte *pDest = getBasePtr(0, y); diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h index c797033859..bd8142fd1a 100644 --- a/engines/mads/msurface.h +++ b/engines/mads/msurface.h @@ -180,6 +180,18 @@ public: } /** + * Scroll the screen horizontally by a given amount + * @param xAmount Horizontal amount + */ + void scrollX(int xAmount); + + /** + * Scroll the screen vertically by a given amount + * @param yAmount Vertical amount + */ + void scrollY(int yAmount); + + /** * Translates the pixels of an image used the passed palette with RGB mapping */ void translate(Common::Array<RGB6> &palette); diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp index aca1298a23..4568f7d39a 100644 --- a/engines/mads/palette.cpp +++ b/engines/mads/palette.cpp @@ -180,6 +180,15 @@ void Palette::setPalette(const byte *colors, uint start, uint num) { reset(); } +void Palette::setEntry(byte palIndex, byte r, byte g, byte b) { + _mainPalette[palIndex * 3] = r; + _mainPalette[palIndex * 3 + 1] = g; + _mainPalette[palIndex * 3 + 2] = b; + + setPalette((const byte *)&_mainPalette[palIndex * 3], palIndex, 1); +} + + void Palette::grabPalette(byte *colors, uint start, uint num) { g_system->getPaletteManager()->grabPalette(colors, start, num); reset(); diff --git a/engines/mads/palette.h b/engines/mads/palette.h index 18b058cccc..a00e1789f4 100644 --- a/engines/mads/palette.h +++ b/engines/mads/palette.h @@ -165,6 +165,11 @@ public: void setPalette(const byte *colors, uint start, uint num); /** + * Set a palette entry + */ + void setEntry(byte palIndex, byte r, byte g, byte b); + + /** * Returns a subset of the currently loaded palette */ void grabPalette(byte *colors, uint start, uint num); diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp index aa15f665f4..23360b0a00 100644 --- a/engines/mads/sprites.cpp +++ b/engines/mads/sprites.cpp @@ -149,6 +149,20 @@ SpriteSlot::SpriteSlot(SpriteType type, int seqIndex) { _scale = 0; } +bool SpriteSlot::operator==(const SpriteSlotSubset &other) const { + return (_spritesIndex == other._spritesIndex) && (_frameNumber == other._frameNumber) && + (_position == other._position) && (_depth == other._depth) && + (_scale == other._scale); +} + +void SpriteSlot::copy(const SpriteSlotSubset &other) { + _spritesIndex = other._spritesIndex; + _frameNumber = other._frameNumber; + _position = other._position; + _depth = other._depth; + _scale = other._scale; +} + /*------------------------------------------------------------------------*/ SpriteSlots::SpriteSlots(MADSEngine *vm) : _vm(vm) { diff --git a/engines/mads/sprites.h b/engines/mads/sprites.h index f9ae46ad9b..49f13add21 100644 --- a/engines/mads/sprites.h +++ b/engines/mads/sprites.h @@ -139,6 +139,8 @@ public: SpriteSlot(SpriteType type, int seqIndex); void setup(int dirtyAreaIndex); + bool operator==(const SpriteSlotSubset &other) const; + void copy(const SpriteSlotSubset &other); }; class SpriteSlots : public Common::Array<SpriteSlot> { |