//----------------------------------------------------------------------------- // Copyright (c) 2012 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "platform/platform.h" #include "util/catmullRom.h" #include "math/mMathFn.h" const F32 CatmullRomBase::smX[] = { 0.0000000000f, 0.5384693101f, -0.5384693101f, 0.9061798459f, -0.9061798459f }; const F32 CatmullRomBase::smC[] = { 0.5688888889f, 0.4786286705f, 0.4786286705f, 0.2369268850f, 0.2369268850f }; CatmullRomBase::CatmullRomBase() : mTimes( NULL ), mLengths( NULL ), mTotalLength( 0.0f ), mCount( 0 ) { } void CatmullRomBase::_initialize( U32 count, const F32 *times ) { //AssertFatal( times, "CatmullRomBase::_initialize() - Got null position!" ) AssertFatal( count > 1, "CatmullRomBase::_initialize() - Must have more than 2 points!" ); // set up arrays mTimes = new F32[count]; mCount = count; // set up curve segment lengths mLengths = new F32[count-1]; mTotalLength = 0.0f; for ( U32 i = 0; i < count-1; ++i ) { mLengths[i] = segmentArcLength(i, 0.0f, 1.0f); mTotalLength += mLengths[i]; } // copy the times if we have them. F32 l = 0.0f; for ( U32 i = 0; i < count; ++i ) { if ( times ) mTimes[i] = times[i]; else { if ( mIsZero( mTotalLength ) ) mTimes[i] = 0.0f; else mTimes[i] = l / mTotalLength; if ( i < count-1 ) l += mLengths[i]; } } } void CatmullRomBase::clear() { delete [] mTimes; mTimes = NULL; delete [] mLengths; mLengths = NULL; mTotalLength = 0.0f; mCount = 0; } F32 CatmullRomBase::arcLength( F32 t1, F32 t2 ) { if ( t2 <= t1 ) return 0.0f; if ( t1 < mTimes[0] ) t1 = mTimes[0]; if ( t2 > mTimes[mCount-1] ) t2 = mTimes[mCount-1]; // find segment and parameter U32 seg1; for ( seg1 = 0; seg1 < mCount-1; ++seg1 ) { if ( t1 <= mTimes[seg1+1] ) { break; } } F32 u1 = (t1 - mTimes[seg1])/(mTimes[seg1+1] - mTimes[seg1]); // find segment and parameter U32 seg2; for ( seg2 = 0; seg2 < mCount-1; ++seg2 ) { if ( t2 <= mTimes[seg2+1] ) { break; } } F32 u2 = (t2 - mTimes[seg2])/(mTimes[seg2+1] - mTimes[seg2]); F32 result; // both parameters lie in one segment if ( seg1 == seg2 ) { result = segmentArcLength( seg1, u1, u2 ); } // parameters cross segments else { result = segmentArcLength( seg1, u1, 1.0f ); for ( U32 i = seg1+1; i < seg2; ++i ) result += mLengths[i]; result += segmentArcLength( seg2, 0.0f, u2 ); } return result; } U32 CatmullRomBase::getPrevNode( F32 t ) { AssertFatal( mCount >= 2, "CatmullRomBase::getPrevNode - Bad point count!" ); // handle boundary conditions if ( t <= mTimes[0] ) return 0; else if ( t >= mTimes[mCount-1] ) return mCount-1; // find segment and parameter U32 i; // segment # for ( i = 0; i < mCount-1; ++i ) { if ( t <= mTimes[i+1] ) break; } AssertFatal( i >= 0 && i < mCount, "CatmullRomBase::getPrevNode - Got bad output index!" ); return i; } F32 CatmullRomBase::getTime( U32 idx ) { AssertFatal( idx >= 0 && idx < mCount, "CatmullRomBase::getTime - Got bad index!" ); return mTimes[idx]; }