added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / src / gfx / animation.cpp
1 /*
2 This file is part of the graphics core library.
3
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 /* fundamental animation system (initally part of 3dgeom.cpp)
22  *
23  * Author: John Tsiombikas 2004
24  * Modified:
25  *              John Tsiombikas 2005
26  */
27
28 #include "3dengfx_config.h"
29
30 #include <algorithm>
31 #include "animation.hpp"
32
33 using std::vector;
34
35
36 ///////////////// PRS /////////////////////
37
38 PRS::PRS() {
39         scale = Vector3(1, 1, 1);
40 }
41
42 PRS::PRS(const Vector3 &pos, const Quaternion &rot, const Vector3 &scale, const Vector3 &pivot) {
43         position = pos;
44         rotation = rot;
45         this->scale = scale;
46         this->pivot = pivot;
47 }
48
49 Matrix4x4 PRS::get_xform_matrix() const {
50         Matrix4x4 trans_mat, rot_mat, scale_mat, pivot_mat, neg_pivot_mat;
51
52         pivot_mat.set_translation(pivot);
53         neg_pivot_mat.set_translation(-pivot);
54         
55         trans_mat.set_translation(position);
56         rot_mat = (Matrix4x4)rotation.get_rotation_matrix();
57         scale_mat.set_scaling(scale);
58         
59         return pivot_mat * trans_mat * rot_mat * scale_mat * neg_pivot_mat;
60 }
61
62 PRS combine_prs(const PRS &prs1, const PRS &prs2) {
63         PRS prs;
64
65         prs.position = prs1.position + prs2.position;
66         prs.rotation = prs2.rotation * prs1.rotation;
67         prs.scale.x = prs1.scale.x * prs2.scale.x;
68         prs.scale.y = prs1.scale.y * prs2.scale.y;
69         prs.scale.z = prs1.scale.z * prs2.scale.z;
70         prs.pivot = prs1.pivot;
71
72         return prs;
73 }
74
75 PRS inherit_prs(const PRS &child, const PRS &parent) {
76         PRS prs;
77         prs.pivot = child.pivot;
78         
79         prs.rotation = parent.rotation * child.rotation;
80
81         prs.position += child.position;
82         prs.position -= parent.position;
83         prs.position.transform(parent.rotation.conjugate());
84         prs.position += parent.position;
85
86         Vector3 ppos_trans = parent.position.transformed(parent.rotation.conjugate());
87         prs.position += ppos_trans;
88         
89         prs.position.x *= parent.scale.x;
90         prs.position.y *= parent.scale.y;
91         prs.position.z *= parent.scale.z;
92
93         prs.scale.x = child.scale.x * parent.scale.x;
94         prs.scale.y = child.scale.y * parent.scale.y;
95         prs.scale.z = child.scale.z * parent.scale.z;
96
97         return prs;
98 }
99
100 std::ostream &operator <<(std::ostream &out, const PRS &prs) {
101         out << "p: " << prs.position << " r: " << prs.rotation << " s: " << prs.scale;
102         return out;
103 }
104
105 //////////////// Keyframe /////////////////
106
107 Keyframe::Keyframe(const PRS &prs, unsigned long time) {
108         this->prs = prs;
109         this->time = time;
110 }
111
112
113 ////////////// XFormNode ///////////////
114 XFormNode::XFormNode() {
115         key_count = 0;
116         use_ctrl = 0;
117         key_time_mode = TIME_CLAMP;
118         parent = 0;
119         cache.valid = false;
120 }
121
122 XFormNode::~XFormNode() {
123 }
124
125 Keyframe *XFormNode::get_nearest_key(int start, int end, unsigned long time) {
126         if(start == end) return &keys[start];
127         if(end - start == 1) {
128                 return abs((int)(time - keys[start].time)) < abs((int)(keys[end].time - time)) ? &keys[start] : &keys[end];
129         }
130
131         int mid = (start + end) / 2;
132         if(time < keys[mid].time) return get_nearest_key(start, mid, time);
133         if(time > keys[mid].time) return get_nearest_key(mid + 1, end, time);
134         return &keys[mid];
135 }
136
137 void XFormNode::get_key_interval(unsigned long time, const Keyframe **start, const Keyframe **end) const {
138         const Keyframe *nearest = get_nearest_key(time);
139
140         *start = nearest;
141         *end = 0;
142         
143         if(time < nearest->time && nearest->time != keys[0].time) {
144                 *start = nearest - 1;
145                 *end = nearest;
146         } else if(time > nearest->time && nearest->time != keys[key_count - 1].time) {
147                 *start = nearest;
148                 *end = nearest + 1;
149         }
150 }
151
152 void XFormNode::add_controller(MotionController ctrl, ControllerType ctrl_type) {
153         switch(ctrl_type) {
154         case CTRL_TRANSLATION:
155                 trans_ctrl.push_back(ctrl);
156                 break;
157                 
158         case CTRL_ROTATION:
159                 rot_ctrl.push_back(ctrl);
160                 break;
161                 
162         case CTRL_SCALING:
163                 scale_ctrl.push_back(ctrl);
164                 break;
165         }
166         use_ctrl = true;
167         cache.valid = false;
168 }
169
170 vector<MotionController> *XFormNode::get_controllers(ControllerType ctrl_type) {
171         switch(ctrl_type) {
172         case CTRL_TRANSLATION:
173                 return &trans_ctrl;
174                 break;
175                 
176         case CTRL_ROTATION:
177                 return &rot_ctrl;
178                 break;
179                 
180         default:        // just to make sure at least one of them is returned
181         case CTRL_SCALING:
182                 return &scale_ctrl;
183                 break;
184         }
185         cache.valid = false;
186 }
187
188 void XFormNode::add_keyframe(const Keyframe &key) {
189         if(!keys.empty()) {
190                 Keyframe *keyframe = get_nearest_key(key.time);
191         
192                 if(keyframe->time == key.time) {
193                         keyframe->prs = key.prs;
194                 } else {
195                         key_count++;
196                         keys.push_back(key);
197                         sort(keys.begin(), keys.end());
198                 }
199         } else {
200                 keys.push_back(key);
201                 key_count++;
202         }
203         cache.valid = false;
204 }
205
206 Keyframe *XFormNode::get_keyframe(unsigned long time) {
207         cache.valid = false;
208         Keyframe *keyframe = get_nearest_key(time);
209         return (keyframe->time == time) ? keyframe : 0;
210 }
211
212 void XFormNode::delete_keyframe(unsigned long time) {
213         vector<Keyframe>::iterator iter = find(keys.begin(), keys.end(), Keyframe(PRS(), time));
214         if(iter != keys.end()) {
215                 keys.erase(iter);
216         }
217         cache.valid = false;
218 }
219
220 std::vector<Keyframe> *XFormNode::get_keyframes() {
221         cache.valid = false;
222         return &keys;
223 }
224
225 void XFormNode::set_timeline_mode(TimelineMode time_mode) {
226         key_time_mode = time_mode;
227         cache.valid = false;
228 }
229
230 void XFormNode::set_position(const Vector3 &pos, unsigned long time) {
231         if(time == XFORM_LOCAL_PRS) {
232                 local_prs.position = pos;
233         } else {
234                 Keyframe *keyframe = get_nearest_key(time);
235                 if(keyframe && keyframe->time == time) {
236                         keyframe->prs.position = pos;
237                 }
238         }
239         cache.valid = false;
240 }
241
242 void XFormNode::set_rotation(const Quaternion &rot, unsigned long time) {
243         if(time == XFORM_LOCAL_PRS) {
244                 local_prs.rotation = rot;
245         } else {
246                 Keyframe *keyframe = get_nearest_key(time);
247                 if(keyframe && keyframe->time == time) {
248                         keyframe->prs.rotation = rot;
249                 }
250         }
251         cache.valid = false;
252 }
253
254 void XFormNode::set_rotation(const Vector3 &euler, unsigned long time) {
255         
256         Quaternion xrot, yrot, zrot;
257         xrot.set_rotation(Vector3(1, 0, 0), euler.x);
258         yrot.set_rotation(Vector3(0, 1, 0), euler.y);
259         zrot.set_rotation(Vector3(0, 0, 1), euler.z);
260         
261         if(time == XFORM_LOCAL_PRS) {           
262                 local_prs.rotation = xrot * yrot * zrot;
263         } else {
264                 Keyframe *keyframe = get_nearest_key(time);
265                 if(keyframe && keyframe->time == time) {
266                         keyframe->prs.rotation = xrot * yrot * zrot;
267                 }
268         }
269         cache.valid = false;
270 }
271
272 void XFormNode::set_scaling(const Vector3 &scale, unsigned long time) {
273         if(time == XFORM_LOCAL_PRS) {
274                 local_prs.scale = scale;
275         } else {
276                 Keyframe *keyframe = get_nearest_key(time);
277                 if(keyframe && keyframe->time == time) {
278                         keyframe->prs.scale = scale;
279                 }
280         }
281         cache.valid = false;
282 }
283
284 void XFormNode::set_pivot(const Vector3 &pivot) {
285         local_prs.pivot = pivot;
286         cache.valid = false;
287 }
288
289
290 Vector3 XFormNode::get_position(unsigned long time) const {
291         return get_prs(time).position;
292 }
293
294 Quaternion XFormNode::get_rotation(unsigned long time) const {
295         return get_prs(time).rotation;
296 }
297
298 Vector3 XFormNode::get_scaling(unsigned long time) const {
299         return get_prs(time).scale;
300 }
301
302 Vector3 XFormNode::get_pivot() const {
303         return local_prs.pivot;
304 }
305
306
307 void XFormNode::translate(const Vector3 &trans, unsigned long time) {
308         if(time == XFORM_LOCAL_PRS) {
309                 local_prs.position += trans;
310         } else {
311                 Keyframe *keyframe = get_nearest_key(time);
312                 if(keyframe && keyframe->time == time) {
313                         keyframe->prs.position += trans;
314                 }
315         }
316         cache.valid = false;
317 }
318
319 void XFormNode::rotate(const Quaternion &rot, unsigned long time) {
320         if(time == XFORM_LOCAL_PRS) {
321                 local_prs.rotation = rot * local_prs.rotation;
322         } else {
323                 Keyframe *keyframe = get_nearest_key(time);
324                 if(keyframe && keyframe->time == time) {
325                         keyframe->prs.rotation = rot * keyframe->prs.rotation;
326                 }
327         }
328         cache.valid = false;
329 }
330
331 void XFormNode::rotate(const Vector3 &euler, unsigned long time) {
332         
333         Quaternion xrot, yrot, zrot;
334         xrot.set_rotation(Vector3(1, 0, 0), euler.x);
335         yrot.set_rotation(Vector3(0, 1, 0), euler.y);
336         zrot.set_rotation(Vector3(0, 0, 1), euler.z);
337         
338         if(time == XFORM_LOCAL_PRS) {           
339                 local_prs.rotation = xrot * yrot * zrot * local_prs.rotation;
340         } else {
341                 Keyframe *keyframe = get_nearest_key(time);
342                 if(keyframe && keyframe->time == time) {
343                         keyframe->prs.rotation = xrot * yrot * zrot * keyframe->prs.rotation;
344                 }
345         }
346         cache.valid = false;
347 }
348
349 void XFormNode::rotate(const Matrix3x3 &rmat, unsigned long time) {
350         // hack a matrix to quat conversion (this should go into the math lib)
351         Quaternion q;
352         q.s = sqrt(rmat[0][0] + rmat[1][1] + rmat[2][2] + 1.0) / 2.0;
353         scalar_t ssq = q.s * q.s;
354         q.v.x = sqrt((rmat[0][0] + 1.0 - 2.0 * ssq) / 2.0);
355         q.v.y = sqrt((rmat[1][1] + 1.0 - 2.0 * ssq) / 2.0);
356         q.v.z = sqrt((rmat[2][2] + 1.0 - 2.0 * ssq) / 2.0);
357
358         rotate(q, time);
359         cache.valid = false;
360 }
361
362 void XFormNode::scale(const Vector3 &scale, unsigned long time) {
363         if(time == XFORM_LOCAL_PRS) {
364                 local_prs.scale.x *= scale.x;
365                 local_prs.scale.y *= scale.y;
366                 local_prs.scale.z *= scale.z;
367         } else {
368                 Keyframe *keyframe = get_nearest_key(time);
369                 if(keyframe && keyframe->time == time) {
370                         keyframe->prs.scale.x *= scale.x;
371                         keyframe->prs.scale.y *= scale.y;
372                         keyframe->prs.scale.z *= scale.z;
373                 }
374         }
375         cache.valid = false;
376 }
377
378
379 void XFormNode::reset_position(unsigned long time) {
380         set_position(Vector3(0, 0, 0), time);
381         cache.valid = false;
382 }
383
384 void XFormNode::reset_rotation(unsigned long time) {
385         set_rotation(Quaternion(), time);
386         cache.valid = false;
387 }
388
389 void XFormNode::reset_scaling(unsigned long time) {
390         set_scaling(Vector3(1, 1, 1), time);
391         cache.valid = false;
392 }
393
394 void XFormNode::reset_xform(unsigned long time) {
395         reset_position(time);
396         reset_rotation(time);
397         reset_scaling(time);
398 }
399
400 #define MIN(a, b)       ((a) < (b) ? (a) : (b))
401 #define MAX(a, b)       ((a) > (b) ? (a) : (b))
402
403 PRS XFormNode::get_prs(unsigned long time) const {
404         /*if(cache.valid && time == cache.time) {
405                 return cache.prs;
406         }
407         */
408         cache.valid = true;
409         cache.time = time;
410
411         PRS parent_prs;
412         if(parent) {
413                 parent_prs = parent->get_prs(time);
414         }
415         
416         if(time == XFORM_LOCAL_PRS) {
417                 cache.prs = combine_prs(local_prs, parent_prs);
418                 return cache.prs;
419         }
420         
421         PRS prs = local_prs;
422
423         // apply keyframes
424         if(key_count) {
425                 unsigned long ktime = get_timeline_time(time, keys[0].time, keys[key_count-1].time, key_time_mode);
426                 
427                 const Keyframe *start, *end;
428                 get_key_interval(ktime, &start, &end);
429
430                 PRS key_prs;
431         
432                 if(end) {
433                         // find the parametric location of the given keyframe in the range we have
434                         scalar_t t = (scalar_t)(ktime - start->time) / (scalar_t)(end->time - start->time);
435         
436                         key_prs.position = start->prs.position + (end->prs.position - start->prs.position) * t;
437                         key_prs.scale = start->prs.scale + (end->prs.scale - start->prs.scale) * t;
438                         key_prs.rotation = slerp(start->prs.rotation, end->prs.rotation, t);
439                 } else {
440                         key_prs = start->prs;
441                 }
442
443                 prs = combine_prs(prs, key_prs);
444         }
445         
446         // now let's also apply the controllers, if any
447         if(use_ctrl) {
448                 PRS ctrl_prs;
449                 
450                 int count = trans_ctrl.size();
451                 for(int i=0; i<count; i++) {
452                         ctrl_prs.position += trans_ctrl[i](time);
453                 }
454                 
455                 count = rot_ctrl.size();
456                 for(int i=0; i<count; i++) {
457                         Quaternion xrot, yrot, zrot;
458                         Vector3 euler = rot_ctrl[i](time);
459                         
460                         xrot.set_rotation(Vector3(1, 0, 0), euler.x);
461                         yrot.set_rotation(Vector3(0, 1, 0), euler.y);
462                         zrot.set_rotation(Vector3(0, 0, 1), euler.z);
463                         
464                         ctrl_prs.rotation = xrot * yrot * zrot * ctrl_prs.rotation;
465                 }
466                 
467                 count = scale_ctrl.size();
468                 for(int i=0; i<count; i++) {
469                         Vector3 scale = scale_ctrl[i](time);
470                         ctrl_prs.scale.x *= scale.x;
471                         ctrl_prs.scale.y *= scale.y;
472                         ctrl_prs.scale.z *= scale.z;
473                 }
474
475                 prs = combine_prs(prs, ctrl_prs);
476         }
477         
478         cache.prs = inherit_prs(prs, parent_prs);
479         return cache.prs;
480 }