1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM 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.
6 *
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.
11 *
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.
16 *
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.
20 *
21 */
22
23 /*
24 * This file is based on WME.
25 * http://dead-code.org/redir.php?target=wme
26 * Copyright (c) 2003-2013 Jan Nedoma and contributors
27 */
28
29 #include "engines/wintermute/base/base_game.h"
30 #include "engines/wintermute/base/gfx/x/animation_set.h"
31 #include "engines/wintermute/base/gfx/x/modelx.h"
32 #include "engines/wintermute/base/gfx/x/loader_x.h"
33 #include "engines/wintermute/dcgf.h"
34
35 namespace Wintermute {
36
37 //////////////////////////////////////////////////////////////////////////
AnimationSet(BaseGame * inGame,ModelX * model)38 AnimationSet::AnimationSet(BaseGame *inGame, ModelX *model) : BaseNamedObject(inGame),
39 _looping(false), _frameTime(-1), _totalTime(0), _model(model) {
40 }
41
42 //////////////////////////////////////////////////////////////////////////
~AnimationSet()43 AnimationSet::~AnimationSet() {
44 // remove child animations
45 for (uint32 i = 0; i < _animations.size(); i++) {
46 delete _animations[i];
47 }
48 _animations.clear();
49
50 // remove events
51 for (uint32 i = 0; i < _events.size(); i++) {
52 delete _events[i];
53 }
54 _events.clear();
55 }
56
loadFromX(XFileLexer & lexer,const Common::String & filename)57 bool AnimationSet::loadFromX(XFileLexer &lexer, const Common::String &filename) {
58 if (lexer.tokenIsIdentifier()) {
59 setName(lexer.tokenToString().c_str());
60 lexer.advanceToNextToken();
61 } else {
62 Common::String name = filename + "_animation";
63 setName(name.c_str());
64 }
65
66 lexer.advanceToNextToken();
67
68 bool ret = true;
69
70 while (!lexer.eof()) {
71 if (lexer.tokenIsIdentifier("Animation")) {
72 lexer.advanceToNextToken();
73
74 Animation *animation = new Animation(_gameRef);
75 animation->loadFromX(lexer, this);
76 _animations.add(animation);
77 } else if (lexer.reachedClosedBraces()) {
78 lexer.advanceToNextToken(); // skip closed braces
79 break;
80 } else {
81 warning("AnimationSet::loadFromX unexpected token");
82 ret = false;
83 break;
84 }
85 }
86
87 return ret;
88 }
89
90 //////////////////////////////////////////////////////////////////////////
findBones(FrameNode * rootFrame)91 bool AnimationSet::findBones(FrameNode *rootFrame) {
92 for (uint32 i = 0; i < _animations.size(); i++) {
93 _animations[i]->findBone(rootFrame);
94 }
95 return true;
96 }
97
98 //////////////////////////////////////////////////////////////////////////
addAnimation(Animation * anim)99 bool AnimationSet::addAnimation(Animation *anim) {
100 if (!anim) {
101 return false;
102 } else {
103 _animations.add(anim);
104 return true;
105 }
106 }
107
108 //////////////////////////////////////////////////////////////////////////
addEvent(AnimationEvent * event)109 bool AnimationSet::addEvent(AnimationEvent *event) {
110 if (!event) {
111 return false;
112 } else {
113 int frameTime = getFrameTime();
114 if (frameTime < 0) {
115 _gameRef->LOG(0, "Error adding animation event %s, no keyframes found", event->_eventName);
116 delete event;
117 return false;
118 }
119
120 int totalFrames = 0;
121 if (frameTime > 0)
122 totalFrames = getTotalTime() / frameTime + 1;
123
124 if (event->_frame < 1)
125 event->_frame = 1;
126 if (event->_frame > totalFrames)
127 event->_frame = totalFrames;
128
129 _events.add(event);
130 return true;
131 }
132 }
133
134 //////////////////////////////////////////////////////////////////////////
update(int slot,uint32 localTime,float lerpValue)135 bool AnimationSet::update(int slot, uint32 localTime, float lerpValue) {
136 bool res;
137 for (uint32 i = 0; i < _animations.size(); i++) {
138 res = _animations[i]->update(slot, localTime * ((float)_model->_ticksPerSecond / 1000.0f), lerpValue);
139 if (!res) {
140 return res;
141 }
142 }
143 return true;
144 }
145
146 //////////////////////////////////////////////////////////////////////////
getFrameTime()147 int AnimationSet::getFrameTime() {
148 if (_frameTime >= 0) {
149 return _frameTime;
150 }
151
152 _frameTime = 0;
153
154 for (uint32 i = 0; i < _animations.size(); i++) {
155 int frameTime = _animations[i]->getFrameTime();
156 if (_frameTime == 0) {
157 _frameTime = frameTime / ((float)_model->_ticksPerSecond / 1000.0f);
158 } else if (frameTime > 0) {
159 _frameTime = MIN(float(_frameTime), frameTime / ((float)_model->_ticksPerSecond / 1000.0f));
160 }
161 }
162 return _frameTime;
163 }
164
165 //////////////////////////////////////////////////////////////////////////
getTotalTime()166 uint32 AnimationSet::getTotalTime() {
167 if (_totalTime > 0) {
168 return _totalTime;
169 }
170
171 _totalTime = 0;
172
173 for (uint32 i = 0; i < _animations.size(); i++) {
174 _totalTime = MAX((float)_totalTime, _animations[i]->getTotalTime() / ((float)_model->_ticksPerSecond / 1000.0f));
175 }
176 return _totalTime;
177 }
178
179 //////////////////////////////////////////////////////////////////////////
onFrameChanged(int currentFrame,int prevFrame)180 bool AnimationSet::onFrameChanged(int currentFrame, int prevFrame) {
181 if (!_model || !_model->_owner) {
182 return true;
183 }
184
185 if (prevFrame > currentFrame) {
186 for (uint32 i = 0; i < _events.size(); i++) {
187 if (_events[i]->_frame > prevFrame) {
188 _model->_owner->applyEvent(_events[i]->_eventName);
189 }
190 }
191 prevFrame = -1;
192 }
193
194 for (uint32 i = 0; i < _events.size(); i++) {
195 if (_events[i]->_frame > prevFrame && _events[i]->_frame <= currentFrame) {
196 _model->_owner->applyEvent(_events[i]->_eventName);
197 }
198 }
199 return true;
200 }
201
202 //////////////////////////////////////////////////////////////////////////
persist(BasePersistenceManager * persistMgr)203 bool AnimationSet::persist(BasePersistenceManager *persistMgr) {
204 persistMgr->transferBool(TMEMBER(_looping));
205
206 // persist events
207 int32 numEvents;
208 if (persistMgr->getIsSaving()) {
209 numEvents = _events.size();
210 }
211
212 persistMgr->transferSint32(TMEMBER(numEvents));
213
214 for (int i = 0; i < numEvents; i++) {
215 if (persistMgr->getIsSaving()) {
216 _events[i]->persist(persistMgr);
217 } else {
218 AnimationEvent *rvent = new AnimationEvent();
219 rvent->persist(persistMgr);
220 _events.add(rvent);
221 }
222 }
223
224 return true;
225 }
226
227 } // namespace Wintermute
228