/** * Apply a constraint to a position or rotation value * * $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 "SCA_IActuator.h" #include "KX_ConstraintActuator.h" #include "SCA_IObject.h" #include "MT_Point3.h" #include "MT_Matrix3x3.h" #include "KX_GameObject.h" /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, int dampTime, float minBound, float maxBound, int locrotxyz, PyTypeObject* T) : SCA_IActuator(gameobj, T) { m_dampTime = dampTime; m_locrot = locrotxyz; /* The units of bounds are determined by the type of constraint. To */ /* make the constraint application easier and more transparent later on, */ /* I think converting the bounds to the applicable domain makes more */ /* sense. */ switch (m_locrot) { case KX_ACT_CONSTRAINT_LOCX: case KX_ACT_CONSTRAINT_LOCY: case KX_ACT_CONSTRAINT_LOCZ: m_minimumBound = minBound; m_maximumBound = maxBound; break; case KX_ACT_CONSTRAINT_ROTX: case KX_ACT_CONSTRAINT_ROTY: case KX_ACT_CONSTRAINT_ROTZ: /* The user interface asks for degrees, we are radian. */ m_minimumBound = MT_radians(minBound); m_maximumBound = MT_radians(maxBound); break; default: ; /* error */ } } /* End of constructor */ KX_ConstraintActuator::~KX_ConstraintActuator() { // there's nothing to be done here, really.... } /* end of destructor */ bool KX_ConstraintActuator::Update(double curtime,double deltatime) { bool result = false; bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (bNegativeEvent) return false; // do nothing on negative events /* Constraint clamps the values to the specified range, with a sort of */ /* low-pass filtered time response, if the damp time is unequal to 0. */ /* Having to retrieve location/rotation and setting it afterwards may not */ /* be efficient enough... Somthing to look at later. */ KX_GameObject *parent = (KX_GameObject*) GetParent(); MT_Point3 position = parent->NodeGetWorldPosition(); MT_Matrix3x3 rotation = parent->NodeGetWorldOrientation(); // MT_Vector3 eulerrot = rotation.getEuler(); switch (m_locrot) { case KX_ACT_CONSTRAINT_LOCX: Clamp(position[0], m_minimumBound, m_maximumBound); break; case KX_ACT_CONSTRAINT_LOCY: Clamp(position[1], m_minimumBound, m_maximumBound); break; case KX_ACT_CONSTRAINT_LOCZ: Clamp(position[2], m_minimumBound, m_maximumBound); break; // case KX_ACT_CONSTRAINT_ROTX: // /* The angles are Euler angles (I think that's what they are called) */ // /* but we need to convert from/to the MT_Matrix3x3. */ // Clamp(eulerrot[0], m_minimumBound, m_maximumBound); // break; // case KX_ACT_CONSTRAINT_ROTY: // Clamp(eulerrot[1], m_minimumBound, m_maximumBound); // break; // case KX_ACT_CONSTRAINT_ROTZ: // Clamp(eulerrot[2], m_minimumBound, m_maximumBound); // break; // default: // ; /* error */ } /* Will be replaced by a filtered clamp. */ switch (m_locrot) { case KX_ACT_CONSTRAINT_LOCX: case KX_ACT_CONSTRAINT_LOCY: case KX_ACT_CONSTRAINT_LOCZ: parent->NodeSetLocalPosition(position); break; // case KX_ACT_CONSTRAINT_ROTX: // case KX_ACT_CONSTRAINT_ROTY: // case KX_ACT_CONSTRAINT_ROTZ: // rotation.setEuler(eulerrot); // parent->NodeSetLocalOrientation(rotation); break; default: ; /* error */ } return false; } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime) */ void KX_ConstraintActuator::Clamp(MT_Scalar &var, float min, float max) { if (var < min) { var = min; } else if (var > max) { var = max; } } bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m) { bool res = false; if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) { res = true; } return res; } /* ------------------------------------------------------------------------- */ /* Python functions */ /* ------------------------------------------------------------------------- */ /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ConstraintActuator::Type = { PyObject_HEAD_INIT(&PyType_Type) 0, "KX_ConstraintActuator", sizeof(KX_ConstraintActuator), 0, PyDestructor, 0, __getattr, __setattr, 0, //&MyPyCompare, __repr, 0, //&cvalue_as_number, 0, 0, 0, 0 }; PyParentObject KX_ConstraintActuator::Parents[] = { &KX_ConstraintActuator::Type, &SCA_IActuator::Type, &SCA_ILogicBrick::Type, &CValue::Type, NULL }; PyMethodDef KX_ConstraintActuator::Methods[] = { {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc}, {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_VARARGS, GetDamp_doc}, {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc}, {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc}, {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc}, {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc}, {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc}, {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, GetLimit_doc}, {NULL,NULL} //Sentinel }; PyObject* KX_ConstraintActuator::_getattr(char* attr) { _getattr_up(SCA_IActuator); } /* 2. setDamp */ char KX_ConstraintActuator::SetDamp_doc[] = "setDamp(duration)\n" "\t- duration: integer\n" "\tSets the time with which the constraint application is delayed.\n" "\tIf the duration is negative, it is set to 0.\n"; PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, PyObject* args, PyObject* kwds) { int dampArg; if(!PyArg_ParseTuple(args, "i", &dampArg)) { return NULL; } m_dampTime = dampArg; if (m_dampTime < 0) m_dampTime = 0; Py_Return; } /* 3. getDamp */ char KX_ConstraintActuator::GetDamp_doc[] = "GetDamp()\n" "\tReturns the damping time for application of the constraint.\n"; PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self, PyObject* args, PyObject* kwds){ return PyInt_FromLong(m_dampTime); } /* 4. setMin */ char KX_ConstraintActuator::SetMin_doc[] = "setMin(lower_bound)\n" "\t- lower_bound: float\n" "\tSets the lower value of the interval to which the value\n" "\tis clipped.\n"; PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, PyObject* args, PyObject* kwds) { float minArg; if(!PyArg_ParseTuple(args, "f", &minArg)) { return NULL; } switch (m_locrot) { case KX_ACT_CONSTRAINT_LOCX: case KX_ACT_CONSTRAINT_LOCY: case KX_ACT_CONSTRAINT_LOCZ: m_minimumBound = minArg; break; case KX_ACT_CONSTRAINT_ROTX: case KX_ACT_CONSTRAINT_ROTY: case KX_ACT_CONSTRAINT_ROTZ: m_minimumBound = MT_radians(minArg); break; default: ; /* error */ } Py_Return; } /* 5. getMin */ char KX_ConstraintActuator::GetMin_doc[] = "getMin()\n" "\tReturns the lower value of the interval to which the value\n" "\tis clipped.\n"; PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self, PyObject* args, PyObject* kwds) { return PyFloat_FromDouble(m_minimumBound); } /* 6. setMax */ char KX_ConstraintActuator::SetMax_doc[] = "setMax(upper_bound)\n" "\t- upper_bound: float\n" "\tSets the upper value of the interval to which the value\n" "\tis clipped.\n"; PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, PyObject* args, PyObject* kwds){ float maxArg; if(!PyArg_ParseTuple(args, "f", &maxArg)) { return NULL; } switch (m_locrot) { case KX_ACT_CONSTRAINT_LOCX: case KX_ACT_CONSTRAINT_LOCY: case KX_ACT_CONSTRAINT_LOCZ: m_maximumBound = maxArg; break; case KX_ACT_CONSTRAINT_ROTX: case KX_ACT_CONSTRAINT_ROTY: case KX_ACT_CONSTRAINT_ROTZ: m_maximumBound = MT_radians(maxArg); break; default: ; /* error */ } Py_Return; } /* 7. getMax */ char KX_ConstraintActuator::GetMax_doc[] = "getMax()\n" "\tReturns the upper value of the interval to which the value\n" "\tis clipped.\n"; PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self, PyObject* args, PyObject* kwds) { return PyFloat_FromDouble(m_maximumBound); } /* This setter/getter probably for the constraint type */ /* 8. setLimit */ char KX_ConstraintActuator::SetLimit_doc[] = "setLimit(type)\n" "\t- type: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY,\n" "\t KX_CONSTRAINTACT_LOCZ, KX_CONSTRAINTACT_ROTX,\n" "\t KX_CONSTRAINTACT_ROTY, or KX_CONSTRAINTACT_ROTZ.\n" "\tSets the type of constraint.\n"; PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, PyObject* args, PyObject* kwds) { int locrotArg; if(!PyArg_ParseTuple(args, "i", &locrotArg)) { return NULL; } if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg; Py_Return; } /* 9. getLimit */ char KX_ConstraintActuator::GetLimit_doc[] = "getLimit(type)\n" "\tReturns the type of constraint.\n"; PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self, PyObject* args, PyObject* kwds) { return PyInt_FromLong(m_locrot); } /* eof */