mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 05:38:56 +00:00
798 lines
22 KiB
C++
798 lines
22 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*
|
|
* This file is dual-licensed.
|
|
* In addition to the GPLv3 license mentioned above, MojoTouch has
|
|
* exclusively licensed this code on March 23th, 2024, to be used in
|
|
* closed-source products.
|
|
* Therefore, any contributions (commits) to it will also be dual-licensed.
|
|
*
|
|
*/
|
|
|
|
#include "common/debug.h"
|
|
#include "common/rect.h"
|
|
|
|
#include "toon/anim.h"
|
|
#include "toon/toon.h"
|
|
#include "toon/tools.h"
|
|
|
|
namespace Toon {
|
|
|
|
bool Animation::loadAnimation(const Common::String &file) {
|
|
debugC(1, kDebugAnim, "loadAnimation(%s)", file.c_str());
|
|
|
|
uint32 fileSize = 0;
|
|
uint8 *fileData = _vm->resources()->getFileData(Common::Path(file), &fileSize);
|
|
if (!fileData)
|
|
return false;
|
|
|
|
Common::strlcpy(_name, "not_loaded", sizeof(_name));
|
|
if (!Common::String((char *)fileData, 12).equals("KevinAguilar"))
|
|
return false;
|
|
|
|
Common::strlcpy(_name, file.c_str(), sizeof(_name));
|
|
|
|
_shadowFlag = Common::String(_name).contains("SHADOW");
|
|
|
|
uint32 headerSize = READ_LE_UINT32(fileData + 16);
|
|
uint32 uncompressedBytes = READ_LE_UINT32(fileData + 20);
|
|
uint32 compressedBytes = READ_LE_UINT32(fileData + 24);
|
|
_numFrames = READ_LE_UINT32(fileData + 28);
|
|
_x1 = READ_LE_UINT32(fileData + 32);
|
|
_y1 = READ_LE_UINT32(fileData + 36);
|
|
_x2 = READ_LE_UINT32(fileData + 40);
|
|
_y2 = READ_LE_UINT32(fileData + 44);
|
|
_paletteEntries = READ_LE_UINT32(fileData + 56);
|
|
// CHECKME: Useless variable _fps
|
|
_fps = READ_LE_UINT32(fileData + 60);
|
|
uint32 paletteSize = READ_LE_UINT32(fileData + 64);
|
|
|
|
uint8 *currentData = fileData + 68;
|
|
if (_paletteEntries) {
|
|
if (paletteSize) {
|
|
delete[] _palette;
|
|
_palette = new uint8[paletteSize];
|
|
memcpy(_palette, currentData, paletteSize);
|
|
currentData += paletteSize;
|
|
} else {
|
|
_palette = 0;
|
|
}
|
|
}
|
|
|
|
byte *finalBuffer = new byte[uncompressedBytes];
|
|
if (uncompressedBytes > compressedBytes)
|
|
decompressLZSS(currentData, finalBuffer, uncompressedBytes);
|
|
else
|
|
memcpy(finalBuffer, currentData, uncompressedBytes);
|
|
|
|
if (READ_LE_UINT32(finalBuffer) == 0x12345678) {
|
|
uint8 *data = finalBuffer;
|
|
delete[] _frames;
|
|
_frames = new AnimationFrame[_numFrames];
|
|
for (int32 e = 0; e < _numFrames; e++) {
|
|
if (READ_LE_UINT32(data) != 0x12345678) {
|
|
delete[] finalBuffer;
|
|
return false;
|
|
}
|
|
|
|
int32 oldRef = READ_LE_UINT32(data + 4);
|
|
uint32 compressedSize = READ_LE_UINT32(data + 8);
|
|
uint32 decompressedSize = READ_LE_UINT32(data + 12);
|
|
|
|
_frames[e]._x1 = READ_LE_UINT32(data + 16);
|
|
_frames[e]._y1 = READ_LE_UINT32(data + 20);
|
|
_frames[e]._x2 = READ_LE_UINT32(data + 24);
|
|
_frames[e]._y2 = READ_LE_UINT32(data + 28);
|
|
|
|
uint8 *imageData = data + headerSize;
|
|
uint32 decompressedLZSSDataSize = 0;
|
|
_frames[e]._dataSize = 0;
|
|
if (oldRef != -1 || decompressedSize == 0) {
|
|
_frames[e]._ref = oldRef;
|
|
_frames[e]._data = nullptr;
|
|
_frames[e]._dataSize = 0;
|
|
} else {
|
|
_frames[e]._ref = -1;
|
|
_frames[e]._data = new uint8[decompressedSize];
|
|
if (compressedSize < decompressedSize) {
|
|
decompressedLZSSDataSize = decompressLZSS(imageData, _frames[e]._data, decompressedSize);
|
|
// assert(decompressedSize == decompressedLZSSDataSize);
|
|
_frames[e]._dataSize = decompressedLZSSDataSize;
|
|
} else {
|
|
memcpy(_frames[e]._data, imageData, compressedSize);
|
|
_frames[e]._dataSize = compressedSize;
|
|
}
|
|
}
|
|
|
|
data += headerSize + compressedSize;
|
|
}
|
|
}
|
|
|
|
_vm->resources()->purgeFileData();
|
|
delete[] finalBuffer;
|
|
return true;
|
|
}
|
|
|
|
Animation::Animation(ToonEngine *vm) : _vm(vm) {
|
|
_palette = nullptr;
|
|
_numFrames = 0;
|
|
_frames = nullptr;
|
|
memset(_name, 0, sizeof(_name));
|
|
_shadowFlag = false;
|
|
|
|
_x1 = _y1 = _x2 = _y2 = 0;
|
|
_fps = 0;
|
|
_paletteEntries = 0;
|
|
}
|
|
|
|
Animation::~Animation() {
|
|
delete[] _palette;
|
|
for (int32 i = 0; i < _numFrames; i++) {
|
|
delete[] _frames[i]._data;
|
|
}
|
|
delete[] _frames;
|
|
}
|
|
|
|
Common::Rect Animation::getRect() {
|
|
debugC(5, kDebugAnim, "getRect");
|
|
return Common::Rect(_x1, _y1, _x2, _y2);
|
|
}
|
|
|
|
void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy) {
|
|
debugC(3, kDebugAnim, "drawFrame(surface, %d, %d, %d)", frame, xx, yy);
|
|
if (frame < 0)
|
|
frame = 0;
|
|
|
|
if (frame >= _numFrames)
|
|
frame = _numFrames - 1;
|
|
|
|
if (_numFrames == 0)
|
|
return;
|
|
|
|
int16 dataFrame = frame;
|
|
|
|
if (_frames[frame]._ref != -1)
|
|
dataFrame = _frames[frame]._ref;
|
|
|
|
if (!_frames[dataFrame]._data)
|
|
return;
|
|
|
|
int16 rectX = _frames[frame]._x2 - _frames[frame]._x1;
|
|
int16 rectY = _frames[frame]._y2 - _frames[frame]._y1;
|
|
int16 offsX = 0;
|
|
int16 offsY = 0;
|
|
|
|
_vm->addDirtyRect(xx + _x1 + _frames[frame]._x1, yy + _y1 + _frames[frame]._y1, xx + rectX + _x1 + _frames[frame]._x1 , yy + rectY + _y1 + _frames[frame]._y1);
|
|
|
|
if (xx + _x1 + _frames[frame]._x1 < 0) {
|
|
offsX = -(xx + _x1 + _frames[frame]._x1);
|
|
}
|
|
|
|
if (offsX >= rectX)
|
|
return;
|
|
else
|
|
rectX -= offsX;
|
|
|
|
if (yy + _y1 + _frames[frame]._y1 < 0) {
|
|
offsY = -(yy + _y1 + _frames[frame]._y1);
|
|
}
|
|
|
|
if (offsY >= rectY)
|
|
return;
|
|
else
|
|
rectY -= offsY;
|
|
|
|
if (rectX + xx + _x1 + _frames[frame]._x1 >= surface.w)
|
|
rectX = surface.w - xx - _x1 - _frames[frame]._x1;
|
|
|
|
if (rectX < 0)
|
|
return;
|
|
|
|
if (rectY + yy + _y1 + _frames[frame]._y1 >= surface.h)
|
|
rectY = surface.h - yy - _y1 - _frames[frame]._y1;
|
|
|
|
if (rectY < 0)
|
|
return;
|
|
|
|
int32 destPitch = surface.pitch;
|
|
uint8 *srcRow = _frames[dataFrame]._data + offsX + (_frames[frame]._x2 - _frames[frame]._x1) * offsY;
|
|
uint8 *curRow = (uint8 *)surface.getBasePtr(xx + _x1 + _frames[frame]._x1 + offsX, yy + _frames[frame]._y1 + _y1 + offsY);
|
|
for (int16 y = 0; y < rectY; y++) {
|
|
uint8 *cur = curRow;
|
|
uint8 *c = srcRow + y * (_frames[frame]._x2 - _frames[frame]._x1);
|
|
for (int16 x = 0; x < rectX; x++) {
|
|
if (*c)
|
|
*cur = *c;
|
|
c++;
|
|
cur++;
|
|
}
|
|
curRow += destPitch;
|
|
}
|
|
}
|
|
|
|
void Animation::drawFrameWithMask(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask) {
|
|
debugC(1, kDebugAnim, "drawFrameWithMask(surface, %d, %d, %d, %d, mask)", frame, xx, yy, zz);
|
|
warning("STUB: drawFrameWithMask()");
|
|
}
|
|
|
|
void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, int32 zz, Picture *mask, int32 scale) {
|
|
debugC(5, kDebugAnim, "drawFrameWithMaskAndScale(surface, %d, %d, %d, %d, mask, %d, %s)", frame, xx, yy, zz, scale, _name);
|
|
// assert(frame < _numFrames && frame >= 0);
|
|
|
|
// TODO Why do we go to int16 here from int32?
|
|
int16 dataFrame = frame;
|
|
|
|
if (_frames[frame]._ref != -1)
|
|
dataFrame = _frames[frame]._ref;
|
|
|
|
// assert(dataFrame < _numFrames && dataFrame >= 0);
|
|
int16 rectX = _frames[frame]._x2 - _frames[frame]._x1;
|
|
int16 rectY = _frames[frame]._y2 - _frames[frame]._y1;
|
|
|
|
int16 finalWidth = rectX * scale / 1024;
|
|
int16 finalHeight = rectY * scale / 1024;
|
|
|
|
// compute final x1, y1, x2, y2
|
|
int16 xx1 = xx + _x1 + _frames[frame]._x1 * scale / 1024;
|
|
int16 yy1 = yy + _y1 + _frames[frame]._y1 * scale / 1024;
|
|
int16 xx2 = xx1 + finalWidth;
|
|
int16 yy2 = yy1 + finalHeight;
|
|
int16 w = _frames[frame]._x2 - _frames[frame]._x1;
|
|
|
|
_vm->addDirtyRect(xx1, yy1, xx2, yy2);
|
|
|
|
int32 destPitch = surface.pitch;
|
|
// assert(mask != nullptr);
|
|
int32 destPitchMask = mask->getWidth();
|
|
// assert(_frames[dataFrame]._data != nullptr);
|
|
uint8 *c = _frames[dataFrame]._data;
|
|
uint8 *curRow = (uint8 *)surface.getPixels();
|
|
// assert(mask->getDataPtr() != nullptr);
|
|
uint8 *curRowMask = mask->getDataPtr();
|
|
const uint32 maskDataSize = mask->getWidth() * mask->getHeight();
|
|
|
|
for (int16 y = yy1; y < yy2; ++y) {
|
|
for (int16 x = xx1; x < xx2; ++x) {
|
|
if (x < 0 || x >= 1280 || y < 0 || y >= 400)
|
|
continue;
|
|
|
|
uint8 *cur = curRow + x + y * destPitch;
|
|
uint32 nextMaskPos = x + y * destPitchMask;
|
|
|
|
// find the good c
|
|
int16 xs = (x - xx1) * 1024 / scale;
|
|
int16 ys = (y - yy1) * 1024 / scale;
|
|
// TODO Maybe check if we overread c here
|
|
// assert(ys * w + xs >= 0 && ys * w + xs < _frames[dataFrame]._dataSize);
|
|
uint8 cc = c[ys * w + xs];
|
|
|
|
if (cc && nextMaskPos < maskDataSize && (*(curRowMask + nextMaskPos)) >= zz) {
|
|
if (_shadowFlag) {
|
|
*cur = _vm->getShadowLUT()[*cur];
|
|
} else {
|
|
*cur = cc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Animation::applyPalette(int32 offset, int32 srcOffset, int32 numEntries) {
|
|
debugC(1, kDebugAnim, "applyPalette(%d, %d, %d)", offset, srcOffset, numEntries);
|
|
_vm->setPaletteEntries(_palette + srcOffset, offset, numEntries);
|
|
}
|
|
|
|
Common::Rect Animation::getFrameRect(int32 frame) {
|
|
debugC(4, kDebugAnim, "getFrameRect(%d)", frame);
|
|
if ((frame < 0) || (frame >= _numFrames)) {
|
|
return Common::Rect();
|
|
}
|
|
|
|
if (_frames[frame]._ref != -1)
|
|
frame = _frames[frame]._ref;
|
|
|
|
return Common::Rect(_frames[frame]._x1, _frames[frame]._y1, _frames[frame]._x2, _frames[frame]._y2);
|
|
}
|
|
|
|
int16 Animation::getFrameWidth(int32 frame) {
|
|
debugC(4, kDebugAnim, "getFrameWidth(%d)", frame);
|
|
if ((frame < 0) || (frame >= _numFrames))
|
|
return 0;
|
|
|
|
return _frames[frame]._x2 - _frames[frame]._x1;
|
|
}
|
|
|
|
int16 Animation::getFrameHeight(int32 frame) {
|
|
debugC(4, kDebugAnim, "getFrameHeight(%d)", frame);
|
|
if (frame < 0 || frame >= _numFrames)
|
|
return 0;
|
|
|
|
return _frames[frame]._y2 - _frames[frame]._y1;
|
|
}
|
|
|
|
int16 Animation::getWidth() const {
|
|
return _x2 - _x1;
|
|
}
|
|
|
|
int16 Animation::getHeight() const {
|
|
return _y2 - _y1;
|
|
}
|
|
|
|
void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int16 xx, int16 yy, byte *colorMap) {
|
|
debugC(4, kDebugAnim, "drawFontFrame(surface, %d, %d, %d, colorMap)", frame, xx, yy);
|
|
if (frame < 0)
|
|
frame = 0;
|
|
|
|
if (frame >= _numFrames)
|
|
frame = _numFrames - 1;
|
|
|
|
if (_numFrames == 0)
|
|
return;
|
|
|
|
int16 dataFrame = frame;
|
|
|
|
if (_frames[frame]._ref != -1)
|
|
dataFrame = _frames[frame]._ref;
|
|
|
|
int16 rectX = _frames[frame]._x2 - _frames[frame]._x1;
|
|
int16 rectY = _frames[frame]._y2 - _frames[frame]._y1;
|
|
|
|
if ((xx + _x1 + _frames[frame]._x1 < 0) || (yy + _y1 + _frames[frame]._y1 < 0))
|
|
return;
|
|
|
|
if (rectX + xx + _x1 + _frames[frame]._x1 >= surface.w)
|
|
rectX = surface.w - xx - _x1 - _frames[frame]._x1;
|
|
|
|
if (rectX < 0)
|
|
return;
|
|
|
|
if (rectY + yy + _y1 + _frames[frame]._y1 >= surface.h)
|
|
rectY = surface.h - yy - _y1 - _frames[frame]._y1;
|
|
|
|
if (rectY < 0)
|
|
return;
|
|
|
|
int32 destPitch = surface.pitch;
|
|
uint8 *c = _frames[dataFrame]._data;
|
|
uint8 *curRow = (uint8 *)surface.getBasePtr(xx + _x1 + _frames[frame]._x1, yy + _frames[frame]._y1 + _y1);
|
|
for (int16 y = 0; y < rectY; y++) {
|
|
unsigned char *cur = curRow;
|
|
for (int16 x = 0; x < rectX; x++) {
|
|
if (*c && *c < 4)
|
|
*cur = colorMap[*c];
|
|
c++;
|
|
cur++;
|
|
}
|
|
curRow += destPitch;
|
|
}
|
|
}
|
|
|
|
void Animation::drawFrameOnPicture(int32 frame, int16 xx, int16 yy) {
|
|
debugC(1, kDebugAnim, "drawFrameOnPicture(%d, %d, %d)", frame, xx, yy);
|
|
if (frame < 0)
|
|
frame = 0;
|
|
|
|
if (frame >= _numFrames)
|
|
frame = _numFrames - 1;
|
|
|
|
if (_numFrames == 0)
|
|
return;
|
|
|
|
if (_frames[frame]._ref != -1)
|
|
frame = _frames[frame]._ref;
|
|
|
|
int16 rectX = _frames[frame]._x2 - _frames[frame]._x1;
|
|
int16 rectY = _frames[frame]._y2 - _frames[frame]._y1;
|
|
|
|
Picture *pic = _vm->getPicture();
|
|
|
|
if ((xx + _x1 + _frames[frame]._x1 < 0) || (yy + _y1 + _frames[frame]._y1 < 0))
|
|
return;
|
|
|
|
if (rectX + xx + _x1 + _frames[frame]._x1 >= pic->getWidth())
|
|
rectX = pic->getWidth() - xx - _x1 - _frames[frame]._x1;
|
|
|
|
if (rectX < 0)
|
|
return;
|
|
|
|
if (rectY + yy + _y1 + _frames[frame]._y1 >= pic->getHeight())
|
|
rectY = pic->getHeight() - yy - _y1 - _frames[frame]._y1;
|
|
|
|
if (rectY < 0)
|
|
return;
|
|
|
|
int32 destPitch = pic->getWidth();
|
|
uint8 *c = _frames[frame]._data;
|
|
uint8 *curRow = (uint8 *)pic->getDataPtr() + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1);
|
|
for (int16 y = 0; y < rectY; y++) {
|
|
unsigned char *cur = curRow;
|
|
for (int16 x = 0; x < rectX; x++) {
|
|
if (*c)
|
|
*cur = *c;
|
|
c++;
|
|
cur++;
|
|
}
|
|
curRow += destPitch;
|
|
}
|
|
}
|
|
|
|
void AnimationInstance::update(int32 timeIncrement) {
|
|
debugC(5, kDebugAnim, "update(%d)", timeIncrement);
|
|
if (_currentFrame == -1)
|
|
return;
|
|
|
|
if (_rangeStart == _rangeEnd) {
|
|
_currentFrame = _rangeStart;
|
|
return;
|
|
}
|
|
|
|
if (_playing) {
|
|
_currentTime += timeIncrement;
|
|
_currentFrame = _currentTime / (1000 / _fps);
|
|
}
|
|
|
|
if (_looping) {
|
|
_currentFrame = (_currentFrame % (_rangeEnd - _rangeStart + 1)) + _rangeStart;
|
|
} else {
|
|
if (_currentFrame >= _rangeEnd - _rangeStart) {
|
|
_playing = false;
|
|
_currentFrame = _rangeEnd;
|
|
} else {
|
|
_currentFrame = _rangeStart + _currentFrame;
|
|
}
|
|
}
|
|
}
|
|
|
|
AnimationInstance::AnimationInstance(ToonEngine *vm, AnimationInstanceType type) : _vm(vm) {
|
|
_id = 0;
|
|
_type = type;
|
|
_animation = nullptr;
|
|
_currentFrame = 0;
|
|
_currentTime = 0;
|
|
_fps = 15;
|
|
_looping = true;
|
|
_playing = false;
|
|
_rangeEnd = 0;
|
|
_useMask = false;
|
|
_alignBottom = false;
|
|
_rangeStart = 0;
|
|
_scale = 1024;
|
|
_x = 0;
|
|
_y = 0;
|
|
_z = 0;
|
|
_layerZ = 0;
|
|
_visible = false;
|
|
}
|
|
|
|
void AnimationInstance::render() {
|
|
debugC(5, kDebugAnim, "AnimationInstance::render()");
|
|
if (_visible && _animation != nullptr) {
|
|
int32 frame = _currentFrame;
|
|
if (frame < 0)
|
|
frame = 0;
|
|
|
|
if (frame >= _animation->_numFrames)
|
|
frame = _animation->_numFrames - 1;
|
|
|
|
int16 x = _x;
|
|
int16 y = _y;
|
|
|
|
if (_alignBottom) {
|
|
int32 offsetX = (_animation->_x2 - _animation->_x1) / 2 * (_scale - 1024);
|
|
int32 offsetY = (_animation->_y2 - _animation->_y1) * (_scale - 1024);
|
|
|
|
x -= offsetX >> 10;
|
|
y -= offsetY >> 10;
|
|
}
|
|
|
|
if (_useMask) {
|
|
//if (_scale == 100) { // 100% scale
|
|
// _animation->drawFrameWithMask(_vm->getMainSurface(), _currentFrame, _x, _y, _z, _vm->getMask());
|
|
//} else {
|
|
_animation->drawFrameWithMaskAndScale(_vm->getMainSurface(), frame, x, y, _z, _vm->getMask(), _scale);
|
|
//}
|
|
} else {
|
|
_animation->drawFrame(_vm->getMainSurface(), frame, _x, _y);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AnimationInstance::renderOnPicture() {
|
|
debugC(5, kDebugAnim, "renderOnPicture()");
|
|
if (_visible && _animation != nullptr)
|
|
_animation->drawFrameOnPicture(_currentFrame, _x, _y);
|
|
}
|
|
|
|
void AnimationInstance::playAnimation() {
|
|
debugC(6, kDebugAnim, "playAnimation()");
|
|
_playing = true;
|
|
}
|
|
|
|
void AnimationInstance::setAnimation(Animation *animation, bool setRange) {
|
|
debugC(5, kDebugAnim, "setAnimation(animation)");
|
|
_animation = animation;
|
|
if (animation && setRange) {
|
|
_rangeStart = 0;
|
|
_rangeEnd = animation->_numFrames - 1;
|
|
}
|
|
}
|
|
|
|
void AnimationInstance::setAnimationRange(int32 rangeStart, int32 rangeEnd) {
|
|
debugC(5, kDebugAnim, "setAnimationRange(%d, %d)", rangeStart, rangeEnd);
|
|
_rangeStart = rangeStart;
|
|
_rangeEnd = rangeEnd;
|
|
|
|
if (_currentFrame < _rangeStart)
|
|
_currentFrame = _rangeStart;
|
|
|
|
if (_currentFrame > _rangeEnd)
|
|
_currentFrame = _rangeEnd;
|
|
}
|
|
|
|
void AnimationInstance::setPosition(int16 x, int16 y, int32 z, bool relative) {
|
|
debugC(5, kDebugAnim, "setPosition(%d, %d, %d, %d)", x, y, z, (relative) ? 1 : 0);
|
|
if (relative || _animation == nullptr) {
|
|
_x = x;
|
|
_y = y;
|
|
_z = z;
|
|
} else {
|
|
_x = x - _animation->_x1;
|
|
_y = y - _animation->_y1;
|
|
_z = z;
|
|
}
|
|
}
|
|
|
|
void AnimationInstance::moveRelative(int16 dx, int16 dy, int32 dz) {
|
|
debugC(1, kDebugAnim, "moveRelative(%d, %d, %d)", dx, dy, dz);
|
|
_x += dx;
|
|
_y += dy;
|
|
_z += dz;
|
|
}
|
|
|
|
void AnimationInstance::forceFrame(int32 position) {
|
|
debugC(5, kDebugAnim, "forceFrame(%d)", position);
|
|
_currentFrame = position;
|
|
_rangeStart = position;
|
|
_rangeEnd = position;
|
|
}
|
|
|
|
void AnimationInstance::setFrame(int32 position) {
|
|
debugC(5, kDebugAnim, "setFrame(%d)", position);
|
|
_currentFrame = position;
|
|
}
|
|
|
|
void AnimationInstance::setFps(int32 fps) {
|
|
debugC(4, kDebugAnim, "setFps(%d)", fps);
|
|
_fps = fps;
|
|
}
|
|
|
|
void AnimationInstance::stopAnimation() {
|
|
debugC(5, kDebugAnim, "stopAnimation()");
|
|
_playing = false;
|
|
}
|
|
|
|
void AnimationInstance::setVisible(bool visible) {
|
|
debugC(1, kDebugAnim, "setVisible(%d)", (visible) ? 1 : 0);
|
|
_visible = visible;
|
|
}
|
|
|
|
void AnimationInstance::setScale(int32 scale, bool align) {
|
|
debugC(4, kDebugAnim, "setScale(%d)", scale);
|
|
_scale = scale;
|
|
_alignBottom = align;
|
|
}
|
|
|
|
void AnimationInstance::setUseMask(bool useMask) {
|
|
debugC(1, kDebugAnim, "setUseMask(%d)", (useMask) ? 1 : 0);
|
|
_useMask = useMask;
|
|
}
|
|
|
|
void AnimationInstance::getRect(int16 *x1, int16 *y1, int16 *x2, int16 *y2) const {
|
|
debugC(5, kDebugAnim, "getRect(%d, %d, %d, %d)", *x1, *y1, *x2, *y2);
|
|
int16 rectX = _animation->_frames[_currentFrame]._x2 - _animation->_frames[_currentFrame]._x1;
|
|
int16 rectY = _animation->_frames[_currentFrame]._y2 - _animation->_frames[_currentFrame]._y1;
|
|
|
|
int16 finalWidth = rectX * _scale / 1024;
|
|
int16 finalHeight = rectY * _scale / 1024;
|
|
|
|
// compute final x1, y1, x2, y2
|
|
*x1 = _x + _animation->_x1 + _animation->_frames[_currentFrame]._x1 * _scale / 1024;
|
|
*y1 = _y + _animation->_y1 + _animation->_frames[_currentFrame]._y1 * _scale / 1024;
|
|
*x2 = *x1 + finalWidth;
|
|
*y2 = *y1 + finalHeight;
|
|
}
|
|
|
|
void AnimationInstance::setX(int16 x, bool relative) {
|
|
debugC(1, kDebugAnim, "setX(%d, %d)", x, (relative) ? 1 : 0);
|
|
if (relative || _animation == nullptr)
|
|
_x = x;
|
|
else
|
|
_x = x - _animation->_x1;
|
|
}
|
|
|
|
void AnimationInstance::setY(int16 y, bool relative) {
|
|
debugC(1, kDebugAnim, "setY(%d, %d)", y, (relative) ? 1 : 0);
|
|
if (relative || _animation == nullptr)
|
|
_y = y;
|
|
else
|
|
_y = y - _animation->_y1;
|
|
}
|
|
|
|
void AnimationInstance::setZ(int32 z, bool relative) {
|
|
debugC(1, kDebugAnim, "setZ(%d, %d)", z, (relative) ? 1 : 0);
|
|
_z = z;
|
|
}
|
|
|
|
void AnimationInstance::setLayerZ(int32 z) {
|
|
_layerZ = z;
|
|
if (_vm->getAnimationManager()->hasInstance(this))
|
|
_vm->getAnimationManager()->updateInstance(this);
|
|
}
|
|
|
|
int32 AnimationInstance::getLayerZ() const {
|
|
return _layerZ;
|
|
}
|
|
|
|
int16 AnimationInstance::getX2() const {
|
|
return _x + _animation->_x1;
|
|
}
|
|
|
|
int16 AnimationInstance::getY2() const {
|
|
return _y + _animation->_y1;
|
|
}
|
|
|
|
int32 AnimationInstance::getZ2() const {
|
|
return _z;
|
|
}
|
|
|
|
void AnimationInstance::save(Common::WriteStream *stream) {
|
|
// we don't load the animation here
|
|
// it must be loaded externally to avoid leaks.
|
|
stream->writeSint32LE(_currentFrame);
|
|
stream->writeSint32LE(_currentTime);
|
|
stream->writeSint32LE(_layerZ);
|
|
stream->writeSint32LE(_x);
|
|
stream->writeSint32LE(_y);
|
|
stream->writeSint32LE(_z);
|
|
stream->writeSint32LE(_scale);
|
|
stream->writeSint32LE(_playing);
|
|
stream->writeSint32LE(_looping);
|
|
stream->writeSint32LE(_rangeStart);
|
|
stream->writeSint32LE(_rangeEnd);
|
|
stream->writeSint32LE(_rangeStart);
|
|
stream->writeSint32LE(_fps);
|
|
stream->writeSint32LE(_id);
|
|
stream->writeSint32LE(_type);
|
|
stream->writeSint32LE(_visible);
|
|
stream->writeSint32LE(_useMask);
|
|
}
|
|
|
|
void AnimationInstance::load(Common::ReadStream *stream) {
|
|
_currentFrame = stream->readSint32LE();
|
|
_currentTime = stream->readSint32LE();
|
|
_layerZ = stream->readSint32LE();
|
|
_x = stream->readSint32LE();
|
|
_y = stream->readSint32LE();
|
|
_z = stream->readSint32LE();
|
|
_scale = stream->readSint32LE();
|
|
_playing = stream->readSint32LE();
|
|
_looping = stream->readSint32LE();
|
|
_rangeStart = stream->readSint32LE();
|
|
_rangeEnd = stream->readSint32LE();
|
|
_rangeStart = stream->readSint32LE();
|
|
_fps = stream->readSint32LE();
|
|
_id = stream->readSint32LE();
|
|
_type = (AnimationInstanceType)stream->readSint32LE();
|
|
_visible = stream->readSint32LE();
|
|
_useMask = stream->readSint32LE();
|
|
}
|
|
|
|
void AnimationInstance::setLooping(bool enable) {
|
|
debugC(6, kDebugAnim, "setLooping(%d)", (enable) ? 1 : 0);
|
|
_looping = enable;
|
|
}
|
|
|
|
void AnimationInstance::reset() {
|
|
_currentFrame = 0;
|
|
_currentTime = 0;
|
|
}
|
|
|
|
AnimationManager::AnimationManager(ToonEngine *vm) : _vm(vm) {
|
|
}
|
|
|
|
bool AnimationManager::hasInstance(AnimationInstance* instance) {
|
|
for (uint32 i = 0; i < _instances.size(); i++) {
|
|
if (_instances[i] == instance)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void AnimationManager::updateInstance(AnimationInstance* instance) {
|
|
// simply remove and readd the instance in the ordered list
|
|
removeInstance(instance);
|
|
addInstance(instance);
|
|
}
|
|
|
|
void AnimationManager::addInstance(AnimationInstance *instance) {
|
|
// if the instance already exists, we skip the add
|
|
for (uint32 i = 0; i < _instances.size(); i++) {
|
|
if (_instances[i] == instance)
|
|
return;
|
|
}
|
|
|
|
int32 found = -1;
|
|
|
|
// here we now do an ordered insert (closer to the original game)
|
|
for (uint32 i = 0; i < _instances.size(); i++) {
|
|
if (_instances[i]->getLayerZ() >= instance->getLayerZ()) {
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found == -1)
|
|
_instances.push_back(instance);
|
|
else
|
|
_instances.insert_at(found, instance);
|
|
}
|
|
|
|
void AnimationManager::removeInstance(AnimationInstance *instance) {
|
|
debugC(1, kDebugAnim, "removeInstance(instance)");
|
|
int32 found = -1;
|
|
for (uint32 i = 0; i < _instances.size(); i++) {
|
|
if (_instances[i] == instance) {
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found > -1)
|
|
_instances.remove_at(found);
|
|
}
|
|
|
|
void AnimationManager::removeAllInstances(AnimationInstanceType type) {
|
|
debugC(1, kDebugAnim, "removeInstance(type)");
|
|
for (int32 i = (int32)_instances.size(); i >= 0; i--) {
|
|
if (_instances[i]->getType() & type)
|
|
_instances.remove_at(i);
|
|
}
|
|
}
|
|
|
|
void AnimationManager::update(int32 timeIncrement) {
|
|
debugC(5, kDebugAnim, "update(%d)", timeIncrement);
|
|
for (uint32 i = 0; i < _instances.size(); i++)
|
|
_instances[i]->update(timeIncrement);
|
|
}
|
|
|
|
void AnimationManager::render() {
|
|
debugC(5, kDebugAnim, "AnimationManager::render()");
|
|
for (uint32 i = 0; i < _instances.size(); i++) {
|
|
if (_instances[i]->getVisible())
|
|
_instances[i]->render();
|
|
}
|
|
}
|
|
|
|
AnimationInstance *AnimationManager::createNewInstance(AnimationInstanceType type) {
|
|
return new AnimationInstance(_vm, type);
|
|
}
|
|
|
|
} // End of namespace Toon
|