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