4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
28 * The engine ties all game modules together.
32 #pragma warning (disable : 4786)
37 #include "KX_KetsjiEngine.h"
39 #include "ListValue.h"
41 #include "VectorValue.h"
42 #include "BoolValue.h"
43 #include "FloatValue.h"
45 #define KX_NUM_ITERATIONS 4
46 #include "RAS_BucketManager.h"
48 #include "RAS_IRasterizer.h"
49 #include "RAS_IRenderTools.h"
50 #include "RAS_ICanvas.h"
51 #include "STR_String.h"
52 #include "MT_Vector3.h"
53 #include "MT_Transform.h"
54 #include "SCA_IInputDevice.h"
56 #include "MT_CmMatrix4x4.h"
57 #include "KX_Camera.h"
59 #include "KX_PythonInit.h"
60 #include "KX_PyConstraintBinding.h"
61 #include "PHY_IPhysicsEnvironment.h"
64 #include "SumoPhysicsEnvironment.h"
67 #include "SND_Scene.h"
68 #include "SND_IAudioDevice.h"
70 #include "NG_NetworkScene.h"
71 #include "NG_NetworkDeviceInterface.h"
73 #include "KX_WorldInfo.h"
74 #include "KX_ISceneConverter.h"
75 #include "KX_TimeCategoryLogger.h"
77 #include "RAS_FramingManager.h"
80 // If define: little test for Nzc: guarded drawing. If the canvas is
81 // not valid, skip rendering this frame.
82 //#define NZC_GUARDED_OUTPUT
83 #define DEFAULT_LOGIC_TIC_RATE 60.0
84 #define DEFAULT_PHYSICS_TIC_RATE 60.0
86 const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
87 "Physics:", // tc_physics
89 "Network:", // tc_network
90 "Scenegraph:", // tc_scenegraph
92 "Rasterizer:", // tc_rasterizer
93 "Services:", // tc_services
94 "Overhead:", // tc_overhead
95 "Outside:" // tc_outside
98 double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;
99 double KX_KetsjiEngine::m_anim_framerate = 25.0;
100 double KX_KetsjiEngine::m_suspendedtime = 0.0;
101 double KX_KetsjiEngine::m_suspendeddelta = 0.0;
102 double KX_KetsjiEngine::m_average_framerate = 0.0;
106 * Constructor of the Ketsji Engine
108 KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
113 m_sceneconverter(NULL),
114 m_networkdevice(NULL),
116 m_pythondictionary(NULL),
117 m_keyboarddevice(NULL),
120 m_propertiesPresent(false),
122 m_bInitialized(false),
130 m_previousClockTime(0.f),
133 m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
139 m_overrideCam(false),
140 m_overrideCamUseOrtho(false),
141 m_overrideCamNear(0.0),
142 m_overrideCamFar(0.0),
149 // Set up timing info display variables
150 m_show_framerate(false),
151 m_show_profile(false),
152 m_showProperties(false),
153 m_showBackground(false),
154 m_show_debug_properties(false),
158 // Default behavior is to hide the cursor every frame.
161 m_overrideFrameColor(false),
162 m_overrideFrameColorR(0.0),
163 m_overrideFrameColorG(0.0),
164 m_overrideFrameColorB(0.0)
166 // Initialize the time logger
167 m_logger = new KX_TimeCategoryLogger (25);
169 for (int i = tc_first; i < tc_numCategories; i++)
170 m_logger->AddCategory((KX_TimeCategory)i);
177 * Destructor of the Ketsji Engine, release all memory
179 KX_KetsjiEngine::~KX_KetsjiEngine()
186 void KX_KetsjiEngine::SetKeyboardDevice(SCA_IInputDevice* keyboarddevice)
188 MT_assert(keyboarddevice);
189 m_keyboarddevice = keyboarddevice;
194 void KX_KetsjiEngine::SetMouseDevice(SCA_IInputDevice* mousedevice)
196 MT_assert(mousedevice);
197 m_mousedevice = mousedevice;
202 void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice)
204 MT_assert(networkdevice);
205 m_networkdevice = networkdevice;
210 void KX_KetsjiEngine::SetAudioDevice(SND_IAudioDevice* audiodevice)
212 MT_assert(audiodevice);
213 m_audiodevice = audiodevice;
218 void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas)
226 void KX_KetsjiEngine::SetRenderTools(RAS_IRenderTools* rendertools)
228 MT_assert(rendertools);
229 m_rendertools = rendertools;
234 void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer)
236 MT_assert(rasterizer);
237 m_rasterizer = rasterizer;
242 * At the moment the GameLogic module is imported into 'pythondictionary' after this function is called.
243 * if this function ever changes to assign a copy, make sure the game logic module is imported into this dictionary before hand.
245 void KX_KetsjiEngine::SetPythonDictionary(PyObject* pythondictionary)
247 MT_assert(pythondictionary);
248 m_pythondictionary = pythondictionary;
253 void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter)
255 MT_assert(sceneconverter);
256 m_sceneconverter = sceneconverter;
262 * Ketsji Init(), Initializes datastructures and converts data from
263 * Blender into Ketsji native (realtime) format also sets up the
266 void KX_KetsjiEngine::StartEngine(bool clearIpo)
268 m_clockTime = m_kxsystem->GetTimeInSeconds();
269 m_frameTime = m_kxsystem->GetTimeInSeconds();
270 m_previousClockTime = m_kxsystem->GetTimeInSeconds();
273 m_bInitialized = true;
274 m_ticrate = DEFAULT_LOGIC_TIC_RATE;
278 m_sceneconverter->ResetPhysicsObjectsAnimationIpo(clearIpo);
279 m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame);
284 void KX_KetsjiEngine::ClearFrame()
286 // clear unless we're drawing overlapping stereo
287 if(m_rasterizer->InterlacedStereo() &&
288 m_rasterizer->GetEye() == RAS_IRasterizer::RAS_STEREO_RIGHTEYE)
291 // clear the viewports with the background color of the first scene
292 bool doclear = false;
293 KX_SceneList::iterator sceneit;
294 RAS_Rect clearvp, area, viewport;
296 for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++)
298 KX_Scene* scene = *sceneit;
299 //const RAS_FrameSettings &framesettings = scene->GetFramingType();
300 list<class KX_Camera*>* cameras = scene->GetCameras();
302 list<KX_Camera*>::iterator it;
303 for(it = cameras->begin(); it != cameras->end(); it++)
305 GetSceneViewport(scene, (*it), area, viewport);
312 if(viewport.GetLeft() < clearvp.GetLeft())
313 clearvp.SetLeft(viewport.GetLeft());
314 if(viewport.GetBottom() < clearvp.GetBottom())
315 clearvp.SetBottom(viewport.GetBottom());
316 if(viewport.GetRight() > clearvp.GetRight())
317 clearvp.SetRight(viewport.GetRight());
318 if(viewport.GetTop() > clearvp.GetTop())
319 clearvp.SetTop(viewport.GetTop());
326 KX_Scene* firstscene = *m_scenes.begin();
327 SetBackGround(firstscene->GetWorldInfo());
329 m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(),
330 clearvp.GetRight(), clearvp.GetTop());
331 m_rasterizer->ClearColorBuffer();
335 bool KX_KetsjiEngine::BeginFrame()
337 // set the area used for rendering (stereo can assign only a subset)
338 m_rasterizer->SetRenderArea();
340 if (m_canvas->BeginDraw())
344 m_rasterizer->BeginFrame(m_drawingmode , m_kxsystem->GetTimeInSeconds());
345 m_rendertools->BeginFrame(m_rasterizer);
354 void KX_KetsjiEngine::EndFrame()
356 // Show profiling info
357 m_logger->StartLog(tc_overhead, m_kxsystem->GetTimeInSeconds(), true);
358 if (m_show_framerate || m_show_profile || (m_show_debug_properties && m_propertiesPresent))
360 RenderDebugProperties();
363 m_average_framerate = m_logger->GetAverage();
364 if (m_average_framerate < 1e-6)
365 m_average_framerate = 1e-6;
366 m_average_framerate = 1.0/m_average_framerate;
368 // Go to next profiling measurement, time spend after this call is shown in the next frame.
369 m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds());
371 m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
372 m_rasterizer->EndFrame();
373 // swap backbuffer (drawing into this buffer) <-> front/visible buffer
374 m_rasterizer->SwapBuffers();
375 m_rendertools->EndFrame(m_rasterizer);
381 //#include "PIL_time.h"
382 //#include "LinearMath/btQuickprof.h"
385 bool KX_KetsjiEngine::NextFrame()
388 // static hidden::Clock sClock;
390 m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true);
392 //float dt = sClock.getTimeMicroseconds() * 0.000001f;
396 m_clockTime += 1./m_ticrate;
400 // m_clockTime += dt;
401 m_clockTime = m_kxsystem->GetTimeInSeconds();
404 double deltatime = m_clockTime - m_frameTime;
407 printf("problem with clock\n");
414 // Compute the number of logic frames to do each update (fixed tic bricks)
415 int frames =int(deltatime*m_ticrate+1e-6);
417 // printf("****************************************");
418 // printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
423 KX_SceneList::iterator sceneit;
429 // printf("framedOut: %d\n",frames);
430 m_frameTime+=(frames-frameOut)*(1.0/m_ticrate);
435 bool doRender = frames>0;
441 m_frameTime += 1.0/m_ticrate;
443 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
444 // for each scene, call the proceed functions
446 KX_Scene* scene = *sceneit;
448 /* Suspension holds the physics and logic processing for an
449 * entire scene. Objects can be suspended individually, and
450 * the settings for that preceed the logic and physics
452 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
454 m_sceneconverter->resetNoneDynamicObjectToIpo();//this is for none dynamic objects with ipo
456 scene->UpdateObjectActivity();
458 if (!scene->IsSuspended())
460 // if the scene was suspended recalcutlate the delta tu "curtime"
461 m_suspendedtime = scene->getSuspendedTime();
462 if (scene->getSuspendedTime()!=0.0)
463 scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
464 m_suspendeddelta = scene->getSuspendedDelta();
467 m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
468 SG_SetActiveStage(SG_STAGE_NETWORK);
469 scene->GetNetworkScene()->proceed(m_frameTime);
471 //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
472 //SG_SetActiveStage(SG_STAGE_NETWORK_UPDATE);
473 //scene->UpdateParents(m_frameTime);
475 m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
476 SG_SetActiveStage(SG_STAGE_PHYSICS1);
477 // set Python hooks for each scene
478 PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
479 KX_SetActiveScene(scene);
481 scene->GetPhysicsEnvironment()->endFrame();
483 // Update scenegraph after physics step. This maps physics calculations
484 // into node positions.
485 //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
486 //SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE);
487 //scene->UpdateParents(m_frameTime);
489 // Process sensors, and controllers
490 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
491 SG_SetActiveStage(SG_STAGE_CONTROLLER);
492 scene->LogicBeginFrame(m_frameTime);
494 // Scenegraph needs to be updated again, because Logic Controllers
495 // can affect the local matrices.
496 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
497 SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE);
498 scene->UpdateParents(m_frameTime);
502 // Do some cleanup work for this logic frame
503 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
504 SG_SetActiveStage(SG_STAGE_ACTUATOR);
505 scene->LogicUpdateFrame(m_frameTime, true);
507 scene->LogicEndFrame();
509 // Actuators can affect the scenegraph
510 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
511 SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE);
512 scene->UpdateParents(m_frameTime);
514 m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
515 SG_SetActiveStage(SG_STAGE_PHYSICS2);
516 scene->GetPhysicsEnvironment()->beginFrame();
518 // Perform physics calculations on the scene. This can involve
519 // many iterations of the physics solver.
520 scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,1.0/m_ticrate);//m_deltatimerealDeltaTime);
522 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
523 SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE);
524 scene->UpdateParents(m_frameTime);
529 m_sceneconverter->WritePhysicsObjectToAnimationIpo(++m_currentFrame);
532 scene->setSuspendedTime(0.0);
535 if(scene->getSuspendedTime()==0.0)
536 scene->setSuspendedTime(m_clockTime);
540 m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
543 // update system devices
544 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
545 if (m_keyboarddevice)
546 m_keyboarddevice->NextFrame();
549 m_mousedevice->NextFrame();
552 m_networkdevice->NextFrame();
555 m_audiodevice->NextFrame();
558 ProcessScheduledScenes();
563 bool bUseAsyncLogicBricks= false;//true;
565 if (bUseAsyncLogicBricks)
567 // Logic update sub frame: this will let some logic bricks run at the
569 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
570 // for each scene, call the proceed functions
572 KX_Scene* scene = *sceneit;
574 if (!scene->IsSuspended())
576 // if the scene was suspended recalcutlate the delta tu "curtime"
577 m_suspendedtime = scene->getSuspendedTime();
578 if (scene->getSuspendedTime()!=0.0)
579 scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
580 m_suspendeddelta = scene->getSuspendedDelta();
582 // set Python hooks for each scene
583 PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
584 KX_SetActiveScene(scene);
586 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
587 SG_SetActiveStage(SG_STAGE_PHYSICS1);
588 scene->UpdateParents(m_clockTime);
590 // Perform physics calculations on the scene. This can involve
591 // many iterations of the physics solver.
592 m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
593 scene->GetPhysicsEnvironment()->proceedDeltaTime(m_clockTime,0.f);
594 // Update scenegraph after physics step. This maps physics calculations
595 // into node positions.
596 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
597 SG_SetActiveStage(SG_STAGE_PHYSICS2);
598 scene->UpdateParents(m_clockTime);
600 // Do some cleanup work for this logic frame
601 m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
602 scene->LogicUpdateFrame(m_clockTime, false);
604 // Actuators can affect the scenegraph
605 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
606 SG_SetActiveStage(SG_STAGE_ACTUATOR);
607 scene->UpdateParents(m_clockTime);
609 scene->setSuspendedTime(0.0);
612 if(scene->getSuspendedTime()==0.0)
613 scene->setSuspendedTime(m_clockTime);
617 m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
622 m_previousClockTime = m_clockTime;
624 // Start logging time spend outside main loop
625 m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
632 void KX_KetsjiEngine::Render()
634 KX_Scene* firstscene = *m_scenes.begin();
635 const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
637 m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
638 SG_SetActiveStage(SG_STAGE_RENDER);
640 // hiding mouse cursor each frame
641 // (came back when going out of focus and then back in again)
643 m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
645 // clear the entire game screen with the border color
646 // only once per frame
647 m_canvas->BeginDraw();
648 if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED) {
649 m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
650 if (m_overrideFrameColor)
652 // Do not use the framing bar color set in the Blender scenes
653 m_canvas->ClearColor(
654 m_overrideFrameColorR,
655 m_overrideFrameColorG,
656 m_overrideFrameColorB,
662 // Use the framing bar color set in the Blender scenes
663 m_canvas->ClearColor(
664 framesettings.BarRed(),
665 framesettings.BarGreen(),
666 framesettings.BarBlue(),
670 // clear the -whole- viewport
671 m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
674 m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
676 // BeginFrame() sets the actual drawing area. You can use a part of the window
680 KX_SceneList::iterator sceneit;
681 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
682 // for each scene, call the proceed functions
684 KX_Scene* scene = *sceneit;
685 KX_Camera* cam = scene->GetActiveCamera();
686 // pass the scene's worldsettings to the rasterizer
687 SetWorldSettings(scene->GetWorldInfo());
690 RenderShadowBuffers(scene);
692 // Avoid drawing the scene with the active camera twice when it's viewport is enabled
693 if(cam && !cam->GetViewport())
695 if (scene->IsClearingZBuffer())
696 m_rasterizer->ClearDepthBuffer();
698 m_rendertools->SetAuxilaryClientInfo(scene);
701 RenderFrame(scene, cam);
704 list<class KX_Camera*>* cameras = scene->GetCameras();
706 // Draw the scene once for each camera with an enabled viewport
707 list<KX_Camera*>::iterator it = cameras->begin();
708 while(it != cameras->end())
710 if((*it)->GetViewport())
712 if (scene->IsClearingZBuffer())
713 m_rasterizer->ClearDepthBuffer();
715 m_rendertools->SetAuxilaryClientInfo(scene);
718 RenderFrame(scene, (*it));
725 // only one place that checks for stereo
726 if(m_rasterizer->Stereo())
728 m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
734 for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
735 // for each scene, call the proceed functions
737 KX_Scene* scene = *sceneit;
738 KX_Camera* cam = scene->GetActiveCamera();
740 // pass the scene's worldsettings to the rasterizer
741 SetWorldSettings(scene->GetWorldInfo());
743 if (scene->IsClearingZBuffer())
744 m_rasterizer->ClearDepthBuffer();
746 //pass the scene, for picking and raycasting (shadows)
747 m_rendertools->SetAuxilaryClientInfo(scene);
750 //RenderFrame(scene);
751 RenderFrame(scene, cam);
753 list<class KX_Camera*>* cameras = scene->GetCameras();
755 // Draw the scene once for each camera with an enabled viewport
756 list<KX_Camera*>::iterator it = cameras->begin();
757 while(it != cameras->end())
759 if((*it)->GetViewport())
761 if (scene->IsClearingZBuffer())
762 m_rasterizer->ClearDepthBuffer();
764 m_rendertools->SetAuxilaryClientInfo(scene);
767 RenderFrame(scene, (*it));
773 } // if(m_rasterizer->Stereo())
780 void KX_KetsjiEngine::RequestExit(int exitrequestmode)
782 m_exitcode = exitrequestmode;
787 void KX_KetsjiEngine::SetNameNextGame(const STR_String& nextgame)
789 m_exitstring = nextgame;
794 int KX_KetsjiEngine::GetExitCode()
796 // if a gameactuator has set an exitcode or if there are no scenes left
799 if (m_scenes.begin()==m_scenes.end())
800 m_exitcode = KX_EXIT_REQUEST_NO_SCENES_LEFT;
808 const STR_String& KX_KetsjiEngine::GetExitString()
815 void KX_KetsjiEngine::DoSound(KX_Scene* scene)
817 m_logger->StartLog(tc_sound, m_kxsystem->GetTimeInSeconds(), true);
819 KX_Camera* cam = scene->GetActiveCamera();
822 MT_Point3 listenerposition = cam->NodeGetWorldPosition();
823 MT_Vector3 listenervelocity = cam->GetLinearVelocity();
824 MT_Matrix3x3 listenerorientation = cam->NodeGetWorldOrientation();
826 SND_Scene* soundscene = scene->GetSoundScene();
827 soundscene->SetListenerTransform(
830 listenerorientation);
832 soundscene->Proceed();
837 void KX_KetsjiEngine::SetBackGround(KX_WorldInfo* wi)
841 if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED)
843 m_rasterizer->SetBackColor(
844 wi->getBackColorRed(),
845 wi->getBackColorGreen(),
846 wi->getBackColorBlue(),
855 void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi)
860 m_rasterizer->SetAmbientColor(
861 wi->getAmbientColorRed(),
862 wi->getAmbientColorGreen(),
863 wi->getAmbientColorBlue()
866 if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED)
870 m_rasterizer->SetFog(
872 wi->getMistDistance(),
873 wi->getMistColorRed(),
874 wi->getMistColorGreen(),
875 wi->getMistColorBlue()
880 m_rasterizer->DisableFog();
888 void KX_KetsjiEngine::SetDrawType(int drawingmode)
890 m_drawingmode = drawingmode;
895 void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene)
897 m_overrideCam = true;
898 m_overrideSceneName = forscene;
903 void KX_KetsjiEngine::SetCameraZoom(float camzoom)
905 m_cameraZoom = camzoom;
910 void KX_KetsjiEngine::SetCameraOverrideUseOrtho(bool useOrtho)
912 m_overrideCamUseOrtho = useOrtho;
917 void KX_KetsjiEngine::SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat)
919 m_overrideCamProjMat = mat;
923 void KX_KetsjiEngine::SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat)
925 m_overrideCamViewMat = mat;
928 void KX_KetsjiEngine::SetCameraOverrideClipping(float near, float far)
930 m_overrideCamNear = near;
931 m_overrideCamFar = far;
934 void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport)
936 // In this function we make sure the rasterizer settings are upto
937 // date. We compute the viewport so that logic
938 // using this information is upto date.
940 // Note we postpone computation of the projection matrix
941 // so that we are using the latest camera position.
942 if (cam->GetViewport()) {
943 RAS_Rect userviewport;
945 userviewport.SetLeft(cam->GetViewportLeft());
946 userviewport.SetBottom(cam->GetViewportBottom());
947 userviewport.SetRight(cam->GetViewportRight());
948 userviewport.SetTop(cam->GetViewportTop());
950 // Don't do bars on user specified viewport
951 RAS_FrameSettings settings = scene->GetFramingType();
952 if(settings.FrameType() == RAS_FrameSettings::e_frame_bars)
953 settings.SetFrameType(RAS_FrameSettings::e_frame_extend);
955 RAS_FramingManager::ComputeViewport(
956 scene->GetFramingType(),
963 else if ( m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) {
964 RAS_FramingManager::ComputeViewport(
965 scene->GetFramingType(),
966 m_canvas->GetDisplayArea(),
970 area = m_canvas->GetDisplayArea();
973 viewport.SetBottom(0);
974 viewport.SetRight(int(m_canvas->GetWidth()));
975 viewport.SetTop(int(m_canvas->GetHeight()));
977 area = m_canvas->GetDisplayArea();
981 void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
983 CListValue *objectlist = scene->GetObjectList();
986 m_rendertools->SetAuxilaryClientInfo(scene);
988 for(i=0; i<objectlist->GetCount(); i++) {
989 KX_GameObject *gameobj = (KX_GameObject*)objectlist->GetValue(i);
991 if(!gameobj->IsLight())
994 KX_LightObject *light = (KX_LightObject*)gameobj;
998 if(m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) {
999 /* make temporary camera */
1000 RAS_CameraData camdata = RAS_CameraData();
1001 KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, false);
1002 cam->SetName("__shadow__cam__");
1004 MT_Transform camtrans;
1006 /* switch drawmode for speed */
1007 drawmode = m_rasterizer->GetDrawingMode();
1008 m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW);
1010 /* binds framebuffer object, sets up camera .. */
1011 light->BindShadowBuffer(m_rasterizer, cam, camtrans);
1014 scene->UpdateMeshTransformations();
1015 scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer());
1018 m_rasterizer->ClearDepthBuffer();
1019 scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
1021 /* unbind framebuffer object, restore drawmode, free camera */
1022 light->UnbindShadowBuffer(m_rasterizer);
1023 m_rasterizer->SetDrawingMode(drawmode);
1030 void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
1032 bool override_camera;
1033 RAS_Rect viewport, area;
1034 float left, right, bottom, top, nearfrust, farfrust, focallength;
1035 const float ortho = 100.0;
1036 // KX_Camera* cam = scene->GetActiveCamera();
1041 GetSceneViewport(scene, cam, area, viewport);
1043 // store the computed viewport in the scene
1044 scene->SetSceneViewport(viewport);
1046 // set the viewport for this frame and scene
1047 m_canvas->SetViewPort(viewport.GetLeft(), viewport.GetBottom(),
1048 viewport.GetRight(), viewport.GetTop());
1050 // see KX_BlenderMaterial::Activate
1051 //m_rasterizer->SetAmbient();
1052 m_rasterizer->DisplayFog();
1054 override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName);
1055 override_camera = override_camera && (cam->GetName() == "__default__cam__");
1057 if (override_camera && m_overrideCamUseOrtho) {
1058 MT_CmMatrix4x4 projmat = m_overrideCamProjMat;
1059 m_rasterizer->SetProjectionMatrix(projmat);
1060 } else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() )
1062 m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
1065 RAS_FrameFrustum frustum;
1066 float lens = cam->GetLens();
1067 bool orthographic = !cam->GetCameraData()->m_perspective;
1068 nearfrust = cam->GetCameraNear();
1069 farfrust = cam->GetCameraFar();
1070 focallength = cam->GetFocalLength();
1072 if(override_camera) {
1073 nearfrust = m_overrideCamNear;
1074 farfrust = m_overrideCamFar;
1079 nearfrust = (nearfrust + 1.0)*ortho;
1083 RAS_FramingManager::ComputeFrustum(
1084 scene->GetFramingType(),
1093 left = frustum.x1 * m_cameraZoom;
1094 right = frustum.x2 * m_cameraZoom;
1095 bottom = frustum.y1 * m_cameraZoom;
1096 top = frustum.y2 * m_cameraZoom;
1097 nearfrust = frustum.camnear;
1098 farfrust = frustum.camfar;
1100 MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
1101 left, right, bottom, top, nearfrust, farfrust, focallength);
1103 cam->SetProjectionMatrix(projmat);
1105 // Otherwise the projection matrix for each eye will be the same...
1106 if (m_rasterizer->Stereo())
1107 cam->InvalidateProjectionMatrix();
1110 MT_Transform camtrans(cam->GetWorldToCamera());
1111 if (!cam->GetCameraData()->m_perspective)
1112 camtrans.getOrigin()[2] *= ortho;
1113 MT_Matrix4x4 viewmat(camtrans);
1115 m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
1116 cam->GetCameraLocation(), cam->GetCameraOrientation());
1117 cam->SetModelviewMatrix(viewmat);
1119 //redundant, already done in
1120 //scene->UpdateMeshTransformations();
1122 // The following actually reschedules all vertices to be
1123 // redrawn. There is a cache between the actual rescheduling
1124 // and this call though. Visibility is imparted when this call
1125 // runs through the individual objects.
1127 m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
1128 SG_SetActiveStage(SG_STAGE_CULLING);
1130 scene->CalculateVisibleMeshes(m_rasterizer,cam);
1132 m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
1133 SG_SetActiveStage(SG_STAGE_RENDER);
1135 scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
1137 if (scene->GetPhysicsEnvironment())
1138 scene->GetPhysicsEnvironment()->debugDrawWorld();
1140 m_rasterizer->FlushDebugLines();
1145 void KX_KetsjiEngine::PostRenderFrame()
1147 m_rendertools->PushMatrix();
1148 m_rendertools->Render2DFilters(m_canvas);
1149 m_rendertools->MotionBlur(m_rasterizer);
1150 m_rendertools->PopMatrix();
1153 void KX_KetsjiEngine::StopEngine()
1160 // printf("TestHandlesPhysicsObjectToAnimationIpo\n");
1161 m_sceneconverter->TestHandlesPhysicsObjectToAnimationIpo();
1164 KX_SceneList::iterator sceneit;
1165 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1167 KX_Scene* scene = *sceneit;
1168 m_sceneconverter->RemoveScene(scene);
1172 // cleanup all the stuff
1173 m_rasterizer->Exit();
1177 // Scene Management is able to switch between scenes
1178 // and have several scene's running in parallel
1179 void KX_KetsjiEngine::AddScene(KX_Scene* scene)
1181 m_scenes.push_back(scene);
1182 PostProcessScene(scene);
1183 SceneListsChanged();
1188 void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
1190 bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName));
1192 SG_SetActiveStage(SG_STAGE_SCENE);
1194 // if there is no activecamera, or the camera is being
1195 // overridden we need to construct a temporarily camera
1196 if (!scene->GetActiveCamera() || override_camera)
1198 KX_Camera* activecam = NULL;
1200 RAS_CameraData camdata = RAS_CameraData();
1201 activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata);
1202 activecam->SetName("__default__cam__");
1204 // set transformation
1205 if (override_camera) {
1206 const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat;
1207 MT_Transform trans = MT_Transform(cammatdata.getPointer());
1208 MT_Transform camtrans;
1209 camtrans.invert(trans);
1211 activecam->NodeSetLocalPosition(camtrans.getOrigin());
1212 activecam->NodeSetLocalOrientation(camtrans.getBasis());
1213 activecam->NodeUpdateGS(0);
1215 activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
1216 activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
1217 activecam->NodeUpdateGS(0);
1220 scene->AddCamera(activecam);
1221 scene->SetActiveCamera(activecam);
1222 scene->GetObjectList()->Add(activecam->AddRef());
1223 scene->GetRootParentList()->Add(activecam->AddRef());
1224 //done with activecam
1225 activecam->Release();
1228 scene->UpdateParents(0.0);
1233 void KX_KetsjiEngine::RenderDebugProperties()
1235 STR_String debugtxt;
1236 int xcoord = 10; // mmmm, these constants were taken from blender source
1237 int ycoord = 14; // to 'mimic' behaviour
1239 float tottime = m_logger->GetAverage();
1240 if (tottime < 1e-6f) {
1244 // Set viewport to entire canvas
1246 m_canvas->SetViewPort(0, 0, int(m_canvas->GetWidth()), int(m_canvas->GetHeight()));
1248 /* Framerate display */
1249 if (m_show_framerate) {
1250 debugtxt.Format("swap : %.3f (%.3f frames per second)", tottime, 1.0/tottime);
1251 m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
1255 m_canvas->GetWidth() /* RdV, TODO ?? */,
1256 m_canvas->GetHeight() /* RdV, TODO ?? */);
1260 /* Profile and framerate display */
1263 for (int j = tc_first; j < tc_numCategories; j++)
1265 debugtxt.Format(m_profileLabels[j]);
1266 m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
1269 m_canvas->GetWidth(),
1270 m_canvas->GetHeight());
1271 double time = m_logger->GetAverage((KX_TimeCategory)j);
1272 debugtxt.Format("%2.2f %%", time/tottime * 100.f);
1273 m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
1275 xcoord + 60 ,ycoord,
1276 m_canvas->GetWidth(),
1277 m_canvas->GetHeight());
1282 /* Property display*/
1283 if (m_show_debug_properties && m_propertiesPresent)
1285 KX_SceneList::iterator sceneit;
1286 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1288 KX_Scene* scene = *sceneit;
1289 /* the 'normal' debug props */
1290 vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
1292 for (vector<SCA_DebugProp*>::iterator it = debugproplist.begin();
1293 !(it==debugproplist.end());it++)
1295 CValue* propobj = (*it)->m_obj;
1296 STR_String objname = propobj->GetName();
1297 STR_String propname = (*it)->m_name;
1298 if (propname == "__state__")
1300 // reserve name for object state
1301 KX_GameObject* gameobj = static_cast<KX_GameObject*>(propobj);
1302 unsigned int state = gameobj->GetState();
1303 debugtxt = objname + "." + propname + " = ";
1305 for (int statenum=1;state;state >>= 1, statenum++)
1313 debugtxt += STR_String(statenum);
1317 m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
1321 m_canvas->GetWidth(),
1322 m_canvas->GetHeight());
1327 CValue* propval = propobj->GetProperty(propname);
1330 STR_String text = propval->GetText();
1331 debugtxt = objname + "." + propname + " = " + text;
1332 m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
1336 m_canvas->GetWidth(),
1337 m_canvas->GetHeight());
1347 KX_SceneList* KX_KetsjiEngine::CurrentScenes()
1354 KX_Scene* KX_KetsjiEngine::FindScene(const STR_String& scenename)
1356 KX_SceneList::iterator sceneit = m_scenes.begin();
1358 // bit risky :) better to split the second clause
1359 while ( (sceneit != m_scenes.end())
1360 && ((*sceneit)->GetName() != scenename))
1365 return ((sceneit == m_scenes.end()) ? NULL : *sceneit);
1370 void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overlay)
1372 // only add scene when it doesn't exist!
1373 if (FindScene(scenename))
1375 STR_String tmpname = scenename;
1376 printf("warning: scene %s already exists, not added!\n",tmpname.Ptr());
1382 m_addingOverlayScenes.insert(scenename);
1386 m_addingBackgroundScenes.insert(scenename);
1394 void KX_KetsjiEngine::RemoveScene(const STR_String& scenename)
1396 if (FindScene(scenename))
1398 m_removingScenes.insert(scenename);
1402 // STR_String tmpname = scenename;
1403 std::cout << "warning: scene " << scenename << " does not exist, not removed!" << std::endl;
1409 void KX_KetsjiEngine::RemoveScheduledScenes()
1411 if (m_removingScenes.size())
1413 set<STR_String>::iterator scenenameit;
1414 for (scenenameit=m_removingScenes.begin();scenenameit != m_removingScenes.end();scenenameit++)
1416 STR_String scenename = *scenenameit;
1418 KX_SceneList::iterator sceneit;
1419 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1421 KX_Scene* scene = *sceneit;
1422 if (scene->GetName()==scenename)
1424 m_sceneconverter->RemoveScene(scene);
1425 m_scenes.erase(sceneit);
1430 m_removingScenes.clear();
1436 KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename)
1438 Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename);
1439 KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice,
1446 m_sceneconverter->ConvertScene(scenename,
1458 void KX_KetsjiEngine::AddScheduledScenes()
1460 set<STR_String>::iterator scenenameit;
1462 if (m_addingOverlayScenes.size())
1464 for (scenenameit = m_addingOverlayScenes.begin();
1465 scenenameit != m_addingOverlayScenes.end();
1468 STR_String scenename = *scenenameit;
1469 KX_Scene* tmpscene = CreateScene(scenename);
1470 m_scenes.push_back(tmpscene);
1471 PostProcessScene(tmpscene);
1473 m_addingOverlayScenes.clear();
1476 if (m_addingBackgroundScenes.size())
1478 for (scenenameit = m_addingBackgroundScenes.begin();
1479 scenenameit != m_addingBackgroundScenes.end();
1482 STR_String scenename = *scenenameit;
1483 KX_Scene* tmpscene = CreateScene(scenename);
1484 m_scenes.insert(m_scenes.begin(),tmpscene);
1485 PostProcessScene(tmpscene);
1488 m_addingBackgroundScenes.clear();
1494 void KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
1496 m_replace_scenes.insert(std::make_pair(oldscene,newscene));
1499 // replace scene is not the same as removing and adding because the
1500 // scene must be in exact the same place (to maintain drawingorder)
1501 // (nzc) - should that not be done with a scene-display list? It seems
1502 // stupid to rely on the mem allocation order...
1503 void KX_KetsjiEngine::ReplaceScheduledScenes()
1505 if (m_replace_scenes.size())
1507 set<pair<STR_String,STR_String> >::iterator scenenameit;
1509 for (scenenameit = m_replace_scenes.begin();
1510 scenenameit != m_replace_scenes.end();
1513 STR_String oldscenename = (*scenenameit).first;
1514 STR_String newscenename = (*scenenameit).second;
1516 /* Scenes are not supposed to be included twice... I think */
1517 KX_SceneList::iterator sceneit;
1518 for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
1520 KX_Scene* scene = *sceneit;
1521 if (scene->GetName() == oldscenename)
1523 m_sceneconverter->RemoveScene(scene);
1524 KX_Scene* tmpscene = CreateScene(newscenename);
1525 m_scenes[i]=tmpscene;
1526 PostProcessScene(tmpscene);
1531 m_replace_scenes.clear();
1537 void KX_KetsjiEngine::SuspendScene(const STR_String& scenename)
1539 KX_Scene* scene = FindScene(scenename);
1540 if (scene) scene->Suspend();
1545 void KX_KetsjiEngine::ResumeScene(const STR_String& scenename)
1547 KX_Scene* scene = FindScene(scenename);
1548 if (scene) scene->Resume();
1553 void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
1555 m_bFixedTime = bUseFixedTime;
1559 void KX_KetsjiEngine::SetGame2IpoMode(bool game2ipo,int startFrame)
1561 m_game2ipo = game2ipo;
1564 //when recording physics keyframes, always run at a fixed framerate
1565 m_bFixedTime = true;
1567 m_currentFrame = startFrame;
1570 bool KX_KetsjiEngine::GetUseFixedTime(void) const
1572 return m_bFixedTime;
1575 double KX_KetsjiEngine::GetSuspendedDelta()
1577 return m_suspendeddelta;
1580 double KX_KetsjiEngine::GetTicRate()
1585 void KX_KetsjiEngine::SetTicRate(double ticrate)
1587 m_ticrate = ticrate;
1590 double KX_KetsjiEngine::GetAnimFrameRate()
1592 return m_anim_framerate;
1595 double KX_KetsjiEngine::GetClockTime(void) const
1600 void KX_KetsjiEngine::SetAnimFrameRate(double framerate)
1602 m_anim_framerate = framerate;
1605 double KX_KetsjiEngine::GetAverageFrameRate()
1607 return m_average_framerate;
1610 void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
1612 m_show_framerate = frameRate;
1613 m_show_profile = profile;
1614 m_show_debug_properties = properties;
1619 void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const
1621 frameRate = m_show_framerate;
1622 profile = m_show_profile;
1623 properties = m_show_debug_properties;
1628 void KX_KetsjiEngine::ProcessScheduledScenes(void)
1630 // Check whether there will be changes to the list of scenes
1631 if (m_addingOverlayScenes.size() ||
1632 m_addingBackgroundScenes.size() ||
1633 m_replace_scenes.size() ||
1634 m_removingScenes.size()) {
1636 // Change the scene list
1637 ReplaceScheduledScenes();
1638 RemoveScheduledScenes();
1639 AddScheduledScenes();
1642 SceneListsChanged();
1648 void KX_KetsjiEngine::SceneListsChanged(void)
1650 m_propertiesPresent = false;
1651 KX_SceneList::iterator sceneit = m_scenes.begin();
1652 while ((sceneit != m_scenes.end()) && (!m_propertiesPresent))
1654 KX_Scene* scene = *sceneit;
1655 vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
1656 m_propertiesPresent = !debugproplist.empty();
1662 void KX_KetsjiEngine::SetHideCursor(bool hideCursor)
1664 m_hideCursor = hideCursor;
1668 bool KX_KetsjiEngine::GetHideCursor(void) const
1670 return m_hideCursor;
1674 void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor)
1676 m_overrideFrameColor = overrideFrameColor;
1680 bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
1682 return m_overrideFrameColor;
1686 void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
1688 m_overrideFrameColorR = r;
1689 m_overrideFrameColorG = g;
1690 m_overrideFrameColorB = b;
1694 void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
1696 r = m_overrideFrameColorR;
1697 g = m_overrideFrameColorG;
1698 b = m_overrideFrameColorB;