Cleanup: remove moar G.main usages.
[blender.git] / source / gameengine / Converter / KX_BlenderSceneConverter.cpp
index 98af99825e1fc96f002400f5829cf825a7f48bd5..34e363b8fc292eba252f71cafd3633c8d0949db6 100644 (file)
 
 #include "KX_Scene.h"
 #include "KX_GameObject.h"
-#include "KX_BlenderSceneConverter.h"
 #include "KX_IpoConvert.h"
 #include "RAS_MeshObject.h"
 #include "KX_PhysicsEngineEnums.h"
 #include "PHY_IPhysicsEnvironment.h"
 #include "KX_KetsjiEngine.h"
 #include "KX_PythonInit.h" // So we can handle adding new text datablocks for Python to import
-#include "KX_IPhysicsController.h"
 #include "BL_Material.h"
 #include "BL_ActionActuator.h"
 #include "KX_BlenderMaterial.h"
-#include "KX_PolygonMaterial.h"
 
 
 #include "BL_System.h"
 
 #include "DummyPhysicsEnvironment.h"
 
-#include "KX_ConvertPhysicsObject.h"
 
 #ifdef WITH_BULLET
 #include "CcdPhysicsEnvironment.h"
 #endif
 
-#include "KX_BlenderSceneConverter.h"
 #include "KX_LibLoadStatus.h"
 #include "KX_BlenderScalarInterpolator.h"
 #include "BL_BlenderDataConversion.h"
-#include "BlenderWorldInfo.h"
-#include "KX_Scene.h"
+#include "KX_WorldInfo.h"
 
 /* This little block needed for linking to Blender... */
 #ifdef WIN32
@@ -75,6 +69,7 @@
 #include "DNA_scene_types.h"
 #include "DNA_world_types.h"
 #include "BKE_main.h"
+#include "BKE_fcurve.h"
 
 #include "BLI_math.h"
 
@@ -93,6 +88,7 @@ extern "C"
 #include "BKE_mesh.h" // BKE_mesh_copy
 #include "DNA_space_types.h"
 #include "DNA_anim_types.h"
+#include "DNA_action_types.h"
 #include "RNA_define.h"
 #include "../../blender/editors/include/ED_keyframing.h"
 }
@@ -100,9 +96,7 @@ extern "C"
 /* Only for dynamic loading and merging */
 #include "RAS_BucketManager.h" // XXX cant stay
 #include "KX_BlenderSceneConverter.h"
-#include "BL_BlenderDataConversion.h"
 #include "KX_MeshProxy.h"
-#include "RAS_MeshObject.h"
 extern "C" {
        #include "PIL_time.h"
        #include "BKE_context.h"
@@ -114,214 +108,130 @@ extern "C" {
        #include "../../blender/blenlib/BLI_linklist.h"
 }
 
-#include <pthread.h>
+#include "BLI_task.h"
 
-/* This is used to avoid including pthread.h in KX_BlenderSceneConverter.h */
+// This is used to avoid including BLI_task.h in KX_BlenderSceneConverter.h
 typedef struct ThreadInfo {
-       vector<pthread_t>       threads;
-       pthread_mutex_t         merge_lock;
+       TaskPool *m_pool;
+       ThreadMutex m_mutex;
 } ThreadInfo;
 
 KX_BlenderSceneConverter::KX_BlenderSceneConverter(
-                                                       struct Main* maggie,
-                                                       class KX_KetsjiEngine* engine
-                                                       )
-                                                       : m_maggie(maggie),
-                                                       /*m_maggie_dyn(NULL),*/
+                                                       Main *maggie,
+                                                       KX_KetsjiEngine *engine)
+                                                       :m_maggie(maggie),
                                                        m_ketsjiEngine(engine),
                                                        m_alwaysUseExpandFraming(false),
                                                        m_usemat(false),
                                                        m_useglslmat(false),
                                                        m_use_mat_cache(true)
 {
-       tag_main(maggie, 0); /* avoid re-tagging later on */
+       BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, false);  /* avoid re-tagging later on */
        m_newfilename = "";
        m_threadinfo = new ThreadInfo();
-       pthread_mutex_init(&m_threadinfo->merge_lock, NULL);
+       m_threadinfo->m_pool = BLI_task_pool_create(engine->GetTaskScheduler(), NULL);
+       BLI_mutex_init(&m_threadinfo->m_mutex);
 }
 
-
 KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
 {
        // clears meshes, and hashmaps from blender to gameengine data
-       int i;
        // delete sumoshapes
-       
-       if (m_threadinfo) {
-               vector<pthread_t>::iterator pit = m_threadinfo->threads.begin();
-               while (pit != m_threadinfo->threads.end()) {
-                       pthread_join((*pit), NULL);
-                       pit++;
-               }
-
-               pthread_mutex_destroy(&m_threadinfo->merge_lock);
-               delete m_threadinfo;
-       }
 
        int numAdtLists = m_map_blender_to_gameAdtList.size();
-       for (i=0; i<numAdtLists; i++) {
-               BL_InterpolatorList *adtList= *m_map_blender_to_gameAdtList.at(i);
+       for (int i = 0; i < numAdtLists; i++) {
+               BL_InterpolatorList *adtList = *m_map_blender_to_gameAdtList.at(i);
 
                delete (adtList);
        }
 
-       vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator itw = m_worldinfos.begin();
+       vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator itw = m_worldinfos.begin();
        while (itw != m_worldinfos.end()) {
-               delete (*itw).second;
+               delete itw->second;
                itw++;
        }
        m_worldinfos.clear();
 
-       vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator itp = m_polymaterials.begin();
+       vector<pair<KX_Scene *,RAS_IPolyMaterial *> >::iterator itp = m_polymaterials.begin();
        while (itp != m_polymaterials.end()) {
-               //m_polymat_cache.erase((*itp).second->GetBlenderMaterial());
-               delete (*itp).second;
+               delete itp->second;
                itp++;
        }
        m_polymaterials.clear();
 
        // delete after RAS_IPolyMaterial
-       vector<pair<KX_Scene*,BL_Material *> >::iterator itmat = m_materials.begin();
+       vector<pair<KX_Scene *,BL_Material *> >::iterator itmat = m_materials.begin();
        while (itmat != m_materials.end()) {
-               //m_mat_cache.erase((*itmat).second->material);
-               delete (*itmat).second;
+               delete itmat->second;
                itmat++;
        }
        m_materials.clear();
 
-
-       vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator itm = m_meshobjects.begin();
+       vector<pair<KX_Scene *,RAS_MeshObject *> >::iterator itm = m_meshobjects.begin();
        while (itm != m_meshobjects.end()) {
-               delete (*itm).second;
+               delete itm->second;
                itm++;
        }
        m_meshobjects.clear();
 
-#ifdef WITH_BULLET
-       KX_ClearBulletSharedShapes();
-#endif
-
        /* free any data that was dynamically loaded */
-       while (m_DynamicMaggie.size() != 0)
-       {
+       while (m_DynamicMaggie.size() != 0) {
                FreeBlendFile(m_DynamicMaggie[0]);
        }
 
        m_DynamicMaggie.clear();
+
+       if (m_threadinfo) {
+               /* 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. */
+               BLI_task_pool_free(m_threadinfo->m_pool);
+               BLI_mutex_end(&m_threadinfo->m_mutex);
+               delete m_threadinfo;
+       }
 }
 
-void KX_BlenderSceneConverter::SetNewFileName(const STR_Stringfilename)
+void KX_BlenderSceneConverter::SetNewFileName(const STR_String &filename)
 {
        m_newfilename = filename;
 }
 
-
-
 bool KX_BlenderSceneConverter::TryAndLoadNewFile()
 {
        bool result = false;
 
-       // find the file
-/*     if ()
-       {
-               result = true;
-       }
-       // if not, clear the newfilename
-       else
-       {
-               m_newfilename = "";
-       }
-*/
        return result;
 }
 
-Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_Stringname)
+Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String &name)
 {
        Scene *sce;
 
        /**
-        * Find the specified scene by name, or the first
-        * scene if nothing matches (shouldn't happen).
+        * Find the specified scene by name, or NULL if nothing matches.
         */
-       if ((sce= (Scene *)BLI_findstring(&m_maggie->scene, name.ReadPtr(), offsetof(ID, name) + 2)))
+       if ((sce = (Scene *)BLI_findstring(&m_maggie->scene, name.ReadPtr(), offsetof(ID, name) + 2)))
                return sce;
 
-       for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++) {
-               Main *main= *it;
+       for (vector<Main *>::iterator it=m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
+               Main *main = *it;
 
                if ((sce= (Scene *)BLI_findstring(&main->scene, name.ReadPtr(), offsetof(ID, name) + 2)))
                        return sce;
        }
 
-       return (Scene*)m_maggie->scene.first;
-
+       return NULL;
 }
