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