scummvm/engines/access/animation.cpp
2014-08-15 20:34:09 -04:00

345 lines
8.3 KiB
C++

/* 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/endian.h"
#include "common/memstream.h"
#include "access/access.h"
#include "access/animation.h"
namespace Access {
AnimationResource::AnimationResource(AccessEngine *vm, const byte *data, int size) {
Common::MemoryReadStream stream(data, size);
int count = stream.readUint16LE();
Common::Array<int> offsets;
for (int i = 0; i < count; ++i)
offsets.push_back(stream.readUint32LE());
_animations.reserve(count);
for (int i = 0; i < count; ++i) {
stream.seek(offsets[i]);
Animation *anim = new Animation(vm, stream);
_animations.push_back(anim);
}
}
AnimationResource::~AnimationResource() {
for (int i = 0; i < (int)_animations.size(); ++i)
delete _animations[i];
}
/*------------------------------------------------------------------------*/
Animation::Animation(AccessEngine *vm, Common::MemoryReadStream &stream):
Manager(vm) {
uint32 startOfs = stream.pos();
_type = stream.readByte();
_scaling = stream.readSByte();
stream.readByte(); // unk
_frameNumber = stream.readByte();
_initialTicks = stream.readUint16LE();
stream.readUint16LE(); // unk
stream.readUint16LE(); // unk
_loopCount = stream.readSint16LE();
_countdownTicks = stream.readUint16LE();
_currentLoopCount = stream.readSint16LE();
stream.readUint16LE(); // unk
Common::Array<uint16> frameOffsets;
uint16 ofs;
while ((ofs = stream.readUint16LE()) != 0)
frameOffsets.push_back(ofs);
for (int i = 0; i < (int)frameOffsets.size(); i++) {
stream.seek(startOfs + frameOffsets[i]);
AnimationFrame *frame = new AnimationFrame(stream, startOfs);
_frames.push_back(frame);
}
}
Animation::~Animation() {
for (int i = 0; i < (int)_frames.size(); ++i)
delete _frames[i];
}
typedef void(Animation::*AnimationMethodPtr)();
void Animation::animate() {
static const AnimationMethodPtr METHODS[8] =
{ &Animation::anim0, &Animation::anim1, &Animation::anim2, &Animation::anim3,
&Animation::anim4, &Animation::animNone, &Animation::animNone, &Animation::anim7 };
(this->*METHODS[_type])();
}
void Animation::anim0() {
if (_currentLoopCount != -1) {
if (_countdownTicks != 0) {
setFrame1(calcFrame());
} else {
_countdownTicks = _initialTicks;
++_frameNumber;
AnimationFrame *frame = calcFrame();
if (frame == nullptr) {
_frameNumber = 0;
_currentLoopCount = -1;
frame = calcFrame();
}
setFrame(frame);
}
}
}
void Animation::anim1() {
if (_currentLoopCount == -1 || _countdownTicks != 0) {
setFrame1(calcFrame());
} else {
_countdownTicks = _initialTicks;
++_frameNumber;
AnimationFrame *frame = calcFrame();
if (frame == nullptr) {
--_frameNumber;
_currentLoopCount = -1;
frame = calcFrame();
}
setFrame(frame);
}
}
void Animation::anim2() {
if (_countdownTicks != 0) {
setFrame1(calcFrame());
} else {
_countdownTicks = _initialTicks;
++_frameNumber;
AnimationFrame *frame = calcFrame();
if (frame == nullptr) {
_frameNumber = 0;
frame = calcFrame();
}
setFrame(frame);
}
}
void Animation::anim3() {
if (_currentLoopCount != -1) {
if (_countdownTicks != 0) {
setFrame1(calcFrame());
} else {
_countdownTicks = _initialTicks;
++_frameNumber;
AnimationFrame *frame = calcFrame();
if (frame == nullptr) {
--_currentLoopCount;
_frameNumber = 0;
frame = calcFrame();
}
setFrame(frame);
}
}
}
void Animation::anim4() {
if (_currentLoopCount == -1 || _countdownTicks != 0) {
setFrame1(calcFrame());
} else {
_countdownTicks = _initialTicks;
++_frameNumber;
AnimationFrame *frame = calcFrame();
if (frame == nullptr) {
if (--_currentLoopCount == -1) {
setFrame1(calcFrame());
return;
} else {
_frameNumber = 0;
frame = calcFrame();
}
}
setFrame(frame);
}
}
void Animation::animNone() {
// No implementation
}
void Animation::anim7() {
setFrame(calcFrame1());
}
AnimationFrame *Animation::calcFrame() {
return (_frameNumber < (int)_frames.size()) ? _frames[_frameNumber] : nullptr;
}
AnimationFrame *Animation::calcFrame1() {
return _frames[0];
}
void Animation::setFrame(AnimationFrame *frame) {
assert(frame);
_countdownTicks += frame->_frameDelay;
setFrame1(frame);
}
void Animation::setFrame1(AnimationFrame *frame) {
_vm->_animation->_base.x = frame->_baseX;
_vm->_animation->_base.y = frame->_baseY;
// Loop to add image draw requests for the parts of the frame
for (uint i = 0; i < frame->_parts.size(); ++i) {
AnimationFramePart *part = frame->_parts[i];
ImageEntry ie;
// Set the flags
ie._flags = part->_flags & 0xF7;
if (_vm->_animation->_frameScale == -1)
ie._flags |= 8;
// Set the other fields
ie._spritesPtr = _vm->_objectsTable[part->_spritesIndex];
ie._frameNumber = part->_frameIndex;
ie._position = part->_position + _vm->_animation->_base;
ie._priority = part->_priority - ie._position.y;
_vm->_images.addToList(&ie);
}
}
/*------------------------------------------------------------------------*/
AnimationFrame::AnimationFrame(Common::MemoryReadStream &stream, int startOffset) {
uint16 nextOffset;
stream.readByte(); // unk
_baseX = stream.readUint16LE();
_baseY = stream.readUint16LE();
_frameDelay = stream.readUint16LE();
nextOffset = stream.readUint16LE();
while (nextOffset != 0) {
stream.seek(startOffset + nextOffset);
AnimationFramePart *framePart = new AnimationFramePart(stream);
_parts.push_back(framePart);
nextOffset = stream.readUint16LE();
}
}
AnimationFrame::~AnimationFrame() {
for (int i = 0; i < (int)_parts.size(); ++i)
delete _parts[i];
}
/*------------------------------------------------------------------------*/
AnimationFramePart::AnimationFramePart(Common::MemoryReadStream &stream) {
_flags = stream.readByte();
_spritesIndex = stream.readByte();
_frameIndex = stream.readByte();
_position.x = stream.readUint16LE();
_position.y = stream.readUint16LE();
_priority = stream.readUint16LE();
}
/*------------------------------------------------------------------------*/
AnimationManager::AnimationManager(AccessEngine *vm) : Manager(vm) {
_animation = nullptr;
_animStart = nullptr;
_frameScale = 0;
}
AnimationManager::~AnimationManager() {
delete _animation;
}
void AnimationManager::freeAnimationData() {
delete _animation;
_animation = nullptr;
_animStart = nullptr;
}
void AnimationManager::clearTimers() {
for (uint i = 0; i < _animationTimers.size(); ++i)
delete _animationTimers[i];
_animationTimers.clear();
}
void AnimationManager::loadAnimations(const byte *data, int size) {
_animationTimers.clear();
delete _animation;
_animation = new AnimationResource(_vm, data, size);
}
Animation *AnimationManager::setAnimation(int animId) {
Animation *anim = findAnimation(animId);
anim->_countdownTicks = anim->_initialTicks;
anim->_frameNumber = 0;
anim->_currentLoopCount = (anim->_type != 3 && anim->_type != 4) ? 0 :
anim->_loopCount;
anim->_field10 = 0;
return anim;
}
void AnimationManager::setAnimTimer(Animation *anim) {
_animationTimers.push_back(anim);
}
Animation *AnimationManager::findAnimation(int animId) {
_animStart = _animation->getAnimation(animId);
return _animStart;
}
void AnimationManager::animate(int animId) {
Animation *anim = findAnimation(animId);
_frameScale = anim->_scaling;
anim->animate();
}
void AnimationManager::updateTimers() {
for (uint idx = 0; idx < _animationTimers.size(); ++idx) {
if (_animationTimers[idx]->_countdownTicks > 0)
_animationTimers[idx]->_countdownTicks--;
}
}
} // End of namespace Access