-#include "KX_PythonInit.h"
-
-#ifdef WITH_BULLET
-
-#include "LinearMath/btIDebugDraw.h"
-
-
-struct BlenderDebugDraw : public btIDebugDraw
-{
-       BlenderDebugDraw () :
-               m_debugMode(0) 
-       {
-       }
-       
-       int m_debugMode;
-
-       virtual void    drawLine(const btVector3& from,const btVector3& to,const btVector3& color)
-       {
-               if (m_debugMode >0)
-               {
-                       MT_Vector3 kxfrom(from[0],from[1],from[2]);
-                       MT_Vector3 kxto(to[0],to[1],to[2]);
-                       MT_Vector3 kxcolor(color[0],color[1],color[2]);
-
-                       KX_RasterizerDrawDebugLine(kxfrom,kxto,kxcolor);
-               }
-       }
-       
-       virtual void    reportErrorWarning(const char* warningString)
-       {
-
-       }
 
-       virtual void    drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,float distance,int lifeTime,const btVector3& color)
-       {
-               //not yet
-       }
-
-       virtual void    setDebugMode(int debugMode)
-       {
-               m_debugMode = debugMode;
-       }
-       virtual int             getDebugMode() const
-       {
-               return m_debugMode;
-       }
-       ///todo: find out if Blender can do this
-       virtual void    draw3dText(const btVector3& location,const char* textString)
-       {
-
-       }
-               
-};
-
-#endif
-
-void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene,
-                                                                                       class RAS_IRenderTools* rendertools,
-                                                                                       class RAS_ICanvas* canvas,
-                                                                                       bool libloading)
+void KX_BlenderSceneConverter::ConvertScene(KX_Scene *destinationscene, RAS_IRasterizer *rendertools,
+                                                                                       RAS_ICanvas *canvas, bool libloading)
 {
        //find out which physics engine
        Scene *blenderscene = destinationscene->GetBlenderScene();
 
+       PHY_IPhysicsEnvironment *phy_env = NULL;
+
        e_PhysicsEngine physics_engine = UseBullet;
-       bool useDbvtCulling = false;
        // hook for registration function during conversion.
        m_currentScene = destinationscene;
        destinationscene->SetSceneConverter(this);
@@ -330,57 +240,32 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene,
        // when doing threaded conversion, so it's disabled for now.
        // SG_SetActiveStage(SG_STAGE_CONVERTER);
 
-       if (blenderscene)
-       {
-       
-               switch (blenderscene->gm.physicsEngine)
+       switch (blenderscene->gm.physicsEngine) {
+#ifdef WITH_BULLET
+       case WOPHY_BULLET:
                {
-               case WOPHY_BULLET:
-                       {
-                               physics_engine = UseBullet;
-                               useDbvtCulling = (blenderscene->gm.mode & WO_DBVT_CULLING) != 0;
-                               break;
-                       }
-                       default:
-                       case WOPHY_NONE:
-                       {
-                               physics_engine = UseNone;
-                               break;
-                       }
-               }
-       }
+                       SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/
+                       int visualizePhysics = SYS_GetCommandLineInt(syshandle, "show_physics", 0);
 
-       switch (physics_engine)
-       {
-#ifdef WITH_BULLET
-               case UseBullet:
-                       {
-                               CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment(useDbvtCulling);
-                               ccdPhysEnv->setDebugDrawer(new BlenderDebugDraw());
-                               ccdPhysEnv->setDeactivationLinearTreshold(blenderscene->gm.lineardeactthreshold);
-                               ccdPhysEnv->setDeactivationAngularTreshold(blenderscene->gm.angulardeactthreshold);
-                               ccdPhysEnv->setDeactivationTime(blenderscene->gm.deactivationtime);
-
-                               SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/
-                               int visualizePhysics = SYS_GetCommandLineInt(syshandle,"show_physics",0);
-                               if (visualizePhysics)
-                                       ccdPhysEnv->setDebugMode(btIDebugDraw::DBG_DrawWireframe|btIDebugDraw::DBG_DrawAabb|btIDebugDraw::DBG_DrawContactPoints|btIDebugDraw::DBG_DrawText|btIDebugDraw::DBG_DrawConstraintLimits|btIDebugDraw::DBG_DrawConstraints);
-               
-                               //todo: get a button in blender ?
-                               //disable / enable debug drawing (contact points, aabb's etc)
-                               //ccdPhysEnv->setDebugMode(1);
-                               destinationscene->SetPhysicsEnvironment(ccdPhysEnv);
-                               break;
-                       }
+                       phy_env = CcdPhysicsEnvironment::Create(blenderscene, visualizePhysics);
+                       physics_engine = UseBullet;
+                       break;
+               }
 #endif
-               default:
-               case UseNone:
+       default:
+       case WOPHY_NONE:
+               {
+                       // We should probably use some sort of factory here
+                       phy_env = new DummyPhysicsEnvironment();
                        physics_engine = UseNone;
-                       destinationscene ->SetPhysicsEnvironment(new DummyPhysicsEnvironment());
                        break;
+               }
        }
 
-       BL_ConvertBlenderObjects(m_maggie,
+       destinationscene->SetPhysicsEnvironment(phy_env);
+
+       BL_ConvertBlenderObjects(
+               m_maggie,
                destinationscene,
                m_ketsjiEngine,
                physics_engine,
@@ -388,8 +273,7 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene,
                canvas,
                this,
                m_alwaysUseExpandFraming,
-               libloading
-               );
+               libloading);
 
        //These lookup are not needed during game
        m_map_blender_to_gameactuator.clear();
@@ -401,12 +285,6 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene,
        //This cache mecanism is buggy so I leave it disable and the memory leak
        //that would result from this is fixed in RemoveScene()
        m_map_mesh_to_gamemesh.clear();
-
-#ifndef WITH_BULLET
-       /* quiet compiler warning */
-       (void)useDbvtCulling;
-#endif
-
 }
 
 // This function removes all entities stored in the converter for that scene
@@ -421,30 +299,32 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene)
        // delete the scene first as it will stop the use of entities
        delete scene;
        // delete the entities of this scene
-       vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit;
+       vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator worldit;
        size = m_worldinfos.size();
