Logo Search packages:      
Sourcecode: blender version File versions

KX_KetsjiEngine.cpp

/*
 * $Id: KX_KetsjiEngine.cpp,v 1.14 2004/12/01 08:43:58 kester Exp $
 *
 * ***** 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 HAVE_CONFIG_H
#include <config.h>
#endif

#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 "SumoPhysicsEnvironment.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
#define DEFAULT_LOGIC_TIC_RATE 30.0
#define DEFAULT_PHYSICS_TIC_RATE 60.0

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
};

double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;


/**
 *    Constructor of the Ketsji Engine
 */
00106 KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
     :      m_canvas(NULL),
      m_rasterizer(NULL),
      m_kxsystem(system),
      m_rendertools(NULL),
      m_sceneconverter(NULL),
      m_networkdevice(NULL),
      m_audiodevice(NULL),
      m_pythondictionary(NULL),
      m_keyboarddevice(NULL),
      m_mousedevice(NULL),

      m_propertiesPresent(false),

      m_bInitialized(false),
      m_activecam(0),
      m_bFixedTime(false),
      
      m_firstframe(true),
      
      m_previoustime(0.0),
      m_deltatime(0.0),

      m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
      m_exitstring(""),
      
      m_drawingmode(5),
      m_cameraZoom(1.0),
      
      m_overrideCam(false),
      m_overrideCamUseOrtho(false),

      m_stereo(false),
      m_curreye(0),

      m_logger(NULL),
      
      // Set up timing info display variables
      m_show_framerate(false),
      m_show_profile(false),
      m_showProperties(false),
      m_showBackground(false),
      m_show_debug_properties(false),

      // Default behavior is to hide the cursor every frame.
      m_hideCursor(false),

      m_overrideFrameColor(false),
      m_overrideFrameColorR(0.0),
      m_overrideFrameColorG(0.0),
      m_overrideFrameColorB(0.0)
{
      // 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);
            
}



/**
 *    Destructor of the Ketsji Engine, release all memory
 */
