73a826c3d0dfa051c952d32712776b01217ee828
[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         const float ortho = 100.0;
740         KX_Camera* cam = scene->GetActiveCamera();
741         
742         if (!cam)
743                 return;
744
745         m_rasterizer->DisplayFog();
746
747         if (m_overrideCam && (scene->GetName() == m_overrideSceneName) && m_overrideCamUseOrtho) {
748                 MT_CmMatrix4x4 projmat = m_overrideCamProjMat;
749                 m_rasterizer->SetProjectionMatrix(projmat);
750         } else if (cam->hasValidProjectionMatrix())
751         {
752                 m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
753         } else
754         {
755                 RAS_FrameFrustum frustum;
756                 float lens = cam->GetLens();
757                 nearfrust = cam->GetCameraNear();
758                 farfrust = cam->GetCameraFar();
759
760                 if (!cam->GetCameraData()->m_perspective)
761                 {
762                         lens *= ortho;
763                         nearfrust = (nearfrust + 1.0)*ortho;
764                         farfrust *= ortho;
765                 }
766                 
767                 RAS_FramingManager::ComputeFrustum(
768                         scene->GetFramingType(),
769                         m_canvas->GetDisplayArea(),
770                         scene->GetSceneViewport(),
771                         lens,
772                         nearfrust,
773                         farfrust,
774                         frustum
775                 );
776
777                 left = frustum.x1 * m_cameraZoom;
778                 right = frustum.x2 * m_cameraZoom;
779                 bottom = frustum.y1 * m_cameraZoom;
780                 top = frustum.y2 * m_cameraZoom;
781                 nearfrust = frustum.camnear;
782                 farfrust = frustum.camfar;
783
784                 MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
785                         left, right, bottom, top, nearfrust, farfrust);
786         
787                 cam->SetProjectionMatrix(projmat);      
788         }
789
790         MT_Transform camtrans(cam->GetWorldToCamera());
791         if (!cam->GetCameraData()->m_perspective)
792                 camtrans.getOrigin()[2] *= ortho;
793         MT_Matrix4x4 viewmat(camtrans);
794         
795         m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
796                 cam->GetCameraLocation(), cam->GetCameraOrientation());
797         cam->SetModelviewMatrix(viewmat);
798
799         scene->UpdateMeshTransformations();
800
801         // The following actually reschedules all vertices to be
802         // redrawn. There is a cache between the actual rescheduling
803         // and this call though. Visibility is imparted when this call
804         // runs through the individual objects.
805         scene->CalculateVisibleMeshes(m_rasterizer);
806
807         scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
808 }
809
810
811
812 void KX_KetsjiEngine::StopEngine()
813 {
814         if (m_bInitialized)
815         {
816                 KX_SceneList::iterator sceneit;
817                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
818                 {
819                         KX_Scene* scene = *sceneit;
820                         delete scene;
821                 }       
822                 m_scenes.clear();
823
824                 // cleanup all the stuff                
825                 m_rasterizer->Exit();
826         }
827 }
828
829 // Scene Management is able to switch between scenes
830 // and have several scene's running in parallel
831 void KX_KetsjiEngine::AddScene(KX_Scene* scene)
832
833         m_scenes.push_back(scene);
834         PostProcessScene(scene);
835         SceneListsChanged();
836 }
837
838
839
840 void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
841 {
842         bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName));
843         
844                 // if there is no activecamera, or the camera is being
845                 // overridden we need to construct a temporarily camera
846         if (!scene->GetActiveCamera() || override_camera)
847         {
848                 KX_Camera* activecam = NULL;
849
850                 RAS_CameraData camdata = RAS_CameraData();
851                 activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata, false);
852                 activecam->SetName("__default__cam__");
853         
854                         // set transformation
855                 if (override_camera) {
856                         const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat;
857                         MT_Transform trans = MT_Transform(cammatdata.getPointer());
858                         MT_Transform camtrans;
859                         camtrans.invert(trans);
860                         
861                         activecam->NodeSetLocalPosition(camtrans.getOrigin());
862                         activecam->NodeSetLocalOrientation(camtrans.getBasis());
863                         activecam->NodeUpdateGS(0,true);
864                 } else {
865                         activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
866                         activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
867                         activecam->NodeUpdateGS(0,true);
868                 }
869
870                 scene->AddCamera(activecam);
871                 scene->SetActiveCamera(activecam);
872                 scene->GetObjectList()->Add(activecam->AddRef());
873                 scene->GetRootParentList()->Add(activecam->AddRef());
874         }
875         
876         scene->UpdateParents(0.0);
877 }
878
879
880
881 void KX_KetsjiEngine::RenderDebugProperties()
882 {
883         STR_String debugtxt;
884         int xcoord = 10;        // mmmm, these constants were taken from blender source
885         int ycoord = 14;        // to 'mimic' behaviour
886
887         float tottime = m_logger->GetAverage();
888         if (tottime < 1e-6f) {
889                 tottime = 1e-6f;
890         }
891         
892         /* Framerate display */
893         if (m_show_framerate) {
894                 debugtxt.Format("swap : %.3f (%.3f frames per second)", tottime, 1.0/tottime);
895                 m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
896                                                                         debugtxt.Ptr(),
897                                                                         xcoord,
898                                                                         ycoord, 
899                                                                         m_canvas->GetWidth() /* RdV, TODO ?? */, 
900                                                                         m_canvas->GetHeight() /* RdV, TODO ?? */);
901                 ycoord += 14;
902         }
903
904         /* Profile and framerate display */
905         if (m_show_profile)
906         {               
907                 for (int j = tc_first; j < tc_numCategories; j++)
908                 {
909                         debugtxt.Format(m_profileLabels[j]);
910                         m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
911                                                                                 debugtxt.Ptr(),
912                                                                                 xcoord,ycoord,
913                                                                                 m_canvas->GetWidth(), 
914                                                                                 m_canvas->GetHeight());
915                         double time = m_logger->GetAverage((KX_TimeCategory)j);
916                         debugtxt.Format("%2.2f %%", time/tottime * 100.f);
917                         m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
918                                                                                 debugtxt.Ptr(),
919                                                                                 xcoord + 60 ,ycoord,
920                                                                                 m_canvas->GetWidth(), 
921                                                                                 m_canvas->GetHeight());
922                         ycoord += 14;
923                 }
924         }
925
926         /* Property display*/
927         if (m_show_debug_properties && m_propertiesPresent)
928         {
929                 KX_SceneList::iterator sceneit;
930                 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
931                 {
932                         KX_Scene* scene = *sceneit;
933                         /* the 'normal' debug props */
934                         vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
935                         
936                         for (vector<SCA_DebugProp*>::iterator it = debugproplist.begin();
937                                  !(it==debugproplist.end());it++)
938                         {
939                                 CValue* propobj = (*it)->m_obj;
940                                 STR_String objname = propobj->GetName();
941                                 STR_String propname = (*it)->m_name;
942                                 CValue* propval = propobj->GetProperty(propname);
943                                 if (propval)
944                                 {
945                                         STR_String text = propval->GetText();
946                                         debugtxt = objname + "." + propname + " = " + text;
947                                         m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, 
948                                                                                                 debugtxt.Ptr(),
949                                                                                                 xcoord,
950                                                                                                 ycoord,
951                                                                                                 m_canvas->GetWidth(),
952                                                                                                 m_canvas->GetHeight());
953                                         ycoord += 14;
954                                 }
955                         }
956                 }
957         }
958 }
959
960
961 KX_SceneList* KX_KetsjiEngine::CurrentScenes()
962 {
963         return &m_scenes;       
964 }
965
966
967
968 KX_Scene* KX_KetsjiEngine::FindScene(const STR_String& scenename)
969 {
970         KX_SceneList::iterator sceneit = m_scenes.begin();
971
972         // bit risky :) better to split the second clause 
973         while ( (sceneit != m_scenes.end()) 
974                         && ((*sceneit)->GetName() != scenename))
975         {
976                 sceneit++;
977         }
978
979         return ((sceneit == m_scenes.end()) ? NULL : *sceneit); 
980 }
981
982
983
984 void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overlay)
985 {
986         // only add scene when it doesn't exist!
987         if (FindScene(scenename))
988         {
989                 STR_String tmpname = scenename;
990                 printf("warning: scene %s already exists, not added!\n",tmpname.Ptr());
991         }
992         else
993         {
994                 if (overlay)
995                 {
996                         m_addingOverlayScenes.insert(scenename);
997                 }
998                 else
999                 {
1000                         m_addingBackgroundScenes.insert(scenename);
1001                 }
1002         }
1003 }
1004
1005
1006
1007
1008 void KX_KetsjiEngine::RemoveScene(const STR_String& scenename)
1009 {
1010         if (FindScene(scenename))
1011         {
1012                 m_removingScenes.insert(scenename);
1013         }
1014         else
1015         {
1016 //              STR_String tmpname = scenename;
1017                 std::cout << "warning: scene " << scenename << " does not exist, not removed!" << std::endl;
1018         }
1019 }
1020
1021
1022
1023 void KX_KetsjiEngine::RemoveScheduledScenes()
1024 {
1025         if (m_removingScenes.size())
1026         {
1027                 set<STR_String>::iterator scenenameit;
1028                 for (scenenameit=m_removingScenes.begin();scenenameit != m_removingScenes.end();scenenameit++)
1029                 {
1030                         STR_String scenename = *scenenameit;
1031
1032                         KX_SceneList::iterator sceneit;
1033                         for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1034                         {
1035                                 KX_Scene* scene = *sceneit;
1036                                 if (scene->GetName()==scenename)
1037                                 {
1038                                         delete scene;
1039                                         m_scenes.erase(sceneit);
1040                                         break;
1041                                 }
1042                         }       
1043                 }
1044                 m_removingScenes.clear();
1045         }
1046 }
1047
1048
1049
1050 KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename)
1051 {
1052
1053         KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice,
1054                                                                           m_mousedevice,
1055                                                                           m_networkdevice,
1056                                                                           m_audiodevice,
1057                                                                           scenename);
1058
1059         m_sceneconverter->ConvertScene(scenename,
1060                                                           tmpscene,
1061                                                           m_pythondictionary,
1062                                                           m_keyboarddevice,
1063                                                           m_rendertools,
1064                                                           m_canvas);
1065
1066         return tmpscene;
1067 }
1068
1069
1070
1071 void KX_KetsjiEngine::AddScheduledScenes()
1072 {
1073         set<STR_String>::iterator scenenameit;
1074
1075         if (m_addingOverlayScenes.size())
1076         {
1077                 for (scenenameit = m_addingOverlayScenes.begin();
1078                         scenenameit != m_addingOverlayScenes.end();
1079                         scenenameit++)
1080                 {
1081                         STR_String scenename = *scenenameit;
1082                         KX_Scene* tmpscene = CreateScene(scenename);
1083                         m_scenes.push_back(tmpscene);
1084                         PostProcessScene(tmpscene);
1085                 }
1086                 m_addingOverlayScenes.clear();
1087         }
1088         
1089         if (m_addingBackgroundScenes.size())
1090         {
1091                 for (scenenameit = m_addingBackgroundScenes.begin();
1092                         scenenameit != m_addingBackgroundScenes.end();
1093                         scenenameit++)
1094                 {
1095                         STR_String scenename = *scenenameit;
1096                         KX_Scene* tmpscene = CreateScene(scenename);
1097                         m_scenes.insert(m_scenes.begin(),tmpscene);
1098                         PostProcessScene(tmpscene);
1099
1100                 }
1101                 m_addingBackgroundScenes.clear();
1102         }
1103 }
1104
1105
1106
1107 void KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
1108 {
1109         m_replace_scenes.insert(std::make_pair(oldscene,newscene));
1110 }
1111
1112 // replace scene is not the same as removing and adding because the
1113 // scene must be in exact the same place (to maintain drawingorder)
1114 // (nzc) - should that not be done with a scene-display list? It seems
1115 // stupid to rely on the mem allocation order...
1116 void KX_KetsjiEngine::ReplaceScheduledScenes()
1117 {
1118         if (m_replace_scenes.size())
1119         {
1120                 set<pair<STR_String,STR_String> >::iterator scenenameit;
1121                 
1122                 for (scenenameit = m_replace_scenes.begin();
1123                         scenenameit != m_replace_scenes.end();
1124                         scenenameit++)
1125                 {
1126                         STR_String oldscenename = (*scenenameit).first;
1127                         STR_String newscenename = (*scenenameit).second;
1128                         int i=0;
1129                         /* Scenes are not supposed to be included twice... I think */
1130                         KX_SceneList::iterator sceneit;
1131                         for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1132                         {
1133                                 KX_Scene* scene = *sceneit;
1134                                 if (scene->GetName() == oldscenename)
1135                                 {
1136                                         delete scene;
1137                                         KX_Scene* tmpscene = CreateScene(newscenename);
1138                                         m_scenes[i]=tmpscene;
1139                                         PostProcessScene(tmpscene);
1140                                 }
1141                                 i++;
1142                         }
1143                 }
1144                 m_replace_scenes.clear();
1145         }       
1146 }
1147
1148
1149
1150 void KX_KetsjiEngine::SuspendScene(const STR_String& scenename)
1151 {
1152         KX_Scene*  scene = FindScene(scenename);
1153         if (scene) scene->Suspend();
1154 }
1155
1156
1157
1158 void KX_KetsjiEngine::ResumeScene(const STR_String& scenename)
1159 {
1160         KX_Scene*  scene = FindScene(scenename);
1161         if (scene) scene->Resume();
1162 }
1163
1164
1165
1166 void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
1167 {
1168         m_bFixedTime = bUseFixedTime;
1169 }
1170
1171
1172
1173 bool KX_KetsjiEngine::GetUseFixedTime(void) const
1174 {
1175         return m_bFixedTime;
1176 }
1177
1178
1179
1180 void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
1181 {
1182         m_show_framerate = frameRate;
1183         m_show_profile = profile;
1184         m_show_debug_properties = properties;
1185 }
1186
1187
1188
1189 void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const
1190 {
1191         frameRate = m_show_framerate;
1192         profile = m_show_profile;
1193         properties = m_show_debug_properties;
1194 }
1195
1196
1197
1198 void KX_KetsjiEngine::ProcessScheduledScenes(void)
1199 {
1200         // Check whether there will be changes to the list of scenes
1201         if (m_addingOverlayScenes.size() ||
1202                 m_addingBackgroundScenes.size() ||
1203                 m_replace_scenes.size() ||
1204                 m_removingScenes.size()) {
1205
1206                 // Change the scene list
1207                 ReplaceScheduledScenes();
1208                 RemoveScheduledScenes();
1209                 AddScheduledScenes();
1210
1211                 // Notify
1212                 SceneListsChanged();
1213         }
1214 }
1215
1216
1217
1218 void KX_KetsjiEngine::SceneListsChanged(void)
1219 {
1220         m_propertiesPresent = false;
1221         KX_SceneList::iterator sceneit = m_scenes.begin();
1222         while ((sceneit != m_scenes.end()) && (!m_propertiesPresent))
1223         {
1224                 KX_Scene* scene = *sceneit;
1225                 vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();    
1226                 m_propertiesPresent = !debugproplist.empty();
1227                 sceneit++;
1228         }
1229 }
1230
1231
1232 void KX_KetsjiEngine::SetHideCursor(bool hideCursor)
1233 {
1234         m_hideCursor = hideCursor;
1235 }
1236
1237
1238 bool KX_KetsjiEngine::GetHideCursor(void) const
1239 {
1240         return m_hideCursor;
1241 }
1242
1243
1244 void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor)
1245 {
1246         m_overrideFrameColor = overrideFrameColor;
1247 }
1248
1249
1250 bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
1251 {
1252         return m_overrideFrameColor;
1253 }
1254
1255
1256 void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
1257 {
1258         m_overrideFrameColorR = r;
1259         m_overrideFrameColorG = g;
1260         m_overrideFrameColorB = b;
1261 }
1262
1263
1264 void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
1265 {
1266         r = m_overrideFrameColorR;
1267         g = m_overrideFrameColorG;
1268         b = m_overrideFrameColorB;
1269 }
1270