-       for (i=0, worldit=m_worldinfos.begin(); i<size; ) {
-               if ((*worldit).first == scene) {
-                       delete (*worldit).second;
+       for (i = 0, worldit = m_worldinfos.begin(); i < size; ) {
+               if (worldit->first == scene) {
+                       delete worldit->second;
                        *worldit = m_worldinfos.back();
                        m_worldinfos.pop_back();
                        size--;
-               } else {
+               } 
+               else {
                        i++;
                        worldit++;
                }
        }
 
-       vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator polymit;
+       vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator polymit;
        size = m_polymaterials.size();
-       for (i=0, polymit=m_polymaterials.begin(); i<size; ) {
-               if ((*polymit).first == scene) {
-                       m_polymat_cache[scene].erase((*polymit).second->GetBlenderMaterial());
-                       delete (*polymit).second;
+       for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
+               if (polymit->first == scene) {
+                       m_polymat_cache[scene].erase(polymit->second->GetBlenderMaterial());
+                       delete polymit->second;
                        *polymit = m_polymaterials.back();
                        m_polymaterials.pop_back();
                        size--;
-               } else {
+               } 
+               else {
                        i++;
                        polymit++;
                }
@@ -452,16 +332,17 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene)
 
        m_polymat_cache.erase(scene);
 
-       vector<pair<KX_Scene*,BL_Material*> >::iterator matit;
+       vector<pair<KX_Scene *, BL_Material *> >::iterator matit;
        size = m_materials.size();
-       for (i=0, matit=m_materials.begin(); i<size; ) {
-               if ((*matit).first == scene) {
-                       m_mat_cache[scene].erase((*matit).second->material);
-                       delete (*matit).second;
+       for (i = 0, matit = m_materials.begin(); i < size; ) {
+               if (matit->first == scene) {
+                       m_mat_cache[scene].erase(matit->second->material);
+                       delete matit->second;
                        *matit = m_materials.back();
                        m_materials.pop_back();
                        size--;
-               } else {
+               } 
+               else {
                        i++;
                        matit++;
                }
@@ -469,15 +350,16 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene)
 
        m_mat_cache.erase(scene);
 
-       vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator meshit;
+       vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator meshit;
        size = m_meshobjects.size();
-       for (i=0, meshit=m_meshobjects.begin(); i<size; ) {
-               if ((*meshit).first == scene) {
-                       delete (*meshit).second;
+       for (i = 0, meshit = m_meshobjects.begin(); i < size; ) {
+               if (meshit->first == scene) {
+                       delete meshit->second;
                        *meshit = m_meshobjects.back();
                        m_meshobjects.pop_back();
                        size--;
-               } else {
+               } 
+               else {
                        i++;
                        meshit++;
                }
@@ -520,43 +402,34 @@ bool KX_BlenderSceneConverter::GetCacheMaterials()
 void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat)
 {
        // First make sure we don't register the material twice
-       vector<pair<KX_Scene*,BL_Material*> >::iterator it;
+       vector<pair<KX_Scene *, BL_Material *> >::iterator it;
        for (it = m_materials.begin(); it != m_materials.end(); ++it)
                if (it->second == mat)
                        return;
 
-       m_materials.push_back(pair<KX_Scene*,BL_Material *>(m_currentScene,mat));
+       m_materials.push_back(pair<KX_Scene *, BL_Material *> (m_currentScene, mat));
 }
 
-
-
-void KX_BlenderSceneConverter::SetAlwaysUseExpandFraming(
-       bool to_what)
+void KX_BlenderSceneConverter::SetAlwaysUseExpandFraming(bool to_what)
 {
        m_alwaysUseExpandFraming= to_what;
 }
 
-       
-
-void KX_BlenderSceneConverter::RegisterGameObject(
-                                                                       KX_GameObject *gameobject, 
-                                                                       struct Object *for_blenderobject) 
+void KX_BlenderSceneConverter::RegisterGameObject(KX_GameObject *gameobject, Object *for_blenderobject) 
 {
        /* only maintained while converting, freed during game runtime */
-       m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject),gameobject);
+       m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject), gameobject);
 }
 
 /* only need to run this during conversion since
  * m_map_blender_to_gameobject is freed after conversion */
-void KX_BlenderSceneConverter::UnregisterGameObject(
-                                                                       KX_GameObject *gameobject) 
+void KX_BlenderSceneConverter::UnregisterGameObject(KX_GameObject *gameobject) 
 {
-       struct Object *bobp= gameobject->GetBlenderObject();
+       Object *bobp = gameobject->GetBlenderObject();
        if (bobp) {
                CHashedPtr bptr(bobp);
-               KX_GameObject **gobp= m_map_blender_to_gameobject[bptr];
-               if (gobp && *gobp == gameobject)
-               {
+               KX_GameObject **gobp = m_map_blender_to_gameobject[bptr];
+               if (gobp && *gobp == gameobject) {
                        // also maintain m_map_blender_to_gameobject if the gameobject
                        // being removed is matching the blender object
                        m_map_blender_to_gameobject.remove(bptr);
@@ -564,47 +437,41 @@ void KX_BlenderSceneConverter::UnregisterGameObject(
        }
 }
 
-KX_GameObject *KX_BlenderSceneConverter::FindGameObject(
-                                                                       struct Object *for_blenderobject) 
+KX_GameObject *KX_BlenderSceneConverter::FindGameObject(Object *for_blenderobject) 
 {
-       KX_GameObject **obp= m_map_blender_to_gameobject[CHashedPtr(for_blenderobject)];
-       
-       return obp?*obp:NULL;
+       KX_GameObject **obp = m_map_blender_to_gameobject[CHashedPtr(for_blenderobject)];
+
+       return obp ? *obp : NULL;
 }
 
-void KX_BlenderSceneConverter::RegisterGameMesh(
-                                                                       RAS_MeshObject *gamemesh,
-                                                                       struct Mesh *for_blendermesh)
+void KX_BlenderSceneConverter::RegisterGameMesh(RAS_MeshObject *gamemesh, Mesh *for_blendermesh)
 {
        if (for_blendermesh) { /* dynamically loaded meshes we don't want to keep lookups for */
                m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh);
        }
-       m_meshobjects.push_back(pair<KX_Scene*,RAS_MeshObject*>(m_currentScene,gamemesh));
+       m_meshobjects.push_back(pair<KX_Scene *, RAS_MeshObject *> (m_currentScene,gamemesh));
 }
 
-
-
-RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh(
-                                                                       struct Mesh *for_blendermesh/*,
-                                                                       unsigned int onlayer*/)
+RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh(Mesh *for_blendermesh)
 {
-       RAS_MeshObject** meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)];
-       
-       if (meshp/* && onlayer==(*meshp)->GetLightLayer()*/) {
+       RAS_MeshObject **meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)];
+
+       if (meshp) {
                return *meshp;
-       } else {
+       } 
+       else {
                return NULL;
        }
-}      
+}
 
 void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat)
 {
        // First make sure we don't register the material twice
-       vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator it;
+       vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator it;
        for (it = m_polymaterials.begin(); it != m_polymaterials.end(); ++it)
                if (it->second == polymat)
                        return;
-       m_polymaterials.push_back(pair<KX_Scene*,RAS_IPolyMaterial*>(m_currentScene,polymat));
+       m_polymaterials.push_back(pair<KX_Scene *, RAS_IPolyMaterial *> (m_currentScene, polymat));
 }
 
 void KX_BlenderSceneConverter::CachePolyMaterial(KX_Scene *scene, Material *mat, RAS_IPolyMaterial *polymat)
@@ -613,130 +480,99 @@ void KX_BlenderSceneConverter::CachePolyMaterial(KX_Scene *scene, Material *mat,
                m_polymat_cache[scene][mat] = polymat;
 }
 
-RAS_IPolyMaterial *KX_BlenderSceneConverter::FindCachedPolyMaterial(KX_Scene *scene, struct Material *mat)
+RAS_IPolyMaterial *KX_BlenderSceneConverter::FindCachedPolyMaterial(KX_Scene *scene, Material *mat)
 {
        return (m_use_mat_cache) ? m_polymat_cache[scene][mat] : NULL;
 }
 
-void KX_BlenderSceneConverter::CacheBlenderMaterial(KX_Scene *scene, struct Material *mat, BL_Material *blmat)
+void KX_BlenderSceneConverter::CacheBlenderMaterial(KX_Scene *scene, Material *mat, BL_Material *blmat)
 {
        if (m_use_mat_cache && mat)
                m_mat_cache[scene][mat] = blmat;
 }
 
-BL_Material *KX_BlenderSceneConverter::FindCachedBlenderMaterial(KX_Scene *scene, struct Material *mat)
+BL_Material *KX_BlenderSceneConverter::FindCachedBlenderMaterial(KX_Scene *scene, Material *mat)
 {
        return (m_use_mat_cache) ? m_mat_cache[scene][mat] : NULL;
 }
 
-void KX_BlenderSceneConverter::RegisterInterpolatorList(
-                                                                       BL_InterpolatorList *actList,
-                                                                       struct bAction *for_act)
+void KX_BlenderSceneConverter::RegisterInterpolatorList(BL_InterpolatorList *actList, bAction *for_act)
 {
        m_map_blender_to_gameAdtList.insert(CHashedPtr(for_act), actList);
 }
 
-
-
-BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList(
-                                                                       struct bAction *for_act)
+BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList(bAction *for_act)
 {
        BL_InterpolatorList **listp = m_map_blender_to_gameAdtList[CHashedPtr(for_act)];
-               
-       return listp?*listp:NULL;
+       return listp ? *listp : NULL;
 }
 
-
-
-void KX_BlenderSceneConverter::RegisterGameActuator(
-                                                                       SCA_IActuator *act,
-                                                                       struct bActuator *for_actuator)
+void KX_BlenderSceneConverter::RegisterGameActuator(SCA_IActuator *act, bActuator *for_actuator)
 {
        m_map_blender_to_gameactuator.insert(CHashedPtr(for_actuator), act);
 }
 
-
-
-SCA_IActuator *KX_BlenderSceneConverter::FindGameActuator(
-                                                                       struct bActuator *for_actuator)
+SCA_IActuator *KX_BlenderSceneConverter::FindGameActuator(bActuator *for_actuator)
 {
        SCA_IActuator **actp = m_map_blender_to_gameactuator[CHashedPtr(for_actuator)];
-       
-       return actp?*actp:NULL;
+       return actp ? *actp : NULL;
 }
 
-
-
-void KX_BlenderSceneConverter::RegisterGameController(
-                                                                       SCA_IController *cont,
-                                                                       struct bController *for_controller)
+void KX_BlenderSceneConverter::RegisterGameController(SCA_IController *cont, bController *for_controller)
 {
        m_map_blender_to_gamecontroller.insert(CHashedPtr(for_controller), cont);
 }
 
-
-
-SCA_IController *KX_BlenderSceneConverter::FindGameController(
-                                                                       struct bController *for_controller)
+SCA_IController *KX_BlenderSceneConverter::FindGameController(bController *for_controller)
 {
        SCA_IController **contp = m_map_blender_to_gamecontroller[CHashedPtr(for_controller)];
-       
-       return contp?*contp:NULL;
+       return contp ? *contp : NULL;
 }
 
