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