forked from bartvdbraak/blender
b23186b2a4
* near and far var names confused mingw64, renamed * mingw defines a macro named DrawText, confusing the DrawText function usage from KX_FontObject.
1969 lines
49 KiB
C++
1969 lines
49 KiB
C++
/*
|
|
* ***** BEGIN GPL 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.
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK *****
|
|
* The engine ties all game modules together.
|
|
*/
|
|
|
|
/** \file gameengine/Ketsji/KX_KetsjiEngine.cpp
|
|
* \ingroup ketsji
|
|
*/
|
|
|
|
|
|
#if defined(WIN32) && !defined(FREE_WINDOWS)
|
|
#pragma warning (disable : 4786)
|
|
#endif //WIN32
|
|
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
|
|
#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 "MT_Vector3.h"
|
|
#include "MT_Transform.h"
|
|
#include "SCA_IInputDevice.h"
|
|
#include "KX_Camera.h"
|
|
#include "KX_FontObject.h"
|
|
#include "KX_Dome.h"
|
|
#include "KX_Light.h"
|
|
#include "KX_PythonInit.h"
|
|
#include "KX_PyConstraintBinding.h"
|
|
#include "PHY_IPhysicsEnvironment.h"
|
|
|
|
#ifdef WITH_AUDASPACE
|
|
# include "AUD_C-API.h"
|
|
# include "AUD_I3DDevice.h"
|
|
#endif
|
|
|
|
#include "NG_NetworkScene.h"
|
|
#include "NG_NetworkDeviceInterface.h"
|
|
|
|
#include "KX_WorldInfo.h"
|
|
#include "KX_ISceneConverter.h"
|
|
#include "KX_TimeCategoryLogger.h"
|
|
|
|
#include "RAS_FramingManager.h"
|
|
#include "DNA_world_types.h"
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "KX_NavMeshObject.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 60.0
|
|
#define DEFAULT_PHYSICS_TIC_RATE 60.0
|
|
|
|
#ifdef FREE_WINDOWS /* XXX mingw64 (gcc 4.7.0) defines a macro for DrawText that translates to DrawTextA. Not good */
|
|
#ifdef DrawText
|
|
#undef DrawText
|
|
#endif
|
|
#endif
|
|
|
|
const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
|
|
"Physics:", // tc_physics
|
|
"Logic:", // tc_logic
|
|
"Animations:", // tc_animations
|
|
"Network:", // tc_network
|
|
"Scenegraph:", // tc_scenegraph
|
|
"Rasterizer:", // tc_rasterizer
|
|
"Services:", // tc_services
|
|
"Overhead:", // tc_overhead
|
|
"Outside:" // tc_outside
|
|
};
|
|
|
|
double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;
|
|
int KX_KetsjiEngine::m_maxLogicFrame = 5;
|
|
int KX_KetsjiEngine::m_maxPhysicsFrame = 5;
|
|
double KX_KetsjiEngine::m_anim_framerate = 25.0;
|
|
double KX_KetsjiEngine::m_suspendedtime = 0.0;
|
|
double KX_KetsjiEngine::m_suspendeddelta = 0.0;
|
|
double KX_KetsjiEngine::m_average_framerate = 0.0;
|
|
bool KX_KetsjiEngine::m_restrict_anim_fps = false;
|
|
short KX_KetsjiEngine::m_exitkey = 130; //ESC Key
|
|
|
|
|
|
/**
|
|
* Constructor of the Ketsji Engine
|
|
*/
|
|
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),
|
|
#ifdef WITH_PYTHON
|
|
m_pythondictionary(NULL),
|
|
#endif
|
|
m_keyboarddevice(NULL),
|
|
m_mousedevice(NULL),
|
|
|
|
m_propertiesPresent(false),
|
|
|
|
m_bInitialized(false),
|
|
m_activecam(0),
|
|
m_bFixedTime(false),
|
|
|
|
m_firstframe(true),
|
|
|
|
m_frameTime(0.f),
|
|
m_clockTime(0.f),
|
|
m_previousClockTime(0.f),
|
|
m_previousAnimTime(0.f),
|
|
|
|
|
|
m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
|
|
m_exitstring(""),
|
|
|
|
m_drawingmode(5),
|
|
m_cameraZoom(1.0),
|
|
|
|
m_overrideCam(false),
|
|
m_overrideCamUseOrtho(false),
|
|
m_overrideCamNear(0.0),
|
|
m_overrideCamFar(0.0),
|
|
|
|
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),
|
|
|
|
m_animation_record(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),
|
|
|
|
m_usedome(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Destructor of the Ketsji Engine, release all memory
|
|
*/
|
|
KX_KetsjiEngine::~KX_KetsjiEngine()
|
|
{
|
|
delete m_logger;
|
|
if (m_usedome)
|
|
delete m_dome;
|
|
}
|
|
|
|
|
|
|
|
void KX_KetsjiEngine::SetKeyboardDevice(SCA_IInputDevice* keyboarddevice)
|
|
{
|
|
MT_assert(keyboarddevice);
|
|
m_keyboarddevice = keyboarddevice;
|
|
}
|
|
|
|
|
|
|
|
void KX_KetsjiEngine::SetMouseDevice(SCA_IInputDevice* mousedevice)
|
|
{
|
|
MT_assert(mousedevice);
|
|
m_mousedevice = mousedevice;
|
|
}
|
|
|
|
|
|
|
|
void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice)
|
|
{
|
|
MT_assert(networkdevice);
|
|
m_networkdevice = networkdevice;
|
|
}
|
|
|
|
|
|
void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas)
|
|
{
|
|
MT_assert(canvas);
|
|
m_canvas = canvas;
|
|
}
|
|
|
|
|
|
|
|
void KX_KetsjiEngine::SetRenderTools(RAS_IRenderTools* rendertools)
|
|
{
|
|
MT_assert(rendertools);
|
|
m_rendertools = rendertools;
|
|
}
|
|
|
|
|
|
|
|
void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer)
|
|
{
|
|
MT_assert(rasterizer);
|
|
m_rasterizer = rasterizer;
|
|
}
|
|
|
|
#ifdef WITH_PYTHON
|
|
/*
|
|
* At the moment the bge.logic module is imported into 'pythondictionary' after this function is called.
|
|
* if this function ever changes to assign a copy, make sure the game logic module is imported into this dictionary before hand.
|
|
*/
|
|
void KX_KetsjiEngine::SetPyNamespace(PyObject* pythondictionary)
|
|
{
|
|
MT_assert(pythondictionary);
|
|
m_pythondictionary = pythondictionary;
|
|
}
|
|
#endif
|
|
|
|
|
|
void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter)
|
|
{
|
|
MT_assert(sceneconverter);
|
|
m_sceneconverter = sceneconverter;
|
|
}
|
|
|
|
void KX_KetsjiEngine::InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text)
|
|
{
|
|
m_dome = new KX_Dome(m_canvas, m_rasterizer, m_rendertools,this, res, mode, angle, resbuf, tilt, text);
|
|
m_usedome = true;
|
|
}
|
|
|
|
void KX_KetsjiEngine::RenderDome()
|
|
{
|
|
GLuint viewport[4]={0};
|
|
glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
|
|
|
|
m_dome->SetViewPort(viewport);
|
|
|
|
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();
|
|
|
|
// BeginFrame() sets the actual drawing area. You can use a part of the window
|
|
if (!BeginFrame())
|
|
return;
|
|
|
|
KX_SceneList::iterator sceneit;
|
|
KX_Scene* scene;
|
|
|
|
int n_renders=m_dome->GetNumberRenders();// usually 4 or 6
|
|
for (int i=0;i<n_renders;i++) {
|
|
m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
|
|
for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
|
|
// for each scene, call the proceed functions
|
|
{
|
|
scene = *sceneit;
|
|
KX_Camera* cam = scene->GetActiveCamera();
|
|
|
|
m_rendertools->BeginFrame(m_rasterizer);
|
|
// pass the scene's worldsettings to the rasterizer
|
|
SetWorldSettings(scene->GetWorldInfo());
|
|
|
|
// shadow buffers
|
|
if (i == 0) {
|
|
RenderShadowBuffers(scene);
|
|
}
|
|
// Avoid drawing the scene with the active camera twice when it's viewport is enabled
|
|
if (cam && !cam->GetViewport())
|
|
{
|
|
if (scene->IsClearingZBuffer())
|
|
m_rasterizer->ClearDepthBuffer();
|
|
|
|
m_rendertools->SetAuxilaryClientInfo(scene);
|
|
|
|
// do the rendering
|
|
m_dome->RenderDomeFrame(scene,cam, i);
|
|
//render all the font objects for this scene
|
|
RenderFonts(scene);
|
|
}
|
|
|
|
list<class KX_Camera*>* cameras = scene->GetCameras();
|
|
|
|
// Draw the scene once for each camera with an enabled viewport
|
|
list<KX_Camera*>::iterator it = cameras->begin();
|
|
while(it != cameras->end())
|
|
{
|
|
if ((*it)->GetViewport())
|
|
{
|
|
if (scene->IsClearingZBuffer())
|
|
m_rasterizer->ClearDepthBuffer();
|
|
|
|
m_rendertools->SetAuxilaryClientInfo(scene);
|
|
|
|
// do the rendering
|
|
m_dome->RenderDomeFrame(scene, (*it),i);
|
|
//render all the font objects for this scene
|
|
RenderFonts(scene);
|
|
}
|
|
|
|
it++;
|
|
}
|
|
// Part of PostRenderScene()
|
|
m_rendertools->MotionBlur(m_rasterizer);
|
|
scene->Render2DFilters(m_canvas);
|
|
// no RunDrawingCallBacks
|
|
// no FlushDebugLines
|
|
}
|
|
m_dome->BindImages(i);
|
|
}
|
|
|
|
m_canvas->EndFrame();//XXX do we really need that?
|
|
|
|
m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
|
|
|
|
if (m_overrideFrameColor) //XXX why do we want
|
|
{
|
|
// 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
|
|
);
|
|
}
|
|
m_dome->Draw();
|
|
// Draw Callback for the last scene
|
|
#ifdef WITH_PYTHON
|
|
scene->RunDrawingCallbacks(scene->GetPostDrawCB());
|
|
#endif
|
|
EndFrame();
|
|
}
|
|
|
|
/**
|
|
* Ketsji Init(), Initializes data-structures and converts data from
|
|
* Blender into Ketsji native (realtime) format also sets up the
|
|
* graphics context
|
|
*/
|
|
void KX_KetsjiEngine::StartEngine(bool clearIpo)
|
|
{
|
|
m_clockTime = m_kxsystem->GetTimeInSeconds();
|
|
m_frameTime = m_kxsystem->GetTimeInSeconds();
|
|
m_previousClockTime = m_kxsystem->GetTimeInSeconds();
|
|
|
|
m_firstframe = true;
|
|
m_bInitialized = true;
|
|
// there is always one scene enabled at startup
|
|
Scene* scene = m_scenes[0]->GetBlenderScene();
|
|
if (scene)
|
|
{
|
|
m_ticrate = scene->gm.ticrate ? scene->gm.ticrate : DEFAULT_LOGIC_TIC_RATE;
|
|
m_maxLogicFrame = scene->gm.maxlogicstep ? scene->gm.maxlogicstep : 5;
|
|
m_maxPhysicsFrame = scene->gm.maxphystep ? scene->gm.maxlogicstep : 5;
|
|
}
|
|
else
|
|
{
|
|
m_ticrate = DEFAULT_LOGIC_TIC_RATE;
|
|
m_maxLogicFrame = 5;
|
|
m_maxPhysicsFrame = 5;
|
|
}
|
|
|
|
if (m_animation_record)
|
|
{
|
|
m_sceneconverter->ResetPhysicsObjectsAnimationIpo(clearIpo);
|
|
m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame);
|
|
}
|
|
|
|
}
|
|
|
|
void KX_KetsjiEngine::ClearFrame()
|
|
{
|
|
// clear unless we're drawing overlapping stereo
|
|
if (m_rasterizer->InterlacedStereo() &&
|
|
m_rasterizer->GetEye() == RAS_IRasterizer::RAS_STEREO_RIGHTEYE)
|
|
return;
|
|
|
|
// clear the viewports with the background color of the first scene
|
|
bool doclear = false;
|
|
KX_SceneList::iterator sceneit;
|
|
RAS_Rect clearvp, area, viewport;
|
|
|
|
for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++)
|
|
{
|
|
KX_Scene* scene = *sceneit;
|
|
//const RAS_FrameSettings &framesettings = scene->GetFramingType();
|
|
list<class KX_Camera*>* cameras = scene->GetCameras();
|
|
|
|
list<KX_Camera*>::iterator it;
|
|
for (it = cameras->begin(); it != cameras->end(); it++)
|
|
{
|
|
GetSceneViewport(scene, (*it), area, viewport);
|
|
|
|
if (!doclear) {
|
|
clearvp = viewport;
|
|
doclear = true;
|
|
}
|
|
else {
|
|
if (viewport.GetLeft() < clearvp.GetLeft())
|
|
clearvp.SetLeft(viewport.GetLeft());
|
|
if (viewport.GetBottom() < clearvp.GetBottom())
|
|
clearvp.SetBottom(viewport.GetBottom());
|
|
if (viewport.GetRight() > clearvp.GetRight())
|
|
clearvp.SetRight(viewport.GetRight());
|
|
if (viewport.GetTop() > clearvp.GetTop())
|
|
clearvp.SetTop(viewport.GetTop());
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (doclear) {
|
|
KX_Scene* firstscene = *m_scenes.begin();
|
|
SetBackGround(firstscene->GetWorldInfo());
|
|
|
|
m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(),
|
|
clearvp.GetRight(), clearvp.GetTop());
|
|
m_rasterizer->ClearColorBuffer();
|
|
}
|
|
}
|
|
|
|
bool KX_KetsjiEngine::BeginFrame()
|
|
{
|
|
// set the area used for rendering (stereo can assign only a subset)
|
|
m_rasterizer->SetRenderArea();
|
|
|
|
if (m_canvas->BeginDraw())
|
|
{
|
|
ClearFrame();
|
|
|
|
m_rasterizer->BeginFrame(m_drawingmode , m_kxsystem->GetTimeInSeconds());
|
|
m_rendertools->BeginFrame(m_rasterizer);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
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();
|
|
}
|
|
|
|
m_average_framerate = m_logger->GetAverage();
|
|
if (m_average_framerate < 1e-6)
|
|
m_average_framerate = 1e-6;
|
|
m_average_framerate = 1.0/m_average_framerate;
|
|
|
|
// 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();
|
|
}
|
|
|
|
//#include "PIL_time.h"
|
|
//#include "LinearMath/btQuickprof.h"
|
|
|
|
|
|
bool KX_KetsjiEngine::NextFrame()
|
|
{
|
|
double timestep = 1.0/m_ticrate;
|
|
double framestep = timestep;
|
|
// static hidden::Clock sClock;
|
|
|
|
m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true);
|
|
|
|
//float dt = sClock.getTimeMicroseconds() * 0.000001f;
|
|
//sClock.reset();
|
|
|
|
if (m_bFixedTime)
|
|
m_clockTime += timestep;
|
|
else
|
|
{
|
|
|
|
// m_clockTime += dt;
|
|
m_clockTime = m_kxsystem->GetTimeInSeconds();
|
|
}
|
|
|
|
double deltatime = m_clockTime - m_frameTime;
|
|
if (deltatime<0.f)
|
|
{
|
|
printf("problem with clock\n");
|
|
deltatime = 0.f;
|
|
m_clockTime = 0.f;
|
|
m_frameTime = 0.f;
|
|
}
|
|
|
|
|
|
// Compute the number of logic frames to do each update (fixed tic bricks)
|
|
int frames =int(deltatime*m_ticrate+1e-6);
|
|
// if (frames>1)
|
|
// printf("****************************************");
|
|
// printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
|
|
|
|
// if (!frames)
|
|
// PIL_sleep_ms(1);
|
|
|
|
KX_SceneList::iterator sceneit;
|
|
|
|
if (frames>m_maxPhysicsFrame)
|
|
{
|
|
|
|
// printf("framedOut: %d\n",frames);
|
|
m_frameTime+=(frames-m_maxPhysicsFrame)*timestep;
|
|
frames = m_maxPhysicsFrame;
|
|
}
|
|
|
|
|
|
bool doRender = frames>0;
|
|
|
|
if (frames > m_maxLogicFrame)
|
|
{
|
|
framestep = (frames*timestep)/m_maxLogicFrame;
|
|
frames = m_maxLogicFrame;
|
|
}
|
|
|
|
while (frames)
|
|
{
|
|
|
|
|
|
m_frameTime += framestep;
|
|
|
|
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);
|
|
|
|
m_sceneconverter->resetNoneDynamicObjectToIpo();//this is for none dynamic objects with ipo
|
|
|
|
scene->UpdateObjectActivity();
|
|
|
|
if (!scene->IsSuspended())
|
|
{
|
|
// if the scene was suspended recalcutlate the delta tu "curtime"
|
|
m_suspendedtime = scene->getSuspendedTime();
|
|
if (scene->getSuspendedTime()!=0.0)
|
|
scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
|
|
m_suspendeddelta = scene->getSuspendedDelta();
|
|
|
|
|
|
m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_NETWORK);
|
|
scene->GetNetworkScene()->proceed(m_frameTime);
|
|
|
|
//m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
|
|
//SG_SetActiveStage(SG_STAGE_NETWORK_UPDATE);
|
|
//scene->UpdateParents(m_frameTime);
|
|
|
|
m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_PHYSICS1);
|
|
// set Python hooks for each scene
|
|
#ifdef WITH_PYTHON
|
|
PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
|
|
#endif
|
|
KX_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);
|
|
//SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE);
|
|
//scene->UpdateParents(m_frameTime);
|
|
|
|
// Process sensors, and controllers
|
|
m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_CONTROLLER);
|
|
scene->LogicBeginFrame(m_frameTime);
|
|
|
|
// Scenegraph needs to be updated again, because Logic Controllers
|
|
// can affect the local matrices.
|
|
m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE);
|
|
scene->UpdateParents(m_frameTime);
|
|
|
|
// Process actuators
|
|
|
|
// Do some cleanup work for this logic frame
|
|
m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_ACTUATOR);
|
|
scene->LogicUpdateFrame(m_frameTime, true);
|
|
|
|
scene->LogicEndFrame();
|
|
|
|
// Actuators can affect the scenegraph
|
|
m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE);
|
|
scene->UpdateParents(m_frameTime);
|
|
|
|
if (!GetRestrictAnimationFPS())
|
|
{
|
|
m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);
|
|
scene->UpdateAnimations(m_frameTime);
|
|
}
|
|
|
|
m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_PHYSICS2);
|
|
scene->GetPhysicsEnvironment()->beginFrame();
|
|
|
|
// Perform physics calculations on the scene. This can involve
|
|
// many iterations of the physics solver.
|
|
scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,timestep,framestep);//m_deltatimerealDeltaTime);
|
|
|
|
m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE);
|
|
scene->UpdateParents(m_frameTime);
|
|
|
|
|
|
if (m_animation_record)
|
|
{
|
|
m_sceneconverter->WritePhysicsObjectToAnimationIpo(++m_currentFrame);
|
|
}
|
|
|
|
scene->setSuspendedTime(0.0);
|
|
} // suspended
|
|
else
|
|
if (scene->getSuspendedTime()==0.0)
|
|
scene->setSuspendedTime(m_clockTime);
|
|
|
|
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();
|
|
|
|
// scene management
|
|
ProcessScheduledScenes();
|
|
|
|
frames--;
|
|
}
|
|
|
|
bool bUseAsyncLogicBricks= false;//true;
|
|
|
|
if (bUseAsyncLogicBricks)
|
|
{
|
|
// 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())
|
|
{
|
|
// if the scene was suspended recalcutlate the delta tu "curtime"
|
|
m_suspendedtime = scene->getSuspendedTime();
|
|
if (scene->getSuspendedTime()!=0.0)
|
|
scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
|
|
m_suspendeddelta = scene->getSuspendedDelta();
|
|
|
|
// set Python hooks for each scene
|
|
#ifdef WITH_PYTHON
|
|
PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
|
|
#endif
|
|
KX_SetActiveScene(scene);
|
|
|
|
m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_PHYSICS1);
|
|
scene->UpdateParents(m_clockTime);
|
|
|
|
// 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()->proceedDeltaTime(m_clockTime,timestep,timestep);
|
|
// Update scenegraph after physics step. This maps physics calculations
|
|
// into node positions.
|
|
m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_PHYSICS2);
|
|
scene->UpdateParents(m_clockTime);
|
|
|
|
// Do some cleanup work for this logic frame
|
|
m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
|
|
scene->LogicUpdateFrame(m_clockTime, false);
|
|
|
|
// Actuators can affect the scenegraph
|
|
m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_ACTUATOR);
|
|
scene->UpdateParents(m_clockTime);
|
|
|
|
scene->setSuspendedTime(0.0);
|
|
} // suspended
|
|
else
|
|
if (scene->getSuspendedTime()==0.0)
|
|
scene->setSuspendedTime(m_clockTime);
|
|
|
|
m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
|
|
}
|
|
}
|
|
|
|
|
|
// Handle the animations independently of the logic time step
|
|
if (GetRestrictAnimationFPS())
|
|
{
|
|
m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);
|
|
|
|
double anim_timestep = 1.0/KX_GetActiveScene()->GetAnimationFPS();
|
|
if (m_clockTime - m_previousAnimTime > anim_timestep)
|
|
{
|
|
// Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep)
|
|
// printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime));
|
|
m_previousAnimTime = m_clockTime;
|
|
for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
|
|
{
|
|
(*sceneit)->UpdateAnimations(m_frameTime);
|
|
}
|
|
}
|
|
m_previousClockTime = m_clockTime;
|
|
}
|
|
|
|
// Start logging time spend outside main loop
|
|
m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
|
|
|
|
return doRender;
|
|
}
|
|
|
|
|
|
|
|
void KX_KetsjiEngine::Render()
|
|
{
|
|
if (m_usedome) {
|
|
RenderDome();
|
|
return;
|
|
}
|
|
KX_Scene* firstscene = *m_scenes.begin();
|
|
const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
|
|
|
|
m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_RENDER);
|
|
|
|
// 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|RAS_ICanvas::DEPTH_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;
|
|
KX_Camera* cam = scene->GetActiveCamera();
|
|
// pass the scene's worldsettings to the rasterizer
|
|
SetWorldSettings(scene->GetWorldInfo());
|
|
|
|
// this is now done incrementatlly in KX_Scene::CalculateVisibleMeshes
|
|
//scene->UpdateMeshTransformations();
|
|
|
|
// shadow buffers
|
|
RenderShadowBuffers(scene);
|
|
|
|
// Avoid drawing the scene with the active camera twice when it's viewport is enabled
|
|
if (cam && !cam->GetViewport())
|
|
{
|
|
if (scene->IsClearingZBuffer())
|
|
m_rasterizer->ClearDepthBuffer();
|
|
|
|
m_rendertools->SetAuxilaryClientInfo(scene);
|
|
|
|
// do the rendering
|
|
RenderFrame(scene, cam);
|
|
}
|
|
|
|
list<class KX_Camera*>* cameras = scene->GetCameras();
|
|
|
|
// Draw the scene once for each camera with an enabled viewport
|
|
list<KX_Camera*>::iterator it = cameras->begin();
|
|
while(it != cameras->end())
|
|
{
|
|
if ((*it)->GetViewport())
|
|
{
|
|
if (scene->IsClearingZBuffer())
|
|
m_rasterizer->ClearDepthBuffer();
|
|
|
|
m_rendertools->SetAuxilaryClientInfo(scene);
|
|
|
|
// do the rendering
|
|
RenderFrame(scene, (*it));
|
|
}
|
|
|
|
it++;
|
|
}
|
|
PostRenderScene(scene);
|
|
}
|
|
|
|
// only one place that checks for stereo
|
|
if (m_rasterizer->Stereo())
|
|
{
|
|
m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
|
|
|
|
if (!BeginFrame())
|
|
return;
|
|
|
|
|
|
for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
|
|
// for each scene, call the proceed functions
|
|
{
|
|
KX_Scene* scene = *sceneit;
|
|
KX_Camera* cam = scene->GetActiveCamera();
|
|
|
|
// 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);
|
|
|
|
// do the rendering
|
|
//RenderFrame(scene);
|
|
RenderFrame(scene, cam);
|
|
|
|
list<class KX_Camera*>* cameras = scene->GetCameras();
|
|
|
|
// Draw the scene once for each camera with an enabled viewport
|
|
list<KX_Camera*>::iterator it = cameras->begin();
|
|
while(it != cameras->end())
|
|
{
|
|
if ((*it)->GetViewport())
|
|
{
|
|
if (scene->IsClearingZBuffer())
|
|
m_rasterizer->ClearDepthBuffer();
|
|
|
|
m_rendertools->SetAuxilaryClientInfo(scene);
|
|
|
|
// do the rendering
|
|
RenderFrame(scene, (*it));
|
|
}
|
|
|
|
it++;
|
|
}
|
|
PostRenderScene(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;
|
|
}
|
|
|
|
// check if the window has been closed.
|
|
if (!m_exitcode)
|
|
{
|
|
//if (!m_canvas->Check()) {
|
|
// m_exitcode = KX_EXIT_REQUEST_OUTSIDE;
|
|
//}
|
|
}
|
|
|
|
return m_exitcode;
|
|
}
|
|
|
|
|
|
|
|
const STR_String& KX_KetsjiEngine::GetExitString()
|
|
{
|
|
return m_exitstring;
|
|
}
|
|
|
|
|
|
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())
|
|
{
|
|
// ...
|
|
m_rasterizer->SetAmbientColor(
|
|
wi->getAmbientColorRed(),
|
|
wi->getAmbientColorGreen(),
|
|
wi->getAmbientColorBlue()
|
|
);
|
|
|
|
if (m_drawingmode >= RAS_IRasterizer::KX_SOLID)
|
|
{
|
|
if (wi->hasMist())
|
|
{
|
|
m_rasterizer->SetFog(
|
|
wi->getMistStart(),
|
|
wi->getMistDistance(),
|
|
wi->getMistColorRed(),
|
|
wi->getMistColorGreen(),
|
|
wi->getMistColorBlue()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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::SetCameraOverrideClipping(float nearfrust, float farfrust)
|
|
{
|
|
m_overrideCamNear = nearfrust;
|
|
m_overrideCamFar = farfrust;
|
|
}
|
|
|
|
void KX_KetsjiEngine::SetCameraOverrideLens(float lens)
|
|
{
|
|
m_overrideCamLens = lens;
|
|
}
|
|
|
|
void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport)
|
|
{
|
|
// 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.
|
|
if (cam->GetViewport()) {
|
|
RAS_Rect userviewport;
|
|
|
|
userviewport.SetLeft(cam->GetViewportLeft());
|
|
userviewport.SetBottom(cam->GetViewportBottom());
|
|
userviewport.SetRight(cam->GetViewportRight());
|
|
userviewport.SetTop(cam->GetViewportTop());
|
|
|
|
// Don't do bars on user specified viewport
|
|
RAS_FrameSettings settings = scene->GetFramingType();
|
|
if (settings.FrameType() == RAS_FrameSettings::e_frame_bars)
|
|
settings.SetFrameType(RAS_FrameSettings::e_frame_extend);
|
|
|
|
RAS_FramingManager::ComputeViewport(
|
|
scene->GetFramingType(),
|
|
userviewport,
|
|
viewport
|
|
);
|
|
|
|
area = userviewport;
|
|
}
|
|
else if ( !m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) {
|
|
RAS_FramingManager::ComputeViewport(
|
|
scene->GetFramingType(),
|
|
m_canvas->GetDisplayArea(),
|
|
viewport
|
|
);
|
|
|
|
area = m_canvas->GetDisplayArea();
|
|
} else {
|
|
viewport.SetLeft(0);
|
|
viewport.SetBottom(0);
|
|
viewport.SetRight(int(m_canvas->GetWidth()));
|
|
viewport.SetTop(int(m_canvas->GetHeight()));
|
|
|
|
area = m_canvas->GetDisplayArea();
|
|
}
|
|
}
|
|
|
|
void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
|
|
{
|
|
CListValue *lightlist = scene->GetLightList();
|
|
int i, drawmode;
|
|
|
|
m_rendertools->SetAuxilaryClientInfo(scene);
|
|
|
|
for (i=0; i<lightlist->GetCount(); i++) {
|
|
KX_GameObject *gameobj = (KX_GameObject*)lightlist->GetValue(i);
|
|
|
|
KX_LightObject *light = (KX_LightObject*)gameobj;
|
|
|
|
light->Update();
|
|
|
|
if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) {
|
|
/* make temporary camera */
|
|
RAS_CameraData camdata = RAS_CameraData();
|
|
KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, true, true);
|
|
cam->SetName("__shadow__cam__");
|
|
|
|
MT_Transform camtrans;
|
|
|
|
/* switch drawmode for speed */
|
|
drawmode = m_rasterizer->GetDrawingMode();
|
|
m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW);
|
|
|
|
/* binds framebuffer object, sets up camera .. */
|
|
light->BindShadowBuffer(m_rasterizer, cam, camtrans);
|
|
|
|
/* update scene */
|
|
scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer());
|
|
|
|
/* render */
|
|
m_rasterizer->ClearDepthBuffer();
|
|
scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
|
|
|
|
/* unbind framebuffer object, restore drawmode, free camera */
|
|
light->UnbindShadowBuffer(m_rasterizer);
|
|
m_rasterizer->SetDrawingMode(drawmode);
|
|
cam->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
// update graphics
|
|
void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
|
|
{
|
|
bool override_camera;
|
|
RAS_Rect viewport, area;
|
|
float nearfrust, farfrust, focallength;
|
|
// KX_Camera* cam = scene->GetActiveCamera();
|
|
|
|
if (!cam)
|
|
return;
|
|
GetSceneViewport(scene, cam, area, viewport);
|
|
|
|
// 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());
|
|
|
|
// see KX_BlenderMaterial::Activate
|
|
//m_rasterizer->SetAmbient();
|
|
m_rasterizer->DisplayFog();
|
|
|
|
override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName);
|
|
override_camera = override_camera && (cam->GetName() == "__default__cam__");
|
|
|
|
if (override_camera && m_overrideCamUseOrtho) {
|
|
m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat);
|
|
if (!cam->hasValidProjectionMatrix()) {
|
|
// needed to get frustrum planes for culling
|
|
MT_Matrix4x4 projmat;
|
|
projmat.setValue(m_overrideCamProjMat.getPointer());
|
|
cam->SetProjectionMatrix(projmat);
|
|
}
|
|
} else if (cam->hasValidProjectionMatrix())
|
|
{
|
|
m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
|
|
} else
|
|
{
|
|
RAS_FrameFrustum frustum;
|
|
bool orthographic = !cam->GetCameraData()->m_perspective;
|
|
nearfrust = cam->GetCameraNear();
|
|
farfrust = cam->GetCameraFar();
|
|
focallength = cam->GetFocalLength();
|
|
MT_Matrix4x4 projmat;
|
|
|
|
if (override_camera) {
|
|
nearfrust = m_overrideCamNear;
|
|
farfrust = m_overrideCamFar;
|
|
}
|
|
|
|
if (orthographic) {
|
|
|
|
RAS_FramingManager::ComputeOrtho(
|
|
scene->GetFramingType(),
|
|
area,
|
|
viewport,
|
|
cam->GetScale(),
|
|
nearfrust,
|
|
farfrust,
|
|
cam->GetSensorFit(),
|
|
frustum
|
|
);
|
|
if (!cam->GetViewport()) {
|
|
frustum.x1 *= m_cameraZoom;
|
|
frustum.x2 *= m_cameraZoom;
|
|
frustum.y1 *= m_cameraZoom;
|
|
frustum.y2 *= m_cameraZoom;
|
|
}
|
|
projmat = m_rasterizer->GetOrthoMatrix(
|
|
frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar);
|
|
|
|
} else {
|
|
RAS_FramingManager::ComputeFrustum(
|
|
scene->GetFramingType(),
|
|
area,
|
|
viewport,
|
|
cam->GetLens(),
|
|
cam->GetSensorWidth(),
|
|
cam->GetSensorHeight(),
|
|
cam->GetSensorFit(),
|
|
nearfrust,
|
|
farfrust,
|
|
frustum
|
|
);
|
|
|
|
if (!cam->GetViewport()) {
|
|
frustum.x1 *= m_cameraZoom;
|
|
frustum.x2 *= m_cameraZoom;
|
|
frustum.y1 *= m_cameraZoom;
|
|
frustum.y2 *= m_cameraZoom;
|
|
}
|
|
projmat = m_rasterizer->GetFrustumMatrix(
|
|
frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength);
|
|
}
|
|
cam->SetProjectionMatrix(projmat);
|
|
|
|
// Otherwise the projection matrix for each eye will be the same...
|
|
if (!orthographic && m_rasterizer->Stereo())
|
|
cam->InvalidateProjectionMatrix();
|
|
}
|
|
|
|
MT_Transform camtrans(cam->GetWorldToCamera());
|
|
MT_Matrix4x4 viewmat(camtrans);
|
|
|
|
m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective);
|
|
cam->SetModelviewMatrix(viewmat);
|
|
|
|
// 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.
|
|
|
|
m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_CULLING);
|
|
|
|
scene->CalculateVisibleMeshes(m_rasterizer,cam);
|
|
|
|
m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
|
|
SG_SetActiveStage(SG_STAGE_RENDER);
|
|
|
|
#ifdef WITH_PYTHON
|
|
// Run any pre-drawing python callbacks
|
|
scene->RunDrawingCallbacks(scene->GetPreDrawCB());
|
|
#endif
|
|
|
|
scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
|
|
|
|
//render all the font objects for this scene
|
|
RenderFonts(scene);
|
|
|
|
if (scene->GetPhysicsEnvironment())
|
|
scene->GetPhysicsEnvironment()->debugDrawWorld();
|
|
}
|
|
|
|
void KX_KetsjiEngine::RenderFonts(KX_Scene* scene)
|
|
{
|
|
list<class KX_FontObject*>* fonts = scene->GetFonts();
|
|
|
|
list<KX_FontObject*>::iterator it = fonts->begin();
|
|
while(it != fonts->end())
|
|
{
|
|
(*it)->DrawText();
|
|
++it;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* To run once per scene
|
|
*/
|
|
void KX_KetsjiEngine::PostRenderScene(KX_Scene* scene)
|
|
{
|
|
// We need to first make sure our viewport is correct (enabling multiple viewports can mess this up)
|
|
m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
|
|
|
|
m_rendertools->MotionBlur(m_rasterizer);
|
|
scene->Render2DFilters(m_canvas);
|
|
#ifdef WITH_PYTHON
|
|
scene->RunDrawingCallbacks(scene->GetPostDrawCB());
|
|
#endif
|
|
m_rasterizer->FlushDebugShapes();
|
|
}
|
|
|
|
void KX_KetsjiEngine::StopEngine()
|
|
{
|
|
if (m_bInitialized)
|
|
{
|
|
|
|
if (m_animation_record)
|
|
{
|
|
// printf("TestHandlesPhysicsObjectToAnimationIpo\n");
|
|
m_sceneconverter->TestHandlesPhysicsObjectToAnimationIpo();
|
|
}
|
|
|
|
KX_SceneList::iterator sceneit;
|
|
for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
|
|
{
|
|
KX_Scene* scene = *sceneit;
|
|
m_sceneconverter->RemoveScene(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));
|
|
|
|
SG_SetActiveStage(SG_STAGE_SCENE);
|
|
|
|
// 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();
|
|
if (override_camera)
|
|
{
|
|
camdata.m_lens = m_overrideCamLens;
|
|
camdata.m_clipstart = m_overrideCamNear;
|
|
camdata.m_clipend = m_overrideCamFar;
|
|
|
|
camdata.m_perspective= !m_overrideCamUseOrtho;
|
|
}
|
|
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);
|
|
} else {
|
|
activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
|
|
activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
|
|
activecam->NodeUpdateGS(0);
|
|
}
|
|
|
|
scene->AddCamera(activecam);
|
|
scene->SetActiveCamera(activecam);
|
|
scene->GetObjectList()->Add(activecam->AddRef());
|
|
scene->GetRootParentList()->Add(activecam->AddRef());
|
|
//done with activecam
|
|
activecam->Release();
|
|
}
|
|
|
|
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' behavior
|
|
|
|
float tottime = m_logger->GetAverage();
|
|
if (tottime < 1e-6f) {
|
|
tottime = 1e-6f;
|
|
}
|
|
|
|
// Set viewport to entire canvas
|
|
RAS_Rect viewport;
|
|
m_canvas->SetViewPort(0, 0, int(m_canvas->GetWidth()), int(m_canvas->GetHeight()));
|
|
|
|
/* 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("%.3fms (%2.2f %%)", time*1000.f, 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;
|
|
if (propname == "__state__")
|
|
{
|
|
// reserve name for object state
|
|
KX_GameObject* gameobj = static_cast<KX_GameObject*>(propobj);
|
|
unsigned int state = gameobj->GetState();
|
|
debugtxt = objname + "." + propname + " = ";
|
|
bool first = true;
|
|
for (int statenum=1;state;state >>= 1, statenum++)
|
|
{
|
|
if (state & 1)
|
|
{
|
|
if (!first)
|
|
{
|
|
debugtxt += ",";
|
|
}
|
|
debugtxt += STR_String(statenum);
|
|
first = false;
|
|
}
|
|
}
|
|
m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
|
|
debugtxt.Ptr(),
|
|
xcoord,
|
|
ycoord,
|
|
m_canvas->GetWidth(),
|
|
m_canvas->GetHeight());
|
|
ycoord += 14;
|
|
}
|
|
else
|
|
{
|
|
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)
|
|
{
|
|
m_sceneconverter->RemoveScene(scene);
|
|
m_scenes.erase(sceneit);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
m_removingScenes.clear();
|
|
}
|
|
}
|
|
|
|
KX_Scene* KX_KetsjiEngine::CreateScene(Scene *scene)
|
|
{
|
|
KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice,
|
|
m_mousedevice,
|
|
m_networkdevice,
|
|
scene->id.name+2,
|
|
scene,
|
|
m_canvas);
|
|
|
|
m_sceneconverter->ConvertScene(tmpscene,
|
|
m_rendertools,
|
|
m_canvas);
|
|
|
|
return tmpscene;
|
|
}
|
|
|
|
KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename)
|
|
{
|
|
Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename);
|
|
return CreateScene(scene);
|
|
}
|
|
|
|
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)
|
|
{
|
|
m_sceneconverter->RemoveScene(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;
|
|
}
|
|
|
|
|
|
void KX_KetsjiEngine::SetAnimRecordMode(bool animation_record, int startFrame)
|
|
{
|
|
m_animation_record = animation_record;
|
|
if (animation_record)
|
|
{
|
|
//when recording physics keyframes, run at a variable (capped) frame rate (fixed time == full speed)
|
|
m_bFixedTime = false;
|
|
}
|
|
m_currentFrame = startFrame;
|
|
}
|
|
|
|
bool KX_KetsjiEngine::GetUseFixedTime(void) const
|
|
{
|
|
return m_bFixedTime;
|
|
}
|
|
|
|
double KX_KetsjiEngine::GetSuspendedDelta()
|
|
{
|
|
return m_suspendeddelta;
|
|
}
|
|
|
|
double KX_KetsjiEngine::GetTicRate()
|
|
{
|
|
return m_ticrate;
|
|
}
|
|
|
|
void KX_KetsjiEngine::SetTicRate(double ticrate)
|
|
{
|
|
m_ticrate = ticrate;
|
|
}
|
|
|
|
int KX_KetsjiEngine::GetMaxLogicFrame()
|
|
{
|
|
return m_maxLogicFrame;
|
|
}
|
|
|
|
void KX_KetsjiEngine::SetMaxLogicFrame(int frame)
|
|
{
|
|
m_maxLogicFrame = frame;
|
|
}
|
|
|
|
int KX_KetsjiEngine::GetMaxPhysicsFrame()
|
|
{
|
|
return m_maxPhysicsFrame;
|
|
}
|
|
|
|
void KX_KetsjiEngine::SetMaxPhysicsFrame(int frame)
|
|
{
|
|
m_maxPhysicsFrame = frame;
|
|
}
|
|
|
|
bool KX_KetsjiEngine::GetRestrictAnimationFPS()
|
|
{
|
|
return m_restrict_anim_fps;
|
|
}
|
|
|
|
void KX_KetsjiEngine::SetRestrictAnimationFPS(bool bRestrictAnimFPS)
|
|
{
|
|
m_restrict_anim_fps = bRestrictAnimFPS;
|
|
}
|
|
|
|
double KX_KetsjiEngine::GetAnimFrameRate()
|
|
{
|
|
return m_anim_framerate;
|
|
}
|
|
|
|
double KX_KetsjiEngine::GetClockTime(void) const
|
|
{
|
|
return m_clockTime;
|
|
}
|
|
|
|
double KX_KetsjiEngine::GetFrameTime(void) const
|
|
{
|
|
return m_frameTime;
|
|
}
|
|
|
|
double KX_KetsjiEngine::GetRealTime(void) const
|
|
{
|
|
return m_kxsystem->GetTimeInSeconds();
|
|
}
|
|
|
|
void KX_KetsjiEngine::SetAnimFrameRate(double framerate)
|
|
{
|
|
m_anim_framerate = framerate;
|
|
}
|
|
|
|
double KX_KetsjiEngine::GetAverageFrameRate()
|
|
{
|
|
return m_average_framerate;
|
|
}
|
|
|
|
void KX_KetsjiEngine::SetExitKey(short key)
|
|
{
|
|
m_exitkey = key;
|
|
}
|
|
|
|
short KX_KetsjiEngine::GetExitKey()
|
|
{
|
|
return m_exitkey;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void KX_KetsjiEngine::SetGlobalSettings(GlobalSettings* gs)
|
|
{
|
|
m_globalsettings.matmode = gs->matmode;
|
|
m_globalsettings.glslflag = gs->glslflag;
|
|
}
|
|
|
|
GlobalSettings* KX_KetsjiEngine::GetGlobalSettings(void)
|
|
{
|
|
return &m_globalsettings;
|
|
}
|
|
|