Cleanup in BLO API: rename 'append' funcs to 'link', since none do append, but only...
[blender.git] / source / gameengine / Converter / KX_BlenderSceneConverter.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file gameengine/Converter/KX_BlenderSceneConverter.cpp
29  *  \ingroup bgeconv
30  */
31
32 #ifdef _MSC_VER
33 #  pragma warning (disable:4786)  /* suppress stl-MSVC debug info warning */
34 #endif
35
36 #include "KX_Scene.h"
37 #include "KX_GameObject.h"
38 #include "KX_IpoConvert.h"
39 #include "RAS_MeshObject.h"
40 #include "KX_PhysicsEngineEnums.h"
41 #include "PHY_IPhysicsEnvironment.h"
42 #include "KX_KetsjiEngine.h"
43 #include "KX_PythonInit.h" // So we can handle adding new text datablocks for Python to import
44 #include "BL_Material.h"
45 #include "BL_ActionActuator.h"
46 #include "KX_BlenderMaterial.h"
47
48
49 #include "BL_System.h"
50
51 #include "DummyPhysicsEnvironment.h"
52
53
54 #ifdef WITH_BULLET
55 #include "CcdPhysicsEnvironment.h"
56 #endif
57
58 #include "KX_LibLoadStatus.h"
59 #include "KX_BlenderScalarInterpolator.h"
60 #include "BL_BlenderDataConversion.h"
61 #include "KX_WorldInfo.h"
62
63 /* This little block needed for linking to Blender... */
64 #ifdef WIN32
65 #include "BLI_winstuff.h"
66 #endif
67
68 /* This list includes only data type definitions */
69 #include "DNA_scene_types.h"
70 #include "DNA_world_types.h"
71 #include "BKE_main.h"
72 #include "BKE_fcurve.h"
73
74 #include "BLI_math.h"
75
76 extern "C"
77 {
78 #include "DNA_object_types.h"
79 #include "DNA_curve_types.h"
80 #include "DNA_mesh_types.h"
81 #include "DNA_material_types.h"
82 #include "BLI_blenlib.h"
83 #include "MEM_guardedalloc.h"
84 #include "BKE_global.h"
85 #include "BKE_animsys.h"
86 #include "BKE_library.h"
87 #include "BKE_material.h" // BKE_material_copy
88 #include "BKE_mesh.h" // BKE_mesh_copy
89 #include "DNA_space_types.h"
90 #include "DNA_anim_types.h"
91 #include "DNA_action_types.h"
92 #include "RNA_define.h"
93 #include "../../blender/editors/include/ED_keyframing.h"
94 }
95
96 /* Only for dynamic loading and merging */
97 #include "RAS_BucketManager.h" // XXX cant stay
98 #include "KX_BlenderSceneConverter.h"
99 #include "KX_MeshProxy.h"
100 extern "C" {
101         #include "PIL_time.h"
102         #include "BKE_context.h"
103         #include "BLO_readfile.h"
104         #include "BKE_idcode.h"
105         #include "BKE_report.h"
106         #include "DNA_space_types.h"
107         #include "DNA_windowmanager_types.h" /* report api */
108         #include "../../blender/blenlib/BLI_linklist.h"
109 }
110
111 #include "BLI_task.h"
112
113 // This is used to avoid including BLI_task.h in KX_BlenderSceneConverter.h
114 typedef struct ThreadInfo {
115         TaskPool *m_pool;
116         ThreadMutex m_mutex;
117 } ThreadInfo;
118
119 KX_BlenderSceneConverter::KX_BlenderSceneConverter(
120                                                         Main *maggie,
121                                                         KX_KetsjiEngine *engine)
122                                                         :m_maggie(maggie),
123                                                         m_ketsjiEngine(engine),
124                                                         m_alwaysUseExpandFraming(false),
125                                                         m_usemat(false),
126                                                         m_useglslmat(false),
127                                                         m_use_mat_cache(true)
128 {
129         BKE_main_id_tag_all(maggie, false);  /* avoid re-tagging later on */
130         m_newfilename = "";
131         m_threadinfo = new ThreadInfo();
132         m_threadinfo->m_pool = BLI_task_pool_create(engine->GetTaskScheduler(), NULL);
133         BLI_mutex_init(&m_threadinfo->m_mutex);
134 }
135
136 KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
137 {
138         // clears meshes, and hashmaps from blender to gameengine data
139         // delete sumoshapes
140
141         if (m_threadinfo) {
142                 BLI_task_pool_work_and_wait(m_threadinfo->m_pool);
143                 BLI_task_pool_free(m_threadinfo->m_pool);
144
145                 BLI_mutex_end(&m_threadinfo->m_mutex);
146                 delete m_threadinfo;
147         }
148
149         int numAdtLists = m_map_blender_to_gameAdtList.size();
150         for (int i = 0; i < numAdtLists; i++) {
151                 BL_InterpolatorList *adtList = *m_map_blender_to_gameAdtList.at(i);
152
153                 delete (adtList);
154         }
155
156         vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator itw = m_worldinfos.begin();
157         while (itw != m_worldinfos.end()) {
158                 delete itw->second;
159                 itw++;
160         }
161         m_worldinfos.clear();
162
163         vector<pair<KX_Scene *,RAS_IPolyMaterial *> >::iterator itp = m_polymaterials.begin();
164         while (itp != m_polymaterials.end()) {
165                 delete itp->second;
166                 itp++;
167         }
168         m_polymaterials.clear();
169
170         // delete after RAS_IPolyMaterial
171         vector<pair<KX_Scene *,BL_Material *> >::iterator itmat = m_materials.begin();
172         while (itmat != m_materials.end()) {
173                 delete itmat->second;
174                 itmat++;
175         }
176         m_materials.clear();
177
178         vector<pair<KX_Scene *,RAS_MeshObject *> >::iterator itm = m_meshobjects.begin();
179         while (itm != m_meshobjects.end()) {
180                 delete itm->second;
181                 itm++;
182         }
183         m_meshobjects.clear();
184
185         /* free any data that was dynamically loaded */
186         while (m_DynamicMaggie.size() != 0) {
187                 FreeBlendFile(m_DynamicMaggie[0]);
188         }
189
190         m_DynamicMaggie.clear();
191 }
192
193 void KX_BlenderSceneConverter::SetNewFileName(const STR_String &filename)
194 {
195         m_newfilename = filename;
196 }
197
198 bool KX_BlenderSceneConverter::TryAndLoadNewFile()
199 {
200         bool result = false;
201
202         return result;
203 }
204
205 Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String &name)
206 {
207         Scene *sce;
208
209         /**
210          * Find the specified scene by name, or NULL if nothing matches.
211          */
212         if ((sce = (Scene *)BLI_findstring(&m_maggie->scene, name.ReadPtr(), offsetof(ID, name) + 2)))
213                 return sce;
214
215         for (vector<Main *>::iterator it=m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
216                 Main *main = *it;
217
218                 if ((sce= (Scene *)BLI_findstring(&main->scene, name.ReadPtr(), offsetof(ID, name) + 2)))
219                         return sce;
220         }
221
222         return NULL;
223 }
224
225 void KX_BlenderSceneConverter::ConvertScene(KX_Scene *destinationscene, RAS_IRasterizer *rendertools,
226                                                                                         RAS_ICanvas *canvas, bool libloading)
227 {
228         //find out which physics engine
229         Scene *blenderscene = destinationscene->GetBlenderScene();
230
231         PHY_IPhysicsEnvironment *phy_env = NULL;
232
233         e_PhysicsEngine physics_engine = UseBullet;
234         // hook for registration function during conversion.
235         m_currentScene = destinationscene;
236         destinationscene->SetSceneConverter(this);
237
238         // This doesn't really seem to do anything except cause potential issues
239         // when doing threaded conversion, so it's disabled for now.
240         // SG_SetActiveStage(SG_STAGE_CONVERTER);
241
242         switch (blenderscene->gm.physicsEngine) {
243 #ifdef WITH_BULLET
244         case WOPHY_BULLET:
245                 {
246                         SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/
247                         int visualizePhysics = SYS_GetCommandLineInt(syshandle, "show_physics", 0);
248
249                         phy_env = CcdPhysicsEnvironment::Create(blenderscene, visualizePhysics);
250                         physics_engine = UseBullet;
251                         break;
252                 }
253 #endif
254         default:
255         case WOPHY_NONE:
256                 {
257                         // We should probably use some sort of factory here
258                         phy_env = new DummyPhysicsEnvironment();
259                         physics_engine = UseNone;
260                         break;
261                 }
262         }
263
264         destinationscene->SetPhysicsEnvironment(phy_env);
265
266         BL_ConvertBlenderObjects(
267                 m_maggie,
268                 destinationscene,
269                 m_ketsjiEngine,
270                 physics_engine,
271                 rendertools,
272                 canvas,
273                 this,
274                 m_alwaysUseExpandFraming,
275                 libloading);
276
277         //These lookup are not needed during game
278         m_map_blender_to_gameactuator.clear();
279         m_map_blender_to_gamecontroller.clear();
280         m_map_blender_to_gameobject.clear();
281
282         //Clearing this lookup table has the effect of disabling the cache of meshes
283         //between scenes, even if they are shared in the blend file.
284         //This cache mecanism is buggy so I leave it disable and the memory leak
285         //that would result from this is fixed in RemoveScene()
286         m_map_mesh_to_gamemesh.clear();
287 }
288
289 // This function removes all entities stored in the converter for that scene
290 // It should be used instead of direct delete scene
291 // Note that there was some provision for sharing entities (meshes...) between
292 // scenes but that is now disabled so all scene will have their own copy
293 // and we can delete them here. If the sharing is reactivated, change this code too..
294 // (see KX_BlenderSceneConverter::ConvertScene)
295 void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene)
296 {
297         int i, size;
298         // delete the scene first as it will stop the use of entities
299         delete scene;
300         // delete the entities of this scene
301         vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator worldit;
302         size = m_worldinfos.size();
303         for (i = 0, worldit = m_worldinfos.begin(); i < size; ) {
304                 if (worldit->first == scene) {
305                         delete worldit->second;
306                         *worldit = m_worldinfos.back();
307                         m_worldinfos.pop_back();
308                         size--;
309                 } 
310                 else {
311                         i++;
312                         worldit++;
313                 }
314         }
315
316         vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator polymit;
317         size = m_polymaterials.size();
318         for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
319                 if (polymit->first == scene) {
320                         m_polymat_cache[scene].erase(polymit->second->GetBlenderMaterial());
321                         delete polymit->second;
322                         *polymit = m_polymaterials.back();
323                         m_polymaterials.pop_back();
324                         size--;
325                 } 
326                 else {
327                         i++;
328                         polymit++;
329                 }
330         }
331
332         m_polymat_cache.erase(scene);
333
334         vector<pair<KX_Scene *, BL_Material *> >::iterator matit;
335         size = m_materials.size();
336         for (i = 0, matit = m_materials.begin(); i < size; ) {
337                 if (matit->first == scene) {
338                         m_mat_cache[scene].erase(matit->second->material);
339                         delete matit->second;
340                         *matit = m_materials.back();
341                         m_materials.pop_back();
342                         size--;
343                 } 
344                 else {
345                         i++;
346                         matit++;
347                 }
348         }
349
350         m_mat_cache.erase(scene);
351
352         vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator meshit;
353         size = m_meshobjects.size();
354         for (i = 0, meshit = m_meshobjects.begin(); i < size; ) {
355                 if (meshit->first == scene) {
356                         delete meshit->second;
357                         *meshit = m_meshobjects.back();
358                         m_meshobjects.pop_back();
359                         size--;
360                 } 
361                 else {
362                         i++;
363                         meshit++;
364                 }
365         }
366 }
367
368 // use blender materials
369 void KX_BlenderSceneConverter::SetMaterials(bool val)
370 {
371         m_usemat = val;
372         m_useglslmat = false;
373 }
374
375 void KX_BlenderSceneConverter::SetGLSLMaterials(bool val)
376 {
377         m_usemat = val;
378         m_useglslmat = val;
379 }
380
381 void KX_BlenderSceneConverter::SetCacheMaterials(bool val)
382 {
383         m_use_mat_cache = val;
384 }
385
386 bool KX_BlenderSceneConverter::GetMaterials()
387 {
388         return m_usemat;
389 }
390
391 bool KX_BlenderSceneConverter::GetGLSLMaterials()
392 {
393         return m_useglslmat;
394 }
395
396 bool KX_BlenderSceneConverter::GetCacheMaterials()
397 {
398         return m_use_mat_cache;
399 }
400
401 void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat)
402 {
403         // First make sure we don't register the material twice
404         vector<pair<KX_Scene *, BL_Material *> >::iterator it;
405         for (it = m_materials.begin(); it != m_materials.end(); ++it)
406                 if (it->second == mat)
407                         return;
408
409         m_materials.push_back(pair<KX_Scene *, BL_Material *> (m_currentScene, mat));
410 }
411
412 void KX_BlenderSceneConverter::SetAlwaysUseExpandFraming(bool to_what)
413 {
414         m_alwaysUseExpandFraming= to_what;
415 }
416
417 void KX_BlenderSceneConverter::RegisterGameObject(KX_GameObject *gameobject, Object *for_blenderobject) 
418 {
419         /* only maintained while converting, freed during game runtime */
420         m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject), gameobject);
421 }
422
423 /* only need to run this during conversion since
424  * m_map_blender_to_gameobject is freed after conversion */
425 void KX_BlenderSceneConverter::UnregisterGameObject(KX_GameObject *gameobject) 
426 {
427         Object *bobp = gameobject->GetBlenderObject();
428         if (bobp) {
429                 CHashedPtr bptr(bobp);
430                 KX_GameObject **gobp = m_map_blender_to_gameobject[bptr];
431                 if (gobp && *gobp == gameobject) {
432                         // also maintain m_map_blender_to_gameobject if the gameobject
433                         // being removed is matching the blender object
434                         m_map_blender_to_gameobject.remove(bptr);
435                 }
436         }
437 }
438
439 KX_GameObject *KX_BlenderSceneConverter::FindGameObject(Object *for_blenderobject) 
440 {
441         KX_GameObject **obp = m_map_blender_to_gameobject[CHashedPtr(for_blenderobject)];
442
443         return obp ? *obp : NULL;
444 }
445
446 void KX_BlenderSceneConverter::RegisterGameMesh(RAS_MeshObject *gamemesh, Mesh *for_blendermesh)
447 {
448         if (for_blendermesh) { /* dynamically loaded meshes we don't want to keep lookups for */
449                 m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh);
450         }
451         m_meshobjects.push_back(pair<KX_Scene *, RAS_MeshObject *> (m_currentScene,gamemesh));
452 }
453
454 RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh(Mesh *for_blendermesh)
455 {
456         RAS_MeshObject **meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)];
457
458         if (meshp) {
459                 return *meshp;
460         } 
461         else {
462                 return NULL;
463         }
464 }
465
466 void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat)
467 {
468         // First make sure we don't register the material twice
469         vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator it;
470         for (it = m_polymaterials.begin(); it != m_polymaterials.end(); ++it)
471                 if (it->second == polymat)
472                         return;
473         m_polymaterials.push_back(pair<KX_Scene *, RAS_IPolyMaterial *> (m_currentScene, polymat));
474 }
475
476 void KX_BlenderSceneConverter::CachePolyMaterial(KX_Scene *scene, Material *mat, RAS_IPolyMaterial *polymat)
477 {
478         if (m_use_mat_cache && mat)
479                 m_polymat_cache[scene][mat] = polymat;
480 }
481
482 RAS_IPolyMaterial *KX_BlenderSceneConverter::FindCachedPolyMaterial(KX_Scene *scene, Material *mat)
483 {
484         return (m_use_mat_cache) ? m_polymat_cache[scene][mat] : NULL;
485 }
486
487 void KX_BlenderSceneConverter::CacheBlenderMaterial(KX_Scene *scene, Material *mat, BL_Material *blmat)
488 {
489         if (m_use_mat_cache && mat)
490                 m_mat_cache[scene][mat] = blmat;
491 }
492
493 BL_Material *KX_BlenderSceneConverter::FindCachedBlenderMaterial(KX_Scene *scene, Material *mat)
494 {
495         return (m_use_mat_cache) ? m_mat_cache[scene][mat] : NULL;
496 }
497
498 void KX_BlenderSceneConverter::RegisterInterpolatorList(BL_InterpolatorList *actList, bAction *for_act)
499 {
500         m_map_blender_to_gameAdtList.insert(CHashedPtr(for_act), actList);
501 }
502
503 BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList(bAction *for_act)
504 {
505         BL_InterpolatorList **listp = m_map_blender_to_gameAdtList[CHashedPtr(for_act)];
506         return listp ? *listp : NULL;
507 }
508
509 void KX_BlenderSceneConverter::RegisterGameActuator(SCA_IActuator *act, bActuator *for_actuator)
510 {
511         m_map_blender_to_gameactuator.insert(CHashedPtr(for_actuator), act);
512 }
513
514 SCA_IActuator *KX_BlenderSceneConverter::FindGameActuator(bActuator *for_actuator)
515 {
516         SCA_IActuator **actp = m_map_blender_to_gameactuator[CHashedPtr(for_actuator)];
517         return actp ? *actp : NULL;
518 }
519
520 void KX_BlenderSceneConverter::RegisterGameController(SCA_IController *cont, bController *for_controller)
521 {
522         m_map_blender_to_gamecontroller.insert(CHashedPtr(for_controller), cont);
523 }
524
525 SCA_IController *KX_BlenderSceneConverter::FindGameController(bController *for_controller)
526 {
527         SCA_IController **contp = m_map_blender_to_gamecontroller[CHashedPtr(for_controller)];
528         return contp ? *contp : NULL;
529 }
530
531 void KX_BlenderSceneConverter::RegisterWorldInfo(KX_WorldInfo *worldinfo)
532 {
533         m_worldinfos.push_back(pair<KX_Scene *, KX_WorldInfo *> (m_currentScene, worldinfo));
534 }
535
536 void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo)
537 {
538         //TODO this entire function is deprecated, written for 2.4x
539         //the functionality should be rewritten, currently it does nothing
540
541         KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
542         int numScenes = scenes->size();
543         int i;
544         for (i = 0; i < numScenes; i++) {
545                 KX_Scene *scene = scenes->at(i);
546                 CListValue *parentList = scene->GetRootParentList();
547                 int numObjects = parentList->GetCount();
548                 int g;
549                 for (g = 0; g < numObjects; g++) {
550                         KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
551                         if (gameObj->IsRecordAnimation()) {
552                                 Object *blenderObject = gameObj->GetBlenderObject();
553                                 if (blenderObject) {
554 #if 0
555                                         //erase existing ipo's
556                                         Ipo* ipo = blenderObject->ipo;//findIpoForName(blenderObject->id.name+2);
557                                         if (ipo) {      //clear the curve data
558                                                 if (clearIpo) {//rcruiz
559                                                         IpoCurve *icu1;
560
561                                                         int numCurves = 0;
562                                                         for ( icu1 = (IpoCurve*)ipo->curve.first; icu1;  ) {
563
564                                                                 IpoCurve* tmpicu = icu1;
565
566                                                                 /*int i;
567                                                                 BezTriple *bezt;
568                                                                 for ( bezt = tmpicu->bezt, i = 0;       i < tmpicu->totvert; i++, bezt++) {
569                                                                         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]);
570                                                                 }*/
571
572                                                                 icu1 = icu1->next;
573                                                                 numCurves++;
574
575                                                                 BLI_remlink( &( blenderObject->ipo->curve ), tmpicu );
576                                                                 if ( tmpicu->bezt )
577                                                                         MEM_freeN( tmpicu->bezt );
578                                                                 MEM_freeN( tmpicu );
579                                                                 localDel_ipoCurve( tmpicu );
580                                                         }
581                                                 }
582                                         } 
583                                         else {
584                                                 ipo = NULL; // XXX add_ipo(blenderObject->id.name+2, ID_OB);
585                                                 blenderObject->ipo = ipo;
586                                         }
587 #endif
588                                 }
589                         }
590                 }
591         }
592 }
593
594 void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo()
595 {
596         //TODO the functionality should be rewritten
597 }
598
599 // this generates ipo curves for position, rotation, allowing to use game physics in animation
600 void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
601 {
602         KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
603         int numScenes = scenes->size();
604         int i;
605         for (i = 0; i < numScenes; i++) {
606                 KX_Scene *scene = scenes->at(i);
607                 //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
608                 CListValue *parentList = scene->GetObjectList();
609                 int numObjects = parentList->GetCount();
610                 int g;
611                 for (g = 0; g < numObjects; g++) {
612                         KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
613                         Object *blenderObject = gameObj->GetBlenderObject();
614                         if (blenderObject && blenderObject->parent == NULL && gameObj->IsRecordAnimation()) {
615                                 if (blenderObject->adt == NULL)
616                                         BKE_animdata_add_id(&blenderObject->id);
617
618                                 if (blenderObject->adt) {
619                                         const MT_Point3 &position = gameObj->NodeGetWorldPosition();
620                                         //const MT_Vector3& scale = gameObj->NodeGetWorldScaling();
621                                         const MT_Matrix3x3 &orn = gameObj->NodeGetWorldOrientation();
622
623                                         position.getValue(blenderObject->loc);
624
625                                         float tmat[3][3];
626                                         for (int r = 0; r < 3; r++)
627                                                 for (int c = 0; c < 3; c++)
628                                                         tmat[r][c] = (float)orn[c][r];
629
630                                         mat3_to_compatible_eul(blenderObject->rot, blenderObject->rot, tmat);
631
632                                         insert_keyframe(NULL, &blenderObject->id, NULL, NULL, "location", -1, (float)frameNumber, INSERTKEY_FAST);
633                                         insert_keyframe(NULL, &blenderObject->id, NULL, NULL, "rotation_euler", -1, (float)frameNumber, INSERTKEY_FAST);
634
635 #if 0
636                                         const MT_Point3& position = gameObj->NodeGetWorldPosition();
637                                         //const MT_Vector3& scale = gameObj->NodeGetWorldScaling();
638                                         const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation();
639                                         
640                                         float eulerAngles[3];
641                                         float eulerAnglesOld[3] = {0.0f, 0.0f, 0.0f};
642                                         float tmat[3][3];
643                                         
644                                         // XXX animato
645                                         Ipo* ipo = blenderObject->ipo;
646
647                                         //create the curves, if not existing, set linear if new
648
649                                         IpoCurve *icu_lx = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX");
650                                         if (!icu_lx) {
651                                                 icu_lx = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1);
652                                                 if (icu_lx) icu_lx->ipo = IPO_LIN;
653                                         }
654                                         IpoCurve *icu_ly = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY");
655                                         if (!icu_ly) {
656                                                 icu_ly = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1);
657                                                 if (icu_ly) icu_ly->ipo = IPO_LIN;
658                                         }
659                                         IpoCurve *icu_lz = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ");
660                                         if (!icu_lz) {
661                                                 icu_lz = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1);
662                                                 if (icu_lz) icu_lz->ipo = IPO_LIN;
663                                         }
664                                         IpoCurve *icu_rx = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX");
665                                         if (!icu_rx) {
666                                                 icu_rx = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1);
667                                                 if (icu_rx) icu_rx->ipo = IPO_LIN;
668                                         }
669                                         IpoCurve *icu_ry = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY");
670                                         if (!icu_ry) {
671                                                 icu_ry = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1);
672                                                 if (icu_ry) icu_ry->ipo = IPO_LIN;
673                                         }
674                                         IpoCurve *icu_rz = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ");
675                                         if (!icu_rz) {
676                                                 icu_rz = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1);
677                                                 if (icu_rz) icu_rz->ipo = IPO_LIN;
678                                         }
679                                         
680                                         if (icu_rx) eulerAnglesOld[0] = eval_icu( icu_rx, frameNumber - 1 ) / ((180 / 3.14159265f) / 10);
681                                         if (icu_ry) eulerAnglesOld[1] = eval_icu( icu_ry, frameNumber - 1 ) / ((180 / 3.14159265f) / 10);
682                                         if (icu_rz) eulerAnglesOld[2] = eval_icu( icu_rz, frameNumber - 1 ) / ((180 / 3.14159265f) / 10);
683                                         
684                                         // orn.getValue((float *)tmat); // uses the wrong ordering, cant use this
685                                         for (int r = 0; r < 3; r++)
686                                                 for (int c = 0; c < 3; c++)
687                                                         tmat[r][c] = orn[c][r];
688                                         
689                                         // mat3_to_eul( eulerAngles,tmat); // better to use Mat3ToCompatibleEul
690                                         mat3_to_compatible_eul( eulerAngles, eulerAnglesOld,tmat);
691                                         
692                                         //eval_icu
693                                         for (int x = 0; x < 3; x++)
694                                                 eulerAngles[x] *= (float) ((180 / 3.14159265f) / 10.0);
695                                         
696                                         //fill the curves with data
697                                         if (icu_lx) insert_vert_icu(icu_lx, frameNumber, position.x(), 1);
698                                         if (icu_ly) insert_vert_icu(icu_ly, frameNumber, position.y(), 1);
699                                         if (icu_lz) insert_vert_icu(icu_lz, frameNumber, position.z(), 1);
700                                         if (icu_rx) insert_vert_icu(icu_rx, frameNumber, eulerAngles[0], 1);
701                                         if (icu_ry) insert_vert_icu(icu_ry, frameNumber, eulerAngles[1], 1);
702                                         if (icu_rz) insert_vert_icu(icu_rz, frameNumber, eulerAngles[2], 1);
703                                         
704                                         // Handles are corrected at the end, testhandles_ipocurve isn't needed yet
705 #endif
706                                 }
707                         }
708                 }
709         }
710 }
711
712 void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo()
713 {
714         KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
715         int numScenes = scenes->size();
716         int i;
717         for (i = 0; i < numScenes; i++) {
718                 KX_Scene *scene = scenes->at(i);
719                 //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
720                 CListValue *parentList = scene->GetRootParentList();
721                 int numObjects = parentList->GetCount();
722                 int g;
723                 for (g = 0; g < numObjects; g++) {
724                         KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
725                         if (gameObj->IsRecordAnimation()) {
726                                 Object *blenderObject = gameObj->GetBlenderObject();
727                                 if (blenderObject && blenderObject->adt) {
728                                         bAction *act = verify_adt_action(&blenderObject->id, false);
729                                         FCurve *fcu;
730
731                                         if (!act) {
732                                                 continue;
733                                         }
734
735                                         /* for now, not much choice but to run this on all curves... */
736                                         for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
737                                                 /* Note: calling `sort_time_fcurve()` here is not needed, since
738                                                  *       all keys have been added in 'right' order. */
739                                                 calchandles_fcurve(fcu);
740                                         }
741 #if 0
742                                         // XXX animato
743                                         Ipo* ipo = blenderObject->ipo;
744
745                                         //create the curves, if not existing
746                                         //testhandles_ipocurve checks for NULL
747                                         testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"));
748                                         testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"));
749                                         testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"));
750                                         testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"));
751                                         testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"));
752                                         testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"));
753 #endif
754                                 }
755                         }
756                 }
757         }
758 }
759
760 #ifdef WITH_PYTHON
761 PyObject *KX_BlenderSceneConverter::GetPyNamespace()
762 {
763         return m_ketsjiEngine->GetPyNamespace();
764 }
765 #endif
766
767 vector<Main *> &KX_BlenderSceneConverter::GetMainDynamic()
768 {
769         return m_DynamicMaggie;
770 }
771
772 Main *KX_BlenderSceneConverter::GetMainDynamicPath(const char *path)
773 {
774         for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++)
775                 if (BLI_path_cmp((*it)->name, path) == 0)
776                         return *it;
777         
778         return NULL;
779 }
780
781 void KX_BlenderSceneConverter::MergeAsyncLoads()
782 {
783         vector<KX_Scene *> *merge_scenes;
784
785         vector<KX_LibLoadStatus *>::iterator mit;
786         vector<KX_Scene *>::iterator sit;
787
788         BLI_mutex_lock(&m_threadinfo->m_mutex);
789
790         for (mit = m_mergequeue.begin(); mit != m_mergequeue.end(); ++mit) {
791                 merge_scenes = (vector<KX_Scene *> *)(*mit)->GetData();
792
793                 for (sit=merge_scenes->begin(); sit!=merge_scenes->end(); ++sit) {
794                         (*mit)->GetMergeScene()->MergeScene(*sit);
795                         delete (*sit);
796                 }
797
798                 delete merge_scenes;
799                 (*mit)->SetData(NULL);
800
801                 (*mit)->Finish();
802         }
803
804         m_mergequeue.clear();
805
806         BLI_mutex_unlock(&m_threadinfo->m_mutex);
807 }
808
809 void KX_BlenderSceneConverter::AddScenesToMergeQueue(KX_LibLoadStatus *status)
810 {
811         BLI_mutex_lock(&m_threadinfo->m_mutex);
812         m_mergequeue.push_back(status);
813         BLI_mutex_unlock(&m_threadinfo->m_mutex);
814 }
815
816 static void async_convert(TaskPool *pool, void *ptr, int UNUSED(threadid))
817 {
818         KX_Scene *new_scene = NULL;
819         KX_LibLoadStatus *status = (KX_LibLoadStatus *)ptr;
820         vector<Scene *> *scenes = (vector<Scene *> *)status->GetData();
821         vector<KX_Scene *> *merge_scenes = new vector<KX_Scene *>(); // Deleted in MergeAsyncLoads
822
823         for (unsigned int i = 0; i < scenes->size(); ++i) {
824                 new_scene = status->GetEngine()->CreateScene((*scenes)[i], true);
825
826                 if (new_scene)
827                         merge_scenes->push_back(new_scene);
828
829                 status->AddProgress((1.0f / scenes->size()) * 0.9f); // We'll call conversion 90% and merging 10% for now
830         }
831
832         delete scenes;
833         status->SetData(merge_scenes);
834
835         status->GetConverter()->AddScenesToMergeQueue(status);
836 }
837
838 KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options)
839 {
840         BlendHandle *bpy_openlib = BLO_blendhandle_from_memory(data, length);
841
842         // Error checking is done in LinkBlendFile
843         return LinkBlendFile(bpy_openlib, path, group, scene_merge, err_str, options);
844 }
845
846 KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFilePath(const char *filepath, char *group, KX_Scene *scene_merge, char **err_str, short options)
847 {
848         BlendHandle *bpy_openlib = BLO_blendhandle_from_file(filepath, NULL);
849
850         // Error checking is done in LinkBlendFile
851         return LinkBlendFile(bpy_openlib, filepath, group, scene_merge, err_str, options);
852 }
853
854 static void load_datablocks(Main *main_tmp, BlendHandle *bpy_openlib, const char *path, int idcode)
855 {
856         LinkNode *names = NULL;
857
858         int totnames_dummy;
859         names = BLO_blendhandle_get_datablock_names(bpy_openlib, idcode, &totnames_dummy);
860         
861         int i = 0;
862         LinkNode *n = names;
863         while (n) {
864                 BLO_library_link_named_part(main_tmp, &bpy_openlib, (char *)n->link, idcode);
865                 n = (LinkNode *)n->next;
866                 i++;
867         }
868         BLI_linklist_free(names, free); /* free linklist *and* each node's data */
869 }
870
871 KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options)
872 {
873         Main *main_newlib; /* stored as a dynamic 'main' until we free it */
874         const int idcode = BKE_idcode_from_name(group);
875         ReportList reports;
876         static char err_local[255];
877
878 //      TIMEIT_START(bge_link_blend_file);
879
880         KX_LibLoadStatus *status;
881
882         /* only scene and mesh supported right now */
883         if (idcode != ID_SCE && idcode != ID_ME && idcode != ID_AC) {
884                 snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group);
885                 *err_str = err_local;
886                 BLO_blendhandle_close(bpy_openlib);
887                 return NULL;
888         }
889         
890         if (GetMainDynamicPath(path)) {
891                 snprintf(err_local, sizeof(err_local), "blend file already open \"%s\"\n", path);
892                 *err_str = err_local;
893                 BLO_blendhandle_close(bpy_openlib);
894                 return NULL;
895         }
896
897         if (bpy_openlib == NULL) {
898                 snprintf(err_local, sizeof(err_local), "could not open blendfile \"%s\"\n", path);
899                 *err_str = err_local;
900                 return NULL;
901         }
902
903         main_newlib = BKE_main_new();
904         BKE_reports_init(&reports, RPT_STORE);
905
906         short flag = 0; /* don't need any special options */
907         /* created only for linking, then freed */
908         Main *main_tmp = BLO_library_link_begin(main_newlib, &bpy_openlib, (char *)path);
909
910         load_datablocks(main_tmp, bpy_openlib, path, idcode);
911
912         if (idcode == ID_SCE && options & LIB_LOAD_LOAD_SCRIPTS) {
913                 load_datablocks(main_tmp, bpy_openlib, path, ID_TXT);
914         }
915
916         /* now do another round of linking for Scenes so all actions are properly loaded */
917         if (idcode == ID_SCE && options & LIB_LOAD_LOAD_ACTIONS) {
918                 load_datablocks(main_tmp, bpy_openlib, path, ID_AC);
919         }
920
921         BLO_library_link_end(NULL, main_tmp, &bpy_openlib, idcode, flag);
922
923         BLO_blendhandle_close(bpy_openlib);
924
925         BKE_reports_clear(&reports);
926         /* done linking */
927         
928         /* needed for lookups*/
929         GetMainDynamic().push_back(main_newlib);
930         BLI_strncpy(main_newlib->name, path, sizeof(main_newlib->name));
931         
932         
933         status = new KX_LibLoadStatus(this, m_ketsjiEngine, scene_merge, path);
934
935         if (idcode == ID_ME) {
936                 /* Convert all new meshes into BGE meshes */
937                 ID *mesh;
938         
939                 for (mesh = (ID *)main_newlib->mesh.first; mesh; mesh = (ID *)mesh->next ) {
940                         if (options & LIB_LOAD_VERBOSE)
941                                 printf("MeshName: %s\n", mesh->name + 2);
942                         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
943                         scene_merge->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj);
944                 }
945         }
946         else if (idcode == ID_AC) {
947                 /* Convert all actions */
948                 ID *action;
949
950                 for (action= (ID *)main_newlib->action.first; action; action = (ID *)action->next) {
951                         if (options & LIB_LOAD_VERBOSE)
952                                 printf("ActionName: %s\n", action->name + 2);
953                         scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action);
954                 }
955         }
956         else if (idcode == ID_SCE) {
957                 /* Merge all new linked in scene into the existing one */
958                 ID *scene;
959                 // scenes gets deleted by the thread when it's done using it (look in async_convert())
960                 vector<Scene *> *scenes = (options & LIB_LOAD_ASYNC) ? new vector<Scene *>() : NULL;
961
962                 for (scene = (ID *)main_newlib->scene.first; scene; scene = (ID *)scene->next ) {
963                         if (options & LIB_LOAD_VERBOSE)
964                                 printf("SceneName: %s\n", scene->name + 2);
965                         
966                         if (options & LIB_LOAD_ASYNC) {
967                                 scenes->push_back((Scene *)scene);
968                         } 
969                         else {
970                                 /* merge into the base  scene */
971                                 KX_Scene* other = m_ketsjiEngine->CreateScene((Scene *)scene, true);
972                                 scene_merge->MergeScene(other);
973                         
974                                 // RemoveScene(other); // Don't run this, it frees the entire scene converter data, just delete the scene
975                                 delete other;
976                         }
977                 }
978
979                 if (options & LIB_LOAD_ASYNC) {
980                         status->SetData(scenes);
981                         BLI_task_pool_push(m_threadinfo->m_pool, async_convert, (void *)status, false, TASK_PRIORITY_LOW);
982                 }
983
984 #ifdef WITH_PYTHON
985                 /* Handle any text datablocks */
986                 if (options & LIB_LOAD_LOAD_SCRIPTS)
987                         addImportMain(main_newlib);
988 #endif
989
990                 /* Now handle all the actions */
991                 if (options & LIB_LOAD_LOAD_ACTIONS) {
992                         ID *action;
993
994                         for (action = (ID *)main_newlib->action.first; action; action = (ID *)action->next) {
995                                 if (options & LIB_LOAD_VERBOSE)
996                                         printf("ActionName: %s\n", action->name + 2);
997                                 scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action);
998                         }
999                 }
1000         }
1001
1002         if (!(options & LIB_LOAD_ASYNC))
1003                 status->Finish();
1004
1005 //      TIMEIT_END(bge_link_blend_file);
1006
1007         m_status_map[main_newlib->name] = status;
1008         return status;
1009 }
1010
1011 /* Note m_map_*** are all ok and don't need to be freed
1012  * most are temp and NewRemoveObject frees m_map_gameobject_to_blender */
1013 bool KX_BlenderSceneConverter::FreeBlendFile(Main *maggie)
1014 {
1015         int maggie_index = -1;
1016         int i = 0;
1017
1018         if (maggie == NULL)
1019                 return false;
1020         
1021         /* tag all false except the one we remove */
1022         for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
1023                 Main *main = *it;
1024                 if (main != maggie) {
1025                         BKE_main_id_tag_all(main, false);
1026                 }
1027                 else {
1028                         maggie_index = i;
1029                 }
1030                 i++;
1031         }
1032
1033         /* should never happen but just to be safe */
1034         if (maggie_index == -1)
1035                 return false;
1036
1037         m_DynamicMaggie.erase(m_DynamicMaggie.begin() + maggie_index);
1038         BKE_main_id_tag_all(maggie, true);
1039
1040         /* free all tagged objects */
1041         KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
1042         int numScenes = scenes->size();
1043
1044         for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) {
1045                 KX_Scene *scene = scenes->at(scene_idx);
1046                 if (IS_TAGGED(scene->GetBlenderScene())) {
1047                         m_ketsjiEngine->RemoveScene(scene->GetName());
1048                         m_mat_cache.erase(scene);
1049                         m_polymat_cache.erase(scene);
1050                         scene_idx--;
1051                         numScenes--;
1052                 }
1053                 else {
1054                         /* in case the mesh might be refered to later */
1055                         {
1056                                 CTR_Map<STR_HashedString, void *> &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap();
1057                                 
1058                                 for (int i = 0; i < mapStringToMeshes.size(); i++) {
1059                                         RAS_MeshObject *meshobj = (RAS_MeshObject *) *mapStringToMeshes.at(i);
1060                                         if (meshobj && IS_TAGGED(meshobj->GetMesh())) {
1061                                                 STR_HashedString mn = meshobj->GetName();
1062                                                 mapStringToMeshes.remove(mn);
1063                                                 m_map_mesh_to_gamemesh.remove(CHashedPtr(meshobj->GetMesh()));
1064                                                 i--;
1065                                         }
1066                                 }
1067                         }
1068
1069                         /* Now unregister actions */
1070                         {
1071                                 CTR_Map<STR_HashedString, void *> &mapStringToActions = scene->GetLogicManager()->GetActionMap();
1072
1073                                 for (int i = 0; i < mapStringToActions.size(); i++) {
1074                                         ID *action = (ID*) *mapStringToActions.at(i);
1075
1076                                         if (IS_TAGGED(action)) {
1077                                                 STR_HashedString an = action->name + 2;
1078                                                 mapStringToActions.remove(an);
1079                                                 m_map_blender_to_gameAdtList.remove(CHashedPtr(action));
1080                                                 i--;
1081                                         }
1082                                 }
1083                         }
1084                         
1085                         //scene->FreeTagged(); /* removed tagged objects and meshes*/
1086                         CListValue *obj_lists[] = {scene->GetObjectList(), scene->GetInactiveList(), NULL};
1087
1088                         for (int ob_ls_idx = 0; obj_lists[ob_ls_idx]; ob_ls_idx++) {
1089                                 CListValue *obs = obj_lists[ob_ls_idx];
1090                                 RAS_MeshObject *mesh;
1091
1092                                 for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++) {
1093                                         KX_GameObject *gameobj = (KX_GameObject*)obs->GetValue(ob_idx);
1094                                         if (IS_TAGGED(gameobj->GetBlenderObject())) {
1095                                                 int size_before = obs->GetCount();
1096
1097                                                 /* Eventually calls RemoveNodeDestructObject
1098                                                  * frees m_map_gameobject_to_blender from UnregisterGameObject */
1099                                                 scene->RemoveObject(gameobj);
1100
1101                                                 if (size_before != obs->GetCount())
1102                                                         ob_idx--;
1103                                                 else {
1104                                                         printf("ERROR COULD NOT REMOVE \"%s\"\n", gameobj->GetName().ReadPtr());
1105                                                 }
1106                                         }
1107                                         else {
1108                                                 gameobj->RemoveTaggedActions();
1109                                                 /* free the mesh, we could be referecing a linked one! */
1110                                                 int mesh_index = gameobj->GetMeshCount();
1111                                                 while (mesh_index--) {
1112                                                         mesh = gameobj->GetMesh(mesh_index);
1113                                                         if (IS_TAGGED(mesh->GetMesh())) {
1114                                                                 gameobj->RemoveMeshes(); /* XXX - slack, should only remove meshes that are library items but mostly objects only have 1 mesh */
1115                                                                 break;
1116                                                         }
1117                                                         else {
1118                                                                 /* also free the mesh if it's using a tagged material */
1119                                                                 int mat_index = mesh->NumMaterials();
1120                                                                 while (mat_index--) {
1121                                                                         if (IS_TAGGED(mesh->GetMeshMaterial(mat_index)->m_bucket->GetPolyMaterial()->GetBlenderMaterial())) {
1122                                                                                 gameobj->RemoveMeshes(); /* XXX - slack, same as above */
1123                                                                                 break;
1124                                                                         }
1125                                                                 }
1126                                                         }
1127                                                 }
1128
1129                                                 /* make sure action actuators are not referencing tagged actions */
1130                                                 for (unsigned int act_idx = 0; act_idx < gameobj->GetActuators().size(); act_idx++) {
1131                                                         if (gameobj->GetActuators()[act_idx]->IsType(SCA_IActuator::KX_ACT_ACTION)) {
1132                                                                 BL_ActionActuator *act = (BL_ActionActuator *)gameobj->GetActuators()[act_idx];
1133                                                                 if (IS_TAGGED(act->GetAction()))
1134                                                                         act->SetAction(NULL);
1135                                                         }
1136                                                 }
1137                                         }
1138                                 }
1139                         }
1140                 }
1141         }
1142
1143         int size;
1144
1145         // delete the entities of this scene
1146         /* TODO - */
1147 #if 0
1148         vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit;
1149         size = m_worldinfos.size();
1150         for (i=0, worldit=m_worldinfos.begin(); i<size; ) {
1151                 if ((*worldit).second) {
1152                         delete (*worldit).second;
1153                         *worldit = m_worldinfos.back();
1154                         m_worldinfos.pop_back();
1155                         size--;
1156                 } else {
1157                         i++;
1158                         worldit++;
1159                 }
1160         }
1161 #endif
1162
1163
1164         /* Worlds don't reference original blender data so we need to make a set from them */
1165         typedef std::set<KX_WorldInfo *> KX_WorldInfoSet;
1166         KX_WorldInfoSet worldset;
1167         for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) {
1168                 KX_Scene *scene = scenes->at(scene_idx);
1169                 if (scene->GetWorldInfo())
1170                         worldset.insert(scene->GetWorldInfo());
1171         }
1172
1173         vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator worldit;
1174         size = m_worldinfos.size();
1175         for (i = 0, worldit = m_worldinfos.begin(); i < size;) {
1176                 if (worldit->second && (worldset.count(worldit->second)) == 0) {
1177                         delete worldit->second;
1178                         *worldit = m_worldinfos.back();
1179                         m_worldinfos.pop_back();
1180                         size--;
1181                 } 
1182                 else {
1183                         i++;
1184                         worldit++;
1185                 }
1186         }
1187         worldset.clear();
1188         /* done freeing the worlds */
1189
1190         vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator polymit;
1191         size = m_polymaterials.size();
1192
1193         for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
1194                 RAS_IPolyMaterial *mat = polymit->second;
1195                 Material *bmat = NULL;
1196
1197                 KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial *>(mat);
1198                 bmat = bl_mat->GetBlenderMaterial();
1199
1200                 if (IS_TAGGED(bmat)) {
1201                         /* only remove from bucket */
1202                         polymit->first->GetBucketManager()->RemoveMaterial(mat);
1203                 }
1204
1205                 i++;
1206                 polymit++;
1207         }
1208
1209         for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
1210                 RAS_IPolyMaterial *mat = polymit->second;
1211                 Material *bmat = NULL;
1212
1213                 KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat);
1214                 bmat = bl_mat->GetBlenderMaterial();
1215
1216                 if (IS_TAGGED(bmat)) {
1217                         // Remove the poly material coresponding to this Blender Material.
1218                         m_polymat_cache[polymit->first].erase(bmat);
1219                         delete polymit->second;
1220                         *polymit = m_polymaterials.back();
1221                         m_polymaterials.pop_back();
1222                         size--;
1223                 } else {
1224                         i++;
1225                         polymit++;
1226                 }
1227         }
1228
1229         vector<pair<KX_Scene *, BL_Material *> >::iterator matit;
1230         size = m_materials.size();
1231         for (i = 0, matit = m_materials.begin(); i < size; ) {
1232                 BL_Material *mat = matit->second;
1233                 if (IS_TAGGED(mat->material)) {
1234                         // Remove the bl material coresponding to this Blender Material.
1235                         m_mat_cache[matit->first].erase(mat->material);
1236                         delete matit->second;
1237                         *matit = m_materials.back();
1238                         m_materials.pop_back();
1239                         size--;
1240                 } 
1241                 else {
1242                         i++;
1243                         matit++;
1244                 }
1245         }
1246
1247         vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator meshit;
1248         RAS_BucketManager::BucketList::iterator bit;
1249         list<RAS_MeshSlot>::iterator msit;
1250         RAS_BucketManager::BucketList buckets;
1251
1252         size = m_meshobjects.size();
1253         for (i = 0, meshit = m_meshobjects.begin(); i < size;) {
1254                 RAS_MeshObject *me = meshit->second;
1255                 if (IS_TAGGED(me->GetMesh())) {
1256                         // Before deleting the mesh object, make sure the rasterizer is
1257                         // no longer referencing it.
1258                         buckets = meshit->first->GetBucketManager()->GetSolidBuckets();
1259                         for (bit = buckets.begin(); bit != buckets.end(); bit++) {
1260                                 msit = (*bit)->msBegin();
1261
1262                                 while (msit != (*bit)->msEnd()) {
1263                                         if (msit->m_mesh == meshit->second)
1264                                                 (*bit)->RemoveMesh(&(*msit++));
1265                                         else
1266                                                 msit++;
1267                                 }
1268                         }
1269
1270                         // And now the alpha buckets
1271                         buckets = meshit->first->GetBucketManager()->GetAlphaBuckets();
1272                         for (bit = buckets.begin(); bit != buckets.end(); bit++) {
1273                                 msit = (*bit)->msBegin();
1274
1275                                 while (msit != (*bit)->msEnd()) {
1276                                         if (msit->m_mesh == meshit->second)
1277                                                 (*bit)->RemoveMesh(&(*msit++));
1278                                         else
1279                                                 msit++;
1280                                 }
1281                         }
1282
1283                         // Now it should be safe to delete
1284                         delete meshit->second;
1285                         *meshit = m_meshobjects.back();
1286                         m_meshobjects.pop_back();
1287                         size--;
1288                 } 
1289                 else {
1290                         i++;
1291                         meshit++;
1292                 }
1293         }
1294
1295 #ifdef WITH_PYTHON
1296         /* make sure this maggie is removed from the import list if it's there
1297          * (this operation is safe if it isn't in the list) */
1298         removeImportMain(maggie);
1299 #endif
1300
1301         delete m_status_map[maggie->name];
1302         m_status_map.erase(maggie->name);
1303
1304         BKE_main_free(maggie);
1305
1306         return true;
1307 }
1308
1309 bool KX_BlenderSceneConverter::FreeBlendFile(const char *path)
1310 {
1311         return FreeBlendFile(GetMainDynamicPath(path));
1312 }
1313
1314 bool KX_BlenderSceneConverter::MergeScene(KX_Scene *to, KX_Scene *from)
1315 {
1316         {
1317                 vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator itp = m_worldinfos.begin();
1318                 while (itp != m_worldinfos.end()) {
1319                         if (itp->first == from)
1320                                 itp->first = to;
1321                         itp++;
1322                 }
1323         }
1324
1325         {
1326                 vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator itp = m_polymaterials.begin();
1327                 while (itp != m_polymaterials.end()) {
1328                         if (itp->first == from) {
1329                                 itp->first = to;
1330
1331                                 /* also switch internal data */
1332                                 RAS_IPolyMaterial *mat = itp->second;
1333                                 mat->Replace_IScene(to);
1334                         }
1335                         itp++;
1336                 }
1337         }
1338
1339         {
1340                 vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator itp = m_meshobjects.begin();
1341                 while (itp != m_meshobjects.end()) {
1342                         if (itp->first == from)
1343                                 itp->first = to;
1344                         itp++;
1345                 }
1346         }
1347
1348         {
1349                 vector<pair<KX_Scene *, BL_Material *> >::iterator itp = m_materials.begin();
1350                 while (itp != m_materials.end()) {
1351                         if (itp->first == from)
1352                                 itp->first = to;
1353                         itp++;
1354                 }
1355         }
1356
1357         MaterialCache::iterator matcacheit = m_mat_cache.find(from);
1358         if (matcacheit != m_mat_cache.end()) {
1359                 // Merge cached BL_Material map.
1360                 m_mat_cache[to].insert(matcacheit->second.begin(), matcacheit->second.end());
1361                 m_mat_cache.erase(matcacheit);
1362         }
1363
1364         PolyMaterialCache::iterator polymatcacheit = m_polymat_cache.find(from);
1365         if (polymatcacheit != m_polymat_cache.end()) {
1366                 // Merge cached RAS_IPolyMaterial map.
1367                 m_polymat_cache[to].insert(polymatcacheit->second.begin(), polymatcacheit->second.end());
1368                 m_polymat_cache.erase(polymatcacheit);
1369         }
1370
1371         return true;
1372 }
1373
1374 /* This function merges a mesh from the current scene into another main
1375  * it does not convert */
1376 RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, const char *name)
1377 {
1378         /* Find a mesh in the current main */
1379         ID *me= static_cast<ID *>(BLI_findstring(&m_maggie->mesh, name, offsetof(ID, name) + 2));
1380         Main *from_maggie = m_maggie;
1381
1382         if (me == NULL) {
1383                 // The mesh wasn't in the current main, try any dynamic (i.e., LibLoaded) ones
1384                 vector<Main *>::iterator it;
1385
1386                 for (it = GetMainDynamic().begin(); it != GetMainDynamic().end(); it++) {
1387                         me = static_cast<ID *>(BLI_findstring(&(*it)->mesh, name, offsetof(ID, name) + 2));
1388                         from_maggie = *it;
1389
1390                         if (me)
1391                                 break;
1392                 }
1393         }
1394
1395         if (me == NULL) {
1396                 printf("Could not be found \"%s\"\n", name);
1397                 return NULL;
1398         }
1399
1400         /* Watch this!, if its used in the original scene can cause big troubles */
1401         if (me->us > 0) {
1402 #ifdef DEBUG
1403                 printf("Mesh has a user \"%s\"\n", name);
1404 #endif
1405                 me = (ID*)BKE_mesh_copy_ex(from_maggie, (Mesh*)me);
1406                 me->us--;
1407         }
1408         BLI_remlink(&from_maggie->mesh, me); /* even if we made the copy it needs to be removed */
1409         BLI_addtail(&maggie->mesh, me);
1410
1411         /* Must copy the materials this uses else we cant free them */
1412         {
1413                 Mesh *mesh = (Mesh *)me;
1414
1415                 /* ensure all materials are tagged */
1416                 for (int i = 0; i < mesh->totcol; i++) {
1417                         if (mesh->mat[i])
1418                                 mesh->mat[i]->id.flag &= ~LIB_DOIT;
1419                 }
1420
1421                 for (int i = 0; i < mesh->totcol; i++) {
1422                         Material *mat_old = mesh->mat[i];
1423
1424                         /* if its tagged its a replaced material */
1425                         if (mat_old && (mat_old->id.flag & LIB_DOIT) == 0) {
1426                                 Material *mat_old = mesh->mat[i];
1427                                 Material *mat_new = BKE_material_copy(mat_old);
1428
1429                                 mat_new->id.flag |= LIB_DOIT;
1430                                 mat_old->id.us--;
1431
1432                                 BLI_remlink(&G.main->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex
1433                                 BLI_addtail(&maggie->mat, mat_new);
1434
1435                                 mesh->mat[i] = mat_new;
1436
1437                                 /* the same material may be used twice */
1438                                 for (int j = i + 1; j < mesh->totcol; j++) {
1439                                         if (mesh->mat[j] == mat_old) {
1440                                                 mesh->mat[j] = mat_new;
1441                                                 mat_new->id.us++;
1442                                                 mat_old->id.us--;
1443                                         }
1444                                 }
1445                         }
1446                 }
1447         }
1448
1449         m_currentScene = kx_scene; // This needs to be set in case we LibLoaded earlier
1450         RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)me, NULL, kx_scene, this, false);
1451         kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
1452         m_map_mesh_to_gamemesh.clear(); /* This is at runtime so no need to keep this, BL_ConvertMesh adds */
1453         return meshobj;
1454 }