-
-
-void KX_BlenderSceneConverter::RegisterWorldInfo(
-                                                                       KX_WorldInfo *worldinfo)
+void KX_BlenderSceneConverter::RegisterWorldInfo(KX_WorldInfo *worldinfo)
 {
-       m_worldinfos.push_back(pair<KX_Scene*,KX_WorldInfo*>(m_currentScene,worldinfo));
+       m_worldinfos.push_back(pair<KX_Scene *, KX_WorldInfo *> (m_currentScene, worldinfo));
 }
 
-void   KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo)
+void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo)
 {
+       //TODO this entire function is deprecated, written for 2.4x
+       //the functionality should be rewritten, currently it does nothing
 
-       KX_SceneListscenes = m_ketsjiEngine->CurrentScenes();
+       KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
        int numScenes = scenes->size();
        int i;
-       for (i=0;i<numScenes;i++)
-       {
-               KX_Scene* scene = scenes->at(i);
-               //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
-               CListValue* parentList = scene->GetRootParentList();
+       for (i = 0; i < numScenes; i++) {
+               KX_Scene *scene = scenes->at(i);
+               CListValue *parentList = scene->GetRootParentList();
                int numObjects = parentList->GetCount();
                int g;
-               for (g=0;g<numObjects;g++)
-               {
-                       KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
-                       if (gameObj->IsDynamic())
-                       {
-                               //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController();
-                               
-                               Object* blenderObject = gameObj->GetBlenderObject();
-                               if (blenderObject)
-                               {
+               for (g = 0; g < numObjects; g++) {
+                       KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
+                       if (gameObj->IsRecordAnimation()) {
+                               Object *blenderObject = gameObj->GetBlenderObject();
+                               if (blenderObject) {
 #if 0
                                        //erase existing ipo's
                                        Ipo* ipo = blenderObject->ipo;//findIpoForName(blenderObject->id.name+2);
-                                       if (ipo)
-                                       {       //clear the curve data
+                                       if (ipo) {      //clear the curve data
                                                if (clearIpo) {//rcruiz
                                                        IpoCurve *icu1;
-                                                                                                               
+
                                                        int numCurves = 0;
                                                        for ( icu1 = (IpoCurve*)ipo->curve.first; icu1;  ) {
-                                                       
+
                                                                IpoCurve* tmpicu = icu1;
-                                                               
+
                                                                /*int i;
                                                                BezTriple *bezt;
                                                                for ( bezt = tmpicu->bezt, i = 0;       i < tmpicu->totvert; i++, bezt++) {
                                                                        printf("(%f,%f,%f),(%f,%f,%f),(%f,%f,%f)\n",bezt->vec[0][0],bezt->vec[0][1],bezt->vec[0][2],bezt->vec[1][0],bezt->vec[1][1],bezt->vec[1][2],bezt->vec[2][0],bezt->vec[2][1],bezt->vec[2][2]);
                                                                }*/
-                                                               
+
                                                                icu1 = icu1->next;
                                                                numCurves++;
-                       
+
                                                                BLI_remlink( &( blenderObject->ipo->curve ), tmpicu );
                                                                if ( tmpicu->bezt )
                                                                        MEM_freeN( tmpicu->bezt );
@@ -744,110 +580,58 @@ void     KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo)
                                                                localDel_ipoCurve( tmpicu );
                                                        }
                                                }
-                                       } else
-                                       {       ipo = NULL; // XXX add_ipo(blenderObject->id.name+2, ID_OB);
+                                       } 
+                                       else {
+                                               ipo = NULL; // XXX add_ipo(blenderObject->id.name+2, ID_OB);
                                                blenderObject->ipo = ipo;
-
                                        }
 #endif
                                }
                        }
-
                }
-               
-       
        }
-
-
-
 }
 
-void   KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo()
+void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo()
 {
-       if (addInitFromFrame) {
-               KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
-               int numScenes = scenes->size();
-               if (numScenes>=0) {
-                       KX_Scene* scene = scenes->at(0);
-                       CListValue* parentList = scene->GetRootParentList();
-                       for (int ix=0;ix<parentList->GetCount();ix++) {
-                               KX_GameObject* gameobj = (KX_GameObject*)parentList->GetValue(ix);
-                               if (!gameobj->IsDynamic()) {
-                                       Object* blenderobject = gameobj->GetBlenderObject();
-                                       if (!blenderobject)
-                                               continue;
-                                       if (blenderobject->type==OB_ARMATURE)
-                                               continue;
-                                       float eu[3];
-                                       mat4_to_eul(eu,blenderobject->obmat);
-                                       MT_Point3 pos = MT_Point3(
-                                               blenderobject->obmat[3][0],
-                                               blenderobject->obmat[3][1],
-                                               blenderobject->obmat[3][2]
-                                       );
-                                       MT_Vector3 eulxyz = MT_Vector3(
-                                               eu[0],
-                                               eu[1],
-                                               eu[2]
-                                       );
-                                       MT_Vector3 scale = MT_Vector3(
-                                               blenderobject->size[0],
-                                               blenderobject->size[1],
-                                               blenderobject->size[2]
-                                       );
-                                       gameobj->NodeSetLocalPosition(pos);
-                                       gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz));
-                                       gameobj->NodeSetLocalScale(scale);
-                                       gameobj->NodeUpdateGS(0);
-                               }
-                       }
-               }
-       }
+       //TODO the functionality should be rewritten
 }
 
-
-       ///this generates ipo curves for position, rotation, allowing to use game physics in animation
-void   KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
+// this generates ipo curves for position, rotation, allowing to use game physics in animation
+void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
 {
-
-       KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+       KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
        int numScenes = scenes->size();
        int i;
-       for (i=0;i<numScenes;i++)
-       {
-               KX_Scene* scene = scenes->at(i);
+       for (i = 0; i < numScenes; i++) {
+               KX_Scene *scene = scenes->at(i);
                //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
-               CListValueparentList = scene->GetObjectList();
+               CListValue *parentList = scene->GetObjectList();
                int numObjects = parentList->GetCount();
                int g;
-               for (g=0;g<numObjects;g++)
-               {
-                       KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
-                       Object* blenderObject = gameObj->GetBlenderObject();
-                       if (blenderObject && blenderObject->parent==NULL && gameObj->IsDynamic())
-                       {
-                               //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController();
-
-                               if (blenderObject->adt==NULL)
-                                       BKE_id_add_animdata(&blenderObject->id);
-
-                               if (blenderObject->adt)
-                               {
-                                       const MT_Point3& position = gameObj->NodeGetWorldPosition();
+               for (g = 0; g < numObjects; g++) {
+                       KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
+                       Object *blenderObject = gameObj->GetBlenderObject();
+                       if (blenderObject && blenderObject->parent == NULL && gameObj->IsRecordAnimation()) {
+                               if (blenderObject->adt == NULL)
+                                       BKE_animdata_add_id(&blenderObject->id);
+
+                               if (blenderObject->adt) {
+                                       const MT_Point3 &position = gameObj->NodeGetWorldPosition();
                                        //const MT_Vector3& scale = gameObj->NodeGetWorldScaling();
-                                       const MT_Matrix3x3orn = gameObj->NodeGetWorldOrientation();
+                                       const MT_Matrix3x3 &orn = gameObj->NodeGetWorldOrientation();
 
                                        position.getValue(blenderObject->loc);
 
                                        float tmat[3][3];
-                                       for (int r=0;r<3;r++)
-                                               for (int c=0;c<3;c++)
+                                       for (int r = 0; r < 3; r++)
+                                               for (int c = 0; c < 3; c++)
                                                        tmat[r][c] = (float)orn[c][r];
 
                                        mat3_to_compatible_eul(blenderObject->rot, blenderObject->rot, tmat);
 
-                                       insert_keyframe(NULL, &blenderObject->id, NULL, NULL, "location", -1, (float)frameNumber, INSERTKEY_FAST);
-                                       insert_keyframe(NULL, &blenderObject->id, NULL, NULL, "rotation_euler", -1, (float)frameNumber, INSERTKEY_FAST);
+                                       insert_keyframe(G.main, NULL, &blenderObject->id, NULL, NULL, "location", -1, (float)frameNumber, BEZT_KEYTYPE_JITTER, INSERTKEY_FAST);
+                                       insert_keyframe(G.main, NULL, &blenderObject->id, NULL, NULL, "rotation_euler", -1, (float)frameNumber, BEZT_KEYTYPE_JITTER, INSERTKEY_FAST);
 
 #if 0
                                        const MT_Point3& position = gameObj->NodeGetWorldPosition();
@@ -926,34 +710,39 @@ void      KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
        }
 }
 
-
-void   KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo()
+void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo()
 {
-
-       KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+       KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
        int numScenes = scenes->size();
        int i;
-       for (i=0;i<numScenes;i++)
-       {
-               KX_Scene* scene = scenes->at(i);
+       for (i = 0; i < numScenes; i++) {
+               KX_Scene *scene = scenes->at(i);
                //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
-               CListValueparentList = scene->GetRootParentList();
+               CListValue *parentList = scene->GetRootParentList();
                int numObjects = parentList->GetCount();
                int g;
-               for (g=0;g<numObjects;g++)
-               {
-                       KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
-                       if (gameObj->IsDynamic())
-                       {
-                               //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController();
-                               
+               for (g = 0; g < numObjects; g++) {
+                       KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
+                       if (gameObj->IsRecordAnimation()) {
+                               Object *blenderObject = gameObj->GetBlenderObject();
+                               if (blenderObject && blenderObject->adt) {
+                                       bAction *act = verify_adt_action(G.main, &blenderObject->id, false);
+                                       FCurve *fcu;
+
+                                       if (!act) {
+                                               continue;
+                                       }
+
+                                       /* for now, not much choice but to run this on all curves... */
+                                       for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
+                                               /* Note: calling `sort_time_fcurve()` here is not needed, since
+                                                *       all keys have been added in 'right' order. */
+                                               calchandles_fcurve(fcu);
+                                       }
 #if 0
-                               Object* blenderObject = gameObj->GetBlenderObject();
-                               if (blenderObject && blenderObject->ipo)
-                               {
                                        // XXX animato
                                        Ipo* ipo = blenderObject->ipo;
-                                       
+
                                        //create the curves, if not existing
                                        //testhandles_ipocurve checks for NULL
                                        testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"));
@@ -962,8 +751,8 @@ void        KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo()
                                        testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"));
                                        testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"));
                                        testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"));
-                               }
 #endif
+                               }
                        }
                }
        }
@@ -976,14 +765,14 @@ PyObject *KX_BlenderSceneConverter::GetPyNamespace()
 }
 #endif
 
-vector<Main*> &KX_BlenderSceneConverter::GetMainDynamic()
+vector<Main *> &KX_BlenderSceneConverter::GetMainDynamic()
 {
        return m_DynamicMaggie;
 }
 
-MainKX_BlenderSceneConverter::GetMainDynamicPath(const char *path)
+Main *KX_BlenderSceneConverter::GetMainDynamicPath(const char *path)
 {
-       for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++)
+       for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++)
                if (BLI_path_cmp((*it)->name, path) == 0)
                        return *it;
        
@@ -992,22 +781,21 @@ Main* KX_BlenderSceneConverter::GetMainDynamicPath(const char *path)
 
 void KX_BlenderSceneConverter::MergeAsyncLoads()
 {
-       vector<KX_Scene*> *merge_scenes;
+       vector<KX_Scene *> *merge_scenes;
 
-       vector<KX_LibLoadStatus*>::iterator mit;
-       vector<KX_Scene*>::iterator sit;
+       vector<KX_LibLoadStatus *>::iterator mit;
+       vector<KX_Scene *>::iterator sit;
 
-       pthread_mutex_lock(&m_threadinfo->merge_lock);
+       BLI_mutex_lock(&m_threadinfo->m_mutex);
 
-       for (mit=m_mergequeue.begin(); mit!=m_mergequeue.end(); ++mit) {
-               merge_scenes = (vector<KX_Scene*>*)(*mit)->GetData();
+       for (mit = m_mergequeue.begin(); mit != m_mergequeue.end(); ++mit) {
+               merge_scenes = (vector<KX_Scene *> *)(*mit)->GetData();
 
                for (sit=merge_scenes->begin(); sit!=merge_scenes->end(); ++sit) {
                        (*mit)->GetMergeScene()->MergeScene(*sit);
                        delete (*sit);
                }
 
-
                delete merge_scenes;
                (*mit)->SetData(NULL);
 
@@ -1016,38 +804,46 @@ void KX_BlenderSceneConverter::MergeAsyncLoads()
 
        m_mergequeue.clear();
 
-       pthread_mutex_unlock(&m_threadinfo->merge_lock);
+       BLI_mutex_unlock(&m_threadinfo->m_mutex);
+}
+
+void KX_BlenderSceneConverter::FinalizeAsyncLoads()
+{
+       // Finish all loading libraries.
+       if (m_threadinfo) {
+               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();
 }
 
 void KX_BlenderSceneConverter::AddScenesToMergeQueue(KX_LibLoadStatus *status)
 {
-       pthread_mutex_lock(&m_threadinfo->merge_lock);
+       BLI_mutex_lock(&m_threadinfo->m_mutex);
        m_mergequeue.push_back(status);
-       pthread_mutex_unlock(&m_threadinfo->merge_lock);
+       BLI_mutex_unlock(&m_threadinfo->m_mutex);
 }
 
-static void *async_convert(void *ptr)
+static void async_convert(TaskPool *pool, void *ptr, int UNUSED(threadid))
 {
        KX_Scene *new_scene = NULL;
-       KX_LibLoadStatus *status = (KX_LibLoadStatus*)ptr;
-       vector<Scene*> *scenes = (vector<Scene*>*)status->GetData();
-       vector<KX_Scene*> *merge_scenes = new vector<KX_Scene*>(); // Deleted in MergeAsyncLoads
+       KX_LibLoadStatus *status = (KX_LibLoadStatus *)ptr;
+       vector<Scene *> *scenes = (vector<Scene *> *)status->GetData();
+       vector<KX_Scene *> *merge_scenes = new vector<KX_Scene *>(); // Deleted in MergeAsyncLoads
 
-       for (unsigned int i=0; i<scenes->size(); ++i) {
+       for (unsigned int i = 0; i < scenes->size(); ++i) {
                new_scene = status->GetEngine()->CreateScene((*scenes)[i], true);
 
                if (new_scene)
                        merge_scenes->push_back(new_scene);
 
-               status->AddProgress((1.f/scenes->size())*0.9f); // We'll call conversion 90% and merging 10% for now
+               status->AddProgress((1.0f / scenes->size()) * 0.9f); // We'll call conversion 90% and merging 10% for now
        }
 
        delete scenes;
        status->SetData(merge_scenes);
 
        status->GetConverter()->AddScenesToMergeQueue(status);
-
-       return NULL;
 }
 
 KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options)
@@ -1066,28 +862,21 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFilePath(const char *filepa
        return LinkBlendFile(bpy_openlib, filepath, group, scene_merge, err_str, options);
 }
 
-static void load_datablocks(Main *main_newlib, BlendHandle *bpy_openlib, const char *path, int idcode)
+static void load_datablocks(Main *main_tmp, BlendHandle *bpy_openlib, const char *path, int idcode)
 {
-       Main *main_tmp= NULL; /* created only for linking, then freed */
        LinkNode *names = NULL;
-       short flag= 0; /* don't need any special options */
-
-       /* here appending/linking starts */
-       main_tmp = BLO_library_append_begin(main_newlib, &bpy_openlib, (char *)path);
 
        int totnames_dummy;
-       names = BLO_blendhandle_get_datablock_names( bpy_openlib, idcode, &totnames_dummy);
+       names = BLO_blendhandle_get_datablock_names(bpy_openlib, idcode, &totnames_dummy);
        
-       int i=0;
-       LinkNode *n= names;
+       int i = 0;
+       LinkNode *n = names;
        while (n) {
-               BLO_library_append_named_part(main_tmp, &bpy_openlib, (char *)n->link, idcode);
-               n= (LinkNode *)n->next;
+               BLO_library_link_named_part(main_tmp, &bpy_openlib, idcode, (char *)n->link);
+               n = (LinkNode *)n->next;
                i++;
        }
        BLI_linklist_free(names, free); /* free linklist *and* each node's data */
-       
-       BLO_library_append_end(NULL, main_tmp, &bpy_openlib, idcode, flag);
 }
 
 KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options)
@@ -1100,42 +889,48 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
 //     TIMEIT_START(bge_link_blend_file);
 
        KX_LibLoadStatus *status;
-       
+
        /* only scene and mesh supported right now */
-       if (idcode!=ID_SCE && idcode!=ID_ME &&idcode!=ID_AC) {
+       if (idcode != ID_SCE && idcode != ID_ME && idcode != ID_AC) {
                snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group);
-               *err_str= err_local;
+               *err_str = err_local;
                BLO_blendhandle_close(bpy_openlib);
                return NULL;
        }
        
        if (GetMainDynamicPath(path)) {
                snprintf(err_local, sizeof(err_local), "blend file already open \"%s\"\n", path);
-               *err_str= err_local;
+               *err_str = err_local;
                BLO_blendhandle_close(bpy_openlib);
                return NULL;
        }
 
-       if (bpy_openlib==NULL) {
+       if (bpy_openlib == NULL) {
                snprintf(err_local, sizeof(err_local), "could not open blendfile \"%s\"\n", path);
-               *err_str= err_local;
+               *err_str = err_local;
                return NULL;
        }
-       
-       main_newlib= (Main *)MEM_callocN( sizeof(Main), "BgeMain");
+
+       main_newlib = BKE_main_new();
        BKE_reports_init(&reports, RPT_STORE);
 
-       load_datablocks(main_newlib, bpy_openlib, path, idcode);
+       short flag = 0; /* don't need any special options */
+       /* created only for linking, then freed */
+       Main *main_tmp = BLO_library_link_begin(main_newlib, &bpy_openlib, (char *)path);
 
-       if (idcode==ID_SCE && options & LIB_LOAD_LOAD_SCRIPTS) {
-               load_datablocks(main_newlib, bpy_openlib, path, ID_TXT);
+       load_datablocks(main_tmp, bpy_openlib, path, idcode);
+
+       if (idcode == ID_SCE && options & LIB_LOAD_LOAD_SCRIPTS) {
+               load_datablocks(main_tmp, bpy_openlib, 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_newlib, bpy_openlib, path, ID_AC);
+       if (idcode == ID_SCE && options & LIB_LOAD_LOAD_ACTIONS) {
+               load_datablocks(main_tmp, bpy_openlib, path, ID_AC);
        }
-       
+
+       BLO_library_link_end(main_tmp, &bpy_openlib, flag, NULL, NULL);
+
        BLO_blendhandle_close(bpy_openlib);
 
        BKE_reports_clear(&reports);
@@ -1148,42 +943,43 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
        
        status = new KX_LibLoadStatus(this, m_ketsjiEngine, scene_merge, path);
 
-       if (idcode==ID_ME) {
+       if (idcode == ID_ME) {
                /* Convert all new meshes into BGE meshes */
-               IDmesh;
+               ID *mesh;
        
-               for (mesh= (ID *)main_newlib->mesh.first; mesh; mesh= (ID *)mesh->next ) {
+               for (mesh = (ID *)main_newlib->mesh.first; mesh; mesh = (ID *)mesh->next ) {
                        if (options & LIB_LOAD_VERBOSE)
-                               printf("MeshName: %s\n", mesh->name+2);
+                               printf("MeshName: %s\n", mesh->name + 2);
                        RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)mesh, NULL, scene_merge, this, false); // For now only use the libloading option for scenes, which need to handle materials/shaders
-                       scene_merge->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
+                       scene_merge->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj);
                }
        }
-       else if (idcode==ID_AC) {
+       else if (idcode == ID_AC) {
                /* Convert all actions */
                ID *action;
 
-               for (action= (ID *)main_newlib->action.first; action; action= (ID *)action->next) {
+               for (action= (ID *)main_newlib->action.first; action; action = (ID *)action->next) {
                        if (options & LIB_LOAD_VERBOSE)
-                               printf("ActionName: %s\n", action->name+2);
-                       scene_merge->GetLogicManager()->RegisterActionName(action->name+2, action);
+                               printf("ActionName: %s\n", action->name + 2);
+                       scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action);
                }
        }
-       else if (idcode==ID_SCE) {
+       else if (idcode == ID_SCE) {
                /* Merge all new linked in scene into the existing one */
                ID *scene;
                // scenes gets deleted by the thread when it's done using it (look in async_convert())
-               vector<Scene*> *scenes =  (options & LIB_LOAD_ASYNC) ? new vector<Scene*>() : NULL;
+               vector<Scene *> *scenes = (options & LIB_LOAD_ASYNC) ? new vector<Scene *>() : NULL;
 
-               for (scene= (ID *)main_newlib->scene.first; scene; scene= (ID *)scene->next ) {
+               for (scene = (ID *)main_newlib->scene.first; scene; scene = (ID *)scene->next ) {
                        if (options & LIB_LOAD_VERBOSE)
-                               printf("SceneName: %s\n", scene->name+2);
+                               printf("SceneName: %s\n", scene->name + 2);
                        
                        if (options & LIB_LOAD_ASYNC) {
-                               scenes->push_back((Scene*)scene);
-                       } else {
+                               scenes->push_back((Scene *)scene);
+                       } 
+                       else {
                                /* merge into the base  scene */
-                               KX_Scene* other= m_ketsjiEngine->CreateScene((Scene *)scene, true);
+                               KX_Scene* other = m_ketsjiEngine->CreateScene((Scene *)scene, true);
                                scene_merge->MergeScene(other);
                        
                                // RemoveScene(other); // Don't run this, it frees the entire scene converter data, just delete the scene
@@ -1192,10 +988,8 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
                }
 
                if (options & LIB_LOAD_ASYNC) {
-                       pthread_t id;
                        status->SetData(scenes);
-                       pthread_create(&id, NULL, &async_convert, (void*)status);
-                       m_threadinfo->threads.push_back(id);
+                       BLI_task_pool_push(m_threadinfo->m_pool, async_convert, (void *)status, false, TASK_PRIORITY_LOW);
                }
 
 #ifdef WITH_PYTHON
@@ -1208,17 +1002,16 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
                if (options & LIB_LOAD_LOAD_ACTIONS) {
                        ID *action;
 
-                       for (action= (ID *)main_newlib->action.first; action; action= (ID *)action->next) {
+                       for (action = (ID *)main_newlib->action.first; action; action = (ID *)action->next) {
                                if (options & LIB_LOAD_VERBOSE)
-                                       printf("ActionName: %s\n", action->name+2);
-                               scene_merge->GetLogicManager()->RegisterActionName(action->name+2, action);
+                                       printf("ActionName: %s\n", action->name + 2);
+                               scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action);
                        }
                }
        }
 
        if (!(options & LIB_LOAD_ASYNC))
                status->Finish();
-       
 
 //     TIMEIT_END(bge_link_blend_file);
 
@@ -1228,22 +1021,34 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
 
 /* 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 KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
+bool KX_BlenderSceneConverter::FreeBlendFile(Main *maggie)
 {
-       int maggie_index= -1;
-       int i=0;
+       int maggie_index = -1;
+       int i = 0;
 
-       if (maggie==NULL)
+       if (maggie == NULL)
                return false;
-       
+
+       // If the given library is currently in loading, we do nothing.
+       if (m_status_map.count(maggie->name)) {
+               BLI_mutex_lock(&m_threadinfo->m_mutex);
+               const bool finished = m_status_map[maggie->name]->IsFinished();
+               BLI_mutex_unlock(&m_threadinfo->m_mutex);
+
+               if (!finished) {
+                       printf("Library (%s) is currently being loaded asynchronously, and cannot be freed until this process is done\n", maggie->name);
+                       return false;
+               }
+       }
+
        /* tag all false except the one we remove */
-       for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++) {
-               Main *main= *it;
+       for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
+               Main *main = *it;
                if (main != maggie) {
-                       tag_main(main, 0);
+                       BKE_main_id_tag_all(main, LIB_TAG_DOIT, false);
                }
                else {
-                       maggie_index= i;
+                       maggie_index = i;
                }
                i++;
        }
@@ -1253,17 +1058,14 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
                return false;
 
        m_DynamicMaggie.erase(m_DynamicMaggie.begin() + maggie_index);
-       tag_main(maggie, 1);
-
+       BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, true);
 
        /* free all tagged objects */
-       KX_SceneListscenes = m_ketsjiEngine->CurrentScenes();
+       KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
        int numScenes = scenes->size();
 
-
-       for (int scene_idx=0;scene_idx<numScenes;scene_idx++)
-       {
-               KX_Scene* scene = scenes->at(scene_idx);
+       for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) {
+               KX_Scene *scene = scenes->at(scene_idx);
                if (IS_TAGGED(scene->GetBlenderScene())) {
                        m_ketsjiEngine->RemoveScene(scene->GetName());
                        m_mat_cache.erase(scene);
@@ -1272,16 +1074,13 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
                        numScenes--;
                }
                else {
-                       
                        /* in case the mesh might be refered to later */
                        {
-                               CTR_Map<STR_HashedString,void*> &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap();
+                               CTR_Map<STR_HashedString, void *> &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap();
                                
-                               for (int i=0; i<mapStringToMeshes.size(); i++)
-                               {
-                                       RAS_MeshObject *meshobj= (RAS_MeshObject *) *mapStringToMeshes.at(i);
-                                       if (meshobj && IS_TAGGED(meshobj->GetMesh()))
-                                       {
+                               for (int i = 0; i < mapStringToMeshes.size(); i++) {
+                                       RAS_MeshObject *meshobj = (RAS_MeshObject *) *mapStringToMeshes.at(i);
+                                       if (meshobj && IS_TAGGED(meshobj->GetMesh())) {
                                                STR_HashedString mn = meshobj->GetName();
                                                mapStringToMeshes.remove(mn);
                                                m_map_mesh_to_gamemesh.remove(CHashedPtr(meshobj->GetMesh()));
@@ -1292,16 +1091,15 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
 
                        /* Now unregister actions */
                        {
-                               CTR_Map<STR_HashedString,void*> &mapStringToActions = scene->GetLogicManager()->GetActionMap();
+                               CTR_Map<STR_HashedString, void *> &mapStringToActions = scene->GetLogicManager()->GetActionMap();
 
-                               for (int i=0; i<mapStringToActions.size(); i++)
-                               {
-                                       ID *action= (ID*) *mapStringToActions.at(i);
+                               for (int i = 0; i < mapStringToActions.size(); i++) {
+                                       ID *action = (ID*) *mapStringToActions.at(i);
 
-                                       if (IS_TAGGED(action))
-                                       {
-                                               STR_HashedString an = action->name+2;
+                                       if (IS_TAGGED(action)) {
+                                               STR_HashedString an = action->name + 2;
                                                mapStringToActions.remove(an);
+                                               m_map_blender_to_gameAdtList.remove(CHashedPtr(action));
                                                i--;
                                        }
                                }
@@ -1310,16 +1108,13 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
                        //scene->FreeTagged(); /* removed tagged objects and meshes*/
                        CListValue *obj_lists[] = {scene->GetObjectList(), scene->GetInactiveList(), NULL};
 
-                       for (int ob_ls_idx=0; obj_lists[ob_ls_idx]; ob_ls_idx++)
-                       {
-                               CListValue *obs= obj_lists[ob_ls_idx];
-                               RAS_MeshObject* mesh;
+                       for (int ob_ls_idx = 0; obj_lists[ob_ls_idx]; ob_ls_idx++) {
+                               CListValue *obs = obj_lists[ob_ls_idx];
+                               RAS_MeshObject *mesh;
 
-                               for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++)
-                               {
-                                       KX_GameObject* gameobj = (KX_GameObject*)obs->GetValue(ob_idx);
+                               for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++) {
+                                       KX_GameObject *gameobj = (KX_GameObject*)obs->GetValue(ob_idx);
                                        if (IS_TAGGED(gameobj->GetBlenderObject())) {
-
                                                int size_before = obs->GetCount();
 
                                                /* Eventually calls RemoveNodeDestructObject
@@ -1333,22 +1128,31 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
                                                }
                                        }
                                        else {
+                                               gameobj->RemoveTaggedActions();
                                                /* free the mesh, we could be referecing a linked one! */
-                                               int mesh_index= gameobj->GetMeshCount();
+                                               int mesh_index = gameobj->GetMeshCount();
                                                while (mesh_index--) {
-                                                       mesh= gameobj->GetMesh(mesh_index);
+                                                       mesh = gameobj->GetMesh(mesh_index);
                                                        if (IS_TAGGED(mesh->GetMesh())) {
                                                                gameobj->RemoveMeshes(); /* XXX - slack, should only remove meshes that are library items but mostly objects only have 1 mesh */
                                                                break;
                                                        }
+                                                       else {
+                                                               /* also free the mesh if it's using a tagged material */
+                                                               int mat_index = mesh->NumMaterials();
+                                                               while (mat_index--) {
+                                                                       if (IS_TAGGED(mesh->GetMeshMaterial(mat_index)->m_bucket->GetPolyMaterial()->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];
+                                               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(NULL);
                                                        }
@@ -1359,7 +1163,6 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
                }
        }
 
-
        int size;
 
        // delete the entities of this scene
@@ -1382,24 +1185,24 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
 
 
        /* Worlds don't reference original blender data so we need to make a set from them */
-       typedef std::set<KX_WorldInfo*> KX_WorldInfoSet;
+       typedef std::set<KX_WorldInfo *> KX_WorldInfoSet;
        KX_WorldInfoSet worldset;
-       for (int scene_idx=0;scene_idx<numScenes;scene_idx++)
-       {
-               KX_Scene* scene = scenes->at(scene_idx);
+       for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) {
+               KX_Scene *scene = scenes->at(scene_idx);
                if (scene->GetWorldInfo())
-                       worldset.insert( scene->GetWorldInfo() );
+                       worldset.insert(scene->GetWorldInfo());
        }
 
-       vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit;
+       vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator worldit;
        size = m_worldinfos.size();
-       for (i=0, worldit=m_worldinfos.begin(); i<size; ) {
-               if ((*worldit).second && (worldset.count((*worldit).second)) == 0) {
-                       delete (*worldit).second;
+       for (i = 0, worldit = m_worldinfos.begin(); i < size;) {
+               if (worldit->second && (worldset.count(worldit->second)) == 0) {
+                       delete worldit->second;
                        *worldit = m_worldinfos.back();
                        m_worldinfos.pop_back();
                        size--;
-               } else {
+               } 
+               else {
                        i++;
                        worldit++;
                }
@@ -1407,98 +1210,106 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
        worldset.clear();
        /* done freeing the worlds */
 
-
-
-
-       vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator polymit;
+       vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator polymit;
        size = m_polymaterials.size();
 
+       for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
+               RAS_IPolyMaterial *mat = polymit->second;
+               Material *bmat = NULL;
 
-
-       for (i=0, polymit=m_polymaterials.begin(); i<size; ) {
-               RAS_IPolyMaterial *mat= (*polymit).second;
-               Material *bmat= NULL;
-
-               /* Why do we need to check for RAS_BLENDERMAT if both are cast to a (PyObject *)? - Campbell */
-               if (mat->GetFlag() & RAS_BLENDERMAT) {
-                       KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat);
-                       bmat= bl_mat->GetBlenderMaterial();
-
-               } else {
-                       KX_PolygonMaterial *kx_mat = static_cast<KX_PolygonMaterial*>(mat);
-                       bmat= kx_mat->GetBlenderMaterial();
-               }
+               KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial *>(mat);
+               bmat = bl_mat->GetBlenderMaterial();
 
                if (IS_TAGGED(bmat)) {
                        /* only remove from bucket */
-                       ((*polymit).first)->GetBucketManager()->RemoveMaterial(mat);
+                       polymit->first->GetBucketManager()->RemoveMaterial(mat);
                }
 
                i++;
                polymit++;
        }
 
+       for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
+               RAS_IPolyMaterial *mat = polymit->second;
+               Material *bmat = NULL;
 
-
-       for (i=0, polymit=m_polymaterials.begin(); i<size; ) {
-               RAS_IPolyMaterial *mat= (*polymit).second;
-               Material *bmat= NULL;
-
-               /* Why do we need to check for RAS_BLENDERMAT if both are cast to a (PyObject *)? - Campbell */
-               if (mat->GetFlag() & RAS_BLENDERMAT) {
-                       KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat);
-                       bmat= bl_mat->GetBlenderMaterial();
-
-               } else {
-                       KX_PolygonMaterial *kx_mat = static_cast<KX_PolygonMaterial*>(mat);
-                       bmat= kx_mat->GetBlenderMaterial();
-               }
-
-               if (bmat) {
-                       //printf("FOUND MAT '%s' !!! ", ((ID*)bmat)->name+2);
-               }
-               else {
-                       //printf("LOST MAT  !!!");
-               }
+               KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat);
+               bmat = bl_mat->GetBlenderMaterial();
 
                if (IS_TAGGED(bmat)) {
-                       delete (*polymit).second;
+                       // Remove the poly material coresponding to this Blender Material.
+                       m_polymat_cache[polymit->first].erase(bmat);
+                       delete polymit->second;
                        *polymit = m_polymaterials.back();
                        m_polymaterials.pop_back();
                        size--;
-                       //printf("tagged !\n");
                } else {
                        i++;
                        polymit++;
-                       //printf("(un)tagged !\n");
                }
        }
 
-       vector<pair<KX_Scene*,BL_Material*> >::iterator matit;
+       vector<pair<KX_Scene *, BL_Material *> >::iterator matit;
        size = m_materials.size();
-       for (i=0, matit=m_materials.begin(); i<size; ) {
-               BL_Material *mat= (*matit).second;
+       for (i = 0, matit = m_materials.begin(); i < size; ) {
+               BL_Material *mat = matit->second;
                if (IS_TAGGED(mat->material)) {
-                       delete (*matit).second;
+                       // Remove the bl material coresponding to this Blender Material.
+                       m_mat_cache[matit->first].erase(mat->material);
+                       delete matit->second;
                        *matit = m_materials.back();
                        m_materials.pop_back();
                        size--;
-               } else {
+               } 
+               else {
                        i++;
                        matit++;
                }
        }
 
-       vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator meshit;
+       vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator meshit;
+       RAS_BucketManager::BucketList::iterator bit;
+       list<RAS_MeshSlot>::iterator msit;
+       RAS_BucketManager::BucketList buckets;
+
        size = m_meshobjects.size();
-       for (i=0, meshit=m_meshobjects.begin(); i<size; ) {
-               RAS_MeshObject *me= (*meshit).second;
+       for (i = 0, meshit = m_meshobjects.begin(); i < size;) {
+               RAS_MeshObject *me = meshit->second;
                if (IS_TAGGED(me->GetMesh())) {
-                       delete (*meshit).second;
+                       // Before deleting the mesh object, make sure the rasterizer is
+                       // no longer referencing it.
+                       buckets = meshit->first->GetBucketManager()->GetSolidBuckets();
+                       for (bit = buckets.begin(); bit != buckets.end(); bit++) {
+                               msit = (*bit)->msBegin();
+
+                               while (msit != (*bit)->msEnd()) {
+                                       if (msit->m_mesh == meshit->second)
+                                               (*bit)->RemoveMesh(&(*msit++));
+                                       else
+                                               msit++;
+                               }
+                       }
+
+                       // And now the alpha buckets
+                       buckets = meshit->first->GetBucketManager()->GetAlphaBuckets();
+                       for (bit = buckets.begin(); bit != buckets.end(); bit++) {
+                               msit = (*bit)->msBegin();
+
+                               while (msit != (*bit)->msEnd()) {
+                                       if (msit->m_mesh == meshit->second)
+                                               (*bit)->RemoveMesh(&(*msit++));
+                                       else
+                                               msit++;
+                               }
+                       }
+
+                       // Now it should be safe to delete
+                       delete meshit->second;
                        *meshit = m_meshobjects.back();
                        m_meshobjects.pop_back();
                        size--;
-               } else {
+               } 
+               else {
                        i++;
                        meshit++;
                }
@@ -1513,7 +1324,7 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
        delete m_status_map[maggie->name];
        m_status_map.erase(maggie->name);
 
-       free_main(maggie);
+       BKE_main_free(maggie);
 
        return true;
 }
@@ -1525,24 +1336,23 @@ bool KX_BlenderSceneConverter::FreeBlendFile(const char *path)
 
 bool KX_BlenderSceneConverter::MergeScene(KX_Scene *to, KX_Scene *from)
 {
-
        {
-               vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator itp = m_worldinfos.begin();
+               vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator itp = m_worldinfos.begin();
                while (itp != m_worldinfos.end()) {
-                       if ((*itp).first==from)
-                               (*itp).first= to;
+                       if (itp->first == from)
+                               itp->first = to;
                        itp++;
                }
        }
 
        {
-               vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator itp = m_polymaterials.begin();
+               vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator itp = m_polymaterials.begin();
                while (itp != m_polymaterials.end()) {
-                       if ((*itp).first==from) {
-                               (*itp).first= to;
+                       if (itp->first == from) {
+                               itp->first = to;
 
                                /* also switch internal data */
-                               RAS_IPolyMaterial*mat= (*itp).second;
+                               RAS_IPolyMaterial *mat = itp->second;
                                mat->Replace_IScene(to);
                        }
                        itp++;
@@ -1550,87 +1360,116 @@ bool KX_BlenderSceneConverter::MergeScene(KX_Scene *to, KX_Scene *from)
        }
 
        {
-               vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator itp = m_meshobjects.begin();
+               vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator itp = m_meshobjects.begin();
                while (itp != m_meshobjects.end()) {
-                       if ((*itp).first==from)
-                               (*itp).first= to;
+                       if (itp->first == from)
+                               itp->first = to;
                        itp++;
                }
        }
 
        {
-               vector<pair<KX_Scene*,BL_Material*> >::iterator itp = m_materials.begin();
+               vector<pair<KX_Scene *, BL_Material *> >::iterator itp = m_materials.begin();
                while (itp != m_materials.end()) {
-                       if ((*itp).first==from)
-                               (*itp).first= to;
+                       if (itp->first == from)
+                               itp->first = to;
                        itp++;
                }
        }
-       
+
+       MaterialCache::iterator matcacheit = m_mat_cache.find(from);
+       if (matcacheit != m_mat_cache.end()) {
+               // Merge cached BL_Material map.
+               m_mat_cache[to].insert(matcacheit->second.begin(), matcacheit->second.end());
+               m_mat_cache.erase(matcacheit);
+       }
+
+       PolyMaterialCache::iterator polymatcacheit = m_polymat_cache.find(from);
+       if (polymatcacheit != m_polymat_cache.end()) {
+               // Merge cached RAS_IPolyMaterial map.
+               m_polymat_cache[to].insert(polymatcacheit->second.begin(), polymatcacheit->second.end());
+               m_polymat_cache.erase(polymatcacheit);
+       }
+
        return true;
 }
 
 /* This function merges a mesh from the current scene into another main
  * it does not convert */
-RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scenekx_scene, Main *maggie, const char *name)
+RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, const char *name)
 {
        /* Find a mesh in the current main */
        ID *me= static_cast<ID *>(BLI_findstring(&m_maggie->mesh, name, offsetof(ID, name) + 2));
-       
-       if (me==NULL) {
+       Main *from_maggie = m_maggie;
+
+       if (me == NULL) {
+               // The mesh wasn't in the current main, try any dynamic (i.e., LibLoaded) ones
+               vector<Main *>::iterator it;
+
+               for (it = GetMainDynamic().begin(); it != GetMainDynamic().end(); it++) {
+                       me = static_cast<ID *>(BLI_findstring(&(*it)->mesh, name, offsetof(ID, name) + 2));
+                       from_maggie = *it;
+
+                       if (me)
+                               break;
+               }
+       }
+
+       if (me == NULL) {
                printf("Could not be found \"%s\"\n", name);
                return NULL;
        }
-       
+
        /* Watch this!, if its used in the original scene can cause big troubles */
        if (me->us > 0) {
+#ifdef DEBUG
                printf("Mesh has a user \"%s\"\n", name);
-               me = (ID*)BKE_mesh_copy((Mesh*)me);
-               me->us--;
+#endif
+               me = (ID*)BKE_mesh_copy(from_maggie, (Mesh*)me);
+               id_us_min(me);
        }
-       BLI_remlink(&m_maggie->mesh, me); /* even if we made the copy it needs to be removed */
+       BLI_remlink(&from_maggie->mesh, me); /* even if we made the copy it needs to be removed */
        BLI_addtail(&maggie->mesh, me);
 
-       
        /* Must copy the materials this uses else we cant free them */
        {
-               Mesh *mesh= (Mesh *)me;
-               
+               Mesh *mesh = (Mesh *)me;
+
                /* ensure all materials are tagged */
-               for (int i=0; i<mesh->totcol; i++)
+               for (int i = 0; i < mesh->totcol; i++) {
                        if (mesh->mat[i])
-                               mesh->mat[i]->id.flag &= ~LIB_DOIT;
-               
-               for (int i=0; i<mesh->totcol; i++)
-               {
-                       Material *mat_old= mesh->mat[i];
-                       
+                               mesh->mat[i]->id.tag &= ~LIB_TAG_DOIT;
+               }
+
+               for (int i = 0; i < mesh->totcol; i++) {
+                       Material *mat_old = mesh->mat[i];
+
                        /* if its tagged its a replaced material */
-                       if (mat_old && (mat_old->id.flag & LIB_DOIT)==0)
-                       {
-                               Material *mat_old= mesh->mat[i];
-                               Material *mat_new= BKE_material_copy( mat_old );
-                               
-                               mat_new->id.flag |= LIB_DOIT;
-                               mat_old->id.us--;
-                               
-                               BLI_remlink(&m_maggie->mat, mat_new);
+                       if (mat_old && (mat_old->id.tag & LIB_TAG_DOIT) == 0) {
+                               Material *mat_old = mesh->mat[i];
+                               Material *mat_new = BKE_material_copy(from_maggie, mat_old);
+
+                               mat_new->id.tag |= LIB_TAG_DOIT;
+                               id_us_min(&mat_old->id);
+
+                               BLI_remlink(&from_maggie->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex
                                BLI_addtail(&maggie->mat, mat_new);
-                               
+
                                mesh->mat[i] = mat_new;
-                               
+
                                /* the same material may be used twice */
                                for (int j = i + 1; j < mesh->totcol; j++) {
                                        if (mesh->mat[j] == mat_old) {
                                                mesh->mat[j] = mat_new;
-                                               mat_new->id.us++;
-                                               mat_old->id.us--;
+                                               id_us_plus(&mat_new->id);
+                                               id_us_min(&mat_old->id);
                                        }
                                }
                        }
                }
        }
-       
+
+       m_currentScene = kx_scene; // This needs to be set in case we LibLoaded earlier
        RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)me, NULL, kx_scene, this, false);
        kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
        m_map_mesh_to_gamemesh.clear(); /* This is at runtime so no need to keep this, BL_ConvertMesh adds */