Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/gameengine/Ketsji/KX_KetsjiEngine.cpp')
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp1250
1 files changed, 1250 insertions, 0 deletions
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
new file mode 100644
index 00000000000..c03e4e3d964
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -0,0 +1,1250 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * The engine ties all game modules together.
+ */
+#ifdef WIN32
+#pragma warning (disable : 4786)
+#endif //WIN32
+
+#include <iostream>
+
+#include "KX_KetsjiEngine.h"
+
+#include "ListValue.h"
+#include "IntValue.h"
+#include "VectorValue.h"
+#include "BoolValue.h"
+#include "FloatValue.h"
+
+#define KX_NUM_ITERATIONS 4
+#include "RAS_BucketManager.h"
+#include "RAS_Rect.h"
+#include "RAS_IRasterizer.h"
+#include "RAS_IRenderTools.h"
+#include "RAS_ICanvas.h"
+#include "STR_String.h"
+#include "MT_Vector3.h"
+#include "MT_Transform.h"
+#include "SCA_IInputDevice.h"
+#include "KX_Scene.h"
+#include "MT_CmMatrix4x4.h"
+#include "KX_Camera.h"
+#include "KX_PythonInit.h"
+#include "KX_PyConstraintBinding.h"
+#include "PHY_IPhysicsEnvironment.h"
+
+#include "SND_Scene.h"
+#include "SND_IAudioDevice.h"
+
+#include "NG_NetworkScene.h"
+#include "NG_NetworkDeviceInterface.h"
+
+#include "KX_WorldInfo.h"
+#include "KX_ISceneConverter.h"
+#include "KX_TimeCategoryLogger.h"
+
+#include "RAS_FramingManager.h"
+
+// If define: little test for Nzc: guarded drawing. If the canvas is
+// not valid, skip rendering this frame.
+//#define NZC_GUARDED_OUTPUT
+
+
+const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
+ "Physics:", // tc_physics
+ "Logic", // tc_logic
+ "Network:", // tc_network
+ "Scenegraph:", // tc_scenegraph
+ "Sound:", // tc_sound
+ "Rasterizer:", // tc_rasterizer
+ "Services:", // tc_services
+ "Overhead:", // tc_overhead
+ "Outside:" // tc_outside
+};
+
+
+
+
+/**
+ * Constructor of the Ketsji Engine
+ */
+KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
+: m_bInitialized(false),
+ m_activecam(0),
+ m_rasterizer(NULL)
+{
+ m_kxsystem = system;
+ m_bFixedTime = false;
+
+ // Initialize the time logger
+ m_logger = new KX_TimeCategoryLogger (25);
+
+ for (int i = tc_first; i < tc_numCategories; i++)
+ m_logger->AddCategory((KX_TimeCategory)i);
+
+ // Set up timing info display variables
+ m_show_framerate = false;
+ m_show_profile = false;
+ m_show_debug_properties = false;
+ m_propertiesPresent = false;
+
+ // Default behavior is to hide the cursor every frame.
+ m_hideCursor = false;
+
+ m_overrideFrameColor = false;
+ m_overrideFrameColorR = (float)0;
+ m_overrideFrameColorG = (float)0;
+ m_overrideFrameColorB = (float)0;
+
+ m_cameraZoom = 1.0;
+ m_drawingmode = 5; /* textured drawing mode */
+ m_overrideCam = false;
+
+ m_exitcode = KX_EXIT_REQUEST_NO_REQUEST;
+ m_exitstring = "";
+}
+
+
+
+/**
+ * Destructor of the Ketsji Engine, release all memory
+ */
+KX_KetsjiEngine::~KX_KetsjiEngine()
+{
+ if (m_logger)
+ delete m_logger;
+}
+
+
+
+void KX_KetsjiEngine::SetKeyboardDevice(SCA_IInputDevice* keyboarddevice)
+{
+ assert(keyboarddevice);
+ m_keyboarddevice = keyboarddevice;
+}
+
+
+
+void KX_KetsjiEngine::SetMouseDevice(SCA_IInputDevice* mousedevice)
+{
+ assert(mousedevice);
+ m_mousedevice = mousedevice;
+}
+
+
+
+void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice)
+{
+ assert(networkdevice);
+ m_networkdevice = networkdevice;
+}
+
+
+
+void KX_KetsjiEngine::SetAudioDevice(SND_IAudioDevice* audiodevice)
+{
+ assert(audiodevice);
+ m_audiodevice = audiodevice;
+}
+
+
+
+void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas)
+{
+ assert(canvas);
+ m_canvas = canvas;
+}
+
+
+
+void KX_KetsjiEngine::SetRenderTools(RAS_IRenderTools* rendertools)
+{
+ assert(rendertools);
+ m_rendertools = rendertools;
+}
+
+
+
+void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer)
+{
+ assert(rasterizer);
+ m_rasterizer = rasterizer;
+}
+
+
+
+void KX_KetsjiEngine::SetPythonDictionary(PyObject* pythondictionary)
+{
+ assert(pythondictionary);
+ m_pythondictionary = pythondictionary;
+}
+
+
+
+void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter)
+{
+ assert(sceneconverter);
+ m_sceneconverter = sceneconverter;
+}
+
+
+
+/**
+ * Ketsji Init(), Initializes datastructures and converts data from
+ * Blender into Ketsji native (realtime) format also sets up the
+ * graphics context
+ */
+void KX_KetsjiEngine::StartEngine()
+{
+ m_previoustime = 0.0;
+ m_missedtime = 0.0;
+ m_firstframe = true;
+
+ // for all scenes, initialize the scenegraph for the first time
+ m_lasttime = m_kxsystem->GetTimeInSeconds()*100.0;
+
+ m_bInitialized = true;
+}
+
+
+
+#define DELTALENGTH 25
+
+double KX_KetsjiEngine::CalculateAverage(double newdelta)
+{
+ if (m_deltatimes.size() < DELTALENGTH)
+ {
+ m_deltatimes.push_back(newdelta);
+ } else
+ {
+ //
+ double totaltime = 0.0;
+ double newlasttime,lasttime = newdelta;
+ double peakmin = 10000;
+ double peakmax = -10000;
+
+ for (int i=m_deltatimes.size()-1;i>=0;i--)
+ { newlasttime = m_deltatimes[i];
+ totaltime += newlasttime;
+ if (peakmin > newlasttime)
+ peakmin = newlasttime;
+ if (peakmax < newlasttime)
+ peakmax = newlasttime;
+
+ m_deltatimes[i] = lasttime;
+ lasttime = newlasttime;
+ };
+ double averagetime;
+
+ if (peakmin < peakmax)
+ {
+ averagetime = ((totaltime - peakmin) - peakmax) / (double) (m_deltatimes.size()-2);
+ } else
+ {
+ averagetime = totaltime / (double) m_deltatimes.size();
+ }
+ return averagetime;
+ }
+
+ return newdelta;
+}
+
+
+
+bool KX_KetsjiEngine::BeginFrame()
+{
+ bool result = false;
+
+ RAS_Rect vp;
+ KX_Scene* firstscene = *m_scenes.begin();
+ const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
+
+ // set the area used for rendering
+ m_rasterizer->SetRenderArea();
+
+ RAS_FramingManager::ComputeViewport(framesettings, m_canvas->GetDisplayArea(), vp);
+
+ if (m_canvas->BeginDraw())
+ {
+ result = true;
+
+ m_canvas->SetViewPort(vp.GetLeft(), vp.GetBottom(), vp.GetRight(), vp.GetTop());
+ SetBackGround( firstscene->GetWorldInfo() );
+ m_rasterizer->BeginFrame( m_drawingmode , m_kxsystem->GetTimeInSeconds());
+ m_rendertools->BeginFrame( m_rasterizer);
+ }
+
+ return result;
+}
+
+
+void KX_KetsjiEngine::EndFrame()
+{
+ // Show profiling info
+ m_logger->StartLog(tc_overhead, m_kxsystem->GetTimeInSeconds(), true);
+ if (m_show_framerate || m_show_profile || (m_show_debug_properties && m_propertiesPresent))
+ {
+ RenderDebugProperties();
+ }
+ // Go to next profiling measurement, time spend after this call is shown in the next frame.
+ m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds());
+
+ m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
+ m_rasterizer->EndFrame();
+ // swap backbuffer (drawing into this buffer) <-> front/visible buffer
+ m_rasterizer->SwapBuffers();
+ m_rendertools->EndFrame(m_rasterizer);
+
+ m_canvas->EndDraw();
+}
+
+
+
+void KX_KetsjiEngine::NextFrame()
+{
+ m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
+
+ double deltatime = 0.02;
+ double curtime;
+
+ if (m_bFixedTime)
+ {
+ curtime = m_previoustime + deltatime;
+ }
+ else
+ {
+ curtime = m_kxsystem->GetTimeInSeconds();
+ if (m_previoustime)
+ deltatime = curtime - m_previoustime;
+
+ if (deltatime > 0.1)
+ deltatime = 0.1;
+
+ deltatime = CalculateAverage(deltatime);
+ }
+
+ m_previoustime = curtime;
+
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
+ // for each scene, call the proceed functions
+ {
+ KX_Scene* scene = *sceneit;
+
+
+
+ /* Suspension holds the physics and logic processing for an
+ * entire scene. Objects can be suspended individually, and
+ * the settings for that preceed the logic and physics
+ * update. */
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateObjectActivity();
+
+ if (!scene->IsSuspended())
+ {
+ m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
+ scene->GetNetworkScene()->proceed(curtime, deltatime);
+
+ // set Python hooks for each scene
+ PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
+ PHY_SetActiveScene(scene);
+
+ // Process sensors, and controllers
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+ scene->LogicBeginFrame(curtime,deltatime);
+
+ // Scenegraph needs to be updated again, because Logic Controllers
+ // can affect the local matrices.
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(curtime);
+
+ // Process actuators
+
+ // Do some cleanup work for this logic frame
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+ scene->LogicUpdateFrame(curtime,deltatime);
+ scene->LogicEndFrame();
+
+ // Actuators can affect the scenegraph
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(curtime);
+
+ // Perform physics calculations on the scene. This can involve
+ // many iterations of the physics solver.
+ m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
+ scene->GetPhysicsEnvironment()->proceed(deltatime);
+
+ // Update scenegraph after physics step. This maps physics calculations
+ // into node positions.
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateParents(curtime);
+
+ } // suspended
+
+ DoSound(scene);
+
+ m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
+ }
+
+ // update system devices
+ m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+
+ if (m_keyboarddevice)
+ m_keyboarddevice->NextFrame();
+
+ if (m_mousedevice)
+ m_mousedevice->NextFrame();
+
+ if (m_networkdevice)
+ m_networkdevice->NextFrame();
+
+ if (m_audiodevice)
+ m_audiodevice->NextFrame();
+
+ // scene management
+ ProcessScheduledScenes();
+
+ // Start logging time spend outside main loop
+ m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
+}
+
+
+
+void KX_KetsjiEngine::Render()
+{
+ KX_Scene* firstscene = *m_scenes.begin();
+ const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
+
+ m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
+
+ // hiding mouse cursor each frame
+ // (came back when going out of focus and then back in again)
+ if (m_hideCursor)
+ m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
+
+ // clear the entire game screen with the border color
+ // only once per frame
+ m_canvas->BeginDraw();
+ if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED) {
+ m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
+ if (m_overrideFrameColor)
+ {
+ // Do not use the framing bar color set in the Blender scenes
+ m_canvas->ClearColor(
+ m_overrideFrameColorR,
+ m_overrideFrameColorG,
+ m_overrideFrameColorB,
+ 1.0
+ );
+ }
+ else
+ {
+ // Use the framing bar color set in the Blender scenes
+ m_canvas->ClearColor(
+ framesettings.BarRed(),
+ framesettings.BarGreen(),
+ framesettings.BarBlue(),
+ 1.0
+ );
+ }
+ // clear the -whole- viewport
+ m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER);
+ }
+
+ m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
+
+ // BeginFrame() sets the actual drawing area. You can use a part of the window
+ if (!BeginFrame())
+ return;
+
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
+ // for each scene, call the proceed functions
+ {
+ KX_Scene* scene = *sceneit;
+
+ // pass the scene's worldsettings to the rasterizer
+ SetWorldSettings(scene->GetWorldInfo());
+
+ if (scene->IsClearingZBuffer())
+ m_rasterizer->ClearDepthBuffer();
+
+ m_rendertools->SetAuxilaryClientInfo(scene);
+
+ //Initialize scene viewport.
+ SetupRenderFrame(scene);
+
+ // do the rendering
+ RenderFrame(scene);
+ }
+
+ // only one place that checks for stereo
+ if(m_rasterizer->Stereo())
+ {
+ m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
+
+ if (!BeginFrame())
+ return;
+
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
+ // for each scene, call the proceed functions
+ {
+ KX_Scene* scene = *sceneit;
+
+ // pass the scene's worldsettings to the rasterizer
+ SetWorldSettings(scene->GetWorldInfo());
+
+ if (scene->IsClearingZBuffer())
+ m_rasterizer->ClearDepthBuffer();
+
+ //pass the scene, for picking and raycasting (shadows)
+ m_rendertools->SetAuxilaryClientInfo(scene);
+
+ //Initialize scene viewport.
+ SetupRenderFrame(scene);
+
+ // do the rendering
+ RenderFrame(scene);
+ }
+ } // if(m_rasterizer->Stereo())
+
+ EndFrame();
+}
+
+
+
+void KX_KetsjiEngine::RequestExit(int exitrequestmode)
+{
+ m_exitcode = exitrequestmode;
+}
+
+
+
+void KX_KetsjiEngine::SetNameNextGame(const STR_String& nextgame)
+{
+ m_exitstring = nextgame;
+}
+
+
+
+int KX_KetsjiEngine::GetExitCode()
+{
+ // if a gameactuator has set an exitcode or if there are no scenes left
+ if (!m_exitcode)
+ {
+ if (m_scenes.begin()==m_scenes.end())
+ m_exitcode = KX_EXIT_REQUEST_NO_SCENES_LEFT;
+ }
+
+ return m_exitcode;
+}
+
+
+
+const STR_String& KX_KetsjiEngine::GetExitString()
+{
+ return m_exitstring;
+}
+
+
+
+void KX_KetsjiEngine::DoSound(KX_Scene* scene)
+{
+ m_logger->StartLog(tc_sound, m_kxsystem->GetTimeInSeconds(), true);
+
+ KX_Camera* cam = scene->GetActiveCamera();
+ MT_Point3 listenerposition = cam->NodeGetWorldPosition();
+ MT_Vector3 listenervelocity = cam->GetLinearVelocity();
+ MT_Matrix3x3 listenerorientation = cam->NodeGetWorldOrientation();
+
+ SND_Scene* soundscene = scene->GetSoundScene();
+ soundscene->SetListenerTransform(
+ listenerposition,
+ listenervelocity,
+ listenerorientation);
+
+ soundscene->Proceed();
+}
+
+
+
+void KX_KetsjiEngine::SetBackGround(KX_WorldInfo* wi)
+{
+ if (wi->hasWorld())
+ {
+ if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED)
+ {
+ m_rasterizer->SetBackColor(
+ wi->getBackColorRed(),
+ wi->getBackColorGreen(),
+ wi->getBackColorBlue(),
+ 0.0
+ );
+ }
+ }
+}
+
+
+
+void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi)
+{
+ if (wi->hasWorld())
+ {
+ if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED)
+ {
+ if (wi->hasMist())
+ {
+ m_rasterizer->SetFog(
+ wi->getMistStart(),
+ wi->getMistDistance(),
+ wi->getMistColorRed(),
+ wi->getMistColorGreen(),
+ wi->getMistColorBlue()
+ );
+ }
+ else
+ {
+ m_rasterizer->DisableFog();
+ }
+ }
+ }
+}
+
+
+
+void KX_KetsjiEngine::SetDrawType(int drawingmode)
+{
+ m_drawingmode = drawingmode;
+}
+
+
+
+void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene)
+{
+ m_overrideCam = true;
+ m_overrideSceneName = forscene;
+}
+
+
+
+void KX_KetsjiEngine::SetCameraZoom(float camzoom)
+{
+ m_cameraZoom = camzoom;
+}
+
+
+
+void KX_KetsjiEngine::SetCameraOverrideUseOrtho(bool useOrtho)
+{
+ m_overrideCamUseOrtho = useOrtho;
+}
+
+
+
+void KX_KetsjiEngine::SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat)
+{
+ m_overrideCamProjMat = mat;
+}
+
+
+void KX_KetsjiEngine::SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat)
+{
+ m_overrideCamViewMat = mat;
+}
+
+
+void KX_KetsjiEngine::SetupRenderFrame(KX_Scene *scene)
+{
+ // In this function we make sure the rasterizer settings are upto
+ // date. We compute the viewport so that logic
+ // using this information is upto date.
+
+ // Note we postpone computation of the projection matrix
+ // so that we are using the latest camera position.
+
+ RAS_Rect viewport;
+
+ if (
+ m_overrideCam ||
+ (scene->GetName() != m_overrideSceneName) ||
+ m_overrideCamUseOrtho
+ ) {
+ RAS_FramingManager::ComputeViewport(
+ scene->GetFramingType(),
+ m_canvas->GetDisplayArea(),
+ viewport
+ );
+ } else {
+ viewport.SetLeft(0);
+ viewport.SetBottom(0);
+ viewport.SetRight(int(m_canvas->GetWidth()));
+ viewport.SetTop(int(m_canvas->GetHeight()));
+ }
+ // store the computed viewport in the scene
+
+ scene->SetSceneViewport(viewport);
+
+ // set the viewport for this frame and scene
+ m_canvas->SetViewPort(
+ viewport.GetLeft(),
+ viewport.GetBottom(),
+ viewport.GetRight(),
+ viewport.GetTop()
+ );
+
+}
+
+
+// update graphics
+void KX_KetsjiEngine::RenderFrame(KX_Scene* scene)
+{
+ float left, right, bottom, top, nearfrust, farfrust;
+ KX_Camera* cam = scene->GetActiveCamera();
+
+ m_rasterizer->DisplayFog();
+
+ if (m_overrideCam && (scene->GetName() == m_overrideSceneName) && m_overrideCamUseOrtho) {
+ MT_CmMatrix4x4 projmat = m_overrideCamProjMat;
+ m_rasterizer->SetProjectionMatrix(projmat);
+ } else {
+ RAS_FrameFrustum frustum;
+
+ RAS_FramingManager::ComputeFrustum(
+ scene->GetFramingType(),
+ m_canvas->GetDisplayArea(),
+ scene->GetSceneViewport(),
+ cam->GetLens(),
+ cam->GetCameraNear(),
+ cam->GetCameraFar(),
+ frustum
+ );
+
+ left = frustum.x1 * m_cameraZoom;
+ right = frustum.x2 * m_cameraZoom;
+ bottom = frustum.y1 * m_cameraZoom;
+ top = frustum.y2 * m_cameraZoom;
+ nearfrust = frustum.camnear;
+ farfrust = frustum.camfar;
+
+ MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
+ left, right, bottom, top, nearfrust, farfrust);
+
+ m_rasterizer->SetProjectionMatrix(projmat);
+ cam->SetProjectionMatrix(projmat);
+ }
+
+ MT_Scalar cammat[16];
+ cam->GetWorldToCamera().getValue(cammat);
+ MT_Matrix4x4 viewmat;
+ viewmat.setValue(cammat); // this _should transpose ...
+ // if finally transposed take care of correct usage
+ // in RAS_OpenGLRasterizer ! (row major vs column major)
+
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
+ cam->GetCameraLocation(), cam->GetCameraOrientation());
+ cam->SetModelviewMatrix(viewmat);
+
+ scene->UpdateMeshTransformations();
+
+ // The following actually reschedules all vertices to be
+ // redrawn. There is a cache between the actual rescheduling
+ // and this call though. Visibility is imparted when this call
+ // runs through the individual objects.
+ scene->CalculateVisibleMeshes(m_rasterizer);
+
+ scene->RenderBuckets(cam->GetWorldToCamera(), m_rasterizer, m_rendertools);
+}
+
+
+
+void KX_KetsjiEngine::StopEngine()
+{
+ if (m_bInitialized)
+ {
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ delete scene;
+ }
+ m_scenes.clear();
+
+ // cleanup all the stuff
+ m_rasterizer->Exit();
+ }
+}
+
+// Scene Management is able to switch between scenes
+// and have several scene's running in parallel
+void KX_KetsjiEngine::AddScene(KX_Scene* scene)
+{
+ m_scenes.push_back(scene);
+ PostProcessScene(scene);
+ SceneListsChanged();
+}
+
+
+
+void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
+{
+ bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName));
+
+ // if there is no activecamera, or the camera is being
+ // overridden we need to construct a temporarily camera
+ if (!scene->GetActiveCamera() || override_camera)
+ {
+ KX_Camera* activecam = NULL;
+
+ RAS_CameraData camdata;
+ camdata.m_lens = 35.0f;
+ camdata.m_clipstart = 0.1f;
+ camdata.m_clipend = 100.0f;
+ activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata);
+ activecam->SetName("__default__cam__");
+
+ // set transformation
+ if (override_camera) {
+ const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat;
+ MT_Transform trans = MT_Transform(cammatdata.getPointer());
+ MT_Transform camtrans;
+ camtrans.invert(trans);
+
+ activecam->NodeSetLocalPosition(camtrans.getOrigin());
+ activecam->NodeSetLocalOrientation(camtrans.getBasis());
+ activecam->NodeUpdateGS(0,true);
+ } else {
+ activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
+ activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
+ activecam->NodeUpdateGS(0,true);
+ }
+
+ scene->AddCamera(activecam);
+ scene->SetActiveCamera(activecam);
+ scene->GetObjectList()->Add(activecam->AddRef());
+ scene->GetRootParentList()->Add(activecam->AddRef());
+ }
+
+ scene->UpdateParents(0.0);
+}
+
+
+
+void KX_KetsjiEngine::RenderDebugProperties()
+{
+ STR_String debugtxt;
+ int xcoord = 10; // mmmm, these constants were taken from blender source
+ int ycoord = 14; // to 'mimic' behaviour
+
+ float tottime = m_logger->GetAverage();
+ if (tottime < 1e-6f) {
+ tottime = 1e-6f;
+ }
+
+ /* Framerate display */
+ if (m_show_framerate) {
+ debugtxt.Format("swap : %.3f (%.3f frames per second)", tottime, 1.0/tottime);
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord,
+ ycoord,
+ m_canvas->GetWidth() /* RdV, TODO ?? */,
+ m_canvas->GetHeight() /* RdV, TODO ?? */);
+ ycoord += 14;
+ }
+
+ /* Profile and framerate display */
+ if (m_show_profile)
+ {
+ for (int j = tc_first; j < tc_numCategories; j++)
+ {
+ debugtxt.Format(m_profileLabels[j]);
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord,ycoord,
+ m_canvas->GetWidth(),
+ m_canvas->GetHeight());
+ double time = m_logger->GetAverage((KX_TimeCategory)j);
+ debugtxt.Format("%2.2f %%", time/tottime * 100.f);
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord + 60 ,ycoord,
+ m_canvas->GetWidth(),
+ m_canvas->GetHeight());
+ ycoord += 14;
+ }
+ }
+
+ /* Property display*/
+ if (m_show_debug_properties && m_propertiesPresent)
+ {
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ /* the 'normal' debug props */
+ vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
+
+ for (vector<SCA_DebugProp*>::iterator it = debugproplist.begin();
+ !(it==debugproplist.end());it++)
+ {
+ CValue* propobj = (*it)->m_obj;
+ STR_String objname = propobj->GetName();
+ STR_String propname = (*it)->m_name;
+ CValue* propval = propobj->GetProperty(propname);
+ if (propval)
+ {
+ STR_String text = propval->GetText();
+ debugtxt = objname + "." + propname + " = " + text;
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord,
+ ycoord,
+ m_canvas->GetWidth(),
+ m_canvas->GetHeight());
+ ycoord += 14;
+ }
+ }
+ }
+ }
+}
+
+
+KX_SceneList* KX_KetsjiEngine::CurrentScenes()
+{
+ return &m_scenes;
+}
+
+
+
+KX_Scene* KX_KetsjiEngine::FindScene(const STR_String& scenename)
+{
+ KX_SceneList::iterator sceneit = m_scenes.begin();
+
+ // bit risky :) better to split the second clause
+ while ( (sceneit != m_scenes.end())
+ && ((*sceneit)->GetName() != scenename))
+ {
+ sceneit++;
+ }
+
+ return ((sceneit == m_scenes.end()) ? NULL : *sceneit);
+}
+
+
+
+void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overlay)
+{
+ // only add scene when it doesn't exist!
+ if (FindScene(scenename))
+ {
+ STR_String tmpname = scenename;
+ printf("warning: scene %s already exists, not added!\n",tmpname.Ptr());
+ }
+ else
+ {
+ if (overlay)
+ {
+ m_addingOverlayScenes.insert(scenename);
+ }
+ else
+ {
+ m_addingBackgroundScenes.insert(scenename);
+ }
+ }
+}
+
+
+
+
+void KX_KetsjiEngine::RemoveScene(const STR_String& scenename)
+{
+ if (FindScene(scenename))
+ {
+ m_removingScenes.insert(scenename);
+ }
+ else
+ {
+ STR_String tmpname = scenename;
+ printf("warning: scene %s does not exist, not removed!\n",tmpname.Ptr());
+ }
+}
+
+
+
+void KX_KetsjiEngine::RemoveScheduledScenes()
+{
+ if (m_removingScenes.size())
+ {
+ set<STR_String>::iterator scenenameit;
+ for (scenenameit=m_removingScenes.begin();scenenameit != m_removingScenes.end();scenenameit++)
+ {
+ STR_String scenename = *scenenameit;
+
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ if (scene->GetName()==scenename)
+ {
+ delete scene;
+ m_scenes.erase(sceneit);
+ break;
+ }
+ }
+ }
+ m_removingScenes.clear();
+ }
+}
+
+
+
+KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename)
+{
+
+ KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice,
+ m_mousedevice,
+ m_networkdevice,
+ m_audiodevice,
+ scenename);
+
+ m_sceneconverter->ConvertScene(scenename,
+ tmpscene,
+ m_pythondictionary,
+ m_keyboarddevice,
+ m_rendertools,
+ m_canvas);
+
+ return tmpscene;
+}
+
+
+
+void KX_KetsjiEngine::AddScheduledScenes()
+{
+ set<STR_String>::iterator scenenameit;
+
+ if (m_addingOverlayScenes.size())
+ {
+ for (scenenameit = m_addingOverlayScenes.begin();
+ scenenameit != m_addingOverlayScenes.end();
+ scenenameit++)
+ {
+ STR_String scenename = *scenenameit;
+ KX_Scene* tmpscene = CreateScene(scenename);
+ m_scenes.push_back(tmpscene);
+ PostProcessScene(tmpscene);
+ }
+ m_addingOverlayScenes.clear();
+ }
+
+ if (m_addingBackgroundScenes.size())
+ {
+ for (scenenameit = m_addingBackgroundScenes.begin();
+ scenenameit != m_addingBackgroundScenes.end();
+ scenenameit++)
+ {
+ STR_String scenename = *scenenameit;
+ KX_Scene* tmpscene = CreateScene(scenename);
+ m_scenes.insert(m_scenes.begin(),tmpscene);
+ PostProcessScene(tmpscene);
+
+ }
+ m_addingBackgroundScenes.clear();
+ }
+}
+
+
+
+void KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
+{
+ m_replace_scenes.insert(std::make_pair(oldscene,newscene));
+}
+
+// replace scene is not the same as removing and adding because the
+// scene must be in exact the same place (to maintain drawingorder)
+// (nzc) - should that not be done with a scene-display list? It seems
+// stupid to rely on the mem allocation order...
+void KX_KetsjiEngine::ReplaceScheduledScenes()
+{
+ if (m_replace_scenes.size())
+ {
+ set<pair<STR_String,STR_String> >::iterator scenenameit;
+
+ for (scenenameit = m_replace_scenes.begin();
+ scenenameit != m_replace_scenes.end();
+ scenenameit++)
+ {
+ STR_String oldscenename = (*scenenameit).first;
+ STR_String newscenename = (*scenenameit).second;
+ int i=0;
+ /* Scenes are not supposed to be included twice... I think */
+ KX_SceneList::iterator sceneit;
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ if (scene->GetName() == oldscenename)
+ {
+ delete scene;
+ KX_Scene* tmpscene = CreateScene(newscenename);
+ m_scenes[i]=tmpscene;
+ PostProcessScene(tmpscene);
+ }
+ i++;
+ }
+ }
+ m_replace_scenes.clear();
+ }
+}
+
+
+
+void KX_KetsjiEngine::SuspendScene(const STR_String& scenename)
+{
+ KX_Scene* scene = FindScene(scenename);
+ if (scene) scene->Suspend();
+}
+
+
+
+void KX_KetsjiEngine::ResumeScene(const STR_String& scenename)
+{
+ KX_Scene* scene = FindScene(scenename);
+ if (scene) scene->Resume();
+}
+
+
+
+void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
+{
+ m_bFixedTime = bUseFixedTime;
+}
+
+
+
+bool KX_KetsjiEngine::GetUseFixedTime(void) const
+{
+ return m_bFixedTime;
+}
+
+
+
+void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
+{
+ m_show_framerate = frameRate;
+ m_show_profile = profile;
+ m_show_debug_properties = properties;
+}
+
+
+
+void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const
+{
+ frameRate = m_show_framerate;
+ profile = m_show_profile;
+ properties = m_show_debug_properties;
+}
+
+
+
+void KX_KetsjiEngine::ProcessScheduledScenes(void)
+{
+ // Check whether there will be changes to the list of scenes
+ if (m_addingOverlayScenes.size() ||
+ m_addingBackgroundScenes.size() ||
+ m_replace_scenes.size() ||
+ m_removingScenes.size()) {
+
+ // Change the scene list
+ ReplaceScheduledScenes();
+ RemoveScheduledScenes();
+ AddScheduledScenes();
+
+ // Notify
+ SceneListsChanged();
+ }
+}
+
+
+
+void KX_KetsjiEngine::SceneListsChanged(void)
+{
+ m_propertiesPresent = false;
+ KX_SceneList::iterator sceneit = m_scenes.begin();
+ while ((sceneit != m_scenes.end()) && (!m_propertiesPresent))
+ {
+ KX_Scene* scene = *sceneit;
+ vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties();
+ m_propertiesPresent = !debugproplist.empty();
+ sceneit++;
+ }
+}
+
+
+void KX_KetsjiEngine::SetHideCursor(bool hideCursor)
+{
+ m_hideCursor = hideCursor;
+}
+
+
+bool KX_KetsjiEngine::GetHideCursor(void) const
+{
+ return m_hideCursor;
+}
+
+
+void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor)
+{
+ m_overrideFrameColor = overrideFrameColor;
+}
+
+
+bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
+{
+ return m_overrideFrameColor;
+}
+
+
+void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
+{
+ m_overrideFrameColorR = r;
+ m_overrideFrameColorG = g;
+ m_overrideFrameColorB = b;
+}
+
+
+void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
+{
+ r = m_overrideFrameColorR;
+ g = m_overrideFrameColorG;
+ b = m_overrideFrameColorB;
+}
+