BGE: Add setMistType and setMistIntensity API.
[blender.git] / source / gameengine / Ketsji / KX_KetsjiEngine.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  * The engine ties all game modules together. 
27  */
28
29 /** \file gameengine/Ketsji/KX_KetsjiEngine.cpp
30  *  \ingroup ketsji
31  */
32
33 #ifdef _MSC_VER
34 #  pragma warning (disable:4786)
35 #endif
36
37 #include <iostream>
38 #include <stdio.h>
39
40 #include "BLI_task.h"
41
42 #include "KX_KetsjiEngine.h"
43
44 #include "ListValue.h"
45 #include "IntValue.h"
46 #include "VectorValue.h"
47 #include "BoolValue.h"
48 #include "FloatValue.h"
49
50 #include "RAS_BucketManager.h"
51 #include "RAS_Rect.h"
52 #include "RAS_IRasterizer.h"
53 #include "RAS_ICanvas.h"
54 #include "RAS_ILightObject.h"
55 #include "MT_Vector3.h"
56 #include "MT_Transform.h"
57 #include "SCA_IInputDevice.h"
58 #include "KX_Camera.h"
59 #include "KX_Dome.h"
60 #include "KX_Light.h"
61 #include "KX_PythonInit.h"
62 #include "KX_PyConstraintBinding.h"
63 #include "PHY_IPhysicsEnvironment.h"
64
65 #ifdef WITH_AUDASPACE
66 #  include "AUD_C-API.h"
67 #  include "AUD_I3DDevice.h"
68 #endif
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 "DNA_world_types.h"
79 #include "DNA_scene_types.h"
80
81 #include "KX_NavMeshObject.h"
82
83 #define DEFAULT_LOGIC_TIC_RATE 60.0
84 //#define DEFAULT_PHYSICS_TIC_RATE 60.0
85
86 #ifdef FREE_WINDOWS /* XXX mingw64 (gcc 4.7.0) defines a macro for DrawText that translates to DrawTextA. Not good */
87 #ifdef DrawText
88 #undef DrawText
89 #endif
90 #endif
91
92 const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
93         "Physics:",             // tc_physics
94         "Logic:",               // tc_logic
95         "Animations:",  // tc_animations
96         "Network:",             // tc_network
97         "Scenegraph:",  // tc_scenegraph
98         "Rasterizer:",  // tc_rasterizer
99         "Services:",    // tc_services
100         "Overhead:",    // tc_overhead
101         "Outside:",             // tc_outside
102         "GPU Latency:"  // tc_latency
103 };
104
105 double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;
106 int        KX_KetsjiEngine::m_maxLogicFrame = 5;
107 int        KX_KetsjiEngine::m_maxPhysicsFrame = 5;
108 double KX_KetsjiEngine::m_anim_framerate = 25.0;
109 double KX_KetsjiEngine::m_suspendedtime = 0.0;
110 double KX_KetsjiEngine::m_suspendeddelta = 0.0;
111 double KX_KetsjiEngine::m_average_framerate = 0.0;
112 bool   KX_KetsjiEngine::m_restrict_anim_fps = false;
113 short  KX_KetsjiEngine::m_exitkey = 130; //ESC Key
114
115
116 /**
117  *      Constructor of the Ketsji Engine
118  */
119 KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
120         :       m_canvas(NULL),
121         m_rasterizer(NULL),
122         m_kxsystem(system),
123         m_sceneconverter(NULL),
124         m_networkdevice(NULL),
125 #ifdef WITH_PYTHON
126         m_pythondictionary(NULL),
127 #endif
128         m_keyboarddevice(NULL),
129         m_mousedevice(NULL),
130
131         m_bInitialized(false),
132         m_activecam(0),
133         m_bFixedTime(false),
134         
135         m_firstframe(true),
136         
137         m_frameTime(0.f),
138         m_clockTime(0.f),
139         m_previousClockTime(0.f),
140         m_previousAnimTime(0.f),
141
142
143         m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
144         m_exitstring(""),
145
146         m_cameraZoom(1.0),
147         
148         m_overrideCam(false),
149         m_overrideCamUseOrtho(false),
150         m_overrideCamNear(0.0),
151         m_overrideCamFar(0.0),
152
153         m_stereo(false),
154         m_curreye(0),
155
156         m_logger(NULL),
157         
158         // Set up timing info display variables
159         m_show_framerate(false),
160         m_show_profile(false),
161         m_showProperties(false),
162         m_showBackground(false),
163         m_show_debug_properties(false),
164         m_autoAddDebugProperties(true),
165
166         m_animation_record(false),
167
168         // Default behavior is to hide the cursor every frame.
169         m_hideCursor(false),
170
171         m_overrideFrameColor(false),
172         m_overrideFrameColorR(0.0),
173         m_overrideFrameColorG(0.0),
174         m_overrideFrameColorB(0.0),
175
176         m_usedome(false)
177 {
178         // Initialize the time logger
179         m_logger = new KX_TimeCategoryLogger (25);
180
181         for (int i = tc_first; i < tc_numCategories; i++)
182                 m_logger->AddCategory((KX_TimeCategory)i);
183
184 #ifdef WITH_PYTHON
185         m_pyprofiledict = PyDict_New();
186 #endif
187
188         m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS);
189 }
190
191
192
193 /**
194  *      Destructor of the Ketsji Engine, release all memory
195  */
196 KX_KetsjiEngine::~KX_KetsjiEngine()
197 {
198         delete m_logger;
199         if (m_usedome)
200                 delete m_dome;
201
202 #ifdef WITH_PYTHON
203         Py_CLEAR(m_pyprofiledict);
204 #endif
205
206         if (m_taskscheduler)
207                 BLI_task_scheduler_free(m_taskscheduler);
208 }
209
210
211
212 void KX_KetsjiEngine::SetKeyboardDevice(SCA_IInputDevice* keyboarddevice)
213 {
214         MT_assert(keyboarddevice);
215         m_keyboarddevice = keyboarddevice;
216 }
217
218
219
220 void KX_KetsjiEngine::SetMouseDevice(SCA_IInputDevice* mousedevice)
221 {
222         MT_assert(mousedevice);
223         m_mousedevice = mousedevice;
224 }
225
226
227
228 void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice)
229 {
230         MT_assert(networkdevice);
231         m_networkdevice = networkdevice;
232 }
233
234
235 void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas)
236 {
237         MT_assert(canvas);
238         m_canvas = canvas;
239 }
240
241
242
243 void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer)
244 {
245         MT_assert(rasterizer);
246         m_rasterizer = rasterizer;
247 }
248
249 #ifdef WITH_PYTHON
250 /*
251  * At the moment the bge.logic module is imported into 'pythondictionary' after this function is called.
252  * if this function ever changes to assign a copy, make sure the game logic module is imported into this dictionary before hand.
253  */
254 void KX_KetsjiEngine::SetPyNamespace(PyObject *pythondictionary)
255 {
256         MT_assert(pythondictionary);
257         m_pythondictionary = pythondictionary;
258 }
259
260 PyObject* KX_KetsjiEngine::GetPyProfileDict()
261 {
262         Py_INCREF(m_pyprofiledict);
263         return m_pyprofiledict;
264 }
265 #endif
266
267
268 void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter)
269 {
270         MT_assert(sceneconverter);
271         m_sceneconverter = sceneconverter;
272 }
273
274 void KX_KetsjiEngine::InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text)
275 {
276         m_dome = new KX_Dome(m_canvas, m_rasterizer,this, res, mode, angle, resbuf, tilt, text);
277         m_usedome = true;
278 }
279
280 void KX_KetsjiEngine::RenderDome()
281 {
282         const GLint *viewport = m_canvas->GetViewPort();
283         
284         m_dome->SetViewPort(viewport);
285
286         KX_Scene* firstscene = *m_scenes.begin();
287         const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
288
289         m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
290
291         // hiding mouse cursor each frame
292         // (came back when going out of focus and then back in again)
293         if (m_hideCursor)
294                 m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
295
296         // clear the entire game screen with the border color
297         // only once per frame
298
299         m_canvas->BeginDraw();
300
301         // BeginFrame() sets the actual drawing area. You can use a part of the window
302         if (!BeginFrame())
303                 return;
304
305         KX_SceneList::iterator sceneit;
306         KX_Scene* scene = NULL;
307
308         int n_renders=m_dome->GetNumberRenders();// usually 4 or 6
309         for (int i=0;i<n_renders;i++) {
310                 m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
311                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
312                 // for each scene, call the proceed functions
313                 {
314                         scene = *sceneit;
315                         KX_Camera* cam = scene->GetActiveCamera();
316
317                         // pass the scene's worldsettings to the rasterizer
318                         SetWorldSettings(scene->GetWorldInfo());
319
320                         // shadow buffers
321                         if (i == 0) {
322                                 RenderShadowBuffers(scene);
323                         }
324                         // Avoid drawing the scene with the active camera twice when it's viewport is enabled
325                         if (cam && !cam->GetViewport())
326                         {
327                                 if (scene->IsClearingZBuffer())
328                                         m_rasterizer->ClearDepthBuffer();
329                 
330                                 m_rasterizer->SetAuxilaryClientInfo(scene);
331                 
332                                 // do the rendering
333                                 m_dome->RenderDomeFrame(scene,cam, i);
334                                 //render all the font objects for this scene
335                                 scene->RenderFonts();
336                         }
337                         
338                         list<class KX_Camera*>* cameras = scene->GetCameras();
339                         
340                         // Draw the scene once for each camera with an enabled viewport
341                         list<KX_Camera*>::iterator it = cameras->begin();
342                         while (it != cameras->end()) {
343                                 if ((*it)->GetViewport())
344                                 {
345                                         if (scene->IsClearingZBuffer())
346                                                 m_rasterizer->ClearDepthBuffer();
347                         
348                                         m_rasterizer->SetAuxilaryClientInfo(scene);
349                         
350                                         // do the rendering
351                                         m_dome->RenderDomeFrame(scene, (*it),i);
352                                         //render all the font objects for this scene
353                                         scene->RenderFonts();
354                                 }
355                                 
356                                 it++;
357                         }
358                         // Part of PostRenderScene()
359                         m_rasterizer->MotionBlur();
360                         scene->Render2DFilters(m_canvas);
361                         // no RunDrawingCallBacks
362                         // no FlushDebugLines
363                 }
364                 m_dome->BindImages(i);
365         }
366
367         m_canvas->EndFrame();//XXX do we really need that?
368
369         m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
370
371         if (m_overrideFrameColor) //XXX why do we want
372         {
373                 // Do not use the framing bar color set in the Blender scenes
374                 m_canvas->ClearColor(
375                         m_overrideFrameColorR,
376                         m_overrideFrameColorG,
377                         m_overrideFrameColorB,
378                         1.0
379                         );
380         }
381         else
382         {
383                 // Use the framing bar color set in the Blender scenes
384                 m_canvas->ClearColor(
385                         framesettings.BarRed(),
386                         framesettings.BarGreen(),
387                         framesettings.BarBlue(),
388                         1.0
389                         );
390         }
391         m_dome->Draw();
392         // Draw Callback for the last scene
393 #ifdef WITH_PYTHON
394         scene->RunDrawingCallbacks(scene->GetPostDrawCB());
395 #endif
396         EndFrame();
397 }
398
399 /**
400  * Ketsji Init(), Initializes data-structures and converts data from
401  * Blender into Ketsji native (realtime) format also sets up the
402  * graphics context
403  */
404 void KX_KetsjiEngine::StartEngine(bool clearIpo)
405 {
406         m_clockTime = m_kxsystem->GetTimeInSeconds();
407         m_frameTime = m_kxsystem->GetTimeInSeconds();
408         m_previousClockTime = m_kxsystem->GetTimeInSeconds();
409
410         m_firstframe = true;
411         m_bInitialized = true;
412         // there is always one scene enabled at startup
413         Scene* scene = m_scenes[0]->GetBlenderScene();
414         if (scene)
415         {
416                 m_ticrate = scene->gm.ticrate ? scene->gm.ticrate : DEFAULT_LOGIC_TIC_RATE;
417                 m_maxLogicFrame = scene->gm.maxlogicstep ? scene->gm.maxlogicstep : 5;
418                 m_maxPhysicsFrame = scene->gm.maxphystep ? scene->gm.maxlogicstep : 5;
419         }
420         else
421         {
422                 m_ticrate = DEFAULT_LOGIC_TIC_RATE;
423                 m_maxLogicFrame = 5;
424                 m_maxPhysicsFrame = 5;
425         }
426         
427         if (m_animation_record)
428         {
429                 m_sceneconverter->ResetPhysicsObjectsAnimationIpo(clearIpo);
430                 m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame);
431         }
432
433 }
434
435 void KX_KetsjiEngine::ClearFrame()
436 {
437         // clear unless we're drawing overlapping stereo
438         if (m_rasterizer->InterlacedStereo() &&
439                 m_rasterizer->GetEye() == RAS_IRasterizer::RAS_STEREO_RIGHTEYE)
440                 return;
441
442         // clear the viewports with the background color of the first scene
443         bool doclear = false;
444         KX_SceneList::iterator sceneit;
445         RAS_Rect clearvp, area, viewport;
446
447         for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++)
448         {
449                 KX_Scene* scene = *sceneit;
450                 //const RAS_FrameSettings &framesettings = scene->GetFramingType();
451                 list<class KX_Camera*>* cameras = scene->GetCameras();
452
453                 list<KX_Camera*>::iterator it;
454                 for (it = cameras->begin(); it != cameras->end(); it++)
455                 {
456                         GetSceneViewport(scene, (*it), area, viewport);
457
458                         if (!doclear) {
459                                 clearvp = viewport;
460                                 doclear = true;
461                         }
462                         else {
463                                 if (viewport.GetLeft() < clearvp.GetLeft())
464                                         clearvp.SetLeft(viewport.GetLeft());
465                                 if (viewport.GetBottom() < clearvp.GetBottom())
466                                         clearvp.SetBottom(viewport.GetBottom());
467                                 if (viewport.GetRight() > clearvp.GetRight())
468                                         clearvp.SetRight(viewport.GetRight());
469                                 if (viewport.GetTop() > clearvp.GetTop())
470                                         clearvp.SetTop(viewport.GetTop());
471
472                         }
473                 }
474         }
475
476         if (doclear) {
477                 KX_Scene* firstscene = *m_scenes.begin();
478                 SetBackGround(firstscene->GetWorldInfo());
479
480                 m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(),
481                         clearvp.GetRight(), clearvp.GetTop());
482                 m_rasterizer->ClearColorBuffer();
483         }
484 }
485
486 bool KX_KetsjiEngine::BeginFrame()
487 {
488         // set the area used for rendering (stereo can assign only a subset)
489         m_rasterizer->SetRenderArea();
490
491         if (m_canvas->BeginDraw())
492         {
493                 ClearFrame();
494
495                 m_rasterizer->BeginFrame(m_kxsystem->GetTimeInSeconds());
496
497                 return true;
498         }
499         
500         return false;
501 }
502
503
504 void KX_KetsjiEngine::EndFrame()
505 {
506         m_rasterizer->MotionBlur();
507
508         // Show profiling info
509         m_logger->StartLog(tc_overhead, m_kxsystem->GetTimeInSeconds(), true);
510         if (m_show_framerate || m_show_profile || (m_show_debug_properties))
511         {
512                 RenderDebugProperties();
513         }
514
515         double tottime = m_logger->GetAverage();
516         if (tottime < 1e-6)
517                 tottime = 1e-6;
518
519 #ifdef WITH_PYTHON
520         for (int i = tc_first; i < tc_numCategories; ++i) {
521                 double time = m_logger->GetAverage((KX_TimeCategory)i);
522                 PyObject *val = PyTuple_New(2);
523                 PyTuple_SetItem(val, 0, PyFloat_FromDouble(time*1000.f));
524                 PyTuple_SetItem(val, 1, PyFloat_FromDouble(time/tottime * 100.f));
525
526                 PyDict_SetItemString(m_pyprofiledict, m_profileLabels[i], val);
527                 Py_DECREF(val);
528         }
529 #endif
530
531         m_average_framerate = 1.0/tottime;
532
533         // Go to next profiling measurement, time spend after this call is shown in the next frame.
534         m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds());
535
536         m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
537         m_rasterizer->EndFrame();
538         // swap backbuffer (drawing into this buffer) <-> front/visible buffer
539         m_logger->StartLog(tc_latency, m_kxsystem->GetTimeInSeconds(), true);
540         m_rasterizer->SwapBuffers();
541         m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
542         
543         m_canvas->EndDraw();
544 }
545
546 //#include "PIL_time.h"
547 //#include "LinearMath/btQuickprof.h"
548
549
550 bool KX_KetsjiEngine::NextFrame()
551 {
552         double timestep = 1.0/m_ticrate;
553         double framestep = timestep;
554         //      static hidden::Clock sClock;
555
556         m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true);
557
558         //float dt = sClock.getTimeMicroseconds() * 0.000001f;
559         //sClock.reset();
560
561         if (m_bFixedTime) {
562                 m_clockTime += timestep;
563         }
564         else {
565                 // m_clockTime += dt;
566                 m_clockTime = m_kxsystem->GetTimeInSeconds();
567         }
568         
569         double deltatime = m_clockTime - m_frameTime;
570         if (deltatime<0.f)
571         {
572                 // We got here too quickly, which means there is nothing todo, just return and don't render.
573                 // Not sure if this is the best fix, but it seems to stop the jumping framerate issue (#33088)
574                 return false;
575         }
576
577
578         // Compute the number of logic frames to do each update (fixed tic bricks)
579         int frames =int(deltatime*m_ticrate+1e-6);
580 //      if (frames>1)
581 //              printf("****************************************");
582 //      printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
583         
584 //      if (!frames)
585 //              PIL_sleep_ms(1);
586         
587         KX_SceneList::iterator sceneit;
588         
589         if (frames>m_maxPhysicsFrame)
590         {
591         
592         //      printf("framedOut: %d\n",frames);
593                 m_frameTime+=(frames-m_maxPhysicsFrame)*timestep;
594                 frames = m_maxPhysicsFrame;
595         }
596         
597
598         bool doRender = frames>0;
599
600         if (frames > m_maxLogicFrame)
601         {
602                 framestep = (frames*timestep)/m_maxLogicFrame;
603                 frames = m_maxLogicFrame;
604         }
605
606         while (frames)
607         {
608         
609
610                 m_frameTime += framestep;
611                 
612                 m_sceneconverter->MergeAsyncLoads();
613
614                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
615                 // for each scene, call the proceed functions
616                 {
617                         KX_Scene* scene = *sceneit;
618         
619                         /* Suspension holds the physics and logic processing for an
620                          * entire scene. Objects can be suspended individually, and
621                          * the settings for that precede the logic and physics
622                          * update. */
623                         m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
624
625                         m_sceneconverter->resetNoneDynamicObjectToIpo();//this is for none dynamic objects with ipo
626
627                         scene->UpdateObjectActivity();
628         
629                         if (!scene->IsSuspended())
630                         {
631                                 // if the scene was suspended recalcutlate the delta tu "curtime"
632                                 m_suspendedtime = scene->getSuspendedTime();
633                                 if (scene->getSuspendedTime()!=0.0)
634                                         scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
635                                 m_suspendeddelta = scene->getSuspendedDelta();
636
637                                 
638                                 m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
639                                 SG_SetActiveStage(SG_STAGE_NETWORK);
640                                 scene->GetNetworkScene()->proceed(m_frameTime);
641         
642                                 //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
643                                 //SG_SetActiveStage(SG_STAGE_NETWORK_UPDATE);
644                                 //scene->UpdateParents(m_frameTime);
645                                 
646                                 m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
647                                 SG_SetActiveStage(SG_STAGE_PHYSICS1);
648                                 // set Python hooks for each scene
649 #ifdef WITH_PYTHON
650                                 PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
651 #endif
652                                 KX_SetActiveScene(scene);
653         
654                                 scene->GetPhysicsEnvironment()->EndFrame();
655                                 
656                                 // Update scenegraph after physics step. This maps physics calculations
657                                 // into node positions.
658                                 //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
659                                 //SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE);
660                                 //scene->UpdateParents(m_frameTime);
661                                 
662                                 // Process sensors, and controllers
663                                 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
664                                 SG_SetActiveStage(SG_STAGE_CONTROLLER);
665                                 scene->LogicBeginFrame(m_frameTime);
666         
667                                 // Scenegraph needs to be updated again, because Logic Controllers 
668                                 // can affect the local matrices.
669                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
670                                 SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE);
671                                 scene->UpdateParents(m_frameTime);
672         
673                                 // Process actuators
674         
675                                 // Do some cleanup work for this logic frame
676                                 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
677                                 SG_SetActiveStage(SG_STAGE_ACTUATOR);
678                                 scene->LogicUpdateFrame(m_frameTime, true);
679                                 
680                                 scene->LogicEndFrame();
681         
682                                 // Actuators can affect the scenegraph
683                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
684                                 SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE);
685                                 scene->UpdateParents(m_frameTime);
686
687                                 // update levels of detail
688                                 scene->UpdateObjectLods();
689
690                                 if (!GetRestrictAnimationFPS())
691                                 {
692                                         m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true);
693                                         SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);
694                                         scene->UpdateAnimations(m_frameTime);
695                                 }
696
697                                 m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
698                                 SG_SetActiveStage(SG_STAGE_PHYSICS2);
699                                 scene->GetPhysicsEnvironment()->BeginFrame();
700                 
701                                 // Perform physics calculations on the scene. This can involve 
702                                 // many iterations of the physics solver.
703                                 scene->GetPhysicsEnvironment()->ProceedDeltaTime(m_frameTime,timestep,framestep);//m_deltatimerealDeltaTime);
704
705                                 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
706                                 SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE);
707                                 scene->UpdateParents(m_frameTime);
708                         
709                         
710                                 if (m_animation_record)
711                                 {
712                                         m_sceneconverter->WritePhysicsObjectToAnimationIpo(++m_currentFrame);
713                                 }
714
715                                 scene->setSuspendedTime(0.0);
716                         } // suspended
717                         else
718                                 if (scene->getSuspendedTime()==0.0)
719                                         scene->setSuspendedTime(m_clockTime);
720                         
721                         m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
722                 }
723
724                 // update system devices
725                 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
726                 if (m_keyboarddevice)
727                         m_keyboarddevice->NextFrame();
728         
729                 if (m_mousedevice)
730                         m_mousedevice->NextFrame();
731                 
732                 if (m_networkdevice)
733                         m_networkdevice->NextFrame();
734
735                 // scene management
736                 ProcessScheduledScenes();
737                 
738                 frames--;
739         }
740
741         // Handle the animations independently of the logic time step
742         if (GetRestrictAnimationFPS())
743         {
744                 double clocktime = m_kxsystem->GetTimeInSeconds();
745                 m_logger->StartLog(tc_animations, clocktime, true);
746                 SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);
747
748                 double anim_timestep = 1.0/KX_GetActiveScene()->GetAnimationFPS();
749                 if (clocktime - m_previousAnimTime > anim_timestep)
750                 {
751                         // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep)
752                         // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime));
753                         m_previousAnimTime = clocktime;
754                         for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
755                         {
756                                 (*sceneit)->UpdateAnimations(clocktime);
757                         }
758                 }
759         }
760         
761         // Start logging time spend outside main loop
762         m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
763         
764         return doRender;
765 }
766
767
768
769 void KX_KetsjiEngine::Render()
770 {
771         if (m_usedome) {
772                 RenderDome();
773                 return;
774         }
775         KX_Scene* firstscene = *m_scenes.begin();
776         const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
777
778         m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
779         SG_SetActiveStage(SG_STAGE_RENDER);
780
781         // hiding mouse cursor each frame
782         // (came back when going out of focus and then back in again)
783         if (m_hideCursor)
784                 m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
785
786         // clear the entire game screen with the border color
787         // only once per frame
788         m_canvas->BeginDraw();
789         if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
790                 m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
791                 if (m_overrideFrameColor)
792                 {
793                         // Do not use the framing bar color set in the Blender scenes
794                         m_canvas->ClearColor(
795                                 m_overrideFrameColorR,
796                                 m_overrideFrameColorG,
797                                 m_overrideFrameColorB,
798                                 1.0
799                                 );
800                 }
801                 else
802                 {
803                         // Use the framing bar color set in the Blender scenes
804                         m_canvas->ClearColor(
805                                 framesettings.BarRed(),
806                                 framesettings.BarGreen(),
807                                 framesettings.BarBlue(),
808                                 1.0
809                                 );
810                 }
811                 // clear the -whole- viewport
812                 m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
813         }
814
815         m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
816
817         // BeginFrame() sets the actual drawing area. You can use a part of the window
818         if (!BeginFrame())
819                 return;
820
821         KX_SceneList::iterator sceneit;
822         for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
823         // for each scene, call the proceed functions
824         {
825                 KX_Scene* scene = *sceneit;
826                 KX_Camera* cam = scene->GetActiveCamera();
827                 // pass the scene's worldsettings to the rasterizer
828                 SetWorldSettings(scene->GetWorldInfo());
829
830                 // this is now done incrementatlly in KX_Scene::CalculateVisibleMeshes
831                 //scene->UpdateMeshTransformations();
832
833                 // shadow buffers
834                 RenderShadowBuffers(scene);
835
836                 // Avoid drawing the scene with the active camera twice when it's viewport is enabled
837                 if (cam && !cam->GetViewport())
838                 {
839                         if (scene->IsClearingZBuffer())
840                                 m_rasterizer->ClearDepthBuffer();
841         
842                         m_rasterizer->SetAuxilaryClientInfo(scene);
843         
844                         // do the rendering
845                         RenderFrame(scene, cam);
846                 }
847                 
848                 list<class KX_Camera*>* cameras = scene->GetCameras();
849                 
850                 // Draw the scene once for each camera with an enabled viewport
851                 list<KX_Camera*>::iterator it = cameras->begin();
852                 while (it != cameras->end()) {
853                         if ((*it)->GetViewport())
854                         {
855                                 if (scene->IsClearingZBuffer())
856                                         m_rasterizer->ClearDepthBuffer();
857                 
858                                 m_rasterizer->SetAuxilaryClientInfo(scene);
859                 
860                                 // do the rendering
861                                 RenderFrame(scene, (*it));
862                         }
863                         
864                         it++;
865                 }
866                 PostRenderScene(scene);
867         }
868
869         // only one place that checks for stereo
870         if (m_rasterizer->Stereo())
871         {
872                 m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
873
874                 if (!BeginFrame())
875                         return;
876
877
878                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
879                 // for each scene, call the proceed functions
880                 {
881                         KX_Scene* scene = *sceneit;
882                         KX_Camera* cam = scene->GetActiveCamera();
883
884                         // pass the scene's worldsettings to the rasterizer
885                         SetWorldSettings(scene->GetWorldInfo());
886                 
887                         if (scene->IsClearingZBuffer())
888                                 m_rasterizer->ClearDepthBuffer();
889
890                         //pass the scene, for picking and raycasting (shadows)
891                         m_rasterizer->SetAuxilaryClientInfo(scene);
892
893                         // do the rendering
894                         //RenderFrame(scene);
895                         RenderFrame(scene, cam);
896
897                         list<class KX_Camera*>* cameras = scene->GetCameras();
898         
899                         // Draw the scene once for each camera with an enabled viewport
900                         list<KX_Camera*>::iterator it = cameras->begin();
901                         while (it != cameras->end()) {
902                                 if ((*it)->GetViewport())
903                                 {
904                                         if (scene->IsClearingZBuffer())
905                                                 m_rasterizer->ClearDepthBuffer();
906                         
907                                         m_rasterizer->SetAuxilaryClientInfo(scene);
908                         
909                                         // do the rendering
910                                         RenderFrame(scene, (*it));
911                                 }
912                                 
913                                 it++;
914                         }
915                         PostRenderScene(scene);
916                 }
917         } // if (m_rasterizer->Stereo())
918
919         EndFrame();
920 }
921
922
923
924 void KX_KetsjiEngine::RequestExit(int exitrequestmode)
925 {
926         m_exitcode = exitrequestmode;
927 }
928
929
930
931 void KX_KetsjiEngine::SetNameNextGame(const STR_String& nextgame)
932 {
933         m_exitstring = nextgame;
934 }
935
936
937
938 int KX_KetsjiEngine::GetExitCode()
939 {
940         // if a gameactuator has set an exitcode or if there are no scenes left
941         if (!m_exitcode)
942         {
943                 if (m_scenes.begin()==m_scenes.end())
944                         m_exitcode = KX_EXIT_REQUEST_NO_SCENES_LEFT;
945         }
946         
947         // check if the window has been closed.
948         if (!m_exitcode)
949         {
950                 //if (!m_canvas->Check()) {
951                 //      m_exitcode = KX_EXIT_REQUEST_OUTSIDE;
952                 //}
953         }
954
955         return m_exitcode;
956 }
957
958
959
960 const STR_String& KX_KetsjiEngine::GetExitString()
961 {
962         return m_exitstring;
963 }
964
965
966 void KX_KetsjiEngine::SetBackGround(KX_WorldInfo* wi)
967 {
968         if (wi->hasWorld())
969         {
970                 if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
971                 {
972                         m_rasterizer->SetBackColor(
973                                 wi->getBackColorRed(),
974                                 wi->getBackColorGreen(),
975                                 wi->getBackColorBlue(),
976                                 0.0
977                         );
978                 }
979         }
980 }
981
982
983
984 void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi)
985 {
986         if (wi->hasWorld())
987         {
988                 if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID)
989                 {
990                         m_rasterizer->SetAmbientColor(
991                                 wi->getAmbientColorRed(),
992                                 wi->getAmbientColorGreen(),
993                                 wi->getAmbientColorBlue()
994                                 );
995
996                         if (wi->hasMist())
997                         {
998                                 m_rasterizer->SetFog(
999                                         wi->getMistType(),
1000                                         wi->getMistStart(),
1001                                         wi->getMistDistance(),
1002                                         wi->getMistIntensity(),
1003                                         wi->getMistColorRed(),
1004                                         wi->getMistColorGreen(),
1005                                         wi->getMistColorBlue()
1006                                 );
1007                                 m_rasterizer->EnableFog(true);
1008                         }
1009                         else {
1010                                 m_rasterizer->EnableFog(false);
1011                         }
1012                 }
1013         }
1014 }
1015
1016
1017         
1018 void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene)
1019 {
1020         m_overrideCam = true;
1021         m_overrideSceneName = forscene;
1022 }
1023
1024 void KX_KetsjiEngine::SetCameraZoom(float camzoom)
1025 {
1026         m_cameraZoom = camzoom;
1027 }
1028
1029 void KX_KetsjiEngine::SetCameraOverrideUseOrtho(bool useOrtho)
1030 {
1031         m_overrideCamUseOrtho = useOrtho;
1032 }
1033
1034 void KX_KetsjiEngine::SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat)
1035 {
1036         m_overrideCamProjMat = mat;
1037 }
1038
1039 void KX_KetsjiEngine::SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat)
1040 {
1041         m_overrideCamViewMat = mat;
1042 }
1043
1044 void KX_KetsjiEngine::SetCameraOverrideClipping(float nearfrust, float farfrust)
1045 {
1046         m_overrideCamNear = nearfrust;
1047         m_overrideCamFar = farfrust;
1048 }
1049
1050 void KX_KetsjiEngine::SetCameraOverrideLens(float lens)
1051 {
1052         m_overrideCamLens = lens;
1053 }
1054
1055 void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport)
1056 {
1057         // In this function we make sure the rasterizer settings are upto
1058         // date. We compute the viewport so that logic
1059         // using this information is upto date.
1060
1061         // Note we postpone computation of the projection matrix
1062         // so that we are using the latest camera position.
1063         if (cam->GetViewport()) {
1064                 RAS_Rect userviewport;
1065
1066                 userviewport.SetLeft(cam->GetViewportLeft()); 
1067                 userviewport.SetBottom(cam->GetViewportBottom());
1068                 userviewport.SetRight(cam->GetViewportRight());
1069                 userviewport.SetTop(cam->GetViewportTop());
1070
1071                 // Don't do bars on user specified viewport
1072                 RAS_FrameSettings settings = scene->GetFramingType();
1073                 if (settings.FrameType() == RAS_FrameSettings::e_frame_bars)
1074                         settings.SetFrameType(RAS_FrameSettings::e_frame_extend);
1075
1076                 RAS_FramingManager::ComputeViewport(
1077                         scene->GetFramingType(),
1078                         userviewport,
1079                         viewport
1080                 );
1081
1082                 area = userviewport;
1083         }
1084         else if ( !m_overrideCam || (scene->GetName() != m_overrideSceneName) ||  m_overrideCamUseOrtho ) {
1085                 RAS_FramingManager::ComputeViewport(
1086                         scene->GetFramingType(),
1087                         m_canvas->GetDisplayArea(),
1088                         viewport
1089                 );
1090
1091                 area = m_canvas->GetDisplayArea();
1092         } else {
1093                 viewport.SetLeft(0); 
1094                 viewport.SetBottom(0);
1095                 viewport.SetRight(int(m_canvas->GetWidth()));
1096                 viewport.SetTop(int(m_canvas->GetHeight()));
1097
1098                 area = m_canvas->GetDisplayArea();
1099         }
1100 }
1101
1102 void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
1103 {
1104         CListValue *lightlist = scene->GetLightList();
1105         int i, drawmode;
1106
1107         m_rasterizer->SetAuxilaryClientInfo(scene);
1108
1109         for (i=0; i<lightlist->GetCount(); i++) {
1110                 KX_GameObject *gameobj = (KX_GameObject*)lightlist->GetValue(i);
1111
1112                 KX_LightObject *light = (KX_LightObject*)gameobj;
1113                 RAS_ILightObject *raslight = light->GetLightData();
1114
1115                 raslight->Update();
1116
1117                 if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED && raslight->HasShadowBuffer()) {
1118                         /* make temporary camera */
1119                         RAS_CameraData camdata = RAS_CameraData();
1120                         KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, true, true);
1121                         cam->SetName("__shadow__cam__");
1122
1123                         MT_Transform camtrans;
1124
1125                         /* switch drawmode for speed */
1126                         drawmode = m_rasterizer->GetDrawingMode();
1127                         m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW);
1128
1129                         /* binds framebuffer object, sets up camera .. */
1130                         raslight->BindShadowBuffer(m_canvas, cam, camtrans);
1131
1132                         /* update scene */
1133                         scene->CalculateVisibleMeshes(m_rasterizer, cam, raslight->GetShadowLayer());
1134
1135                         /* render */
1136                         m_rasterizer->ClearDepthBuffer();
1137                         m_rasterizer->ClearColorBuffer();
1138                         scene->RenderBuckets(camtrans, m_rasterizer);
1139
1140                         /* unbind framebuffer object, restore drawmode, free camera */
1141                         raslight->UnbindShadowBuffer();
1142                         m_rasterizer->SetDrawingMode(drawmode);
1143                         cam->Release();
1144                 }
1145         }
1146 }
1147         
1148 // update graphics
1149 void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
1150 {
1151         bool override_camera;
1152         RAS_Rect viewport, area;
1153         float nearfrust, farfrust, focallength;
1154 //      KX_Camera* cam = scene->GetActiveCamera();
1155         
1156         if (!cam)
1157                 return;
1158         GetSceneViewport(scene, cam, area, viewport);
1159
1160         // store the computed viewport in the scene
1161         scene->SetSceneViewport(viewport);
1162
1163         // set the viewport for this frame and scene
1164         m_canvas->SetViewPort(viewport.GetLeft(), viewport.GetBottom(),
1165                 viewport.GetRight(), viewport.GetTop());
1166         
1167         // see KX_BlenderMaterial::Activate
1168         //m_rasterizer->SetAmbient();
1169         m_rasterizer->DisplayFog();
1170
1171         override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName);
1172         override_camera = override_camera && (cam->GetName() == "__default__cam__");
1173
1174         if (override_camera && m_overrideCamUseOrtho) {
1175                 m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat);
1176                 if (!cam->hasValidProjectionMatrix()) {
1177                         // needed to get frustrum planes for culling
1178                         MT_Matrix4x4 projmat;
1179                         projmat.setValue(m_overrideCamProjMat.getPointer());
1180                         cam->SetProjectionMatrix(projmat);
1181                 }
1182         } else if (cam->hasValidProjectionMatrix())
1183         {
1184                 m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
1185         } else
1186         {
1187                 RAS_FrameFrustum frustum;
1188                 bool orthographic = !cam->GetCameraData()->m_perspective;
1189                 nearfrust = cam->GetCameraNear();
1190                 farfrust = cam->GetCameraFar();
1191                 focallength = cam->GetFocalLength();
1192                 MT_Matrix4x4 projmat;
1193
1194                 if (override_camera) {
1195                         nearfrust = m_overrideCamNear;
1196                         farfrust = m_overrideCamFar;
1197                 }
1198
1199                 if (orthographic) {
1200
1201                         RAS_FramingManager::ComputeOrtho(
1202                                 scene->GetFramingType(),
1203                                 area,
1204                                 viewport,
1205                                 cam->GetScale(),
1206                                 nearfrust,
1207                                 farfrust,
1208                                 cam->GetSensorFit(),
1209                                 frustum
1210                         );
1211                         if (!cam->GetViewport()) {
1212                                 frustum.x1 *= m_cameraZoom;
1213                                 frustum.x2 *= m_cameraZoom;
1214                                 frustum.y1 *= m_cameraZoom;
1215                                 frustum.y2 *= m_cameraZoom;
1216                         }
1217                         projmat = m_rasterizer->GetOrthoMatrix(
1218                                 frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar);
1219
1220                 } else {
1221                         RAS_FramingManager::ComputeFrustum(
1222                                 scene->GetFramingType(),
1223                                 area,
1224                                 viewport,
1225                                 cam->GetLens(),
1226                                 cam->GetSensorWidth(),
1227                                 cam->GetSensorHeight(),
1228                                 cam->GetSensorFit(),
1229                                 nearfrust,
1230                                 farfrust,
1231                                 frustum
1232                         );
1233
1234                         if (!cam->GetViewport()) {
1235                                 frustum.x1 *= m_cameraZoom;
1236                                 frustum.x2 *= m_cameraZoom;
1237                                 frustum.y1 *= m_cameraZoom;
1238                                 frustum.y2 *= m_cameraZoom;
1239                         }
1240                         projmat = m_rasterizer->GetFrustumMatrix(
1241                                 frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength);
1242                 }
1243                 cam->SetProjectionMatrix(projmat);
1244                 
1245                 // Otherwise the projection matrix for each eye will be the same...
1246                 if (!orthographic && m_rasterizer->Stereo())
1247                         cam->InvalidateProjectionMatrix();
1248         }
1249
1250         MT_Transform camtrans(cam->GetWorldToCamera());
1251         MT_Matrix4x4 viewmat(camtrans);
1252         
1253         m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
1254         cam->SetModelviewMatrix(viewmat);
1255
1256         // The following actually reschedules all vertices to be
1257         // redrawn. There is a cache between the actual rescheduling
1258         // and this call though. Visibility is imparted when this call
1259         // runs through the individual objects.
1260
1261         m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
1262         SG_SetActiveStage(SG_STAGE_CULLING);
1263
1264         scene->CalculateVisibleMeshes(m_rasterizer,cam);
1265
1266         m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
1267         SG_SetActiveStage(SG_STAGE_RENDER);
1268
1269 #ifdef WITH_PYTHON
1270         // Run any pre-drawing python callbacks
1271         scene->RunDrawingCallbacks(scene->GetPreDrawCB());
1272 #endif
1273
1274         scene->RenderBuckets(camtrans, m_rasterizer);
1275
1276         //render all the font objects for this scene
1277         scene->RenderFonts();
1278         
1279         if (scene->GetPhysicsEnvironment())
1280                 scene->GetPhysicsEnvironment()->DebugDrawWorld();
1281 }
1282
1283 /*
1284  * To run once per scene
1285  */
1286 void KX_KetsjiEngine::PostRenderScene(KX_Scene* scene)
1287 {
1288         // We need to first make sure our viewport is correct (enabling multiple viewports can mess this up)
1289         m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
1290         
1291         m_rasterizer->FlushDebugShapes();
1292         scene->Render2DFilters(m_canvas);
1293 #ifdef WITH_PYTHON
1294         scene->RunDrawingCallbacks(scene->GetPostDrawCB());
1295 #endif
1296 }
1297
1298 void KX_KetsjiEngine::StopEngine()
1299 {
1300         if (m_bInitialized)
1301         {
1302
1303                 if (m_animation_record)
1304                 {
1305 //                      printf("TestHandlesPhysicsObjectToAnimationIpo\n");
1306                         m_sceneconverter->TestHandlesPhysicsObjectToAnimationIpo();
1307                 }
1308
1309                 KX_SceneList::iterator sceneit;
1310                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1311                 {
1312                         KX_Scene* scene = *sceneit;
1313                         m_sceneconverter->RemoveScene(scene);
1314                 }
1315                 m_scenes.clear();
1316
1317                 // cleanup all the stuff
1318                 m_rasterizer->Exit();
1319         }
1320 }
1321
1322 // Scene Management is able to switch between scenes
1323 // and have several scene's running in parallel
1324 void KX_KetsjiEngine::AddScene(KX_Scene* scene)
1325
1326         m_scenes.push_back(scene);
1327         PostProcessScene(scene);
1328 }
1329
1330
1331
1332 void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
1333 {
1334         bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName));
1335
1336         SG_SetActiveStage(SG_STAGE_SCENE);
1337
1338         // if there is no activecamera, or the camera is being
1339         // overridden we need to construct a temporarily camera
1340         if (!scene->GetActiveCamera() || override_camera)
1341         {
1342                 KX_Camera* activecam = NULL;
1343
1344                 RAS_CameraData camdata = RAS_CameraData();
1345                 if (override_camera)
1346                 {
1347                         camdata.m_lens = m_overrideCamLens;
1348                         camdata.m_clipstart = m_overrideCamNear;
1349                         camdata.m_clipend = m_overrideCamFar;
1350                         
1351                         camdata.m_perspective= !m_overrideCamUseOrtho;
1352                 }
1353                 activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata);
1354                 activecam->SetName("__default__cam__");
1355         
1356                         // set transformation
1357                 if (override_camera) {
1358                         const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat;
1359                         MT_Transform trans = MT_Transform(cammatdata.getPointer());
1360                         MT_Transform camtrans;
1361                         camtrans.invert(trans);
1362                         
1363                         activecam->NodeSetLocalPosition(camtrans.getOrigin());
1364                         activecam->NodeSetLocalOrientation(camtrans.getBasis());
1365                         activecam->NodeUpdateGS(0);
1366                 } else {
1367                         activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
1368                         activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
1369                         activecam->NodeUpdateGS(0);
1370                 }
1371
1372                 scene->AddCamera(activecam);
1373                 scene->SetActiveCamera(activecam);
1374                 scene->GetObjectList()->Add(activecam->AddRef());
1375                 scene->GetRootParentList()->Add(activecam->AddRef());
1376                 //done with activecam
1377                 activecam->Release();
1378         }
1379         
1380         scene->UpdateParents(0.0);
1381 }
1382
1383
1384
1385 void KX_KetsjiEngine::RenderDebugProperties()
1386 {
1387         STR_String debugtxt;
1388         int title_xmargin = -7;
1389         int title_y_top_margin = 4;
1390         int title_y_bottom_margin = 2;
1391
1392         int const_xindent = 4;
1393         int const_ysize = 14;
1394
1395         int xcoord = 12;        // mmmm, these constants were taken from blender source
1396         int ycoord = 17;        // to 'mimic' behavior
1397         
1398         int profile_indent = 72;
1399
1400         float tottime = m_logger->GetAverage();
1401         if (tottime < 1e-6f) {
1402                 tottime = 1e-6f;
1403         }
1404
1405         // Set viewport to entire canvas
1406         RAS_Rect viewport;
1407         m_canvas->SetViewPort(0, 0, int(m_canvas->GetWidth()), int(m_canvas->GetHeight()));
1408         
1409         if (m_show_framerate || m_show_profile) {
1410                 /* Title for profiling("Profile") */
1411                 m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
1412                                             "Profile",
1413                                             xcoord + const_xindent + title_xmargin, // Adds the constant x indent (0 for now) to the title x margin
1414                                             ycoord,
1415                                             m_canvas->GetWidth() /* RdV, TODO ?? */,
1416                                             m_canvas->GetHeight() /* RdV, TODO ?? */);
1417
1418                 // Increase the indent by default increase
1419                 ycoord += const_ysize;
1420                 // Add the title indent afterwards
1421                 ycoord += title_y_bottom_margin;
1422         }
1423
1424         /* Framerate display */
1425         if (m_show_framerate) {
1426                 m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
1427                                             "Frametime :",
1428                                             xcoord + const_xindent,
1429                                             ycoord,
1430                                             m_canvas->GetWidth() /* RdV, TODO ?? */,
1431                                             m_canvas->GetHeight() /* RdV, TODO ?? */);
1432                 
1433                 debugtxt.Format("%5.1fms (%.1ffps)", tottime * 1000.f, 1.0/tottime);
1434                 m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
1435                                             debugtxt.ReadPtr(),
1436                                             xcoord + const_xindent + profile_indent,
1437                                             ycoord,
1438                                             m_canvas->GetWidth() /* RdV, TODO ?? */,
1439                                             m_canvas->GetHeight() /* RdV, TODO ?? */);
1440                 // Increase the indent by default increase
1441                 ycoord += const_ysize;
1442         }
1443
1444         /* Profile display */
1445         if (m_show_profile) {
1446                 for (int j = tc_first; j < tc_numCategories; j++) {
1447                         m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
1448                                                     m_profileLabels[j],
1449                                                     xcoord + const_xindent,
1450                                                     ycoord,
1451                                                     m_canvas->GetWidth(),
1452                                                     m_canvas->GetHeight());
1453
1454                         double time = m_logger->GetAverage((KX_TimeCategory)j);
1455
1456                         debugtxt.Format("%5.2fms | %d%%", time*1000.f, (int)(time/tottime * 100.f));
1457                         m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
1458                                                     debugtxt.ReadPtr(),
1459                                                     xcoord + const_xindent + profile_indent, ycoord,
1460                                                     m_canvas->GetWidth(),
1461                                                     m_canvas->GetHeight());
1462
1463                         m_rasterizer->RenderBox2D(xcoord + (int)(2.2 * profile_indent), ycoord, m_canvas->GetWidth(), m_canvas->GetHeight(), time/tottime);
1464                         ycoord += const_ysize;
1465                 }
1466         }
1467         // Add the ymargin for titles below the other section of debug info
1468         ycoord += title_y_top_margin;
1469
1470         /* Property display*/
1471         if (m_show_debug_properties) {
1472
1473                 /* Title for debugging("Debug properties") */
1474                 m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
1475                                             "Debug Properties",
1476                                             xcoord + const_xindent + title_xmargin, // Adds the constant x indent (0 for now) to the title x margin
1477                                             ycoord,
1478                                             m_canvas->GetWidth() /* RdV, TODO ?? */,
1479                                             m_canvas->GetHeight() /* RdV, TODO ?? */);
1480
1481                 // Increase the indent by default increase
1482                 ycoord += const_ysize;
1483                 // Add the title indent afterwards
1484                 ycoord += title_y_bottom_margin;
1485
1486                 /* Calculate amount of properties that can displayed. */
1487                 unsigned propsAct = 0;
1488                 unsigned propsMax = (m_canvas->GetHeight() - ycoord) / const_ysize;
1489
1490                 KX_SceneList::iterator sceneit;
1491                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) {
1492                         KX_Scene* scene = *sceneit;
1493                         /* the 'normal' debug props */
1494                         vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
1495                         
1496                         for (unsigned i=0; i < debugproplist.size() && propsAct < propsMax; i++)
1497                         {
1498                                 CValue *propobj = debugproplist[i]->m_obj;
1499                                 STR_String objname = propobj->GetName();
1500                                 STR_String propname = debugproplist[i]->m_name;
1501                                 propsAct++;
1502                                 if (propname == "__state__") {
1503                                         // reserve name for object state
1504                                         KX_GameObject* gameobj = static_cast<KX_GameObject*>(propobj);
1505                                         unsigned int state = gameobj->GetState();
1506                                         debugtxt = objname + "." + propname + " = ";
1507                                         bool first = true;
1508                                         for (int statenum=1;state;state >>= 1, statenum++)
1509                                         {
1510                                                 if (state & 1)
1511                                                 {
1512                                                         if (!first)
1513                                                         {
1514                                                                 debugtxt += ",";
1515                                                         }
1516                                                         debugtxt += STR_String(statenum);
1517                                                         first = false;
1518                                                 }
1519                                         }
1520                                         m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
1521                                                                     debugtxt.ReadPtr(),
1522                                                                     xcoord + const_xindent,
1523                                                                     ycoord,
1524                                                                     m_canvas->GetWidth(),
1525                                                                     m_canvas->GetHeight());
1526                                         ycoord += const_ysize;
1527                                 }
1528                                 else {
1529                                         CValue *propval = propobj->GetProperty(propname);
1530                                         if (propval) {
1531                                                 STR_String text = propval->GetText();
1532                                                 debugtxt = objname + ": '" + propname + "' = " + text;
1533                                                 m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
1534                                                                             debugtxt.ReadPtr(),
1535                                                                             xcoord + const_xindent,
1536                                                                             ycoord,
1537                                                                             m_canvas->GetWidth(),
1538                                                                             m_canvas->GetHeight());
1539                                                 ycoord += const_ysize;
1540                                         }
1541                                 }
1542                         }
1543                 }
1544         }
1545 }
1546
1547
1548 KX_SceneList* KX_KetsjiEngine::CurrentScenes()
1549 {
1550         return &m_scenes;
1551 }
1552
1553
1554
1555 KX_Scene* KX_KetsjiEngine::FindScene(const STR_String& scenename)
1556 {
1557         KX_SceneList::iterator sceneit = m_scenes.begin();
1558
1559         // bit risky :) better to split the second clause 
1560         while ( (sceneit != m_scenes.end()) 
1561                         && ((*sceneit)->GetName() != scenename))
1562         {
1563                 sceneit++;
1564         }
1565
1566         return ((sceneit == m_scenes.end()) ? NULL : *sceneit);
1567 }
1568
1569
1570
1571 void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overlay)
1572 {
1573         // only add scene when it doesn't exist!
1574         if (FindScene(scenename)) {
1575                 printf("warning: scene %s already exists, not added!\n",scenename.ReadPtr());
1576         }
1577         else {
1578                 if (overlay) {
1579                         m_addingOverlayScenes.push_back(scenename);
1580                 }
1581                 else {
1582                         m_addingBackgroundScenes.push_back(scenename);
1583                 }
1584         }
1585 }
1586
1587
1588
1589
1590 void KX_KetsjiEngine::RemoveScene(const STR_String& scenename)
1591 {
1592         if (FindScene(scenename))
1593         {
1594                 m_removingScenes.push_back(scenename);
1595         }
1596         else
1597         {
1598 //              STR_String tmpname = scenename;
1599                 std::cout << "warning: scene " << scenename << " does not exist, not removed!" << std::endl;
1600         }
1601 }
1602
1603
1604
1605 void KX_KetsjiEngine::RemoveScheduledScenes()
1606 {
1607         if (m_removingScenes.size())
1608         {
1609                 vector<STR_String>::iterator scenenameit;
1610                 for (scenenameit=m_removingScenes.begin();scenenameit != m_removingScenes.end();scenenameit++)
1611                 {
1612                         STR_String scenename = *scenenameit;
1613
1614                         KX_SceneList::iterator sceneit;
1615                         for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1616                         {
1617                                 KX_Scene* scene = *sceneit;
1618                                 if (scene->GetName()==scenename)
1619                                 {
1620                                         m_sceneconverter->RemoveScene(scene);
1621                                         m_scenes.erase(sceneit);
1622                                         break;
1623                                 }
1624                         }
1625                 }
1626                 m_removingScenes.clear();
1627         }
1628 }
1629
1630 KX_Scene* KX_KetsjiEngine::CreateScene(Scene *scene, bool libloading)
1631 {
1632         KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice,
1633                                                                           m_mousedevice,
1634                                                                           m_networkdevice,
1635                                                                           scene->id.name+2,
1636                                                                           scene,
1637                                                                           m_canvas);
1638
1639         m_sceneconverter->ConvertScene(tmpscene,
1640                                                           m_rasterizer,
1641                                                           m_canvas,
1642                                                           libloading);
1643
1644         return tmpscene;
1645 }
1646
1647 KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename)
1648 {
1649         Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename);
1650         if (!scene)
1651                 return NULL;
1652         return CreateScene(scene);
1653 }
1654
1655 void KX_KetsjiEngine::AddScheduledScenes()
1656 {
1657         vector<STR_String>::iterator scenenameit;
1658
1659         if (m_addingOverlayScenes.size())
1660         {
1661                 for (scenenameit = m_addingOverlayScenes.begin();
1662                         scenenameit != m_addingOverlayScenes.end();
1663                         scenenameit++)
1664                 {
1665                         STR_String scenename = *scenenameit;
1666                         KX_Scene* tmpscene = CreateScene(scenename);
1667                         if (tmpscene) {
1668                                 m_scenes.push_back(tmpscene);
1669                                 PostProcessScene(tmpscene);
1670                         } else {
1671                                 printf("warning: scene %s could not be found, not added!\n",scenename.ReadPtr());
1672                         }
1673                 }
1674                 m_addingOverlayScenes.clear();
1675         }
1676         
1677         if (m_addingBackgroundScenes.size())
1678         {
1679                 for (scenenameit = m_addingBackgroundScenes.begin();
1680                         scenenameit != m_addingBackgroundScenes.end();
1681                         scenenameit++)
1682                 {
1683                         STR_String scenename = *scenenameit;
1684                         KX_Scene* tmpscene = CreateScene(scenename);
1685                         if (tmpscene) {
1686                                 m_scenes.insert(m_scenes.begin(),tmpscene);
1687                                 PostProcessScene(tmpscene);
1688                         } else {
1689                                 printf("warning: scene %s could not be found, not added!\n",scenename.ReadPtr());
1690                         }
1691                 }
1692                 m_addingBackgroundScenes.clear();
1693         }
1694 }
1695
1696
1697
1698 bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
1699 {
1700         // Don't allow replacement if the new scene doesn't exists.
1701         // Allows smarter game design (used to have no check here).
1702         // Note that it creates a small backward compatbility issue
1703         // for a game that did a replace followed by a lib load with the
1704         // new scene in the lib => it won't work anymore, the lib
1705         // must be loaded before doing the replace.
1706         if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL) {
1707                 m_replace_scenes.push_back(std::make_pair(oldscene,newscene));
1708                 return true;
1709         }
1710         return false;
1711 }
1712
1713 // replace scene is not the same as removing and adding because the
1714 // scene must be in exact the same place (to maintain drawingorder)
1715 // (nzc) - should that not be done with a scene-display list? It seems
1716 // stupid to rely on the mem allocation order...
1717 void KX_KetsjiEngine::ReplaceScheduledScenes()
1718 {
1719         if (m_replace_scenes.size())
1720         {
1721                 vector<pair<STR_String,STR_String> >::iterator scenenameit;
1722                 
1723                 for (scenenameit = m_replace_scenes.begin();
1724                         scenenameit != m_replace_scenes.end();
1725                         scenenameit++)
1726                 {
1727                         STR_String oldscenename = (*scenenameit).first;
1728                         STR_String newscenename = (*scenenameit).second;
1729                         int i=0;
1730                         /* Scenes are not supposed to be included twice... I think */
1731                         KX_SceneList::iterator sceneit;
1732                         for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) {
1733                                 KX_Scene* scene = *sceneit;
1734                                 if (scene->GetName() == oldscenename) {
1735                                         // avoid crash if the new scene doesn't exist, just do nothing
1736                                         Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename);
1737                                         if (blScene) {
1738                                                 m_sceneconverter->RemoveScene(scene);
1739                                                 KX_Scene* tmpscene = CreateScene(blScene);
1740                                                 m_scenes[i]=tmpscene;
1741                                                 PostProcessScene(tmpscene);
1742                                         }
1743                                         else {
1744                                                 printf("warning: scene %s could not be found, not replaced!\n",newscenename.ReadPtr());
1745                                         }
1746                                 }
1747                                 i++;
1748                         }
1749                 }
1750                 m_replace_scenes.clear();
1751         }
1752 }
1753
1754
1755
1756 void KX_KetsjiEngine::SuspendScene(const STR_String& scenename)
1757 {
1758         KX_Scene*  scene = FindScene(scenename);
1759         if (scene) scene->Suspend();
1760 }
1761
1762
1763
1764 void KX_KetsjiEngine::ResumeScene(const STR_String& scenename)
1765 {
1766         KX_Scene*  scene = FindScene(scenename);
1767         if (scene) scene->Resume();
1768 }
1769
1770
1771
1772 void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
1773 {
1774         m_bFixedTime = bUseFixedTime;
1775 }
1776
1777
1778 void    KX_KetsjiEngine::SetAnimRecordMode(bool animation_record, int startFrame)
1779 {
1780         m_animation_record = animation_record;
1781         if (animation_record)
1782         {
1783                 //when recording physics keyframes, run at a variable (capped) frame rate (fixed time == full speed)
1784                 m_bFixedTime = false;
1785         }
1786         m_currentFrame = startFrame;
1787 }
1788
1789 bool KX_KetsjiEngine::GetUseFixedTime(void) const
1790 {
1791         return m_bFixedTime;
1792 }
1793
1794 double KX_KetsjiEngine::GetSuspendedDelta()
1795 {
1796         return m_suspendeddelta;
1797 }
1798
1799 double KX_KetsjiEngine::GetTicRate()
1800 {
1801         return m_ticrate;
1802 }
1803
1804 void KX_KetsjiEngine::SetTicRate(double ticrate)
1805 {
1806         m_ticrate = ticrate;
1807 }
1808
1809 int KX_KetsjiEngine::GetMaxLogicFrame()
1810 {
1811         return m_maxLogicFrame;
1812 }
1813
1814 void KX_KetsjiEngine::SetMaxLogicFrame(int frame)
1815 {
1816         m_maxLogicFrame = frame;
1817 }
1818
1819 int KX_KetsjiEngine::GetMaxPhysicsFrame()
1820 {
1821         return m_maxPhysicsFrame;
1822 }
1823
1824 void KX_KetsjiEngine::SetMaxPhysicsFrame(int frame)
1825 {
1826         m_maxPhysicsFrame = frame;
1827 }
1828
1829 bool KX_KetsjiEngine::GetRestrictAnimationFPS()
1830 {
1831         return m_restrict_anim_fps;
1832 }
1833
1834 void KX_KetsjiEngine::SetRestrictAnimationFPS(bool bRestrictAnimFPS)
1835 {
1836         m_restrict_anim_fps = bRestrictAnimFPS;
1837 }
1838
1839 double KX_KetsjiEngine::GetAnimFrameRate()
1840 {
1841         return m_anim_framerate;
1842 }
1843
1844 double KX_KetsjiEngine::GetClockTime(void) const
1845 {
1846         return m_clockTime;
1847 }
1848
1849 double KX_KetsjiEngine::GetFrameTime(void) const
1850 {
1851         return m_frameTime;
1852 }
1853
1854 double KX_KetsjiEngine::GetRealTime(void) const
1855 {
1856         return m_kxsystem->GetTimeInSeconds();
1857 }
1858
1859 void KX_KetsjiEngine::SetAnimFrameRate(double framerate)
1860 {
1861         m_anim_framerate = framerate;
1862 }
1863
1864 double KX_KetsjiEngine::GetAverageFrameRate()
1865 {
1866         return m_average_framerate;
1867 }
1868
1869 void KX_KetsjiEngine::SetExitKey(short key)
1870 {
1871         m_exitkey = key;
1872 }
1873
1874 short KX_KetsjiEngine::GetExitKey()
1875 {
1876         return m_exitkey;
1877 }
1878
1879 void KX_KetsjiEngine::SetShowFramerate(bool frameRate)
1880 {
1881         m_show_framerate = frameRate;
1882 }
1883
1884 bool KX_KetsjiEngine::GetShowFramerate()
1885 {
1886         return m_show_framerate;
1887 }
1888
1889 void KX_KetsjiEngine::SetShowProfile(bool profile)
1890 {
1891         m_show_profile = profile;
1892 }
1893
1894 bool KX_KetsjiEngine::GetShowProfile()
1895 {
1896         return m_show_profile;
1897 }
1898
1899 void KX_KetsjiEngine::SetShowProperties(bool properties)
1900 {
1901         m_show_debug_properties = properties;
1902 }
1903
1904 bool KX_KetsjiEngine::GetShowProperties()
1905 {
1906         return m_show_debug_properties;
1907 }
1908
1909 void KX_KetsjiEngine::SetAutoAddDebugProperties(bool add)
1910 {
1911         m_autoAddDebugProperties = add;
1912 }
1913
1914 bool KX_KetsjiEngine::GetAutoAddDebugProperties()
1915 {
1916         return m_autoAddDebugProperties;
1917 }
1918
1919 void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
1920 {
1921         m_show_framerate = frameRate;
1922         m_show_profile = profile;
1923         m_show_debug_properties = properties;
1924 }
1925
1926
1927
1928 void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const
1929 {
1930         frameRate = m_show_framerate;
1931         profile = m_show_profile;
1932         properties = m_show_debug_properties;
1933 }
1934
1935
1936
1937 void KX_KetsjiEngine::ProcessScheduledScenes(void)
1938 {
1939         // Check whether there will be changes to the list of scenes
1940         if (m_addingOverlayScenes.size() ||
1941                 m_addingBackgroundScenes.size() ||
1942                 m_replace_scenes.size() ||
1943                 m_removingScenes.size()) {
1944
1945                 // Change the scene list
1946                 ReplaceScheduledScenes();
1947                 RemoveScheduledScenes();
1948                 AddScheduledScenes();
1949         }
1950 }
1951
1952
1953 void KX_KetsjiEngine::SetHideCursor(bool hideCursor)
1954 {
1955         m_hideCursor = hideCursor;
1956 }
1957
1958
1959 bool KX_KetsjiEngine::GetHideCursor(void) const
1960 {
1961         return m_hideCursor;
1962 }
1963
1964
1965 void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor)
1966 {
1967         m_overrideFrameColor = overrideFrameColor;
1968 }
1969
1970
1971 bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
1972 {
1973         return m_overrideFrameColor;
1974 }
1975
1976
1977 void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
1978 {
1979         m_overrideFrameColorR = r;
1980         m_overrideFrameColorG = g;
1981         m_overrideFrameColorB = b;
1982 }
1983
1984
1985 void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
1986 {
1987         r = m_overrideFrameColorR;
1988         g = m_overrideFrameColorG;
1989         b = m_overrideFrameColorB;
1990 }
1991
1992
1993 void KX_KetsjiEngine::Resize()
1994 {
1995         KX_SceneList::iterator sceneit;
1996
1997         /* extended mode needs to recalculate camera frustrums when */
1998         KX_Scene* firstscene = *m_scenes.begin();
1999         const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
2000
2001         if (framesettings.FrameType() == RAS_FrameSettings::e_frame_extend) {
2002                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) {
2003                         KX_Camera* cam = ((KX_Scene *)*sceneit)->GetActiveCamera();
2004                         cam->InvalidateProjectionMatrix();
2005                 }
2006         }
2007 }
2008
2009
2010 void KX_KetsjiEngine::SetGlobalSettings(GlobalSettings* gs)
2011 {
2012         m_globalsettings.matmode = gs->matmode;
2013         m_globalsettings.glslflag = gs->glslflag;
2014 }
2015
2016 GlobalSettings* KX_KetsjiEngine::GetGlobalSettings(void)
2017 {
2018         return &m_globalsettings;
2019 }
2020