blender/source/gameengine/Ketsji/KX_IpoActuator.cpp
Kester Maddock 44f45894c2 Miscellaneous Fixes:
Add Python Mapping method to CListValue
Fix Bernoulli bool distribution python method for random actuator
Fix Python IpoActuator methods setProperty and force acts local
Make data objects private
Better sort method for polygon materials - much easier to understand
2004-06-04 03:00:13 +00:00

652 lines
17 KiB
C++

/**
* 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"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* ------------------------------------------------------------------------- */
/* 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_bNegativeEvent(false),
m_starttime (starttime),
m_endtime(endtime),
m_recurse(recurse),
m_localtime(starttime),
m_direction(1),
m_propname(propname),
m_ipo_as_force(ipo_as_force),
m_force_ipo_local(force_ipo_local),
m_type((IpoActType)acttype)
{
// 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},
{"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal,
METH_VARARGS, SetForceIpoActsLocal_doc},
{"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal,
METH_VARARGS, GetForceIpoActsLocal_doc},
{NULL,NULL} //Sentinel
};
PyObject* KX_IpoActuator::_getattr(const STR_String& 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;
}
m_propname = propertyName;
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 */