|
Blender
V2.59
|
00001 /* 00002 * Do Ipo stuff 00003 * 00004 * $Id: KX_IpoActuator.cpp 35171 2011-02-25 13:35:59Z jesterking $ 00005 * 00006 * ***** BEGIN GPL LICENSE BLOCK ***** 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * as published by the Free Software Foundation; either version 2 00011 * of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00023 * All rights reserved. 00024 * 00025 * The Original Code is: all of this file. 00026 * 00027 * Contributor(s): none yet. 00028 * 00029 * ***** END GPL LICENSE BLOCK ***** 00030 */ 00031 00037 #if defined (__sgi) 00038 #include <math.h> 00039 #else 00040 #include <cmath> 00041 #endif 00042 00043 #include "KX_IpoActuator.h" 00044 #include "KX_GameObject.h" 00045 #include "FloatValue.h" 00046 00047 #include "KX_KetsjiEngine.h" 00048 00049 /* ------------------------------------------------------------------------- */ 00050 /* Type strings */ 00051 /* ------------------------------------------------------------------------- */ 00052 00053 const char *KX_IpoActuator::S_KX_ACT_IPO_PLAY_STRING = "Play"; 00054 const char *KX_IpoActuator::S_KX_ACT_IPO_PINGPONG_STRING = "PingPong"; 00055 const char *KX_IpoActuator::S_KX_ACT_IPO_FLIPPER_STRING = "Flipper"; 00056 const char *KX_IpoActuator::S_KX_ACT_IPO_LOOPSTOP_STRING = "LoopStop"; 00057 const char *KX_IpoActuator::S_KX_ACT_IPO_LOOPEND_STRING = "LoopEnd"; 00058 const char *KX_IpoActuator::S_KX_ACT_IPO_KEY2KEY_STRING = "Key2key"; 00059 const char *KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp"; 00060 00061 /* ------------------------------------------------------------------------- */ 00062 /* Native functions */ 00063 /* ------------------------------------------------------------------------- */ 00064 00065 KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj, 00066 const STR_String& propname, 00067 const STR_String& framePropname, 00068 float starttime, 00069 float endtime, 00070 bool recurse, 00071 int acttype, 00072 bool ipo_as_force, 00073 bool ipo_add, 00074 bool ipo_local) 00075 : SCA_IActuator(gameobj, KX_ACT_IPO), 00076 m_bNegativeEvent(false), 00077 m_startframe (starttime), 00078 m_endframe(endtime), 00079 m_recurse(recurse), 00080 m_localtime(starttime), 00081 m_direction(1), 00082 m_propname(propname), 00083 m_framepropname(framePropname), 00084 m_ipo_as_force(ipo_as_force), 00085 m_ipo_add(ipo_add), 00086 m_ipo_local(ipo_local), 00087 m_type(acttype) 00088 { 00089 this->ResetStartTime(); 00090 m_bIpoPlaying = false; 00091 } 00092 00093 void KX_IpoActuator::SetStart(float starttime) 00094 { 00095 m_startframe=starttime; 00096 } 00097 00098 void KX_IpoActuator::SetEnd(float endtime) 00099 { 00100 m_endframe=endtime; 00101 } 00102 00103 bool KX_IpoActuator::ClampLocalTime() 00104 { 00105 if (m_startframe < m_endframe) 00106 { 00107 if (m_localtime < m_startframe) 00108 { 00109 m_localtime = m_startframe; 00110 return true; 00111 } 00112 else if (m_localtime > m_endframe) 00113 { 00114 m_localtime = m_endframe; 00115 return true; 00116 } 00117 } else { 00118 if (m_localtime > m_startframe) 00119 { 00120 m_localtime = m_startframe; 00121 return true; 00122 } 00123 else if (m_localtime < m_endframe) 00124 { 00125 m_localtime = m_endframe; 00126 return true; 00127 } 00128 } 00129 return false; 00130 } 00131 00132 void KX_IpoActuator::SetStartTime(float curtime) 00133 { 00134 float direction = m_startframe < m_endframe ? 1.0f : -1.0f; 00135 00136 if (m_direction > 0) 00137 m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate(); 00138 else 00139 m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate(); 00140 } 00141 00142 void KX_IpoActuator::SetLocalTime(float curtime) 00143 { 00144 float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate(); 00145 00146 // negative delta_time is caused by floating point inaccuracy 00147 // perhaps the inaccuracy could be reduced a bit 00148 if ((m_localtime==m_startframe || m_localtime==m_endframe) && delta_time<0.0) 00149 { 00150 delta_time = 0.0; 00151 } 00152 00153 if (m_endframe < m_startframe) 00154 delta_time = -delta_time; 00155 00156 if (m_direction > 0) 00157 m_localtime = m_startframe + delta_time; 00158 else 00159 m_localtime = m_endframe - delta_time; 00160 } 00161 00162 bool KX_IpoActuator::Update(double curtime, bool frame) 00163 { 00164 // result = true if animation has to be continued, false if animation stops 00165 // maybe there are events for us in the queue ! 00166 bool bNegativeEvent = false; 00167 bool numevents = false; 00168 bool bIpoStart = false; 00169 00170 curtime -= KX_KetsjiEngine::GetSuspendedDelta(); 00171 00172 if (frame) 00173 { 00174 numevents = m_posevent || m_negevent; 00175 bNegativeEvent = IsNegativeEvent(); 00176 RemoveAllEvents(); 00177 } 00178 00179 float start_smaller_then_end = ( m_startframe < m_endframe ? 1.0f : -1.0f); 00180 00181 bool result=true; 00182 if (!bNegativeEvent) 00183 { 00184 if (m_starttime < -2.0f*fabs(m_endframe - m_startframe)) 00185 { 00186 // start for all Ipo, initial start for LOOP_STOP 00187 m_starttime = curtime; 00188 m_bIpoPlaying = true; 00189 bIpoStart = true; 00190 } 00191 } 00192 00193 switch ((IpoActType)m_type) 00194 { 00195 00196 case KX_ACT_IPO_PLAY: 00197 { 00198 // Check if playing forwards. result = ! finished 00199 00200 if (start_smaller_then_end > 0.f) 00201 result = (m_localtime < m_endframe && m_bIpoPlaying); 00202 else 00203 result = (m_localtime > m_endframe && m_bIpoPlaying); 00204 00205 if (result) 00206 { 00207 SetLocalTime(curtime); 00208 00209 /* Perform clamping */ 00210 ClampLocalTime(); 00211 00212 if (bIpoStart) 00213 ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); 00214 ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); 00215 } else 00216 { 00217 m_localtime=m_startframe; 00218 m_direction=1; 00219 } 00220 break; 00221 } 00222 case KX_ACT_IPO_PINGPONG: 00223 { 00224 result = true; 00225 if (bNegativeEvent && !m_bIpoPlaying) 00226 result = false; 00227 else 00228 SetLocalTime(curtime); 00229 00230 if (ClampLocalTime()) 00231 { 00232 result = false; 00233 m_direction = -m_direction; 00234 } 00235 00236 if (bIpoStart && m_direction > 0) 00237 ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); 00238 ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); 00239 break; 00240 } 00241 case KX_ACT_IPO_FLIPPER: 00242 { 00243 if (bNegativeEvent && !m_bIpoPlaying) 00244 result = false; 00245 if (numevents) 00246 { 00247 float oldDirection = m_direction; 00248 if (bNegativeEvent) 00249 m_direction = -1; 00250 else 00251 m_direction = 1; 00252 if (m_direction != oldDirection) 00253 // changing direction, reset start time 00254 SetStartTime(curtime); 00255 } 00256 00257 SetLocalTime(curtime); 00258 00259 if (ClampLocalTime() && m_localtime == m_startframe) 00260 result = false; 00261 00262 if (bIpoStart) 00263 ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); 00264 ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); 00265 break; 00266 } 00267 00268 case KX_ACT_IPO_LOOPSTOP: 00269 { 00270 if (numevents) 00271 { 00272 if (bNegativeEvent) 00273 { 00274 result = false; 00275 m_bNegativeEvent = false; 00276 numevents = false; 00277 } 00278 if (!m_bIpoPlaying) 00279 { 00280 // Ipo was stopped, make sure we will restart from where it stopped 00281 SetStartTime(curtime); 00282 if (!bNegativeEvent) 00283 // positive signal will restart the Ipo 00284 m_bIpoPlaying = true; 00285 } 00286 00287 } // fall through to loopend, and quit the ipo animation immediatly 00288 } 00289 case KX_ACT_IPO_LOOPEND: 00290 { 00291 if (numevents){ 00292 if (bNegativeEvent && m_bIpoPlaying){ 00293 m_bNegativeEvent = true; 00294 } 00295 } 00296 00297 if (bNegativeEvent && !m_bIpoPlaying){ 00298 result = false; 00299 } 00300 else 00301 { 00302 if (m_localtime*start_smaller_then_end < m_endframe*start_smaller_then_end) 00303 { 00304 SetLocalTime(curtime); 00305 } 00306 else{ 00307 if (!m_bNegativeEvent){ 00308 /* Perform wraparound */ 00309 SetLocalTime(curtime); 00310 if (start_smaller_then_end > 0.f) 00311 m_localtime = m_startframe + fmod(m_localtime - m_startframe, m_endframe - m_startframe); 00312 else 00313 m_localtime = m_startframe - fmod(m_startframe - m_localtime, m_startframe - m_endframe); 00314 SetStartTime(curtime); 00315 bIpoStart = true; 00316 } 00317 else 00318 { 00319 /* Perform clamping */ 00320 m_localtime=m_endframe; 00321 result = false; 00322 m_bNegativeEvent = false; 00323 } 00324 } 00325 } 00326 00327 if (m_bIpoPlaying && bIpoStart) 00328 ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); 00329 ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); 00330 break; 00331 } 00332 00333 case KX_ACT_IPO_KEY2KEY: 00334 { 00335 // not implemented yet 00336 result = false; 00337 break; 00338 } 00339 00340 case KX_ACT_IPO_FROM_PROP: 00341 { 00342 result = !bNegativeEvent; 00343 00344 CValue* propval = GetParent()->GetProperty(m_propname); 00345 if (propval) 00346 { 00347 m_localtime = propval->GetNumber(); 00348 00349 if (bIpoStart) 00350 ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); 00351 ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); 00352 } else 00353 { 00354 result = false; 00355 } 00356 break; 00357 } 00358 00359 default: 00360 result = false; 00361 } 00362 00363 /* Set the property if its defined */ 00364 if (m_framepropname[0] != '\0') { 00365 CValue* propowner = GetParent(); 00366 CValue* oldprop = propowner->GetProperty(m_framepropname); 00367 CValue* newval = new CFloatValue(m_localtime); 00368 if (oldprop) { 00369 oldprop->SetValue(newval); 00370 } else { 00371 propowner->SetProperty(m_framepropname, newval); 00372 } 00373 newval->Release(); 00374 } 00375 00376 if (!result) 00377 { 00378 if (m_type != KX_ACT_IPO_LOOPSTOP) 00379 this->ResetStartTime(); 00380 m_bIpoPlaying = false; 00381 } 00382 00383 return result; 00384 } 00385 00386 void KX_IpoActuator::ResetStartTime() 00387 { 00388 this->m_starttime = -2.0*fabs(this->m_endframe - this->m_startframe) - 1.0; 00389 } 00390 00391 int KX_IpoActuator::string2mode(char* modename) { 00392 IpoActType res = KX_ACT_IPO_NODEF; 00393 00394 if (strcmp(modename, S_KX_ACT_IPO_PLAY_STRING)==0) { 00395 res = KX_ACT_IPO_PLAY; 00396 } else if (strcmp(modename, S_KX_ACT_IPO_PINGPONG_STRING)==0) { 00397 res = KX_ACT_IPO_PINGPONG; 00398 } else if (strcmp(modename, S_KX_ACT_IPO_FLIPPER_STRING)==0) { 00399 res = KX_ACT_IPO_FLIPPER; 00400 } else if (strcmp(modename, S_KX_ACT_IPO_LOOPSTOP_STRING)==0) { 00401 res = KX_ACT_IPO_LOOPSTOP; 00402 } else if (strcmp(modename, S_KX_ACT_IPO_LOOPEND_STRING)==0) { 00403 res = KX_ACT_IPO_LOOPEND; 00404 } else if (strcmp(modename, S_KX_ACT_IPO_KEY2KEY_STRING)==0) { 00405 res = KX_ACT_IPO_KEY2KEY; 00406 } else if (strcmp(modename, S_KX_ACT_IPO_FROM_PROP_STRING)==0) { 00407 res = KX_ACT_IPO_FROM_PROP; 00408 } 00409 00410 return res; 00411 } 00412 00413 #ifdef WITH_PYTHON 00414 00415 /* ------------------------------------------------------------------------- */ 00416 /* Python functions */ 00417 /* ------------------------------------------------------------------------- */ 00418 00419 00420 /* Integration hooks ------------------------------------------------------- */ 00421 PyTypeObject KX_IpoActuator::Type = { 00422 PyVarObject_HEAD_INIT(NULL, 0) 00423 "KX_IpoActuator", 00424 sizeof(PyObjectPlus_Proxy), 00425 0, 00426 py_base_dealloc, 00427 0, 00428 0, 00429 0, 00430 0, 00431 py_base_repr, 00432 0,0,0,0,0,0,0,0,0, 00433 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 00434 0,0,0,0,0,0,0, 00435 Methods, 00436 0, 00437 0, 00438 &SCA_IActuator::Type, 00439 0,0,0,0,0,0, 00440 py_base_new 00441 }; 00442 00443 PyMethodDef KX_IpoActuator::Methods[] = { 00444 {NULL,NULL} //Sentinel 00445 }; 00446 00447 PyAttributeDef KX_IpoActuator::Attributes[] = { 00448 KX_PYATTRIBUTE_RW_FUNCTION("frameStart", KX_IpoActuator, pyattr_get_frame_start, pyattr_set_frame_start), 00449 KX_PYATTRIBUTE_RW_FUNCTION("frameEnd", KX_IpoActuator, pyattr_get_frame_end, pyattr_set_frame_end), 00450 KX_PYATTRIBUTE_STRING_RW("propName", 0, 64, false, KX_IpoActuator, m_propname), 00451 KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 64, false, KX_IpoActuator, m_framepropname), 00452 KX_PYATTRIBUTE_INT_RW("mode", KX_ACT_IPO_NODEF+1, KX_ACT_IPO_MAX-1, true, KX_IpoActuator, m_type), 00453 KX_PYATTRIBUTE_BOOL_RW("useIpoAsForce", KX_IpoActuator, m_ipo_as_force), 00454 KX_PYATTRIBUTE_BOOL_RW("useIpoAdd", KX_IpoActuator, m_ipo_add), 00455 KX_PYATTRIBUTE_BOOL_RW("useIpoLocal", KX_IpoActuator, m_ipo_local), 00456 KX_PYATTRIBUTE_BOOL_RW("useChildren", KX_IpoActuator, m_recurse), 00457 00458 { NULL } //Sentinel 00459 }; 00460 00461 PyObject* KX_IpoActuator::pyattr_get_frame_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 00462 { 00463 KX_IpoActuator* self= static_cast<KX_IpoActuator*>(self_v); 00464 return PyFloat_FromDouble(self->m_startframe); 00465 } 00466 00467 int KX_IpoActuator::pyattr_set_frame_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00468 { 00469 KX_IpoActuator* self= static_cast<KX_IpoActuator*>(self_v); 00470 float param = PyFloat_AsDouble(value); 00471 00472 if (PyErr_Occurred()) { 00473 PyErr_SetString(PyExc_AttributeError, "frameStart = float: KX_IpoActuator, expected a float value"); 00474 return PY_SET_ATTR_FAIL; 00475 } 00476 00477 self->m_startframe = param; 00478 self->ResetStartTime(); 00479 return PY_SET_ATTR_SUCCESS; 00480 } 00481 00482 PyObject* KX_IpoActuator::pyattr_get_frame_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 00483 { 00484 KX_IpoActuator* self= static_cast<KX_IpoActuator*>(self_v); 00485 return PyFloat_FromDouble(self->m_endframe); 00486 } 00487 00488 int KX_IpoActuator::pyattr_set_frame_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00489 { 00490 KX_IpoActuator* self= static_cast<KX_IpoActuator*>(self_v); 00491 float param = PyFloat_AsDouble(value); 00492 00493 if (PyErr_Occurred()) { 00494 PyErr_SetString(PyExc_AttributeError, "frameEnd = float: KX_IpoActuator, expected a float value"); 00495 return PY_SET_ATTR_FAIL; 00496 } 00497 00498 self->m_endframe = param; 00499 self->ResetStartTime(); 00500 return PY_SET_ATTR_SUCCESS; 00501 } 00502 00503 #endif // WITH_PYTHON 00504 00505 /* eof */