diff options
Diffstat (limited to 'source/gameengine/Ketsji/KX_IpoActuator.cpp')
-rw-r--r-- | source/gameengine/Ketsji/KX_IpoActuator.cpp | 643 |
1 files changed, 643 insertions, 0 deletions
diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp new file mode 100644 index 00000000000..1e351834822 --- /dev/null +++ b/source/gameengine/Ketsji/KX_IpoActuator.cpp @@ -0,0 +1,643 @@ +/** + * Do Ipo stuff + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "KX_IpoActuator.h" +#include "KX_GameObject.h" + + +/* ------------------------------------------------------------------------- */ +/* Type strings */ +/* ------------------------------------------------------------------------- */ + +STR_String KX_IpoActuator::S_KX_ACT_IPO_PLAY_STRING = "Play"; +STR_String KX_IpoActuator::S_KX_ACT_IPO_PINGPONG_STRING = "PingPong"; +STR_String KX_IpoActuator::S_KX_ACT_IPO_FLIPPER_STRING = "Flipper"; +STR_String KX_IpoActuator::S_KX_ACT_IPO_LOOPSTOP_STRING = "LoopStop"; +STR_String KX_IpoActuator::S_KX_ACT_IPO_LOOPEND_STRING = "LoopEnd"; +STR_String KX_IpoActuator::S_KX_ACT_IPO_KEY2KEY_STRING = "Key2key"; +STR_String KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp"; + +/* ------------------------------------------------------------------------- */ +/* Native functions */ +/* ------------------------------------------------------------------------- */ +/** Another poltergeist? This seems to be a very transient class... */ +class CIpoAction : public CAction +{ + float m_curtime; + bool m_resurse; + KX_GameObject* m_gameobj; + bool m_ipo_as_force; + bool m_force_ipo_local; + +public: + CIpoAction(KX_GameObject* gameobj, + float curtime, + bool recurse, + bool ipo_as_force, + bool force_ipo_local) : + m_curtime(curtime) , + m_resurse(recurse), + m_gameobj(gameobj), + m_ipo_as_force(ipo_as_force), + m_force_ipo_local(force_ipo_local) + { + /* intentionally empty */ + }; + + virtual void Execute() const + { + m_gameobj->UpdateIPO( + m_curtime, + m_resurse, + m_ipo_as_force, + m_force_ipo_local); + }; + +}; + + +KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj, + const STR_String& propname, + float starttime, + float endtime, + bool recurse, + int acttype, + bool ipo_as_force, + bool force_ipo_local, + PyTypeObject* T) + : SCA_IActuator(gameobj,T), + m_starttime (starttime), + m_endtime(endtime) , + m_localtime(starttime), + m_recurse(recurse), + m_type((IpoActType)acttype) , + m_direction(1), + m_bNegativeEvent(false), + m_propname(propname), + m_ipo_as_force(ipo_as_force), + m_force_ipo_local(force_ipo_local) +{ + // intentionally empty +} + +void KX_IpoActuator::SetStart(float starttime) +{ + m_starttime=starttime; +} + +void KX_IpoActuator::SetEnd(float endtime) +{ + m_endtime=endtime; +} + + +bool KX_IpoActuator::Update(double curtime,double delta_time) +{ + SCA_IActuator::Update(curtime,delta_time); + // result = true if animation has to be continued, false if animation stops + // maybe there are events for us in the queue ! + + + bool bNegativeEvent = false; + int numevents = m_events.size(); + + for (vector<CValue*>::iterator i=m_events.end(); !(i==m_events.begin());) + { + i--; + if ((*i)->GetNumber() == 0.0f) + { + int ka=0; + bNegativeEvent = true; + } + (*i)->Release(); + m_events.pop_back(); + } + + if (bNegativeEvent) + { + RemoveAllEvents(); + } + + + double start_smaller_then_end = ( m_starttime < m_endtime ? 1.0 : -1.0); + + double deltaframetime = start_smaller_then_end * delta_time * KX_FIXED_FRAME_PER_SEC; + + bool result=true; + + switch (m_type) + { + + case KX_ACT_IPO_PLAY: + { + + if (start_smaller_then_end > 0.0) + result = (m_localtime < m_endtime && !(m_localtime == m_starttime && bNegativeEvent)); + else + result = (m_localtime > m_endtime && !(m_localtime == m_starttime && bNegativeEvent)); + if (result) + { + m_localtime += m_direction * deltaframetime; + + /* Perform clamping */ + if ((m_localtime*start_smaller_then_end)>(m_endtime*start_smaller_then_end)) + m_localtime=m_endtime; + + CIpoAction ipoaction( + (KX_GameObject*)GetParent(), + m_localtime, + m_recurse, + m_ipo_as_force, + m_force_ipo_local); + GetParent()->Execute(ipoaction); + } else + { + m_localtime=m_starttime; + m_direction=1; + } + break; + } + case KX_ACT_IPO_PINGPONG: + { + result = true; + if (bNegativeEvent && ((m_localtime == m_starttime )|| (m_localtime == m_endtime))) + { + result = false; + } else + { + m_localtime += m_direction * deltaframetime; + } + + if (m_localtime*start_smaller_then_end < m_starttime*start_smaller_then_end) + { + m_localtime = m_starttime; + result = false; + m_direction = 1; + }else + if (m_localtime*start_smaller_then_end > m_endtime*start_smaller_then_end) + { + m_localtime = m_endtime; + result = false; + m_direction = -1; + } + + CIpoAction ipoaction( + (KX_GameObject*) GetParent(), + m_localtime, + m_recurse, + m_ipo_as_force, + m_force_ipo_local); + GetParent()->Execute(ipoaction); + break; + } + + case KX_ACT_IPO_FLIPPER: + { + result = true; + if (numevents) + { + if (bNegativeEvent) + m_direction = -1; + else + m_direction = 1; + } + + m_localtime += m_direction * deltaframetime; + + if (m_localtime*start_smaller_then_end > m_endtime*start_smaller_then_end) + { + m_localtime = m_endtime; + } else + if (m_localtime*start_smaller_then_end < m_starttime*start_smaller_then_end) + { + m_localtime = m_starttime; + result = false; + } + + CIpoAction ipoaction( + (KX_GameObject*) GetParent(), + m_localtime, + m_recurse, + m_ipo_as_force, + m_force_ipo_local); + GetParent()->Execute(ipoaction); + break; + } + + case KX_ACT_IPO_LOOPSTOP: + { + if (numevents) + { + if (bNegativeEvent) + { + result = false; + m_bNegativeEvent = false; + numevents = 0; + } + } // fall through to loopend, and quit the ipo animation immediatly + } + + case KX_ACT_IPO_LOOPEND: + { + if (numevents){ + if (bNegativeEvent){ + m_bNegativeEvent = true; + } + } + + if (bNegativeEvent && m_localtime == m_starttime){ + result = false; + } + else{ + if (m_localtime*start_smaller_then_end < m_endtime*start_smaller_then_end){ + m_localtime += m_direction * deltaframetime; + } + else{ + if (!m_bNegativeEvent){ + /* Perform wraparound */ + float slop = m_localtime-m_endtime; + float length = fabs(m_starttime-m_endtime); + m_localtime = m_starttime + (slop - (int(slop/length)*(int(length)))); + + } + else + { + /* Perform clamping */ + if ((m_localtime*start_smaller_then_end)>(m_endtime*start_smaller_then_end)) + m_localtime=m_endtime; + + result = false; + m_bNegativeEvent = false; + } + } + } + CIpoAction ipoaction( + (KX_GameObject*) GetParent(), + m_localtime, + m_recurse, + m_ipo_as_force, + m_force_ipo_local); + GetParent()->Execute(ipoaction); + break; + } + case KX_ACT_IPO_KEY2KEY: + { + // not implemented yet + result = false; + break; + } + case KX_ACT_IPO_FROM_PROP: + { + result = !bNegativeEvent; + + CValue* propval = GetParent()->GetProperty(m_propname); + if (propval) + { + m_localtime = propval->GetNumber(); + CIpoAction ipoaction( + (KX_GameObject*) GetParent(), + m_localtime, + m_recurse, + m_ipo_as_force, + m_force_ipo_local); + GetParent()->Execute(ipoaction); + + } else + { + result = false; + } + break; + } + + default: + { + result = false; + } + } + + return result; +} + +KX_IpoActuator::IpoActType KX_IpoActuator::string2mode(char* modename) { + IpoActType res = KX_ACT_IPO_NODEF; + + if (modename == S_KX_ACT_IPO_PLAY_STRING) { + res = KX_ACT_IPO_PLAY; + } else if (modename == S_KX_ACT_IPO_PINGPONG_STRING) { + res = KX_ACT_IPO_PINGPONG; + } else if (modename == S_KX_ACT_IPO_FLIPPER_STRING) { + res = KX_ACT_IPO_FLIPPER; + } else if (modename == S_KX_ACT_IPO_LOOPSTOP_STRING) { + res = KX_ACT_IPO_LOOPSTOP; + } else if (modename == S_KX_ACT_IPO_LOOPEND_STRING) { + res = KX_ACT_IPO_LOOPEND; + } else if (modename == S_KX_ACT_IPO_KEY2KEY_STRING) { + res = KX_ACT_IPO_KEY2KEY; + } else if (modename == S_KX_ACT_IPO_FROM_PROP_STRING) { + res = KX_ACT_IPO_FROM_PROP; + } + + return res; +} + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + + + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject KX_IpoActuator::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "KX_IpoActuator", + sizeof(KX_IpoActuator), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject KX_IpoActuator::Parents[] = { + &KX_IpoActuator::Type, + &SCA_IActuator::Type, + &SCA_ILogicBrick::Type, + &CValue::Type, + NULL +}; + +PyMethodDef KX_IpoActuator::Methods[] = { + {"set", (PyCFunction) KX_IpoActuator::sPySet, + METH_VARARGS, Set_doc}, + {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty, + METH_VARARGS, SetProperty_doc}, + {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart, + METH_VARARGS, SetStart_doc}, + {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart, + METH_VARARGS, GetStart_doc}, + {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd, + METH_VARARGS, SetEnd_doc}, + {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd, + METH_VARARGS, GetEnd_doc}, + {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce, + METH_VARARGS, SetIpoAsForce_doc}, + {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce, + METH_VARARGS, GetIpoAsForce_doc}, + {"setType", (PyCFunction) KX_IpoActuator::sPySetType, + METH_VARARGS, SetType_doc}, + {"getType", (PyCFunction) KX_IpoActuator::sPyGetType, + METH_VARARGS, GetType_doc}, + {NULL,NULL} //Sentinel +}; + +PyObject* KX_IpoActuator::_getattr(char* attr) { + _getattr_up(SCA_IActuator); +} + + + +/* set --------------------------------------------------------------------- */ +char KX_IpoActuator::Set_doc[] = +"set(mode, startframe, endframe, force?)\n" +"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" +"\t - startframe: first frame to use (int)\n" +"\t - endframe : last frame to use (int)\n" +"\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)" +"\tSet the properties of the actuator.\n"; +PyObject* KX_IpoActuator::PySet(PyObject* self, + PyObject* args, + PyObject* kwds) { + /* sets modes PLAY, PINGPONG, FLIPPER, LOOPSTOP, LOOPEND */ + /* arg 1 = mode string, arg 2 = startframe, arg3 = stopframe, */ + /* arg4 = force toggle */ + char* mode; + int forceToggle; + IpoActType modenum; + int startFrame, stopFrame; + if(!PyArg_ParseTuple(args, "siii", &mode, &startFrame, + &stopFrame, &forceToggle)) { + return NULL; + } + modenum = string2mode(mode); + + switch (modenum) { + case KX_ACT_IPO_PLAY: + case KX_ACT_IPO_PINGPONG: + case KX_ACT_IPO_FLIPPER: + case KX_ACT_IPO_LOOPSTOP: + case KX_ACT_IPO_LOOPEND: + m_type = modenum; + m_starttime = startFrame; + m_endtime = stopFrame; + m_ipo_as_force = PyArgToBool(forceToggle); + break; + default: + ; /* error */ + } + + Py_Return; +} + +/* set property ----------------------------------------------------------- */ +char KX_IpoActuator::SetProperty_doc[] = +"setProperty(propname)\n" +"\t - propname: name of the property (string)\n" +"\tSet the property to be used in FromProp mode.\n"; +PyObject* KX_IpoActuator::PySetProperty(PyObject* self, + PyObject* args, + PyObject* kwds) { + /* mode is implicit here, but not supported yet... */ + /* args: property */ + char *propertyName; + if(!PyArg_ParseTuple(args, "s", &propertyName)) { + return NULL; + } + + Py_Return; +} + +/* 4. setStart: */ +char KX_IpoActuator::SetStart_doc[] = +"setStart(frame)\n" +"\t - frame: first frame to use (int)\n" +"\tSet the frame from which the ipo starts playing.\n"; +PyObject* KX_IpoActuator::PySetStart(PyObject* self, + PyObject* args, + PyObject* kwds) { + float startArg; + if(!PyArg_ParseTuple(args, "f", &startArg)) { + return NULL; + } + + m_starttime = startArg; + + Py_Return; +} +/* 5. getStart: */ +char KX_IpoActuator::GetStart_doc[] = +"getStart()\n" +"\tReturns the frame from which the ipo starts playing.\n"; +PyObject* KX_IpoActuator::PyGetStart(PyObject* self, + PyObject* args, + PyObject* kwds) { + return PyFloat_FromDouble(m_starttime); +} + +/* 6. setEnd: */ +char KX_IpoActuator::SetEnd_doc[] = +"setEnd(frame)\n" +"\t - frame: last frame to use (int)\n" +"\tSet the frame at which the ipo stops playing.\n"; +PyObject* KX_IpoActuator::PySetEnd(PyObject* self, + PyObject* args, + PyObject* kwds) { + float endArg; + if(!PyArg_ParseTuple(args, "f", &endArg)) { + return NULL; + } + + m_endtime = endArg; + + Py_Return; +} +/* 7. getEnd: */ +char KX_IpoActuator::GetEnd_doc[] = +"getEnd()\n" +"\tReturns the frame at which the ipo stops playing.\n"; +PyObject* KX_IpoActuator::PyGetEnd(PyObject* self, + PyObject* args, + PyObject* kwds) { + return PyFloat_FromDouble(m_endtime); +} + +/* 6. setIpoAsForce: */ +char KX_IpoActuator::SetIpoAsForce_doc[] = +"setIpoAsForce(force?)\n" +"\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)\n" +"\tSet whether to interpret the ipo as a force rather than a displacement.\n"; +PyObject* KX_IpoActuator::PySetIpoAsForce(PyObject* self, + PyObject* args, + PyObject* kwds) { + int boolArg; + + if (!PyArg_ParseTuple(args, "i", &boolArg)) { + return NULL; + } + + m_ipo_as_force = PyArgToBool(boolArg); + + Py_Return; +} +/* 7. getIpoAsForce: */ +char KX_IpoActuator::GetIpoAsForce_doc[] = +"getIpoAsForce()\n" +"\tReturns whether to interpret the ipo as a force rather than a displacement.\n"; +PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self, + PyObject* args, + PyObject* kwds) { + return BoolToPyArg(m_ipo_as_force); +} + +/* 8. setType: */ +char KX_IpoActuator::SetType_doc[] = +"setType(mode)\n" +"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" +"\tSet the operation mode of the actuator.\n"; +PyObject* KX_IpoActuator::PySetType(PyObject* self, + PyObject* args, + PyObject* kwds) { + int typeArg; + + if (!PyArg_ParseTuple(args, "i", &typeArg)) { + return NULL; + } + + if ( (typeArg > KX_ACT_IPO_NODEF) + && (typeArg < KX_ACT_IPO_KEY2KEY) ) { + m_type = (IpoActType) typeArg; + } + + Py_Return; +} +/* 9. getType: */ +char KX_IpoActuator::GetType_doc[] = +"getType()\n" +"\tReturns the operation mode of the actuator.\n"; +PyObject* KX_IpoActuator::PyGetType(PyObject* self, + PyObject* args, + PyObject* kwds) { + return PyInt_FromLong(m_type); +} + +/* 10. setForceIpoActsLocal: */ +char KX_IpoActuator::SetForceIpoActsLocal_doc[] = +"setForceIpoActsLocal(local?)\n" +"\t - local? : Apply the ipo-as-force in the object's local\n" +"\t coordinates? (KX_TRUE, KX_FALSE)\n" +"\tSet whether to apply the force in the object's local\n" +"\tcoordinates rather than the world global coordinates.\n"; +PyObject* KX_IpoActuator::PySetForceIpoActsLocal(PyObject* self, + PyObject* args, + PyObject* kwds) { + int boolArg; + + if (!PyArg_ParseTuple(args, "i", &boolArg)) { + return NULL; + } + + m_force_ipo_local = PyArgToBool(boolArg); + + Py_Return; +} +/* 11. getForceIpoActsLocal: */ +char KX_IpoActuator::GetForceIpoActsLocal_doc[] = +"getForceIpoActsLocal()\n" +"\tReturn whether to apply the force in the object's local\n" +"\tcoordinates rather than the world global coordinates.\n"; +PyObject* KX_IpoActuator::PyGetForceIpoActsLocal(PyObject* self, + PyObject* args, + PyObject* kwds) { + return BoolToPyArg(m_force_ipo_local); +} + + +/* eof */ |