diff options
Diffstat (limited to 'engines/m4/animation.cpp')
-rw-r--r-- | engines/m4/animation.cpp | 531 |
1 files changed, 132 insertions, 399 deletions
diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index 55566aad7e..fe46e121f0 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -26,448 +26,181 @@ #include "m4/assets.h" #include "m4/animation.h" #include "m4/compression.h" -#include "m4/mads_scene.h" namespace M4 { // TODO: this code needs cleanup -MadsAnimation::MadsAnimation(MadsM4Engine *vm, MadsView *view): Animation(vm), _view(view) { - _font = NULL; - _freeFlag = false; - _skipLoad = false; - _unkIndex = -1; - _messageCtr= 0; +Animation::Animation(MadsM4Engine *vm) { + _vm = vm; + _playing = false; } -MadsAnimation::~MadsAnimation() { - for (uint i = 0; i < _messages.size(); ++i) { - if (_messages[i].kernelMsgIndex >= 0) - _view->_kernelMessages.remove(_messages[i].kernelMsgIndex); - } - - // Further deletion logic - if (_field12) { - _view->_spriteSlots.deleteSprites(_spriteListIndexes[_spriteListIndex]); - } - - delete _font; +void Animation::loadFullScreen(const char *filename) { + _vm->_palette->deleteAllRanges(); + load(filename); } -/** - * Initialises and loads the data of an animation - */ -void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface) { - MadsPack anim(filename.c_str(), _vm); - bool madsRes = filename[0] == '*'; +void Animation::load(const char *filename) { + MadsPack anim(filename, _vm); char buffer[20]; - int streamIndex = 1; // Chunk 1: header // header - + // TODO: there are some unknown fields here, plus we don't read + // the entire chunk Common::SeekableReadStream *animStream = anim.getItemStream(0); + Common::SeekableReadStream *spriteSeriesStream; + //printf("Chunk 0, size %i\n", animStream->size()); + _seriesCount = animStream->readUint16LE(); + _frameCount = animStream->readUint16LE(); + _frameEntryCount = animStream->readUint16LE(); - int spriteListCount = animStream->readUint16LE(); - int miscEntriesCount = animStream->readUint16LE(); - int frameEntryCount = animStream->readUint16LE(); - int messagesCount = animStream->readUint16LE(); - animStream->skip(1); - _flags = animStream->readByte(); - - animStream->skip(2); - _animMode = animStream->readUint16LE(); - _roomNumber = animStream->readUint16LE(); - animStream->skip(2); - _field12 = animStream->readUint16LE() != 0; - _spriteListIndex = animStream->readUint16LE(); - _scrollX = animStream->readUint16LE(); - _scrollY = animStream->readSint16LE(); - animStream->skip(10); - - animStream->read(buffer, 13); - _interfaceFile = Common::String(buffer, 13); - - for (int i = 0; i < 10; ++i) { - animStream->read(buffer, 13); - _spriteSetNames[i] = Common::String(buffer, 13); - } - - animStream->skip(81); - animStream->read(buffer, 13); - _lbmFilename = Common::String(buffer, 13); - animStream->read(buffer, 13); - _spritesFilename = Common::String(buffer, 13); - animStream->skip(48); - animStream->read(buffer, 13); - _soundName = Common::String(buffer, 13); - animStream->skip(26); - animStream->read(buffer, 13); - Common::String fontResource(buffer, 13); - - if (_animMode == 4) - flags |= 0x4000; - if (flags & 0x100) - loadInterface(interfaceSurface, sceneSurface); - - // Initialise the reference list - for (int i = 0; i < spriteListCount; ++i) - _spriteListIndexes.push_back(-1); - - delete animStream; - - if (messagesCount > 0) { - // Chunk 2 - // Following is a list of any messages for the animation - - animStream = anim.getItemStream(streamIndex++); - - for (int i = 0; i < messagesCount; ++i) { - AnimMessage rec; - animStream->read(rec.msg, 70); - rec.pos.x = animStream->readUint16LE(); - rec.pos.y = animStream->readUint16LE(); - animStream->readUint16LE(); - rec.rgb1.r = animStream->readByte(); - rec.rgb1.g = animStream->readByte(); - rec.rgb1.b = animStream->readByte(); - rec.rgb2.r = animStream->readByte(); - rec.rgb2.g = animStream->readByte(); - rec.rgb2.b = animStream->readByte(); - rec.kernelMsgIndex = animStream->readUint16LE(); - animStream->skip(6); - rec.startFrame = animStream->readUint16LE(); - rec.endFrame = animStream->readUint16LE(); - animStream->readUint16LE(); - - _messages.push_back(rec); - } - - delete animStream; - } - - if (frameEntryCount > 0) { - // Chunk 3: animation frame info - animStream = anim.getItemStream(streamIndex++); - - for (int i = 0; i < frameEntryCount; i++) { - AnimFrameEntry rec; - rec.frameNumber = animStream->readUint16LE(); - rec.seqIndex = animStream->readByte(); - rec.spriteSlot.spriteListIndex = animStream->readByte(); - rec.spriteSlot.frameNumber = animStream->readUint16LE(); - rec.spriteSlot.xp = animStream->readUint16LE(); - rec.spriteSlot.yp = animStream->readUint16LE(); - rec.spriteSlot.depth = animStream->readByte(); - rec.spriteSlot.scale = animStream->readByte(); - - _frameEntries.push_back(rec); - } - - delete animStream; - } + // Unknown + for (int i = 0; i < 43; i++) + animStream->readByte(); - if (miscEntriesCount > 0) { - // Chunk 4: Misc Data - animStream = anim.getItemStream(streamIndex); + _spriteSeriesNames = new Common::String[_seriesCount]; + printf("%i sprite series\n", _seriesCount); - for (int i = 0; i < miscEntriesCount; ++i) { - AnimMiscEntry rec; - rec.soundNum = animStream->readByte(); - animStream->skip(1); - rec.numTicks = animStream->readUint16LE(); - rec.posAdjust.x = animStream->readUint16LE(); - rec.posAdjust.y = animStream->readUint16LE(); - animStream->readUint16LE(); + // TODO: for now, we only load the first sprite series + if (_seriesCount > 1) + printf("TODO: Anim has %i sprite series, for now, we only load the first one\n", _seriesCount); + _seriesCount = 1; // TODO - _miscEntries.push_back(rec); + for (int i = 0; i < _seriesCount; i++) { + animStream->read(buffer, 13); + _spriteSeriesNames[i] = Common::String(buffer); + //printf("%03d: %s\n", i, _spriteSeriesNames[i].c_str()); + + spriteSeriesStream = _vm->res()->get(_spriteSeriesNames[i].c_str()); + _spriteSeries = new SpriteAsset(_vm, spriteSeriesStream, + spriteSeriesStream->size(), _spriteSeriesNames[i].c_str()); + _vm->res()->toss(_spriteSeriesNames[i].c_str()); + + // Adjust the palette of the sprites in the sprite series + // so that they can be displayed on screen correctly + RGBList *palData = new RGBList(_spriteSeries->getColorCount(), _spriteSeries->getPalette(), true); + _vm->_palette->addRange(palData); + + for (int k = 0; k < _spriteSeries->getCount(); k++) { + M4Sprite *spr = _spriteSeries->getFrame(k); + spr->translate(palData); // sprite pixel translation } - - delete animStream; } - // If the animation specifies a font, then load it for access - if (_flags & ANIM_CUSTOM_FONT) { - Common::String fontName; - if (madsRes) - fontName += "*"; - fontName += fontResource; - - _font = _vm->_font->getFont(fontName); - } - - // Load all the sprite sets for the animation - for (int i = 0; i < spriteListCount; ++i) { - _spriteListIndexes[i] = _view->_spriteSlots.addSprites(_spriteSetNames[i].c_str()); - } + //printf("End pos: %i\n", animStream->pos()); + delete animStream; - if (_field12) { - Common::String resName; - if (madsRes) - resName += "*"; - resName += _spriteSetNames[_spriteListIndex]; - - _spriteListIndexes[_spriteListIndex] = _view->_spriteSlots.addSprites(resName.c_str()); - } + // ------------------ + + // Chunk 2: anim info + AnimationFrame frame; + animStream = anim.getItemStream(1); + //printf("Chunk 1, size %i\n", animStream->size()); + + _frameEntries = new AnimationFrame[_frameEntryCount]; + + for (int i = 0; i < _frameEntryCount; i++) { + + frame.animFrameIndex = animStream->readUint16LE(); + frame.u = animStream->readByte(); + frame.seriesIndex = animStream->readByte(); + frame.seriesFrameIndex = animStream->readUint16LE(); + frame.x = animStream->readUint16LE(); + frame.y = animStream->readUint16LE(); + frame.v = animStream->readByte(); + frame.w = animStream->readByte(); + + _frameEntries[i] = frame; + + /* + printf( + "animFrameIndex = %4d, " + "u = %3d, " + "seriesIndex = %3d, " + "seriesFrameIndex = %6d, " + "x = %3d, " + "y = %3d, " + "v = %3d, " + "w = %3d\n", + + frame.animFrameIndex, + frame.u, + frame.seriesIndex, + frame.seriesFrameIndex, + frame.x, + frame.y, + frame.v, + frame.w + ); + */ + } + //printf("End pos: %i\n", animStream->pos()); - // TODO: Unknown section about handling palette entries - I think it's adjusting sprite sets - // to the palette of the game screen + delete animStream; - // Process the sprite list indexes to remap them to the actual sprite list indexes - + // Chunk 3: unknown (seems to be sound data?) + // TODO } -/** - * Loads an animation file for display - */ -void MadsAnimation::load(const Common::String &filename, int abortTimers) { - initialise(filename, 0, NULL, NULL); - _messageCtr = 0; - _skipLoad = true; - - if (_field12) { - _unkIndex = -1; - int listIndex = _spriteListIndexes[_spriteListIndex]; - SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(listIndex); -warning("%d", spriteSet.getCount()); - } - - // Initialise miscellaneous fields - _currentFrame = 0; - _oldFrameEntry = 0; - _nextFrameTimer = _madsVm->_currentTimer; - _abortTimers = abortTimers; - _abortMode = _madsVm->scene()->_abortTimersMode2; - - for (int i = 0; i < 3; ++i) - _actionNouns[i] = _madsVm->scene()->actionNouns[i]; +Animation::~Animation() { + //delete[] _spriteSeriesNames; + //delete[] _spriteSeries; + //delete[] _frameEntries; +} - // Initialise kernel message list - for (uint i = 0; i < _messages.size(); ++i) - _messages[i].kernelMsgIndex = -1; +void Animation::start() { + _curFrame = 0; + _curFrameEntry = 0; + //for (int i = 0; i < _seriesCount; i++) { + //_spriteSeries[i] = new SpriteSeries((char*)_spriteSeriesNames[i].c_str()); + //} + _playing = true; + updateAnim(); } -void MadsAnimation::update() { - if (_field12) { - int spriteListIndex = _spriteListIndexes[_spriteListIndex]; - int newIndex = -1; - - for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) { - if (_frameEntries[idx].frameNumber > _currentFrame) - break; - if (_frameEntries[idx].spriteSlot.spriteListIndex == spriteListIndex) - newIndex = _frameEntries[idx].spriteSlot.frameNumber; - } +bool Animation::updateAnim() { + if (!_playing) + return true; - if (newIndex >= 0) - load1(newIndex); - } + // Get the scene background surface + M4Surface *bg = _vm->_scene->getBackgroundSurface(); - // If it's not time for the next frame, then exit - if (_madsVm->_currentTimer < _nextFrameTimer) - return; + while (_frameEntries[_curFrameEntry].animFrameIndex == _curFrame) { + AnimationFrame *frame = &_frameEntries[_curFrameEntry]; + int seriesFrameIndex = (frame->seriesFrameIndex & 0x7FFF) - 1; - // Loop checks for any prior animation sprite slots to be expired - for (int slotIndex = 0; slotIndex < _view->_spriteSlots.startIndex; ++slotIndex) { - if ((_view->_spriteSlots[slotIndex].seqIndex >= 0x80) && - (_view->_spriteSlots[slotIndex].seqIndex <= 0xFD)) { - // Flag the frame as animation sprite slot - _view->_spriteSlots[slotIndex].spriteType = EXPIRED_SPRITE; - } - } + // Write the sprite onto the screen + M4Sprite *spr = _spriteSeries->getFrame(seriesFrameIndex); - // 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 starting any sound for this frame - AnimMiscEntry &misc = _miscEntries[_currentFrame]; - if (misc.soundNum) - _vm->_sound->playSound(misc.soundNum); + // FIXME: correct x, y + spr->copyTo(bg, frame->x, frame->y, (int)spr->getTransparentColor()); - bool screenChanged = false; + // HACK: wait a bit + g_system->delayMillis(100); - // Handle any scrolling of the screen surface - if ((_scrollX != 0) || (_scrollY != 0)) { - _view->_bgSurface->scrollX(_scrollX); - _view->_bgSurface->scrollY(_scrollY); - - screenChanged = true; + //printf("_curFrameEntry = %d\n", _curFrameEntry); + _curFrameEntry++; } - // Handle any offset adjustment for sprites as of this frame - if (_view->_posAdjust.x != misc.posAdjust.x) { - misc.posAdjust.x = _view->_posAdjust.x; - screenChanged = true; - } - if (_view->_posAdjust.y != misc.posAdjust.y) { - misc.posAdjust.y = _view->_posAdjust.y; - screenChanged = true; - } - if (screenChanged) { - // Signal the entire screen needs refreshing - _view->_spriteSlots.fullRefresh(); - } + //printf("_curFrame = %d\n", _curFrame); - int spriteSlotsMax = _view->_spriteSlots.startIndex; - - // 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 < spriteSlotsMax)) { - int seqIndex = _frameEntries[_oldFrameEntry].seqIndex - _view->_spriteSlots[index].seqIndex; - if (seqIndex == 0x80) { - if (_view->_spriteSlots[index] == _frameEntries[_oldFrameEntry].spriteSlot) - _view->_spriteSlots[index].spriteType = SPRITE_ZERO; - } - ++index; - continue; - } - - if (spriteSlotIndex == 0) { - int slotIndex = _view->_spriteSlots.getIndex(); - _view->_spriteSlots[slotIndex].copy(_frameEntries[_oldFrameEntry].spriteSlot); - _view->_spriteSlots[slotIndex].seqIndex += 0x80; - - SpriteAsset &spriteSet = _view->_spriteSlots.getSprite( - _view->_spriteSlots[slotIndex].spriteListIndex); - - _view->_spriteSlots[slotIndex].spriteType = (spriteSet.getAssetType() == 0) ? - SPRITE_FOUR : SPRITE_ZERO; - } - 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)) { - _view->_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 colour 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.r, me.rgb1.g, me.rgb1.b); - _vm->_palette->setEntry(colIndex + 1, me.rgb2.r, me.rgb2.g, me.rgb2.b); - - // Add a kernel message to display the given text - me.kernelMsgIndex = _view->_kernelMessages.add(me.pos, colIndex * 101, 0, 0, INDEFINITE_TIMEOUT, me.msg); - ++_messageCtr; - } - } - - // Move to the next frame - _currentFrame++; - if (_currentFrame >= (int)_miscEntries.size()) { - // Animation is complete - if (_abortTimers != 0) { - _view->_abortTimers = _abortTimers; - _view->_abortTimersMode = _abortMode; - - if (_abortMode != ABORTMODE_1) { - // Copy the noun list - for (int i = 0; i < 3; ++i) - _madsVm->scene()->actionNouns[i] = _actionNouns[i]; - } - } - } + _curFrame++; + if (_curFrame >= _frameCount) // anim done + stop(); - int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1); - _nextFrameTimer = _madsVm->_currentTimer + _miscEntries[frameNum].numTicks; + return _curFrame >= _frameCount; } -void MadsAnimation::setCurrentFrame(int frameNumber) { - _currentFrame = frameNumber; - _oldFrameEntry = 0; - _freeFlag = false; -} - -void MadsAnimation::load1(int frameNumber) { - if (_skipLoad) - return; - - Common::Point pt; - int listIndex = _spriteListIndexes[_spriteListIndex]; - SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(listIndex); - - if (_unkIndex < 0) { - M4Surface *frame = spriteSet.getFrame(0); - pt.x = frame->bounds().left; - pt.y = frame->bounds().top; - } else { - pt.x = _unkList[_unkIndex].x; - pt.y = _unkList[_unkIndex].y; - _unkIndex = 1 - _unkIndex; - } - - if (proc1(spriteSet, pt, frameNumber)) - error("proc1 failure"); -} - -bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber) { - return 0; -} +void Animation::stop() { + _playing = false; -void MadsAnimation::loadInterface(M4Surface *&interfaceSurface, M4Surface *&depthSurface) { - if (_animMode <= 2) { - MadsSceneResources sceneResources; - sceneResources.load(_roomNumber, _interfaceFile.c_str(), 0, depthSurface, interfaceSurface); - - // Rex only supports a single dialog draw style - assert(sceneResources.drawStyle == 2); - - } else if (_animMode == 4) { - // Load a scene interface - interfaceSurface->madsLoadInterface(_interfaceFile); - } else { - // This mode allocates two large surfaces for the animation - // TODO: Are these ever properly freed? -error("Anim mode %d - need to check free logic", _animMode); - assert(!interfaceSurface); - assert(!depthSurface); - depthSurface = new M4Surface(MADS_SURFACE_WIDTH, MADS_SCREEN_HEIGHT); - interfaceSurface = new M4Surface(MADS_SURFACE_WIDTH, MADS_SCREEN_HEIGHT); - depthSurface->clear(); - interfaceSurface->clear(); + for (int i = 0; i < _seriesCount; i++) { + // TODO: cleanup + //delete _spriteSeries[i]; + //_spriteSeries[i] = NULL; } } |