svn merge -r 13452:14721 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / gameengine / Ketsji / KX_Scene.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Ketsji scene. Holds references to all scene data.
29  */
30
31 #ifdef WIN32
32 #pragma warning (disable : 4786)
33 #endif //WIN32
34
35
36 #include "KX_Scene.h"
37 #include "MT_assert.h"
38
39 #include "KX_KetsjiEngine.h"
40 #include "RAS_IPolygonMaterial.h"
41 #include "ListValue.h"
42 #include "SCA_LogicManager.h"
43 #include "SCA_TimeEventManager.h"
44 #include "SCA_AlwaysEventManager.h"
45 #include "SCA_RandomEventManager.h"
46 #include "KX_RayEventManager.h"
47 #include "KX_TouchEventManager.h"
48 #include "SCA_KeyboardManager.h"
49 #include "SCA_MouseManager.h"
50 #include "SCA_PropertyEventManager.h"
51 #include "KX_Camera.h"
52 #include "SCA_JoystickManager.h"
53
54 #include "RAS_MeshObject.h"
55 #include "BL_SkinMeshObject.h"
56
57 #include "RAS_IRasterizer.h"
58 #include "RAS_BucketManager.h"
59
60 #include "FloatValue.h"
61 #include "SCA_IController.h"
62 #include "SCA_IActuator.h"
63 #include "SG_Node.h"
64 #include "SYS_System.h"
65 #include "SG_Controller.h"
66 #include "SG_IObject.h"
67 #include "SG_Tree.h"
68
69 #include "KX_SG_NodeRelationships.h"
70
71 #include "KX_NetworkEventManager.h"
72 #include "NG_NetworkScene.h"
73 #include "PHY_IPhysicsEnvironment.h"
74 #include "KX_IPhysicsController.h"
75 #include "KX_BlenderSceneConverter.h"
76
77 #include "BL_SkinDeformer.h"
78 #include "BL_DeformableGameObject.h"
79
80 // to get USE_BULLET!
81 #include "KX_ConvertPhysicsObject.h"
82
83 #ifdef USE_BULLET
84 #include "CcdPhysicsEnvironment.h"
85 #include "CcdPhysicsController.h"
86 #endif
87
88 void* KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene)
89 {
90         KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj);
91
92         return (void*)replica;
93 }
94
95 void* KX_SceneDestructionFunc(SG_IObject* node,void* gameobj,void* scene)
96 {
97         ((KX_Scene*)scene)->RemoveNodeDestructObject(node,(KX_GameObject*)gameobj);
98
99         return NULL;
100 };
101
102 SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks(KX_SceneReplicationFunc,KX_SceneDestructionFunc,KX_GameObject::UpdateTransformFunc);
103
104 // temporarily var until there is a button in the userinterface
105 // (defined in KX_PythonInit.cpp)
106 extern bool gUseVisibilityTemp;
107
108 KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
109                                    class SCA_IInputDevice* mousedevice,
110                                    class NG_NetworkDeviceInterface *ndi,
111                                    class SND_IAudioDevice* adi,
112                                    const STR_String& sceneName): 
113         PyObjectPlus(&KX_Scene::Type),
114         m_keyboardmgr(NULL),
115         m_mousemgr(NULL),
116         m_physicsEnvironment(0),
117         m_sceneName(sceneName),
118         m_adi(adi),
119         m_networkDeviceInterface(ndi),
120         m_active_camera(NULL),
121         m_ueberExecutionPriority(0),
122         m_sceneConverter(NULL)
123 {
124         m_suspendedtime = 0.0;
125         m_suspendeddelta = 0.0;
126
127         m_activity_culling = false;
128         m_suspend = false;
129         m_isclearingZbuffer = true;
130         m_tempObjectList = new CListValue();
131         m_objectlist = new CListValue();
132         m_parentlist = new CListValue();
133         m_lightlist= new CListValue();
134         m_inactivelist = new CListValue();
135         m_euthanasyobjects = new CListValue();
136         m_delayReleaseObjects = new CListValue();
137
138         m_logicmgr = new SCA_LogicManager();
139         
140         m_timemgr = new SCA_TimeEventManager(m_logicmgr);
141         m_keyboardmgr = new SCA_KeyboardManager(m_logicmgr,keyboarddevice);
142         m_mousemgr = new SCA_MouseManager(m_logicmgr,mousedevice);
143         
144         SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr);
145         SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr);
146         SCA_RandomEventManager* rndmgr = new SCA_RandomEventManager(m_logicmgr);
147         KX_RayEventManager* raymgr = new KX_RayEventManager(m_logicmgr);
148
149         KX_NetworkEventManager* netmgr = new KX_NetworkEventManager(m_logicmgr, ndi);
150         
151         SCA_JoystickManager *joymgr     = new SCA_JoystickManager(m_logicmgr);
152
153         m_logicmgr->RegisterEventManager(alwaysmgr);
154         m_logicmgr->RegisterEventManager(propmgr);
155         m_logicmgr->RegisterEventManager(m_keyboardmgr);
156         m_logicmgr->RegisterEventManager(m_mousemgr);
157         m_logicmgr->RegisterEventManager(m_timemgr);
158         m_logicmgr->RegisterEventManager(rndmgr);
159         m_logicmgr->RegisterEventManager(raymgr);
160         m_logicmgr->RegisterEventManager(netmgr);
161         m_logicmgr->RegisterEventManager(joymgr);
162
163         m_soundScene = new SND_Scene(adi);
164         MT_assert (m_networkDeviceInterface != NULL);
165         m_networkScene = new NG_NetworkScene(m_networkDeviceInterface);
166         
167         m_rootnode = NULL;
168
169         m_bucketmanager=new RAS_BucketManager();
170
171         m_canvasDesignWidth = 0;
172         m_canvasDesignHeight = 0;
173         
174         m_attrlist = PyDict_New(); /* new ref */
175 }
176
177
178
179 KX_Scene::~KX_Scene()
180 {
181         // The release of debug properties used to be in SCA_IScene::~SCA_IScene
182         // It's still there but we remove all properties here otherwise some
183         // reference might be hanging and causing late release of objects
184         RemoveAllDebugProperties();
185
186         while (GetRootParentList()->GetCount() > 0) 
187         {
188                 KX_GameObject* parentobj = (KX_GameObject*) GetRootParentList()->GetValue(0);
189                 this->RemoveObject(parentobj);
190         }
191
192         if(m_objectlist)
193                 m_objectlist->Release();
194
195         if (m_parentlist)
196                 m_parentlist->Release();
197         
198         if (m_inactivelist)
199                 m_inactivelist->Release();
200
201         if (m_lightlist)
202                 m_lightlist->Release();
203         
204         if (m_tempObjectList)
205                 m_tempObjectList->Release();
206
207         if (m_euthanasyobjects)
208                 m_euthanasyobjects->Release();
209         if (m_delayReleaseObjects)
210                 m_delayReleaseObjects->Release();
211
212         if (m_logicmgr)
213                 delete m_logicmgr;
214
215         if (m_physicsEnvironment)
216                 delete m_physicsEnvironment;
217
218         if (m_soundScene)
219                 delete m_soundScene;
220
221         if (m_networkScene)
222                 delete m_networkScene;
223         
224         if (m_bucketmanager)
225         {
226                 delete m_bucketmanager;
227         }
228 #ifdef USE_BULLET
229         // This is a fix for memory leaks in bullet: the collision shapes is not destroyed 
230         // when the physical controllers are destroyed. The reason is that shapes are shared
231         // between replicas of an object. There is no reference count in Bullet so the
232         // only workaround that does not involve changes in Bullet is to save in this array
233         // the list of shapes that are created when the scene is created (see KX_ConvertPhysicsObjects.cpp)
234         class btCollisionShape* shape;
235         class btTriangleMeshShape* meshShape;
236         vector<class btCollisionShape*>::iterator it = m_shapes.begin();
237         while (it != m_shapes.end()) {
238                 shape = *it;
239                 if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
240                 {
241                         meshShape = static_cast<btTriangleMeshShape*>(shape);
242                         // shapes based on meshes use an interface that contains the vertices.
243                         // Again the idea is to be able to share the interface between shapes but
244                         // this is not used in Blender: each base object will have its own interface 
245                         btStridingMeshInterface* meshInterface = meshShape->getMeshInterface();
246                         if (meshInterface)
247                                 delete meshInterface;
248                 }
249                 delete shape;
250                 it++;
251         }
252 #endif
253         //Py_DECREF(m_attrlist);
254 }
255
256 void KX_Scene::AddShape(class btCollisionShape*shape)
257 {
258         m_shapes.push_back(shape);
259 }
260
261
262 void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat)
263 {
264         m_projectionmat = pmat;
265 }
266
267
268
269 RAS_BucketManager* KX_Scene::GetBucketManager()
270 {
271         return m_bucketmanager;
272 }
273
274
275
276 CListValue* KX_Scene::GetObjectList()
277 {
278         return m_objectlist;
279 }
280
281
282
283 CListValue* KX_Scene::GetRootParentList()
284 {
285         return m_parentlist;
286 }
287
288 CListValue* KX_Scene::GetInactiveList()
289 {
290         return m_inactivelist;
291 }
292
293
294
295 CListValue* KX_Scene::GetLightList()
296 {
297         return m_lightlist;
298 }
299
300 SCA_LogicManager* KX_Scene::GetLogicManager()
301 {
302         return m_logicmgr;
303 }
304
305 SCA_TimeEventManager* KX_Scene::GetTimeEventManager()
306 {
307         return m_timemgr;
308 }
309
310
311
312  
313 list<class KX_Camera*>* KX_Scene::GetCameras()
314 {
315         return &m_cameras;
316 }
317
318
319
320 void KX_Scene::SetFramingType(RAS_FrameSettings & frame_settings)
321 {
322         m_frame_settings = frame_settings;
323 };
324
325 /**
326  * Return a const reference to the framing 
327  * type set by the above call.
328  * The contents are not guarenteed to be sensible
329  * if you don't call the above function.
330  */
331 const RAS_FrameSettings& KX_Scene::GetFramingType() const 
332 {
333         return m_frame_settings;
334 };      
335
336
337
338 /**
339  * Store the current scene's viewport on the 
340  * game engine canvas.
341  */
342 void KX_Scene::SetSceneViewport(const RAS_Rect &viewport)
343 {
344         m_viewport = viewport;
345 }
346
347
348
349 const RAS_Rect& KX_Scene::GetSceneViewport() const 
350 {
351         return m_viewport;
352 }
353
354
355
356 void KX_Scene::SetWorldInfo(class KX_WorldInfo* worldinfo)
357 {
358         m_worldinfo = worldinfo;
359 }
360
361
362
363 class KX_WorldInfo* KX_Scene::GetWorldInfo()
364 {
365         return m_worldinfo;
366 }
367
368
369
370 SND_Scene* KX_Scene::GetSoundScene()
371 {
372         return m_soundScene;
373 }
374
375 const STR_String& KX_Scene::GetName()
376 {
377         return m_sceneName;
378 }
379
380
381 void KX_Scene::Suspend()
382 {
383         m_suspend = true;
384 }
385
386 void KX_Scene::Resume()
387 {
388         m_suspend = false;
389 }
390
391 void KX_Scene::SetActivityCulling(bool b)
392 {
393         m_activity_culling = b;
394 }
395
396 bool KX_Scene::IsSuspended()
397 {
398         return m_suspend;
399 }
400
401 bool KX_Scene::IsClearingZBuffer()
402 {
403         return m_isclearingZbuffer;
404 }
405
406 void KX_Scene::EnableZBufferClearing(bool isclearingZbuffer)
407 {
408         m_isclearingZbuffer = isclearingZbuffer;
409 }
410
411 void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gameobj)
412 {
413         KX_GameObject* orgobj = (KX_GameObject*)gameobj;        
414         if (NewRemoveObject(orgobj) != 0)
415         {
416                 // object is not yet deleted (this can happen when it hangs in an add object actuator
417                 // last object created reference. It's a bad situation, don't know how to fix it exactly
418                 // The least I can do, is remove the reference to the node in the object as the node
419                 // will in any case be deleted. This ensures that the object will not try to use the node
420                 // when it is finally deleted (see KX_GameObject destructor)
421                 orgobj->SetSGNode(NULL);
422         }
423         if (node)
424                 delete node;
425 }
426
427 KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CValue* gameobj)
428 {
429         KX_GameObject* orgobj = (KX_GameObject*)gameobj;
430         KX_GameObject* newobj = (KX_GameObject*)orgobj->GetReplica();
431         m_map_gameobject_to_replica.insert(orgobj, newobj);
432
433         // also register 'timers' (time properties) of the replica
434         int numprops = newobj->GetPropertyCount();
435
436         for (int i = 0; i < numprops; i++)
437         {
438                 CValue* prop = newobj->GetProperty(i);
439
440                 if (prop->GetProperty("timer"))
441                         this->m_timemgr->AddTimeProperty(prop);
442         }
443
444         if (node)
445         {
446                 newobj->SetSGNode((SG_Node*)node);
447         }
448         else
449         {
450                 m_rootnode = new SG_Node(newobj,this,KX_Scene::m_callbacks);
451         
452                 // this fixes part of the scaling-added object bug
453                 SG_Node* orgnode = orgobj->GetSGNode();
454                 m_rootnode->SetLocalScale(orgnode->GetLocalScale());
455                 m_rootnode->SetLocalPosition(orgnode->GetLocalPosition());
456                 m_rootnode->SetLocalOrientation(orgnode->GetLocalOrientation());
457
458                 // define the relationship between this node and it's parent.
459                 KX_NormalParentRelation * parent_relation = 
460                         KX_NormalParentRelation::New();
461                 m_rootnode->SetParentRelation(parent_relation);
462
463                 newobj->SetSGNode(m_rootnode);
464         }
465         
466         SG_IObject* replicanode = newobj->GetSGNode();
467 //      SG_Node* rootnode = (replicanode == m_rootnode ? NULL : m_rootnode);
468
469         replicanode->SetSGClientObject(newobj);
470
471         // this is the list of object that are send to the graphics pipeline
472         m_objectlist->Add(newobj->AddRef());
473         newobj->Bucketize();
474
475         // logic cannot be replicated, until the whole hierarchy is replicated.
476         m_logicHierarchicalGameObjects.push_back(newobj);
477         //replicate controllers of this node
478         SGControllerList        scenegraphcontrollers = orgobj->GetSGNode()->GetSGControllerList();
479         replicanode->RemoveAllControllers();
480         SGControllerList::iterator cit;
481         //int numcont = scenegraphcontrollers.size();
482         
483         for (cit = scenegraphcontrollers.begin();!(cit==scenegraphcontrollers.end());++cit)
484         {
485                 // controller replication is quite complicated
486                 // only replicate ipo and physics controller for now
487
488                 SG_Controller* replicacontroller = (*cit)->GetReplica((SG_Node*) replicanode);
489                 if (replicacontroller)
490                 {
491                         replicacontroller->SetObject(replicanode);
492                         replicanode->AddSGController(replicacontroller);
493                 }
494         }
495         
496         return newobj;
497 }
498
499
500
501 // before calling this method KX_Scene::ReplicateLogic(), make sure to
502 // have called 'GameObject::ReParentLogic' for each object this
503 // hierarchy that's because first ALL bricks must exist in the new
504 // replica of the hierarchy in order to make cross-links work properly
505 // !
506 void KX_Scene::ReplicateLogic(KX_GameObject* newobj)
507 {
508         // also relink the controller to sensors/actuators
509         SCA_ControllerList& controllers = newobj->GetControllers();
510         //SCA_SensorList&     sensors     = newobj->GetSensors();
511         //SCA_ActuatorList&   actuators   = newobj->GetActuators();
512
513         for (SCA_ControllerList::iterator itc = controllers.begin(); !(itc==controllers.end());itc++)
514         {
515                 SCA_IController* cont = (*itc);
516                 cont->SetUeberExecutePriority(m_ueberExecutionPriority);
517                 vector<SCA_ISensor*> linkedsensors = cont->GetLinkedSensors();
518                 vector<SCA_IActuator*> linkedactuators = cont->GetLinkedActuators();
519
520                 // disconnect the sensors and actuators
521                 cont->UnlinkAllSensors();
522                 cont->UnlinkAllActuators();
523                 
524                 // now relink each sensor
525                 for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());its++)
526                 {
527                         SCA_ISensor* oldsensor = (*its);
528                         STR_String name = oldsensor->GetName();
529                         //find this name in the list
530                         SCA_ISensor* newsensor = newobj->FindSensor(name);
531                 
532                         if (newsensor)
533                         {
534                                 // relink this newsensor to the controller
535                                 m_logicmgr->RegisterToSensor(cont,newsensor);
536                         }
537                         else
538                         {
539                                 // it can be linked somewhere in the hierarchy or...
540                                 for (vector<KX_GameObject*>::iterator git = m_logicHierarchicalGameObjects.begin();
541                                 !(git==m_logicHierarchicalGameObjects.end());++git)
542                                 {
543                                         newsensor = (*git)->FindSensor(name);
544                                         if (newsensor)
545                                                 break;
546                                 } 
547
548                                 if (newsensor)
549                                 {
550                                         // relink this newsensor to the controller somewhere else within this
551                                         // hierarchy
552                                         m_logicmgr->RegisterToSensor(cont,newsensor);
553                                 }
554                                 else
555                                 {
556                                         // must be an external sensor, so...
557                                         m_logicmgr->RegisterToSensor(cont,oldsensor);
558                                 }
559                         }
560                 }
561                 
562                 // now relink each actuator
563                 for (vector<SCA_IActuator*>::iterator ita = linkedactuators.begin();!(ita==linkedactuators.end());ita++)
564                 {
565                         SCA_IActuator* oldactuator = (*ita);
566                         STR_String name = oldactuator->GetName();
567                         //find this name in the list
568                         SCA_IActuator* newactuator = newobj->FindActuator(name);
569                         if (newactuator)
570                         {
571                                 // relink this newsensor to the controller
572                                 m_logicmgr->RegisterToActuator(cont,newactuator);
573                                 newactuator->SetUeberExecutePriority(m_ueberExecutionPriority);
574                         }
575                         else
576                         {
577                                 // it can be linked somewhere in the hierarchy or...
578                                 for (vector<KX_GameObject*>::iterator git = m_logicHierarchicalGameObjects.begin();
579                                 !(git==m_logicHierarchicalGameObjects.end());++git)
580                                 {
581                                         newactuator= (*git)->FindActuator(name);
582                                         if (newactuator)
583                                                 break;
584                                 } 
585
586                                 if (newactuator)
587                                 {
588                                         // relink this actuator to the controller somewhere else within this
589                                         // hierarchy
590                                         m_logicmgr->RegisterToActuator(cont,newactuator);
591                                         newactuator->SetUeberExecutePriority(m_ueberExecutionPriority);
592                                 }
593                                 else
594                                 {
595                                         // must be an external actuator, so...
596                                         m_logicmgr->RegisterToActuator(cont,oldactuator);
597                                 }
598                         }
599                 }
600         }
601 }
602
603
604
605 SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
606                                                                                 class CValue* parentobject,
607                                                                                 int lifespan)
608 {
609
610         m_logicHierarchicalGameObjects.clear();
611         m_map_gameobject_to_replica.clear();
612
613         // todo: place a timebomb in the object, for temporarily objects :)
614         // lifespan of zero means 'this object lives forever'
615         KX_GameObject* originalobj = (KX_GameObject*) originalobject;
616         KX_GameObject* parentobj = (KX_GameObject*) parentobject;
617
618         m_ueberExecutionPriority++;
619
620         // lets create a replica
621         KX_GameObject* replica = (KX_GameObject*) AddNodeReplicaObject(NULL,originalobj);
622
623         if (lifespan > 0)
624         {
625                 // add a timebomb to this object
626                 // for now, convert between so called frames and realtime
627                 m_tempObjectList->Add(replica->AddRef());
628                 CValue *fval = new CFloatValue(lifespan*0.02);
629                 replica->SetProperty("::timebomb",fval);
630                 fval->Release();
631         }
632
633         // add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame)
634         m_parentlist->Add(replica->AddRef());
635
636         // recurse replication into children nodes
637
638         NodeList& children = originalobj->GetSGNode()->GetSGChildren();
639
640         replica->GetSGNode()->ClearSGChildren();
641         for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit)
642         {
643                 SG_Node* orgnode = (*childit);
644                 SG_Node* childreplicanode = orgnode->GetSGReplica();
645                 replica->GetSGNode()->AddChild(childreplicanode);
646         }
647
648         //      relink any pointers as necessary, sort of a temporary solution
649         vector<KX_GameObject*>::iterator git;
650         for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
651         {
652                 (*git)->Relink(&m_map_gameobject_to_replica);
653                 // add the object in the layer of the parent
654                 (*git)->SetLayer(parentobj->GetLayer());
655         }
656
657         // now replicate logic
658         for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
659         {
660                 (*git)->ReParentLogic();
661         }
662         
663         // replicate crosslinks etc. between logic bricks
664         for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
665         {
666                 ReplicateLogic((*git));
667         }
668         
669         MT_Point3 newpos = ((KX_GameObject*) parentobject)->NodeGetWorldPosition();
670         replica->NodeSetLocalPosition(newpos);
671
672         MT_Matrix3x3 newori = ((KX_GameObject*) parentobject)->NodeGetWorldOrientation();
673         replica->NodeSetLocalOrientation(newori);
674         
675         // get the rootnode's scale
676         MT_Vector3 newscale = parentobj->GetSGNode()->GetRootSGParent()->GetLocalScale();
677
678         // set the replica's relative scale with the rootnode's scale
679         replica->NodeSetRelativeScale(newscale);
680
681         if (replica->GetPhysicsController())
682         {
683                 replica->GetPhysicsController()->setPosition(newpos);
684                 replica->GetPhysicsController()->setOrientation(newori.getRotation());
685                 replica->GetPhysicsController()->setScaling(newscale);
686         }
687
688         // here we want to set the relative scale: the rootnode's scale will override all other
689         // scalings, so lets better prepare for it
690
691
692         replica->GetSGNode()->UpdateWorldData(0);
693         replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox());
694         replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius());
695         //      don't release replica here because we are returning it, not done with it...
696         return replica;
697 }
698
699
700
701 void KX_Scene::RemoveObject(class CValue* gameobj)
702 {
703         KX_GameObject* newobj = (KX_GameObject*) gameobj;
704
705         // first disconnect child from parent
706         SG_Node* node = newobj->GetSGNode();
707
708         if (node)
709         {
710                 node->DisconnectFromParent();
711
712                 // recursively destruct
713                 node->Destruct();
714         }
715         //no need to do that: the object is destroyed and memory released 
716         //newobj->SetSGNode(0);
717 }
718
719 void KX_Scene::DelayedReleaseObject(CValue* gameobj)
720 {
721         m_delayReleaseObjects->Add(gameobj->AddRef());
722 }
723
724
725 void KX_Scene::DelayedRemoveObject(class CValue* gameobj)
726 {
727         //KX_GameObject* newobj = (KX_GameObject*) gameobj;
728         if (!m_euthanasyobjects->SearchValue(gameobj))
729         {
730                 m_euthanasyobjects->Add(gameobj->AddRef());
731         } 
732 }
733
734
735
736 int KX_Scene::NewRemoveObject(class CValue* gameobj)
737 {
738         int ret;
739         KX_GameObject* newobj = (KX_GameObject*) gameobj;
740
741         //todo: look at this
742         //GetPhysicsEnvironment()->RemovePhysicsController(gameobj->getPhysicsController());
743
744         // remove all sensors/controllers/actuators from logicsystem...
745         
746         SCA_SensorList& sensors = newobj->GetSensors();
747         for (SCA_SensorList::iterator its = sensors.begin();
748                  !(its==sensors.end());its++)
749         {
750                 m_logicmgr->RemoveSensor(*its);
751         }
752         
753     SCA_ControllerList& controllers = newobj->GetControllers();
754         for (SCA_ControllerList::iterator itc = controllers.begin();
755                  !(itc==controllers.end());itc++)
756         {
757                 (*itc)->UnlinkAllSensors();
758                 (*itc)->UnlinkAllActuators();
759                 m_logicmgr->RemoveController(*itc);
760         }
761
762         SCA_ActuatorList& actuators = newobj->GetActuators();
763         for (SCA_ActuatorList::iterator ita = actuators.begin();
764                  !(ita==actuators.end());ita++)
765         {
766                 m_logicmgr->RemoveDestroyedActuator(*ita);
767         }
768         // the sensors/controllers/actuators must also be released, this is done in ~SCA_IObject
769
770         // now remove the timer properties from the time manager
771         int numprops = newobj->GetPropertyCount();
772
773         for (int i = 0; i < numprops; i++)
774         {
775                 CValue* propval = newobj->GetProperty(i);
776                 if (propval->GetProperty("timer"))
777                 {
778                         m_timemgr->RemoveTimeProperty(propval);
779                 }
780         }
781         
782         newobj->RemoveMeshes();
783         ret = 1;
784         if (m_objectlist->RemoveValue(newobj))
785                 ret = newobj->Release();
786         if (m_tempObjectList->RemoveValue(newobj))
787                 ret = newobj->Release();
788         if (m_parentlist->RemoveValue(newobj))
789                 ret = newobj->Release();
790         if (m_inactivelist->RemoveValue(newobj))
791                 ret = newobj->Release();
792         if (m_euthanasyobjects->RemoveValue(newobj))
793                 ret = newobj->Release();
794                 
795         if (newobj == m_active_camera)
796         {
797                 //no AddRef done on m_active_camera so no Release
798                 //m_active_camera->Release();
799                 m_active_camera = NULL;
800         }
801         // in case this is a camera
802         m_cameras.remove((KX_Camera*)newobj);
803
804         if (m_sceneConverter)
805                 m_sceneConverter->UnregisterGameObject(newobj);
806         // return value will be 0 if the object is actually deleted (all reference gone)
807         return ret;
808 }
809
810
811
812 void KX_Scene::ReplaceMesh(class CValue* gameobj,void* meshobj)
813 {
814         KX_GameObject* newobj = static_cast<KX_GameObject*>(gameobj);
815         RAS_MeshObject* mesh = static_cast<RAS_MeshObject*>(meshobj);
816
817         const STR_String origMeshName = newobj->GetMesh(0)->GetName();
818
819         if( !newobj || !mesh ) 
820         {
821                 std::cout << "warning: invalid object, mesh will not be replaced" << std::endl;
822                 return;
823         }
824
825         newobj->RemoveMeshes();
826         newobj->AddMesh(mesh);
827
828         bool isDeformer = (newobj->m_isDeformable && mesh->m_class == 1);
829         if(isDeformer)
830         {
831                 /* FindBlendObjByGameObj() can return 0... 
832                         In the case of 0 here,
833                         the replicated object that is calling this function
834                         is some how not in the map. (which is strange because it's added)
835                         So we will search the map by the first mesh name
836                         to try to locate it there. If its still not found 
837                         spit some message rather than crash 
838                 */
839                 Object* blendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameObj(newobj));
840                 Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName()));
841         
842                 bool parSkin = blendobj && blendobj->parent && blendobj->parent->type == OB_ARMATURE && blendobj->partype==PARSKEL;
843                 bool releaseParent = true;
844                 KX_GameObject* parentobj = newobj->GetParent();
845
846
847                 // lookup by mesh name if blendobj is 0 
848                 if( !blendobj &&  parentobj )
849                 {
850                         blendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(origMeshName));
851
852                         // replace the mesh on the parent armature 
853                         if( blendobj )
854                                 parSkin = parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE;
855
856                         // can't do it 
857                         else 
858                                 std::cout << "warning: child object for " << parentobj->GetName().ReadPtr() 
859                                         << " not found, and can't create!" << std::endl;
860                 }
861
862                 if( blendobj && oldblendobj )
863                 {
864                         isDeformer = (static_cast<Mesh*>(blendobj->data)->dvert != 0);
865                         BL_DeformableGameObject* deformIter =0;
866
867                         // armature parent
868                         if( parSkin && isDeformer )
869                         {
870                                 deformIter = static_cast<BL_DeformableGameObject*>( newobj );
871                                 delete deformIter->m_pDeformer;
872
873                                 BL_SkinDeformer* skinDeformer = new BL_SkinDeformer(
874                                         oldblendobj, blendobj,
875                                         static_cast<BL_SkinMeshObject*>(mesh),
876                                         true,
877                                         static_cast<BL_ArmatureObject*>( parentobj )
878                                 );
879                                 releaseParent= false;
880                                 deformIter->m_pDeformer = skinDeformer;
881                         }
882
883                         // normal deformer
884                         if( !parSkin && isDeformer)
885                         {
886                                 deformIter = static_cast<BL_DeformableGameObject*>( newobj );
887                                 delete deformIter->m_pDeformer;
888
889                                 BL_MeshDeformer* meshdeformer = new BL_MeshDeformer(
890                                         oldblendobj, static_cast<BL_SkinMeshObject*>(mesh)
891                                 );
892
893                                 deformIter->m_pDeformer = meshdeformer;
894                         }
895                 }
896                 // release parent reference if its not being used 
897                 if( releaseParent && parentobj)
898                         parentobj->Release();
899         }
900         newobj->Bucketize();
901 }
902
903
904
905 MT_CmMatrix4x4& KX_Scene::GetViewMatrix()
906 {
907         MT_Scalar cammat[16];
908         m_active_camera->GetWorldToCamera().getValue(cammat);
909         m_viewmat = cammat;
910         return m_viewmat;
911 }
912
913
914
915 MT_CmMatrix4x4& KX_Scene::GetProjectionMatrix()
916 {
917         return m_projectionmat;
918 }
919
920
921 KX_Camera* KX_Scene::FindCamera(KX_Camera* cam)
922 {
923         list<KX_Camera*>::iterator it = m_cameras.begin();
924
925         while ( (it != m_cameras.end()) 
926                         && ((*it) != cam) ) {
927           it++;
928         }
929
930         return ((it == m_cameras.end()) ? NULL : (*it));
931 }
932
933
934 KX_Camera* KX_Scene::FindCamera(STR_String& name)
935 {
936         list<KX_Camera*>::iterator it = m_cameras.begin();
937
938         while ( (it != m_cameras.end()) 
939                         && ((*it)->GetName() != name) ) {
940           it++;
941         }
942
943         return ((it == m_cameras.end()) ? NULL : (*it));
944 }
945
946 void KX_Scene::AddCamera(KX_Camera* cam)
947 {
948         if (!FindCamera(cam))
949                 m_cameras.push_back(cam);
950 }
951
952
953 KX_Camera* KX_Scene::GetActiveCamera()
954 {       
955         // NULL if not defined
956         return m_active_camera;
957 }
958
959
960 void KX_Scene::SetActiveCamera(KX_Camera* cam)
961 {
962         // only set if the cam is in the active list? Or add it otherwise?
963         if (!FindCamera(cam)){
964                 AddCamera(cam);
965                 if (cam) std::cout << "Added cam " << cam->GetName() << std::endl;
966         } 
967
968         m_active_camera = cam;
969 }
970
971 void KX_Scene::SetCameraOnTop(KX_Camera* cam)
972 {
973         if (!FindCamera(cam)){
974                 // adding is always done at the back, so that's all that needs to be done
975                 AddCamera(cam);
976                 if (cam) std::cout << "Added cam " << cam->GetName() << std::endl;
977         } else {
978                 m_cameras.remove(cam);
979                 m_cameras.push_back(cam);
980         }
981 }
982
983
984 void KX_Scene::UpdateMeshTransformations()
985 {
986         // do this incrementally in the future
987         for (int i = 0; i < m_objectlist->GetCount(); i++)
988         {
989                 KX_GameObject* gameobj = (KX_GameObject*)m_objectlist->GetValue(i);
990                 gameobj->GetOpenGLMatrix();
991 //              gameobj->UpdateNonDynas();
992         }
993 }
994
995 void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam)
996 {
997         int intersect = KX_Camera::INTERSECT;
998         KX_GameObject *gameobj = node->Client()?(KX_GameObject*) node->Client()->GetSGClientObject():NULL;
999         bool dotest = (gameobj && gameobj->GetVisible()) || node->Left() || node->Right();
1000         
1001         /* If the camera is inside the box, assume intersect. */
1002         if (dotest && !node->inside( cam->NodeGetWorldPosition()))
1003         {
1004                 MT_Scalar radius = node->Radius();
1005                 MT_Point3 center = node->Center();
1006                 
1007                 intersect =  cam->SphereInsideFrustum(center, radius); 
1008                 
1009                 if (intersect == KX_Camera::INTERSECT)
1010                 {
1011                         MT_Point3 box[8];
1012                         node->get(box);
1013                         intersect = cam->BoxInsideFrustum(box);
1014                 }
1015         }
1016
1017         switch (intersect)
1018         {
1019                 case KX_Camera::OUTSIDE:
1020                         MarkSubTreeVisible(node, rasty, false, cam);
1021                         break;
1022                 case KX_Camera::INTERSECT:
1023                         if (gameobj)
1024                                 MarkVisible(rasty, gameobj,cam);
1025                         if (node->Left())
1026                                 MarkVisible(node->Left(), rasty,cam);
1027                         if (node->Right())
1028                                 MarkVisible(node->Right(), rasty,cam);
1029                         break;
1030                 case KX_Camera::INSIDE:
1031                         MarkSubTreeVisible(node, rasty, true,cam);
1032                         break;
1033         }
1034 }
1035
1036 void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible,KX_Camera* cam)
1037 {
1038         if (node->Client())
1039         {
1040                 KX_GameObject *gameobj = (KX_GameObject*) node->Client()->GetSGClientObject();
1041                 if (gameobj->GetVisible())
1042                 {
1043                         if (visible)
1044                         {
1045                                 int nummeshes = gameobj->GetMeshCount();
1046                                 MT_Transform t( cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform());
1047         
1048                                 
1049                                 for (int m=0;m<nummeshes;m++)
1050                                 {
1051                                         // this adds the vertices to the display list
1052                                         (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode());
1053                                 }
1054                         }
1055                         gameobj->MarkVisible(visible);
1056                 }
1057         }
1058         if (node->Left())
1059                 MarkSubTreeVisible(node->Left(), rasty, visible,cam);
1060         if (node->Right())
1061                 MarkSubTreeVisible(node->Right(), rasty, visible,cam);
1062 }
1063
1064 void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Camera*  cam)
1065 {
1066         // User (Python/Actuator) has forced object invisible...
1067         if (!gameobj->GetVisible())
1068                 return;
1069         // If Frustum culling is off, the object is always visible.
1070         bool vis = !cam->GetFrustumCulling();
1071         
1072         // If the camera is inside this node, then the object is visible.
1073         if (!vis)
1074         {
1075                 vis = gameobj->GetSGNode()->inside( GetActiveCamera()->GetCameraLocation() );
1076         }
1077                 
1078         // Test the object's bound sphere against the view frustum.
1079         if (!vis)
1080         {
1081                 MT_Vector3 scale = gameobj->GetSGNode()->GetWorldScaling();
1082                 MT_Scalar radius = fabs(scale[scale.closestAxis()] * gameobj->GetSGNode()->Radius());
1083                 switch (cam->SphereInsideFrustum(gameobj->NodeGetWorldPosition(), radius))
1084                 {
1085                         case KX_Camera::INSIDE:
1086                                 vis = true;
1087                                 break;
1088                         case KX_Camera::OUTSIDE:
1089                                 vis = false;
1090                                 break;
1091                         case KX_Camera::INTERSECT:
1092                                 // Test the object's bound box against the view frustum.
1093                                 MT_Point3 box[8];
1094                                 gameobj->GetSGNode()->getBBox(box); 
1095                                 vis = cam->BoxInsideFrustum(box) != KX_Camera::OUTSIDE;
1096                                 break;
1097                 }
1098         }
1099         
1100         if (vis)
1101         {
1102                 int nummeshes = gameobj->GetMeshCount();
1103                 MT_Transform t(cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform());
1104                 
1105                 for (int m=0;m<nummeshes;m++)
1106                 {
1107                         // this adds the vertices to the display list
1108                         (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode());
1109                 }
1110                 // Visibility/ non-visibility are marked
1111                 // elsewhere now.
1112                 gameobj->MarkVisible();
1113         } else {
1114                 gameobj->MarkVisible(false);
1115         }
1116 }
1117
1118 void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam)
1119 {
1120 // FIXME: When tree is operational
1121 #if 1
1122         // do this incrementally in the future
1123         for (int i = 0; i < m_objectlist->GetCount(); i++)
1124         {
1125                 MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam);
1126         }
1127 #else
1128         if (cam->GetFrustumCulling())
1129                 MarkVisible(m_objecttree, rasty, cam);
1130         else
1131                 MarkSubTreeVisible(m_objecttree, rasty, true, cam);
1132 #endif
1133 }
1134
1135 // logic stuff
1136 void KX_Scene::LogicBeginFrame(double curtime)
1137 {
1138         // have a look at temp objects ...
1139         int lastobj = m_tempObjectList->GetCount() - 1;
1140         
1141         for (int i = lastobj; i >= 0; i--)
1142         {
1143                 CValue* objval = m_tempObjectList->GetValue(i);
1144                 CFloatValue* propval = (CFloatValue*) objval->GetProperty("::timebomb");
1145                 
1146                 if (propval)
1147                 {
1148                         float timeleft = propval->GetNumber() - 1.0/KX_KetsjiEngine::GetTicRate();
1149                         
1150                         if (timeleft > 0)
1151                         {
1152                                 propval->SetFloat(timeleft);
1153                         }
1154                         else
1155                         {
1156                                 DelayedRemoveObject(objval);
1157                                 // remove obj
1158                         }
1159                 }
1160                 else
1161                 {
1162                         // all object is the tempObjectList should have a clock
1163                 }
1164         }
1165         m_logicmgr->BeginFrame(curtime, 1.0/KX_KetsjiEngine::GetTicRate());
1166 }
1167
1168
1169
1170 void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
1171 {
1172         m_logicmgr->UpdateFrame(curtime, frame);
1173 }
1174
1175
1176
1177 void KX_Scene::LogicEndFrame()
1178 {
1179         m_logicmgr->EndFrame();
1180         int numobj = m_euthanasyobjects->GetCount();
1181         int i;
1182         for (i = numobj - 1; i >= 0; i--)
1183         {
1184                 KX_GameObject* gameobj = (KX_GameObject*)m_euthanasyobjects->GetValue(i);
1185                 // KX_Scene::RemoveObject will also remove the object from this list
1186                 // that's why we start from the end
1187                 this->RemoveObject(gameobj);
1188         }
1189
1190         numobj= m_delayReleaseObjects->GetCount();
1191         for (i = numobj-1;i>=0;i--)
1192         {
1193                 KX_GameObject* gameobj = (KX_GameObject*)m_delayReleaseObjects->GetValue(i);
1194                 // This list is not for object removal, but just object release
1195                 gameobj->Release();
1196         }
1197         // empty the list as we have removed all references
1198         m_delayReleaseObjects->Resize(0);       
1199 }
1200
1201
1202
1203 /**
1204   * UpdateParents: SceneGraph transformation update.
1205   */
1206 void KX_Scene::UpdateParents(double curtime)
1207 {
1208 //      int numrootobjects = GetRootParentList()->GetCount();
1209
1210         for (int i=0; i<GetRootParentList()->GetCount(); i++)
1211         {
1212                 KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i);
1213                 parentobj->NodeUpdateGS(curtime,true);
1214         }
1215 }
1216
1217
1218
1219 RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool &bucketCreated)
1220 {
1221         return m_bucketmanager->RAS_BucketManagerFindBucket(polymat, bucketCreated);
1222 }
1223
1224
1225
1226 void KX_Scene::RenderBuckets(const MT_Transform & cameratransform,
1227                                                          class RAS_IRasterizer* rasty,
1228                                                          class RAS_IRenderTools* rendertools)
1229 {
1230         m_bucketmanager->Renderbuckets(cameratransform,rasty,rendertools);
1231 }
1232
1233
1234
1235 void KX_Scene::UpdateObjectActivity(void) 
1236 {
1237         if (m_activity_culling) {
1238                 /* determine the activity criterium and set objects accordingly */
1239                 int i=0;
1240                 
1241                 MT_Point3 camloc = GetActiveCamera()->NodeGetWorldPosition(); //GetCameraLocation();
1242                 
1243                 for (i=0;i<GetObjectList()->GetCount();i++)
1244                 {
1245                         KX_GameObject* ob = (KX_GameObject*) GetObjectList()->GetValue(i);
1246                         
1247                         if (!ob->GetIgnoreActivityCulling()) {
1248                                 /* Simple test: more than 10 away from the camera, count
1249                                  * Manhattan distance. */
1250                                 MT_Point3 obpos = ob->NodeGetWorldPosition();
1251                                 
1252                                 if ( (fabs(camloc[0] - obpos[0]) > m_activity_box_radius)
1253                                          || (fabs(camloc[1] - obpos[1]) > m_activity_box_radius)
1254                                          || (fabs(camloc[2] - obpos[2]) > m_activity_box_radius) )
1255                                 {                       
1256                                         ob->Suspend();
1257                                 } else {
1258                                         ob->Resume();
1259                                 }
1260                         }
1261                 }               
1262         }
1263 }
1264
1265 void KX_Scene::SetActivityCullingRadius(float f)
1266 {
1267         if (f < 0.5)
1268                 f = 0.5;
1269         m_activity_box_radius = f;
1270 }
1271         
1272 NG_NetworkDeviceInterface* KX_Scene::GetNetworkDeviceInterface()
1273 {
1274         return m_networkDeviceInterface;
1275 }
1276
1277 NG_NetworkScene* KX_Scene::GetNetworkScene()
1278 {
1279         return m_networkScene;
1280 }
1281
1282 void KX_Scene::SetNetworkDeviceInterface(NG_NetworkDeviceInterface* newInterface)
1283 {
1284         m_networkDeviceInterface = newInterface;
1285 }
1286
1287 void KX_Scene::SetNetworkScene(NG_NetworkScene *newScene)
1288 {
1289         m_networkScene = newScene;
1290 }
1291
1292
1293 void    KX_Scene::SetGravity(const MT_Vector3& gravity)
1294 {
1295         GetPhysicsEnvironment()->setGravity(gravity[0],gravity[1],gravity[2]);
1296 }
1297
1298 void KX_Scene::SetNodeTree(SG_Tree* root)
1299 {
1300         m_objecttree = root;
1301 }
1302
1303 void KX_Scene::SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter)
1304 {
1305         m_sceneConverter = sceneConverter;
1306 }
1307
1308 void KX_Scene::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv)
1309 {
1310         m_physicsEnvironment = physEnv;
1311
1312         KX_TouchEventManager* touchmgr = new KX_TouchEventManager(m_logicmgr, physEnv);
1313         m_logicmgr->RegisterEventManager(touchmgr);
1314         return;
1315 }
1316  
1317 void KX_Scene::setSuspendedTime(double suspendedtime)
1318 {
1319         m_suspendedtime = suspendedtime;
1320 }
1321 double KX_Scene::getSuspendedTime()
1322 {
1323         return m_suspendedtime;
1324 }
1325 void KX_Scene::setSuspendedDelta(double suspendeddelta)
1326 {
1327         m_suspendeddelta = suspendeddelta;
1328 }
1329 double KX_Scene::getSuspendedDelta()
1330 {
1331         return m_suspendeddelta;
1332 }
1333
1334 //----------------------------------------------------------------------------
1335 //Python
1336
1337 PyMethodDef KX_Scene::Methods[] = {
1338         KX_PYMETHODTABLE(KX_Scene, getLightList),
1339         KX_PYMETHODTABLE(KX_Scene, getObjectList),
1340         KX_PYMETHODTABLE(KX_Scene, getName),
1341         
1342         {NULL,NULL} //Sentinel
1343 };
1344
1345 PyTypeObject KX_Scene::Type = {
1346         PyObject_HEAD_INIT(&PyType_Type)
1347                 0,
1348                 "KX_Scene",
1349                 sizeof(KX_Scene),
1350                 0,
1351                 PyDestructor,
1352                 0,
1353                 __getattr,
1354                 __setattr,
1355                 0, //&MyPyCompare,
1356                 __repr,
1357                 0, //&cvalue_as_number,
1358                 0,
1359                 0,
1360                 0,
1361                 0, 0, 0, 0, 0, 0
1362 };
1363
1364 PyParentObject KX_Scene::Parents[] = {
1365         &KX_Scene::Type,
1366                 &CValue::Type,
1367                 NULL
1368 };
1369
1370 PyObject* KX_Scene::_getattr(const STR_String& attr)
1371 {
1372         if (attr == "name")
1373                 return PyString_FromString(GetName());
1374         
1375         if (attr == "active_camera")
1376         {
1377                 KX_Camera *camera = GetActiveCamera();
1378                 camera->AddRef();
1379                 return (PyObject*) camera;
1380         }
1381         
1382         if (attr == "suspended")
1383                 return PyInt_FromLong(m_suspend);
1384         
1385         if (attr == "activity_culling")
1386                 return PyInt_FromLong(m_activity_culling);
1387         
1388         if (attr == "activity_culling_radius")
1389                 return PyFloat_FromDouble(m_activity_box_radius);
1390         
1391         PyObject* value = PyDict_GetItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()));
1392         if (value)
1393         {
1394                 Py_INCREF(value);
1395                 return value;
1396         }
1397         
1398         _getattr_up(PyObjectPlus);
1399 }
1400
1401 int KX_Scene::_delattr(const STR_String &attr)
1402 {
1403         PyDict_DelItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()));
1404         return 0;
1405 }
1406
1407 int KX_Scene::_setattr(const STR_String &attr, PyObject *pyvalue)
1408 {
1409
1410         if (!PyDict_SetItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()), pyvalue))
1411                 return 0;
1412
1413         return PyObjectPlus::_setattr(attr, pyvalue);
1414 }
1415
1416 KX_PYMETHODDEF_DOC(KX_Scene, getLightList,
1417 "getLightList() -> list [KX_Light]\n"
1418 "Returns a list of all lights in the scene.\n"
1419 )
1420 {
1421         m_lightlist->AddRef();
1422         return (PyObject*) m_lightlist;
1423 }
1424
1425 KX_PYMETHODDEF_DOC(KX_Scene, getObjectList,
1426 "getObjectList() -> list [KX_GameObject]\n"
1427 "Returns a list of all game objects in the scene.\n"
1428 )
1429 {
1430         m_objectlist->AddRef();
1431         return (PyObject*) m_objectlist;
1432 }
1433
1434 KX_PYMETHODDEF_DOC(KX_Scene, getName,
1435 "getName() -> string\n"
1436 "Returns the name of the scene.\n"
1437 )
1438 {
1439         return PyString_FromString(GetName());
1440 }