Blender  V2.59
KX_ObjectActuator.cpp
Go to the documentation of this file.
00001 /*
00002  * Do translation/rotation actions
00003  *
00004  * $Id: KX_ObjectActuator.cpp 36523 2011-05-06 20:18:42Z blendix $
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 #include "KX_ObjectActuator.h"
00038 #include "KX_GameObject.h"
00039 #include "KX_PyMath.h" // For PyVecTo - should this include be put in PyObjectPlus?
00040 #include "KX_IPhysicsController.h"
00041 
00042 /* ------------------------------------------------------------------------- */
00043 /* Native functions                                                          */
00044 /* ------------------------------------------------------------------------- */
00045 
00046 KX_ObjectActuator::
00047 KX_ObjectActuator(
00048         SCA_IObject* gameobj,
00049         KX_GameObject* refobj,
00050         const MT_Vector3& force,
00051         const MT_Vector3& torque,
00052         const MT_Vector3& dloc,
00053         const MT_Vector3& drot,
00054         const MT_Vector3& linV,
00055         const MT_Vector3& angV,
00056         const short damping,
00057         const KX_LocalFlags& flag
00058 ) : 
00059         SCA_IActuator(gameobj, KX_ACT_OBJECT),
00060         m_force(force),
00061         m_torque(torque),
00062         m_dloc(dloc),
00063         m_drot(drot),
00064         m_linear_velocity(linV),
00065         m_angular_velocity(angV),
00066         m_linear_length2(0.0),
00067         m_current_linear_factor(0.0),
00068         m_current_angular_factor(0.0),
00069         m_damping(damping),
00070         m_previous_error(0.0,0.0,0.0),
00071         m_error_accumulator(0.0,0.0,0.0),
00072         m_bitLocalFlag (flag),
00073         m_reference(refobj),
00074         m_active_combined_velocity (false),
00075         m_linear_damping_active(false),
00076         m_angular_damping_active(false)
00077 {
00078         if (m_bitLocalFlag.ServoControl)
00079         {
00080                 // in servo motion, the force is local if the target velocity is local
00081                 m_bitLocalFlag.Force = m_bitLocalFlag.LinearVelocity;
00082 
00083                 m_pid = m_torque;
00084         }
00085         if (m_reference)
00086                 m_reference->RegisterActuator(this);
00087         UpdateFuzzyFlags();
00088 }
00089 
00090 KX_ObjectActuator::~KX_ObjectActuator()
00091 {
00092         if (m_reference)
00093                 m_reference->UnregisterActuator(this);
00094 }
00095 
00096 bool KX_ObjectActuator::Update()
00097 {
00098         
00099         bool bNegativeEvent = IsNegativeEvent();
00100         RemoveAllEvents();
00101                 
00102         KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent()); 
00103 
00104         if (bNegativeEvent) {
00105                 // If we previously set the linear velocity we now have to inform
00106                 // the physics controller that we no longer wish to apply it and that
00107                 // it should reconcile the externally set velocity with it's 
00108                 // own velocity.
00109                 if (m_active_combined_velocity) {
00110                         if (parent)
00111                                 parent->ResolveCombinedVelocities(
00112                                                 m_linear_velocity,
00113                                                 m_angular_velocity,
00114                                                 (m_bitLocalFlag.LinearVelocity) != 0,
00115                                                 (m_bitLocalFlag.AngularVelocity) != 0
00116                                         );
00117                         m_active_combined_velocity = false;
00118                 } 
00119                 m_linear_damping_active = false;
00120                 m_angular_damping_active = false;
00121                 m_error_accumulator.setValue(0.0,0.0,0.0);
00122                 m_previous_error.setValue(0.0,0.0,0.0);
00123                 return false; 
00124 
00125         } else if (parent)
00126         {
00127                 if (m_bitLocalFlag.ServoControl) 
00128                 {
00129                         // In this mode, we try to reach a target speed using force
00130                         // As we don't know the friction, we must implement a generic 
00131                         // servo control to achieve the speed in a configurable
00132                         // v = current velocity
00133                         // V = target velocity
00134                         // e = V-v = speed error
00135                         // dt = time interval since previous update
00136                         // I = sum(e(t)*dt)
00137                         // dv = e(t) - e(t-1)
00138                         // KP, KD, KI : coefficient
00139                         // F = KP*e+KI*I+KD*dv
00140                         MT_Scalar mass = parent->GetMass();
00141                         if (mass < MT_EPSILON)
00142                                 return false;
00143                         MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
00144                         if (m_reference)
00145                         {
00146                                 const MT_Point3& mypos = parent->NodeGetWorldPosition();
00147                                 const MT_Point3& refpos = m_reference->NodeGetWorldPosition();
00148                                 MT_Point3 relpos;
00149                                 relpos = (mypos-refpos);
00150                                 MT_Vector3 vel= m_reference->GetVelocity(relpos);
00151                                 if (m_bitLocalFlag.LinearVelocity)
00152                                         // must convert in local space
00153                                         vel = parent->NodeGetWorldOrientation().transposed()*vel;
00154                                 v -= vel;
00155                         }
00156                         MT_Vector3 e = m_linear_velocity - v;
00157                         MT_Vector3 dv = e - m_previous_error;
00158                         MT_Vector3 I = m_error_accumulator + e;
00159 
00160                         m_force = m_pid.x()*e+m_pid.y()*I+m_pid.z()*dv;
00161                         // to automatically adapt the PID coefficient to mass;
00162                         m_force *= mass;
00163                         if (m_bitLocalFlag.Torque) 
00164                         {
00165                                 if (m_force[0] > m_dloc[0])
00166                                 {
00167                                         m_force[0] = m_dloc[0];
00168                                         I[0] = m_error_accumulator[0];
00169                                 } else if (m_force[0] < m_drot[0])
00170                                 {
00171                                         m_force[0] = m_drot[0];
00172                                         I[0] = m_error_accumulator[0];
00173                                 }
00174                         }
00175                         if (m_bitLocalFlag.DLoc) 
00176                         {
00177                                 if (m_force[1] > m_dloc[1])
00178                                 {
00179                                         m_force[1] = m_dloc[1];
00180                                         I[1] = m_error_accumulator[1];
00181                                 } else if (m_force[1] < m_drot[1])
00182                                 {
00183                                         m_force[1] = m_drot[1];
00184                                         I[1] = m_error_accumulator[1];
00185                                 }
00186                         }
00187                         if (m_bitLocalFlag.DRot) 
00188                         {
00189                                 if (m_force[2] > m_dloc[2])
00190                                 {
00191                                         m_force[2] = m_dloc[2];
00192                                         I[2] = m_error_accumulator[2];
00193                                 } else if (m_force[2] < m_drot[2])
00194                                 {
00195                                         m_force[2] = m_drot[2];
00196                                         I[2] = m_error_accumulator[2];
00197                                 }
00198                         }
00199                         m_previous_error = e;
00200                         m_error_accumulator = I;
00201                         parent->ApplyForce(m_force,(m_bitLocalFlag.LinearVelocity) != 0);
00202                 } else
00203                 {
00204                         if (!m_bitLocalFlag.ZeroForce)
00205                         {
00206                                 parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
00207                         }
00208                         if (!m_bitLocalFlag.ZeroTorque)
00209                         {
00210                                 parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
00211                         }
00212                         if (!m_bitLocalFlag.ZeroDLoc)
00213                         {
00214                                 parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0);
00215                         }
00216                         if (!m_bitLocalFlag.ZeroDRot)
00217                         {
00218                                 parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
00219                         }
00220                         if (!m_bitLocalFlag.ZeroLinearVelocity)
00221                         {
00222                                 if (m_bitLocalFlag.AddOrSetLinV) {
00223                                         parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
00224                                 } else {
00225                                         m_active_combined_velocity = true;
00226                                         if (m_damping > 0) {
00227                                                 MT_Vector3 linV;
00228                                                 if (!m_linear_damping_active) {
00229                                                         // delta and the start speed (depends on the existing speed in that direction)
00230                                                         linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
00231                                                         // keep only the projection along the desired direction
00232                                                         m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2;
00233                                                         m_linear_damping_active = true;
00234                                                 }
00235                                                 if (m_current_linear_factor < 1.0)
00236                                                         m_current_linear_factor += 1.0/m_damping;
00237                                                 if (m_current_linear_factor > 1.0)
00238                                                         m_current_linear_factor = 1.0;
00239                                                 linV = m_current_linear_factor * m_linear_velocity;
00240                                                 parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0);
00241                                         } else {
00242                                                 parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
00243                                         }
00244                                 }
00245                         }
00246                         if (!m_bitLocalFlag.ZeroAngularVelocity)
00247                         {
00248                                 m_active_combined_velocity = true;
00249                                 if (m_damping > 0) {
00250                                         MT_Vector3 angV;
00251                                         if (!m_angular_damping_active) {
00252                                                 // delta and the start speed (depends on the existing speed in that direction)
00253                                                 angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
00254                                                 // keep only the projection along the desired direction
00255                                                 m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2;
00256                                                 m_angular_damping_active = true;
00257                                         }
00258                                         if (m_current_angular_factor < 1.0)
00259                                                 m_current_angular_factor += 1.0/m_damping;
00260                                         if (m_current_angular_factor > 1.0)
00261                                                 m_current_angular_factor = 1.0;
00262                                         angV = m_current_angular_factor * m_angular_velocity;
00263                                         parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0);
00264                                 } else {
00265                                         parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
00266                                 }
00267                         }
00268                 }
00269                 
00270         }
00271         return true;
00272 }
00273 
00274 
00275 
00276 CValue* KX_ObjectActuator::GetReplica()
00277 {
00278         KX_ObjectActuator* replica = new KX_ObjectActuator(*this);//m_float,GetName());
00279         replica->ProcessReplica();
00280 
00281         return replica;
00282 }
00283 
00284 void KX_ObjectActuator::ProcessReplica()
00285 {
00286         SCA_IActuator::ProcessReplica();
00287         if (m_reference)
00288                 m_reference->RegisterActuator(this);
00289 }
00290 
00291 bool KX_ObjectActuator::UnlinkObject(SCA_IObject* clientobj)
00292 {
00293         if (clientobj == (SCA_IObject*)m_reference)
00294         {
00295                 // this object is being deleted, we cannot continue to use it as reference.
00296                 m_reference = NULL;
00297                 return true;
00298         }
00299         return false;
00300 }
00301 
00302 void KX_ObjectActuator::Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map)
00303 {
00304         void **h_obj = (*obj_map)[m_reference];
00305         if (h_obj) {
00306                 if (m_reference)
00307                         m_reference->UnregisterActuator(this);
00308                 m_reference = (KX_GameObject*)(*h_obj);
00309                 m_reference->RegisterActuator(this);
00310         }
00311 }
00312 
00313 /* some 'standard' utilities... */
00314 bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type)
00315 {
00316         bool res = false;
00317         res = (type > KX_OBJECT_ACT_NODEF) && (type < KX_OBJECT_ACT_MAX);
00318         return res;
00319 }
00320 
00321 #ifdef WITH_PYTHON
00322 
00323 /* ------------------------------------------------------------------------- */
00324 /* Python functions                                                          */
00325 /* ------------------------------------------------------------------------- */
00326 
00327 /* Integration hooks ------------------------------------------------------- */
00328 PyTypeObject KX_ObjectActuator::Type = {
00329         PyVarObject_HEAD_INIT(NULL, 0)
00330         "KX_ObjectActuator",
00331         sizeof(PyObjectPlus_Proxy),
00332         0,
00333         py_base_dealloc,
00334         0,
00335         0,
00336         0,
00337         0,
00338         py_base_repr,
00339         0,0,0,0,0,0,0,0,0,
00340         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00341         0,0,0,0,0,0,0,
00342         Methods,
00343         0,
00344         0,
00345         &SCA_IActuator::Type,
00346         0,0,0,0,0,0,
00347         py_base_new
00348 };
00349 
00350 PyMethodDef KX_ObjectActuator::Methods[] = {
00351         {NULL,NULL} //Sentinel
00352 };
00353 
00354 PyAttributeDef KX_ObjectActuator::Attributes[] = {
00355         KX_PYATTRIBUTE_VECTOR_RW_CHECK("force", -1000, 1000, false, KX_ObjectActuator, m_force, PyUpdateFuzzyFlags),
00356         KX_PYATTRIBUTE_BOOL_RW("useLocalForce", KX_ObjectActuator, m_bitLocalFlag.Force),
00357         KX_PYATTRIBUTE_VECTOR_RW_CHECK("torque", -1000, 1000, false, KX_ObjectActuator, m_torque, PyUpdateFuzzyFlags),
00358         KX_PYATTRIBUTE_BOOL_RW("useLocalTorque", KX_ObjectActuator, m_bitLocalFlag.Torque),
00359         KX_PYATTRIBUTE_VECTOR_RW_CHECK("dLoc", -1000, 1000, false, KX_ObjectActuator, m_dloc, PyUpdateFuzzyFlags),
00360         KX_PYATTRIBUTE_BOOL_RW("useLocalDLoc", KX_ObjectActuator, m_bitLocalFlag.DLoc),
00361         KX_PYATTRIBUTE_VECTOR_RW_CHECK("dRot", -1000, 1000, false, KX_ObjectActuator, m_drot, PyUpdateFuzzyFlags),
00362         KX_PYATTRIBUTE_BOOL_RW("useLocalDRot", KX_ObjectActuator, m_bitLocalFlag.DRot),
00363 #ifdef USE_MATHUTILS
00364         KX_PYATTRIBUTE_RW_FUNCTION("linV", KX_ObjectActuator, pyattr_get_linV, pyattr_set_linV),
00365         KX_PYATTRIBUTE_RW_FUNCTION("angV", KX_ObjectActuator, pyattr_get_angV, pyattr_set_angV),
00366 #else
00367         KX_PYATTRIBUTE_VECTOR_RW_CHECK("linV", -1000, 1000, false, KX_ObjectActuator, m_linear_velocity, PyUpdateFuzzyFlags),
00368         KX_PYATTRIBUTE_VECTOR_RW_CHECK("angV", -1000, 1000, false, KX_ObjectActuator, m_angular_velocity, PyUpdateFuzzyFlags),
00369 #endif
00370         KX_PYATTRIBUTE_BOOL_RW("useLocalLinV", KX_ObjectActuator, m_bitLocalFlag.LinearVelocity),
00371         KX_PYATTRIBUTE_BOOL_RW("useLocalAngV", KX_ObjectActuator, m_bitLocalFlag.AngularVelocity),
00372         KX_PYATTRIBUTE_SHORT_RW("damping", 0, 1000, false, KX_ObjectActuator, m_damping),
00373         KX_PYATTRIBUTE_RW_FUNCTION("forceLimitX", KX_ObjectActuator, pyattr_get_forceLimitX, pyattr_set_forceLimitX),
00374         KX_PYATTRIBUTE_RW_FUNCTION("forceLimitY", KX_ObjectActuator, pyattr_get_forceLimitY, pyattr_set_forceLimitY),
00375         KX_PYATTRIBUTE_RW_FUNCTION("forceLimitZ", KX_ObjectActuator, pyattr_get_forceLimitZ, pyattr_set_forceLimitZ),
00376         KX_PYATTRIBUTE_VECTOR_RW_CHECK("pid", -100, 200, true, KX_ObjectActuator, m_pid, PyCheckPid),
00377         KX_PYATTRIBUTE_RW_FUNCTION("reference", KX_ObjectActuator,pyattr_get_reference,pyattr_set_reference),
00378         { NULL }        //Sentinel
00379 };
00380 
00381 /* Attribute get/set functions */
00382 
00383 #ifdef USE_MATHUTILS
00384 
00385 /* These require an SGNode */
00386 #define MATHUTILS_VEC_CB_LINV 1
00387 #define MATHUTILS_VEC_CB_ANGV 2
00388 
00389 static int mathutils_kxobactu_vector_cb_index= -1; /* index for our callbacks */
00390 
00391 static int mathutils_obactu_generic_check(BaseMathObject *bmo)
00392 {
00393         KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>BGE_PROXY_REF(bmo->cb_user);
00394         if(self==NULL)
00395                 return -1;
00396 
00397         return 0;
00398 }
00399 
00400 static int mathutils_obactu_vector_get(BaseMathObject *bmo, int subtype)
00401 {
00402         KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>BGE_PROXY_REF(bmo->cb_user);
00403         if(self==NULL)
00404                 return -1;
00405 
00406         switch(subtype) {
00407                 case MATHUTILS_VEC_CB_LINV:
00408                         self->m_linear_velocity.getValue(bmo->data);
00409                         break;
00410                 case MATHUTILS_VEC_CB_ANGV:
00411                         self->m_angular_velocity.getValue(bmo->data);
00412                         break;
00413         }
00414 
00415         return 0;
00416 }
00417 
00418 static int mathutils_obactu_vector_set(BaseMathObject *bmo, int subtype)
00419 {
00420         KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>BGE_PROXY_REF(bmo->cb_user);
00421         if(self==NULL)
00422                 return -1;
00423 
00424         switch(subtype) {
00425                 case MATHUTILS_VEC_CB_LINV:
00426                         self->m_linear_velocity.setValue(bmo->data);
00427                         break;
00428                 case MATHUTILS_VEC_CB_ANGV:
00429                         self->m_angular_velocity.setValue(bmo->data);
00430                         break;
00431         }
00432 
00433         return 0;
00434 }
00435 
00436 static int mathutils_obactu_vector_get_index(BaseMathObject *bmo, int subtype, int index)
00437 {
00438         /* lazy, avoid repeteing the case statement */
00439         if(mathutils_obactu_vector_get(bmo, subtype) == -1)
00440                 return -1;
00441         return 0;
00442 }
00443 
00444 static int mathutils_obactu_vector_set_index(BaseMathObject *bmo, int subtype, int index)
00445 {
00446         float f= bmo->data[index];
00447 
00448         /* lazy, avoid repeteing the case statement */
00449         if(mathutils_obactu_vector_get(bmo, subtype) == -1)
00450                 return -1;
00451 
00452         bmo->data[index]= f;
00453         return mathutils_obactu_vector_set(bmo, subtype);
00454 }
00455 
00456 Mathutils_Callback mathutils_obactu_vector_cb = {
00457         mathutils_obactu_generic_check,
00458         mathutils_obactu_vector_get,
00459         mathutils_obactu_vector_set,
00460         mathutils_obactu_vector_get_index,
00461         mathutils_obactu_vector_set_index
00462 };
00463 
00464 PyObject* KX_ObjectActuator::pyattr_get_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00465 {
00466         return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV);
00467 }
00468 
00469 int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00470 {
00471         KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>(self_v);
00472         if (!PyVecTo(value, self->m_linear_velocity))
00473                 return PY_SET_ATTR_FAIL;
00474 
00475         self->UpdateFuzzyFlags();
00476 
00477         return PY_SET_ATTR_SUCCESS;
00478 }
00479 
00480 PyObject* KX_ObjectActuator::pyattr_get_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00481 {
00482         return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV);
00483 }
00484 
00485 int KX_ObjectActuator::pyattr_set_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00486 {
00487         KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>(self_v);
00488         if (!PyVecTo(value, self->m_angular_velocity))
00489                 return PY_SET_ATTR_FAIL;
00490 
00491         self->UpdateFuzzyFlags();
00492 
00493         return PY_SET_ATTR_SUCCESS;
00494 }
00495 
00496 
00497 void KX_ObjectActuator_Mathutils_Callback_Init(void)
00498 {
00499         // register mathutils callbacks, ok to run more then once.
00500         mathutils_kxobactu_vector_cb_index= Mathutils_RegisterCallback(&mathutils_obactu_vector_cb);
00501 }
00502 
00503 #endif // USE_MATHUTILS
00504 
00505 PyObject* KX_ObjectActuator::pyattr_get_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00506 {
00507         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
00508         PyObject *retVal = PyList_New(3);
00509 
00510         PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[0]));
00511         PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[0]));
00512         PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.Torque));
00513         
00514         return retVal;
00515 }
00516 
00517 int KX_ObjectActuator::pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00518 {
00519         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
00520 
00521         PyObject* seq = PySequence_Fast(value, "");
00522         if (seq && PySequence_Fast_GET_SIZE(seq) == 3)
00523         {
00524                 self->m_drot[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0));
00525                 self->m_dloc[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1));
00526                 self->m_bitLocalFlag.Torque = (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2)) != 0);
00527 
00528                 if (!PyErr_Occurred())
00529                 {
00530                         Py_DECREF(seq);
00531                         return PY_SET_ATTR_SUCCESS;
00532                 }
00533         }
00534 
00535         Py_XDECREF(seq);
00536 
00537         PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool");
00538         return PY_SET_ATTR_FAIL;
00539 }
00540 
00541 PyObject* KX_ObjectActuator::pyattr_get_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00542 {
00543         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
00544         PyObject *retVal = PyList_New(3);
00545 
00546         PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[1]));
00547         PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[1]));
00548         PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.DLoc));
00549         
00550         return retVal;
00551 }
00552 
00553 int     KX_ObjectActuator::pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00554 {
00555         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
00556 
00557         PyObject* seq = PySequence_Fast(value, "");
00558         if (seq && PySequence_Fast_GET_SIZE(seq) == 3)
00559         {
00560                 self->m_drot[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0));
00561                 self->m_dloc[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1));
00562                 self->m_bitLocalFlag.DLoc = (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2)) != 0);
00563 
00564                 if (!PyErr_Occurred())
00565                 {
00566                         Py_DECREF(seq);
00567                         return PY_SET_ATTR_SUCCESS;
00568                 }
00569         }
00570 
00571         Py_XDECREF(seq);
00572 
00573         PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool");
00574         return PY_SET_ATTR_FAIL;
00575 }
00576 
00577 PyObject* KX_ObjectActuator::pyattr_get_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00578 {
00579         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
00580         PyObject *retVal = PyList_New(3);
00581 
00582         PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[2]));
00583         PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[2]));
00584         PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.DRot));
00585         
00586         return retVal;
00587 }
00588 
00589 int     KX_ObjectActuator::pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00590 {
00591         KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v);
00592 
00593         PyObject* seq = PySequence_Fast(value, "");
00594         if (seq && PySequence_Fast_GET_SIZE(seq) == 3)
00595         {
00596                 self->m_drot[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0));
00597                 self->m_dloc[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1));
00598                 self->m_bitLocalFlag.DRot = (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2)) != 0);
00599 
00600                 if (!PyErr_Occurred())
00601                 {
00602                         Py_DECREF(seq);
00603                         return PY_SET_ATTR_SUCCESS;
00604                 }
00605         }
00606 
00607         Py_XDECREF(seq);
00608 
00609         PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool");
00610         return PY_SET_ATTR_FAIL;
00611 }
00612 
00613 PyObject* KX_ObjectActuator::pyattr_get_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
00614 {
00615         KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self);
00616         if (!actuator->m_reference)
00617                 Py_RETURN_NONE;
00618         
00619         return actuator->m_reference->GetProxy();
00620 }
00621 
00622 int KX_ObjectActuator::pyattr_set_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00623 {
00624         KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self);
00625         KX_GameObject *refOb;
00626         
00627         if (!ConvertPythonToGameObject(value, &refOb, true, "actu.reference = value: KX_ObjectActuator"))
00628                 return PY_SET_ATTR_FAIL;
00629         
00630         if (actuator->m_reference)
00631                 actuator->m_reference->UnregisterActuator(actuator);
00632         
00633         if(refOb==NULL) {
00634                 actuator->m_reference= NULL;
00635         }
00636         else {  
00637                 actuator->m_reference = refOb;
00638                 actuator->m_reference->RegisterActuator(actuator);
00639         }
00640         
00641         return PY_SET_ATTR_SUCCESS;
00642 }
00643 
00644 #endif // WITH_PYTHON
00645 
00646 /* eof */