diff --git a/source/gameengine/Common/CM_Map.h b/source/gameengine/Common/CM_Map.h new file mode 100644 index 000000000000..cf0088ea7db5 --- /dev/null +++ b/source/gameengine/Common/CM_Map.h @@ -0,0 +1,70 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file CM_List.h + * \ingroup common + */ + +#ifndef __CM_LIST_H__ +#define __CM_LIST_H__ + +#include +#include + +template +inline const Item& CM_MapGetItemNoInsert(const std::map& map, const Key& key, const Item defaultItem = nullptr) +{ + const typename std::map::iterator it = map.find(key); + if (it != map.end()) { + return it->second; + } + return defaultItem; +} + +template +inline const Item& CM_MapGetItemNoInsert(const std::unordered_map& map, const Key& key, const Item defaultItem = nullptr) +{ + const typename std::map::iterator it = map.find(key); + if (it != map.end()) { + return it->second; + } + return defaultItem; +} + +template +inline bool CM_MapRemoveIfItemFound(Map& map, const Item& item) +{ + bool found = false; + for (typename Map::iterator it = map.begin(); it != map.end();) { + if (it->second == item) { + it = map.erase(it); + found = true; + } + else { + ++it; + } + } + + return found; +} + +#endif // __CM_LIST_H__ diff --git a/source/gameengine/Common/CMakeLists.txt b/source/gameengine/Common/CMakeLists.txt index 6d2f2ea8a684..13f165b8a85b 100644 --- a/source/gameengine/Common/CMakeLists.txt +++ b/source/gameengine/Common/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC CM_Clock.h CM_Format.h CM_List.h + CM_Map.h CM_Message.h CM_RefCount.h CM_Template.h diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 1c8cd8e40a45..2fe5398cbbef 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -64,7 +64,7 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj, const std::string& framepropname, float starttime, float endtime, - struct bAction *action, + const std::string& actionName, short playtype, short blend_mode, short blendin, @@ -85,7 +85,7 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj, m_priority(priority), m_layer(layer), m_ipo_flags(ipo_flags), - m_action(action), + m_actionName(actionName), m_propname(propname), m_framepropname(framepropname) { @@ -121,7 +121,7 @@ bool BL_ActionActuator::Update(double curtime) float end = m_endframe; // If we don't have an action, we can't do anything - if (!m_action) { + if (m_actionName.empty()) { return false; } @@ -174,7 +174,7 @@ bool BL_ActionActuator::Update(double curtime) } // If a different action is playing, we've been overruled and are no longer active - if (obj->GetCurrentAction(m_layer) != m_action && !obj->IsActionDone(m_layer)) { + if (obj->GetCurrentActionName(m_layer) != m_actionName && !obj->IsActionDone(m_layer)) { m_flag &= ~ACT_FLAG_ACTIVE; } @@ -229,8 +229,8 @@ bool BL_ActionActuator::Update(double curtime) } else if ((m_flag & ACT_FLAG_ACTIVE) && negativeEvent) { m_localtime = obj->GetActionFrame(m_layer); - bAction *curr_action = obj->GetCurrentAction(m_layer); - if (curr_action && curr_action != m_action) { + const std::string curr_action = obj->GetCurrentActionName(m_layer); + if (!curr_action.empty() && curr_action != m_actionName) { // Someone changed the action on us, so we wont mess with it // Hopefully there wont be too many problems with two actuators using // the same action... @@ -262,7 +262,7 @@ bool BL_ActionActuator::Update(double curtime) // Convert into a play action and play back to the beginning float temp = end; end = start; - start = curr_action ? obj->GetActionFrame(m_layer) : temp; + start = curr_action.empty() ? temp : obj->GetActionFrame(m_layer); Play(obj, start, end, BL_Action::ACT_MODE_PLAY); m_flag |= ACT_FLAG_PLAY_END; break; @@ -287,7 +287,7 @@ void BL_ActionActuator::DecLink() bool BL_ActionActuator::Play(KX_GameObject *obj, float start, float end, short mode) { const short blendmode = (m_blendmode == ACT_ACTION_ADD) ? BL_Action::ACT_BLEND_ADD : BL_Action::ACT_BLEND_BLEND; - return obj->PlayAction(m_action->id.name + 2, start, end, m_layer, m_priority, m_blendin, mode, m_layer_weight, m_ipo_flags, 1.0f, blendmode); + return obj->PlayAction(m_actionName, start, end, m_layer, m_priority, m_blendin, mode, m_layer_weight, m_ipo_flags, 1.0f, blendmode); } #ifdef WITH_PYTHON @@ -341,7 +341,7 @@ PyAttributeDef BL_ActionActuator::Attributes[] = { PyObject *BL_ActionActuator::pyattr_get_action(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { BL_ActionActuator *self = static_cast(self_v); - return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name + 2 : ""); + return PyUnicode_FromStdString(self->m_actionName); } int BL_ActionActuator::pyattr_set_action(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) @@ -353,18 +353,16 @@ int BL_ActionActuator::pyattr_set_action(EXP_PyObjectPlus *self_v, const EXP_PYA return PY_SET_ATTR_FAIL; } - bAction *action = nullptr; std::string val = _PyUnicode_AsString(value); - if (val != "") { - action = (bAction *)self->GetLogicManager()->GetActionByName(val); - if (!action) { + if (!val.empty()) { + if (!self->GetLogicManager()->GetActionByName(val)) { PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, action not found!"); return PY_SET_ATTR_FAIL; } } - self->SetAction(action); + self->m_actionName = val; return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index ee137fcd2991..0c6d75d33326 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -45,7 +45,7 @@ class BL_ActionActuator : public SCA_IActuator const std::string& framepropname, float starttime, float endtime, - struct bAction *action, + const std::string& actionName, short playtype, short blend_mode, short blendin, @@ -63,9 +63,6 @@ class BL_ActionActuator : public SCA_IActuator void SetLocalTime(float curtime); void ResetStartTime(float curtime); - bAction* GetAction() { return m_action; } - void SetAction(bAction* act) { m_action= act; } - virtual void DecLink(); bool Play(KX_GameObject *obj, float start, float end, short mode); @@ -114,7 +111,7 @@ class BL_ActionActuator : public SCA_IActuator short m_priority; short m_layer; short m_ipo_flags; - struct bAction *m_action; + std::string m_actionName; std::string m_propname; std::string m_framepropname; }; diff --git a/source/gameengine/Converter/BL_ActionData.cpp b/source/gameengine/Converter/BL_ActionData.cpp new file mode 100644 index 000000000000..500bb2c436a4 --- /dev/null +++ b/source/gameengine/Converter/BL_ActionData.cpp @@ -0,0 +1,38 @@ +#include "BL_ActionData.h" + +extern "C" { +# include "DNA_action_types.h" +# include "DNA_anim_types.h" +# include "BKE_fcurve.h" +} + +BL_ActionData::BL_ActionData(bAction *action) + :m_action(action) +{ + for (FCurve *fcu = (FCurve *)action->curves.first; fcu; fcu = fcu->next) { + if (fcu->rna_path) { + m_interpolators.emplace_back(fcu); + } + } +} + +std::string BL_ActionData::GetName() const +{ + return m_action->id.name + 2; +} + +bAction *BL_ActionData::GetAction() const +{ + return m_action; +} + +BL_ScalarInterpolator *BL_ActionData::GetScalarInterpolator(const std::string& rna_path, int array_index) +{ + for (BL_ScalarInterpolator &interp : m_interpolators) { + FCurve *fcu = interp.GetFCurve(); + if (array_index == fcu->array_index && rna_path == fcu->rna_path) { + return &interp; + } + } + return nullptr; +} diff --git a/source/gameengine/Converter/BL_ActionData.h b/source/gameengine/Converter/BL_ActionData.h new file mode 100644 index 000000000000..5956255645db --- /dev/null +++ b/source/gameengine/Converter/BL_ActionData.h @@ -0,0 +1,31 @@ +#ifndef __BL_ACTION_DATA_H__ +#define __BL_ACTION_DATA_H__ + +#include "BL_Resource.h" +#include "BL_ScalarInterpolator.h" + +#include + +struct bAction; + +/** Data related to a blender animation. + */ +class BL_ActionData : public BL_Resource +{ +private: + /// The blender action. + bAction *m_action; + /// The interpolators for each curve (FCurve) of the action. + std::vector m_interpolators; + +public: + BL_ActionData(bAction *action); + ~BL_ActionData() = default; + + std::string GetName() const; + bAction *GetAction() const; + + BL_ScalarInterpolator *GetScalarInterpolator(const std::string& rna_path, int array_index); +}; + +#endif // __BL_ACTION_DATA_H__ diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index a9979c555687..1c9f8a31ae9a 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -112,6 +112,7 @@ #include "BL_ConvertProperties.h" #include "BL_ConvertObjectInfo.h" #include "BL_ArmatureObject.h" +#include "BL_ActionData.h" #include "LA_SystemCommandLine.h" @@ -524,7 +525,10 @@ KX_Mesh *BL_ConvertMesh(Mesh *me, Object *blenderobj, KX_Scene *scene, BL_SceneC dm->release(dm); + // Needed for python scripting. + scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj); converter.RegisterGameMesh(meshobj, me); + return meshobj; } @@ -729,6 +733,23 @@ RAS_Deformer *BL_ConvertDeformer(KX_GameObject *object, KX_Mesh *meshobj) return deformer; } +BL_ActionData *BL_ConvertAction(bAction *action, KX_Scene *scene, BL_SceneConverter& converter) +{ + BL_ActionData *data = new BL_ActionData(action); + converter.RegisterActionData(data); + scene->GetLogicManager()->RegisterActionName(action->id.name + 2, data); + + return data; +} + +void BL_ConvertActions(KX_Scene *scene, Main *maggie, BL_SceneConverter& converter) +{ + // Convert all actions and register. + for (bAction *act = (bAction *)maggie->action.first; act; act = (bAction *)act->id.next) { + BL_ConvertAction(act, scene, converter); + } +} + static void BL_CreateGraphicObjectNew(KX_GameObject *gameobj, KX_Scene *kxscene, bool isActive, PHY_IPhysicsEnvironment *phyEnv) { #ifdef WITH_BULLET @@ -968,9 +989,6 @@ static KX_GameObject *BL_GameObjectFromBlenderObject(Object *ob, KX_Scene *kxsce Mesh *mesh = static_cast(ob->data); KX_Mesh *meshobj = BL_ConvertMesh(mesh, ob, kxscene, converter); - // needed for python scripting - kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj); - if (ob->gameflag & OB_NAVMESH) { gameobj = new KX_NavMeshObject(kxscene, KX_Scene::m_callbacks); gameobj->AddMesh(meshobj); @@ -1424,12 +1442,6 @@ void BL_ConvertBlenderObjects(struct Main *maggie, EXP_ListValue *logicbrick_conversionlist = new EXP_ListValue(); - // Convert actions to actionmap. - bAction *curAct; - for (curAct = (bAction *)maggie->action.first; curAct; curAct = (bAction *)curAct->id.next) { - logicmgr->RegisterActionName(curAct->id.name + 2, curAct); - } - BL_SetBlenderSceneBackground(blenderscene); /* Let's support scene set. diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.h b/source/gameengine/Converter/BL_BlenderDataConversion.h index 9fd29c5d19f0..1fbea3c3a1f7 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.h +++ b/source/gameengine/Converter/BL_BlenderDataConversion.h @@ -41,10 +41,12 @@ class RAS_ICanvas; class KX_KetsjiEngine; class KX_Scene; class BL_SceneConverter; +class BL_ActionData; struct Mesh; struct DerivedMesh; struct Object; struct Main; +struct bAction; struct BL_MeshMaterial { RAS_DisplayArray *array; @@ -61,6 +63,10 @@ void BL_ConvertDerivedMeshToArray(DerivedMesh *dm, Mesh *me, const std::vectoract) ? actact->act->id.name + 2 : ""; + BL_ActionActuator *tmpbaseact = new BL_ActionActuator( gameobj, propname, propframe, actact->sta, actact->end, - actact->act, + actionName, actact->type, // + 1, because Blender starts to count at zero, actact->blend_mode, actact->blendin, diff --git a/source/gameengine/Converter/BL_ConvertObjectInfo.cpp b/source/gameengine/Converter/BL_ConvertObjectInfo.cpp new file mode 100644 index 000000000000..e99ad270083a --- /dev/null +++ b/source/gameengine/Converter/BL_ConvertObjectInfo.cpp @@ -0,0 +1,6 @@ +#include "BL_ConvertObjectInfo.h" + +BL_ConvertObjectInfo::BL_ConvertObjectInfo(Object *blendobj) + :m_blenderObject(blendobj) +{ +} diff --git a/source/gameengine/Converter/BL_ConvertObjectInfo.h b/source/gameengine/Converter/BL_ConvertObjectInfo.h index 2649b29f2bd3..7900da52a1a9 100644 --- a/source/gameengine/Converter/BL_ConvertObjectInfo.h +++ b/source/gameengine/Converter/BL_ConvertObjectInfo.h @@ -1,18 +1,22 @@ #ifndef __BL_CONVERT_OBJECT_INFO__ #define __BL_CONVERT_OBJECT_INFO__ +#include "BL_Resource.h" + #include struct bRigidBodyJointConstraint; struct Object; -class BL_ConvertObjectInfo +class BL_ConvertObjectInfo : public BL_Resource { public: /// Blender object used during conversion. Object *m_blenderObject; /// Object constraints defined by the user. std::vector m_constraints; + + BL_ConvertObjectInfo(Object *blendobj); }; #endif // __BL_CONVERT_OBJECT_INFO__ diff --git a/source/gameengine/Converter/BL_Converter.cpp b/source/gameengine/Converter/BL_Converter.cpp index 259c971c6fa4..332a676cccc6 100644 --- a/source/gameengine/Converter/BL_Converter.cpp +++ b/source/gameengine/Converter/BL_Converter.cpp @@ -41,7 +41,7 @@ #include "KX_KetsjiEngine.h" #include "KX_PythonInit.h" // So we can handle adding new text datablocks for Python to import #include "KX_LibLoadStatus.h" -#include "BL_ScalarInterpolator.h" +#include "BL_ActionData.h" #include "BL_Converter.h" #include "BL_SceneConverter.h" #include "BL_BlenderDataConversion.h" @@ -77,6 +77,7 @@ extern "C" { #include "CM_Message.h" #include +#include BL_Converter::SceneSlot::SceneSlot() = default; @@ -89,9 +90,6 @@ BL_Converter::SceneSlot::~SceneSlot() = default; void BL_Converter::SceneSlot::Merge(BL_Converter::SceneSlot& other) { - m_interpolators.insert(m_interpolators.begin(), - std::make_move_iterator(other.m_interpolators.begin()), - std::make_move_iterator(other.m_interpolators.end())); m_materials.insert(m_materials.begin(), std::make_move_iterator(other.m_materials.begin()), std::make_move_iterator(other.m_materials.end())); @@ -101,7 +99,9 @@ void BL_Converter::SceneSlot::Merge(BL_Converter::SceneSlot& other) m_objectInfos.insert(m_objectInfos.begin(), std::make_move_iterator(other.m_objectInfos.begin()), std::make_move_iterator(other.m_objectInfos.end())); - m_actionToInterp.insert(other.m_actionToInterp.begin(), other.m_actionToInterp.end()); + m_actions.insert(m_actions.begin(), + std::make_move_iterator(other.m_actions.begin()), + std::make_move_iterator(other.m_actions.end())); } void BL_Converter::SceneSlot::Merge(const BL_SceneConverter& converter) @@ -115,6 +115,9 @@ void BL_Converter::SceneSlot::Merge(const BL_SceneConverter& converter) for (BL_ConvertObjectInfo *info : converter.m_objectInfos) { m_objectInfos.emplace_back(info); } + for (BL_ActionData *action : converter.m_actions) { + m_actions.emplace_back(action); + } } BL_Converter::BL_Converter(Main *maggie, KX_KetsjiEngine *engine, bool alwaysUseExpandFraming, float camZoom) @@ -125,17 +128,17 @@ BL_Converter::BL_Converter(Main *maggie, KX_KetsjiEngine *engine, bool alwaysUse { BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, false); // avoid re-tagging later on m_threadinfo.m_pool = BLI_task_pool_create(engine->GetTaskScheduler(), nullptr); + + m_maggies.push_back(m_maggie); } BL_Converter::~BL_Converter() { // free any data that was dynamically loaded - while (m_DynamicMaggie.size() != 0) { - FreeBlendFile(m_DynamicMaggie[0]); + while (!m_dynamicMaggies.empty()) { + FreeBlendFile(m_dynamicMaggies.front()); } - m_DynamicMaggie.clear(); - /* Thread infos like mutex must be freed after FreeBlendFile function. Because it needs to lock the mutex, even if there's no active task when it's in the scene converter destructor. */ @@ -144,15 +147,9 @@ BL_Converter::~BL_Converter() Scene *BL_Converter::GetBlenderSceneForName(const std::string &name) { - Scene *sce; - - // Find the specified scene by name, or nullptr if nothing matches. - if ((sce = (Scene *)BLI_findstring(&m_maggie->scene, name.c_str(), offsetof(ID, name) + 2))) { - return sce; - } - - for (Main *main : m_DynamicMaggie) { - if ((sce = (Scene *)BLI_findstring(&main->scene, name.c_str(), offsetof(ID, name) + 2))) { + for (Main *maggie : m_maggies) { + Scene *sce = (Scene *)BLI_findstring(&maggie->scene, name.c_str(), offsetof(ID, name) + 2); + if (sce) { return sce; } } @@ -176,7 +173,16 @@ EXP_ListValue *BL_Converter::GetInactiveSceneNames() return list; } -void BL_Converter::ConvertScene(BL_SceneConverter& converter, bool libloading) +void BL_Converter::ConvertScene(KX_Scene *scene) +{ + BL_SceneConverter converter(scene, BL_Resource::Library(m_maggie)); + ConvertScene(converter, false, true); + PostConvertScene(converter); + m_sceneSlots.emplace(scene, converter); + ReloadShaders(scene); +} + +void BL_Converter::ConvertScene(BL_SceneConverter& converter, bool libloading, bool actions) { KX_Scene *scene = converter.GetScene(); @@ -190,6 +196,11 @@ void BL_Converter::ConvertScene(BL_SceneConverter& converter, bool libloading) m_alwaysUseExpandFraming, m_camZoom, libloading); + + // Handle actions. + if (actions) { + BL_ConvertActions(scene, m_maggie, converter); + } } void BL_Converter::PostConvertScene(const BL_SceneConverter& converter) @@ -216,64 +227,62 @@ void BL_Converter::RemoveScene(KX_Scene *scene) m_sceneSlots.erase(scene); } -void BL_Converter::RegisterInterpolatorList(KX_Scene *scene, BL_InterpolatorList *interpolator, bAction *for_act) -{ - SceneSlot& sceneSlot = m_sceneSlots[scene]; - sceneSlot.m_interpolators.emplace_back(interpolator); - sceneSlot.m_actionToInterp[for_act] = interpolator; -} - -BL_InterpolatorList *BL_Converter::FindInterpolatorList(KX_Scene *scene, bAction *for_act) -{ - return m_sceneSlots[scene].m_actionToInterp[for_act]; -} - void BL_Converter::RegisterMesh(KX_Scene *scene, KX_Mesh *mesh) { m_sceneSlots[scene].m_meshobjects.emplace_back(mesh); } -Main *BL_Converter::CreateMainDynamic(const std::string& path) +Main *BL_Converter::CreateLibrary(const std::string& path) { Main *maggie = BKE_main_new(); strncpy(maggie->name, path.c_str(), sizeof(maggie->name) - 1); - m_DynamicMaggie.push_back(maggie); + m_dynamicMaggies.push_back(maggie); return maggie; } -const std::vector
&BL_Converter::GetMainDynamic() const +bool BL_Converter::ExistLibrary(const std::string& path) const { - return m_DynamicMaggie; + for (Main *maggie : m_dynamicMaggies) { + if (BLI_path_cmp(maggie->name, path.c_str()) == 0) { + return true; + } + } + + return false; } -Main *BL_Converter::GetMainDynamicPath(const std::string& path) const +std::vector BL_Converter::GetLibraryNames() const { - for (Main *maggie : m_DynamicMaggie) { - if (BLI_path_cmp(maggie->name, path.c_str()) == 0) { - return maggie; - } + std::vector names; + for (Main *maggie : m_dynamicMaggies) { + names.push_back(maggie->name); } - return nullptr; + return names; } -void BL_Converter::MergeAsyncLoads() +void BL_Converter::ProcessScheduledLibraries() { m_threadinfo.m_mutex.Lock(); + const std::vector mergeQueue = m_mergequeue; + m_mergequeue.clear(); + m_threadinfo.m_mutex.Unlock(); - for (KX_LibLoadStatus *libload : m_mergequeue) { + for (KX_LibLoadStatus *libload : mergeQueue) { KX_Scene *mergeScene = libload->GetMergeScene(); - for (const BL_SceneConverter& converter : libload->GetSceneConverters()) { + std::vector& converters = libload->GetSceneConverters(); + for (const BL_SceneConverter& converter : converters) { MergeScene(mergeScene, converter); } libload->Finish(); } - m_mergequeue.clear(); - - m_threadinfo.m_mutex.Unlock(); + for (Main *maggie : m_freeQueue) { + FreeBlendFileData(maggie); + } + m_freeQueue.clear(); } void BL_Converter::FinalizeAsyncLoads() @@ -281,7 +290,7 @@ void BL_Converter::FinalizeAsyncLoads() // Finish all loading libraries. BLI_task_pool_work_and_wait(m_threadinfo.m_pool); // Merge all libraries data in the current scene, to avoid memory leak of unmerged scenes. - MergeAsyncLoads(); + ProcessScheduledLibraries(); } void BL_Converter::AddScenesToMergeQueue(KX_LibLoadStatus *status) @@ -291,23 +300,29 @@ void BL_Converter::AddScenesToMergeQueue(KX_LibLoadStatus *status) m_threadinfo.m_mutex.Unlock(); } -static void async_convert(TaskPool *pool, void *ptr, int UNUSED(threadid)) +void BL_Converter::AsyncConvertTask(TaskPool *pool, void *ptr, int UNUSED(threadid)) { KX_LibLoadStatus *status = static_cast(ptr); BL_Converter *converter = status->GetConverter(); - const std::vector& scenes = status->GetScenes(); - - for (KX_Scene *scene : scenes) { - BL_SceneConverter sceneConverter(scene); - converter->ConvertScene(sceneConverter, true); + std::vector& converters = status->GetSceneConverters(); + for (BL_SceneConverter& sceneConverter : converters) { + converter->ConvertScene(sceneConverter, true, false); + status->AddProgress((1.0f / converters.size()) * 0.9f); // We'll call conversion 90% and merging 10% for now + } - status->AddSceneConverter(std::move(sceneConverter)); + status->GetConverter()->AddScenesToMergeQueue(status); +} - status->AddProgress((1.0f / scenes.size()) * 0.9f); // We'll call conversion 90% and merging 10% for now +Main *BL_Converter::GetLibraryPath(const std::string& path) +{ + for (Main *maggie : m_dynamicMaggies) { + if (BLI_path_cmp(maggie->name, path.c_str()) == 0) { + return maggie; + } } - status->GetConverter()->AddScenesToMergeQueue(status); + return nullptr; } KX_LibLoadStatus *BL_Converter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) @@ -345,22 +360,18 @@ static void load_datablocks(Main *main_tmp, BlendHandle *blendlib, const char *p KX_LibLoadStatus *BL_Converter::LinkBlendFile(BlendHandle *blendlib, 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); - ReportList reports; static char err_local[255]; - KX_LibLoadStatus *status; - // only scene and mesh supported right now - if (idcode != ID_SCE && idcode != ID_ME && idcode != ID_AC) { + if (!ELEM(idcode, ID_SCE, ID_ME, ID_AC)) { snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group); *err_str = err_local; BLO_blendhandle_close(blendlib); return nullptr; } - if (GetMainDynamicPath(path)) { + if (ExistLibrary(path)) { snprintf(err_local, sizeof(err_local), "blend file already open \"%s\"\n", path); *err_str = err_local; BLO_blendhandle_close(blendlib); @@ -373,260 +384,195 @@ KX_LibLoadStatus *BL_Converter::LinkBlendFile(BlendHandle *blendlib, const char return nullptr; } - main_newlib = BKE_main_new(); - BKE_reports_init(&reports, RPT_STORE); + Main *main_newlib = BKE_main_new(); - short flag = 0; // don't need any special options - // created only for linking, then freed - Main *main_tmp = BLO_library_link_begin(main_newlib, &blendlib, (char *)path); + ReportList reports; + BKE_reports_init(&reports, RPT_STORE); + // Created only for linking, then freed. + Main *main_tmp = BLO_library_link_begin(main_newlib, &blendlib, path); load_datablocks(main_tmp, blendlib, path, idcode); - if (idcode == ID_SCE && options & LIB_LOAD_LOAD_SCRIPTS) { - load_datablocks(main_tmp, blendlib, path, ID_TXT); - } - - // now do another round of linking for Scenes so all actions are properly loaded - if (idcode == ID_SCE && options & LIB_LOAD_LOAD_ACTIONS) { - load_datablocks(main_tmp, blendlib, path, ID_AC); + // In case of scene, optionally link texts and actions. + if (idcode == ID_SCE) { + if (options & LIB_LOAD_LOAD_SCRIPTS) { + load_datablocks(main_tmp, blendlib, path, ID_TXT); + } + if (options & LIB_LOAD_LOAD_ACTIONS) { + load_datablocks(main_tmp, blendlib, path, ID_AC); + } } + // Don't need any special options. + const short flag = 0; BLO_library_link_end(main_tmp, &blendlib, flag, nullptr, nullptr); - BLO_blendhandle_close(blendlib); BKE_reports_clear(&reports); - // done linking - // needed for lookups - m_DynamicMaggie.push_back(main_newlib); BLI_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; - - BL_SceneConverter sceneConverter(scene_merge); - for (mesh = (ID *)main_newlib->mesh.first; mesh; mesh = (ID *)mesh->next) { - if (options & LIB_LOAD_VERBOSE) { - CM_Debug("mesh name: " << mesh->name + 2); + // Debug data to load. + if (options & LIB_LOAD_VERBOSE) { + if (idcode == ID_AC || (options & LIB_LOAD_LOAD_ACTIONS && idcode == ID_SCE)) { + for (bAction *act = (bAction *)main_newlib->action.first; act; act = (bAction *)act->id.next) { + CM_Debug("action name: " << act->id.name + 2); + } + } + if (ELEM(idcode, ID_ME, ID_SCE)) { + for (Mesh *mesh = (Mesh *)main_newlib->mesh.first; mesh; mesh = (Mesh *)mesh->id.next) { + CM_Debug("mesh name: " << mesh->id.name + 2); + } + } + if (idcode == ID_SCE) { + for (Scene *bscene = (Scene *)main_newlib->scene.first; bscene; bscene = (Scene *)bscene->id.next) { + CM_Debug("scene name: " << bscene->id.name + 2); } - KX_Mesh *meshobj = BL_ConvertMesh((Mesh *)mesh, nullptr, scene_merge, sceneConverter); - scene_merge->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj); } - - MergeSceneData(scene_merge, sceneConverter); - FinalizeSceneData(sceneConverter); } - else if (idcode == ID_AC) { - // Convert all actions - ID *action; - for (action = (ID *)main_newlib->action.first; action; action = (ID *)action->next) { - if (options & LIB_LOAD_VERBOSE) { - CM_Debug("action name: " << action->name + 2); + // Linking done. + + KX_LibLoadStatus *status = new KX_LibLoadStatus(this, m_ketsjiEngine, scene_merge, path); + + const BL_Resource::Library libraryId(main_newlib); + + switch (idcode) { + case ID_ME: + { + BL_SceneConverter sceneConverter(scene_merge, libraryId); + // Convert all new meshes into BGE meshes + for (Mesh *mesh = (Mesh *)main_newlib->mesh.first; mesh; mesh = (Mesh *)mesh->id.next) { + BL_ConvertMesh((Mesh *)mesh, nullptr, scene_merge, sceneConverter); } - scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action); + + // Merge the meshes and materials in the targeted scene. + MergeSceneData(scene_merge, sceneConverter); + // Load shaders for new created materials. + ReloadShaders(scene_merge); + break; } - } - else if (idcode == ID_SCE) { - // Merge all new linked in scene into the existing one + case ID_AC: + { + BL_SceneConverter sceneConverter(scene_merge, libraryId); + // Convert all actions and register. + BL_ConvertActions(scene_merge, main_newlib, sceneConverter); + // Merge the actions in the targeted scene. + MergeSceneData(scene_merge, sceneConverter); + break; + } + case ID_SCE: + { + // Merge all new linked scenes into the existing one + if (options & LIB_LOAD_LOAD_SCRIPTS) { #ifdef WITH_PYTHON - // Handle any text datablocks - if (options & LIB_LOAD_LOAD_SCRIPTS) { - addImportMain(main_newlib); - } + // Handle any text datablocks + addImportMain(main_newlib); #endif - // Now handle all the actions - if (options & LIB_LOAD_LOAD_ACTIONS) { - ID *action; + } - for (action = (ID *)main_newlib->action.first; action; action = (ID *)action->next) { - if (options & LIB_LOAD_VERBOSE) { - CM_Debug("action name: " << action->name + 2); - } - scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action); + /** Actions aren't owned by scenes, to merge them in the targeted scene, + * a global scene converter is created and register every action, then this + * converter is merged into the targeted scene. + */ + if (options & LIB_LOAD_LOAD_ACTIONS) { + BL_SceneConverter sceneConverter(scene_merge, libraryId); + // Convert all actions and register. + BL_ConvertActions(scene_merge, main_newlib, sceneConverter); + // Merge the actions in the targeted scene. + MergeSceneData(scene_merge, sceneConverter); } - } - if (options & LIB_LOAD_ASYNC) { - std::vector scenes; for (Scene *bscene = (Scene *)main_newlib->scene.first; bscene; bscene = (Scene *)bscene->id.next) { - if (options & LIB_LOAD_VERBOSE) { - CM_Debug("scene name: " << bscene->id.name + 2); - } - KX_Scene *scene = m_ketsjiEngine->CreateScene(bscene); - // Build list of scene to convert. - scenes.push_back(scene); - } - - status->SetScenes(scenes); - BLI_task_pool_push(m_threadinfo.m_pool, async_convert, (void *)status, false, TASK_PRIORITY_LOW); - } - else { - for (Scene *scene = (Scene *)main_newlib->scene.first; scene; scene = (Scene *)scene->id.next) { - if (options & LIB_LOAD_VERBOSE) { - CM_Debug("scene name: " << scene->id.name + 2); + // Schedule conversion and merge. + if (options & LIB_LOAD_ASYNC) { + status->AddSceneConverter(scene, libraryId); + } + // Or proceed direct conversion and merge. + else { + BL_SceneConverter sceneConverter(scene, libraryId); + ConvertScene(sceneConverter, true, false); + MergeScene(scene_merge, sceneConverter); } - - // merge into the base scene - KX_Scene *other = m_ketsjiEngine->CreateScene(scene); - - BL_SceneConverter sceneConverter(other); - ConvertScene(sceneConverter, true); - MergeScene(scene_merge, sceneConverter); } + break; } } - if (!(options & LIB_LOAD_ASYNC)) { + if (options & LIB_LOAD_ASYNC) { + BLI_task_pool_push(m_threadinfo.m_pool, AsyncConvertTask, (void *)status, false, TASK_PRIORITY_LOW); + } + else { status->Finish(); } - m_status_map[main_newlib->name] = status; + // Register new library. + m_dynamicMaggies.push_back(main_newlib); + m_maggies.push_back(main_newlib); + + // Register associated KX_LibLoadStatus. + m_libloadStatus[main_newlib].reset(status); + return status; } -/** Note m_map_*** are all ok and don't need to be freed - * most are temp and NewRemoveObject frees m_map_gameobject_to_blender */ -bool BL_Converter::FreeBlendFile(Main *maggie) +bool BL_Converter::FreeBlendFileData(Main *maggie) { - if (maggie == nullptr) { - return false; - } + // Indentifier used to recognize ressources of this library. + const BL_Resource::Library libraryId(maggie); + KX_LibLoadStatus *status = m_libloadStatus[maggie].get(); // If the given library is currently in loading, we do nothing. - if (m_status_map.count(maggie->name)) { - m_threadinfo.m_mutex.Lock(); - const bool finished = m_status_map[maggie->name]->IsFinished(); - m_threadinfo.m_mutex.Unlock(); - - if (!finished) { - CM_Error("Library (" << maggie->name << ") is currently being loaded asynchronously, and cannot be freed until this process is done"); - return false; - } - } + m_threadinfo.m_mutex.Lock(); + const bool finished = status->IsFinished(); + m_threadinfo.m_mutex.Unlock(); - // tag all false except the one we remove - for (std::vector
::iterator it = m_DynamicMaggie.begin(); it != m_DynamicMaggie.end(); ) { - Main *main = *it; - if (main == maggie) { - BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, true); - it = m_DynamicMaggie.erase(it); - } - if (main != maggie) { - BKE_main_id_tag_all(main, LIB_TAG_DOIT, false); - ++it; - } + if (!finished) { + CM_Error("Library (" << maggie->name << ") is currently being loaded asynchronously, and cannot be freed until this process is done"); + return false; } - // free all tagged objects - EXP_ListValue *scenes = m_ketsjiEngine->CurrentScenes(); - int numScenes = scenes->GetCount(); + // For each scene try to remove any usage of ressources from the library. + for (KX_Scene *scene : m_ketsjiEngine->CurrentScenes()) { + // Both list containing all the scene objects. + std::array *, 2> allObjects{{scene->GetObjectList(), scene->GetInactiveList()}}; - for (unsigned int sce_idx = 0; sce_idx < numScenes; ++sce_idx) { - KX_Scene *scene = scenes->GetValue(sce_idx); - if (IS_TAGGED(scene->GetBlenderScene())) { - m_ketsjiEngine->RemoveScene(scene->GetName()); - m_sceneSlots.erase(scene); - sce_idx--; - numScenes--; - } - else { - // in case the mesh might be refered to later - std::map &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap(); - for (std::map::iterator it = mapStringToMeshes.begin(), end = mapStringToMeshes.end(); it != end; ) { - KX_Mesh *meshobj = (KX_Mesh *)it->second; - if (meshobj && IS_TAGGED(meshobj->GetMesh())) { - it = mapStringToMeshes.erase(it); + for (EXP_ListValue *objectList : allObjects) { + for (KX_GameObject *gameobj : objectList) { + BL_ConvertObjectInfo *info = gameobj->GetConvertObjectInfo(); + // Object as default camera are not linked to a blender resource. + if (!info) { + continue; } - else { - ++it; - } - } - // Now unregister actions. - std::map &mapStringToActions = scene->GetLogicManager()->GetActionMap(); - for (std::map::iterator it = mapStringToActions.begin(), end = mapStringToActions.end(); it != end; ) { - ID *action = (ID *)it->second; - if (IS_TAGGED(action)) { - it = mapStringToActions.erase(it); + // Free object directly depending on blender object of the library. + if (info->Belong(libraryId)) { + scene->DelayedRemoveObject(gameobj); } + // Else try to remove used ressource (e.g actions, meshes, materials...). else { - ++it; - } - } - - // removed tagged objects and meshes - EXP_ListValue *obj_lists[] = {scene->GetObjectList(), scene->GetInactiveList(), nullptr}; - - for (int ob_ls_idx = 0; obj_lists[ob_ls_idx]; ob_ls_idx++) { - EXP_ListValue *obs = obj_lists[ob_ls_idx]; - - for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++) { - KX_GameObject *gameobj = 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 { - CM_Error("could not remove \"" << gameobj->GetName() << "\""); - } - } - else { - gameobj->RemoveTaggedActions(); - // free the mesh, we could be referecing a linked one! - - for (KX_Mesh *meshobj : gameobj->GetMeshList()) { - if (IS_TAGGED(meshobj->GetMesh())) { - gameobj->RemoveMeshes(); /* XXX - slack, should only remove meshes that are library items but mostly objects only have 1 mesh */ - break; - } - else { - // also free the mesh if it's using a tagged material - for (RAS_MeshMaterial *meshmat : meshobj->GetMeshMaterialList()) { - if (IS_TAGGED(meshmat->GetBucket()->GetMaterial()->GetBlenderMaterial())) { - gameobj->RemoveMeshes(); // XXX - slack, same as above - break; - } - } - } - } - - // make sure action actuators are not referencing tagged actions - for (unsigned int act_idx = 0; act_idx < gameobj->GetActuators().size(); act_idx++) { - if (gameobj->GetActuators()[act_idx]->IsType(SCA_IActuator::KX_ACT_ACTION)) { - BL_ActionActuator *act = (BL_ActionActuator *)gameobj->GetActuators()[act_idx]; - if (IS_TAGGED(act->GetAction())) { - act->SetAction(nullptr); - } - } - } - } + gameobj->RemoveRessources(libraryId); } } } + + scene->RemoveEuthanasyObjects(); } - for (std::map::iterator sit = m_sceneSlots.begin(), send = m_sceneSlots.end(); sit != send; ++sit) { - KX_Scene *scene = sit->first; - SceneSlot& sceneSlot = sit->second; + // Free ressources belonging to the library and unregister them. + for (auto& pair : m_sceneSlots) { + KX_Scene *scene = pair.first; + SCA_LogicManager *logicmgr = scene->GetLogicManager(); + SceneSlot& sceneSlot = pair.second; + // Free meshes. for (UniquePtrList::iterator it = sceneSlot.m_meshobjects.begin(); it != sceneSlot.m_meshobjects.end(); ) { - KX_Mesh *mesh = (*it).get(); - if (IS_TAGGED(mesh->GetMesh())) { + KX_Mesh *mesh = it->get(); + if (mesh->Belong(libraryId)) { + logicmgr->UnregisterMesh(mesh); it = sceneSlot.m_meshobjects.erase(it); } else { @@ -634,10 +580,10 @@ bool BL_Converter::FreeBlendFile(Main *maggie) } } + // Free materials. for (UniquePtrList::iterator it = sceneSlot.m_materials.begin(); it != sceneSlot.m_materials.end(); ) { - KX_BlenderMaterial *mat = (*it).get(); - Material *bmat = mat->GetBlenderMaterial(); - if (IS_TAGGED(bmat)) { + KX_BlenderMaterial *mat = it->get(); + if (mat->Belong(libraryId)) { scene->GetBucketManager()->RemoveMaterial(mat); it = sceneSlot.m_materials.erase(it); } @@ -646,36 +592,67 @@ bool BL_Converter::FreeBlendFile(Main *maggie) } } - for (UniquePtrList::iterator it = sceneSlot.m_interpolators.begin(); it != sceneSlot.m_interpolators.end(); ) { - BL_InterpolatorList *interp = (*it).get(); - bAction *action = interp->GetAction(); - if (IS_TAGGED(action)) { - sceneSlot.m_actionToInterp.erase(action); - it = sceneSlot.m_interpolators.erase(it); + // Free actions. + for (UniquePtrList::iterator it = sceneSlot.m_actions.begin(); it != sceneSlot.m_actions.end(); ) { + BL_ActionData *act = it->get(); + if (act->Belong(libraryId)) { + logicmgr->UnregisterAction(act); + it = sceneSlot.m_actions.erase(it); + } + else { + ++it; + } + } + + // Free object infos. + for (UniquePtrList::iterator it = sceneSlot.m_objectInfos.begin(); it != sceneSlot.m_objectInfos.end(); ) { + BL_ConvertObjectInfo *info = it->get(); + if (info->Belong(libraryId)) { + it = sceneSlot.m_objectInfos.erase(it); } else { ++it; } } + + // Reload materials cause they used lamps removed now. + scene->GetBucketManager()->ReloadMaterials(); } + // Remove and destruct the KX_LibLoadStatus associated to the just free library. + m_libloadStatus.erase(maggie); + + // Actual free of the blender library. + FreeBlendFile(maggie); + + return true; +} + +void BL_Converter::FreeBlendFile(Main *maggie) +{ #ifdef WITH_PYTHON /* make sure this maggie is removed from the import list if it's there * (this operation is safe if it isn't in the list) */ removeImportMain(maggie); #endif - delete m_status_map[maggie->name]; - m_status_map.erase(maggie->name); + // Remove the library from lists. + CM_ListRemoveIfFound(m_maggies, maggie); + CM_ListRemoveIfFound(m_dynamicMaggies, maggie); BKE_main_free(maggie); - - return true; } bool BL_Converter::FreeBlendFile(const std::string& path) { - return FreeBlendFile(GetMainDynamicPath(path)); + Main *maggie = GetLibraryPath(path); + if (!maggie) { + return false; + } + + // Delay library free in ProcessScheduledLibraries. + m_freeQueue.push_back(maggie); + return true; } void BL_Converter::MergeSceneData(KX_Scene *to, const BL_SceneConverter& converter) @@ -701,40 +678,41 @@ void BL_Converter::MergeScene(KX_Scene *to, const BL_SceneConverter& converter) KX_Scene *from = converter.GetScene(); to->MergeScene(from); - FinalizeSceneData(converter); + ReloadShaders(to); delete from; } -void BL_Converter::FinalizeSceneData(const BL_SceneConverter& converter) +void BL_Converter::ReloadShaders(KX_Scene *scene) { - for (KX_BlenderMaterial *mat : converter.m_materials) { - mat->InitShader(); + for (std::unique_ptr& mat : m_sceneSlots[scene].m_materials) { + mat->ReloadMaterial(); } - KX_WorldInfo *world = converter.GetScene()->GetWorldInfo(); + KX_WorldInfo *world = scene->GetWorldInfo(); if (world) { world->ReloadMaterial(); } } +void BL_Converter::ReloadShaders(const BL_SceneConverter& converter) +{ + for (KX_BlenderMaterial *mat : converter.m_materials) { + mat->ReloadMaterial(); + } +} + /** This function merges a mesh from the current scene into another main * it does not convert */ KX_Mesh *BL_Converter::ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, const std::string& name) { - // Find a mesh in the current main */ - ID *me = static_cast(BLI_findstring(&m_maggie->mesh, name.c_str(), offsetof(ID, name) + 2)); - Main *from_maggie = m_maggie; - - if (me == nullptr) { - // The mesh wasn't in the current main, try any dynamic (i.e., LibLoaded) ones - for (Main *main : m_DynamicMaggie) { - me = static_cast(BLI_findstring(&main->mesh, name.c_str(), offsetof(ID, name) + 2)); + Main *from_maggie; + ID *me = nullptr; + for (Main *main : m_maggies) { + me = static_cast(BLI_findstring(&main->mesh, name.c_str(), offsetof(ID, name) + 2)); + if (me) { from_maggie = main; - - if (me) { - break; - } + break; } } @@ -792,13 +770,12 @@ KX_Mesh *BL_Converter::ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, cons } } - BL_SceneConverter sceneConverter(kx_scene); + BL_SceneConverter sceneConverter(kx_scene, BL_Resource::Library(maggie)); KX_Mesh *meshobj = BL_ConvertMesh((Mesh *)me, nullptr, kx_scene, sceneConverter); - kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj); MergeSceneData(kx_scene, sceneConverter); - FinalizeSceneData(sceneConverter); + ReloadShaders(sceneConverter); return meshobj; } @@ -810,7 +787,7 @@ void BL_Converter::PrintStats() unsigned int nummat = 0; unsigned int nummesh = 0; - unsigned int numinter = 0; + unsigned int numacts = 0; for (const auto& pair : m_sceneSlots) { KX_Scene *scene = pair.first; @@ -818,17 +795,17 @@ void BL_Converter::PrintStats() nummat += sceneSlot.m_materials.size(); nummesh += sceneSlot.m_meshobjects.size(); - numinter += sceneSlot.m_interpolators.size(); + numacts += sceneSlot.m_actions.size(); CM_Message("\tscene: " << scene->GetName()) CM_Message("\t\t materials: " << sceneSlot.m_materials.size()); CM_Message("\t\t meshes: " << sceneSlot.m_meshobjects.size()); - CM_Message("\t\t interpolators: " << sceneSlot.m_interpolators.size()); + CM_Message("\t\t actions: " << sceneSlot.m_actions.size()); } CM_Message(std::endl << "Total:"); CM_Message("\t scenes: " << m_sceneSlots.size()); CM_Message("\t materials: " << nummat); CM_Message("\t meshes: " << nummesh); - CM_Message("\t interpolators: " << numinter); + CM_Message("\t actions: " << numacts); } diff --git a/source/gameengine/Converter/BL_Converter.h b/source/gameengine/Converter/BL_Converter.h index 1238d1b78699..8946d66161be 100644 --- a/source/gameengine/Converter/BL_Converter.h +++ b/source/gameengine/Converter/BL_Converter.h @@ -40,8 +40,11 @@ # include "KX_Mesh.h" # include "BL_ConvertObjectInfo.h" # include "BL_ScalarInterpolator.h" +# include "BL_ActionData.h" #endif +#include "BL_SceneConverter.h" + #include "CM_Thread.h" class EXP_StringValue; @@ -50,7 +53,6 @@ class BL_ConvertObjectInfo; class KX_KetsjiEngine; class KX_LibLoadStatus; class KX_BlenderMaterial; -class BL_InterpolatorList; class SCA_IActuator; class SCA_IController; class KX_Mesh; @@ -75,11 +77,9 @@ class BL_Converter public: UniquePtrList m_materials; UniquePtrList m_meshobjects; - UniquePtrList m_interpolators; + UniquePtrList m_actions; UniquePtrList m_objectInfos; - std::map m_actionToInterp; - SceneSlot(); SceneSlot(const BL_SceneConverter& converter); ~SceneSlot(); @@ -95,17 +95,32 @@ class BL_Converter CM_ThreadMutex m_mutex; } m_threadinfo; - // Saved KX_LibLoadStatus objects - std::map m_status_map; + /// List of loaded libraries to merge. std::vector m_mergequeue; + /// List of libraries to free. + std::vector
m_freeQueue; + /// Blender current maggie at game start. Main *m_maggie; - std::vector
m_DynamicMaggie; + /// Libloaded maggies. + std::vector
m_dynamicMaggies; + /// All maggies, original and loaded. + std::vector
m_maggies; + /// Loaded library status associated to library. + std::unordered_map
> m_libloadStatus; KX_KetsjiEngine *m_ketsjiEngine; bool m_alwaysUseExpandFraming; float m_camZoom; + /// Partially convert a potential libloaded scene. + void ConvertScene(BL_SceneConverter& converter, bool libloading, bool actions); + + /** Convert all scene data that can't in a separate thread such as python components. + * \param converter The scene convert to finalize. + */ + void PostConvertScene(const BL_SceneConverter& converter); + /** Merge all data contained in the scene converter to the scene slot of * the destination scene and update the data to use the destination scene. * \param to The destination scene. @@ -121,21 +136,36 @@ class BL_Converter */ void MergeScene(KX_Scene *to, const BL_SceneConverter& converter); -public: - BL_Converter(Main *maggie, KX_KetsjiEngine *engine, bool alwaysUseExpandFraming, float camZoom); - virtual ~BL_Converter(); + /** Regenerate material shader after a converting or merging a scene + * depending on all the lights into the destination scene. + */ + void ReloadShaders(KX_Scene *scene); + /// Regenerate shaders of material in given scene converter, used when creating mesh. + void ReloadShaders(const BL_SceneConverter& converter); - void ConvertScene(BL_SceneConverter& converter, bool libloading); + /// Delay library merging to ProcessScheduledLibraries. + void AddScenesToMergeQueue(KX_LibLoadStatus *status); - /** Convert all scene data that can't in a separate thread such as python components. - * \param converter The scene convert to finalize. + /** Asynchronously convert scenes from a library. + * \param ptr Pointer to the library status. */ - void PostConvertScene(const BL_SceneConverter& converter); + static void AsyncConvertTask(TaskPool *pool, void *ptr, int UNUSED(threadid)); - /** Finalize all data depending on scene context after a potential scene merging, - * such as shader creation depending on lights into scene. - */ - void FinalizeSceneData(const BL_SceneConverter& converter); + Main *GetLibraryPath(const std::string& path); + + KX_LibLoadStatus *LinkBlendFile(BlendHandle *blendlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); + + /// Free blend file and remove data from merged scene. + bool FreeBlendFileData(Main *maggie); + /// Free blend file and remove library from internal lists. + void FreeBlendFile(Main *maggie); + +public: + BL_Converter(Main *maggie, KX_KetsjiEngine *engine, bool alwaysUseExpandFraming, float camZoom); + virtual ~BL_Converter(); + + /// Fully convert a non-libloaded scene. + void ConvertScene(KX_Scene *scene); /** This function removes all entities stored in the converter for that scene * It should be used instead of direct delete scene @@ -146,30 +176,29 @@ class BL_Converter */ void RemoveScene(KX_Scene *scene); - void RegisterInterpolatorList(KX_Scene *scene, BL_InterpolatorList *interpolator, bAction *for_act); - BL_InterpolatorList *FindInterpolatorList(KX_Scene *scene, bAction *for_act); /// Register a mesh object copy. void RegisterMesh(KX_Scene *scene, KX_Mesh *mesh); Scene *GetBlenderSceneForName(const std::string& name); EXP_ListValue *GetInactiveSceneNames(); - Main *CreateMainDynamic(const std::string& path); - Main *GetMainDynamicPath(const std::string& path) const; - const std::vector
&GetMainDynamic() const; + /// Return a new empty library of name path. + Main *CreateLibrary(const std::string& path); + bool ExistLibrary(const std::string& path) const; + std::vector GetLibraryNames() const; KX_LibLoadStatus *LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); KX_LibLoadStatus *LinkBlendFilePath(const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); - KX_LibLoadStatus *LinkBlendFile(BlendHandle *blendlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); - bool FreeBlendFile(Main *maggie); + /// Register library to free by name. bool FreeBlendFile(const std::string& path); KX_Mesh *ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, const std::string& name); - void MergeAsyncLoads(); + /// Merge scheduled loaded libraries and remove scheduled libraries. + void ProcessScheduledLibraries(); + /// Wait until all libraries are loaded. void FinalizeAsyncLoads(); - void AddScenesToMergeQueue(KX_LibLoadStatus *status); void PrintStats(); diff --git a/source/gameengine/Converter/BL_IpoConvert.cpp b/source/gameengine/Converter/BL_IpoConvert.cpp index 41e0de669f2a..80b1653b813b 100644 --- a/source/gameengine/Converter/BL_IpoConvert.cpp +++ b/source/gameengine/Converter/BL_IpoConvert.cpp @@ -40,7 +40,7 @@ #include "BL_IpoConvert.h" #include "SG_Interpolator.h" -#include "BL_ScalarInterpolator.h" +#include "BL_ActionData.h" #include "BL_Converter.h" #include "KX_Globals.h" @@ -66,20 +66,7 @@ #include "SG_Node.h" #include "SG_Interpolator.h" -static BL_InterpolatorList *GetAdtList(struct bAction *for_act, KX_Scene *scene) -{ - BL_Converter *converter = KX_GetActiveEngine()->GetConverter(); - BL_InterpolatorList *adtList = converter->FindInterpolatorList(scene, for_act); - - if (!adtList) { - adtList = new BL_InterpolatorList(for_act); - converter->RegisterInterpolatorList(scene, adtList, for_act); - } - - return adtList; -} - -SG_Controller *BL_CreateIPO(struct bAction *action, KX_GameObject *gameobj, KX_Scene *scene) +SG_Controller *BL_CreateIPO(BL_ActionData *action, KX_GameObject *gameobj, KX_Scene *scene) { KX_IpoController *ipocontr = new KX_IpoController(); @@ -110,50 +97,48 @@ SG_Controller *BL_CreateIPO(struct bAction *action, KX_GameObject *gameobj, KX_S } } - BL_InterpolatorList *adtList = GetAdtList(action, scene); - - // For each active channel in the adtList add an + // For each active channel in the action add an // interpolator to the game object. BL_ScalarInterpolator *interp; for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator("location", i))) { + if ((interp = action->GetScalarInterpolator("location", i))) { SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetPosition()[i]), interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetIPOChannelActive(OB_LOC_X + i, true); } } for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator("delta_location", i))) { + if ((interp = action->GetScalarInterpolator("delta_location", i))) { SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetDeltaPosition()[i]), interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetIPOChannelActive(OB_DLOC_X + i, true); } } for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator(rotmode, i))) { + if ((interp = action->GetScalarInterpolator(rotmode, i))) { SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetEulerAngles()[i]), interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetIPOChannelActive(OB_ROT_X + i, true); } } for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator(drotmode, i))) { + if ((interp = action->GetScalarInterpolator(drotmode, i))) { SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[i]), interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetIPOChannelActive(OB_DROT_X + i, true); } } for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator("scale", i))) { + if ((interp = action->GetScalarInterpolator("scale", i))) { SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetScaling()[i]), interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetIPOChannelActive(OB_SIZE_X + i, true); } } for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator("delta_scale", i))) { + if ((interp = action->GetScalarInterpolator("delta_scale", i))) { SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetDeltaScaling()[i]), interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetIPOChannelActive(OB_DSIZE_X + i, true); @@ -165,14 +150,13 @@ SG_Controller *BL_CreateIPO(struct bAction *action, KX_GameObject *gameobj, KX_S } -SG_Controller *BL_CreateObColorIPO(struct bAction *action, KX_GameObject *gameobj, KX_Scene *scene) +SG_Controller *BL_CreateObColorIPO(BL_ActionData *action, KX_GameObject *gameobj, KX_Scene *scene) { KX_ObColorIpoSGController *ipocontr_obcol = nullptr; BL_ScalarInterpolator *interp; - BL_InterpolatorList *adtList = GetAdtList(action, scene); for (int i = 0; i < 4; i++) { - if ((interp = adtList->GetScalarInterpolator("color", i))) { + if ((interp = action->GetScalarInterpolator("color", i))) { if (!ipocontr_obcol) { ipocontr_obcol = new KX_ObColorIpoSGController(); } @@ -184,7 +168,7 @@ SG_Controller *BL_CreateObColorIPO(struct bAction *action, KX_GameObject *gameob return ipocontr_obcol; } -SG_Controller *BL_CreateLampIPO(struct bAction *action, KX_GameObject *lightobj, KX_Scene *scene) +SG_Controller *BL_CreateLampIPO(BL_ActionData *action, KX_GameObject *lightobj, KX_Scene *scene) { KX_LightIpoSGController *ipocontr = new KX_LightIpoSGController(); @@ -196,27 +180,25 @@ SG_Controller *BL_CreateLampIPO(struct bAction *action, KX_GameObject *lightobj, ipocontr->m_col_rgb[2] = blenderlamp->b; ipocontr->m_dist = blenderlamp->dist; - BL_InterpolatorList *adtList = GetAdtList(action, scene); - - // For each active channel in the adtList add an + // For each active channel in the action add an // interpolator to the game object. BL_ScalarInterpolator *interp; - if ((interp = adtList->GetScalarInterpolator("energy", 0))) { + if ((interp = action->GetScalarInterpolator("energy", 0))) { SG_Interpolator interpolator(&ipocontr->m_energy, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyEnergy(true); } - if ((interp = adtList->GetScalarInterpolator("distance", 0))) { + if ((interp = action->GetScalarInterpolator("distance", 0))) { SG_Interpolator interpolator(&ipocontr->m_dist, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyDist(true); } for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator("color", i))) { + if ((interp = action->GetScalarInterpolator("color", i))) { SG_Interpolator interpolator(&ipocontr->m_col_rgb[i], interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyColor(true); @@ -226,7 +208,7 @@ SG_Controller *BL_CreateLampIPO(struct bAction *action, KX_GameObject *lightobj, return ipocontr; } -SG_Controller *BL_CreateCameraIPO(struct bAction *action, KX_GameObject *cameraobj, KX_Scene *scene) +SG_Controller *BL_CreateCameraIPO(BL_ActionData *action, KX_GameObject *cameraobj, KX_Scene *scene) { KX_CameraIpoSGController *ipocontr = new KX_CameraIpoSGController(); @@ -236,26 +218,24 @@ SG_Controller *BL_CreateCameraIPO(struct bAction *action, KX_GameObject *camerao ipocontr->m_clipstart = blendercamera->clipsta; ipocontr->m_clipend = blendercamera->clipend; - BL_InterpolatorList *adtList = GetAdtList(action, scene); - - // For each active channel in the adtList add an + // For each active channel in the action add an // interpolator to the game object. BL_ScalarInterpolator *interp; - if ((interp = adtList->GetScalarInterpolator("lens", 0))) { + if ((interp = action->GetScalarInterpolator("lens", 0))) { SG_Interpolator interpolator(&ipocontr->m_lens, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyLens(true); } - if ((interp = adtList->GetScalarInterpolator("clip_start", 0))) { + if ((interp = action->GetScalarInterpolator("clip_start", 0))) { SG_Interpolator interpolator(&ipocontr->m_clipstart, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyClipStart(true); } - if ((interp = adtList->GetScalarInterpolator("clip_end", 0))) { + if ((interp = action->GetScalarInterpolator("clip_end", 0))) { SG_Interpolator interpolator(&ipocontr->m_clipend, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyClipEnd(true); @@ -265,18 +245,16 @@ SG_Controller *BL_CreateCameraIPO(struct bAction *action, KX_GameObject *camerao } -SG_Controller *BL_CreateWorldIPO(bAction *action, struct World *blenderworld, KX_Scene *scene) +SG_Controller *BL_CreateWorldIPO(BL_ActionData *action, struct World *blenderworld, KX_Scene *scene) { KX_WorldIpoController *ipocontr = nullptr; if (blenderworld) { - BL_InterpolatorList *adtList = GetAdtList(action, scene); - - // For each active channel in the adtList add an interpolator to the game object. + // For each active channel in the action add an interpolator to the game object. BL_ScalarInterpolator *interp; for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator("ambient_color", i))) { + if ((interp = action->GetScalarInterpolator("ambient_color", i))) { if (!ipocontr) { ipocontr = new KX_WorldIpoController(); } @@ -287,7 +265,7 @@ SG_Controller *BL_CreateWorldIPO(bAction *action, struct World *blenderworld, KX } for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator("horizon_color", i))) { + if ((interp = action->GetScalarInterpolator("horizon_color", i))) { if (!ipocontr) { ipocontr = new KX_WorldIpoController(); } @@ -298,7 +276,7 @@ SG_Controller *BL_CreateWorldIPO(bAction *action, struct World *blenderworld, KX } for (int i = 0; i < 3; i++) { - if ((interp = adtList->GetScalarInterpolator("zenith_color", i))) { + if ((interp = action->GetScalarInterpolator("zenith_color", i))) { if (!ipocontr) { ipocontr = new KX_WorldIpoController(); } @@ -308,7 +286,7 @@ SG_Controller *BL_CreateWorldIPO(bAction *action, struct World *blenderworld, KX } } - if ((interp = adtList->GetScalarInterpolator("mist_settings.start", 0))) { + if ((interp = action->GetScalarInterpolator("mist_settings.start", 0))) { if (!ipocontr) { ipocontr = new KX_WorldIpoController(); } @@ -317,7 +295,7 @@ SG_Controller *BL_CreateWorldIPO(bAction *action, struct World *blenderworld, KX ipocontr->SetModifyMistStart(true); } - if ((interp = adtList->GetScalarInterpolator("mist_settings.depth", 0))) { + if ((interp = action->GetScalarInterpolator("mist_settings.depth", 0))) { if (!ipocontr) { ipocontr = new KX_WorldIpoController(); } @@ -326,7 +304,7 @@ SG_Controller *BL_CreateWorldIPO(bAction *action, struct World *blenderworld, KX ipocontr->SetModifyMistDist(true); } - if ((interp = adtList->GetScalarInterpolator("mist_settings.intensity", 0))) { + if ((interp = action->GetScalarInterpolator("mist_settings.intensity", 0))) { if (!ipocontr) { ipocontr = new KX_WorldIpoController(); } @@ -350,19 +328,17 @@ SG_Controller *BL_CreateWorldIPO(bAction *action, struct World *blenderworld, KX return ipocontr; } -SG_Controller *BL_CreateMaterialIpo(struct bAction *action, +SG_Controller *BL_CreateMaterialIpo(BL_ActionData *action, RAS_IMaterial *mat, KX_GameObject *gameobj, KX_Scene *scene) { KX_MaterialIpoController *ipocontr = nullptr; - BL_InterpolatorList *adtList = GetAdtList(action, scene); BL_ScalarInterpolator *sinterp; - // -- for (int i = 0; i < 3; i++) { - if ((sinterp = adtList->GetScalarInterpolator("diffuse_color", i))) { + if ((sinterp = action->GetScalarInterpolator("diffuse_color", i))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } @@ -371,7 +347,7 @@ SG_Controller *BL_CreateMaterialIpo(struct bAction *action, } } - if ((sinterp = adtList->GetScalarInterpolator("alpha", 0))) { + if ((sinterp = action->GetScalarInterpolator("alpha", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } @@ -380,7 +356,7 @@ SG_Controller *BL_CreateMaterialIpo(struct bAction *action, } for (int i = 0; i < 3; i++) { - if ((sinterp = adtList->GetScalarInterpolator("specular_color", i))) { + if ((sinterp = action->GetScalarInterpolator("specular_color", i))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } @@ -389,7 +365,7 @@ SG_Controller *BL_CreateMaterialIpo(struct bAction *action, } } - if ((sinterp = adtList->GetScalarInterpolator("specular_hardness", 0))) { + if ((sinterp = action->GetScalarInterpolator("specular_hardness", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } @@ -397,7 +373,7 @@ SG_Controller *BL_CreateMaterialIpo(struct bAction *action, ipocontr->AddInterpolator(interpolator); } - if ((sinterp = adtList->GetScalarInterpolator("specular_intensity", 0))) { + if ((sinterp = action->GetScalarInterpolator("specular_intensity", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } @@ -405,7 +381,7 @@ SG_Controller *BL_CreateMaterialIpo(struct bAction *action, ipocontr->AddInterpolator(interpolator); } - if ((sinterp = adtList->GetScalarInterpolator("diffuse_intensity", 0))) { + if ((sinterp = action->GetScalarInterpolator("diffuse_intensity", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } @@ -413,7 +389,7 @@ SG_Controller *BL_CreateMaterialIpo(struct bAction *action, ipocontr->AddInterpolator(interpolator); } - if ((sinterp = adtList->GetScalarInterpolator("emit", 0))) { + if ((sinterp = action->GetScalarInterpolator("emit", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } @@ -421,7 +397,7 @@ SG_Controller *BL_CreateMaterialIpo(struct bAction *action, ipocontr->AddInterpolator(interpolator); } - if ((sinterp = adtList->GetScalarInterpolator("ambient", 0))) { + if ((sinterp = action->GetScalarInterpolator("ambient", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } @@ -429,7 +405,7 @@ SG_Controller *BL_CreateMaterialIpo(struct bAction *action, ipocontr->AddInterpolator(interpolator); } - if ((sinterp = adtList->GetScalarInterpolator("specular_alpha", 0))) { + if ((sinterp = action->GetScalarInterpolator("specular_alpha", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(mat); } diff --git a/source/gameengine/Converter/BL_IpoConvert.h b/source/gameengine/Converter/BL_IpoConvert.h index dc2bf40f7c7c..a1b98addb668 100644 --- a/source/gameengine/Converter/BL_IpoConvert.h +++ b/source/gameengine/Converter/BL_IpoConvert.h @@ -32,35 +32,34 @@ #ifndef __KX_IPOCONVERT_H__ #define __KX_IPOCONVERT_H__ -struct Object; -struct bAction; class SG_Controller; +class BL_ActionData; class KX_GameObject; class KX_Scene; class RAS_IMaterial; -SG_Controller *BL_CreateIPO(bAction *action, +SG_Controller *BL_CreateIPO(BL_ActionData *action, KX_GameObject* gameobj, KX_Scene *scene); -SG_Controller *BL_CreateObColorIPO(bAction *action, +SG_Controller *BL_CreateObColorIPO(BL_ActionData *action, KX_GameObject* gameobj, KX_Scene *scene); -SG_Controller *BL_CreateLampIPO(bAction *action, +SG_Controller *BL_CreateLampIPO(BL_ActionData *action, KX_GameObject* lightobj, KX_Scene *scene); -SG_Controller *BL_CreateWorldIPO(bAction *action, +SG_Controller *BL_CreateWorldIPO(BL_ActionData *action, struct World *blenderworld, KX_Scene *scene); -SG_Controller *BL_CreateCameraIPO(bAction *action, +SG_Controller *BL_CreateCameraIPO(BL_ActionData *action, KX_GameObject* cameraobj, KX_Scene *scene); SG_Controller *BL_CreateMaterialIpo( - bAction *action, + BL_ActionData *action, RAS_IMaterial *mat, KX_GameObject* gameobj, KX_Scene *scene); diff --git a/source/gameengine/Converter/BL_Resource.cpp b/source/gameengine/Converter/BL_Resource.cpp new file mode 100644 index 000000000000..c72d9a8d37c2 --- /dev/null +++ b/source/gameengine/Converter/BL_Resource.cpp @@ -0,0 +1,31 @@ +#include "BL_Resource.h" + +#include "BLI_utildefines.h" + +BL_Resource::Library::Library() + :m_id(0) +{ +} + +BL_Resource::Library::Library(Main *maggie) + :m_id((uintptr_t)maggie) +{ +} + +bool BL_Resource::Library::Valid() const +{ + return (m_id != 0); +} + +void BL_Resource::SetOwner(const Library& libraryId) +{ + // Forbid changing of library, replacing a valid library. + BLI_assert(!m_libraryId.Valid()); + + m_libraryId = libraryId; +} + +bool BL_Resource::Belong(const Library& libraryId) const +{ + return (m_libraryId == libraryId); +} diff --git a/source/gameengine/Converter/BL_Resource.h b/source/gameengine/Converter/BL_Resource.h new file mode 100644 index 000000000000..f3381d60c490 --- /dev/null +++ b/source/gameengine/Converter/BL_Resource.h @@ -0,0 +1,47 @@ +#ifndef __BL_RESOURCE_H__ +#define __BL_RESOURCE_H__ + +#include + +class BL_SceneConverter; +struct Main; + +/** Base class of resources. Used to identify the library of the resource. + */ +class BL_Resource +{ +public: + /// Opaque library identifier. + class Library + { + private: + uintptr_t m_id; + + public: + Library(); + explicit Library(Main *maggie); + + /// Return true if the identifier was constructed along an existing library. + bool Valid() const; + + inline bool operator==(const Library& other) const + { + return (m_id == other.m_id); + } + }; + +private: + /// The identifier of library owning the resource. + Library m_libraryId; + +public: + /// Initialize the library of this resource, must be called only once. + void SetOwner(const Library& libraryId); + + /** Return true if the libraryId match m_libraryId. + * Meaning the resource was converted with date from this library. + */ + bool Belong(const Library& libraryId) const; +}; + +#endif // __BL_RESOURCE_H__ diff --git a/source/gameengine/Converter/BL_ScalarInterpolator.cpp b/source/gameengine/Converter/BL_ScalarInterpolator.cpp index 061051588e4a..0598a06f263c 100644 --- a/source/gameengine/Converter/BL_ScalarInterpolator.cpp +++ b/source/gameengine/Converter/BL_ScalarInterpolator.cpp @@ -32,7 +32,6 @@ #include "BL_ScalarInterpolator.h" extern "C" { -# include "DNA_action_types.h" # include "DNA_anim_types.h" # include "BKE_fcurve.h" } @@ -51,38 +50,3 @@ FCurve *BL_ScalarInterpolator::GetFCurve() const { return m_fcu; } - -BL_InterpolatorList::BL_InterpolatorList(bAction *action) - :m_action(action) -{ - if (!action) { - return; - } - - for (FCurve *fcu = (FCurve *)action->curves.first; fcu; fcu = fcu->next) { - if (fcu->rna_path) { - m_interpolators.emplace_back(fcu); - } - } -} - -BL_InterpolatorList::~BL_InterpolatorList() -{ -} - -bAction *BL_InterpolatorList::GetAction() const -{ - return m_action; -} - -BL_ScalarInterpolator *BL_InterpolatorList::GetScalarInterpolator(const std::string& rna_path, int array_index) -{ - for (BL_ScalarInterpolator &interp : m_interpolators) { - FCurve *fcu = interp.GetFCurve(); - if (array_index == fcu->array_index && rna_path == fcu->rna_path) { - return &interp; - } - } - return nullptr; -} - diff --git a/source/gameengine/Converter/BL_ScalarInterpolator.h b/source/gameengine/Converter/BL_ScalarInterpolator.h index 5ab346cd93ba..27ad12d4aad6 100644 --- a/source/gameengine/Converter/BL_ScalarInterpolator.h +++ b/source/gameengine/Converter/BL_ScalarInterpolator.h @@ -53,19 +53,4 @@ class BL_ScalarInterpolator : public SG_ScalarInterpolator FCurve *GetFCurve() const; }; -class BL_InterpolatorList -{ -private: - bAction *m_action; - std::vector m_interpolators; - -public: - BL_InterpolatorList(bAction *action); - ~BL_InterpolatorList(); - - bAction *GetAction() const; - - BL_ScalarInterpolator *GetScalarInterpolator(const std::string& rna_path, int array_index); -}; - #endif /* __KX_BLENDERSCALARINTERPOLATOR_H__ */ diff --git a/source/gameengine/Converter/BL_SceneConverter.cpp b/source/gameengine/Converter/BL_SceneConverter.cpp index 50cedc17a4e0..a9770eb90966 100644 --- a/source/gameengine/Converter/BL_SceneConverter.cpp +++ b/source/gameengine/Converter/BL_SceneConverter.cpp @@ -31,20 +31,26 @@ #include "BL_SceneConverter.h" #include "BL_ConvertObjectInfo.h" +#include "BL_ActionData.h" #include "KX_GameObject.h" +#include "KX_Mesh.h" +#include "KX_BlenderMaterial.h" #include "CM_List.h" -BL_SceneConverter::BL_SceneConverter(KX_Scene *scene) - :m_scene(scene) +BL_SceneConverter::BL_SceneConverter(KX_Scene *scene, const BL_Resource::Library& libraryId) + :m_scene(scene), + m_libraryId(libraryId) { } BL_SceneConverter::BL_SceneConverter(BL_SceneConverter&& other) :m_scene(other.m_scene), + m_libraryId(other.m_libraryId), m_materials(std::move(other.m_materials)), m_meshobjects(std::move(other.m_meshobjects)), m_objectInfos(std::move(other.m_objectInfos)), + m_actions(std::move(other.m_actions)), m_objects(std::move(other.m_objects)), m_blenderToObjectInfos(std::move(other.m_blenderToObjectInfos)), m_map_blender_to_gameobject(std::move(other.m_map_blender_to_gameobject)), @@ -91,6 +97,8 @@ KX_GameObject *BL_SceneConverter::FindGameObject(Object *for_blenderobject) void BL_SceneConverter::RegisterGameMesh(KX_Mesh *gamemesh, Mesh *for_blendermesh) { + gamemesh->SetOwner(m_libraryId); + if (for_blendermesh) { // dynamically loaded meshes we don't want to keep lookups for m_map_mesh_to_gamemesh[for_blendermesh] = gamemesh; } @@ -104,6 +112,8 @@ KX_Mesh *BL_SceneConverter::FindGameMesh(Mesh *for_blendermesh) void BL_SceneConverter::RegisterMaterial(KX_BlenderMaterial *blmat, Material *mat) { + blmat->SetOwner(m_libraryId); + if (mat) { m_map_mesh_to_polyaterial[mat] = blmat; } @@ -115,6 +125,12 @@ KX_BlenderMaterial *BL_SceneConverter::FindMaterial(Material *mat) return m_map_mesh_to_polyaterial[mat]; } +void BL_SceneConverter::RegisterActionData(BL_ActionData *data) +{ + data->SetOwner(m_libraryId); + m_actions.push_back(data); +} + void BL_SceneConverter::RegisterGameActuator(SCA_IActuator *act, bActuator *for_actuator) { m_map_blender_to_gameactuator[for_actuator] = act; @@ -139,7 +155,9 @@ BL_ConvertObjectInfo *BL_SceneConverter::GetObjectInfo(Object *blenderobj) { const auto& it = m_blenderToObjectInfos.find(blenderobj); if (it == m_blenderToObjectInfos.end()) { - BL_ConvertObjectInfo *info = m_blenderToObjectInfos[blenderobj] = new BL_ConvertObjectInfo{blenderobj, {}}; + BL_ConvertObjectInfo *info = m_blenderToObjectInfos[blenderobj] = new BL_ConvertObjectInfo(blenderobj); + info->SetOwner(m_libraryId); + m_objectInfos.push_back(info); return info; } diff --git a/source/gameengine/Converter/BL_SceneConverter.h b/source/gameengine/Converter/BL_SceneConverter.h index b19c07a0a74b..2adad7d47a36 100644 --- a/source/gameengine/Converter/BL_SceneConverter.h +++ b/source/gameengine/Converter/BL_SceneConverter.h @@ -32,7 +32,7 @@ #ifndef __KX_BLENDERSCENECONVERTER_H__ #define __KX_BLENDERSCENECONVERTER_H__ -#include "CM_Message.h" +#include "BL_Resource.h" #include #include @@ -43,6 +43,7 @@ class KX_Mesh; class KX_BlenderMaterial; class BL_Converter; class BL_ConvertObjectInfo; +class BL_ActionData; class KX_GameObject; class KX_Scene; class KX_LibLoadStatus; @@ -52,6 +53,7 @@ struct Object; struct Scene; struct Mesh; struct Material; +struct bAction; struct bActuator; struct bController; @@ -61,11 +63,16 @@ class BL_SceneConverter private: KX_Scene *m_scene; + const BL_Resource::Library m_libraryId; + + /// Ressources from the scene. std::vector m_materials; std::vector m_meshobjects; std::vector m_objectInfos; - // List of all object converted, active and inactive. + std::vector m_actions; + + /// List of all object converted, active and inactive, not considered as a ressource. std::vector m_objects; std::map m_blenderToObjectInfos; @@ -76,12 +83,11 @@ class BL_SceneConverter std::map m_map_blender_to_gamecontroller; public: - BL_SceneConverter(KX_Scene *scene); + BL_SceneConverter(KX_Scene *scene, const BL_Resource::Library& libraryId); ~BL_SceneConverter() = default; // Disable dangerous copy. BL_SceneConverter(const BL_SceneConverter& other) = delete; - BL_SceneConverter(BL_SceneConverter&& other); KX_Scene *GetScene() const; @@ -96,6 +102,8 @@ class BL_SceneConverter void RegisterMaterial(KX_BlenderMaterial *blmat, Material *mat); KX_BlenderMaterial *FindMaterial(Material *mat); + void RegisterActionData(BL_ActionData *data); + void RegisterGameActuator(SCA_IActuator *act, bActuator *for_actuator); SCA_IActuator *FindGameActuator(bActuator *for_actuator); diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index 454c2ff378f9..c4ad9fdbcea7 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -66,35 +66,40 @@ set(INC_SYS set(SRC BL_ActionActuator.cpp + BL_ActionData.cpp BL_ArmatureActuator.cpp BL_ArmatureChannel.cpp BL_ArmatureConstraint.cpp BL_ArmatureObject.cpp BL_BlenderDataConversion.cpp + BL_Converter.cpp BL_MeshDeformer.cpp BL_ModifierDeformer.cpp + BL_Resource.cpp BL_ShapeDeformer.cpp BL_SkinDeformer.cpp - BL_Converter.cpp BL_ScalarInterpolator.cpp BL_SceneConverter.cpp BL_ConvertActuators.cpp BL_ConvertControllers.cpp + BL_ConvertObjectInfo.cpp BL_ConvertProperties.cpp BL_ConvertSensors.cpp BL_IpoConvert.cpp BL_ActionActuator.h + BL_ActionData.h BL_ArmatureActuator.h BL_ArmatureChannel.h BL_ArmatureConstraint.h BL_ArmatureObject.h BL_BlenderDataConversion.h + BL_Converter.h BL_MeshDeformer.h BL_ModifierDeformer.h + BL_Resource.h BL_ShapeDeformer.h BL_SkinDeformer.h - BL_Converter.h BL_ScalarInterpolator.h BL_SceneConverter.h BL_ConvertActuators.h diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index 30d8eb8a6deb..aa61e654a98b 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -37,8 +37,8 @@ #include "SCA_IActuator.h" #include "SCA_EventManager.h" #include "SCA_PythonController.h" -#include +#include "CM_Map.h" SCA_LogicManager::SCA_LogicManager() { @@ -220,32 +220,38 @@ void SCA_LogicManager::UpdateFrame(double curtime) void *SCA_LogicManager::GetActionByName(const std::string& actname) { - std::string an = actname; - return m_mapStringToActions[an]; -} - + const auto it = m_mapStringToActions.find(actname); + if (it != m_mapStringToActions.end()) { + return it->second; + } + return nullptr; +} void *SCA_LogicManager::GetMeshByName(const std::string& meshname) { - std::string mn = meshname; - return m_mapStringToMeshes[mn]; -} - + const auto it = m_mapStringToMeshes.find(meshname); + if (it != m_mapStringToMeshes.end()) { + return it->second; + } + return nullptr; +} void SCA_LogicManager::RegisterMeshName(const std::string& meshname, void *mesh) { - std::string mn = meshname; - m_mapStringToMeshes[mn] = mesh; + m_mapStringToMeshes[meshname] = mesh; } void SCA_LogicManager::UnregisterMeshName(const std::string& meshname, void *mesh) { - std::string mn = meshname; - m_mapStringToMeshes.erase(mn); + m_mapStringToMeshes.erase(meshname); } +void SCA_LogicManager::UnregisterMesh(void *mesh) +{ + CM_MapRemoveIfItemFound(m_mapStringToMeshes, mesh); +} void SCA_LogicManager::RegisterActionName(const std::string& actname, void *action) { @@ -253,7 +259,10 @@ void SCA_LogicManager::RegisterActionName(const std::string& actname, void *acti m_mapStringToActions[an] = action; } - +void SCA_LogicManager::UnregisterAction(void *action) +{ + CM_MapRemoveIfItemFound(m_mapStringToActions, action); +} void SCA_LogicManager::EndFrame() { diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h index e9220df085bf..c4969a28208b 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.h +++ b/source/gameengine/GameLogic/SCA_LogicManager.h @@ -119,10 +119,10 @@ class SCA_LogicManager // for the scripting... needs a FactoryManager later (if we would have time... ;) void RegisterMeshName(const std::string& meshname,void* mesh); void UnregisterMeshName(const std::string& meshname,void* mesh); - std::map& GetMeshMap() { return m_mapStringToMeshes; } - std::map& GetActionMap() { return m_mapStringToActions; } - + void UnregisterMesh(void *mesh); + void RegisterActionName(const std::string& actname,void* action); + void UnregisterAction(void *action); void* GetActionByName (const std::string& actname); void* GetMeshByName(const std::string& meshname); diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp index 2ea646235f8e..bf1b3d559513 100644 --- a/source/gameengine/Ketsji/BL_Action.cpp +++ b/source/gameengine/Ketsji/BL_Action.cpp @@ -30,6 +30,7 @@ #include "BL_ArmatureObject.h" #include "BL_ShapeDeformer.h" #include "BL_IpoConvert.h" +#include "BL_ActionData.h" #include "KX_GameObject.h" #include "KX_Globals.h" #include "KX_Mesh.h" @@ -60,7 +61,7 @@ extern "C" { #include "BKE_global.h" BL_Action::BL_Action(KX_GameObject *gameobj) - :m_action(nullptr), + :m_actionData(nullptr), m_tmpaction(nullptr), m_blendpose(nullptr), m_blendinpose(nullptr), @@ -137,13 +138,13 @@ bool BL_Action::Play(const std::string& name, return false; } m_priority = priority; - bAction *prev_action = m_action; + BL_ActionData *prev_action = m_actionData; KX_Scene *kxscene = m_obj->GetScene(); // First try to load the action - m_action = (bAction *)kxscene->GetLogicManager()->GetActionByName(name); - if (!m_action) { + m_actionData = static_cast(kxscene->GetLogicManager()->GetActionByName(name)); + if (!m_actionData) { CM_Error("failed to load action: " << name); m_done = true; return false; @@ -155,7 +156,7 @@ bool BL_Action::Play(const std::string& name, // However, this may eventually lead to issues where a user wants to override an already // playing action with the same action and settings. If this becomes an issue, // then this fix may have to be re-evaluated. - if (!IsDone() && m_action == prev_action && m_startframe == start && m_endframe == end + if (!IsDone() && m_actionData == prev_action && m_startframe == start && m_endframe == end && m_priority == priority && m_speed == playback_speed) { return false; } @@ -165,32 +166,33 @@ bool BL_Action::Play(const std::string& name, BKE_libblock_free(G.main, m_tmpaction); m_tmpaction = nullptr; } - m_tmpaction = BKE_action_copy(G.main, m_action); + + m_tmpaction = BKE_action_copy(G.main, m_actionData->GetAction()); // First get rid of any old controllers ClearControllerList(); // Create an SG_Controller - AddController(BL_CreateIPO(m_action, m_obj, kxscene)); + AddController(BL_CreateIPO(m_actionData, m_obj, kxscene)); // World - AddController(BL_CreateWorldIPO(m_action, kxscene->GetBlenderScene()->world, kxscene)); + AddController(BL_CreateWorldIPO(m_actionData, kxscene->GetBlenderScene()->world, kxscene)); // Try obcolor - AddController(BL_CreateObColorIPO(m_action, m_obj, kxscene)); + AddController(BL_CreateObColorIPO(m_actionData, m_obj, kxscene)); // Now try materials for (KX_Mesh *mesh : m_obj->GetMeshList()) { for (RAS_MeshMaterial *meshmat : mesh->GetMeshMaterialList()) { RAS_IMaterial *mat = meshmat->GetBucket()->GetMaterial(); - AddController(BL_CreateMaterialIpo(m_action, mat, m_obj, kxscene)); + AddController(BL_CreateMaterialIpo(m_actionData, mat, m_obj, kxscene)); } } // Extra controllers if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT) { - AddController(BL_CreateLampIPO(m_action, m_obj, kxscene)); + AddController(BL_CreateLampIPO(m_actionData, m_obj, kxscene)); } else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) { - AddController(BL_CreateCameraIPO(m_action, m_obj, kxscene)); + AddController(BL_CreateCameraIPO(m_actionData, m_obj, kxscene)); } m_ipo_flags = ipo_flags; @@ -253,9 +255,9 @@ void BL_Action::InitIPO() } } -bAction *BL_Action::GetAction() +BL_ActionData *BL_Action::GetActionData() { - return (IsDone()) ? nullptr : m_action; + return (IsDone()) ? nullptr : m_actionData; } float BL_Action::GetFrame() @@ -265,12 +267,7 @@ float BL_Action::GetFrame() const std::string BL_Action::GetName() { - if (m_action != nullptr) { - return m_action->id.name + 2; - } - else { - return ""; - } + return (m_actionData) ? m_actionData->GetName() : ""; } void BL_Action::SetFrame(float frame) diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h index d82a6be0ac09..f4b421fc3387 100644 --- a/source/gameengine/Ketsji/BL_Action.h +++ b/source/gameengine/Ketsji/BL_Action.h @@ -32,14 +32,14 @@ class KX_GameObject; class SG_Controller; - +class BL_ActionData; struct bAction; struct bPose; class BL_Action { private: - bAction* m_action; + BL_ActionData *m_actionData; bAction* m_tmpaction; bPose* m_blendpose; bPose* m_blendinpose; @@ -126,7 +126,7 @@ class BL_Action float GetFrame(); const std::string GetName(); - struct bAction *GetAction(); + BL_ActionData *GetActionData(); // Mutators void SetFrame(float frame); diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp index b4400229b25a..e3272a876d04 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.cpp +++ b/source/gameengine/Ketsji/BL_ActionManager.cpp @@ -25,10 +25,8 @@ */ #include "BL_Action.h" +#include "BL_ActionData.h" #include "BL_ActionManager.h" -#include "DNA_ID.h" - -#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT)) BL_ActionManager::BL_ActionManager(class KX_GameObject *obj) : m_obj(obj), @@ -47,11 +45,11 @@ BL_ActionManager::~BL_ActionManager() m_layers.clear(); } -BL_Action *BL_ActionManager::GetAction(short layer) +BL_Action *BL_ActionManager::GetAction(short layer) const { - BL_ActionMap::iterator it = m_layers.find(layer); + BL_ActionMap::const_iterator it = m_layers.find(layer); - return (it != m_layers.end()) ? it->second : 0; + return (it != m_layers.end()) ? it->second : nullptr; } float BL_ActionManager::GetActionFrame(short layer) @@ -76,11 +74,11 @@ void BL_ActionManager::SetActionFrame(short layer, float frame) } } -struct bAction *BL_ActionManager::GetCurrentAction(short layer) +std::string BL_ActionManager::GetCurrentActionName(short layer) const { BL_Action *action = GetAction(layer); - return action ? action->GetAction() : 0; + return action ? action->GetName() : ""; } void BL_ActionManager::SetPlayMode(short layer, short mode) @@ -129,10 +127,10 @@ void BL_ActionManager::StopAction(short layer) } } -void BL_ActionManager::RemoveTaggedActions() +void BL_ActionManager::RemoveActions(const BL_Resource::Library& libraryId) { for (BL_ActionMap::iterator it = m_layers.begin(); it != m_layers.end(); ) { - if (IS_TAGGED(it->second->GetAction())) { + if (it->second->GetActionData()->Belong(libraryId)) { delete it->second; it = m_layers.erase(it); } diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h index f841b8f1518d..34d6657ecbc2 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.h +++ b/source/gameengine/Ketsji/BL_ActionManager.h @@ -53,7 +53,7 @@ class BL_ActionManager /** * Check if an action exists */ - BL_Action* GetAction(short layer); + BL_Action* GetAction(short layer) const; public: BL_ActionManager(class KX_GameObject* obj); @@ -88,7 +88,7 @@ class BL_ActionManager /** * Gets the currently running action on the given layer */ - struct bAction *GetCurrentAction(short layer); + std::string GetCurrentActionName(short layer) const; /** * Sets play mode of the action on the given layer @@ -100,10 +100,7 @@ class BL_ActionManager */ void StopAction(short layer); - /** - * Remove playing tagged actions. - */ - void RemoveTaggedActions(); + void RemoveActions(const BL_Resource::Library& libraryId); /** * Check if an action has finished playing diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 8bd5ce482a15..0378718955d4 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -117,8 +117,6 @@ KX_BlenderMaterial::KX_BlenderMaterial(Material *mat, const std::string& name, K m_blendFunc[0] = RAS_Rasterizer::RAS_ZERO; m_blendFunc[1] = RAS_Rasterizer::RAS_ZERO; - - InitTextures(); } KX_BlenderMaterial::~KX_BlenderMaterial() @@ -193,9 +191,23 @@ SCA_IScene *KX_BlenderMaterial::GetScene() const void KX_BlenderMaterial::ReloadMaterial() { + BLI_assert(m_scene); + if (m_blenderShader) { + // If shader exists reload it. m_blenderShader->ReloadMaterial(); } + else { + // Init textures. + InitTextures(); + // Create shader. + m_blenderShader = new BL_BlenderShader(m_scene, m_material, this); + + if (!m_blenderShader->Ok()) { + delete m_blenderShader; + m_blenderShader = nullptr; + } + } } void KX_BlenderMaterial::ReplaceScene(KX_Scene *scene) @@ -216,19 +228,6 @@ void KX_BlenderMaterial::InitTextures() } } -void KX_BlenderMaterial::InitShader() -{ - BLI_assert(!m_blenderShader); - BLI_assert(m_scene); - - m_blenderShader = new BL_BlenderShader(m_scene, m_material, this); - - if (!m_blenderShader->Ok()) { - delete m_blenderShader; - m_blenderShader = nullptr; - } -} - void KX_BlenderMaterial::EndFrame(RAS_Rasterizer *rasty) { rasty->SetAlphaBlend(GPU_BLEND_SOLID); diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 5d210a7c13e6..e93bd26da975 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -8,6 +8,7 @@ #include "RAS_IMaterial.h" #include "BL_Texture.h" +#include "BL_Resource.h" #include "EXP_Value.h" @@ -21,7 +22,7 @@ struct Material; void KX_BlenderMaterial_Mathutils_Callback_Init(void); #endif -class KX_BlenderMaterial : public EXP_Value, public RAS_IMaterial +class KX_BlenderMaterial : public EXP_Value, public BL_Resource, public RAS_IMaterial { Py_Header @@ -53,7 +54,6 @@ class KX_BlenderMaterial : public EXP_Value, public RAS_IMaterial virtual void ReloadMaterial(); void ReplaceScene(KX_Scene *scene); - void InitShader(); static void EndFrame(RAS_Rasterizer *rasty); diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index ea03758ce120..be0acfe44943 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -48,6 +48,7 @@ #include "KX_NavMeshObject.h" #include "KX_Mesh.h" #include "KX_PolyProxy.h" +#include "KX_BlenderMaterial.h" #include "SG_Controller.h" #include "PHY_IGraphicController.h" #include "SG_Node.h" @@ -487,11 +488,6 @@ void KX_GameObject::StopAction(short layer) GetActionManager()->StopAction(layer); } -void KX_GameObject::RemoveTaggedActions() -{ - GetActionManager()->RemoveTaggedActions(); -} - bool KX_GameObject::IsActionDone(short layer) { return GetActionManager()->IsActionDone(layer); @@ -522,9 +518,9 @@ void KX_GameObject::SetActionFrame(short layer, float frame) GetActionManager()->SetActionFrame(layer, frame); } -bAction *KX_GameObject::GetCurrentAction(short layer) +std::string KX_GameObject::GetCurrentActionName(short layer) { - return GetActionManager()->GetCurrentAction(layer); + return GetActionManager()->GetCurrentActionName(layer); } void KX_GameObject::SetPlayMode(short layer, short mode) @@ -593,6 +589,31 @@ EXP_Value *KX_GameObject::GetReplica() return replica; } +void KX_GameObject::RemoveRessources(const BL_Resource::Library& libraryId) +{ + // If the object is using actions, try remove actions from this library. + if (m_actionManager) { + m_actionManager->RemoveActions(libraryId); + } + + for (KX_Mesh *mesh : m_meshes) { + // If the mesh comes from this lirbary, remove all meshes. + if (mesh->Belong(libraryId)) { + RemoveMeshes(); + break; + } + else { + // If one of the material used by the mesh comes from this library, remove all meshes too. + for (RAS_MeshMaterial *meshmat : mesh->GetMeshMaterialList()) { + if (static_cast(meshmat->GetBucket()->GetMaterial())->Belong(libraryId)) { + RemoveMeshes(); + break; + } + } + } + } +} + bool KX_GameObject::IsDynamic() const { if (m_physicsController) { diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 8cc6877a1889..c0382268ed6a 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -51,6 +51,7 @@ #include "DNA_constraint_types.h" /* for constraint replication */ #include "DNA_object_types.h" #include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */ +#include "BL_Resource.h" // For BL_Resource::Library. class KX_RayCast; class KX_LodManager; @@ -291,7 +292,7 @@ class KX_GameObject : public SCA_IObject, public mt::SimdClassAllocator /** * Gets the currently running action on the given layer */ - bAction *GetCurrentAction(short layer); + std::string GetCurrentActionName(short layer); /** * Sets play mode of the action on the given layer @@ -303,11 +304,6 @@ class KX_GameObject : public SCA_IObject, public mt::SimdClassAllocator */ void StopAction(short layer); - /** - * Remove playing tagged actions. - */ - void RemoveTaggedActions(); - /** * Check if an action has finished playing */ @@ -368,6 +364,12 @@ class KX_GameObject : public SCA_IObject, public mt::SimdClassAllocator * object belongs with the caller. */ virtual EXP_Value *GetReplica(); + + /** Remove object resource coming from the given library. + * These resource could be actions and meshes. + * \param libraryId The identifier of the library used to recognize the resource. + */ + void RemoveRessources(const BL_Resource::Library& libraryId); /** * Return the linear velocity of the game object. diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 93765a584488..d191eb9e2347 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -417,8 +417,6 @@ bool KX_KetsjiEngine::NextFrame() for (unsigned short i = 0; i < times.frames; ++i) { m_frameTime += times.framestep; - m_converter->MergeAsyncLoads(); - if (m_inputDevice) { m_inputDevice->ReleaseMoveEvent(); } @@ -490,6 +488,8 @@ bool KX_KetsjiEngine::NextFrame() m_inputDevice->ClearInputs(); } + m_converter->ProcessScheduledLibraries(); + UpdateSuspendedScenes(times.framestep); // scene management ProcessScheduledScenes(); @@ -1336,14 +1336,6 @@ KX_Scene *KX_KetsjiEngine::CreateScene(const std::string& scenename) return CreateScene(scene); } -void KX_KetsjiEngine::ConvertScene(KX_Scene *scene) -{ - BL_SceneConverter sceneConverter(scene); - m_converter->ConvertScene(sceneConverter, false); - m_converter->PostConvertScene(sceneConverter); - m_converter->FinalizeSceneData(sceneConverter); -} - void KX_KetsjiEngine::AddScheduledScenes() { if (!m_addingOverlayScenes.empty()) { @@ -1351,7 +1343,7 @@ void KX_KetsjiEngine::AddScheduledScenes() KX_Scene *tmpscene = CreateScene(scenename); if (tmpscene) { - ConvertScene(tmpscene); + m_converter->ConvertScene(tmpscene); m_scenes->Add(CM_AddRef(tmpscene)); PostProcessScene(tmpscene); tmpscene->Release(); @@ -1368,7 +1360,7 @@ void KX_KetsjiEngine::AddScheduledScenes() KX_Scene *tmpscene = CreateScene(scenename); if (tmpscene) { - ConvertScene(tmpscene); + m_converter->ConvertScene(tmpscene); m_scenes->Insert(0, CM_AddRef(tmpscene)); PostProcessScene(tmpscene); tmpscene->Release(); @@ -1422,7 +1414,7 @@ void KX_KetsjiEngine::ReplaceScheduledScenes() DestructScene(scene); KX_Scene *tmpscene = CreateScene(blScene); - ConvertScene(tmpscene); + m_converter->ConvertScene(tmpscene); m_scenes->SetValue(sce_idx, CM_AddRef(tmpscene)); PostProcessScene(tmpscene); diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 3e3282b57b09..eb6aea7a8400 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -508,9 +508,6 @@ class KX_KetsjiEngine : public mt::SimdClassAllocator KX_Scene *CreateScene(const std::string& scenename); KX_Scene *CreateScene(Scene *scene); - /// Fully convert a non-libloaded scene. - void ConvertScene(KX_Scene *scene); - GlobalSettings *GetGlobalSettings(void); void SetGlobalSettings(GlobalSettings *gs); diff --git a/source/gameengine/Ketsji/KX_LibLoadStatus.cpp b/source/gameengine/Ketsji/KX_LibLoadStatus.cpp index 52fab5c806f9..73b097aeff35 100644 --- a/source/gameengine/Ketsji/KX_LibLoadStatus.cpp +++ b/source/gameengine/Ketsji/KX_LibLoadStatus.cpp @@ -88,24 +88,14 @@ KX_Scene *KX_LibLoadStatus::GetMergeScene() const return m_mergescene; } -const std::vector& KX_LibLoadStatus::GetScenes() const -{ - return m_scenes; -} - -void KX_LibLoadStatus::SetScenes(const std::vector& scenes) -{ - m_scenes = scenes; -} - -const std::vector& KX_LibLoadStatus::GetSceneConverters() const +std::vector& KX_LibLoadStatus::GetSceneConverters() { return m_sceneConvertes; } -void KX_LibLoadStatus::AddSceneConverter(BL_SceneConverter&& converter) +void KX_LibLoadStatus::AddSceneConverter(KX_Scene *scene, const BL_Resource::Library& libraryId) { - m_sceneConvertes.push_back(std::move(converter)); + m_sceneConvertes.emplace_back(scene, libraryId); } bool KX_LibLoadStatus::IsFinished() const diff --git a/source/gameengine/Ketsji/KX_LibLoadStatus.h b/source/gameengine/Ketsji/KX_LibLoadStatus.h index 2a670fd418b6..ac2528ee30e9 100644 --- a/source/gameengine/Ketsji/KX_LibLoadStatus.h +++ b/source/gameengine/Ketsji/KX_LibLoadStatus.h @@ -41,7 +41,6 @@ class KX_LibLoadStatus : public EXP_PyObjectPlus BL_Converter *m_converter; KX_KetsjiEngine *m_engine; KX_Scene *m_mergescene; - std::vector m_scenes; std::vector m_sceneConvertes; std::string m_libname; @@ -69,10 +68,8 @@ class KX_LibLoadStatus : public EXP_PyObjectPlus KX_KetsjiEngine *GetEngine() const; KX_Scene *GetMergeScene() const; - const std::vector& GetScenes() const; - void SetScenes(const std::vector& scenes); - const std::vector& GetSceneConverters() const; - void AddSceneConverter(BL_SceneConverter&& converter); + std::vector& GetSceneConverters(); + void AddSceneConverter(KX_Scene *scene, const BL_Resource::Library& libraryId); bool IsFinished() const; diff --git a/source/gameengine/Ketsji/KX_Mesh.h b/source/gameengine/Ketsji/KX_Mesh.h index 3a1eb08b19ba..43f9d8c83ea5 100644 --- a/source/gameengine/Ketsji/KX_Mesh.h +++ b/source/gameengine/Ketsji/KX_Mesh.h @@ -34,6 +34,8 @@ #include "RAS_Mesh.h" +#include "BL_Resource.h" + #include "EXP_Value.h" class KX_Mesh; @@ -46,7 +48,7 @@ bool ConvertPythonToMesh(SCA_LogicManager *logicmgr, PyObject *value, KX_Mesh ** #endif // WITH_PYTHON -class KX_Mesh : public EXP_Value, public RAS_Mesh +class KX_Mesh : public EXP_Value, public BL_Resource, public RAS_Mesh { Py_Header diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index edfa123daf7b..9149a1f9706d 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -716,7 +716,7 @@ static PyObject *gLibNew(PyObject *, PyObject *args) BL_Converter *converter = KX_GetActiveEngine()->GetConverter(); - if (converter->GetMainDynamicPath(path)) { + if (converter->ExistLibrary(path)) { PyErr_SetString(PyExc_KeyError, "the name of the path given exists"); return nullptr; } @@ -727,7 +727,7 @@ static PyObject *gLibNew(PyObject *, PyObject *args) return nullptr; } - Main *maggie = converter->CreateMainDynamic(path); + Main *maggie = converter->CreateLibrary(path); /* Copy the object into main */ if (idcode == ID_ME) { @@ -773,11 +773,11 @@ static PyObject *gLibFree(PyObject *, PyObject *args) static PyObject *gLibList(PyObject *, PyObject *args) { - const std::vector
&dynMaggie = KX_GetActiveEngine()->GetConverter()->GetMainDynamic(); - PyObject *list = PyList_New(dynMaggie.size()); + const std::vector names = KX_GetActiveEngine()->GetConverter()->GetLibraryNames(); + PyObject *list = PyList_New(names.size()); - for (unsigned short i = 0, size = dynMaggie.size(); i < size; ++i) { - PyList_SET_ITEM(list, i, PyUnicode_FromString(dynMaggie[i]->name)); + for (unsigned short i = 0, size = names.size(); i < size; ++i) { + PyList_SET_ITEM(list, i, PyUnicode_FromStdString(names[i])); } return list; diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index aaf7bff37a4b..17fc7c735476 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -923,7 +923,7 @@ void KX_Scene::RemoveObject(KX_GameObject *gameobj) void KX_Scene::RemoveDupliGroup(KX_GameObject *gameobj) { - if (gameobj->IsDupliGroup()) { + if (gameobj->GetInstanceObjects()) { for (KX_GameObject *instance : gameobj->GetInstanceObjects()) { DelayedRemoveObject(instance); } @@ -937,6 +937,19 @@ void KX_Scene::DelayedRemoveObject(KX_GameObject *gameobj) CM_ListAddIfNotFound(m_euthanasyobjects, gameobj); } +void KX_Scene::RemoveEuthanasyObjects() +{ + /* Don't remove the objects from the euthanasy list here as the child objects of a deleted + * parent object are destructed directly from the sgnode in the same time the parent + * object is destructed. These child objects must be removed automatically from the + * euthanasy list to avoid double deletion in case the user ask to delete the child object + * explicitly. NewRemoveObject is the place to do it. + */ + while (!m_euthanasyobjects.empty()) { + RemoveObject(m_euthanasyobjects.front()); + } +} + bool KX_Scene::NewRemoveObject(KX_GameObject *gameobj) { // Remove property from debug list. @@ -1360,15 +1373,7 @@ void KX_Scene::LogicEndFrame() { m_logicmgr->EndFrame(); - /* Don't remove the objects from the euthanasy list here as the child objects of a deleted - * parent object are destructed directly from the sgnode in the same time the parent - * object is destructed. These child objects must be removed automatically from the - * euthanasy list to avoid double deletion in case the user ask to delete the child object - * explicitly. NewRemoveObject is the place to do it. - */ - while (!m_euthanasyobjects.empty()) { - RemoveObject(m_euthanasyobjects.front()); - } + RemoveEuthanasyObjects(); //prepare obstacle simulation for new frame if (m_obstacleSimulation) { diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 358b19c242b9..a8269500eab1 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -259,6 +259,11 @@ class KX_Scene : public EXP_Value, public SCA_IScene bool m_isActivedHysteresis; int m_lodHysteresisValue; + void RemoveNodeDestructObject(KX_GameObject *gameobj); + void RemoveObject(KX_GameObject *gameobj); + void RemoveDupliGroup(KX_GameObject *gameobj); + bool NewRemoveObject(KX_GameObject *gameobj); + public: KX_Scene(SCA_IInputDevice *inputDevice, const std::string& scenename, @@ -287,11 +292,10 @@ class KX_Scene : public EXP_Value, public SCA_IScene KX_GameObject *AddReplicaObject(KX_GameObject *gameobj, KX_GameObject *locationobj, float lifespan = 0.0f); KX_GameObject *AddNodeReplicaObject(SG_Node *node, KX_GameObject *gameobj); - void RemoveNodeDestructObject(KX_GameObject *gameobj); - void RemoveObject(KX_GameObject *gameobj); - void RemoveDupliGroup(KX_GameObject *gameobj); + /// Add an object to remove. void DelayedRemoveObject(KX_GameObject *gameobj); - bool NewRemoveObject(KX_GameObject *gameobj); + /// Effectivly remove object added with DelayedRemoveObject + void RemoveEuthanasyObjects(); void AddAnimatedObject(KX_GameObject *gameobj); diff --git a/source/gameengine/Launcher/LA_Launcher.cpp b/source/gameengine/Launcher/LA_Launcher.cpp index f5ee9f560ca9..7f1b2e4629a1 100644 --- a/source/gameengine/Launcher/LA_Launcher.cpp +++ b/source/gameengine/Launcher/LA_Launcher.cpp @@ -296,7 +296,7 @@ void LA_Launcher::InitEngine() #endif // WITH_AUDASPACE // Convert scene data. - m_ketsjiEngine->ConvertScene(m_kxStartScene); + m_converter->ConvertScene(m_kxStartScene); m_ketsjiEngine->AddScene(m_kxStartScene); m_kxStartScene->Release(); diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt index df3727d636a1..ec563a37cbac 100644 --- a/source/gameengine/Rasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/CMakeLists.txt @@ -28,6 +28,7 @@ set(INC Node RAS_OpenGLRasterizer ../Common + ../Converter ../Expressions ../Ketsji ../Physics/Common diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp index 4d4ef1aab0f0..e467595f4526 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp +++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp @@ -378,22 +378,23 @@ void RAS_BucketManager::ReloadMaterials(RAS_IMaterial *mat) } } -/* frees the bucket, only used when freeing scenes */ void RAS_BucketManager::RemoveMaterial(RAS_IMaterial *mat) { - for (unsigned short i = 0; i < NUM_BUCKET_TYPE; ++i) { - BucketList& buckets = m_buckets[i]; - for (BucketList::iterator it = buckets.begin(); it != buckets.end(); ) { - RAS_MaterialBucket *bucket = *it; - if (mat == bucket->GetMaterial()) { - it = buckets.erase(it); - if (i == ALL_BUCKET) { - delete bucket; - } - } - else { - ++it; + BucketList& allBuckets = m_buckets[ALL_BUCKET]; + for (BucketList::iterator it = allBuckets.begin(); it != allBuckets.end();) { + RAS_MaterialBucket *bucket = *it; + // Find the bucket in ALL_BUCKET list. + if (mat == bucket->GetMaterial()) { + // Iterate over all bucket list excepted ALL_BUCKET and remove the bucket. + for (unsigned short i = 0; i < ALL_BUCKET; ++i) { + CM_ListRemoveIfFound(m_buckets[i], bucket); } + // Remove the bucket from ALL_BUCKET and destruct it. + it = allBuckets.erase(it); + delete bucket; + } + else { + ++it; } } } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt index 8274dbea158b..017cfb07eca7 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt @@ -29,6 +29,7 @@ set(INC # XXX Remove these <<< ../../BlenderRoutines ../../Common + ../../Converter ../../Expressions ../../GameLogic ../../Ketsji diff --git a/source/gameengine/Rasterizer/RAS_Texture.cpp b/source/gameengine/Rasterizer/RAS_Texture.cpp index e16ba2e0e50b..bd43f6211b1d 100644 --- a/source/gameengine/Rasterizer/RAS_Texture.cpp +++ b/source/gameengine/Rasterizer/RAS_Texture.cpp @@ -23,6 +23,7 @@ */ #include "RAS_Texture.h" +#include "RAS_TextureRenderer.h" #include "GPU_glew.h" @@ -35,6 +36,10 @@ RAS_Texture::RAS_Texture() RAS_Texture::~RAS_Texture() { + // If the texture is free before the renderer (e.g lib free) then unregsiter ourself. + if (m_renderer) { + m_renderer->RemoveTextureUser(this); + } } std::string& RAS_Texture::GetName() diff --git a/source/gameengine/Rasterizer/RAS_TextureRenderer.cpp b/source/gameengine/Rasterizer/RAS_TextureRenderer.cpp index c770242c5587..eed887177b5c 100644 --- a/source/gameengine/Rasterizer/RAS_TextureRenderer.cpp +++ b/source/gameengine/Rasterizer/RAS_TextureRenderer.cpp @@ -32,6 +32,8 @@ #include "GPU_framebuffer.h" #include "GPU_draw.h" +#include "CM_List.h" + #include "BKE_image.h" #include "BLI_utildefines.h" @@ -177,6 +179,12 @@ void RAS_TextureRenderer::AddTextureUser(RAS_Texture *texture) texture->SetRenderer(this); } +void RAS_TextureRenderer::RemoveTextureUser(RAS_Texture *texture) +{ + CM_ListRemoveIfFound(m_textureUsers, texture); + texture->SetRenderer(nullptr); +} + void RAS_TextureRenderer::BeginRender(RAS_Rasterizer *rasty) { GetValidTexture(); diff --git a/source/gameengine/Rasterizer/RAS_TextureRenderer.h b/source/gameengine/Rasterizer/RAS_TextureRenderer.h index 5b4c121106ca..ee221efea270 100644 --- a/source/gameengine/Rasterizer/RAS_TextureRenderer.h +++ b/source/gameengine/Rasterizer/RAS_TextureRenderer.h @@ -87,6 +87,7 @@ class RAS_TextureRenderer /// Return true if the material texture use the same data than one of the texture user. bool EqualTextureUser(RAS_Texture *texture) const; void AddTextureUser(RAS_Texture *texture); + void RemoveTextureUser(RAS_Texture *texture); virtual void BeginRender(RAS_Rasterizer *rasty); virtual void EndRender(RAS_Rasterizer *rasty); diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt index 3676c7472b66..0587af786a62 100644 --- a/source/gameengine/VideoTexture/CMakeLists.txt +++ b/source/gameengine/VideoTexture/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC . ../BlenderRoutines ../Common + ../Converter ../Device ../Expressions ../GameLogic