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