Torque3D Documentation / _generateds / cameraSpline.cpp

cameraSpline.cpp

Engine/source/T3D/cameraSpline.cpp

More...

Public Variables

bool

Detailed Description

Public Variables

bool gBuilding 
  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24
 25#include "T3D/cameraSpline.h"
 26
 27#include "console/console.h"
 28#include "gfx/gfxDevice.h"
 29
 30
 31//-----------------------------------------------------------------------------
 32
 33CameraSpline::Knot::Knot()
 34{
 35   mPosition = Point3F::Zero;
 36   mRotation = QuatF::Identity;
 37   mSpeed = 0.0f;
 38   mType = NORMAL;
 39   mPath = SPLINE;
 40   mDistance = 0.0f;
 41   prev = NULL; next = NULL;
 42};
 43
 44CameraSpline::Knot::Knot(const Knot &k)
 45{
 46   mPosition = k.mPosition;
 47   mRotation = k.mRotation;
 48   mSpeed    = k.mSpeed;
 49   mType = k.mType;
 50   mPath = k.mPath;
 51   mDistance = k.mDistance;
 52   prev = NULL; next = NULL;
 53}
 54
 55CameraSpline::Knot::Knot(const Point3F &p, const QuatF &r, F32 s, Knot::Type type, Knot::Path path)
 56{
 57   mPosition = p;
 58   mRotation = r;
 59   mSpeed    = s;
 60   mType = type;
 61   mPath = path;
 62   mDistance = 0.0f;
 63   prev = NULL; next = NULL;
 64}
 65
 66
 67//-----------------------------------------------------------------------------
 68
 69CameraSpline::CameraSpline()
 70{
 71   mFront = NULL;
 72   mSize = 0;
 73   mIsMapDirty = true;
 74   VECTOR_SET_ASSOCIATION(mTimeMap);
 75}
 76
 77
 78CameraSpline::~CameraSpline()
 79{
 80   removeAll();
 81}
 82
 83
 84void CameraSpline::push_back(Knot *w)
 85{
 86   if (!mFront)
 87   {
 88      mFront = w;
 89      w->next = w;
 90      w->prev = w;
 91   }
 92   else
 93   {
 94      Knot *before = back();
 95      Knot *after  = before->next;
 96
 97      w->next = before->next;
 98      w->prev = before;
 99      after->prev = w;
100      before->next = w;
101   }
102   ++mSize;
103   mIsMapDirty = true;
104}
105
106CameraSpline::Knot* CameraSpline::getKnot(S32 i)
107{
108   Knot *k = mFront;
109   while(i--)
110      k = k->next;
111   return k;
112}
113
114CameraSpline::Knot* CameraSpline::remove(Knot *w)
115{
116   if (w->next == mFront && w->prev == mFront)
117      mFront = NULL;
118   else
119   {
120      w->prev->next = w->next;
121      w->next->prev = w->prev;
122      if (mFront == w)
123         mFront = w->next;
124   }
125   --mSize;
126   mIsMapDirty = true;
127   return w;
128}
129
130
131void CameraSpline::removeAll()
132{
133   while(front())
134      delete remove(front());
135  mSize = 0;
136}
137
138
139//-----------------------------------------------------------------------------
140
141static bool gBuilding = false;
142
143void CameraSpline::buildTimeMap()
144{
145   if (!mIsMapDirty)
146      return;
147
148   gBuilding = true;
149
150   mTimeMap.clear();
151   mTimeMap.reserve(size()*3);      // preallocate
152
153   // Initial node and knot value..
154   TimeMap map;
155   map.mTime = 0;
156   map.mDistance = 0;
157   mTimeMap.push_back(map);
158
159   Knot ka,kj,ki;
160   value(0, &kj, true);
161   F32 length = 0.0f;
162   ka = kj;
163
164   // Loop through the knots and add nodes. Nodes are added for every knot and
165   // whenever the spline length and segment length deviate by epsilon.
166   F32 epsilon = Con::getFloatVariable("CameraSpline::epsilon", 0.90f);
167   const F32 Step = 0.05f;
168   F32 lt = 0,time = 0;
169   do  
170   {
171      if ((time += Step) > F32(mSize - 1))
172         time = (F32)mSize - 1.0f;
173
174      value(time, &ki, true);
175      length += (ki.mPosition - kj.mPosition).len();
176      F32 segment = (ki.mPosition - ka.mPosition).len();
177
178      if ((segment / length) < epsilon || time == (mSize - 1) || mFloor(lt) != mFloor(time)) 
179      {
180         map.mTime = time;
181         map.mDistance = length;
182         mTimeMap.push_back(map);
183         ka = ki;
184      }
185      kj = ki;
186      lt = time;
187   }
188   while (time < mSize - 1);
189
190   mIsMapDirty = false;
191
192   gBuilding = false;
193}
194
195
196//-----------------------------------------------------------------------------
197
198void CameraSpline::renderTimeMap()
199{
200   buildTimeMap();
201
202   gBuilding = true;
203
204   // Build vertex buffer
205   GFXVertexBufferHandle<GFXVertexPCT> vb;
206   vb.set(GFX, mTimeMap.size(), GFXBufferTypeVolatile);
207   void *ptr = vb.lock();
208   if(!ptr) return;
209
210   MRandomLCG random(1376312589 * (uintptr_t)this);
211   S32 index = 0;
212   for(Vector<TimeMap>::iterator itr=mTimeMap.begin(); itr != mTimeMap.end(); itr++)
213   {
214      Knot a;
215      value(itr->mTime, &a, true);
216
217      S32 cr = random.randI(0,255);
218      S32 cg = random.randI(0,255);
219      S32 cb = random.randI(0,255);
220      vb[index].color.set(cr, cg, cb);
221      vb[index].point.set(a.mPosition.x, a.mPosition.y, a.mPosition.z);
222      index++;
223   }
224
225   gBuilding = false;
226
227   vb.unlock();
228
229   // Render the buffer
230   GFX->pushWorldMatrix();
231   GFX->setupGenericShaders();
232   GFX->setVertexBuffer(vb);
233   GFX->drawPrimitive(GFXLineStrip,0,index);
234   GFX->popWorldMatrix();
235}
236
237
238//-----------------------------------------------------------------------------
239
240F32 CameraSpline::advanceTime(F32 t, S32 delta_ms)
241{
242   buildTimeMap();
243   Knot k;
244   value(t, &k, false);
245   F32 dist = getDistance(t) + k.mSpeed * (F32(delta_ms) / 1000.0f);
246   return getTime(dist);
247}
248
249
250F32 CameraSpline::advanceDist(F32 t, F32 meters)
251{
252   buildTimeMap();
253   F32 dist = getDistance(t) + meters;
254   return getTime(dist);
255}
256
257
258F32 CameraSpline::getDistance(F32 t)
259{
260   if (mSize <= 1)
261      return 0;
262
263   // Find the nodes spanning the time
264   Vector<TimeMap>::iterator end = mTimeMap.begin() + 1, start;
265   for (; end < (mTimeMap.end() - 1) && end->mTime < t; end++)  {  }
266   start = end - 1;
267
268   // Interpolate between the two nodes
269   F32 i = (t - start->mTime) / (end->mTime - start->mTime);
270   return start->mDistance + (end->mDistance - start->mDistance) * i;
271}
272
273
274F32 CameraSpline::getTime(F32 d)
275{
276   if (mSize <= 1)
277      return 0;
278
279   // Find nodes spanning the distance
280   Vector<TimeMap>::iterator end = mTimeMap.begin() + 1, start;
281   for (; end < (mTimeMap.end() - 1) && end->mDistance < d; end++) {  }
282   start = end - 1;
283
284   // Check for duplicate points..
285   F32 seg = end->mDistance - start->mDistance;
286   if (!seg)
287      return end->mTime;
288
289   // Interpolate between the two nodes
290   F32 i = (d - start->mDistance) / (end->mDistance - start->mDistance);
291   return start->mTime + (end->mTime - start->mTime) * i;
292}
293
294
295//-----------------------------------------------------------------------------
296void CameraSpline::value(F32 t, CameraSpline::Knot *result, bool skip_rotation)
297{
298   // Do some easing in and out for t.
299   if(!gBuilding)
300   {
301      F32 oldT = t;
302      if(oldT < 0.5f)
303      {
304         t = 0.5f - (mSin( (0.5 - oldT) * M_PI ) / 2.f);
305      }
306
307      if((F32(size()) - 1.5f) > 0.f && oldT - (F32(size()) - 1.5f) > 0.f)
308      {
309         oldT -= (F32(size()) - 1.5f);
310         t = (F32(size()) - 1.5f) + (mCos( (0.5f - oldT) * F32(M_PI) ) / 2.f);
311      }
312   }
313
314   // Verify that t is in range [0 >= t > size]
315//   AssertFatal(t >= 0.0f && t < (F32)size(), "t out of range");
316   Knot *p1 = getKnot((S32)mFloor(t));
317   Knot *p2 = next(p1);
318
319   F32 i = t - mFloor(t);  // adjust t to 0 to 1 on p1-p2 interval
320
321   if (p1->mPath == Knot::SPLINE)
322   {
323      Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1);
324      Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2);
325      result->mPosition.x = mCatmullrom(i, p0->mPosition.x, p1->mPosition.x, p2->mPosition.x, p3->mPosition.x);
326      result->mPosition.y = mCatmullrom(i, p0->mPosition.y, p1->mPosition.y, p2->mPosition.y, p3->mPosition.y);
327      result->mPosition.z = mCatmullrom(i, p0->mPosition.z, p1->mPosition.z, p2->mPosition.z, p3->mPosition.z);
328   }
329   else
330   {   // Linear
331      result->mPosition.interpolate(p1->mPosition, p2->mPosition, i);
332   }
333
334   if (skip_rotation)
335      return;
336
337   buildTimeMap();
338
339   // find the two knots to interpolate rotation and velocity through since some
340   // knots are only positional
341   S32 start = (S32)mFloor(t);
342   S32 end   = (p2 == p1) ? start : (start + 1);
343   while (p1->mType == Knot::POSITION_ONLY && p1 != front())
344   {
345      p1 = prev(p1);
346      start--;
347   }
348
349   while (p2->mType == Knot::POSITION_ONLY && p2 != back())
350   {
351      p2 = next(p2);
352      end++;
353   }
354
355   if (start == end) 
356   {
357      result->mRotation = p1->mRotation;
358      result->mSpeed = p1->mSpeed;
359   }
360   else 
361   {
362      
363      F32 c = getDistance(t);
364      F32 d1 = getDistance((F32)start);
365      F32 d2 = getDistance((F32)end);
366      
367      if (d1 == d2) 
368      {
369         result->mRotation = p2->mRotation;
370         result->mSpeed    = p2->mSpeed;
371      }
372      else 
373      {
374         i  = (c-d1)/(d2-d1);
375
376         if(p1->mPath == Knot::SPLINE)
377         {
378            Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1);
379            Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2);
380
381            F32 q,w,e;
382            q = mCatmullrom(i, 0, 1, 1, 1);
383            w = mCatmullrom(i, 0, 0, 0, 1);
384            e = mCatmullrom(i, 0, 0, 1, 1);
385
386            QuatF a; a.interpolate(p0->mRotation, p1->mRotation, q);
387            QuatF b; b.interpolate(p2->mRotation, p3->mRotation, w);
388            
389            result->mRotation.interpolate(a, b, e);
390            result->mSpeed = mCatmullrom(i, p0->mSpeed, p1->mSpeed, p2->mSpeed, p3->mSpeed);
391         }
392         else
393         {
394            result->mRotation.interpolate(p1->mRotation, p2->mRotation, i);
395            result->mSpeed = (p1->mSpeed * (1.0f-i)) + (p2->mSpeed * i);
396         }
397      }
398   }
399}
400
401
402
403