diff options
Diffstat (limited to 'source')
42 files changed, 1164 insertions, 45 deletions
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index 8e7560cdcbd..e599b89a2bb 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -40,6 +40,10 @@ #include "KX_KetsjiEngine.h" #include "KX_IPhysicsController.h" #include "BL_Material.h" +#include "KX_BlenderMaterial.h" +#include "KX_PolygonMaterial.h" + + #include "SYS_System.h" #include "DummyPhysicsEnvironment.h" @@ -72,27 +76,48 @@ extern "C" { #include "DNA_object_types.h" #include "DNA_curve_types.h" +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" #include "BLI_blenlib.h" #include "MEM_guardedalloc.h" //XXX #include "BSE_editipo.h" //XXX #include "BSE_editipo_types.h" #include "DNA_ipo_types.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_ipo.h" // eval_icu +#include "BKE_material.h" // copy_material +#include "BKE_mesh.h" // copy_mesh #include "DNA_space_types.h" } +/* Only for dynamic loading and merging */ +#include "RAS_BucketManager.h" // XXX cant stay +#include "KX_BlenderSceneConverter.h" +#include "BL_BlenderDataConversion.h" +#include "KX_MeshProxy.h" +#include "RAS_MeshObject.h" +extern "C" { + #include "BKE_context.h" + #include "BLO_readfile.h" + #include "BKE_report.h" + #include "DNA_space_types.h" + #include "DNA_windowmanager_types.h" /* report api */ + #include "../../blender/blenlib/BLI_linklist.h" +} KX_BlenderSceneConverter::KX_BlenderSceneConverter( struct Main* maggie, class KX_KetsjiEngine* engine ) : m_maggie(maggie), + /*m_maggie_dyn(NULL),*/ m_ketsjiEngine(engine), m_alwaysUseExpandFraming(false), m_usemat(false), m_useglslmat(false) { + tag_main(maggie, 0); /* avoid re-tagging later on */ m_newfilename = ""; } @@ -141,9 +166,14 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter() KX_ClearBulletSharedShapes(); #endif -} - + /* free any data that was dynamically loaded */ + for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++) { + Main *main= *it; + free_main(main); + } + m_DynamicMaggie.clear(); +} void KX_BlenderSceneConverter::SetNewFileName(const STR_String& filename) { @@ -183,6 +213,14 @@ Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String& name) if (name == (sce->id.name+2)) return sce; + for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++) { + Main *main= *it; + + for (sce= (Scene*) main->scene.first; sce; sce= (Scene*) sce->id.next) + if (name == (sce->id.name+2)) + return sce; + } + return (Scene*)m_maggie->scene.first; } @@ -490,7 +528,9 @@ void KX_BlenderSceneConverter::RegisterGameMesh( RAS_MeshObject *gamemesh, struct Mesh *for_blendermesh) { - m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh); + if(for_blendermesh) { /* dynamically loaded meshes we dont want to keep lookups for */ + m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh); + } m_meshobjects.push_back(pair<KX_Scene*,RAS_MeshObject*>(m_currentScene,gamemesh)); } @@ -925,3 +965,480 @@ PyObject *KX_BlenderSceneConverter::GetPyNamespace() return m_ketsjiEngine->GetPyNamespace(); } #endif + +vector<Main*> &KX_BlenderSceneConverter::GetMainDynamic() +{ + return m_DynamicMaggie; +} + +Main* KX_BlenderSceneConverter::GetMainDynamicPath(const char *path) +{ + for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++) + if(strcmp((*it)->name, path)==0) + return *it; + + return NULL; +} + +bool KX_BlenderSceneConverter::LinkBlendFile(const char *path, char *group, KX_Scene *scene_merge, char **err_str) +{ + bContext *C; + Main *main_newlib; /* stored as a dynamic 'main' until we free it */ + Main *main_tmp= NULL; /* created only for linking, then freed */ + LinkNode *names = NULL; + BlendHandle *bpy_openlib = NULL; /* ptr to the open .blend file */ + int idcode= BLO_idcode_from_name(group); + short flag= 0; /* dont need any special options */ + ReportList reports; + static char err_local[255]; + + /* only scene and mesh supported right now */ + if(idcode!=ID_SCE && idcode!=ID_ME) { + snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group); + return false; + } + + if(GetMainDynamicPath(path)) { + snprintf(err_local, sizeof(err_local), "blend file alredy open \"%s\"\n", path); + *err_str= err_local; + return false; + } + + bpy_openlib = BLO_blendhandle_from_file( (char *)path ); + if(bpy_openlib==NULL) { + snprintf(err_local, sizeof(err_local), "could not open blendfile \"%s\"\n", path); + *err_str= err_local; + return false; + } + + main_newlib= (Main *)MEM_callocN( sizeof(Main), "BgeMain"); + C= CTX_create(); + CTX_data_main_set(C, main_newlib); + BKE_reports_init(&reports, RPT_STORE); + + /* here appending/linking starts */ + main_tmp = BLO_library_append_begin(C, &bpy_openlib, (char *)path); + + names = BLO_blendhandle_get_datablock_names( bpy_openlib, idcode); + + int i=0; + LinkNode *n= names; + while(n) { + BLO_library_append_named_part(C, main_tmp, &bpy_openlib, (char *)n->link, idcode, 0); + n= (LinkNode *)n->next; + i++; + } + BLI_linklist_free(names, free); /* free linklist *and* each node's data */ + + BLO_library_append_end(C, main_tmp, &bpy_openlib, idcode, flag); + BLO_blendhandle_close(bpy_openlib); + + CTX_free(C); + BKE_reports_clear(&reports); + /* done linking */ + + /* needed for lookups*/ + GetMainDynamic().push_back(main_newlib); + strncpy(main_newlib->name, path, sizeof(main_newlib->name)); + + + if(idcode==ID_ME) { + /* Convert all new meshes into BGE meshes */ + ID* mesh; + KX_Scene *kx_scene= m_currentScene; + + for(mesh= (ID *)main_newlib->mesh.first; mesh; mesh= (ID *)mesh->next ) { + RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)mesh, NULL, scene_merge, this); + kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); + } + } + else if(idcode==ID_SCE) { + /* Merge all new linked in scene into the existing one */ + ID *scene; + for(scene= (ID *)main_newlib->scene.first; scene; scene= (ID *)scene->next ) { + printf("SceneName: %s\n", scene->name); + + /* merge into the base scene */ + KX_Scene* other= m_ketsjiEngine->CreateScene((Scene *)scene); + scene_merge->MergeScene(other); + + // RemoveScene(other); // Dont run this, it frees the entire scene converter data, just delete the scene + delete other; + } + } + + return true; +} + +/* Note m_map_*** are all ok and dont need to be freed + * most are temp and NewRemoveObject frees m_map_gameobject_to_blender */ +bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie) +{ + int maggie_index; + int i=0; + + if(maggie==NULL) + return false; + + /* tag all false except the one we remove */ + for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++) { + Main *main= *it; + if(main != maggie) { + tag_main(main, 0); + } + else { + maggie_index= i; + } + i++; + } + + m_DynamicMaggie.erase(m_DynamicMaggie.begin() + maggie_index); + tag_main(maggie, 1); + + + /* free all tagged objects */ + KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes(); + int numScenes = scenes->size(); + + + for (int scene_idx=0;scene_idx<numScenes;scene_idx++) + { + KX_Scene* scene = scenes->at(scene_idx); + if(IS_TAGGED(scene->GetBlenderScene())) { + RemoveScene(scene); // XXX - not tested yet + scene_idx--; + numScenes--; + } + else { + + /* incase the mesh might be refered to later */ + { + GEN_Map<STR_HashedString,void*> &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap(); + + for(int i=0; i<mapStringToMeshes.size(); i++) + { + RAS_MeshObject *meshobj= (RAS_MeshObject *) *mapStringToMeshes.at(i); + if(meshobj && IS_TAGGED(meshobj->GetMesh())) + { + STR_HashedString mn = meshobj->GetName(); + mapStringToMeshes.remove(mn); + i--; + } + } + } + + //scene->FreeTagged(); /* removed tagged objects and meshes*/ + CListValue *obj_lists[] = {scene->GetObjectList(), scene->GetInactiveList(), NULL}; + + for(int ob_ls_idx=0; obj_lists[ob_ls_idx]; ob_ls_idx++) + { + CListValue *obs= obj_lists[ob_ls_idx]; + RAS_MeshObject* mesh; + + for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++) + { + KX_GameObject* gameobj = (KX_GameObject*)obs->GetValue(ob_idx); + if(IS_TAGGED(gameobj->GetBlenderObject())) { + + int size_before = obs->GetCount(); + + /* Eventually calls RemoveNodeDestructObject + * frees m_map_gameobject_to_blender from UnregisterGameObject */ + scene->RemoveObject(gameobj); + + if(size_before != obs->GetCount()) + ob_idx--; + else { + printf("ERROR COULD NOT REMOVE \"%s\"\n", gameobj->GetName().ReadPtr()); + } + } + else { + /* free the mesh, we could be referecing a linked one! */ + int mesh_index= gameobj->GetMeshCount(); + while(mesh_index--) { + mesh= gameobj->GetMesh(mesh_index); + if(IS_TAGGED(mesh->GetMesh())) { + gameobj->RemoveMeshes(); /* XXX - slack, should only remove meshes that are library items but mostly objects only have 1 mesh */ + break; + } + } + } + } + } + } + } + + + int size; + + // delete the entities of this scene + /* TODO - */ + /* + vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit; + size = m_worldinfos.size(); + for (i=0, worldit=m_worldinfos.begin(); i<size; ) { + if ((*worldit).second) { + delete (*worldit).second; + *worldit = m_worldinfos.back(); + m_worldinfos.pop_back(); + size--; + } else { + i++; + worldit++; + } + }*/ + + + /* Worlds dont reference original blender data so we need to make a set from them */ + typedef std::set<KX_WorldInfo*> KX_WorldInfoSet; + KX_WorldInfoSet worldset; + for (int scene_idx=0;scene_idx<numScenes;scene_idx++) + { + KX_Scene* scene = scenes->at(scene_idx); + if(scene->GetWorldInfo()) + worldset.insert( scene->GetWorldInfo() ); + } + + vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit; + size = m_worldinfos.size(); + for (i=0, worldit=m_worldinfos.begin(); i<size; ) { + if ((*worldit).second && (worldset.count((*worldit).second)) == 0) { + delete (*worldit).second; + *worldit = m_worldinfos.back(); + m_worldinfos.pop_back(); + size--; + } else { + i++; + worldit++; + } + } + worldset.clear(); + /* done freeing the worlds */ + + + + + vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator polymit; + size = m_polymaterials.size(); + + + + for (i=0, polymit=m_polymaterials.begin(); i<size; ) { + RAS_IPolyMaterial *mat= (*polymit).second; + Material *bmat= NULL; + + /* Why do we need to check for RAS_BLENDERMAT if both are cast to a (PyObject*)? - Campbell */ + if(mat->GetFlag() & RAS_BLENDERMAT) { + KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat); + bmat= bl_mat->GetBlenderMaterial(); + + } else { + KX_PolygonMaterial *kx_mat = static_cast<KX_PolygonMaterial*>(mat); + bmat= kx_mat->GetBlenderMaterial(); + } + + if (IS_TAGGED(bmat)) { + /* only remove from bucket */ + ((*polymit).first)->GetBucketManager()->RemoveMaterial(mat); + } + + i++; + polymit++; + } + + + + for (i=0, polymit=m_polymaterials.begin(); i<size; ) { + RAS_IPolyMaterial *mat= (*polymit).second; + Material *bmat= NULL; + + /* Why do we need to check for RAS_BLENDERMAT if both are cast to a (PyObject*)? - Campbell */ + if(mat->GetFlag() & RAS_BLENDERMAT) { + KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat); + bmat= bl_mat->GetBlenderMaterial(); + + } else { + KX_PolygonMaterial *kx_mat = static_cast<KX_PolygonMaterial*>(mat); + bmat= kx_mat->GetBlenderMaterial(); + } + + if(bmat) { + //printf("FOUND MAT '%s' !!! ", ((ID*)bmat)->name+2); + } + else { + //printf("LOST MAT !!!"); + } + + if (IS_TAGGED(bmat)) { + + delete (*polymit).second; + *polymit = m_polymaterials.back(); + m_polymaterials.pop_back(); + size--; + //printf("tagged !\n"); + } else { + i++; + polymit++; + //printf("(un)tagged !\n"); + } + } + + vector<pair<KX_Scene*,BL_Material*> >::iterator matit; + size = m_materials.size(); + for (i=0, matit=m_materials.begin(); i<size; ) { + BL_Material *mat= (*matit).second; + if (IS_TAGGED(mat->material)) { + delete (*matit).second; + *matit = m_materials.back(); + m_materials.pop_back(); + size--; + } else { + i++; + matit++; + } + } + + vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator meshit; + size = m_meshobjects.size(); + for (i=0, meshit=m_meshobjects.begin(); i<size; ) { + RAS_MeshObject *me= (*meshit).second; + if (IS_TAGGED(me->GetMesh())) { + delete (*meshit).second; + *meshit = m_meshobjects.back(); + m_meshobjects.pop_back(); + size--; + } else { + i++; + meshit++; + } + } + + free_main(maggie); + + return true; +} + +bool KX_BlenderSceneConverter::FreeBlendFile(const char *path) +{ + return FreeBlendFile(GetMainDynamicPath(path)); +} + +bool KX_BlenderSceneConverter::MergeScene(KX_Scene *to, KX_Scene *from) +{ + + { + vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator itp = m_worldinfos.begin(); + while (itp != m_worldinfos.end()) { + if ((*itp).first==from) + (*itp).first= to; + itp++; + } + } + + { + vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator itp = m_polymaterials.begin(); + while (itp != m_polymaterials.end()) { + if ((*itp).first==from) { + (*itp).first= to; + + /* also switch internal data */ + RAS_IPolyMaterial*mat= (*itp).second; + mat->Replace_IScene(to); + } + itp++; + } + } + + { + vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator itp = m_meshobjects.begin(); + while (itp != m_meshobjects.end()) { + if ((*itp).first==from) + (*itp).first= to; + itp++; + } + } + + { + vector<pair<KX_Scene*,BL_Material*> >::iterator itp = m_materials.begin(); + while (itp != m_materials.end()) { + if ((*itp).first==from) + (*itp).first= to; + itp++; + } + } + + return true; +} + +/* This function merges a mesh from the current scene into another main + * it does not convert */ +RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene* kx_scene, Main *maggie, const char *name) +{ + ID *me; + + /* Find a mesh in the current main */ + for(me = (ID *)m_maggie->mesh.first; me; me= (ID *)me->next) + if(strcmp(name, me->name+2)==0) + break; + + if(me==NULL) { + printf("Could not be found \"%s\"\n", name); + return NULL; + } + + /* Watch this!, if its used in the original scene can cause big troubles */ + if(me->us > 0) { + printf("Mesh has a user \"%s\"\n", name); + me = (ID*)copy_mesh((Mesh*)me); + me->us--; + } + BLI_remlink(&m_maggie->mesh, me); /* even if we made the copy it needs to be removed */ + BLI_addtail(&maggie->mesh, me); + + + /* Must copy the materials this uses else we cant free them */ + { + Mesh *mesh= (Mesh *)me; + + /* ensure all materials are tagged */ + for(int i=0; i<mesh->totcol; i++) + if(mesh->mat[i]) + mesh->mat[i]->id.flag &= ~LIB_DOIT; + + for(int i=0; i<mesh->totcol; i++) + { + Material *mat_old= mesh->mat[i]; + + /* if its tagged its a replaced material */ + if(mat_old && (mat_old->id.flag & LIB_DOIT)==0) + { + Material *mat_old= mesh->mat[i]; + Material *mat_new= copy_material( mat_old ); + + mat_new->id.flag |= LIB_DOIT; + mat_old->id.us--; + + BLI_remlink(&m_maggie->mat, mat_new); + BLI_addtail(&maggie->mat, mat_new); + + mesh->mat[i]= mat_new; + + /* the same material may be used twice */ + for(int j=i+1; j<mesh->totcol; j++) + { + if(mesh->mat[j]==mat_old) + { + mesh->mat[j]= mat_new; + mat_new->id.us++; + mat_old->id.us--; + } + } + } + } + } + + RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)me, NULL, kx_scene, this); + kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); + m_map_mesh_to_gamemesh.clear(); /* This is at runtime so no need to keep this, BL_ConvertMesh adds */ + return meshobj; +} diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h index f74944d3552..62d771f1256 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h @@ -64,6 +64,7 @@ class KX_BlenderSceneConverter : public KX_ISceneConverter GEN_Map<CHashedPtr,BL_InterpolatorList*> m_map_blender_to_gameAdtList; Main* m_maggie; + vector<struct Main*> m_DynamicMaggie; STR_String m_newfilename; class KX_KetsjiEngine* m_ketsjiEngine; @@ -140,7 +141,39 @@ public: struct Scene* GetBlenderSceneForName(const STR_String& name); - struct Main* GetMain() { return m_maggie; }; +// struct Main* GetMain() { return m_maggie; }; + struct Main* GetMainDynamicPath(const char *path); + vector<struct Main*> &GetMainDynamic(); + + bool LinkBlendFile(const char *path, char *group, KX_Scene *scene_merge, char **err_str); + bool MergeScene(KX_Scene *to, KX_Scene *from); + RAS_MeshObject *ConvertMeshSpecial(KX_Scene* kx_scene, Main *maggie, const char *name); + bool FreeBlendFile(struct Main *maggie); + bool FreeBlendFile(const char *path); + + void PrintStats() { + printf("BGE STATS!\n"); + + printf("\nAssets...\n"); + printf("\t m_worldinfos: %d\n", m_worldinfos.size()); + printf("\t m_polymaterials: %d\n", m_polymaterials.size()); + printf("\t m_meshobjects: %d\n", m_meshobjects.size()); + printf("\t m_materials: %d\n", m_materials.size()); + + printf("\nMappings...\n"); + printf("\t m_map_blender_to_gameobject: %d\n", m_map_blender_to_gameobject.size()); + printf("\t m_map_mesh_to_gamemesh: %d\n", m_map_mesh_to_gamemesh.size()); + printf("\t m_map_blender_to_gameactuator: %d\n", m_map_blender_to_gameactuator.size()); + printf("\t m_map_blender_to_gamecontroller: %d\n", m_map_blender_to_gamecontroller.size()); + printf("\t m_map_blender_to_gameAdtList: %d\n", m_map_blender_to_gameAdtList.size()); + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_printmemlist_pydict(); +#endif +// /printf("\t m_ketsjiEngine->m_scenes: %d\n", m_ketsjiEngine->CurrentScenes()->size()); + } + + #ifndef DISABLE_PYTHON PyObject *GetPyNamespace(); diff --git a/source/gameengine/GameLogic/SCA_EventManager.h b/source/gameengine/GameLogic/SCA_EventManager.h index debefcc45b0..8d3610acc5f 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.h +++ b/source/gameengine/GameLogic/SCA_EventManager.h @@ -70,6 +70,11 @@ public: virtual void EndFrame(); virtual void RegisterSensor(class SCA_ISensor* sensor); int GetType(); + //SG_DList &GetSensors() { return m_sensors; } + + + void Replace_LogicManager(SCA_LogicManager* logicmgr) { m_logicmgr= logicmgr; } + virtual void Replace_PhysicsScene(class PHY_IPhysicsEnvironment* env) { } /* only for event managers that use one */ protected: EVENT_MANAGER_TYPE m_mgrtype; diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.h b/source/gameengine/GameLogic/SCA_ILogicBrick.h index 11885f988f3..cebfcf6bdc4 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.h +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.h @@ -35,6 +35,9 @@ #include "GEN_Map.h" #include "GEN_HashedPtr.h" +class NG_NetworkScene; +class SCA_IScene; + class SCA_ILogicBrick : public CValue { Py_Header; @@ -122,9 +125,14 @@ public: virtual bool LessComparedTo(SCA_ILogicBrick* other); + /* runtime variable, set when Triggering the python controller */ static class SCA_LogicManager* m_sCurrentLogicManager; + /* for moving logic bricks between scenes */ + virtual void Replace_IScene(SCA_IScene *val) {}; + virtual void Replace_NetworkScene(NG_NetworkScene *val) {}; + #ifndef DISABLE_PYTHON // python methods diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp index 877563e3161..3191c99fb2f 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.cpp +++ b/source/gameengine/GameLogic/SCA_ISensor.cpp @@ -160,6 +160,19 @@ void SCA_ISensor::RegisterToManager() m_eventmgr->RegisterSensor(this); } +void SCA_ISensor::Replace_EventManager(class SCA_LogicManager* logicmgr) +{ + if(m_links) { /* true if we're used currently */ + + m_eventmgr->RemoveSensor(this); + m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType()); + m_eventmgr->RegisterSensor(this); + } + else { + m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType()); + } +} + void SCA_ISensor::LinkToController(SCA_IController* controller) { m_linkedcontrollers.push_back(controller); diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h index fce5f340be1..e01f5775289 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.h +++ b/source/gameengine/GameLogic/SCA_ISensor.h @@ -133,6 +133,7 @@ public: virtual void RegisterToManager(); virtual void UnregisterToManager(); + void Replace_EventManager(class SCA_LogicManager* logicmgr); void ReserveController(int num) { m_linkedcontrollers.reserve(num); diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index d93f2e70e36..848b7df6658 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -282,6 +282,11 @@ void SCA_LogicManager::RegisterMeshName(const STR_String& meshname,void* mesh) m_mapStringToMeshes.insert(mn,mesh); } +void SCA_LogicManager::UnregisterMeshName(const STR_String& meshname,void* mesh) +{ + STR_HashedString mn = meshname; + m_mapStringToMeshes.remove(mn); +} void SCA_LogicManager::RegisterActionName(const STR_String& actname,void* action) diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h index 402090357cb..0c2effc2516 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.h +++ b/source/gameengine/GameLogic/SCA_LogicManager.h @@ -66,6 +66,7 @@ typedef std::map<class SCA_ISensor*,controllerlist > sensormap_t; #include "SCA_ILogicBrick.h" #include "SCA_IActuator.h" +#include "SCA_EventManager.h" class SCA_LogicManager @@ -110,6 +111,7 @@ public: void AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor); SCA_EventManager* FindEventManager(int eventmgrtype); + vector<class SCA_EventManager*> GetEventManagers() { return m_eventmanagers; } void RemoveGameObject(const STR_String& gameobjname); @@ -123,6 +125,9 @@ public: // for the scripting... needs a FactoryManager later (if we would have time... ;) void RegisterMeshName(const STR_String& meshname,void* mesh); + void UnregisterMeshName(const STR_String& meshname,void* mesh); + GEN_Map<STR_HashedString,void*>& GetMeshMap() { return m_mapStringToMeshes; }; + void RegisterActionName(const STR_String& actname,void* action); void* GetActionByName (const STR_String& actname); diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h index fa7a674c250..95283dcce50 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h @@ -55,6 +55,10 @@ public: virtual bool Update(); virtual CValue* GetReplica(); + virtual void Replace_NetworkScene(NG_NetworkScene *val) + { + m_networkscene= val; + }; /* ------------------------------------------------------------ */ /* Python interface ------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h index 3a8fe760bb9..90ba5db15ef 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h @@ -66,6 +66,11 @@ public: virtual void Init(); void EndFrame(); + virtual void Replace_NetworkScene(NG_NetworkScene *val) + { + m_NetworkScene= val; + }; + #ifndef DISABLE_PYTHON /* ------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 0946cd320c5..088d17ea741 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -19,6 +19,9 @@ #include "MEM_guardedalloc.h" #endif +#include "SCA_IScene.h" /* only for Replace_IScene */ +#include "KX_Scene.h" + struct MTFace; class KX_Scene; @@ -68,6 +71,7 @@ public: TCachingInfo& cachingInfo )const; + Material* GetBlenderMaterial() const; MTFace* GetMTFace(void) const; unsigned int* GetMCol(void) const; BL_Texture * getTex (unsigned int idx) { @@ -83,6 +87,11 @@ public: MT_Scalar ref, MT_Scalar emit, MT_Scalar alpha ); + virtual void Replace_IScene(SCA_IScene *val) + { + mScene= static_cast<KX_Scene *>(val); + }; + #ifndef DISABLE_PYTHON // -------------------------------- virtual PyObject* py_repr(void) { return PyUnicode_FromString(mMaterial->matname.ReadPtr()); } @@ -119,7 +128,6 @@ private: bool UsesLighting(RAS_IRasterizer *rasty) const; void GetMaterialRGBAColor(unsigned char *rgba) const; - Material* GetBlenderMaterial() const; Scene* GetBlenderScene() const; void ReleaseMaterial(); diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp index bc0f875bca6..d6e2a623007 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.cpp +++ b/source/gameengine/Ketsji/KX_GameActuator.cpp @@ -51,7 +51,7 @@ KX_GameActuator::KX_GameActuator(SCA_IObject *gameobj, int mode, const STR_String& filename, const STR_String& loadinganimationname, - KX_Scene* scene, + SCA_IScene* scene, KX_KetsjiEngine* ketsjiengine) : SCA_IActuator(gameobj, KX_ACT_GAME) { diff --git a/source/gameengine/Ketsji/KX_GameActuator.h b/source/gameengine/Ketsji/KX_GameActuator.h index 37d09a5a9fb..4880d476e36 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.h +++ b/source/gameengine/Ketsji/KX_GameActuator.h @@ -35,6 +35,9 @@ #include "SCA_IActuator.h" +#include "SCA_IScene.h" /* Replace_IScene only */ +#include "KX_Scene.h" /* Replace_IScene only */ + class KX_GameActuator : public SCA_IActuator { Py_Header; @@ -43,7 +46,7 @@ protected: bool m_restart; STR_String m_filename; STR_String m_loadinganimationname; - class KX_Scene* m_scene; + class SCA_IScene* m_scene; class KX_KetsjiEngine* m_ketsjiengine; public: @@ -64,7 +67,7 @@ protected: int mode, const STR_String& filename, const STR_String& loadinganimationname, - KX_Scene* scene, + SCA_IScene* scene, KX_KetsjiEngine* ketsjiEngine); virtual ~KX_GameActuator(); @@ -72,6 +75,11 @@ protected: virtual bool Update(); + virtual void Replace_IScene(SCA_IScene *val) + { + m_scene= val; + }; + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 9f4fa9a7c02..6800b2aa871 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -1606,15 +1606,12 @@ void KX_KetsjiEngine::RemoveScheduledScenes() } } - - -KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename) +KX_Scene* KX_KetsjiEngine::CreateScene(Scene *scene) { - Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename); KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice, m_mousedevice, m_networkdevice, - scenename, + scene->id.name+2, scene); m_sceneconverter->ConvertScene(tmpscene, @@ -1624,7 +1621,11 @@ KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename) return tmpscene; } - +KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename) +{ + Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename); + return CreateScene(scene); +} void KX_KetsjiEngine::AddScheduledScenes() { diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 74d683fbad6..b815ca0c716 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -380,6 +380,9 @@ public: * @param b Blue component of the override color. */ void GetOverrideFrameColor(float& r, float& g, float& b) const; + + KX_Scene* CreateScene(const STR_String& scenename); + KX_Scene* CreateScene(Scene *scene); protected: /** @@ -399,7 +402,6 @@ protected: void AddScheduledScenes(void); void ReplaceScheduledScenes(void); void PostProcessScene(class KX_Scene* scene); - KX_Scene* CreateScene(const STR_String& scenename); bool BeginFrame(); void ClearFrame(); diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index d4063ef1d16..e3f0e2b34f5 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -66,6 +66,13 @@ class KX_MouseFocusSensor : public SCA_MouseSensor replica->ProcessReplica(); return replica; }; + + virtual void Replace_IScene(SCA_IScene *val) + { + m_kxscene= static_cast<KX_Scene *>(val); + }; + + /** * @attention Overrides default evaluate. */ diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.h b/source/gameengine/Ketsji/KX_PolygonMaterial.h index dba12acee7f..4f7d7f7888d 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.h +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.h @@ -102,6 +102,11 @@ public: void DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const; virtual bool Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const; + Material *GetBlenderMaterial() const + { + return m_material; + } + /** * Returns the Blender texture face structure that is used for this material. * @return The material's texture face. diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 1339200a740..ae4f3498471 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -30,9 +30,6 @@ #include "GL/glew.h" -// directory header for py function getBlendFileList -#include <stdlib.h> - #ifdef WIN32 #pragma warning (disable : 4786) #endif //WIN32 @@ -50,6 +47,16 @@ extern "C" { #endif #include "KX_PythonInit.h" + +// directory header for py function getBlendFileList +#ifndef WIN32 + #include <dirent.h> + #include <stdlib.h> +#else + #include <io.h> + #include "BLI_winstuff.h" +#endif + //python physics binding #include "KX_PyConstraintBinding.h" @@ -82,6 +89,8 @@ extern "C" { #include "InputParser.h" #include "KX_Scene.h" +#include "NG_NetworkScene.h" //Needed for sendMessage() + #include "BL_Shader.h" #include "KX_PyMath.h" @@ -100,12 +109,16 @@ extern "C" { #include "BKE_global.h" #include "BLI_blenlib.h" #include "GPU_material.h" +#include "MEM_guardedalloc.h" + +/* for converting new scenes */ +#include "KX_BlenderSceneConverter.h" +#include "KX_MeshProxy.h" /* for creating a new library of mesh objects */ +extern "C" { + #include "BLO_readfile.h" +} + -#ifndef WIN32 - #include <dirent.h> -#else - #include "BLI_winstuff.h" -#endif #include "NG_NetworkScene.h" //Needed for sendMessage() static void setSandbox(TPythonSecurityLevel level); @@ -509,10 +522,16 @@ static PyObject* gPyGetSceneList(PyObject* self) KX_Scene* scene = scenes->at(i); PyList_SET_ITEM(list, i, scene->GetProxy()); } - + return list; } +static PyObject *pyPrintStats(PyObject *,PyObject *,PyObject *) +{ + gp_KetsjiScene->GetSceneConverter()->PrintStats(); + Py_RETURN_NONE; +} + static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) { #define pprint(x) std::cout << x << std::endl; @@ -584,6 +603,116 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) Py_RETURN_NONE; } +static PyObject *gLibLoad(PyObject*, PyObject* args) +{ + KX_Scene *kx_scene= gp_KetsjiScene; + char *path; + char *group; + char *err_str= NULL; + + if (!PyArg_ParseTuple(args,"ss:LibLoad",&path, &group)) + return NULL; + + if(kx_scene->GetSceneConverter()->LinkBlendFile(path, group, kx_scene, &err_str)) { + Py_RETURN_TRUE; + } + + if(err_str) { + PyErr_SetString(PyExc_ValueError, err_str); + return NULL; + } + + Py_RETURN_FALSE; +} + +static PyObject *gLibNew(PyObject*, PyObject* args) +{ + KX_Scene *kx_scene= gp_KetsjiScene; + char *path; + char *group; + char *name; + PyObject *names; + int idcode; + + if (!PyArg_ParseTuple(args,"ssO!:LibNew",&path, &group, &PyList_Type, &names)) + return NULL; + + if(kx_scene->GetSceneConverter()->GetMainDynamicPath(path)) + { + PyErr_SetString(PyExc_KeyError, "the name of the path given exists"); + return NULL; + } + + idcode= BLO_idcode_from_name(group); + if(idcode==0) { + PyErr_Format(PyExc_ValueError, "invalid group given \"%s\"", group); + return NULL; + } + + Main *maggie= (Main *)MEM_callocN( sizeof(Main), "BgeMain"); + kx_scene->GetSceneConverter()->GetMainDynamic().push_back(maggie); + strncpy(maggie->name, path, sizeof(maggie->name)-1); + + /* Copy the object into main */ + if(idcode==ID_ME) { + PyObject *ret= PyList_New(0); + PyObject *item; + for(int i= 0; i < PyList_GET_SIZE(names); i++) { + name= _PyUnicode_AsString(PyList_GET_ITEM(names, i)); + if(name) { + RAS_MeshObject *meshobj= kx_scene->GetSceneConverter()->ConvertMeshSpecial(kx_scene, maggie, name); + if(meshobj) { + KX_MeshProxy* meshproxy = new KX_MeshProxy(meshobj); + item= meshproxy->NewProxy(true); + PyList_Append(ret, item); + Py_DECREF(item); + } + } + else { + PyErr_Clear(); /* wasnt a string, ignore for now */ + } + } + + return ret; + } + else { + PyErr_Format(PyExc_ValueError, "only \"Mesh\" group currently supported"); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject *gLibFree(PyObject*, PyObject* args) +{ + KX_Scene *kx_scene= gp_KetsjiScene; + char *path; + + if (!PyArg_ParseTuple(args,"s:LibFree",&path)) + return NULL; + + if (kx_scene->GetSceneConverter()->FreeBlendFile(path)) + { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject *gLibList(PyObject*, PyObject* args) +{ + vector<Main*> &dynMaggie = gp_KetsjiScene->GetSceneConverter()->GetMainDynamic(); + int i= 0; + PyObject *list= PyList_New(dynMaggie.size()); + + for (vector<Main*>::iterator it=dynMaggie.begin(); !(it==dynMaggie.end()); it++) + { + PyList_SET_ITEM(list, i++, PyUnicode_FromString( (*it)->name) ); + } + + return list; +} static struct PyMethodDef game_methods[] = { {"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, (const char *)gPyExpandPath_doc}, @@ -616,6 +745,14 @@ static struct PyMethodDef game_methods[] = { {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"}, {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (const char *)"Gets a list of blend files in the same directory as the current blend file"}, {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (const char *)"Prints GL Extension Info"}, + {"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine stastics"}, + + /* library functions */ + {"LibLoad", (PyCFunction)gLibLoad, METH_VARARGS, (const char *)""}, + {"LibNew", (PyCFunction)gLibNew, METH_VARARGS, (const char *)""}, + {"LibFree", (PyCFunction)gLibFree, METH_VARARGS, (const char *)""}, + {"LibList", (PyCFunction)gLibList, METH_VARARGS, (const char *)""}, + {NULL, (PyCFunction) NULL, 0, NULL } }; diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index 39b447b5657..ea7dd544cb1 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -34,6 +34,8 @@ #include "SCA_ISensor.h" #include "MT_Point3.h" +#include "SCA_IScene.h" /* only for scene replace */ +#include "KX_Scene.h" /* only for scene replace */ struct KX_ClientObjectInfo; class KX_RayCast; @@ -73,6 +75,10 @@ public: bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); bool NeedRayCast(KX_ClientObjectInfo* client); + virtual void Replace_IScene(SCA_IScene *val) + { + m_scene= static_cast<KX_Scene *>(val); + } //Python Interface enum RayAxis { diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h index 4cccc406b58..53a71e3c6ea 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h @@ -43,6 +43,8 @@ #include "MT_Vector3.h" + + class SCA_IScene; class KX_SCA_AddObjectActuator : public SCA_IActuator @@ -100,6 +102,11 @@ public: virtual void ProcessReplica(); + virtual void Replace_IScene(SCA_IScene *val) + { + m_scene= val; + }; + virtual bool UnlinkObject(SCA_IObject* clientobj); diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h index 782a24b1ef1..b99f40be707 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h @@ -59,6 +59,11 @@ class KX_SCA_EndObjectActuator : public SCA_IActuator virtual bool Update(); + virtual void Replace_IScene(SCA_IScene *val) + { + m_scene= val; + }; + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h index 47c823afa9f..5f62c603ac6 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h @@ -80,6 +80,11 @@ class KX_SCA_ReplaceMeshActuator : public SCA_IActuator /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ + virtual void Replace_IScene(SCA_IScene *val) + { + m_scene= val; + }; + static PyObject* pyattr_get_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index c93ead74182..655c8eedaae 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -273,6 +273,10 @@ RAS_BucketManager* KX_Scene::GetBucketManager() } +CListValue* KX_Scene::GetTempObjectList() +{ + return m_tempObjectList; +} CListValue* KX_Scene::GetObjectList() { @@ -280,7 +284,6 @@ CListValue* KX_Scene::GetObjectList() } - CListValue* KX_Scene::GetRootParentList() { return m_parentlist; @@ -1043,7 +1046,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u newobj->SetDeformer(NULL); } - if (mesh->IsDeformed()) + if (mesh->IsDeformed()) /* checks GetMesh() isnt NULL */ { // we must create a new deformer but which one? KX_GameObject* parentobj = newobj->GetParent(); @@ -1588,10 +1591,10 @@ void KX_Scene::SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter) void KX_Scene::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv) { m_physicsEnvironment = physEnv; - - KX_TouchEventManager* touchmgr = new KX_TouchEventManager(m_logicmgr, physEnv); - m_logicmgr->RegisterEventManager(touchmgr); - return; + if(m_physicsEnvironment) { + KX_TouchEventManager* touchmgr = new KX_TouchEventManager(m_logicmgr, physEnv); + m_logicmgr->RegisterEventManager(touchmgr); + } } void KX_Scene::setSuspendedTime(double suspendedtime) @@ -1613,6 +1616,182 @@ double KX_Scene::getSuspendedDelta() #ifndef DISABLE_PYTHON + +#include "KX_BulletPhysicsController.h" + +static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *to) +{ + SCA_LogicManager *logicmgr= to->GetLogicManager(); + + brick->Replace_IScene(to); + brick->Replace_NetworkScene(to->GetNetworkScene()); + + SCA_ISensor *sensor= dynamic_cast<class SCA_ISensor *>(brick); + if(sensor) { + sensor->Replace_EventManager(logicmgr); + } + + /* near sensors have physics controllers */ + KX_TouchSensor *touch_sensor = dynamic_cast<class KX_TouchSensor *>(brick); + if(touch_sensor) { + touch_sensor->GetPhysicsController()->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); + } +} + +#include "CcdGraphicController.h" // XXX ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); +#include "CcdPhysicsEnvironment.h" // XXX ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); +#include "KX_BulletPhysicsController.h" + + +static void MergeScene_GameObject(KX_GameObject* gameobj, KX_Scene *to, KX_Scene *from) +{ + { + SCA_ActuatorList& actuators= gameobj->GetActuators(); + SCA_ActuatorList::iterator ita; + + for (ita = actuators.begin(); !(ita==actuators.end()); ++ita) + { + MergeScene_LogicBrick(*ita, to); + } + } + + + { + SCA_SensorList& sensors= gameobj->GetSensors(); + SCA_SensorList::iterator its; + + for (its = sensors.begin(); !(its==sensors.end()); ++its) + { + MergeScene_LogicBrick(*its, to); + } + } + + { + SCA_ControllerList& controllers= gameobj->GetControllers(); + SCA_ControllerList::iterator itc; + + for (itc = controllers.begin(); !(itc==controllers.end()); ++itc) + { + SCA_IController *cont= *itc; + MergeScene_LogicBrick(cont, to); + + vector<SCA_ISensor*> linkedsensors = cont->GetLinkedSensors(); + vector<SCA_IActuator*> linkedactuators = cont->GetLinkedActuators(); + + for (vector<SCA_IActuator*>::iterator ita = linkedactuators.begin();!(ita==linkedactuators.end());++ita) { + MergeScene_LogicBrick(*ita, to); + } + + for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());++its) { + MergeScene_LogicBrick(*its, to); + } + } + } + + /* graphics controller */ + PHY_IGraphicController *ctrl = gameobj->GetGraphicController(); + if(ctrl) { + /* SHOULD update the m_cullingTree */ + ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); + } + + /* SG_Node can hold a scene reference */ + SG_Node *sg= gameobj->GetSGNode(); + if(sg) { + if(sg->GetSGClientInfo() == from) { + sg->SetSGClientInfo(to); + } + + SGControllerList::iterator contit; + SGControllerList& controllers = sg->GetSGControllerList(); + for (contit = controllers.begin();contit!=controllers.end();++contit) + { + KX_BulletPhysicsController *phys_ctrl= dynamic_cast<KX_BulletPhysicsController *>(*contit); + if (phys_ctrl) + phys_ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); + } + } +} + +bool KX_Scene::MergeScene(KX_Scene *other) +{ + CcdPhysicsEnvironment *env= dynamic_cast<CcdPhysicsEnvironment *>(this->GetPhysicsEnvironment()); + CcdPhysicsEnvironment *env_other= dynamic_cast<CcdPhysicsEnvironment *>(other->GetPhysicsEnvironment()); + + if((env==NULL) != (env_other==NULL)) /* TODO - even when both scenes have NONE physics, the other is loaded with bullet enabled, ??? */ + { + printf("KX_Scene::MergeScene: physics scenes type differ, aborting\n"); + printf("\tsource %d, terget %d\n", (int)(env!=NULL), (int)(env_other!=NULL)); + return false; + } + + if(GetSceneConverter() != other->GetSceneConverter()) { + printf("KX_Scene::MergeScene: converters differ, aborting\n"); + return false; + } + + + GetBucketManager()->MergeBucketManager(other->GetBucketManager()); + + /* move materials across, assume they both use the same scene-converters */ + GetSceneConverter()->MergeScene(this, other); + + /* active + inactive == all ??? - lets hope so */ + for (int i = 0; i < other->GetObjectList()->GetCount(); i++) + { + KX_GameObject* gameobj = (KX_GameObject*)other->GetObjectList()->GetValue(i); + MergeScene_GameObject(gameobj, this, other); + + gameobj->UpdateBuckets(false); /* only for active objects */ + } + + for (int i = 0; i < other->GetInactiveList()->GetCount(); i++) + { + KX_GameObject* gameobj = (KX_GameObject*)other->GetInactiveList()->GetValue(i); + MergeScene_GameObject(gameobj, this, other); + } + + GetTempObjectList()->MergeList(other->GetTempObjectList()); + other->GetTempObjectList()->ReleaseAndRemoveAll(); + + GetObjectList()->MergeList(other->GetObjectList()); + other->GetObjectList()->ReleaseAndRemoveAll(); + + GetInactiveList()->MergeList(other->GetInactiveList()); + other->GetInactiveList()->ReleaseAndRemoveAll(); + + GetRootParentList()->MergeList(other->GetRootParentList()); + other->GetRootParentList()->ReleaseAndRemoveAll(); + + GetLightList()->MergeList(other->GetLightList()); + other->GetLightList()->ReleaseAndRemoveAll(); + + if(env) /* bullet scene? - dummy scenes dont need touching */ + env->MergeEnvironment(env_other); + + /* merge logic */ + { + SCA_LogicManager *logicmgr= GetLogicManager(); + SCA_LogicManager *logicmgr_other= other->GetLogicManager(); + + vector<class SCA_EventManager*>evtmgrs= logicmgr->GetEventManagers(); + //vector<class SCA_EventManager*>evtmgrs_others= logicmgr_other->GetEventManagers(); + + //SCA_EventManager *evtmgr; + SCA_EventManager *evtmgr_other; + + for(int i= 0; i < evtmgrs.size(); i++) { + evtmgr_other= logicmgr_other->FindEventManager(evtmgrs[i]->GetType()); + + if(evtmgr_other) /* unlikely but possible one scene has a joystick and not the other */ + evtmgr_other->Replace_LogicManager(logicmgr); + + /* when merging objects sensors are moved across into the new manager, dont need to do this here */ + } + } + return true; +} + //---------------------------------------------------------------------------- //Python diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index da72ba2ec98..4b01ab39d95 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -73,7 +73,6 @@ class KX_Camera; class KX_GameObject; class KX_LightObject; class RAS_BucketManager; -class RAS_BucketManager; class RAS_MaterialBucket; class RAS_IPolyMaterial; class RAS_IRasterizer; @@ -83,6 +82,9 @@ class btCollisionShape; class KX_BlenderSceneConverter; struct KX_ClientObjectInfo; +/* for ID freeing */ +#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->flag & LIB_DOIT)) + /** * The KX_Scene holds all data for an independent scene. It relates * KX_Objects to the specific objects in the modules. @@ -100,6 +102,7 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene CullingInfo(int layer) : m_layer(layer) {} }; + protected: RAS_BucketManager* m_bucketmanager; CListValue* m_tempObjectList; @@ -321,6 +324,10 @@ public: ); CListValue* + GetTempObjectList( + ); + + CListValue* GetObjectList( ); @@ -471,6 +478,7 @@ public: KX_Camera* GetpCamera(); NG_NetworkDeviceInterface* GetNetworkDeviceInterface(); NG_NetworkScene* GetNetworkScene(); + KX_BlenderSceneConverter *GetSceneConverter() { return m_sceneConverter; } /** * Replicate the logic bricks associated to this object. @@ -567,6 +575,15 @@ public: * Returns the Blender scene this was made from */ struct Scene *GetBlenderScene() { return m_blenderScene; } + + bool MergeScene(KX_Scene *other); + + + //void PrintStats(int verbose_level) { + // m_bucketmanager->PrintStats(verbose_level) + //} + + }; typedef std::vector<KX_Scene*> KX_SceneList; diff --git a/source/gameengine/Ketsji/KX_SceneActuator.h b/source/gameengine/Ketsji/KX_SceneActuator.h index e11a94798c9..4afa8926970 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.h +++ b/source/gameengine/Ketsji/KX_SceneActuator.h @@ -34,6 +34,8 @@ #define __KX_SCENEACTUATOR #include "SCA_IActuator.h" +#include "SCA_IScene.h" /* Replace_IScene only */ +#include "KX_Scene.h" /* Replace_IScene only */ class KX_SceneActuator : public SCA_IActuator { @@ -89,6 +91,11 @@ class KX_SceneActuator : public SCA_IActuator #ifndef DISABLE_PYTHON + virtual void Replace_IScene(SCA_IScene *val) + { + m_scene= static_cast<KX_Scene *>(val); + }; + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h index e6414a2e285..c3da11eb1e2 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.h +++ b/source/gameengine/Ketsji/KX_TouchEventManager.h @@ -74,6 +74,7 @@ public: virtual void RemoveSensor(SCA_ISensor* sensor); SCA_LogicManager* GetLogicManager() { return m_logicmgr;} PHY_IPhysicsEnvironment *GetPhysicsEnvironment() { return m_physEnv; } + virtual void Replace_PhysicsScene(PHY_IPhysicsEnvironment* env) { m_physEnv= env; } #ifdef WITH_CXX_GUARDEDALLOC diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h index ae5b68da845..248ce170d71 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.h +++ b/source/gameengine/Ketsji/KX_TouchSensor.h @@ -110,10 +110,12 @@ public: if (m_invert) result = !result; return result; } - virtual void EndFrame(); + class PHY_IPhysicsController* GetPhysicsController() { return m_physCtrl; } + + // todo: put some info for collision maybe #ifndef DISABLE_PYTHON diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp index 2dbbb7fa4a0..73ac789edf7 100644 --- a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp +++ b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp @@ -124,6 +124,21 @@ PHY_IGraphicController* CcdGraphicController::GetReplica(class PHY_IMotionState* return replica; } +void CcdGraphicController::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* env) +{ + CcdPhysicsEnvironment* phyEnv = static_cast<CcdPhysicsEnvironment*>(env); + /* Updates the m_phyEnv's m_cullingTree & m_cullingCache */ + if(getBroadphaseHandle()) { + /* insert into the new physics scene */ + Activate(false); + m_phyEnv= phyEnv; + Activate(true); + } + else { + m_phyEnv= phyEnv; + } +} + void CcdGraphicController::Activate(bool active) { if (active) diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.h b/source/gameengine/Physics/Bullet/CcdGraphicController.h index 99885eb99ee..07cf6d940cb 100644 --- a/source/gameengine/Physics/Bullet/CcdGraphicController.h +++ b/source/gameengine/Physics/Bullet/CcdGraphicController.h @@ -47,6 +47,8 @@ public: virtual void setBroadphaseHandle(btBroadphaseProxy* handle) { m_handle = handle; } virtual btBroadphaseProxy* getBroadphaseHandle() { return m_handle; } + virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* env); + //////////////////////////////////// // PHY_IGraphicController interface //////////////////////////////////// diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index b7d0dd2f6e7..69b63affeef 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -804,6 +804,23 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta } +void CcdPhysicsController::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env) +{ + // can safely assume CCD environment + CcdPhysicsEnvironment *physicsEnv = static_cast<CcdPhysicsEnvironment*>(env); + + if (m_cci.m_physicsEnv != physicsEnv) + { + // since the environment is changing, we must also move the controler to the + // new environement. Note that we don't handle sensor explicitely: this + // function can be called on sensor but only when they are not registered + if (m_cci.m_physicsEnv->removeCcdPhysicsController(this)) + { + physicsEnv->addCcdPhysicsController(this); + } + m_cci.m_physicsEnv = physicsEnv; + } +} void CcdPhysicsController::SetCenterOfMassTransform(btTransform& xform) { diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 69b16ca35bd..02d723472f6 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -432,6 +432,7 @@ protected: // controller replication virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl); + virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env); // kinematic methods virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index bf28802870a..22722c0927a 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -420,7 +420,7 @@ void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) -void CcdPhysicsEnvironment::removeCcdPhysicsController(CcdPhysicsController* ctrl) +bool CcdPhysicsEnvironment::removeCcdPhysicsController(CcdPhysicsController* ctrl) { //also remove constraint btRigidBody* body = ctrl->GetRigidBody(); @@ -445,13 +445,13 @@ void CcdPhysicsEnvironment::removeCcdPhysicsController(CcdPhysicsController* ctr m_dynamicsWorld->removeCollisionObject(ctrl->GetCollisionObject()); } } - m_controllers.erase(ctrl); - if (ctrl->m_registerCount != 0) printf("Warning: removing controller with non-zero m_registerCount: %d\n", ctrl->m_registerCount); //remove it from the triggers m_triggerControllers.erase(ctrl); + + return (m_controllers.erase(ctrl) != 0); } void CcdPhysicsEnvironment::updateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask) @@ -1736,10 +1736,19 @@ btDispatcher* CcdPhysicsEnvironment::getDispatcher() return m_dynamicsWorld->getDispatcher(); } +void CcdPhysicsEnvironment::MergeEnvironment(CcdPhysicsEnvironment *other) +{ + std::set<CcdPhysicsController*>::iterator it; + while (other->m_controllers.begin() != other->m_controllers.end()) + { + it= other->m_controllers.begin(); + CcdPhysicsController* ctrl= (*it); - - + other->removeCcdPhysicsController(ctrl); + this->addCcdPhysicsController(ctrl); + } +} CcdPhysicsEnvironment::~CcdPhysicsEnvironment() { diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index e087eac32c5..21f74e95ed4 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -199,7 +199,7 @@ protected: void addCcdPhysicsController(CcdPhysicsController* ctrl); - void removeCcdPhysicsController(CcdPhysicsController* ctrl); + bool removeCcdPhysicsController(CcdPhysicsController* ctrl); void updateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask); @@ -242,13 +242,13 @@ protected: class btConstraintSolver* GetConstraintSolver(); + void MergeEnvironment(CcdPhysicsEnvironment *other); + protected: - std::set<CcdPhysicsController*> m_controllers; - std::set<CcdPhysicsController*> m_triggerControllers; PHY_ResponseCallback m_triggerCallbacks[PHY_NUM_RESPONSE]; diff --git a/source/gameengine/Physics/common/PHY_IController.h b/source/gameengine/Physics/common/PHY_IController.h index a053a9679b8..e897de255c1 100644 --- a/source/gameengine/Physics/common/PHY_IController.h +++ b/source/gameengine/Physics/common/PHY_IController.h @@ -31,6 +31,8 @@ #include "PHY_DynamicTypes.h" +class PHY_IPhysicsEnvironment; + #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" #endif @@ -45,8 +47,9 @@ class PHY_IController public: virtual ~PHY_IController(); // clientinfo for raycasts for example - virtual void* getNewClientInfo()=0; - virtual void setNewClientInfo(void* clientinfo)=0; + virtual void* getNewClientInfo()=0; + virtual void setNewClientInfo(void* clientinfo)=0; + virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env)=0; #ifdef WITH_CXX_GUARDEDALLOC diff --git a/source/gameengine/Physics/common/PHY_IGraphicController.h b/source/gameengine/Physics/common/PHY_IGraphicController.h index aae971ff42a..eac3de68d4f 100644 --- a/source/gameengine/Physics/common/PHY_IGraphicController.h +++ b/source/gameengine/Physics/common/PHY_IGraphicController.h @@ -32,7 +32,6 @@ #include "PHY_IController.h" - /** PHY_IPhysicsController is the abstract simplified Interface to a physical object. It contains the IMotionState and IDeformableMesh Interfaces. @@ -51,7 +50,6 @@ class PHY_IGraphicController : public PHY_IController virtual PHY_IGraphicController* GetReplica(class PHY_IMotionState* motionstate) {return 0;} - #ifdef WITH_CXX_GUARDEDALLOC void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:PHY_IController"); } void operator delete( void *mem ) { MEM_freeN(mem); } diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h index 664e5fddd83..b34f8417e4c 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsController.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h @@ -32,6 +32,7 @@ #include "PHY_IController.h" class PHY_IMotionState; +class PHY_IPhysicsEnvironment; /** PHY_IPhysicsController is the abstract simplified Interface to a physical object. diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp index 8b3c4990a7a..f5750b39998 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp +++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp @@ -317,3 +317,44 @@ void RAS_BucketManager::ReleaseMaterials(RAS_IPolyMaterial * mat) } } +/* frees the bucket, only used when freeing scenes */ +void RAS_BucketManager::RemoveMaterial(RAS_IPolyMaterial * mat) +{ + BucketList::iterator bit, bitp; + list<RAS_MeshSlot>::iterator mit; + int i; + + + for(i=0; i<m_SolidBuckets.size(); i++) { + RAS_MaterialBucket *bucket = m_SolidBuckets[i]; + if (mat == bucket->GetPolyMaterial()) { + m_SolidBuckets.erase(m_SolidBuckets.begin()+i); + delete bucket; + i--; + } + } + + for(int i=0; i<m_AlphaBuckets.size(); i++) { + RAS_MaterialBucket *bucket = m_AlphaBuckets[i]; + if (mat == bucket->GetPolyMaterial()) { + m_AlphaBuckets.erase(m_AlphaBuckets.begin()+i); + delete bucket; + i--; + } + } +} + +//#include <stdio.h> + +void RAS_BucketManager::MergeBucketManager(RAS_BucketManager *other) +{ + /* concatinate lists */ + // printf("BEFORE %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size()); + GetSolidBuckets().insert( GetSolidBuckets().end(), other->GetSolidBuckets().begin(), other->GetSolidBuckets().end() ); + other->GetSolidBuckets().clear(); + + GetAlphaBuckets().insert( GetAlphaBuckets().end(), other->GetAlphaBuckets().begin(), other->GetAlphaBuckets().end() ); + other->GetAlphaBuckets().clear(); + //printf("AFTER %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size()); +} + diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h index dcac41ab6e9..75b5e12a05b 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.h +++ b/source/gameengine/Rasterizer/RAS_BucketManager.h @@ -60,6 +60,21 @@ public: void ReleaseDisplayLists(RAS_IPolyMaterial * material = NULL); void ReleaseMaterials(RAS_IPolyMaterial * material = NULL); + void RemoveMaterial(RAS_IPolyMaterial * mat); // freeing scenes only + + /* for merging */ + void MergeBucketManager(RAS_BucketManager *other); + BucketList & GetSolidBuckets() {return m_SolidBuckets;}; + BucketList & GetAlphaBuckets() {return m_AlphaBuckets;}; + + /*void PrintStats(int verbose_level) { + printf("\nMappings...\n"); + printf("\t m_SolidBuckets: %d\n", m_SolidBuckets.size()); + printf("\t\t m_SolidBuckets: %d\n", m_SolidBuckets.size()); + printf("\t m_AlphaBuckets: %d\n", m_AlphaBuckets.size()); + }*/ + + private: void OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector<sortedmeshslot>& slots, bool alpha); diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h index af909dfa731..a387d96c383 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h @@ -46,6 +46,7 @@ class RAS_IRasterizer; struct MTFace; struct Material; struct Scene; +class SCA_IScene; enum MaterialProps { @@ -164,6 +165,9 @@ public: virtual void GetMaterialRGBAColor(unsigned char *rgba) const; virtual bool UsesLighting(RAS_IRasterizer *rasty) const; virtual bool UsesObjectColor() const; + + virtual void Replace_IScene(SCA_IScene *val) {}; /* overridden by KX_BlenderMaterial */ + /* * PreCalculate texture gen */ diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp index 0995d5acdd5..ffc18e5612f 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.cpp +++ b/source/gameengine/Rasterizer/RAS_MeshObject.cpp @@ -104,6 +104,10 @@ RAS_MeshObject::~RAS_MeshObject() for(it=m_Polygons.begin(); it!=m_Polygons.end(); it++) delete (*it); + + m_sharedvertex_map.clear(); + m_Polygons.clear(); + m_materials.clear(); } bool RAS_MeshObject::MeshModified() diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h index 1738423c4f3..c9ca8152a7e 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.h +++ b/source/gameengine/Rasterizer/RAS_MeshObject.h @@ -80,7 +80,7 @@ public: virtual ~RAS_MeshObject(); - bool IsDeformed() { return m_bDeformed; } + bool IsDeformed() { return (m_bDeformed && m_mesh); } /* materials */ int NumMaterials(); diff --git a/source/gameengine/SceneGraph/SG_IObject.h b/source/gameengine/SceneGraph/SG_IObject.h index 23e6c1e9c99..523be0ef279 100644 --- a/source/gameengine/SceneGraph/SG_IObject.h +++ b/source/gameengine/SceneGraph/SG_IObject.h @@ -241,6 +241,22 @@ public: m_SGclientObject = clientObject; } + + /* needed for scene switching */ + inline const void* GetSGClientInfo() const + { + return m_SGclientInfo; + } + inline void* GetSGClientInfo() + { + return m_SGclientInfo; + } + void SetSGClientInfo(void* clientInfo) + { + m_SGclientInfo = clientInfo; + } + + /** * Set the current simulation time for this node. * The implementation of this function runs through |