BGE Scenegraph and View frustrum culling improvement.
[blender-staging.git] / source / gameengine / Ketsji / KX_KetsjiEngine.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  * The engine ties all game modules together. 
29  */
30
31 #ifdef WIN32
32 #pragma warning (disable : 4786)
33 #endif //WIN32
34
35 #include <iostream>
36
37 #include "KX_KetsjiEngine.h"
38
39 #include "ListValue.h"
40 #include "IntValue.h"
41 #include "VectorValue.h"
42 #include "BoolValue.h"
43 #include "FloatValue.h"
44
45 #define KX_NUM_ITERATIONS 4
46 #include "RAS_BucketManager.h"
47 #include "RAS_Rect.h"
48 #include "RAS_IRasterizer.h"
49 #include "RAS_IRenderTools.h"
50 #include "RAS_ICanvas.h"
51 #include "STR_String.h"
52 #include "MT_Vector3.h"
53 #include "MT_Transform.h"
54 #include "SCA_IInputDevice.h"
55 #include "KX_Scene.h"
56 #include "MT_CmMatrix4x4.h"
57 #include "KX_Camera.h"
58 #include "KX_Light.h"
59 #include "KX_PythonInit.h"
60 #include "KX_PyConstraintBinding.h"
61 #include "PHY_IPhysicsEnvironment.h"
62
63 #ifdef USE_SUMO_SOLID
64 #include "SumoPhysicsEnvironment.h"
65 #endif
66
67 #include "SND_Scene.h"
68 #include "SND_IAudioDevice.h"
69
70 #include "NG_NetworkScene.h"
71 #include "NG_NetworkDeviceInterface.h"
72
73 #include "KX_WorldInfo.h"
74 #include "KX_ISceneConverter.h"
75 #include "KX_TimeCategoryLogger.h"
76
77 #include "RAS_FramingManager.h"
78 #include "stdio.h"
79
80 // If define: little test for Nzc: guarded drawing. If the canvas is
81 // not valid, skip rendering this frame.
82 //#define NZC_GUARDED_OUTPUT
83 #define DEFAULT_LOGIC_TIC_RATE 60.0
84 #define DEFAULT_PHYSICS_TIC_RATE 60.0
85
86 const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
87         "Physics:",             // tc_physics
88         "Logic",                // tc_logic
89         "Network:",             // tc_network
90         "Scenegraph:",  // tc_scenegraph
91         "Sound:",               // tc_sound
92         "Rasterizer:",  // tc_rasterizer
93         "Services:",    // tc_services
94         "Overhead:",    // tc_overhead
95         "Outside:"              // tc_outside
96 };
97
98 double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;
99 double KX_KetsjiEngine::m_anim_framerate = 25.0;
100 double KX_KetsjiEngine::m_suspendedtime = 0.0;
101 double KX_KetsjiEngine::m_suspendeddelta = 0.0;
102 double KX_KetsjiEngine::m_average_framerate = 0.0;
103
104
105 /**
106  *      Constructor of the Ketsji Engine
107  */
108 KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
109      :  m_canvas(NULL),
110         m_rasterizer(NULL),
111         m_kxsystem(system),
112         m_rendertools(NULL),
113         m_sceneconverter(NULL),
114         m_networkdevice(NULL),
115         m_audiodevice(NULL),
116         m_pythondictionary(NULL),
117         m_keyboarddevice(NULL),
118         m_mousedevice(NULL),
119
120         m_propertiesPresent(false),
121
122         m_bInitialized(false),
123         m_activecam(0),
124         m_bFixedTime(false),
125         
126         m_firstframe(true),
127         
128         m_frameTime(0.f),
129         m_clockTime(0.f),
130         m_previousClockTime(0.f),
131
132
133         m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
134         m_exitstring(""),
135         
136         m_drawingmode(5),
137         m_cameraZoom(1.0),
138         
139         m_overrideCam(false),
140         m_overrideCamUseOrtho(false),
141         m_overrideCamNear(0.0),
142         m_overrideCamFar(0.0),
143
144         m_stereo(false),
145         m_curreye(0),
146
147         m_logger(NULL),
148         
149         // Set up timing info display variables
150         m_show_framerate(false),
151         m_show_profile(false),
152         m_showProperties(false),
153         m_showBackground(false),
154         m_show_debug_properties(false),
155
156         m_game2ipo(false),
157
158         // Default behavior is to hide the cursor every frame.
159         m_hideCursor(false),
160
161         m_overrideFrameColor(false),
162         m_overrideFrameColorR(0.0),
163         m_overrideFrameColorG(0.0),
164         m_overrideFrameColorB(0.0)
165 {
166         // Initialize the time logger
167         m_logger = new KX_TimeCategoryLogger (25);
168
169         for (int i = tc_first; i < tc_numCategories; i++)
170                 m_logger->AddCategory((KX_TimeCategory)i);
171                 
172 }
173
174
175
176 /**
177  *      Destructor of the Ketsji Engine, release all memory
178  */
179 KX_KetsjiEngine::~KX_KetsjiEngine()
180 {
181         delete m_logger;
182 }
183
184
185
186 void KX_KetsjiEngine::SetKeyboardDevice(SCA_IInputDevice* keyboarddevice)
187 {
188         MT_assert(keyboarddevice);
189         m_keyboarddevice = keyboarddevice;
190 }
191
192
193
194 void KX_KetsjiEngine::SetMouseDevice(SCA_IInputDevice* mousedevice)
195 {
196         MT_assert(mousedevice);
197         m_mousedevice = mousedevice;
198 }
199
200
201
202 void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice)
203 {
204         MT_assert(networkdevice);
205         m_networkdevice = networkdevice;
206 }
207
208
209
210 void KX_KetsjiEngine::SetAudioDevice(SND_IAudioDevice* audiodevice)
211 {
212         MT_assert(audiodevice);
213         m_audiodevice = audiodevice;
214 }
215
216
217
218 void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas)
219 {
220         MT_assert(canvas);
221         m_canvas = canvas;
222 }
223
224
225
226 void KX_KetsjiEngine::SetRenderTools(RAS_IRenderTools* rendertools)
227 {
228         MT_assert(rendertools);
229         m_rendertools = rendertools;
230 }
231
232
233
234 void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer)
235 {
236         MT_assert(rasterizer);
237         m_rasterizer = rasterizer;
238 }
239
240
241 /*
242  * At the moment the GameLogic module is imported into 'pythondictionary' after this function is called.
243  * if this function ever changes to assign a copy, make sure the game logic module is imported into this dictionary before hand.
244  */
245 void KX_KetsjiEngine::SetPythonDictionary(PyObject* pythondictionary)
246 {
247         MT_assert(pythondictionary);
248         m_pythondictionary = pythondictionary;
249 }
250
251
252
253 void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter)
254 {
255         MT_assert(sceneconverter);
256         m_sceneconverter = sceneconverter;
257 }
258
259
260
261 /**
262  * Ketsji Init(), Initializes datastructures and converts data from
263  * Blender into Ketsji native (realtime) format also sets up the
264  * graphics context
265  */
266 void KX_KetsjiEngine::StartEngine(bool clearIpo)
267 {
268         m_clockTime = m_kxsystem->GetTimeInSeconds();
269         m_frameTime = m_kxsystem->GetTimeInSeconds();
270         m_previousClockTime = m_kxsystem->GetTimeInSeconds();
271
272         m_firstframe = true;
273         m_bInitialized = true;
274         m_ticrate = DEFAULT_LOGIC_TIC_RATE;
275         
276         if (m_game2ipo)
277         {
278                 m_sceneconverter->ResetPhysicsObjectsAnimationIpo(clearIpo);
279                 m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame);
280         }
281
282 }
283
284 void KX_KetsjiEngine::ClearFrame()
285 {
286         // clear unless we're drawing overlapping stereo
287         if(m_rasterizer->InterlacedStereo() &&
288                 m_rasterizer->GetEye() == RAS_IRasterizer::RAS_STEREO_RIGHTEYE)
289                 return;
290
291         // clear the viewports with the background color of the first scene
292         bool doclear = false;
293         KX_SceneList::iterator sceneit;
294         RAS_Rect clearvp, area, viewport;
295
296         for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++)
297         {
298                 KX_Scene* scene = *sceneit;
299                 //const RAS_FrameSettings &framesettings = scene->GetFramingType();
300                 list<class KX_Camera*>* cameras = scene->GetCameras();
301
302                 list<KX_Camera*>::iterator it;
303                 for(it = cameras->begin(); it != cameras->end(); it++)
304                 {
305                         GetSceneViewport(scene, (*it), area, viewport);
306
307                         if(!doclear) {
308                                 clearvp = viewport;
309                                 doclear = true;
310                         }
311                         else {
312                                 if(viewport.GetLeft() < clearvp.GetLeft())
313                                         clearvp.SetLeft(viewport.GetLeft());
314                                 if(viewport.GetBottom() < clearvp.GetBottom())
315                                         clearvp.SetBottom(viewport.GetBottom());
316                                 if(viewport.GetRight() > clearvp.GetRight())
317                                         clearvp.SetRight(viewport.GetRight());
318                                 if(viewport.GetTop() > clearvp.GetTop())
319                                         clearvp.SetTop(viewport.GetTop());
320
321                         }
322                 }
323         }
324
325         if(doclear) {
326                 KX_Scene* firstscene = *m_scenes.begin();
327                 SetBackGround(firstscene->GetWorldInfo());
328
329                 m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(),
330                         clearvp.GetRight(), clearvp.GetTop());  
331                 m_rasterizer->ClearColorBuffer();
332         }
333 }
334
335 bool KX_KetsjiEngine::BeginFrame()
336 {
337         // set the area used for rendering (stereo can assign only a subset)
338         m_rasterizer->SetRenderArea();
339
340         if (m_canvas->BeginDraw())
341         {
342                 ClearFrame();
343
344                 m_rasterizer->BeginFrame(m_drawingmode , m_kxsystem->GetTimeInSeconds());
345                 m_rendertools->BeginFrame(m_rasterizer);
346
347                 return true;
348         }
349         
350         return false;
351 }               
352
353
354 void KX_KetsjiEngine::EndFrame()
355 {
356         // Show profiling info
357         m_logger->StartLog(tc_overhead, m_kxsystem->GetTimeInSeconds(), true);
358         if (m_show_framerate || m_show_profile || (m_show_debug_properties && m_propertiesPresent))
359         {
360                 RenderDebugProperties();
361         }
362
363         m_average_framerate = m_logger->GetAverage();
364         if (m_average_framerate < 1e-6)
365                 m_average_framerate = 1e-6;
366         m_average_framerate = 1.0/m_average_framerate;
367
368         // Go to next profiling measurement, time spend after this call is shown in the next frame.
369         m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds());
370
371         m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
372         m_rasterizer->EndFrame();
373         // swap backbuffer (drawing into this buffer) <-> front/visible buffer
374         m_rasterizer->SwapBuffers();
375         m_rendertools->EndFrame(m_rasterizer);
376
377         
378         m_canvas->EndDraw();
379 }
380
381 //#include "PIL_time.h"
382 //#include "LinearMath/btQuickprof.h"
383
384
385 bool KX_KetsjiEngine::NextFrame()
386 {
387
388 //      static hidden::Clock sClock;
389
390 m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true);
391
392 //float dt = sClock.getTimeMicroseconds() * 0.000001f;
393 //sClock.reset();
394
395 if (m_bFixedTime)
396         m_clockTime += 1./m_ticrate;
397 else
398 {
399
400 //      m_clockTime += dt;
401         m_clockTime = m_kxsystem->GetTimeInSeconds();
402 }
403         
404         double deltatime = m_clockTime - m_frameTime;
405         if (deltatime<0.f)
406         {
407                 printf("problem with clock\n");
408                 deltatime = 0.f;
409                 m_clockTime = 0.f;
410                 m_frameTime = 0.f;
411         }
412
413
414         // Compute the number of logic frames to do each update (fixed tic bricks)
415         int frames =int(deltatime*m_ticrate+1e-6);
416 //      if (frames>1)
417 //              printf("****************************************");
418 //      printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
419         
420 //      if (!frames)
421 //              PIL_sleep_ms(1);
422         
423         KX_SceneList::iterator sceneit;
424         int frameOut = 5;
425         
426         if (frames>frameOut)
427         {
428         
429         //      printf("framedOut: %d\n",frames);
430                 m_frameTime+=(frames-frameOut)*(1.0/m_ticrate);
431                 frames = frameOut;
432         }
433         
434
435         bool doRender = frames>0;
436
437         while (frames)
438         {
439         
440
441                 m_frameTime += 1.0/m_ticrate;
442                 
443                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
444                 // for each scene, call the proceed functions
445                 {
446                         KX_Scene* scene = *sceneit;
447         
448                         /* Suspension holds the physics and logic processing for an
449                         * entire scene. Objects can be suspended individually, and
450                         * the settings for that preceed the logic and physics
451                         * update. */
452                         m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
453
454                         m_sceneconverter->resetNoneDynamicObjectToIpo();//this is for none dynamic objects with ipo
455
456                         scene->UpdateObjectActivity();
457         
458                         if (!scene->IsSuspended())
459                         {
460                                 // if the scene was suspended recalcutlate the delta tu "curtime"
461                                 m_suspendedtime = scene->getSuspendedTime();
462                                 if (scene->getSuspendedTime()!=0.0)
463                                         scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
464                                 m_suspendeddelta = scene->getSuspendedDelta();
465
466                                 
467                                 m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
468                                 SG_SetActiveStage(SG_STAGE_NETWORK);
469                                 scene->GetNetworkScene()->proceed(m_frameTime);
470         
471                                 //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
472                                 //SG_SetActiveStage(SG_STAGE_NETWORK_UPDATE);
473                                 //scene->UpdateParents(m_frameTime);
474                                 
475                                 m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
476                                 SG_SetActiveStage(SG_STAGE_PHYSICS1);
477                                 // set Python hooks for each scene
478                                 PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
479                                 KX_SetActiveScene(scene);
480         
481                                 scene->GetPhysicsEnvironment()->endFrame();
482                                 
483                                 // Update scenegraph after physics step. This maps physics calculations
484                                 // into node positions.         
485                                 //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
486                                 //SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE);
487                                 //scene->UpdateParents(m_frameTime);
488                                 
489                                 // Process sensors, and controllers
490                                 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
491                                 SG_SetActiveStage(SG_STAGE_CONTROLLER);
492                                 scene->LogicBeginFrame(m_frameTime);
493         
494                                 // Scenegraph needs to be updated again, because Logic Controllers 
495                                 // can affect the local matrices.
496                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
497                                 SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE);
498                                 scene->UpdateParents(m_frameTime);
499         
500                                 // Process actuators
501         
502                                 // Do some cleanup work for this logic frame
503                                 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
504                                 SG_SetActiveStage(SG_STAGE_ACTUATOR);
505                                 scene->LogicUpdateFrame(m_frameTime, true);
506                                 
507                                 scene->LogicEndFrame();
508         
509                                 // Actuators can affect the scenegraph
510                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
511                                 SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE);
512                                 scene->UpdateParents(m_frameTime);
513                                 
514                                 m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
515                                 SG_SetActiveStage(SG_STAGE_PHYSICS2);
516                                 scene->GetPhysicsEnvironment()->beginFrame();
517                 
518                                 // Perform physics calculations on the scene. This can involve 
519                                 // many iterations of the physics solver.
520                                 scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,1.0/m_ticrate);//m_deltatimerealDeltaTime);
521
522                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
523                                 SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE);
524                                 scene->UpdateParents(m_frameTime);
525                         
526                         
527                                 if (m_game2ipo)
528                                 {                                       
529                                         m_sceneconverter->WritePhysicsObjectToAnimationIpo(++m_currentFrame);
530                                 }
531
532                                 scene->setSuspendedTime(0.0);
533                         } // suspended
534                         else
535                                 if(scene->getSuspendedTime()==0.0)
536                                         scene->setSuspendedTime(m_clockTime);
537         
538                         DoSound(scene);
539                         
540                         m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
541                 }
542
543                 // update system devices
544                 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
545                 if (m_keyboarddevice)
546                         m_keyboarddevice->NextFrame();
547         
548                 if (m_mousedevice)
549                         m_mousedevice->NextFrame();
550                 
551                 if (m_networkdevice)
552                         m_networkdevice->NextFrame();
553         
554                 if (m_audiodevice)
555                         m_audiodevice->NextFrame();
556         
557                 // scene management
558                 ProcessScheduledScenes();
559                 
560                 frames--;
561         }
562
563         bool bUseAsyncLogicBricks= false;//true;
564
565         if (bUseAsyncLogicBricks)
566         {       
567                 // Logic update sub frame: this will let some logic bricks run at the
568                 // full frame rate.
569                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
570                 // for each scene, call the proceed functions
571                 {
572                         KX_Scene* scene = *sceneit;
573
574                         if (!scene->IsSuspended())
575                         {
576                                 // if the scene was suspended recalcutlate the delta tu "curtime"
577                                 m_suspendedtime = scene->getSuspendedTime();
578                                 if (scene->getSuspendedTime()!=0.0)
579                                         scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
580                                 m_suspendeddelta = scene->getSuspendedDelta();
581                                 
582                                 // set Python hooks for each scene
583                                 PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
584                                 KX_SetActiveScene(scene);
585                                 
586                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
587                                 SG_SetActiveStage(SG_STAGE_PHYSICS1);
588                                 scene->UpdateParents(m_clockTime);
589
590                                 // Perform physics calculations on the scene. This can involve 
591                                 // many iterations of the physics solver.
592                                 m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
593                                 scene->GetPhysicsEnvironment()->proceedDeltaTime(m_clockTime,0.f);
594                                 // Update scenegraph after physics step. This maps physics calculations
595                                 // into node positions.         
596                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
597                                 SG_SetActiveStage(SG_STAGE_PHYSICS2);
598                                 scene->UpdateParents(m_clockTime);
599                                 
600                                 // Do some cleanup work for this logic frame
601                                 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
602                                 scene->LogicUpdateFrame(m_clockTime, false);
603
604                                 // Actuators can affect the scenegraph
605                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
606                                 SG_SetActiveStage(SG_STAGE_ACTUATOR);
607                                 scene->UpdateParents(m_clockTime);
608                                  
609                                 scene->setSuspendedTime(0.0);
610                         } // suspended
611                         else
612                                 if(scene->getSuspendedTime()==0.0)
613                                         scene->setSuspendedTime(m_clockTime);
614
615                         DoSound(scene);
616
617                         m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
618                 }
619         }
620
621
622         m_previousClockTime = m_clockTime;
623         
624         // Start logging time spend outside main loop
625         m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
626         
627         return doRender;
628 }
629
630
631
632 void KX_KetsjiEngine::Render()
633 {
634         KX_Scene* firstscene = *m_scenes.begin();
635         const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
636
637         m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
638         SG_SetActiveStage(SG_STAGE_RENDER);
639
640         // hiding mouse cursor each frame
641         // (came back when going out of focus and then back in again)
642         if (m_hideCursor)
643                 m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
644
645         // clear the entire game screen with the border color
646         // only once per frame
647         m_canvas->BeginDraw();
648         if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED) {
649                 m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
650                 if (m_overrideFrameColor)
651                 {
652                         // Do not use the framing bar color set in the Blender scenes
653                         m_canvas->ClearColor(
654                                 m_overrideFrameColorR,
655                                 m_overrideFrameColorG,
656                                 m_overrideFrameColorB,
657                                 1.0
658                                 );
659                 }
660                 else
661                 {
662                         // Use the framing bar color set in the Blender scenes
663                         m_canvas->ClearColor(
664                                 framesettings.BarRed(),
665                                 framesettings.BarGreen(),
666                                 framesettings.BarBlue(),
667                                 1.0
668                                 );
669                 }
670                 // clear the -whole- viewport
671                 m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
672         }
673
674         m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
675
676         // BeginFrame() sets the actual drawing area. You can use a part of the window
677         if (!BeginFrame())
678                 return;
679
680         KX_SceneList::iterator sceneit;
681         for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
682         // for each scene, call the proceed functions
683         {
684                 KX_Scene* scene = *sceneit;
685                 KX_Camera* cam = scene->GetActiveCamera();
686                 // pass the scene's worldsettings to the rasterizer
687                 SetWorldSettings(scene->GetWorldInfo());
688
689                 // shadow buffers
690                 RenderShadowBuffers(scene);
691
692                 // Avoid drawing the scene with the active camera twice when it's viewport is enabled
693                 if(cam && !cam->GetViewport())
694                 {
695                         if (scene->IsClearingZBuffer())
696                                 m_rasterizer->ClearDepthBuffer();
697         
698                         m_rendertools->SetAuxilaryClientInfo(scene);
699         
700                         // do the rendering
701                         RenderFrame(scene, cam);
702                 }
703                 
704                 list<class KX_Camera*>* cameras = scene->GetCameras();
705                 
706                 // Draw the scene once for each camera with an enabled viewport
707                 list<KX_Camera*>::iterator it = cameras->begin();
708                 while(it != cameras->end())
709                 {
710                         if((*it)->GetViewport())
711                         {
712                                 if (scene->IsClearingZBuffer())
713                                         m_rasterizer->ClearDepthBuffer();
714                 
715                                 m_rendertools->SetAuxilaryClientInfo(scene);
716                 
717                                 // do the rendering
718                                 RenderFrame(scene, (*it));
719                         }
720                         
721                         it++;
722                 }
723         }
724
725         // only one place that checks for stereo
726         if(m_rasterizer->Stereo())
727         {
728                 m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
729
730                 if (!BeginFrame())
731                         return;
732
733
734                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
735                 // for each scene, call the proceed functions
736                 {
737                         KX_Scene* scene = *sceneit;
738                         KX_Camera* cam = scene->GetActiveCamera();
739
740                         // pass the scene's worldsettings to the rasterizer
741                         SetWorldSettings(scene->GetWorldInfo());
742                 
743                         if (scene->IsClearingZBuffer())
744                                 m_rasterizer->ClearDepthBuffer();
745
746                         //pass the scene, for picking and raycasting (shadows)
747                         m_rendertools->SetAuxilaryClientInfo(scene);
748
749                         // do the rendering
750                         //RenderFrame(scene);
751                         RenderFrame(scene, cam);
752
753                         list<class KX_Camera*>* cameras = scene->GetCameras();                  
754         
755                         // Draw the scene once for each camera with an enabled viewport
756                         list<KX_Camera*>::iterator it = cameras->begin();
757                         while(it != cameras->end())
758                         {
759                                 if((*it)->GetViewport())
760                                 {
761                                         if (scene->IsClearingZBuffer())
762                                                 m_rasterizer->ClearDepthBuffer();
763                         
764                                         m_rendertools->SetAuxilaryClientInfo(scene);
765                         
766                                         // do the rendering
767                                         RenderFrame(scene, (*it));
768                                 }
769                                 
770                                 it++;
771                         }
772                 }
773         } // if(m_rasterizer->Stereo())
774
775         EndFrame();
776 }
777
778
779
780 void KX_KetsjiEngine::RequestExit(int exitrequestmode)
781 {
782         m_exitcode = exitrequestmode;
783 }
784
785
786
787 void KX_KetsjiEngine::SetNameNextGame(const STR_String& nextgame)
788 {
789         m_exitstring = nextgame;
790 }
791
792
793
794 int KX_KetsjiEngine::GetExitCode()
795 {
796         // if a gameactuator has set an exitcode or if there are no scenes left
797         if (!m_exitcode)
798         {
799                 if (m_scenes.begin()==m_scenes.end())
800                         m_exitcode = KX_EXIT_REQUEST_NO_SCENES_LEFT;
801         }
802
803         return m_exitcode;
804 }
805
806
807
808 const STR_String& KX_KetsjiEngine::GetExitString()
809 {
810         return m_exitstring;
811 }
812
813
814
815 void KX_KetsjiEngine::DoSound(KX_Scene* scene)
816 {
817         m_logger->StartLog(tc_sound, m_kxsystem->GetTimeInSeconds(), true);
818
819         KX_Camera* cam = scene->GetActiveCamera();
820         if (!cam)
821                 return;
822         MT_Point3 listenerposition = cam->NodeGetWorldPosition();
823         MT_Vector3 listenervelocity = cam->GetLinearVelocity();
824         MT_Matrix3x3 listenerorientation = cam->NodeGetWorldOrientation();
825
826         SND_Scene* soundscene = scene->GetSoundScene();
827         soundscene->SetListenerTransform(
828                 listenerposition,
829                 listenervelocity,
830                 listenerorientation);
831
832         soundscene->Proceed();
833 }
834
835
836
837 void KX_KetsjiEngine::SetBackGround(KX_WorldInfo* wi)
838 {
839         if (wi->hasWorld())
840         {
841                 if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED)
842                 {       
843                         m_rasterizer->SetBackColor(
844                                 wi->getBackColorRed(),
845                                 wi->getBackColorGreen(),
846                                 wi->getBackColorBlue(),
847                                 0.0
848                         );
849                 }
850         }
851 }
852
853
854
855 void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi)
856 {
857         if (wi->hasWorld())
858         {
859                 // ...
860                 m_rasterizer->SetAmbientColor(
861                         wi->getAmbientColorRed(),
862                         wi->getAmbientColorGreen(),
863                         wi->getAmbientColorBlue()
864                 );
865
866                 if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED)
867                 {       
868                         if (wi->hasMist())
869                         {
870                                 m_rasterizer->SetFog(
871                                         wi->getMistStart(),
872                                         wi->getMistDistance(),
873                                         wi->getMistColorRed(),
874                                         wi->getMistColorGreen(),
875                                         wi->getMistColorBlue()
876                                 );
877                         }
878                         else
879                         {
880                                 m_rasterizer->DisableFog();
881                         }
882                 }
883         }
884 }
885
886
887
888 void KX_KetsjiEngine::SetDrawType(int drawingmode)
889 {
890         m_drawingmode = drawingmode;
891 }
892
893
894         
895 void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene)
896 {
897         m_overrideCam = true;
898         m_overrideSceneName = forscene;
899 }
900
901
902
903 void KX_KetsjiEngine::SetCameraZoom(float camzoom)
904 {
905         m_cameraZoom = camzoom;
906 }
907
908
909
910 void KX_KetsjiEngine::SetCameraOverrideUseOrtho(bool useOrtho)
911 {
912         m_overrideCamUseOrtho = useOrtho;
913 }
914
915
916
917 void KX_KetsjiEngine::SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat)
918 {
919         m_overrideCamProjMat = mat;
920 }
921
922
923 void KX_KetsjiEngine::SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat)
924 {
925         m_overrideCamViewMat = mat;
926 }
927
928 void KX_KetsjiEngine::SetCameraOverrideClipping(float near, float far)
929 {
930         m_overrideCamNear = near;
931         m_overrideCamFar = far;
932 }
933
934 void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport)
935 {
936         // In this function we make sure the rasterizer settings are upto
937         // date. We compute the viewport so that logic
938         // using this information is upto date.
939
940         // Note we postpone computation of the projection matrix
941         // so that we are using the latest camera position.
942         if (cam->GetViewport()) {
943                 RAS_Rect userviewport;
944
945                 userviewport.SetLeft(cam->GetViewportLeft()); 
946                 userviewport.SetBottom(cam->GetViewportBottom());
947                 userviewport.SetRight(cam->GetViewportRight());
948                 userviewport.SetTop(cam->GetViewportTop());
949
950                 // Don't do bars on user specified viewport
951                 RAS_FrameSettings settings = scene->GetFramingType();
952                 if(settings.FrameType() == RAS_FrameSettings::e_frame_bars)
953                         settings.SetFrameType(RAS_FrameSettings::e_frame_extend);
954
955                 RAS_FramingManager::ComputeViewport(
956                         scene->GetFramingType(),
957                         userviewport,
958                         viewport
959                 );
960
961                 area = userviewport;
962         }
963         else if ( m_overrideCam || (scene->GetName() != m_overrideSceneName) ||  m_overrideCamUseOrtho ) {
964                 RAS_FramingManager::ComputeViewport(
965                         scene->GetFramingType(),
966                         m_canvas->GetDisplayArea(),
967                         viewport
968                 );
969
970                 area = m_canvas->GetDisplayArea();
971         } else {
972                 viewport.SetLeft(0); 
973                 viewport.SetBottom(0);
974                 viewport.SetRight(int(m_canvas->GetWidth()));
975                 viewport.SetTop(int(m_canvas->GetHeight()));
976
977                 area = m_canvas->GetDisplayArea();
978         }
979 }
980
981 void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
982 {
983         CListValue *objectlist = scene->GetObjectList();
984         int i, drawmode;
985
986         m_rendertools->SetAuxilaryClientInfo(scene);
987
988         for(i=0; i<objectlist->GetCount(); i++) {
989                 KX_GameObject *gameobj = (KX_GameObject*)objectlist->GetValue(i);
990
991                 if(!gameobj->IsLight())
992                         continue;
993
994                 KX_LightObject *light = (KX_LightObject*)gameobj;
995
996                 light->Update();
997
998                 if(m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) {
999                         /* make temporary camera */
1000                         RAS_CameraData camdata = RAS_CameraData();
1001                         KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, false);
1002                         cam->SetName("__shadow__cam__");
1003
1004                         MT_Transform camtrans;
1005
1006                         /* switch drawmode for speed */
1007                         drawmode = m_rasterizer->GetDrawingMode();
1008                         m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW);
1009
1010                         /* binds framebuffer object, sets up camera .. */
1011                         light->BindShadowBuffer(m_rasterizer, cam, camtrans);
1012
1013                         /* update scene */
1014                         scene->UpdateMeshTransformations();
1015                         scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer());
1016
1017                         /* render */
1018                         m_rasterizer->ClearDepthBuffer();
1019                         scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
1020
1021                         /* unbind framebuffer object, restore drawmode, free camera */
1022                         light->UnbindShadowBuffer(m_rasterizer);
1023                         m_rasterizer->SetDrawingMode(drawmode);
1024                         cam->Release();
1025                 }
1026         }
1027 }
1028         
1029 // update graphics
1030 void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
1031 {
1032         bool override_camera;
1033         RAS_Rect viewport, area;
1034         float left, right, bottom, top, nearfrust, farfrust, focallength;
1035         const float ortho = 100.0;
1036 //      KX_Camera* cam = scene->GetActiveCamera();
1037         
1038         if (!cam)
1039                 return;
1040
1041         GetSceneViewport(scene, cam, area, viewport);
1042
1043         // store the computed viewport in the scene
1044         scene->SetSceneViewport(viewport);      
1045
1046         // set the viewport for this frame and scene
1047         m_canvas->SetViewPort(viewport.GetLeft(), viewport.GetBottom(),
1048                 viewport.GetRight(), viewport.GetTop());        
1049         
1050         // see KX_BlenderMaterial::Activate
1051         //m_rasterizer->SetAmbient();
1052         m_rasterizer->DisplayFog();
1053
1054         override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName);
1055         override_camera = override_camera && (cam->GetName() == "__default__cam__");
1056
1057         if (override_camera && m_overrideCamUseOrtho) {
1058                 MT_CmMatrix4x4 projmat = m_overrideCamProjMat;
1059                 m_rasterizer->SetProjectionMatrix(projmat);
1060         } else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() )
1061         {
1062                 m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
1063         } else
1064         {
1065                 RAS_FrameFrustum frustum;
1066                 float lens = cam->GetLens();
1067                 bool orthographic = !cam->GetCameraData()->m_perspective;
1068                 nearfrust = cam->GetCameraNear();
1069                 farfrust = cam->GetCameraFar();
1070                 focallength = cam->GetFocalLength();
1071
1072                 if(override_camera) {
1073                         nearfrust = m_overrideCamNear;
1074                         farfrust = m_overrideCamFar;
1075                 }
1076
1077                 if (orthographic) {
1078                         lens *= ortho;
1079                         nearfrust = (nearfrust + 1.0)*ortho;
1080                         farfrust *= ortho;
1081                 }
1082                 
1083                 RAS_FramingManager::ComputeFrustum(
1084                         scene->GetFramingType(),
1085                         area,
1086                         viewport,
1087                         lens,
1088                         nearfrust,
1089                         farfrust,
1090                         frustum
1091                 );
1092
1093                 left = frustum.x1 * m_cameraZoom;
1094                 right = frustum.x2 * m_cameraZoom;
1095                 bottom = frustum.y1 * m_cameraZoom;
1096                 top = frustum.y2 * m_cameraZoom;
1097                 nearfrust = frustum.camnear;
1098                 farfrust = frustum.camfar;
1099
1100                 MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
1101                         left, right, bottom, top, nearfrust, farfrust, focallength);
1102
1103                 cam->SetProjectionMatrix(projmat);
1104                 
1105                 // Otherwise the projection matrix for each eye will be the same...
1106                 if (m_rasterizer->Stereo())
1107                         cam->InvalidateProjectionMatrix();
1108         }
1109
1110         MT_Transform camtrans(cam->GetWorldToCamera());
1111         if (!cam->GetCameraData()->m_perspective)
1112                 camtrans.getOrigin()[2] *= ortho;
1113         MT_Matrix4x4 viewmat(camtrans);
1114         
1115         m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
1116                 cam->GetCameraLocation(), cam->GetCameraOrientation());
1117         cam->SetModelviewMatrix(viewmat);
1118
1119         //redundant, already done in 
1120         //scene->UpdateMeshTransformations();
1121
1122         // The following actually reschedules all vertices to be
1123         // redrawn. There is a cache between the actual rescheduling
1124         // and this call though. Visibility is imparted when this call
1125         // runs through the individual objects.
1126
1127         m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
1128         SG_SetActiveStage(SG_STAGE_CULLING);
1129
1130         scene->CalculateVisibleMeshes(m_rasterizer,cam);
1131
1132         m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
1133         SG_SetActiveStage(SG_STAGE_RENDER);
1134
1135         scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
1136         
1137         if (scene->GetPhysicsEnvironment())
1138                 scene->GetPhysicsEnvironment()->debugDrawWorld();
1139         
1140         m_rasterizer->FlushDebugLines();
1141
1142         PostRenderFrame();
1143 }
1144
1145 void KX_KetsjiEngine::PostRenderFrame()
1146 {
1147         m_rendertools->PushMatrix();
1148         m_rendertools->Render2DFilters(m_canvas);
1149         m_rendertools->MotionBlur(m_rasterizer);
1150         m_rendertools->PopMatrix();
1151 }
1152
1153 void KX_KetsjiEngine::StopEngine()
1154 {
1155         if (m_bInitialized)
1156         {
1157
1158                 if (m_game2ipo)
1159                 {
1160 //                      printf("TestHandlesPhysicsObjectToAnimationIpo\n");
1161                         m_sceneconverter->TestHandlesPhysicsObjectToAnimationIpo();
1162                 }
1163
1164                 KX_SceneList::iterator sceneit;
1165                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1166                 {
1167                         KX_Scene* scene = *sceneit;
1168                         m_sceneconverter->RemoveScene(scene);
1169                 }       
1170                 m_scenes.clear();
1171
1172                 // cleanup all the stuff                
1173                 m_rasterizer->Exit();
1174         }
1175 }
1176
1177 // Scene Management is able to switch between scenes
1178 // and have several scene's running in parallel
1179 void KX_KetsjiEngine::AddScene(KX_Scene* scene)
1180
1181         m_scenes.push_back(scene);
1182         PostProcessScene(scene);
1183         SceneListsChanged();
1184 }
1185
1186
1187
1188 void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
1189 {
1190         bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName));
1191
1192         SG_SetActiveStage(SG_STAGE_SCENE);
1193
1194         // if there is no activecamera, or the camera is being
1195         // overridden we need to construct a temporarily camera
1196         if (!scene->GetActiveCamera() || override_camera)
1197         {
1198                 KX_Camera* activecam = NULL;
1199
1200                 RAS_CameraData camdata = RAS_CameraData();
1201                 activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata);
1202                 activecam->SetName("__default__cam__");
1203         
1204                         // set transformation
1205                 if (override_camera) {
1206                         const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat;
1207                         MT_Transform trans = MT_Transform(cammatdata.getPointer());
1208                         MT_Transform camtrans;
1209                         camtrans.invert(trans);
1210                         
1211                         activecam->NodeSetLocalPosition(camtrans.getOrigin());
1212                         activecam->NodeSetLocalOrientation(camtrans.getBasis());
1213                         activecam->NodeUpdateGS(0);
1214                 } else {
1215                         activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
1216                         activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
1217                         activecam->NodeUpdateGS(0);
1218                 }
1219
1220                 scene->AddCamera(activecam);
1221                 scene->SetActiveCamera(activecam);
1222                 scene->GetObjectList()->Add(activecam->AddRef());
1223                 scene->GetRootParentList()->Add(activecam->AddRef());
1224                 //done with activecam
1225                 activecam->Release();
1226         }
1227         
1228         scene->UpdateParents(0.0);
1229 }
1230
1231
1232
1233 void KX_KetsjiEngine::RenderDebugProperties()
1234 {
1235         STR_String debugtxt;
1236         int xcoord = 10;        // mmmm, these constants were taken from blender source
1237         int ycoord = 14;        // to 'mimic' behaviour
1238
1239         float tottime = m_logger->GetAverage();
1240         if (tottime < 1e-6f) {
1241                 tottime = 1e-6f;
1242         }
1243
1244         // Set viewport to entire canvas
1245         RAS_Rect viewport;
1246         m_canvas->SetViewPort(0, 0, int(m_canvas->GetWidth()), int(m_canvas->GetHeight()));
1247         
1248         /* Framerate display */
1249         if (m_show_framerate) {
1250                 debugtxt.Format("swap : %.3f (%.3f frames per second)", tottime, 1.0/tottime);
1251                 m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
1252                                                                         debugtxt.Ptr(),
1253                                                                         xcoord,
1254                                                                         ycoord, 
1255                                                                         m_canvas->GetWidth() /* RdV, TODO ?? */, 
1256                                                                         m_canvas->GetHeight() /* RdV, TODO ?? */);
1257                 ycoord += 14;
1258         }
1259
1260         /* Profile and framerate display */
1261         if (m_show_profile)
1262         {               
1263                 for (int j = tc_first; j < tc_numCategories; j++)
1264                 {
1265                         debugtxt.Format(m_profileLabels[j]);
1266                         m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
1267                                                                                 debugtxt.Ptr(),
1268                                                                                 xcoord,ycoord,
1269                                                                                 m_canvas->GetWidth(), 
1270                                                                                 m_canvas->GetHeight());
1271                         double time = m_logger->GetAverage((KX_TimeCategory)j);
1272                         debugtxt.Format("%2.2f %%", time/tottime * 100.f);
1273                         m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
1274                                                                                 debugtxt.Ptr(),
1275                                                                                 xcoord + 60 ,ycoord,
1276                                                                                 m_canvas->GetWidth(), 
1277                                                                                 m_canvas->GetHeight());
1278                         ycoord += 14;
1279                 }
1280         }
1281
1282         /* Property display*/
1283         if (m_show_debug_properties && m_propertiesPresent)
1284         {
1285                 KX_SceneList::iterator sceneit;
1286                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1287                 {
1288                         KX_Scene* scene = *sceneit;
1289                         /* the 'normal' debug props */
1290                         vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
1291                         
1292                         for (vector<SCA_DebugProp*>::iterator it = debugproplist.begin();
1293                                  !(it==debugproplist.end());it++)
1294                         {
1295                                 CValue* propobj = (*it)->m_obj;
1296                                 STR_String objname = propobj->GetName();
1297                                 STR_String propname = (*it)->m_name;
1298                                 if (propname == "__state__")
1299                                 {
1300                                         // reserve name for object state
1301                                         KX_GameObject* gameobj = static_cast<KX_GameObject*>(propobj);
1302                                         unsigned int state = gameobj->GetState();
1303                                         debugtxt = objname + "." + propname + " = ";
1304                                         bool first = true;
1305                                         for (int statenum=1;state;state >>= 1, statenum++)
1306                                         {
1307                                                 if (state & 1)
1308                                                 {
1309                                                         if (!first)
1310                                                         {
1311                                                                 debugtxt += ",";
1312                                                         }
1313                                                         debugtxt += STR_String(statenum);
1314                                                         first = false;
1315                                                 }
1316                                         }
1317                                         m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
1318                                                                                                         debugtxt.Ptr(),
1319                                                                                                         xcoord,
1320                                                                                                         ycoord,
1321                                                                                                         m_canvas->GetWidth(),
1322                                                                                                         m_canvas->GetHeight());
1323                                         ycoord += 14;
1324                                 }
1325                                 else
1326                                 {
1327                                         CValue* propval = propobj->GetProperty(propname);
1328                                         if (propval)
1329                                         {
1330                                                 STR_String text = propval->GetText();
1331                                                 debugtxt = objname + "." + propname + " = " + text;
1332                                                 m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
1333                                                                                                         debugtxt.Ptr(),
1334                                                                                                         xcoord,
1335                                                                                                         ycoord,
1336                                                                                                         m_canvas->GetWidth(),
1337                                                                                                         m_canvas->GetHeight());
1338                                                 ycoord += 14;
1339                                         }
1340                                 }
1341                         }
1342                 }
1343         }
1344 }
1345
1346
1347 KX_SceneList* KX_KetsjiEngine::CurrentScenes()
1348 {
1349         return &m_scenes;       
1350 }
1351
1352
1353
1354 KX_Scene* KX_KetsjiEngine::FindScene(const STR_String& scenename)
1355 {
1356         KX_SceneList::iterator sceneit = m_scenes.begin();
1357
1358         // bit risky :) better to split the second clause 
1359         while ( (sceneit != m_scenes.end()) 
1360                         && ((*sceneit)->GetName() != scenename))
1361         {
1362                 sceneit++;
1363         }
1364
1365         return ((sceneit == m_scenes.end()) ? NULL : *sceneit); 
1366 }
1367
1368
1369
1370 void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overlay)
1371 {
1372         // only add scene when it doesn't exist!
1373         if (FindScene(scenename))
1374         {
1375                 STR_String tmpname = scenename;
1376                 printf("warning: scene %s already exists, not added!\n",tmpname.Ptr());
1377         }
1378         else
1379         {
1380                 if (overlay)
1381                 {
1382                         m_addingOverlayScenes.insert(scenename);
1383                 }
1384                 else
1385                 {
1386                         m_addingBackgroundScenes.insert(scenename);
1387                 }
1388         }
1389 }
1390
1391
1392
1393
1394 void KX_KetsjiEngine::RemoveScene(const STR_String& scenename)
1395 {
1396         if (FindScene(scenename))
1397         {
1398                 m_removingScenes.insert(scenename);
1399         }
1400         else
1401         {
1402 //              STR_String tmpname = scenename;
1403                 std::cout << "warning: scene " << scenename << " does not exist, not removed!" << std::endl;
1404         }
1405 }
1406
1407
1408
1409 void KX_KetsjiEngine::RemoveScheduledScenes()
1410 {
1411         if (m_removingScenes.size())
1412         {
1413                 set<STR_String>::iterator scenenameit;
1414                 for (scenenameit=m_removingScenes.begin();scenenameit != m_removingScenes.end();scenenameit++)
1415                 {
1416                         STR_String scenename = *scenenameit;
1417
1418                         KX_SceneList::iterator sceneit;
1419                         for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1420                         {
1421                                 KX_Scene* scene = *sceneit;
1422                                 if (scene->GetName()==scenename)
1423                                 {
1424                                         m_sceneconverter->RemoveScene(scene);
1425                                         m_scenes.erase(sceneit);
1426                                         break;
1427                                 }
1428                         }       
1429                 }
1430                 m_removingScenes.clear();
1431         }
1432 }
1433
1434
1435
1436 KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename)
1437 {
1438         Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename);
1439         KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice,
1440                                                                           m_mousedevice,
1441                                                                           m_networkdevice,
1442                                                                           m_audiodevice,
1443                                                                           scenename,
1444                                                                           scene);
1445
1446         m_sceneconverter->ConvertScene(scenename,
1447                                                           tmpscene,
1448                                                           m_pythondictionary,
1449                                                           m_keyboarddevice,
1450                                                           m_rendertools,
1451                                                           m_canvas);
1452
1453         return tmpscene;
1454 }
1455
1456
1457
1458 void KX_KetsjiEngine::AddScheduledScenes()
1459 {
1460         set<STR_String>::iterator scenenameit;
1461
1462         if (m_addingOverlayScenes.size())
1463         {
1464                 for (scenenameit = m_addingOverlayScenes.begin();
1465                         scenenameit != m_addingOverlayScenes.end();
1466                         scenenameit++)
1467                 {
1468                         STR_String scenename = *scenenameit;
1469                         KX_Scene* tmpscene = CreateScene(scenename);
1470                         m_scenes.push_back(tmpscene);
1471                         PostProcessScene(tmpscene);
1472                 }
1473                 m_addingOverlayScenes.clear();
1474         }
1475         
1476         if (m_addingBackgroundScenes.size())
1477         {
1478                 for (scenenameit = m_addingBackgroundScenes.begin();
1479                         scenenameit != m_addingBackgroundScenes.end();
1480                         scenenameit++)
1481                 {
1482                         STR_String scenename = *scenenameit;
1483                         KX_Scene* tmpscene = CreateScene(scenename);
1484                         m_scenes.insert(m_scenes.begin(),tmpscene);
1485                         PostProcessScene(tmpscene);
1486
1487                 }
1488                 m_addingBackgroundScenes.clear();
1489         }
1490 }
1491
1492
1493
1494 void KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
1495 {
1496         m_replace_scenes.insert(std::make_pair(oldscene,newscene));
1497 }
1498
1499 // replace scene is not the same as removing and adding because the
1500 // scene must be in exact the same place (to maintain drawingorder)
1501 // (nzc) - should that not be done with a scene-display list? It seems
1502 // stupid to rely on the mem allocation order...
1503 void KX_KetsjiEngine::ReplaceScheduledScenes()
1504 {
1505         if (m_replace_scenes.size())
1506         {
1507                 set<pair<STR_String,STR_String> >::iterator scenenameit;
1508                 
1509                 for (scenenameit = m_replace_scenes.begin();
1510                         scenenameit != m_replace_scenes.end();
1511                         scenenameit++)
1512                 {
1513                         STR_String oldscenename = (*scenenameit).first;
1514                         STR_String newscenename = (*scenenameit).second;
1515                         int i=0;
1516                         /* Scenes are not supposed to be included twice... I think */
1517                         KX_SceneList::iterator sceneit;
1518                         for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1519                         {
1520                                 KX_Scene* scene = *sceneit;
1521                                 if (scene->GetName() == oldscenename)
1522                                 {
1523                                         m_sceneconverter->RemoveScene(scene);
1524                                         KX_Scene* tmpscene = CreateScene(newscenename);
1525                                         m_scenes[i]=tmpscene;
1526                                         PostProcessScene(tmpscene);
1527                                 }
1528                                 i++;
1529                         }
1530                 }
1531                 m_replace_scenes.clear();
1532         }       
1533 }
1534
1535
1536
1537 void KX_KetsjiEngine::SuspendScene(const STR_String& scenename)
1538 {
1539         KX_Scene*  scene = FindScene(scenename);
1540         if (scene) scene->Suspend();
1541 }
1542
1543
1544
1545 void KX_KetsjiEngine::ResumeScene(const STR_String& scenename)
1546 {
1547         KX_Scene*  scene = FindScene(scenename);
1548         if (scene) scene->Resume();
1549 }
1550
1551
1552
1553 void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
1554 {
1555         m_bFixedTime = bUseFixedTime;
1556 }
1557
1558
1559 void    KX_KetsjiEngine::SetGame2IpoMode(bool game2ipo,int startFrame)
1560 {
1561         m_game2ipo = game2ipo;
1562         if (game2ipo)
1563         {
1564                 //when recording physics keyframes, always run at a fixed framerate
1565                 m_bFixedTime = true;
1566         }
1567         m_currentFrame = startFrame;
1568 }
1569
1570 bool KX_KetsjiEngine::GetUseFixedTime(void) const
1571 {
1572         return m_bFixedTime;
1573 }
1574
1575 double KX_KetsjiEngine::GetSuspendedDelta()
1576 {
1577         return m_suspendeddelta;
1578 }
1579
1580 double KX_KetsjiEngine::GetTicRate()
1581 {
1582         return m_ticrate;
1583 }
1584
1585 void KX_KetsjiEngine::SetTicRate(double ticrate)
1586 {
1587         m_ticrate = ticrate;
1588 }
1589
1590 double KX_KetsjiEngine::GetAnimFrameRate()
1591 {
1592         return m_anim_framerate;
1593 }
1594
1595 double KX_KetsjiEngine::GetClockTime(void) const
1596 {
1597         return m_clockTime;
1598 }
1599
1600 void KX_KetsjiEngine::SetAnimFrameRate(double framerate)
1601 {
1602         m_anim_framerate = framerate;
1603 }
1604
1605 double KX_KetsjiEngine::GetAverageFrameRate()
1606 {
1607         return m_average_framerate;
1608 }
1609
1610 void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
1611 {
1612         m_show_framerate = frameRate;
1613         m_show_profile = profile;
1614         m_show_debug_properties = properties;
1615 }
1616
1617
1618
1619 void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const
1620 {
1621         frameRate = m_show_framerate;
1622         profile = m_show_profile;
1623         properties = m_show_debug_properties;
1624 }
1625
1626
1627
1628 void KX_KetsjiEngine::ProcessScheduledScenes(void)
1629 {
1630         // Check whether there will be changes to the list of scenes
1631         if (m_addingOverlayScenes.size() ||
1632                 m_addingBackgroundScenes.size() ||
1633                 m_replace_scenes.size() ||
1634                 m_removingScenes.size()) {
1635
1636                 // Change the scene list
1637                 ReplaceScheduledScenes();
1638                 RemoveScheduledScenes();
1639                 AddScheduledScenes();
1640
1641                 // Notify
1642                 SceneListsChanged();
1643         }
1644 }
1645
1646
1647
1648 void KX_KetsjiEngine::SceneListsChanged(void)
1649 {
1650         m_propertiesPresent = false;
1651         KX_SceneList::iterator sceneit = m_scenes.begin();
1652         while ((sceneit != m_scenes.end()) && (!m_propertiesPresent))
1653         {
1654                 KX_Scene* scene = *sceneit;
1655                 vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();    
1656                 m_propertiesPresent = !debugproplist.empty();
1657                 sceneit++;
1658         }
1659 }
1660
1661
1662 void KX_KetsjiEngine::SetHideCursor(bool hideCursor)
1663 {
1664         m_hideCursor = hideCursor;
1665 }
1666
1667
1668 bool KX_KetsjiEngine::GetHideCursor(void) const
1669 {
1670         return m_hideCursor;
1671 }
1672
1673
1674 void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor)
1675 {
1676         m_overrideFrameColor = overrideFrameColor;
1677 }
1678
1679
1680 bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
1681 {
1682         return m_overrideFrameColor;
1683 }
1684
1685
1686 void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
1687 {
1688         m_overrideFrameColorR = r;
1689         m_overrideFrameColorG = g;
1690         m_overrideFrameColorB = b;
1691 }
1692
1693
1694 void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
1695 {
1696         r = m_overrideFrameColorR;
1697         g = m_overrideFrameColorG;
1698         b = m_overrideFrameColorB;
1699 }
1700
1701
1702