diff options
Diffstat (limited to 'source/gameengine/Converter/KX_BlenderSceneConverter.cpp')
-rw-r--r-- | source/gameengine/Converter/KX_BlenderSceneConverter.cpp | 218 |
1 files changed, 186 insertions, 32 deletions
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index d1684db0f5a..86e8c9c6e76 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -55,11 +55,12 @@ #include "KX_ConvertPhysicsObject.h" -#ifdef USE_BULLET +#ifdef WITH_BULLET #include "CcdPhysicsEnvironment.h" #endif #include "KX_BlenderSceneConverter.h" +#include "KX_LibLoadStatus.h" #include "KX_BlenderScalarInterpolator.h" #include "BL_BlenderDataConversion.h" #include "BlenderWorldInfo.h" @@ -113,6 +114,14 @@ extern "C" { #include "../../blender/blenlib/BLI_linklist.h" } +#include <pthread.h> + +/* This is used to avoid including pthread.h in KX_BlenderSceneConverter.h */ +typedef struct ThreadInfo { + vector<pthread_t> threads; + pthread_mutex_t merge_lock; +} ThreadInfo; + KX_BlenderSceneConverter::KX_BlenderSceneConverter( struct Main* maggie, class KX_KetsjiEngine* engine @@ -122,10 +131,13 @@ KX_BlenderSceneConverter::KX_BlenderSceneConverter( m_ketsjiEngine(engine), m_alwaysUseExpandFraming(false), m_usemat(false), - m_useglslmat(false) + m_useglslmat(false), + m_use_mat_cache(true) { tag_main(maggie, 0); /* avoid re-tagging later on */ m_newfilename = ""; + m_threadinfo = new ThreadInfo(); + pthread_mutex_init(&m_threadinfo->merge_lock, NULL); } @@ -135,6 +147,16 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter() int i; // delete sumoshapes + if (m_threadinfo) { + vector<pthread_t>::iterator pit = m_threadinfo->threads.begin(); + while (pit != m_threadinfo->threads.end()) { + pthread_join((*pit), NULL); + pit++; + } + + pthread_mutex_destroy(&m_threadinfo->merge_lock); + delete m_threadinfo; + } int numAdtLists = m_map_blender_to_gameAdtList.size(); for (i=0; i<numAdtLists; i++) { @@ -151,6 +173,7 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter() vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator itp = m_polymaterials.begin(); while (itp != m_polymaterials.end()) { + m_polymat_cache.erase((*itp).second->GetBlenderMaterial()); delete (*itp).second; itp++; } @@ -158,6 +181,7 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter() // delete after RAS_IPolyMaterial vector<pair<KX_Scene*,BL_Material *> >::iterator itmat = m_materials.begin(); while (itmat != m_materials.end()) { + m_mat_cache.erase((*itmat).second->material); delete (*itmat).second; itmat++; } @@ -169,7 +193,7 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter() itm++; } -#ifdef USE_BULLET +#ifdef WITH_BULLET KX_ClearBulletSharedShapes(); #endif @@ -230,7 +254,7 @@ Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String& name) } #include "KX_PythonInit.h" -#ifdef USE_BULLET +#ifdef WITH_BULLET #include "LinearMath/btIDebugDraw.h" @@ -286,7 +310,8 @@ struct BlenderDebugDraw : public btIDebugDraw void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, class RAS_IRenderTools* rendertools, - class RAS_ICanvas* canvas) + class RAS_ICanvas* canvas, + bool libloading) { //find out which physics engine Scene *blenderscene = destinationscene->GetBlenderScene(); @@ -296,7 +321,10 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, // hook for registration function during conversion. m_currentScene = destinationscene; destinationscene->SetSceneConverter(this); - SG_SetActiveStage(SG_STAGE_CONVERTER); + + // This doesn't really seem to do anything except cause potential issues + // when doing threaded conversion, so it's disabled for now. + // SG_SetActiveStage(SG_STAGE_CONVERTER); if (blenderscene) { @@ -320,7 +348,7 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, switch (physics_engine) { -#ifdef USE_BULLET +#ifdef WITH_BULLET case UseBullet: { CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment(useDbvtCulling); @@ -355,7 +383,8 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, rendertools, canvas, this, - m_alwaysUseExpandFraming + m_alwaysUseExpandFraming, + libloading ); //These lookup are not needed during game @@ -369,7 +398,7 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, //that would result from this is fixed in RemoveScene() m_map_mesh_to_gamemesh.clear(); -#ifndef USE_BULLET +#ifndef WITH_BULLET /* quiet compiler warning */ (void)useDbvtCulling; #endif @@ -406,6 +435,7 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene) size = m_polymaterials.size(); for (i=0, polymit=m_polymaterials.begin(); i<size; ) { if ((*polymit).first == scene) { + m_polymat_cache.erase((*polymit).second->GetBlenderMaterial()); delete (*polymit).second; *polymit = m_polymaterials.back(); m_polymaterials.pop_back(); @@ -420,6 +450,7 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene) size = m_materials.size(); for (i=0, matit=m_materials.begin(); i<size; ) { if ((*matit).first == scene) { + m_mat_cache.erase((*matit).second->material); delete (*matit).second; *matit = m_materials.back(); m_materials.pop_back(); @@ -458,6 +489,11 @@ void KX_BlenderSceneConverter::SetGLSLMaterials(bool val) m_useglslmat = val; } +void KX_BlenderSceneConverter::SetCacheMaterials(bool val) +{ + m_use_mat_cache = val; +} + bool KX_BlenderSceneConverter::GetMaterials() { return m_usemat; @@ -468,8 +504,19 @@ bool KX_BlenderSceneConverter::GetGLSLMaterials() return m_useglslmat; } +bool KX_BlenderSceneConverter::GetCacheMaterials() +{ + return m_use_mat_cache; +} + void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat) { + // First make sure we don't register the material twice + vector<pair<KX_Scene*,BL_Material*> >::iterator it; + for (it = m_materials.begin(); it != m_materials.end(); ++it) + if (it->second == mat) + return; + m_materials.push_back(pair<KX_Scene*,BL_Material *>(m_currentScene,mat)); } @@ -540,19 +587,39 @@ RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh( } else { return NULL; } -} - - - - - +} void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat) { + // First make sure we don't register the material twice + vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator it; + for (it = m_polymaterials.begin(); it != m_polymaterials.end(); ++it) + if (it->second == polymat) + return; m_polymaterials.push_back(pair<KX_Scene*,RAS_IPolyMaterial*>(m_currentScene,polymat)); } +void KX_BlenderSceneConverter::CachePolyMaterial(struct Material *mat, RAS_IPolyMaterial *polymat) +{ + if (m_use_mat_cache) + m_polymat_cache[mat] = polymat; +} + +RAS_IPolyMaterial *KX_BlenderSceneConverter::FindCachedPolyMaterial(struct Material *mat) +{ + return (m_use_mat_cache) ? m_polymat_cache[mat] : NULL; +} +void KX_BlenderSceneConverter::CacheBlenderMaterial(struct Material *mat, BL_Material *blmat) +{ + if (m_use_mat_cache) + m_mat_cache[mat] = blmat; +} + +BL_Material *KX_BlenderSceneConverter::FindCachedBlenderMaterial(struct Material *mat) +{ + return (m_use_mat_cache) ? m_mat_cache[mat] : NULL; +} void KX_BlenderSceneConverter::RegisterInterpolatorList( BL_InterpolatorList *actList, @@ -915,7 +982,67 @@ Main* KX_BlenderSceneConverter::GetMainDynamicPath(const char *path) return NULL; } -bool KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) +void KX_BlenderSceneConverter::MergeAsyncLoads() +{ + vector<KX_Scene*> *merge_scenes; + + vector<KX_LibLoadStatus*>::iterator mit; + vector<KX_Scene*>::iterator sit; + + pthread_mutex_lock(&m_threadinfo->merge_lock); + + for (mit=m_mergequeue.begin(); mit!=m_mergequeue.end(); ++mit) { + merge_scenes = (vector<KX_Scene*>*)(*mit)->GetData(); + + for (sit=merge_scenes->begin(); sit!=merge_scenes->end(); ++sit) { + (*mit)->GetMergeScene()->MergeScene(*sit); + delete (*sit); + } + + + delete merge_scenes; + (*mit)->SetData(NULL); + + (*mit)->Finish(); + } + + m_mergequeue.clear(); + + pthread_mutex_unlock(&m_threadinfo->merge_lock); +} + +void KX_BlenderSceneConverter::AddScenesToMergeQueue(KX_LibLoadStatus *status) +{ + pthread_mutex_lock(&m_threadinfo->merge_lock); + m_mergequeue.push_back(status); + pthread_mutex_unlock(&m_threadinfo->merge_lock); +} + +static void *async_convert(void *ptr) +{ + KX_Scene *new_scene = NULL; + KX_LibLoadStatus *status = (KX_LibLoadStatus*)ptr; + vector<Scene*> *scenes = (vector<Scene*>*)status->GetData(); + vector<KX_Scene*> *merge_scenes = new vector<KX_Scene*>(); // Deleted in MergeAsyncLoads + + for (unsigned int i=0; i<scenes->size(); ++i) { + new_scene = status->GetEngine()->CreateScene((*scenes)[i], true); + + if (new_scene) + merge_scenes->push_back(new_scene); + + status->AddProgress((1.f/scenes->size())*0.9f); // We'll call conversion 90% and merging 10% for now + } + + delete scenes; + status->SetData(merge_scenes); + + status->GetConverter()->AddScenesToMergeQueue(status); + + return NULL; +} + +KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) { BlendHandle *bpy_openlib = BLO_blendhandle_from_memory(data, length); @@ -923,12 +1050,12 @@ bool KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const return LinkBlendFile(bpy_openlib, path, group, scene_merge, err_str, options); } -bool KX_BlenderSceneConverter::LinkBlendFilePath(const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) +KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFilePath(const char *filepath, char *group, KX_Scene *scene_merge, char **err_str, short options) { - BlendHandle *bpy_openlib = BLO_blendhandle_from_file((char *)path, NULL); + BlendHandle *bpy_openlib = BLO_blendhandle_from_file(filepath, NULL); // Error checking is done in LinkBlendFile - return LinkBlendFile(bpy_openlib, path, group, scene_merge, err_str, options); + return LinkBlendFile(bpy_openlib, filepath, group, scene_merge, err_str, options); } static void load_datablocks(Main *main_newlib, BlendHandle *bpy_openlib, const char *path, int idcode) @@ -955,7 +1082,7 @@ static void load_datablocks(Main *main_newlib, BlendHandle *bpy_openlib, const c BLO_library_append_end(NULL, main_tmp, &bpy_openlib, idcode, flag); } -bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) +KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) { Main *main_newlib; /* stored as a dynamic 'main' until we free it */ const int idcode = BKE_idcode_from_name(group); @@ -964,25 +1091,27 @@ bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const cha // TIMEIT_START(bge_link_blend_file); + KX_LibLoadStatus *status; + /* only scene and mesh supported right now */ if (idcode!=ID_SCE && idcode!=ID_ME &&idcode!=ID_AC) { snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group); *err_str= err_local; BLO_blendhandle_close(bpy_openlib); - return false; + return NULL; } if (GetMainDynamicPath(path)) { snprintf(err_local, sizeof(err_local), "blend file already open \"%s\"\n", path); *err_str= err_local; BLO_blendhandle_close(bpy_openlib); - return false; + return NULL; } if (bpy_openlib==NULL) { snprintf(err_local, sizeof(err_local), "could not open blendfile \"%s\"\n", path); *err_str= err_local; - return false; + return NULL; } main_newlib= (Main *)MEM_callocN( sizeof(Main), "BgeMain"); @@ -1009,6 +1138,8 @@ bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const cha strncpy(main_newlib->name, path, sizeof(main_newlib->name)); + status = new KX_LibLoadStatus(this, m_ketsjiEngine, scene_merge, path); + if (idcode==ID_ME) { /* Convert all new meshes into BGE meshes */ ID* mesh; @@ -1016,7 +1147,7 @@ bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const cha for (mesh= (ID *)main_newlib->mesh.first; mesh; mesh= (ID *)mesh->next ) { if (options & LIB_LOAD_VERBOSE) printf("MeshName: %s\n", mesh->name+2); - RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)mesh, NULL, scene_merge, this); + RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)mesh, NULL, scene_merge, this, false); // For now only use the libloading option for scenes, which need to handle materials/shaders scene_merge->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); } } @@ -1033,16 +1164,30 @@ bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const cha else if (idcode==ID_SCE) { /* Merge all new linked in scene into the existing one */ ID *scene; + // scenes gets deleted by the thread when it's done using it (look in async_convert()) + vector<Scene*> *scenes = (options & LIB_LOAD_ASYNC) ? new vector<Scene*>() : NULL; + for (scene= (ID *)main_newlib->scene.first; scene; scene= (ID *)scene->next ) { if (options & LIB_LOAD_VERBOSE) printf("SceneName: %s\n", scene->name+2); - /* merge into the base scene */ - KX_Scene* other= m_ketsjiEngine->CreateScene((Scene *)scene); - scene_merge->MergeScene(other); + if (options & LIB_LOAD_ASYNC) { + scenes->push_back((Scene*)scene); + } else { + /* merge into the base scene */ + KX_Scene* other= m_ketsjiEngine->CreateScene((Scene *)scene, true); + scene_merge->MergeScene(other); - // RemoveScene(other); // Don't run this, it frees the entire scene converter data, just delete the scene - delete other; + // RemoveScene(other); // Don't run this, it frees the entire scene converter data, just delete the scene + delete other; + } + } + + if (options & LIB_LOAD_ASYNC) { + pthread_t id; + status->SetData(scenes); + pthread_create(&id, NULL, &async_convert, (void*)status); + m_threadinfo->threads.push_back(id); } #ifdef WITH_PYTHON @@ -1063,9 +1208,14 @@ bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const cha } } + if (!(options & LIB_LOAD_ASYNC)) + status->Finish(); + + // TIMEIT_END(bge_link_blend_file); - return true; + m_status_map[main_newlib->name] = status; + return status; } /* Note m_map_*** are all ok and don't need to be freed @@ -1302,7 +1452,7 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie) } if (IS_TAGGED(bmat)) { - + m_polymat_cache.erase((*polymit).second->GetBlenderMaterial()); delete (*polymit).second; *polymit = m_polymaterials.back(); m_polymaterials.pop_back(); @@ -1320,6 +1470,7 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie) for (i=0, matit=m_materials.begin(); i<size; ) { BL_Material *mat= (*matit).second; if (IS_TAGGED(mat->material)) { + m_mat_cache.erase((*matit).second->material); delete (*matit).second; *matit = m_materials.back(); m_materials.pop_back(); @@ -1351,6 +1502,9 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie) removeImportMain(maggie); #endif + delete m_status_map[maggie->name]; + m_status_map.erase(maggie->name); + free_main(maggie); return true; @@ -1469,7 +1623,7 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene* kx_scene, } } - RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)me, NULL, kx_scene, this); + RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)me, NULL, kx_scene, this, false); 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; |