From bbdaa03d6598a6f09e7272ade1ef96abf3ce1d53 Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Wed, 15 Apr 2009 21:17:08 +0000 Subject: [PATCH] BGE bug #18168: Get local orientation of object using game engine python script system. Added localOrientation and worldOrientation. orientation attribute deprecated. Same for position and scaling. World attributes are read-only except for worldPosition. Add systematic check on NULL SGNode in all python functions. This is necessary to handle zombie objects (deleted by the game but kept alive by a reference in a list). --- source/gameengine/Ketsji/KX_GameObject.cpp | 171 ++++++++++++++------- source/gameengine/Ketsji/KX_GameObject.h | 16 +- source/gameengine/PyDoc/KX_GameObject.py | 21 ++- 3 files changed, 143 insertions(+), 65 deletions(-) diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 36fb9142adc..283b78c2947 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -76,6 +76,10 @@ typedef unsigned long uint_ptr; #include "KX_SG_NodeRelationships.h" static MT_Point3 dummy_point= MT_Point3(0.0, 0.0, 0.0); +static MT_Vector3 dummy_scaling = MT_Vector3(1.0, 1.0, 1.0); +static MT_Matrix3x3 dummy_orientation = MT_Matrix3x3( 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); KX_GameObject::KX_GameObject( void* sgReplicationInfo, @@ -373,11 +377,14 @@ void KX_GameObject::ApplyTorque(const MT_Vector3& torque,bool local) void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local) { - if (m_pPhysicsController1) // (IsDynamic()) + if (GetSGNode()) { - m_pPhysicsController1->RelativeTranslate(dloc,local); + if (m_pPhysicsController1) // (IsDynamic()) + { + m_pPhysicsController1->RelativeTranslate(dloc,local); + } + GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local); } - GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local); } @@ -385,11 +392,13 @@ void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local) void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local) { MT_Matrix3x3 rotmat(drot); + + if (GetSGNode()) { + GetSGNode()->RelativeRotate(rotmat,local); - GetSGNode()->RelativeRotate(rotmat,local); - - if (m_pPhysicsController1) { // (IsDynamic()) - m_pPhysicsController1->RelativeRotate(rotmat,local); + if (m_pPhysicsController1) { // (IsDynamic()) + m_pPhysicsController1->RelativeRotate(rotmat,local); + } } } @@ -402,16 +411,17 @@ double* KX_GameObject::GetOpenGLMatrix() { // todo: optimize and only update if necessary double* fl = m_OpenGL_4x4Matrix.getPointer(); - MT_Transform trans; + if (GetSGNode()) { + MT_Transform trans; - trans.setOrigin(GetSGNode()->GetWorldPosition()); - trans.setBasis(GetSGNode()->GetWorldOrientation()); + trans.setOrigin(GetSGNode()->GetWorldPosition()); + trans.setBasis(GetSGNode()->GetWorldOrientation()); - MT_Vector3 scaling = GetSGNode()->GetWorldScaling(); - m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false; - trans.scale(scaling[0], scaling[1], scaling[2]); - trans.getValue(fl); - + MT_Vector3 scaling = GetSGNode()->GetWorldScaling(); + m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false; + trans.scale(scaling[0], scaling[1], scaling[2]); + trans.getValue(fl); + } return fl; } @@ -442,13 +452,15 @@ static void UpdateBuckets_recursive(SG_Node* node) void KX_GameObject::UpdateBuckets( bool recursive ) { - double* fl = GetOpenGLMatrixPtr()->getPointer(); + if (GetSGNode()) { + double* fl = GetOpenGLMatrixPtr()->getPointer(); - for (size_t i=0;iUpdateBuckets(this, fl, m_bUseObjectColor, m_objectColor, m_bVisible, m_bCulled); + for (size_t i=0;iUpdateBuckets(this, fl, m_bUseObjectColor, m_objectColor, m_bVisible, m_bCulled); - if (recursive) { - UpdateBuckets_recursive(m_pSGNode); + if (recursive) { + UpdateBuckets_recursive(GetSGNode()); + } } } @@ -599,9 +611,11 @@ KX_GameObject::SetVisible( bool recursive ) { - m_bVisible = v; - if (recursive) - setVisible_recursive(m_pSGNode, v); + if (GetSGNode()) { + m_bVisible = v; + if (recursive) + setVisible_recursive(GetSGNode(), v); + } } static void setOccluder_recursive(SG_Node* node, bool v) @@ -627,9 +641,11 @@ KX_GameObject::SetOccluder( bool recursive ) { - m_bOccluder = v; - if (recursive) - setOccluder_recursive(m_pSGNode, v); + if (GetSGNode()) { + m_bOccluder = v; + if (recursive) + setOccluder_recursive(GetSGNode(), v); + } } void @@ -929,7 +945,9 @@ void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale) void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans) { - SG_Node* parent = m_pSGNode->GetSGParent(); + if (!GetSGNode()) + return; + SG_Node* parent = GetSGNode()->GetSGParent(); if (parent != NULL) { // Make sure the objects have some scale @@ -964,13 +982,9 @@ void KX_GameObject::NodeUpdateGS(double time) const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const { - static MT_Matrix3x3 defaultOrientation = MT_Matrix3x3( 1.0, 0.0, 0.0, - 0.0, 1.0, 0.0, - 0.0, 0.0, 1.0); - // check on valid node in case a python controller holds a reference to a deleted object if (!GetSGNode()) - return defaultOrientation; + return dummy_orientation; return GetSGNode()->GetWorldOrientation(); } @@ -978,11 +992,9 @@ const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const { - static MT_Vector3 defaultScaling = MT_Vector3(1.0, 1.0, 1.0); - // check on valid node in case a python controller holds a reference to a deleted object if (!GetSGNode()) - return defaultScaling; + return dummy_scaling; return GetSGNode()->GetWorldScaling(); } @@ -1091,13 +1103,19 @@ PyAttributeDef KX_GameObject::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMax", KX_GameObject, pyattr_get_lin_vel_max, pyattr_set_lin_vel_max), KX_PYATTRIBUTE_RW_FUNCTION("visible", KX_GameObject, pyattr_get_visible, pyattr_set_visible), KX_PYATTRIBUTE_BOOL_RW ("occlusion", KX_GameObject, m_bOccluder), - KX_PYATTRIBUTE_RW_FUNCTION("position", KX_GameObject, pyattr_get_position, pyattr_set_position), + KX_PYATTRIBUTE_RW_FUNCTION("position", KX_GameObject, pyattr_get_worldPosition, pyattr_set_localPosition), KX_PYATTRIBUTE_RO_FUNCTION("localInertia", KX_GameObject, pyattr_get_localInertia), - KX_PYATTRIBUTE_RW_FUNCTION("orientation",KX_GameObject,pyattr_get_orientation,pyattr_set_orientation), - KX_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_scaling, pyattr_set_scaling), + KX_PYATTRIBUTE_RW_FUNCTION("orientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_localOrientation), + KX_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_worldScaling, pyattr_set_localScaling), KX_PYATTRIBUTE_RW_FUNCTION("timeOffset",KX_GameObject, pyattr_get_timeOffset,pyattr_set_timeOffset), KX_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state), KX_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes), + KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation), + KX_PYATTRIBUTE_RO_FUNCTION("worldOrientation",KX_GameObject,pyattr_get_worldOrientation), + KX_PYATTRIBUTE_RW_FUNCTION("localPosition", KX_GameObject, pyattr_get_localPosition, pyattr_set_localPosition), + KX_PYATTRIBUTE_RW_FUNCTION("worldPosition", KX_GameObject, pyattr_get_worldPosition, pyattr_set_worldPosition), + KX_PYATTRIBUTE_RW_FUNCTION("localScaling", KX_GameObject, pyattr_get_localScaling, pyattr_set_localScaling), + KX_PYATTRIBUTE_RO_FUNCTION("worldScaling", KX_GameObject, pyattr_get_worldScaling), KX_PYATTRIBUTE_RO_FUNCTION("__dict__", KX_GameObject, pyattr_get_dir_dict), @@ -1448,13 +1466,34 @@ int KX_GameObject::pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *at return 0; } -PyObject* KX_GameObject::pyattr_get_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject* KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject* self= static_cast(self_v); return PyObjectFrom(self->NodeGetWorldPosition()); } -int KX_GameObject::pyattr_set_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast(self_v); + MT_Point3 pos; + if (!PyVecTo(value, pos)) + return 1; + + self->NodeSetWorldPosition(pos); + self->NodeUpdateGS(0.f); + return 0; +} + +PyObject* KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast(self_v); + if (self->GetSGNode()) + return PyObjectFrom(self->GetSGNode()->GetLocalPosition()); + else + return PyObjectFrom(dummy_point); +} + +int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_GameObject* self= static_cast(self_v); MT_Point3 pos; @@ -1476,13 +1515,22 @@ PyObject* KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIB return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f); } -PyObject* KX_GameObject::pyattr_get_orientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject* KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject* self= static_cast(self_v); return PyObjectFrom(self->NodeGetWorldOrientation()); } -int KX_GameObject::pyattr_set_orientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +PyObject* KX_GameObject::pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast(self_v); + if (self->GetSGNode()) + return PyObjectFrom(self->GetSGNode()->GetLocalOrientation()); + else + return PyObjectFrom(dummy_orientation); +} + +int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_GameObject* self= static_cast(self_v); if (!PySequence_Check(value)) { @@ -1530,13 +1578,22 @@ int KX_GameObject::pyattr_set_orientation(void *self_v, const KX_PYATTRIBUTE_DEF return 1; } -PyObject* KX_GameObject::pyattr_get_scaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject* KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject* self= static_cast(self_v); return PyObjectFrom(self->NodeGetWorldScaling()); } -int KX_GameObject::pyattr_set_scaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +PyObject* KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast(self_v); + if (self->GetSGNode()) + return PyObjectFrom(self->GetSGNode()->GetLocalScale()); + else + return PyObjectFrom(dummy_scaling); +} + +int KX_GameObject::pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_GameObject* self= static_cast(self_v); MT_Vector3 scale; @@ -1551,8 +1608,8 @@ int KX_GameObject::pyattr_set_scaling(void *self_v, const KX_PYATTRIBUTE_DEF *at PyObject* KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject* self= static_cast(self_v); - SG_Node* sg_parent= self->GetSGNode()->GetSGParent(); /* GetSGNode() is valid or exception would be raised */ - if (sg_parent && sg_parent->IsSlowParent()) { + SG_Node* sg_parent; + if (self->GetSGNode() && (sg_parent = self->GetSGNode()->GetSGParent()) != NULL && sg_parent->IsSlowParent()) { return PyFloat_FromDouble(static_cast(sg_parent->GetParentRelation())->GetTimeOffset()); } else { return PyFloat_FromDouble(0.0); @@ -1562,16 +1619,16 @@ PyObject* KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUT int KX_GameObject::pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_GameObject* self= static_cast(self_v); - MT_Scalar val = PyFloat_AsDouble(value); - SG_Node* sg_parent= self->GetSGNode()->GetSGParent(); /* GetSGNode() is valid or exception would be raised */ - if (val < 0.0f) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, "expected a float zero or above"); - return 1; + if (self->GetSGNode()) { + MT_Scalar val = PyFloat_AsDouble(value); + SG_Node* sg_parent= self->GetSGNode()->GetSGParent(); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "expected a float zero or above"); + return 1; + } + if (sg_parent && sg_parent->IsSlowParent()) + static_cast(sg_parent->GetParentRelation())->SetTimeOffset(val); } - - if (sg_parent && sg_parent->IsSlowParent()) - static_cast(sg_parent->GetParentRelation())->SetTimeOffset(val); - return 0; } @@ -2092,6 +2149,8 @@ PyObject* KX_GameObject::PyRemoveParent(PyObject* self) static void walk_children(SG_Node* node, CListValue* list, bool recursive) { + if (!node) + return; NodeList& children = node->GetSGChildren(); for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) @@ -2122,7 +2181,7 @@ PyObject* KX_GameObject::PyGetChildren(PyObject* self) PyObject* KX_GameObject::PyGetChildrenRecursive(PyObject* self) { CListValue* list = new CListValue(); - walk_children(m_pSGNode, list, 1); + walk_children(GetSGNode(), list, 1); return list; } diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 0bf3e60f34b..cf0c0e6b0f5 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -880,14 +880,18 @@ public: static int pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_orientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_orientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_scaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_scaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); diff --git a/source/gameengine/PyDoc/KX_GameObject.py b/source/gameengine/PyDoc/KX_GameObject.py index 4aa9de2fe86..21ddf439924 100644 --- a/source/gameengine/PyDoc/KX_GameObject.py +++ b/source/gameengine/PyDoc/KX_GameObject.py @@ -39,11 +39,26 @@ class KX_GameObject: # (SCA_IObject) @ivar occlusion: occlusion capability flag. @type occlusion: boolean @ivar position: The object's position. - @type position: list [x, y, z] + DEPRECATED: use localPosition and worldPosition + @type position: list [x, y, z] On write: local position, on read: world position @ivar orientation: The object's orientation. 3x3 Matrix. You can also write a Quaternion or Euler vector. - @type orientation: 3x3 Matrix [[float]] + DEPRECATED: use localOrientation and worldOrientation + @type orientation: 3x3 Matrix [[float]] On write: local orientation, on read: world orientation @ivar scaling: The object's scaling factor. list [sx, sy, sz] - @type scaling: list [sx, sy, sz] + DEPRECATED: use localScaling and worldScaling + @type scaling: list [sx, sy, sz] On write: local scaling, on read: world scaling + @ivar localOrientation: The object's local orientation. 3x3 Matrix. You can also write a Quaternion or Euler vector. + @type localOrientation: 3x3 Matrix [[float]] + @ivar worldOrientation: The object's world orientation. Read-only. + @type worldOrientation: 3x3 Matrix [[float]] + @ivar localScaling: The object's local scaling factor. + @type localScaling: list [sx, sy, sz] + @ivar worldScaling: The object's world scaling factor. Read-only + @type worldScaling: list [sx, sy, sz] + @ivar localPosition: The object's local position. + @type localPosition: list [x, y, z] + @ivar worldPosition: The object's world position. + @type worldPosition: list [x, y, z] @ivar timeOffset: adjust the slowparent delay at runtime. @type timeOffset: float @ivar state: the game object's state bitmask, using the first 30 bits, one bit must always be set.