00171 KX_KetsjiEngine::~KX_KetsjiEngine()
{
      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
 */
00255 void KX_KetsjiEngine::StartEngine()
{
      m_previoustime = m_kxsystem->GetTimeInSeconds();
      m_firstframe = true;
      m_bInitialized = true;
      m_ticrate = DEFAULT_LOGIC_TIC_RATE;
      SumoPhysicsEnvironment::setTicRate(DEFAULT_PHYSICS_TIC_RATE);
}

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 curtime;
      if (m_bFixedTime)
            curtime = m_previoustime + 1.0/m_ticrate;
      else
            curtime = m_kxsystem->GetTimeInSeconds();
      m_deltatime += curtime - m_previoustime;
      m_previoustime = curtime;
      double localtime = curtime - m_deltatime;

      // Compute the number of logic frames to do each update (fixed tic bricks)
      int frames = (int) (m_deltatime*m_ticrate);
      m_deltatime -= double(frames)/m_ticrate;
      
      KX_SceneList::iterator sceneit;
      
      while (frames)
      {
            localtime += 1.0/m_ticrate;
            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_physics, m_kxsystem->GetTimeInSeconds(), true);
                        m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
                        scene->GetNetworkScene()->proceed(localtime);
      
                        // set Python hooks for each scene
                        PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
                        PHY_SetActiveScene(scene);
      
                        scene->GetPhysicsEnvironment()->endFrame();
                        
                        // Update scenegraph after physics step. This maps physics calculations
                        // into node positions.       
                        m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
                        scene->UpdateParents(localtime);
                        
                        // Process sensors, and controllers
                        m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
                        scene->LogicBeginFrame(localtime);
      
                        // 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(localtime);
      
                        // Process actuators
      
                        // Do some cleanup work for this logic frame
                        m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
                        scene->LogicUpdateFrame(localtime, true);
                        scene->LogicEndFrame();
      
                        // Actuators can affect the scenegraph
                        m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
                        scene->UpdateParents(localtime);
                        
                        scene->GetPhysicsEnvironment()->beginFrame();
            
                        // 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(localtime);
                  } // 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();
            
            frames--;
      }

      // Logic update sub frame: this will let some logic bricks run at the
      // full frame rate.
      for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
      // for each scene, call the proceed functions
      {
            KX_Scene* scene = *sceneit;

            if (!scene->IsSuspended())
            {
                  // set Python hooks for each scene
                  PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
                  PHY_SetActiveScene(scene);
                  
                  // 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(curtime);
                  // Update scenegraph after physics step. This maps physics calculations
                  // into node positions.       
                  m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
                  scene->UpdateParents(curtime);
                  
                  // Do some cleanup work for this logic frame
                  m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
                  scene->LogicUpdateFrame(curtime, false);

                  // Actuators can affect the scenegraph
                  m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
                  scene->UpdateParents(curtime);
            } // suspended

            DoSound(scene);

            m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
      }
      
      // 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();
      if (!cam)
            return;
      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;
      const float ortho = 100.0;
      KX_Camera* cam = scene->GetActiveCamera();
      
      if (!cam)
            return;

      m_rasterizer->DisplayFog();

      if (m_overrideCam && (scene->GetName() == m_overrideSceneName) && m_overrideCamUseOrtho) {
            MT_CmMatrix4x4 projmat = m_overrideCamProjMat;
            m_rasterizer->SetProjectionMatrix(projmat);
      } else if (cam->hasValidProjectionMatrix())
      {
            m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
      } else
      {
            RAS_FrameFrustum frustum;
            float lens = cam->GetLens();
            nearfrust = cam->GetCameraNear();
            farfrust = cam->GetCameraFar();

            if (!cam->GetCameraData()->m_perspective)
            {
                  lens *= ortho;
                  nearfrust = (nearfrust + 1.0)*ortho;
                  farfrust *= ortho;
            }
            
            RAS_FramingManager::ComputeFrustum(
                  scene->GetFramingType(),
                  m_canvas->GetDisplayArea(),
                  scene->GetSceneViewport(),
                  lens,
                  nearfrust,
                  farfrust,
                  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);
      
            cam->SetProjectionMatrix(projmat);
            
            // Otherwise the projection matrix for each eye will be the same...
            if (m_rasterizer->Stereo())
                  cam->InvalidateProjectionMatrix();
      }

      MT_Transform camtrans(cam->GetWorldToCamera());
      if (!cam->GetCameraData()->m_perspective)
            camtrans.getOrigin()[2] *= ortho;
      MT_Matrix4x4 viewmat(camtrans);
      
      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(camtrans, 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 = RAS_CameraData();
            activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata, false);
            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;
            std::cout << "warning: scene " << scenename << " does not exist, not removed!" << std::endl;
      }
}



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();
}



01182 void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
{
      m_bFixedTime = bUseFixedTime;
}



01189 bool KX_KetsjiEngine::GetUseFixedTime(void) const
{
      return m_bFixedTime;
}

01194 double KX_KetsjiEngine::GetTicRate()
{
      return m_ticrate;
}

01199 void KX_KetsjiEngine::SetTicRate(double ticrate)
{
      m_ticrate = ticrate;
}

01204 void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
{
      m_show_framerate = frameRate;
      m_show_profile = profile;
      m_show_debug_properties = properties;
}



01213 void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const
{
      frameRate = m_show_framerate;
      profile = m_show_profile;
      properties = m_show_debug_properties;
}



01222 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();
      }
}



01242 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++;
      }
}


01256 void KX_KetsjiEngine::SetHideCursor(bool hideCursor)
{
      m_hideCursor = hideCursor;
}


01262 bool KX_KetsjiEngine::GetHideCursor(void) const
{
      return m_hideCursor;
}


01268 void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor)
{
      m_overrideFrameColor = overrideFrameColor;
}


01274 bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const
{
      return m_overrideFrameColor;
}


01280 void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b)
{
      m_overrideFrameColorR = r;
      m_overrideFrameColorG = g;
      m_overrideFrameColorB = b;
}


01288 void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
{
      r = m_overrideFrameColorR;
      g = m_overrideFrameColorG;
      b = m_overrideFrameColorB;
}


Generated by  Doxygen 1.6.0   Back to index