1
/* ScummVM - Graphic Adventure Engine
3
* ScummVM is the legal property of its developers, whose names
4
* are too numerous to list here. Please refer to the COPYRIGHT
5
* file distributed with this source distribution.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27
* This code is based on Broken Sword 2.5 engine
29
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
31
* Licensed under GNU GPL v2
35
#include "sword25/gfx/animation.h"
37
#include "sword25/kernel/kernel.h"
38
#include "sword25/kernel/resmanager.h"
39
#include "sword25/kernel/inputpersistenceblock.h"
40
#include "sword25/kernel/outputpersistenceblock.h"
41
#include "sword25/package/packagemanager.h"
42
#include "sword25/gfx/image/image.h"
43
#include "sword25/gfx/animationtemplate.h"
44
#include "sword25/gfx/animationtemplateregistry.h"
45
#include "sword25/gfx/animationresource.h"
46
#include "sword25/gfx/bitmapresource.h"
47
#include "sword25/gfx/graphicengine.h"
51
Animation::Animation(RenderObjectPtr<RenderObject> parentPtr, const Common::String &fileName) :
52
TimedRenderObject(parentPtr, RenderObject::TYPE_ANIMATION) {
53
// Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
59
// Vom negativen Fall ausgehen.
62
initializeAnimationResource(fileName);
64
// Erfolg signalisieren.
68
Animation::Animation(RenderObjectPtr<RenderObject> parentPtr, const AnimationTemplate &templ) :
69
TimedRenderObject(parentPtr, RenderObject::TYPE_ANIMATION) {
70
// Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
76
// Vom negativen Fall ausgehen.
79
_animationTemplateHandle = AnimationTemplate::create(templ);
81
// Erfolg signalisieren.
85
Animation::Animation(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
86
TimedRenderObject(parentPtr, RenderObject::TYPE_ANIMATION, handle) {
87
// Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
93
// Objekt vom Stream laden.
94
_initSuccess = unpersist(reader);
97
void Animation::initializeAnimationResource(const Common::String &fileName) {
98
// Die Resource wird fļæ½r die gesamte Lebensdauer des Animations-Objektes gelockt.
99
Resource *resourcePtr = Kernel::getInstance()->getResourceManager()->requestResource(fileName);
100
if (resourcePtr && resourcePtr->getType() == Resource::TYPE_ANIMATION)
101
_animationResourcePtr = static_cast<AnimationResource *>(resourcePtr);
103
error("The resource \"%s\" could not be requested. The Animation can't be created.", fileName.c_str());
107
// Grļæ½ļæ½e und Position der Animation anhand des aktuellen Frames bestimmen.
108
computeCurrentCharacteristics();
111
void Animation::initMembers() {
113
_currentFrameTime = 0;
114
_direction = FORWARD;
119
_scaleFactorX = 1.0f;
120
_scaleFactorY = 1.0f;
121
_modulationColor = 0xffffffff;
122
_animationResourcePtr = 0;
123
_animationTemplateHandle = 0;
124
_framesLocked = false;
127
Animation::~Animation() {
128
if (getAnimationDescription()) {
130
getAnimationDescription()->unlock();
133
// Invoke the "delete" callback
135
(_deleteCallback)(getHandle());
139
void Animation::play() {
140
// If the animation was completed, then play it again from the start.
148
void Animation::pause() {
153
void Animation::stop() {
155
_currentFrameTime = 0;
156
_direction = FORWARD;
160
void Animation::setFrame(uint nr) {
161
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
162
assert(animationDescriptionPtr);
164
if (nr >= animationDescriptionPtr->getFrameCount()) {
165
error("Tried to set animation to illegal frame (%d). Value must be between 0 and %d.",
166
nr, animationDescriptionPtr->getFrameCount());
171
_currentFrameTime = 0;
172
computeCurrentCharacteristics();
176
bool Animation::doRender() {
177
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
178
assert(animationDescriptionPtr);
179
assert(_currentFrame < animationDescriptionPtr->getFrameCount());
181
// Bitmap des aktuellen Frames holen
182
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(_currentFrame).fileName);
184
assert(pResource->getType() == Resource::TYPE_BITMAP);
185
BitmapResource *pBitmapResource = static_cast<BitmapResource *>(pResource);
187
// Framebufferobjekt holen
188
GraphicEngine *pGfx = Kernel::getInstance()->getGfx();
193
if (isScalingAllowed() && (_width != pBitmapResource->getWidth() || _height != pBitmapResource->getHeight())) {
194
result = pBitmapResource->blit(_absoluteX, _absoluteY,
195
(animationDescriptionPtr->getFrame(_currentFrame).flipV ? BitmapResource::FLIP_V : 0) |
196
(animationDescriptionPtr->getFrame(_currentFrame).flipH ? BitmapResource::FLIP_H : 0),
197
0, _modulationColor, _width, _height);
199
result = pBitmapResource->blit(_absoluteX, _absoluteY,
200
(animationDescriptionPtr->getFrame(_currentFrame).flipV ? BitmapResource::FLIP_V : 0) |
201
(animationDescriptionPtr->getFrame(_currentFrame).flipH ? BitmapResource::FLIP_H : 0),
202
0, _modulationColor, -1, -1);
205
// Resource freigeben
206
pBitmapResource->release();
211
void Animation::frameNotification(int timeElapsed) {
212
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
213
assert(animationDescriptionPtr);
214
assert(timeElapsed >= 0);
216
// Nur wenn die Animation lļæ½uft wird sie auch weiterbewegt
218
// Gesamte vergangene Zeit bestimmen (inkl. Restzeit des aktuellen Frames)
219
_currentFrameTime += timeElapsed;
221
// Anzahl an zu ļæ½berpringenden Frames bestimmen
222
int skipFrames = animationDescriptionPtr->getMillisPerFrame() == 0 ? 0 : _currentFrameTime / animationDescriptionPtr->getMillisPerFrame();
224
// Neue Frame-Restzeit bestimmen
225
_currentFrameTime -= animationDescriptionPtr->getMillisPerFrame() * skipFrames;
227
// Neuen Frame bestimmen (je nach aktuellener Abspielrichtung wird addiert oder subtrahiert)
228
int tmpCurFrame = _currentFrame;
229
switch (_direction) {
231
tmpCurFrame += skipFrames;
235
tmpCurFrame -= skipFrames;
242
// Deal with overflows
243
if (tmpCurFrame < 0) {
244
// Loop-Point callback
245
if (_loopPointCallback && !(_loopPointCallback)(getHandle()))
246
_loopPointCallback = 0;
248
// An underflow may only occur if the animation type is JOJO.
249
assert(animationDescriptionPtr->getAnimationType() == AT_JOJO);
250
tmpCurFrame = - tmpCurFrame;
251
_direction = FORWARD;
252
} else if (static_cast<uint>(tmpCurFrame) >= animationDescriptionPtr->getFrameCount()) {
253
// Loop-Point callback
254
if (_loopPointCallback && !(_loopPointCallback)(getHandle()))
255
_loopPointCallback = 0;
257
switch (animationDescriptionPtr->getAnimationType()) {
259
tmpCurFrame = animationDescriptionPtr->getFrameCount() - 1;
265
tmpCurFrame = tmpCurFrame % animationDescriptionPtr->getFrameCount();
269
tmpCurFrame = animationDescriptionPtr->getFrameCount() - (tmpCurFrame % animationDescriptionPtr->getFrameCount()) - 1;
270
_direction = BACKWARD;
278
if ((int)_currentFrame != tmpCurFrame) {
281
if (animationDescriptionPtr->getFrame(_currentFrame).action != "") {
283
if (_actionCallback && !(_actionCallback)(getHandle()))
288
_currentFrame = static_cast<uint>(tmpCurFrame);
291
// Grļæ½ļæ½e und Position der Animation anhand des aktuellen Frames bestimmen
292
computeCurrentCharacteristics();
294
assert(_currentFrame < animationDescriptionPtr->getFrameCount());
295
assert(_currentFrameTime >= 0);
298
void Animation::computeCurrentCharacteristics() {
299
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
300
assert(animationDescriptionPtr);
301
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
303
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
305
assert(pResource->getType() == Resource::TYPE_BITMAP);
306
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
308
// Grļæ½ļæ½e des Bitmaps auf die Animation ļæ½bertragen
309
_width = static_cast<int>(pBitmap->getWidth() * _scaleFactorX);
310
_height = static_cast<int>(pBitmap->getHeight() * _scaleFactorY);
312
// Position anhand des Hotspots berechnen und setzen
313
int posX = _relX + computeXModifier();
314
int posY = _relY + computeYModifier();
316
RenderObject::setPos(posX, posY);
321
bool Animation::lockAllFrames() {
322
if (!_framesLocked) {
323
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
324
assert(animationDescriptionPtr);
325
for (uint i = 0; i < animationDescriptionPtr->getFrameCount(); ++i) {
326
if (!Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(i).fileName)) {
327
error("Could not lock all animation frames.");
332
_framesLocked = true;
338
bool Animation::unlockAllFrames() {
340
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
341
assert(animationDescriptionPtr);
342
for (uint i = 0; i < animationDescriptionPtr->getFrameCount(); ++i) {
344
if (!(pResource = Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(i).fileName))) {
345
error("Could not unlock all animation frames.");
349
// Zwei mal freigeben um den Request von LockAllFrames() und den jetzigen Request aufzuheben
350
pResource->release();
351
if (pResource->getLockCount())
352
pResource->release();
355
_framesLocked = false;
361
Animation::ANIMATION_TYPES Animation::getAnimationType() const {
362
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
363
assert(animationDescriptionPtr);
364
return animationDescriptionPtr->getAnimationType();
367
int Animation::getFPS() const {
368
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
369
assert(animationDescriptionPtr);
370
return animationDescriptionPtr->getFPS();
373
int Animation::getFrameCount() const {
374
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
375
assert(animationDescriptionPtr);
376
return animationDescriptionPtr->getFrameCount();
379
bool Animation::isScalingAllowed() const {
380
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
381
assert(animationDescriptionPtr);
382
return animationDescriptionPtr->isScalingAllowed();
385
bool Animation::isAlphaAllowed() const {
386
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
387
assert(animationDescriptionPtr);
388
return animationDescriptionPtr->isAlphaAllowed();
391
bool Animation::isColorModulationAllowed() const {
392
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
393
assert(animationDescriptionPtr);
394
return animationDescriptionPtr->isColorModulationAllowed();
397
void Animation::setPos(int relX, int relY) {
401
computeCurrentCharacteristics();
404
void Animation::setX(int relX) {
407
computeCurrentCharacteristics();
410
void Animation::setY(int relY) {
413
computeCurrentCharacteristics();
416
void Animation::setAlpha(int alpha) {
417
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
418
assert(animationDescriptionPtr);
419
if (!animationDescriptionPtr->isAlphaAllowed()) {
420
warning("Tried to set alpha value on an animation that does not support alpha. Call was ignored.");
424
uint newModulationColor = (_modulationColor & 0x00ffffff) | alpha << 24;
425
if (newModulationColor != _modulationColor) {
426
_modulationColor = newModulationColor;
431
void Animation::setModulationColor(uint modulationColor) {
432
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
433
assert(animationDescriptionPtr);
434
if (!animationDescriptionPtr->isColorModulationAllowed()) {
435
warning("Tried to set modulation color on an animation that does not support color modulation. Call was ignored");
439
uint newModulationColor = (modulationColor & 0x00ffffff) | (_modulationColor & 0xff000000);
440
if (newModulationColor != _modulationColor) {
441
_modulationColor = newModulationColor;
446
void Animation::setScaleFactor(float scaleFactor) {
447
setScaleFactorX(scaleFactor);
448
setScaleFactorY(scaleFactor);
451
void Animation::setScaleFactorX(float scaleFactorX) {
452
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
453
assert(animationDescriptionPtr);
454
if (!animationDescriptionPtr->isScalingAllowed()) {
455
warning("Tried to set x scale factor on an animation that does not support scaling. Call was ignored");
459
if (scaleFactorX != _scaleFactorX) {
460
_scaleFactorX = scaleFactorX;
461
if (_scaleFactorX <= 0.0f)
462
_scaleFactorX = 0.001f;
464
computeCurrentCharacteristics();
468
void Animation::setScaleFactorY(float scaleFactorY) {
469
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
470
assert(animationDescriptionPtr);
471
if (!animationDescriptionPtr->isScalingAllowed()) {
472
warning("Tried to set y scale factor on an animation that does not support scaling. Call was ignored");
476
if (scaleFactorY != _scaleFactorY) {
477
_scaleFactorY = scaleFactorY;
478
if (_scaleFactorY <= 0.0f)
479
_scaleFactorY = 0.001f;
481
computeCurrentCharacteristics();
485
const Common::String &Animation::getCurrentAction() const {
486
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
487
assert(animationDescriptionPtr);
488
return animationDescriptionPtr->getFrame(_currentFrame).action;
491
int Animation::getX() const {
495
int Animation::getY() const {
499
int Animation::getAbsoluteX() const {
500
return _absoluteX + (_relX - _x);
503
int Animation::getAbsoluteY() const {
504
return _absoluteY + (_relY - _y);
507
int Animation::computeXModifier() const {
508
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
509
assert(animationDescriptionPtr);
510
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
512
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
514
assert(pResource->getType() == Resource::TYPE_BITMAP);
515
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
517
int result = curFrame.flipV ? - static_cast<int>((pBitmap->getWidth() - 1 - curFrame.hotspotX) * _scaleFactorX) :
518
- static_cast<int>(curFrame.hotspotX * _scaleFactorX);
525
int Animation::computeYModifier() const {
526
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
527
assert(animationDescriptionPtr);
528
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
530
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
532
assert(pResource->getType() == Resource::TYPE_BITMAP);
533
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
535
int result = curFrame.flipH ? - static_cast<int>((pBitmap->getHeight() - 1 - curFrame.hotspotY) * _scaleFactorY) :
536
- static_cast<int>(curFrame.hotspotY * _scaleFactorY);
543
bool Animation::persist(OutputPersistenceBlock &writer) {
546
result &= RenderObject::persist(writer);
550
writer.write(_scaleFactorX);
551
writer.write(_scaleFactorY);
552
writer.write(_modulationColor);
553
writer.write(_currentFrame);
554
writer.write(_currentFrameTime);
555
writer.write(_running);
556
writer.write(_finished);
557
writer.write(static_cast<uint>(_direction));
559
// Je nach Animationstyp entweder das Template oder die Ressource speichern.
560
if (_animationResourcePtr) {
562
writer.write(marker);
563
writer.writeString(_animationResourcePtr->getFileName());
564
} else if (_animationTemplateHandle) {
566
writer.write(marker);
567
writer.write(_animationTemplateHandle);
572
//writer.write(_AnimationDescriptionPtr);
574
writer.write(_framesLocked);
576
// The following is only there to for compatibility with older saves
577
// resp. the original engine.
578
writer.write((uint)1);
579
writer.writeString("LuaLoopPointCB");
580
writer.write(getHandle());
581
writer.write((uint)1);
582
writer.writeString("LuaActionCB");
583
writer.write(getHandle());
584
writer.write((uint)1);
585
writer.writeString("LuaDeleteCB");
586
writer.write(getHandle());
588
result &= RenderObject::persistChildren(writer);
593
// -----------------------------------------------------------------------------
595
bool Animation::unpersist(InputPersistenceBlock &reader) {
598
result &= RenderObject::unpersist(reader);
602
reader.read(_scaleFactorX);
603
reader.read(_scaleFactorY);
604
reader.read(_modulationColor);
605
reader.read(_currentFrame);
606
reader.read(_currentFrameTime);
607
reader.read(_running);
608
reader.read(_finished);
610
reader.read(direction);
611
_direction = static_cast<Direction>(direction);
613
// Animationstyp einlesen.
617
Common::String resourceFilename;
618
reader.readString(resourceFilename);
619
initializeAnimationResource(resourceFilename);
620
} else if (marker == 1) {
621
reader.read(_animationTemplateHandle);
626
reader.read(_framesLocked);
631
// The following is only there to for compatibility with older saves
632
// resp. the original engine.
634
Common::String callbackFunctionName;
637
// loop point callback
638
reader.read(callbackCount);
639
assert(callbackCount == 1);
640
reader.readString(callbackFunctionName);
641
assert(callbackFunctionName == "LuaLoopPointCB");
642
reader.read(callbackData);
643
assert(callbackData == getHandle());
645
// loop point callback
646
reader.read(callbackCount);
647
assert(callbackCount == 1);
648
reader.readString(callbackFunctionName);
649
assert(callbackFunctionName == "LuaActionCB");
650
reader.read(callbackData);
651
assert(callbackData == getHandle());
653
// loop point callback
654
reader.read(callbackCount);
655
assert(callbackCount == 1);
656
reader.readString(callbackFunctionName);
657
assert(callbackFunctionName == "LuaDeleteCB");
658
reader.read(callbackData);
659
assert(callbackData == getHandle());
664
result &= RenderObject::unpersistChildren(reader);
666
return reader.isGood() && result;
669
// -----------------------------------------------------------------------------
671
AnimationDescription *Animation::getAnimationDescription() const {
672
if (_animationResourcePtr)
673
return _animationResourcePtr;
675
return AnimationTemplateRegistry::instance().resolveHandle(_animationTemplateHandle);
678
} // End of namespace Sword25