Patch 2793067: fix trunk with OGRE_THREAD_SUPPORT=1 on non-Windows platforms (don...
[ogre3d.git] / OgreMain / src / OgreRotationSpline.cpp
blob21698aa3ec3ebd0fd8089b6f8d711083b3fd8f1b
1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
7 Copyright (c) 2000-2006 Torus Knot Software Ltd
8 Also see acknowledgements in Readme.html
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22 http://www.gnu.org/copyleft/lesser.txt.
24 You may alternatively use this source under the terms of a specific version of
25 the OGRE Unrestricted License provided you have obtained such a license from
26 Torus Knot Software Ltd.
27 -----------------------------------------------------------------------------
29 #include "OgreStableHeaders.h"
30 #include "OgreRotationalSpline.h"
34 namespace Ogre {
36 //---------------------------------------------------------------------
37 RotationalSpline::RotationalSpline()
38 : mAutoCalc(true)
41 //---------------------------------------------------------------------
42 RotationalSpline::~RotationalSpline()
45 //---------------------------------------------------------------------
46 void RotationalSpline::addPoint(const Quaternion& p)
48 mPoints.push_back(p);
49 if (mAutoCalc)
51 recalcTangents();
54 //---------------------------------------------------------------------
55 Quaternion RotationalSpline::interpolate(Real t, bool useShortestPath)
57 // Work out which segment this is in
58 Real fSeg = t * (mPoints.size() - 1);
59 unsigned int segIdx = (unsigned int)fSeg;
60 // Apportion t
61 t = fSeg - segIdx;
63 return interpolate(segIdx, t, useShortestPath);
66 //---------------------------------------------------------------------
67 Quaternion RotationalSpline::interpolate(unsigned int fromIndex, Real t,
68 bool useShortestPath)
70 // Bounds check
71 assert (fromIndex >= 0 && fromIndex < mPoints.size() &&
72 "fromIndex out of bounds");
74 if ((fromIndex + 1) == mPoints.size())
76 // Duff request, cannot blend to nothing
77 // Just return source
78 return mPoints[fromIndex];
81 // Fast special cases
82 if (t == 0.0f)
84 return mPoints[fromIndex];
86 else if(t == 1.0f)
88 return mPoints[fromIndex + 1];
91 // Real interpolation
92 // Use squad using tangents we've already set up
93 Quaternion &p = mPoints[fromIndex];
94 Quaternion &q = mPoints[fromIndex+1];
95 Quaternion &a = mTangents[fromIndex];
96 Quaternion &b = mTangents[fromIndex+1];
98 // NB interpolate to nearest rotation
99 return Quaternion::Squad(t, p, a, b, q, useShortestPath);
102 //---------------------------------------------------------------------
103 void RotationalSpline::recalcTangents(void)
105 // ShoeMake (1987) approach
106 // Just like Catmull-Rom really, just more gnarly
107 // And no, I don't understand how to derive this!
109 // let p = point[i], pInv = p.Inverse
110 // tangent[i] = p * exp( -0.25 * ( log(pInv * point[i+1]) + log(pInv * point[i-1]) ) )
112 // Assume endpoint tangents are parallel with line with neighbour
114 unsigned int i, numPoints;
115 bool isClosed;
117 numPoints = (unsigned int)mPoints.size();
119 if (numPoints < 2)
121 // Can't do anything yet
122 return;
125 mTangents.resize(numPoints);
127 if (mPoints[0] == mPoints[numPoints-1])
129 isClosed = true;
131 else
133 isClosed = false;
136 Quaternion invp, part1, part2, preExp;
137 for(i = 0; i < numPoints; ++i)
139 Quaternion &p = mPoints[i];
140 invp = p.Inverse();
142 if (i ==0)
144 // special case start
145 part1 = (invp * mPoints[i+1]).Log();
146 if (isClosed)
148 // Use numPoints-2 since numPoints-1 == end == start == this one
149 part2 = (invp * mPoints[numPoints-2]).Log();
151 else
153 part2 = (invp * p).Log();
156 else if (i == numPoints-1)
158 // special case end
159 if (isClosed)
161 // Wrap to [1] (not [0], this is the same as end == this one)
162 part1 = (invp * mPoints[1]).Log();
164 else
166 part1 = (invp * p).Log();
168 part2 = (invp * mPoints[i-1]).Log();
170 else
172 part1 = (invp * mPoints[i+1]).Log();
173 part2 = (invp * mPoints[i-1]).Log();
176 preExp = -0.25 * (part1 + part2);
177 mTangents[i] = p * preExp.Exp();
184 //---------------------------------------------------------------------
185 const Quaternion& RotationalSpline::getPoint(unsigned short index) const
187 assert (index < mPoints.size() && "Point index is out of bounds!!");
189 return mPoints[index];
191 //---------------------------------------------------------------------
192 unsigned short RotationalSpline::getNumPoints(void) const
194 return (unsigned short)mPoints.size();
196 //---------------------------------------------------------------------
197 void RotationalSpline::clear(void)
199 mPoints.clear();
200 mTangents.clear();
202 //---------------------------------------------------------------------
203 void RotationalSpline::updatePoint(unsigned short index, const Quaternion& value)
205 assert (index < mPoints.size() && "Point index is out of bounds!!");
207 mPoints[index] = value;
208 if (mAutoCalc)
210 recalcTangents();
213 //---------------------------------------------------------------------
214 void RotationalSpline::setAutoCalculate(bool autoCalc)
216 mAutoCalc = autoCalc;
218 //---------------------------------------------------------------------