2 This file is part of the graphics core library.
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
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.
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.
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
21 /* fundamental animation system (initally part of 3dgeom.cpp)
23 * Author: John Tsiombikas 2004
25 * John Tsiombikas 2005
28 #include "3dengfx_config.h"
31 #include "animation.hpp"
36 ///////////////// PRS /////////////////////
39 scale = Vector3(1, 1, 1);
42 PRS::PRS(const Vector3 &pos, const Quaternion &rot, const Vector3 &scale, const Vector3 &pivot) {
49 Matrix4x4 PRS::get_xform_matrix() const {
50 Matrix4x4 trans_mat, rot_mat, scale_mat, pivot_mat, neg_pivot_mat;
52 pivot_mat.set_translation(pivot);
53 neg_pivot_mat.set_translation(-pivot);
55 trans_mat.set_translation(position);
56 rot_mat = (Matrix4x4)rotation.get_rotation_matrix();
57 scale_mat.set_scaling(scale);
59 return pivot_mat * trans_mat * rot_mat * scale_mat * neg_pivot_mat;
62 PRS combine_prs(const PRS &prs1, const PRS &prs2) {
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;
75 PRS inherit_prs(const PRS &child, const PRS &parent) {
77 prs.pivot = child.pivot;
79 prs.rotation = parent.rotation * child.rotation;
81 prs.position += child.position;
82 prs.position -= parent.position;
83 prs.position.transform(parent.rotation.conjugate());
84 prs.position += parent.position;
86 Vector3 ppos_trans = parent.position.transformed(parent.rotation.conjugate());
87 prs.position += ppos_trans;
89 prs.position.x *= parent.scale.x;
90 prs.position.y *= parent.scale.y;
91 prs.position.z *= parent.scale.z;
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;
100 std::ostream &operator <<(std::ostream &out, const PRS &prs) {
101 out << "p: " << prs.position << " r: " << prs.rotation << " s: " << prs.scale;
105 //////////////// Keyframe /////////////////
107 Keyframe::Keyframe(const PRS &prs, unsigned long time) {
113 ////////////// XFormNode ///////////////
114 XFormNode::XFormNode() {
117 key_time_mode = TIME_CLAMP;
122 XFormNode::~XFormNode() {
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];
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);
137 void XFormNode::get_key_interval(unsigned long time, const Keyframe **start, const Keyframe **end) const {
138 const Keyframe *nearest = get_nearest_key(time);
143 if(time < nearest->time && nearest->time != keys[0].time) {
144 *start = nearest - 1;
146 } else if(time > nearest->time && nearest->time != keys[key_count - 1].time) {
152 void XFormNode::add_controller(MotionController ctrl, ControllerType ctrl_type) {
154 case CTRL_TRANSLATION:
155 trans_ctrl.push_back(ctrl);
159 rot_ctrl.push_back(ctrl);
163 scale_ctrl.push_back(ctrl);
170 vector<MotionController> *XFormNode::get_controllers(ControllerType ctrl_type) {
172 case CTRL_TRANSLATION:
180 default: // just to make sure at least one of them is returned
188 void XFormNode::add_keyframe(const Keyframe &key) {
190 Keyframe *keyframe = get_nearest_key(key.time);
192 if(keyframe->time == key.time) {
193 keyframe->prs = key.prs;
197 sort(keys.begin(), keys.end());
206 Keyframe *XFormNode::get_keyframe(unsigned long time) {
208 Keyframe *keyframe = get_nearest_key(time);
209 return (keyframe->time == time) ? keyframe : 0;
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()) {
220 std::vector<Keyframe> *XFormNode::get_keyframes() {
225 void XFormNode::set_timeline_mode(TimelineMode time_mode) {
226 key_time_mode = time_mode;
230 void XFormNode::set_position(const Vector3 &pos, unsigned long time) {
231 if(time == XFORM_LOCAL_PRS) {
232 local_prs.position = pos;
234 Keyframe *keyframe = get_nearest_key(time);
235 if(keyframe && keyframe->time == time) {
236 keyframe->prs.position = pos;
242 void XFormNode::set_rotation(const Quaternion &rot, unsigned long time) {
243 if(time == XFORM_LOCAL_PRS) {
244 local_prs.rotation = rot;
246 Keyframe *keyframe = get_nearest_key(time);
247 if(keyframe && keyframe->time == time) {
248 keyframe->prs.rotation = rot;
254 void XFormNode::set_rotation(const Vector3 &euler, unsigned long time) {
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);
261 if(time == XFORM_LOCAL_PRS) {
262 local_prs.rotation = xrot * yrot * zrot;
264 Keyframe *keyframe = get_nearest_key(time);
265 if(keyframe && keyframe->time == time) {
266 keyframe->prs.rotation = xrot * yrot * zrot;
272 void XFormNode::set_scaling(const Vector3 &scale, unsigned long time) {
273 if(time == XFORM_LOCAL_PRS) {
274 local_prs.scale = scale;
276 Keyframe *keyframe = get_nearest_key(time);
277 if(keyframe && keyframe->time == time) {
278 keyframe->prs.scale = scale;
284 void XFormNode::set_pivot(const Vector3 &pivot) {
285 local_prs.pivot = pivot;
290 Vector3 XFormNode::get_position(unsigned long time) const {
291 return get_prs(time).position;
294 Quaternion XFormNode::get_rotation(unsigned long time) const {
295 return get_prs(time).rotation;
298 Vector3 XFormNode::get_scaling(unsigned long time) const {
299 return get_prs(time).scale;
302 Vector3 XFormNode::get_pivot() const {
303 return local_prs.pivot;
307 void XFormNode::translate(const Vector3 &trans, unsigned long time) {
308 if(time == XFORM_LOCAL_PRS) {
309 local_prs.position += trans;
311 Keyframe *keyframe = get_nearest_key(time);
312 if(keyframe && keyframe->time == time) {
313 keyframe->prs.position += trans;
319 void XFormNode::rotate(const Quaternion &rot, unsigned long time) {
320 if(time == XFORM_LOCAL_PRS) {
321 local_prs.rotation = rot * local_prs.rotation;
323 Keyframe *keyframe = get_nearest_key(time);
324 if(keyframe && keyframe->time == time) {
325 keyframe->prs.rotation = rot * keyframe->prs.rotation;
331 void XFormNode::rotate(const Vector3 &euler, unsigned long time) {
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);
338 if(time == XFORM_LOCAL_PRS) {
339 local_prs.rotation = xrot * yrot * zrot * local_prs.rotation;
341 Keyframe *keyframe = get_nearest_key(time);
342 if(keyframe && keyframe->time == time) {
343 keyframe->prs.rotation = xrot * yrot * zrot * keyframe->prs.rotation;
349 void XFormNode::rotate(const Matrix3x3 &rmat, unsigned long time) {
350 // hack a matrix to quat conversion (this should go into the math lib)
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);
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;
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;
379 void XFormNode::reset_position(unsigned long time) {
380 set_position(Vector3(0, 0, 0), time);
384 void XFormNode::reset_rotation(unsigned long time) {
385 set_rotation(Quaternion(), time);
389 void XFormNode::reset_scaling(unsigned long time) {
390 set_scaling(Vector3(1, 1, 1), time);
394 void XFormNode::reset_xform(unsigned long time) {
395 reset_position(time);
396 reset_rotation(time);
400 #define MIN(a, b) ((a) < (b) ? (a) : (b))
401 #define MAX(a, b) ((a) > (b) ? (a) : (b))
403 PRS XFormNode::get_prs(unsigned long time) const {
404 /*if(cache.valid && time == cache.time) {
413 parent_prs = parent->get_prs(time);
416 if(time == XFORM_LOCAL_PRS) {
417 cache.prs = combine_prs(local_prs, parent_prs);
425 unsigned long ktime = get_timeline_time(time, keys[0].time, keys[key_count-1].time, key_time_mode);
427 const Keyframe *start, *end;
428 get_key_interval(ktime, &start, &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);
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);
440 key_prs = start->prs;
443 prs = combine_prs(prs, key_prs);
446 // now let's also apply the controllers, if any
450 int count = trans_ctrl.size();
451 for(int i=0; i<count; i++) {
452 ctrl_prs.position += trans_ctrl[i](time);
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);
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);
464 ctrl_prs.rotation = xrot * yrot * zrot * ctrl_prs.rotation;
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;
475 prs = combine_prs(prs, ctrl_prs);
478 cache.prs = inherit_prs(prs, parent_prs);