afxAnimCurve.cpp
Engine/source/afx/util/afxAnimCurve.cpp
Detailed Description
1 2 3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 5// Copyright (C) 2015 Faust Logic, Inc. 6// 7// Permission is hereby granted, free of charge, to any person obtaining a copy 8// of this software and associated documentation files (the "Software"), to 9// deal in the Software without restriction, including without limitation the 10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11// sell copies of the Software, and to permit persons to whom the Software is 12// furnished to do so, subject to the following conditions: 13// 14// The above copyright notice and this permission notice shall be included in 15// all copies or substantial portions of the Software. 16// 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23// IN THE SOFTWARE. 24// 25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 26 27#include "afx/arcaneFX.h" 28#include "afx/util/afxAnimCurve.h" 29 30afxAnimCurve::afxAnimCurve() : usable( false ), final_value( 0.0f ), start_value( 0.0f ) 31{ 32 evaluator = new afxHermiteEval(); 33 final_time = 0.0f; 34 start_time = 0.0f; 35} 36 37afxAnimCurve::~afxAnimCurve() 38{ 39 delete evaluator; 40} 41 42void afxAnimCurve::addKey( Point2F &v ) 43{ 44 Key k; 45 k.time = v.x; 46 k.value = v.y; 47 48 keys.push_back( k ); 49 50 usable = false; 51} 52 53void afxAnimCurve::addKey( F32 time, F32 value ) 54{ 55 Key k; 56 k.time = time; 57 k.value = value; 58 59 keys.push_back( k ); 60 61 usable = false; 62} 63 64void afxAnimCurve::setKeyTime( int index, F32 t ) 65{ 66 if( ( index < 0 ) || ( index >= keys.size() ) ) 67 return; 68 69 Key &k = keys[index]; 70 k.time = t; 71 72 usable = false; 73} 74 75void afxAnimCurve::setKeyValue( int index, F32 v ) 76{ 77 if( ( index < 0 ) || ( index >= keys.size() ) ) 78 return; 79 80 Key &k = keys[index]; 81 k.value = v; 82 83 if( index == 0 ) 84 start_value = v; 85 else if( index == keys.size()-1 ) 86 final_value = v; 87} 88 89//bool afxAnimCurve::compare_Key( const afxAnimCurve::Key &a, const afxAnimCurve::Key &b ) 90//{ 91// return a.time < b.time; 92//} 93 94S32 QSORT_CALLBACK afxAnimCurve::compare_Key( const void* a, const void* b ) 95{ 96 const Key *key_a = (Key *)a; 97 const Key *key_b = (Key *)b; 98 99 //Con::printf( "*** %f %f", key_a->time, key_b->time ); 100 101 //return key_a->time < key_b->time; 102 103 104 if (key_a->time > key_b->time) 105 return 1; 106 else if (key_a->time < key_b->time) 107 return -1; 108 else 109 return 0; 110} 111 112void afxAnimCurve::sort( ) 113{ 114 if( keys.size() == 0 ) 115 return; 116 117 //std::sort( keys.begin(), keys.end(), afxAnimCurve::compare_Key ); 118 dQsort( keys.address(), keys.size(), sizeof(Key), afxAnimCurve::compare_Key ); 119 120 start_value = keys[0].value; 121 final_value = keys[keys.size()-1].value; 122 123 start_time = keys[0].time; 124 final_time = keys[keys.size()-1].time; 125 126 usable = true; 127} 128 129int afxAnimCurve::numKeys() 130{ 131 return keys.size(); 132} 133 134F32 afxAnimCurve::getKeyTime( int index ) 135{ 136 if( ( index < 0 ) || ( index >= keys.size() ) ) 137 return 0.0f; 138 139 Key &k = keys[index]; 140 return k.time; 141} 142 143F32 afxAnimCurve::getKeyValue( int index ) 144{ 145 if( ( index < 0 ) || ( index >= keys.size() ) ) 146 return 0.0f; 147 148 Key &k = keys[index]; 149 return k.value; 150} 151 152Point2F afxAnimCurve::getSegment( F32 time ) 153{ 154 Point2F segment( 0, 0 ); 155 156 if( keys.size() == 0 ) 157 return segment; 158 159 int start_index = 0; 160 for( ; start_index < keys.size()-1; start_index++ ) 161 { 162 if( time < keys[start_index+1].time ) 163 break; 164 } 165 int end_index = start_index+1; 166 167 segment.x = (F32)start_index; 168 segment.y = (F32)end_index; 169 170 return segment; 171} 172 173F32 afxAnimCurve::evaluate( F32 time ) 174{ 175 if( !usable ) 176 return 0.0f; 177 178 if( time <= start_time ) 179 return start_value; 180 181 if( time >= final_time ) 182 return final_value; 183 184 if( keys.size() == 1 ) 185 return start_value; 186 187 int start_index = 0; 188 for( ; start_index < keys.size()-1; start_index++ ) 189 { 190 if( time < keys[start_index+1].time ) 191 break; 192 } 193 int end_index = start_index+1; 194 195 Key k0 = keys[start_index]; 196 Key k1 = keys[end_index]; 197 198 Point2F v0( (F32) k0.time, k0.value ); 199 Point2F v1( (F32) k1.time, k1.value ); 200 201 // Compute tangents 202 Point2F tan0 = computeTangentK0( v0, v1, start_index ); 203 Point2F tan1 = computeTangentK1( v0, v1, end_index ); 204 205 F32 time_perc = (F32)( time - k0.time ) / (F32)( k1.time - k0.time ); 206 207 Point2F vnew = evaluator->evaluateCurve( v0, 208 v1, 209 tan0, 210 tan1, 211 time_perc ); 212 213 return vnew.y; 214} 215 216Point2F afxAnimCurve::computeTangentK0( Point2F &k0, Point2F &k1, int start_index ) 217{ 218 Point2F tan0; 219 220 Point2F k_prev; 221 Point2F k_next; 222 223 // tangent for k0 224 if( start_index == 0 ) 225 { 226 k_prev = k0; // Setting previous point to k0, creating a hidden point in 227 // the same spot 228 k_next = k1; 229 } 230 else 231 { 232 Key &k = keys[start_index-1]; 233 k_prev.set( k.time, k.value ); 234 k_next = k1; 235 } 236 tan0 = k_next-k_prev; //k_next.subtract( k_prev ); 237 tan0 *= .5f; 238 239 return tan0; 240} 241 242Point2F afxAnimCurve::computeTangentK1( Point2F &k0, Point2F &k1, int end_index ) 243{ 244 Point2F tan1; 245 246 Point2F k_prev; 247 Point2F k_next; 248 249 // tangent for k1 250 if( end_index == keys.size()-1 ) 251 { 252 k_prev = k0; 253 k_next = k1; // Setting next point to k1, creating a hidden point in 254 // the same spot 255 } 256 else 257 { 258 k_prev = k0; 259 Key &k = keys[end_index+1]; 260 k_next.set( k.time, k.value ); 261 } 262 tan1 = k_next-k_prev; //k_next.subtract( k_prev ); 263 tan1 *= .5f; 264 265 return tan1; 266} 267 268void afxAnimCurve::print() 269{ 270 Con::printf( "afxAnimCurve -------------------------" ); 271 for( int i = 0; i < keys.size(); i++ ) 272 { 273 Key &k = keys[i]; 274 Con::printf( "%f: %f", k.time, k.value ); 275 } 276 Con::printf( "-----------------------------------" ); 277} 278 279void afxAnimCurve::printKey( int index ) 280{ 281 Key &k = keys[index]; 282 Con::printf( "%f: %f", k.time, k.value ); 283} 284