diff options
Diffstat (limited to 'source/gameengine/Ketsji/KX_Scene.cpp')
-rw-r--r-- | source/gameengine/Ketsji/KX_Scene.cpp | 288 |
1 files changed, 190 insertions, 98 deletions
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index aa7bd65f240..c0d8a7090c4 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -34,7 +34,7 @@ #include "KX_Scene.h" #include "MT_assert.h" - +#include "SND_Scene.h" #include "KX_KetsjiEngine.h" #include "KX_BlenderMaterial.h" #include "RAS_IPolygonMaterial.h" @@ -80,6 +80,7 @@ #include "KX_BlenderSceneConverter.h" #include "KX_MotionState.h" +#include "BL_ModifierDeformer.h" #include "BL_ShapeDeformer.h" #include "BL_DeformableGameObject.h" @@ -110,7 +111,22 @@ void* KX_SceneDestructionFunc(SG_IObject* node,void* gameobj,void* scene) return NULL; }; -SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks(KX_SceneReplicationFunc,KX_SceneDestructionFunc,KX_GameObject::UpdateTransformFunc); +bool KX_Scene::KX_ScenegraphUpdateFunc(SG_IObject* node,void* gameobj,void* scene) +{ + return ((SG_Node*)node)->Schedule(((KX_Scene*)scene)->m_sghead); +} + +bool KX_Scene::KX_ScenegraphRescheduleFunc(SG_IObject* node,void* gameobj,void* scene) +{ + return ((SG_Node*)node)->Reschedule(((KX_Scene*)scene)->m_sghead); +} + +SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks( + KX_SceneReplicationFunc, + KX_SceneDestructionFunc, + KX_GameObject::UpdateTransformFunc, + KX_Scene::KX_ScenegraphUpdateFunc, + KX_Scene::KX_ScenegraphRescheduleFunc); // temporarily var until there is a button in the userinterface // (defined in KX_PythonInit.cpp) @@ -148,7 +164,6 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_lightlist= new CListValue(); m_inactivelist = new CListValue(); m_euthanasyobjects = new CListValue(); - m_delayReleaseObjects = new CListValue(); m_logicmgr = new SCA_LogicManager(); @@ -192,9 +207,6 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_rootnode = NULL; m_bucketmanager=new RAS_BucketManager(); - - m_canvasDesignWidth = 0; - m_canvasDesignHeight = 0; m_attr_dict = PyDict_New(); /* new ref */ } @@ -231,8 +243,6 @@ KX_Scene::~KX_Scene() if (m_euthanasyobjects) m_euthanasyobjects->Release(); - if (m_delayReleaseObjects) - m_delayReleaseObjects->Release(); if (m_logicmgr) delete m_logicmgr; @@ -254,13 +264,6 @@ KX_Scene::~KX_Scene() Py_DECREF(m_attr_dict); } -void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat) -{ - m_projectionmat = pmat; -} - - - RAS_BucketManager* KX_Scene::GetBucketManager() { return m_bucketmanager; @@ -408,11 +411,11 @@ void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gam KX_GameObject* orgobj = (KX_GameObject*)gameobj; if (NewRemoveObject(orgobj) != 0) { - // object is not yet deleted (this can happen when it hangs in an add object actuator - // last object created reference. It's a bad situation, don't know how to fix it exactly - // The least I can do, is remove the reference to the node in the object as the node - // will in any case be deleted. This ensures that the object will not try to use the node - // when it is finally deleted (see KX_GameObject destructor) + // object is not yet deleted because a reference is hanging somewhere. + // This should not happen anymore since we use proxy object for Python + // confident enough to put an assert? + //assert(false); + printf("Zombie object! name=%s\n", orgobj->GetName().ReadPtr()); orgobj->SetSGNode(NULL); PHY_IGraphicController* ctrl = orgobj->GetGraphicController(); if (ctrl) @@ -477,6 +480,8 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal // this is the list of object that are send to the graphics pipeline m_objectlist->Add(newobj->AddRef()); + if (newobj->IsLight()) + m_lightlist->Add(newobj->AddRef()); newobj->AddMeshUser(); // logic cannot be replicated, until the whole hierarchy is replicated. @@ -537,8 +542,9 @@ void KX_Scene::ReplicateLogic(KX_GameObject* newobj) vector<SCA_IActuator*> linkedactuators = cont->GetLinkedActuators(); // disconnect the sensors and actuators - cont->UnlinkAllSensors(); - cont->UnlinkAllActuators(); + // do it directly on the list at this controller is not connected to anything at this stage + cont->GetLinkedSensors().clear(); + cont->GetLinkedActuators().clear(); // now relink each sensor for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());its++) @@ -716,16 +722,20 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) // set the replica's relative scale with the rootnode's scale replica->NodeSetRelativeScale(newscale); - MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); - replica->NodeSetLocalOrientation(newori); MT_Point3 offset(group->dupli_ofs); MT_Point3 newpos = groupobj->NodeGetWorldPosition() + newscale*(groupobj->NodeGetWorldOrientation() * (gameobj->NodeGetWorldPosition()-offset)); replica->NodeSetLocalPosition(newpos); - + // set the orientation after position for softbody! + MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); + replica->NodeSetLocalOrientation(newori); + // update scenegraph for entire tree of children replica->GetSGNode()->UpdateWorldData(0); replica->GetSGNode()->SetBBox(gameobj->GetSGNode()->BBox()); replica->GetSGNode()->SetRadius(gameobj->GetSGNode()->Radius()); + // we can now add the graphic controller to the physic engine + replica->ActivateGraphicController(true); + // done with replica replica->Release(); } @@ -836,6 +846,8 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, replica->GetSGNode()->UpdateWorldData(0); replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox()); replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius()); + // the size is correct, we can add the graphic controller to the physic engine + replica->ActivateGraphicController(true); // now replicate logic vector<KX_GameObject*>::iterator git; @@ -889,7 +901,7 @@ void KX_Scene::RemoveObject(class CValue* gameobj) { KX_GameObject* newobj = (KX_GameObject*) gameobj; - // first disconnect child from parent + // disconnect child from parent SG_Node* node = newobj->GetSGNode(); if (node) @@ -903,12 +915,6 @@ void KX_Scene::RemoveObject(class CValue* gameobj) //newobj->SetSGNode(0); } -void KX_Scene::DelayedReleaseObject(CValue* gameobj) -{ - m_delayReleaseObjects->Add(gameobj->AddRef()); -} - - void KX_Scene::DelayedRemoveObject(class CValue* gameobj) { //KX_GameObject* newobj = (KX_GameObject*) gameobj; @@ -925,6 +931,13 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) int ret; KX_GameObject* newobj = (KX_GameObject*) gameobj; + /* Invalidate the python reference, since the object may exist in script lists + * its possible that it wont be automatically invalidated, so do it manually here, + * + * if for some reason the object is added back into the scene python can always get a new Proxy + */ + newobj->InvalidateProxy(); + // keep the blender->game object association up to date // note that all the replicas of an object will have the same // blender object, that's why we need to check the game object @@ -954,7 +967,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) for (SCA_ActuatorList::iterator ita = actuators.begin(); !(ita==actuators.end());ita++) { - m_logicmgr->RemoveDestroyedActuator(*ita); + m_logicmgr->RemoveActuator(*ita); } // the sensors/controllers/actuators must also be released, this is done in ~SCA_IObject @@ -1038,6 +1051,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName())); Mesh* blendmesh = mesh->GetMesh(); + bool bHasModifier = BL_ModifierDeformer::HasCompatibleDeformer(blendobj); bool bHasShapeKey = blendmesh->key != NULL && blendmesh->key->type==KEY_RELATIVE; bool bHasDvert = blendmesh->dvert != NULL; bool bHasArmature = @@ -1053,10 +1067,39 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) if (oldblendobj==NULL) { std::cout << "warning: ReplaceMesh() new mesh is not used in an object from the current scene, you will get incorrect behavior" << std::endl; - bHasShapeKey= bHasDvert= bHasArmature= false; + bHasShapeKey= bHasDvert= bHasArmature=bHasModifier= false; } - if (bHasShapeKey) + if (bHasModifier) + { + BL_ModifierDeformer* modifierDeformer; + if (bHasShapeKey || bHasArmature) + { + modifierDeformer = new BL_ModifierDeformer( + newobj, + m_blenderScene, + oldblendobj, blendobj, + static_cast<BL_SkinMeshObject*>(mesh), + true, + static_cast<BL_ArmatureObject*>( parentobj ) + ); + releaseParent= false; + modifierDeformer->LoadShapeDrivers(blendobj->parent); + } + else + { + modifierDeformer = new BL_ModifierDeformer( + newobj, + m_blenderScene, + oldblendobj, blendobj, + static_cast<BL_SkinMeshObject*>(mesh), + false, + NULL + ); + } + newobj->SetDeformer(modifierDeformer); + } + else if (bHasShapeKey) { BL_ShapeDeformer* shapeDeformer; if (bHasArmature) @@ -1066,6 +1109,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), true, + true, static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; @@ -1078,6 +1122,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), false, + true, NULL ); } @@ -1090,6 +1135,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), true, + true, static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; @@ -1112,24 +1158,6 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) gameobj->AddMeshUser(); } - - -MT_CmMatrix4x4& KX_Scene::GetViewMatrix() -{ - MT_Scalar cammat[16]; - m_active_camera->GetWorldToCamera().getValue(cammat); - m_viewmat = cammat; - return m_viewmat; -} - - - -MT_CmMatrix4x4& KX_Scene::GetProjectionMatrix() -{ - return m_projectionmat; -} - - KX_Camera* KX_Scene::FindCamera(KX_Camera* cam) { list<KX_Camera*>::iterator it = m_cameras.begin(); @@ -1423,24 +1451,17 @@ void KX_Scene::LogicEndFrame() { m_logicmgr->EndFrame(); int numobj = m_euthanasyobjects->GetCount(); - int i; - for (i = numobj - 1; i >= 0; i--) - { - KX_GameObject* gameobj = (KX_GameObject*)m_euthanasyobjects->GetValue(i); - // KX_Scene::RemoveObject will also remove the object from this list - // that's why we start from the end - this->RemoveObject(gameobj); - } - numobj= m_delayReleaseObjects->GetCount(); - for (i = numobj-1;i>=0;i--) + KX_GameObject* obj; + + while ((numobj = m_euthanasyobjects->GetCount()) > 0) { - KX_GameObject* gameobj = (KX_GameObject*)m_delayReleaseObjects->GetValue(i); - // This list is not for object removal, but just object release - gameobj->Release(); + // remove the object from this list to make sure we will not hit it again + obj = (KX_GameObject*)m_euthanasyobjects->GetValue(numobj-1); + m_euthanasyobjects->Remove(numobj-1); + obj->Release(); + RemoveObject(obj); } - // empty the list as we have removed all references - m_delayReleaseObjects->Resize(0); } @@ -1450,15 +1471,28 @@ void KX_Scene::LogicEndFrame() */ void KX_Scene::UpdateParents(double curtime) { -// int numrootobjects = GetRootParentList()->GetCount(); + // we use the SG dynamic list + SG_Node* node; - for (int i=0; i<GetRootParentList()->GetCount(); i++) + while ((node = SG_Node::GetNextScheduled(m_sghead)) != NULL) { - KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i); - parentobj->NodeUpdateGS(curtime); + node->UpdateWorldData(curtime); } -} + //for (int i=0; i<GetRootParentList()->GetCount(); i++) + //{ + // KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i); + // parentobj->NodeUpdateGS(curtime); + //} + + // the list must be empty here + assert(m_sghead.Empty()); + // some nodes may be ready for reschedule, move them to schedule list for next time + while ((node = SG_Node::GetNextRescheduled(m_sghead)) != NULL) + { + node->Schedule(m_sghead); + } +} RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool &bucketCreated) @@ -1579,8 +1613,13 @@ double KX_Scene::getSuspendedDelta() //Python PyTypeObject KX_Scene::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_Scene", sizeof(PyObjectPlus_Proxy), 0, @@ -1604,9 +1643,9 @@ PyParentObject KX_Scene::Parents[] = { }; PyMethodDef KX_Scene::Methods[] = { - KX_PYMETHODTABLE(KX_Scene, getLightList), - KX_PYMETHODTABLE(KX_Scene, getObjectList), - KX_PYMETHODTABLE(KX_Scene, getName), + KX_PYMETHODTABLE_NOARGS(KX_Scene, getLightList), + KX_PYMETHODTABLE_NOARGS(KX_Scene, getObjectList), + KX_PYMETHODTABLE_NOARGS(KX_Scene, getName), KX_PYMETHODTABLE(KX_Scene, addObject), {NULL,NULL} //Sentinel @@ -1624,46 +1663,81 @@ PyObject* KX_Scene::pyattr_get_objects(void *self_v, const KX_PYATTRIBUTE_DEF *a return self->GetObjectList()->GetProxy(); } +PyObject* KX_Scene::pyattr_get_objects_inactive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return self->GetInactiveList()->GetProxy(); +} + +PyObject* KX_Scene::pyattr_get_lights(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return self->GetLightList()->GetProxy(); +} + +PyObject* KX_Scene::pyattr_get_cameras(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + /* With refcounts in this case... + * the new CListValue is owned by python, so its possible python holds onto it longer then the BGE + * however this is the same with "scene.objects + []", when you make a copy by adding lists. + */ + + KX_Scene* self= static_cast<KX_Scene*>(self_v); + CListValue* clist = new CListValue(); + + /* return self->GetCameras()->GetProxy(); */ + + list<KX_Camera*>::iterator it = self->GetCameras()->begin(); + while (it != self->GetCameras()->end()) { + clist->Add((*it)->AddRef()); + it++; + } + + return clist->NewProxy(true); +} + PyObject* KX_Scene::pyattr_get_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_Scene* self= static_cast<KX_Scene*>(self_v); return self->GetActiveCamera()->GetProxy(); } -/* __dict__ only for the purpose of giving useful dir() results */ -PyObject* KX_Scene::pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) + +int KX_Scene::pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_Scene* self= static_cast<KX_Scene*>(self_v); - /* Useually done by py_getattro_up but in this case we want to include m_attr_dict dict */ - PyObject *dict_str= PyString_FromString("__dict__"); - PyObject *dict= py_getattr_dict(self->PyObjectPlus::py_getattro(dict_str), Type.tp_dict); - Py_DECREF(dict_str); + KX_Camera *camOb; - PyDict_Update(dict, self->m_attr_dict); - return dict; + if (!ConvertPythonToCamera(value, &camOb, false, "scene.active_camera = value: KX_Scene")) + return PY_SET_ATTR_FAIL; + + self->SetActiveCamera(camOb); + return PY_SET_ATTR_SUCCESS; } + PyAttributeDef KX_Scene::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), - KX_PYATTRIBUTE_RO_FUNCTION("objects", KX_Scene, pyattr_get_objects), - KX_PYATTRIBUTE_RO_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera), - KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), - KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling), + KX_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), + KX_PYATTRIBUTE_RO_FUNCTION("objects", KX_Scene, pyattr_get_objects), + KX_PYATTRIBUTE_RO_FUNCTION("objectsInactive", KX_Scene, pyattr_get_objects_inactive), KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), + KX_PYATTRIBUTE_RO_FUNCTION("cameras", KX_Scene, pyattr_get_cameras), + KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), + KX_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera), + KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), + KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling), KX_PYATTRIBUTE_FLOAT_RW("activity_culling_radius", 0.5f, FLT_MAX, KX_Scene, m_activity_box_radius), - KX_PYATTRIBUTE_BOOL_RO("dbvt_culling", KX_Scene, m_dbvt_culling), - KX_PYATTRIBUTE_RO_FUNCTION("__dict__", KX_Scene, pyattr_get_dir_dict), + KX_PYATTRIBUTE_BOOL_RO("dbvt_culling", KX_Scene, m_dbvt_culling), { NULL } //Sentinel }; - PyObject* KX_Scene::py_getattro__internal(PyObject *attr) { py_getattro_up(PyObjectPlus); } -int KX_Scene::py_setattro__internal(PyObject *attr, PyObject *pyvalue) +int KX_Scene::py_setattro__internal(PyObject *attr, PyObject *value) { - return PyObjectPlus::py_setattro(attr, pyvalue); + py_setattro_up(PyObjectPlus); } PyObject* KX_Scene::py_getattro(PyObject *attr) @@ -1685,6 +1759,18 @@ PyObject* KX_Scene::py_getattro(PyObject *attr) return object; } +PyObject* KX_Scene::py_getattro_dict() { + //py_getattro_dict_up(PyObjectPlus); + + PyObject *dict= py_getattr_dict(PyObjectPlus::py_getattro_dict(), Type.tp_dict); + if(dict==NULL) + return NULL; + + /* normally just return this but KX_Scene has some more items */ + + PyDict_Update(dict, m_attr_dict); + return dict; +} int KX_Scene::py_setattro(PyObject *attr, PyObject *value) { @@ -1715,6 +1801,7 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_Scene, getLightList, "Returns a list of all lights in the scene.\n" ) { + ShowDeprecationWarning("getLightList()", "the lights property"); return m_lightlist->GetProxy(); } @@ -1723,7 +1810,7 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_Scene, getObjectList, "Returns a list of all game objects in the scene.\n" ) { - // ShowDeprecationWarning("getObjectList()", "the objects property"); // XXX Grr, why doesnt this work? + ShowDeprecationWarning("getObjectList()", "the objects property"); return m_objectlist->GetProxy(); } @@ -1732,6 +1819,7 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_Scene, getName, "Returns the name of the scene.\n" ) { + ShowDeprecationWarning("getName()", "the name property"); return PyString_FromString(GetName()); } @@ -1753,5 +1841,9 @@ KX_PYMETHODDEF_DOC(KX_Scene, addObject, SCA_IObject* replica = AddReplicaObject((SCA_IObject*)ob, other, time); + + // release here because AddReplicaObject AddRef's + // the object is added to the scene so we dont want python to own a reference + replica->Release(); return replica->GetProxy(); -}
\ No newline at end of file +} |