Changeset View
Changeset View
Standalone View
Standalone View
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
| Context not available. | |||||
| * Contributor(s): none yet. | * Contributor(s): none yet. | ||||
| * | * | ||||
| * ***** END GPL LICENSE BLOCK ***** | * ***** END GPL LICENSE BLOCK ***** | ||||
| * The engine ties all game modules together. | * The engine ties all game modules together. | ||||
| */ | */ | ||||
| /** \file gameengine/Ketsji/KX_KetsjiEngine.cpp | /** \file gameengine/Ketsji/KX_KetsjiEngine.cpp | ||||
| Context not available. | |||||
| # pragma warning (disable:4786) | # pragma warning (disable:4786) | ||||
| #endif | #endif | ||||
| #include <iostream> | #include "CM_Message.h" | ||||
| #include <stdio.h> | |||||
| #include <boost/format.hpp> | |||||
| #include "BLI_task.h" | #include "BLI_task.h" | ||||
| Context not available. | |||||
| #include "EXP_ListValue.h" | #include "EXP_ListValue.h" | ||||
| #include "EXP_IntValue.h" | #include "EXP_IntValue.h" | ||||
| #include "EXP_VectorValue.h" | |||||
| #include "EXP_BoolValue.h" | #include "EXP_BoolValue.h" | ||||
| #include "EXP_FloatValue.h" | #include "EXP_FloatValue.h" | ||||
| Context not available. | |||||
| #include "MT_Transform.h" | #include "MT_Transform.h" | ||||
| #include "SCA_IInputDevice.h" | #include "SCA_IInputDevice.h" | ||||
| #include "KX_Camera.h" | #include "KX_Camera.h" | ||||
| #include "KX_Dome.h" | |||||
| #include "KX_Light.h" | #include "KX_Light.h" | ||||
| #include "KX_PythonInit.h" | #include "KX_Globals.h" | ||||
| #include "KX_PyConstraintBinding.h" | #include "KX_PyConstraintBinding.h" | ||||
| #include "PHY_IPhysicsEnvironment.h" | #include "PHY_IPhysicsEnvironment.h" | ||||
| #include "NG_NetworkScene.h" | #include "KX_NetworkMessageScene.h" | ||||
| #include "NG_NetworkDeviceInterface.h" | |||||
| #include "DEV_Joystick.h" // for DEV_Joystick::HandleEvents | |||||
| #include "KX_PythonInit.h" // for updatePythonJoysticks | |||||
| #include "KX_WorldInfo.h" | #include "KX_WorldInfo.h" | ||||
| #include "KX_ISceneConverter.h" | #include "KX_ISceneConverter.h" | ||||
| Context not available. | |||||
| #include "KX_NavMeshObject.h" | #include "KX_NavMeshObject.h" | ||||
| #include "BL_Action.h" // For managing action lock. | |||||
| #define DEFAULT_LOGIC_TIC_RATE 60.0 | #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 FREE_WINDOWS /* XXX mingw64 (gcc 4.7.0) defines a macro for DrawText that translates to DrawTextA. Not good */ | ||||
| #ifdef DrawText | # ifdef DrawText | ||||
| #undef DrawText | # undef DrawText | ||||
| #endif | # endif | ||||
| #endif | #endif | ||||
| const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = { | const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = { | ||||
| "Physics:", // tc_physics | "Physics:", // tc_physics | ||||
| "Logic:", // tc_logic | "Logic:", // tc_logic | ||||
| "Animations:", // tc_animations | "Animations:", // tc_animations | ||||
| "Network:", // tc_network | "Network:", // tc_network | ||||
| "Scenegraph:", // tc_scenegraph | "Scenegraph:", // tc_scenegraph | ||||
| "Rasterizer:", // tc_rasterizer | "Rasterizer:", // tc_rasterizer | ||||
| "Services:", // tc_services | "Services:", // tc_services | ||||
| "Overhead:", // tc_overhead | "Overhead:", // tc_overhead | ||||
| "Outside:", // tc_outside | "Outside:", // tc_outside | ||||
| "GPU Latency:" // tc_latency | "GPU Latency:" // tc_latency | ||||
| }; | }; | ||||
| double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE; | double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE; | ||||
| int KX_KetsjiEngine::m_maxLogicFrame = 5; | int KX_KetsjiEngine::m_maxLogicFrame = 5; | ||||
| int KX_KetsjiEngine::m_maxPhysicsFrame = 5; | int KX_KetsjiEngine::m_maxPhysicsFrame = 5; | ||||
| double KX_KetsjiEngine::m_anim_framerate = 25.0; | double KX_KetsjiEngine::m_anim_framerate = 25.0; | ||||
| double KX_KetsjiEngine::m_suspendedtime = 0.0; | double KX_KetsjiEngine::m_suspendedtime = 0.0; | ||||
| double KX_KetsjiEngine::m_suspendeddelta = 0.0; | double KX_KetsjiEngine::m_suspendeddelta = 0.0; | ||||
| double KX_KetsjiEngine::m_average_framerate = 0.0; | double KX_KetsjiEngine::m_average_framerate = 0.0; | ||||
| bool KX_KetsjiEngine::m_restrict_anim_fps = false; | bool KX_KetsjiEngine::m_restrict_anim_fps = false; | ||||
| short KX_KetsjiEngine::m_exitkey = 130; // ESC Key | short KX_KetsjiEngine::m_exitkey = 130; // ESC Key | ||||
| bool KX_KetsjiEngine::m_doRender = true; | bool KX_KetsjiEngine::m_doRender = true; | ||||
| /** | /** | ||||
| * Constructor of the Ketsji Engine | * Constructor of the Ketsji Engine | ||||
| */ | */ | ||||
| KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) | KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem *system) | ||||
| : m_canvas(NULL), | :m_canvas(NULL), | ||||
| m_rasterizer(NULL), | m_rasterizer(NULL), | ||||
| m_kxsystem(system), | m_kxsystem(system), | ||||
| m_sceneconverter(NULL), | m_sceneconverter(NULL), | ||||
| m_networkdevice(NULL), | |||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| m_pythondictionary(NULL), | m_pythondictionary(NULL), | ||||
| #endif | #endif | ||||
| m_keyboarddevice(NULL), | m_inputDevice(NULL), | ||||
| m_mousedevice(NULL), | |||||
| m_bInitialized(false), | m_bInitialized(false), | ||||
| m_activecam(0), | m_activecam(0), | ||||
| m_bFixedTime(false), | m_fixedFramerate(false), | ||||
| m_useExternalClock(false), | m_useExternalClock(false), | ||||
| m_firstframe(true), | m_firstframe(true), | ||||
| m_frameTime(0.0f), | |||||
| m_frameTime(0.f), | m_clockTime(0.0f), | ||||
| m_clockTime(0.f), | m_previousClockTime(0.0f), | ||||
| m_previousClockTime(0.f), | m_previousAnimTime(0.0f), | ||||
| m_previousAnimTime(0.f), | |||||
| m_timescale(1.0f), | m_timescale(1.0f), | ||||
| m_previousRealTime(0.0f), | m_previousRealTime(0.0f), | ||||
| m_exitcode(KX_EXIT_REQUEST_NO_REQUEST), | m_exitcode(KX_EXIT_REQUEST_NO_REQUEST), | ||||
| m_exitstring(""), | m_exitstring(""), | ||||
| m_cameraZoom(1.0f), | m_cameraZoom(1.0f), | ||||
| m_overrideCam(false), | m_overrideCam(false), | ||||
| m_overrideCamUseOrtho(false), | m_overrideCamUseOrtho(false), | ||||
| m_overrideCamNear(0.0f), | m_overrideCamNear(0.0f), | ||||
| m_overrideCamFar(0.0f), | m_overrideCamFar(0.0f), | ||||
| m_overrideCamZoom(1.0f), | m_overrideCamZoom(1.0f), | ||||
| m_stereo(false), | m_stereo(false), | ||||
| m_curreye(0), | m_curreye(0), | ||||
| m_logger(NULL), | m_logger(NULL), | ||||
| // Set up timing info display variables | // Set up timing info display variables | ||||
| m_show_framerate(false), | m_show_framerate(false), | ||||
| m_show_profile(false), | m_show_profile(false), | ||||
| Context not available. | |||||
| m_showBackground(false), | m_showBackground(false), | ||||
| m_show_debug_properties(false), | m_show_debug_properties(false), | ||||
| m_autoAddDebugProperties(true), | m_autoAddDebugProperties(true), | ||||
| m_animation_record(false), | |||||
| // Default behavior is to hide the cursor every frame. | // Default behavior is to hide the cursor every frame. | ||||
| m_hideCursor(false), | m_hideCursor(false), | ||||
| m_showBoundingBox(false), | |||||
| m_showArmature(false), | |||||
| m_overrideFrameColor(false), | m_overrideFrameColor(false), | ||||
| m_overrideFrameColorR(0.0f), | m_overrideFrameColorR(0.0f), | ||||
| m_overrideFrameColorG(0.0f), | m_overrideFrameColorG(0.0f), | ||||
| m_overrideFrameColorB(0.0f), | m_overrideFrameColorB(0.0f), | ||||
| m_overrideFrameColorA(0.0f), | m_overrideFrameColorA(0.0f) | ||||
| m_usedome(false) | |||||
| { | { | ||||
| // Initialize the time logger | // Initialize the time logger | ||||
| m_logger = new KX_TimeCategoryLogger (25); | m_logger = new KX_TimeCategoryLogger(25); | ||||
| for (int i = tc_first; i < tc_numCategories; i++) | for (int i = tc_first; i < tc_numCategories; i++) | ||||
| m_logger->AddCategory((KX_TimeCategory)i); | m_logger->AddCategory((KX_TimeCategory)i); | ||||
| Context not available. | |||||
| m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS); | m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS); | ||||
| BL_Action::InitLock(); | m_scenes = new CListValue(); | ||||
| } | } | ||||
| /** | /** | ||||
| * Destructor of the Ketsji Engine, release all memory | * Destructor of the Ketsji Engine, release all memory | ||||
| */ | */ | ||||
| KX_KetsjiEngine::~KX_KetsjiEngine() | KX_KetsjiEngine::~KX_KetsjiEngine() | ||||
| { | { | ||||
| delete m_logger; | delete m_logger; | ||||
| if (m_usedome) | |||||
| delete m_dome; | |||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| Py_CLEAR(m_pyprofiledict); | Py_CLEAR(m_pyprofiledict); | ||||
| Context not available. | |||||
| if (m_taskscheduler) | if (m_taskscheduler) | ||||
| BLI_task_scheduler_free(m_taskscheduler); | BLI_task_scheduler_free(m_taskscheduler); | ||||
| BL_Action::EndLock(); | m_scenes->Release(); | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetInputDevice(SCA_IInputDevice *inputDevice) | |||||
| void KX_KetsjiEngine::SetKeyboardDevice(SCA_IInputDevice* keyboarddevice) | |||||
| { | { | ||||
| MT_assert(keyboarddevice); | BLI_assert(inputDevice); | ||||
| m_keyboarddevice = keyboarddevice; | m_inputDevice = inputDevice; | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetCanvas(RAS_ICanvas *canvas) | |||||
| void KX_KetsjiEngine::SetMouseDevice(SCA_IInputDevice* mousedevice) | |||||
| { | { | ||||
| MT_assert(mousedevice); | BLI_assert(canvas); | ||||
| m_mousedevice = mousedevice; | m_canvas = canvas; | ||||
| } | |||||
| void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice) | |||||
| { | |||||
| MT_assert(networkdevice); | |||||
| m_networkdevice = networkdevice; | |||||
| } | } | ||||
| void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer *rasterizer) | |||||
| void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas) | |||||
| { | { | ||||
| MT_assert(canvas); | BLI_assert(rasterizer); | ||||
| m_canvas = canvas; | m_rasterizer = rasterizer; | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetNetworkMessageManager(KX_NetworkMessageManager *manager) | |||||
| void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer) | |||||
| { | { | ||||
| MT_assert(rasterizer); | m_networkMessageManager = manager; | ||||
| m_rasterizer = rasterizer; | |||||
| } | } | ||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| Context not available. | |||||
| */ | */ | ||||
| void KX_KetsjiEngine::SetPyNamespace(PyObject *pythondictionary) | void KX_KetsjiEngine::SetPyNamespace(PyObject *pythondictionary) | ||||
| { | { | ||||
| MT_assert(pythondictionary); | BLI_assert(pythondictionary); | ||||
| m_pythondictionary = pythondictionary; | m_pythondictionary = pythondictionary; | ||||
| } | } | ||||
| PyObject* KX_KetsjiEngine::GetPyProfileDict() | PyObject *KX_KetsjiEngine::GetPyProfileDict() | ||||
| { | { | ||||
| Py_INCREF(m_pyprofiledict); | Py_INCREF(m_pyprofiledict); | ||||
| return m_pyprofiledict; | return m_pyprofiledict; | ||||
| } | } | ||||
| #endif | #endif | ||||
| void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter *sceneconverter) | |||||
| void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter) | |||||
| { | { | ||||
| MT_assert(sceneconverter); | BLI_assert(sceneconverter); | ||||
| m_sceneconverter = 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,this, res, mode, angle, resbuf, tilt, text); | |||||
| m_usedome = true; | |||||
| } | |||||
| void KX_KetsjiEngine::RenderDome() | |||||
| { | |||||
| const GLint *viewport = m_canvas->GetViewPort(); | |||||
| 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 = NULL; | |||||
| 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_SetActiveScene(scene); | |||||
| KX_Camera* cam = scene->GetActiveCamera(); | |||||
| // pass the scene's worldsettings to the rasterizer | |||||
| scene->GetWorldInfo()->UpdateWorldSettings(); | |||||
| // shadow buffers | |||||
| if (i == 0) { | |||||
| RenderShadowBuffers(scene); | |||||
| } | |||||
| // Avoid drawing the scene with the active camera twice when its viewport is enabled | |||||
| if (cam && !cam->GetViewport()) | |||||
| { | |||||
| if (scene->IsClearingZBuffer()) | |||||
| m_rasterizer->ClearDepthBuffer(); | |||||
| m_rasterizer->SetAuxilaryClientInfo(scene); | |||||
| // do the rendering | |||||
| m_dome->RenderDomeFrame(scene,cam, i); | |||||
| // render all the font objects for this scene | |||||
| scene->RenderFonts(); | |||||
| } | |||||
| 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_rasterizer->SetAuxilaryClientInfo(scene); | |||||
| // do the rendering | |||||
| m_dome->RenderDomeFrame(scene, (*it),i); | |||||
| // render all the font objects for this scene | |||||
| scene->RenderFonts(); | |||||
| } | |||||
| it++; | |||||
| } | |||||
| // Part of PostRenderScene() | |||||
| m_rasterizer->MotionBlur(); | |||||
| 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, | |||||
| m_overrideFrameColorA | |||||
| ); | |||||
| } | |||||
| 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 | |||||
| PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); | |||||
| scene->RunDrawingCallbacks(scene->GetPostDrawCB()); | |||||
| #endif | |||||
| EndFrame(); | |||||
| } | |||||
| /** | /** | ||||
| * Ketsji Init(), Initializes data-structures and converts data from | * Ketsji Init(), Initializes data-structures and converts data from | ||||
| * Blender into Ketsji native (realtime) format also sets up the | * Blender into Ketsji native (realtime) format also sets up the | ||||
| Context not available. | |||||
| m_firstframe = true; | m_firstframe = true; | ||||
| m_bInitialized = true; | m_bInitialized = true; | ||||
| // there is always one scene enabled at startup | // there is always one scene enabled at startup | ||||
| Scene* scene = m_scenes[0]->GetBlenderScene(); | Scene *scene = ((KX_Scene *)m_scenes->GetFront())->GetBlenderScene(); | ||||
| if (scene) | if (scene) { | ||||
| { | |||||
| m_ticrate = scene->gm.ticrate ? scene->gm.ticrate : DEFAULT_LOGIC_TIC_RATE; | m_ticrate = scene->gm.ticrate ? scene->gm.ticrate : DEFAULT_LOGIC_TIC_RATE; | ||||
| m_maxLogicFrame = scene->gm.maxlogicstep ? scene->gm.maxlogicstep : 5; | m_maxLogicFrame = scene->gm.maxlogicstep ? scene->gm.maxlogicstep : 5; | ||||
| m_maxPhysicsFrame = scene->gm.maxphystep ? scene->gm.maxlogicstep : 5; | m_maxPhysicsFrame = scene->gm.maxphystep ? scene->gm.maxlogicstep : 5; | ||||
| } | } | ||||
| else | else { | ||||
| { | |||||
| m_ticrate = DEFAULT_LOGIC_TIC_RATE; | m_ticrate = DEFAULT_LOGIC_TIC_RATE; | ||||
| m_maxLogicFrame = 5; | m_maxLogicFrame = 5; | ||||
| m_maxPhysicsFrame = 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(); | |||||
| firstscene->GetWorldInfo()->UpdateBackGround(); | |||||
| m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(), | |||||
| clearvp.GetRight(), clearvp.GetTop()); | |||||
| m_rasterizer->ClearColorBuffer(); | |||||
| } | |||||
| } | } | ||||
| bool KX_KetsjiEngine::BeginFrame() | void KX_KetsjiEngine::BeginFrame() | ||||
| { | { | ||||
| // set the area used for rendering (stereo can assign only a subset) | m_rasterizer->BeginFrame(m_kxsystem->GetTimeInSeconds()); | ||||
| m_rasterizer->SetRenderArea(); | |||||
| if (m_canvas->BeginDraw()) | |||||
| { | |||||
| ClearFrame(); | |||||
| m_rasterizer->BeginFrame(m_kxsystem->GetTimeInSeconds()); | m_canvas->BeginDraw(); | ||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | } | ||||
| void KX_KetsjiEngine::EndFrame() | void KX_KetsjiEngine::EndFrame() | ||||
| { | { | ||||
| m_rasterizer->MotionBlur(); | m_rasterizer->MotionBlur(); | ||||
| // Show profiling info | // Show profiling info | ||||
| m_logger->StartLog(tc_overhead, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_overhead, m_kxsystem->GetTimeInSeconds(), true); | ||||
| if (m_show_framerate || m_show_profile || (m_show_debug_properties)) | if (m_show_framerate || m_show_profile || (m_show_debug_properties)) { | ||||
| { | |||||
| RenderDebugProperties(); | RenderDebugProperties(); | ||||
| } | } | ||||
| Context not available. | |||||
| for (int i = tc_first; i < tc_numCategories; ++i) { | for (int i = tc_first; i < tc_numCategories; ++i) { | ||||
| double time = m_logger->GetAverage((KX_TimeCategory)i); | double time = m_logger->GetAverage((KX_TimeCategory)i); | ||||
| PyObject *val = PyTuple_New(2); | PyObject *val = PyTuple_New(2); | ||||
| PyTuple_SetItem(val, 0, PyFloat_FromDouble(time*1000.0)); | PyTuple_SetItem(val, 0, PyFloat_FromDouble(time * 1000.0)); | ||||
| PyTuple_SetItem(val, 1, PyFloat_FromDouble(time/tottime * 100.0)); | PyTuple_SetItem(val, 1, PyFloat_FromDouble(time / tottime * 100.0)); | ||||
| PyDict_SetItemString(m_pyprofiledict, m_profileLabels[i], val); | PyDict_SetItemString(m_pyprofiledict, m_profileLabels[i], val); | ||||
| Py_DECREF(val); | Py_DECREF(val); | ||||
| } | } | ||||
| #endif | #endif | ||||
| m_average_framerate = 1.0/tottime; | m_average_framerate = 1.0 / tottime; | ||||
| // Go to next profiling measurement, time spent after this call is shown in the next frame. | // Go to next profiling measurement, time spent after this call is shown in the next frame. | ||||
| m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds()); | m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds()); | ||||
| Context not available. | |||||
| m_rasterizer->EndFrame(); | m_rasterizer->EndFrame(); | ||||
| // swap backbuffer (drawing into this buffer) <-> front/visible buffer | // swap backbuffer (drawing into this buffer) <-> front/visible buffer | ||||
| m_logger->StartLog(tc_latency, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_latency, m_kxsystem->GetTimeInSeconds(), true); | ||||
| m_rasterizer->SwapBuffers(); | m_rasterizer->SwapBuffers(m_canvas); | ||||
| m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); | ||||
| m_canvas->EndDraw(); | m_canvas->EndDraw(); | ||||
| } | } | ||||
| //#include "PIL_time.h" | |||||
| //#include "LinearMath/btQuickprof.h" | |||||
| bool KX_KetsjiEngine::NextFrame() | bool KX_KetsjiEngine::NextFrame() | ||||
| { | { | ||||
| double timestep = m_timescale / m_ticrate; | |||||
| double framestep = timestep; | |||||
| // static hidden::Clock sClock; | |||||
| m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true); | |||||
| //float dt = sClock.getTimeMicroseconds() * 0.000001f; | m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); | ||||
| //sClock.reset(); | |||||
| /* | /* | ||||
| * Clock advancement. There is basically three case: | * Clock advancement. There is basically two case: | ||||
| * - m_useExternalClock is true, the user is responsible to advance the time | * - m_useExternalClock is true, the user is responsible to advance the time | ||||
| * manually using setClockTime, so here, we do not do anything. | * manually using setClockTime, so here, we do not do anything. | ||||
| * - m_useExternalClock is false, m_bFixedTime is true, we advance for one | * - m_useExternalClock is false, we consider how much | ||||
| * timestep, which already handle the time scaling parameter | |||||
| * - m_useExternalClock is false, m_bFixedTime is false, we consider how much | |||||
| * time has elapsed since last call and we scale this time by the time | * time has elapsed since last call and we scale this time by the time | ||||
| * scaling parameter. If m_timescale is 1.0 (default value), the clock | * scaling parameter. If m_timescale is 1.0 (default value), the clock | ||||
| * corresponds to the computer clock. | * corresponds to the computer clock. | ||||
| Context not available. | |||||
| * - ticrate | * - ticrate | ||||
| * - max_physic_frame | * - max_physic_frame | ||||
| * - max_logic_frame | * - max_logic_frame | ||||
| * - fixed_framerate | |||||
| * XXX The logic over computation framestep is definitively not clear (and | * XXX The logic over computation framestep is definitively not clear (and | ||||
| * I'm not even sure it is correct). If needed frame is strictly greater | * I'm not even sure it is correct). If needed frame is strictly greater | ||||
| * than max_physics_frame, we are doing a jump in game time, but keeping | * than max_physics_frame, we are doing a jump in game time, but keeping | ||||
| Context not available. | |||||
| * | * | ||||
| * XXX render.fps is not considred anywhere. | * XXX render.fps is not considred anywhere. | ||||
| */ | */ | ||||
| double timestep = m_timescale / m_ticrate; | |||||
| if (!m_useExternalClock) { | if (!m_useExternalClock) { | ||||
| if (m_bFixedTime) { | double current_time = m_kxsystem->GetTimeInSeconds(); | ||||
| m_clockTime += timestep; | double dt = current_time - m_previousRealTime; | ||||
| } | m_previousRealTime = current_time; | ||||
| else { | m_clockTime += dt * m_timescale; | ||||
| double current_time = m_kxsystem->GetTimeInSeconds(); | |||||
| double dt = current_time - m_previousRealTime; | if (!m_fixedFramerate) { | ||||
| m_previousRealTime = current_time; | timestep = dt * m_timescale; | ||||
| // m_clockTime += dt; | |||||
| m_clockTime += dt * m_timescale; | |||||
| } | } | ||||
| } | } | ||||
| double deltatime = m_clockTime - m_frameTime; | double deltatime = m_clockTime - m_frameTime; | ||||
| if (deltatime<0.0) | if (deltatime < 0.0) { | ||||
| { | |||||
| // We got here too quickly, which means there is nothing to do, just return and don't render. | // We got here too quickly, which means there is nothing to do, just return and don't render. | ||||
| // Not sure if this is the best fix, but it seems to stop the jumping framerate issue (#33088) | // Not sure if this is the best fix, but it seems to stop the jumping framerate issue (#33088) | ||||
| return false; | return false; | ||||
| } | } | ||||
| // Compute the number of logic frames to do each update (fixed tic bricks) | // In case of non-fixed framerate, we always proceed one frame. | ||||
| int frames = int(deltatime * m_ticrate / m_timescale + 1e-6); | int frames = 1; | ||||
| // if (frames>1) | |||||
| // printf("****************************************"); | // Compute the number of logic frames to do each update in case of fixed framerate. | ||||
| // printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames); | if (m_fixedFramerate) { | ||||
| frames = int(deltatime * m_ticrate / m_timescale + 1e-6); | |||||
| // if (!frames) | } | ||||
| // PIL_sleep_ms(1); | |||||
| KX_SceneList::iterator sceneit; | // CM_Debug("dt = " << dt << ", deltatime = " << deltatime << ", frames = " << frames); | ||||
| if (frames>m_maxPhysicsFrame) | double framestep = timestep; | ||||
| { | |||||
| if (frames > m_maxPhysicsFrame) { | |||||
| // printf("framedOut: %d\n",frames); | m_frameTime += (frames - m_maxPhysicsFrame) * timestep; | ||||
| m_frameTime+=(frames-m_maxPhysicsFrame)*timestep; | |||||
| frames = m_maxPhysicsFrame; | frames = m_maxPhysicsFrame; | ||||
| } | } | ||||
| bool doRender = frames>0; | bool doRender = frames > 0; | ||||
| if (frames > m_maxLogicFrame) | if (frames > m_maxLogicFrame) { | ||||
| { | framestep = (frames * timestep) / m_maxLogicFrame; | ||||
| framestep = (frames*timestep)/m_maxLogicFrame; | |||||
| frames = m_maxLogicFrame; | frames = m_maxLogicFrame; | ||||
| } | } | ||||
| while (frames) | while (frames) { | ||||
| { | |||||
| m_frameTime += framestep; | m_frameTime += framestep; | ||||
| m_sceneconverter->MergeAsyncLoads(); | m_sceneconverter->MergeAsyncLoads(); | ||||
| for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) | if (m_inputDevice) { | ||||
| m_inputDevice->ReleaseMoveEvent(); | |||||
| } | |||||
| #ifdef WITH_SDL | |||||
| // Handle all SDL Joystick events here to share them for all scenes properly. | |||||
| short addrem[JOYINDEX_MAX] = {0}; | |||||
| if (DEV_Joystick::HandleEvents(addrem)) { | |||||
| # ifdef WITH_PYTHON | |||||
| updatePythonJoysticks(addrem); | |||||
| # endif // WITH_PYTHON | |||||
| } | |||||
| #endif // WITH_SDL | |||||
| // for each scene, call the proceed functions | // for each scene, call the proceed functions | ||||
| { | for (CListValue::iterator<KX_Scene> sceit = m_scenes->GetBegin(), sceend = m_scenes->GetEnd(); sceit != sceend; ++sceit) { | ||||
| KX_Scene* scene = *sceneit; | KX_Scene *scene = *sceit; | ||||
| /* Suspension holds the physics and logic processing for an | /* Suspension holds the physics and logic processing for an | ||||
| * entire scene. Objects can be suspended individually, and | * entire scene. Objects can be suspended individually, and | ||||
| * the settings for that precede the logic and physics | * the settings for that precede the logic and physics | ||||
| * update. */ | * update. */ | ||||
| m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); | ||||
| m_sceneconverter->resetNoneDynamicObjectToIpo(); // this is for none dynamic objects with ipo | |||||
| scene->UpdateObjectActivity(); | scene->UpdateObjectActivity(); | ||||
| if (!scene->IsSuspended()) | if (!scene->IsSuspended()) { | ||||
| { | |||||
| // if the scene was suspended recalculate 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); | m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_PHYSICS1); | SG_SetActiveStage(SG_STAGE_PHYSICS1); | ||||
| // set Python hooks for each scene | // set Python hooks for each scene | ||||
| Context not available. | |||||
| PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); | PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); | ||||
| #endif | #endif | ||||
| KX_SetActiveScene(scene); | KX_SetActiveScene(scene); | ||||
| scene->GetPhysicsEnvironment()->EndFrame(); | scene->GetPhysicsEnvironment()->EndFrame(); | ||||
| // Update scenegraph after physics step. This maps physics calculations | // Update scenegraph after physics step. This maps physics calculations | ||||
| // into node positions. | // into node positions. | ||||
| //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | ||||
| //SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE); | //SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE); | ||||
| //scene->UpdateParents(m_frameTime); | //scene->UpdateParents(m_frameTime); | ||||
| // Process sensors, and controllers | // Process sensors, and controllers | ||||
| m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_CONTROLLER); | SG_SetActiveStage(SG_STAGE_CONTROLLER); | ||||
| scene->LogicBeginFrame(m_frameTime); | scene->LogicBeginFrame(m_frameTime, framestep); | ||||
| // Scenegraph needs to be updated again, because Logic Controllers | // Scenegraph needs to be updated again, because Logic Controllers | ||||
| // can affect the local matrices. | // can affect the local matrices. | ||||
| m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE); | SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE); | ||||
| scene->UpdateParents(m_frameTime); | scene->UpdateParents(m_frameTime); | ||||
| // Process actuators | // Process actuators | ||||
| // Do some cleanup work for this logic frame | // Do some cleanup work for this logic frame | ||||
| m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_ACTUATOR); | SG_SetActiveStage(SG_STAGE_ACTUATOR); | ||||
| scene->LogicUpdateFrame(m_frameTime, true); | scene->LogicUpdateFrame(m_frameTime, true); | ||||
| scene->LogicEndFrame(); | scene->LogicEndFrame(); | ||||
| // Actuators can affect the scenegraph | // Actuators can affect the scenegraph | ||||
| m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE); | SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE); | ||||
| scene->UpdateParents(m_frameTime); | scene->UpdateParents(m_frameTime); | ||||
| // update levels of detail | |||||
| scene->UpdateObjectLods(); | |||||
| m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_PHYSICS2); | SG_SetActiveStage(SG_STAGE_PHYSICS2); | ||||
| scene->GetPhysicsEnvironment()->BeginFrame(); | scene->GetPhysicsEnvironment()->BeginFrame(); | ||||
| // Perform physics calculations on the scene. This can involve | // Perform physics calculations on the scene. This can involve | ||||
| // many iterations of the physics solver. | // many iterations of the physics solver. | ||||
| scene->GetPhysicsEnvironment()->ProceedDeltaTime(m_frameTime,timestep,framestep);//m_deltatimerealDeltaTime); | scene->GetPhysicsEnvironment()->ProceedDeltaTime(m_frameTime, timestep, framestep);//m_deltatimerealDeltaTime); | ||||
| m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE); | SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE); | ||||
| scene->UpdateParents(m_frameTime); | 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); | m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); | ||||
| // invalidates the shadow buffer from previous render/ImageRender because the scene has changed | |||||
| scene->SetShadowDone(false); | |||||
| } | } | ||||
| m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true); | |||||
| SG_SetActiveStage(SG_STAGE_NETWORK); | |||||
| m_networkMessageManager->ClearMessages(); | |||||
| m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); | |||||
| // update system devices | // update system devices | ||||
| m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); | ||||
| if (m_keyboarddevice) | if (m_inputDevice) { | ||||
| m_keyboarddevice->NextFrame(); | m_inputDevice->ClearInputs(); | ||||
| } | |||||
| if (m_mousedevice) | |||||
| m_mousedevice->NextFrame(); | |||||
| if (m_networkdevice) | |||||
| m_networkdevice->NextFrame(); | |||||
| UpdateSuspendedScenes(); | |||||
| // scene management | // scene management | ||||
| ProcessScheduledScenes(); | ProcessScheduledScenes(); | ||||
| frames--; | frames--; | ||||
| } | } | ||||
| // Start logging time spent outside main loop | // Start logging time spent outside main loop | ||||
| m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true); | ||||
| return doRender && m_doRender; | return doRender && m_doRender; | ||||
| } | } | ||||
| void KX_KetsjiEngine::UpdateSuspendedScenes() | |||||
| { | |||||
| for (CListValue::iterator<KX_Scene> sceneit = m_scenes->GetBegin(), sceneend = m_scenes->GetEnd(); sceneit != sceneend; ++sceneit) { | |||||
| KX_Scene *scene = *sceneit; | |||||
| if (scene->IsSuspended()) { | |||||
| if (scene->getSuspendedTime() == 0.0f) { | |||||
| scene->setSuspendedTime(m_clockTime); | |||||
| } | |||||
| } | |||||
| else { | |||||
| // if the scene was suspended recalcutlate the delta to "curtime" | |||||
| if (scene->getSuspendedTime() != 0.0f) { | |||||
| scene->setSuspendedDelta(scene->getSuspendedDelta() + m_clockTime - scene->getSuspendedTime()); | |||||
| } | |||||
| scene->setSuspendedTime(0.0f); | |||||
| } | |||||
| } | |||||
| } | |||||
| void KX_KetsjiEngine::Render() | void KX_KetsjiEngine::Render() | ||||
| { | { | ||||
| if (m_usedome) { | KX_Scene *firstscene = (KX_Scene *)m_scenes->GetFront(); | ||||
| RenderDome(); | |||||
| return; | |||||
| } | |||||
| KX_Scene* firstscene = *m_scenes.begin(); | |||||
| const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); | const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); | ||||
| const int width = m_canvas->GetWidth(); | |||||
| const int height = m_canvas->GetHeight(); | |||||
| m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_RENDER); | SG_SetActiveStage(SG_STAGE_RENDER); | ||||
| Context not available. | |||||
| if (m_hideCursor) | if (m_hideCursor) | ||||
| m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); | m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); | ||||
| BeginFrame(); | |||||
| for (CListValue::iterator<KX_Scene> sceit = m_scenes->GetBegin(), sceend = m_scenes->GetEnd(); sceit != sceend; ++sceit) { | |||||
| KX_Scene *scene = *sceit; | |||||
| // shadow buffers | |||||
| RenderShadowBuffers(scene); | |||||
| // cubemaps | |||||
| scene->RenderCubeMaps(m_rasterizer); | |||||
| } | |||||
| // Update all off screen to the current canvas size. | |||||
| m_rasterizer->UpdateOffScreens(m_canvas); | |||||
| // Bind render off screen as default. | |||||
| m_rasterizer->BindOffScreen(RAS_IRasterizer::RAS_OFFSCREEN_RENDER); | |||||
| // clear the entire game screen with the border color | // clear the entire game screen with the border color | ||||
| // only once per frame | // only once per frame | ||||
| m_canvas->BeginDraw(); | m_rasterizer->SetViewport(0, 0, width + 1, height + 1); | ||||
| if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { | m_rasterizer->SetScissor(0, 0, width + 1, height + 1); | ||||
| m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); | if (m_overrideFrameColor) { | ||||
| if (m_overrideFrameColor) | // Do not use the framing bar color set in the Blender scenes | ||||
| { | m_rasterizer->SetClearColor( | ||||
| // Do not use the framing bar color set in the Blender scenes | m_overrideFrameColorR, | ||||
| m_canvas->ClearColor( | m_overrideFrameColorG, | ||||
| m_overrideFrameColorR, | m_overrideFrameColorB, | ||||
| m_overrideFrameColorG, | m_overrideFrameColorA | ||||
| m_overrideFrameColorB, | ); | ||||
| m_overrideFrameColorA | } | ||||
| ); | else { | ||||
| } | // Use the framing bar color set in the Blender scenes | ||||
| else | m_rasterizer->SetClearColor( | ||||
| { | framesettings.BarRed(), | ||||
| // Use the framing bar color set in the Blender scenes | framesettings.BarGreen(), | ||||
| m_canvas->ClearColor( | framesettings.BarBlue(), | ||||
| framesettings.BarRed(), | 1.0f); | ||||
| framesettings.BarGreen(), | |||||
| framesettings.BarBlue(), | |||||
| 1.0 | |||||
| ); | |||||
| } | |||||
| // clear the -whole- viewport | |||||
| m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); | |||||
| } | } | ||||
| // clear the -whole- viewport | |||||
| m_rasterizer->Clear(RAS_IRasterizer::RAS_COLOR_BUFFER_BIT | RAS_IRasterizer::RAS_DEPTH_BUFFER_BIT); | |||||
| m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE); | const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); | ||||
| // Set to true when each eye needs to be rendered in a separated off screen. | |||||
| const bool renderpereye = stereomode == RAS_IRasterizer::RAS_STEREO_INTERLACED || | |||||
| stereomode == RAS_IRasterizer::RAS_STEREO_VINTERLACE || | |||||
| stereomode == RAS_IRasterizer::RAS_STEREO_ANAGLYPH; | |||||
| // BeginFrame() sets the actual drawing area. You can use a part of the window | const unsigned short numeyepass = (stereomode != RAS_IRasterizer::RAS_STEREO_NOSTEREO) ? 2 : 1; | ||||
| if (!BeginFrame()) | |||||
| return; | // The current bound eye off screen if we are using per eye stereo. | ||||
| int eyefboindex[2] = {RAS_IRasterizer::RAS_OFFSCREEN_EYE_LEFT0, RAS_IRasterizer::RAS_OFFSCREEN_EYE_RIGHT0}; | |||||
| // Used to detect when a camera is the first rendered an then doesn't request a depth clear. | |||||
| unsigned short pass = 0; | |||||
| KX_SceneList::iterator sceneit; | |||||
| for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) | |||||
| // for each scene, call the proceed functions | // for each scene, call the proceed functions | ||||
| { | for (CListValue::iterator<KX_Scene> sceit = m_scenes->GetBegin(), sceend = m_scenes->GetEnd(); sceit != sceend; ++sceit) { | ||||
| KX_Scene* scene = *sceneit; | KX_Scene *scene = *sceit; | ||||
| KX_Camera* cam = scene->GetActiveCamera(); | KX_Camera *activecam = scene->GetActiveCamera(); | ||||
| // pass the scene's worldsettings to the rasterizer | CListValue *cameras = scene->GetCameraList(); | ||||
| scene->GetWorldInfo()->UpdateWorldSettings(); | |||||
| // this is now done incrementally in KX_Scene::CalculateVisibleMeshes | const bool firstscene = (scene == m_scenes->GetFront()); | ||||
| //scene->UpdateMeshTransformations(); | const bool lastscene = (scene == m_scenes->GetBack()); | ||||
| // shadow buffers | // pass the scene's worldsettings to the rasterizer | ||||
| RenderShadowBuffers(scene); | scene->GetWorldInfo()->UpdateWorldSettings(m_rasterizer); | ||||
| // Avoid drawing the scene with the active camera twice when its viewport is enabled | m_rasterizer->SetAuxilaryClientInfo(scene); | ||||
| if (cam && !cam->GetViewport()) | |||||
| { | |||||
| if (scene->IsClearingZBuffer()) | |||||
| m_rasterizer->ClearDepthBuffer(); | |||||
| m_rasterizer->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_rasterizer->SetAuxilaryClientInfo(scene); | |||||
| // do the rendering | |||||
| RenderFrame(scene, (*it)); | |||||
| } | |||||
| it++; | |||||
| } | |||||
| PostRenderScene(scene); | |||||
| } | |||||
| // only one place that checks for stereo | for (unsigned short eyepass = 0; eyepass < numeyepass; ++eyepass) { | ||||
| if (m_rasterizer->Stereo()) | m_rasterizer->SetEye((eyepass == 0) ? RAS_IRasterizer::RAS_STEREO_LEFTEYE : RAS_IRasterizer::RAS_STEREO_RIGHTEYE); | ||||
| { | // set the area used for rendering (stereo can assign only a subset) | ||||
| m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_RIGHTEYE); | m_rasterizer->SetRenderArea(m_canvas); | ||||
| if (!BeginFrame()) | // Choose unique off screen per eyes in case of stereo. | ||||
| return; | if (renderpereye) { | ||||
| m_rasterizer->BindOffScreen(eyefboindex[eyepass]); | |||||
| // Clear eye off screen only before the first scene render. | |||||
| if (firstscene) { | |||||
| m_rasterizer->Clear(RAS_IRasterizer::RAS_COLOR_BUFFER_BIT | RAS_IRasterizer::RAS_DEPTH_BUFFER_BIT); | |||||
| } | |||||
| } | |||||
| // Avoid drawing the scene with the active camera twice when its viewport is enabled | |||||
| if (activecam && !activecam->GetViewport()) { | |||||
| // do the rendering | |||||
| RenderFrame(scene, activecam, pass++); | |||||
| } | |||||
| for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) | // Draw the scene once for each camera with an enabled viewport | ||||
| // for each scene, call the proceed functions | for (CListValue::iterator<KX_Camera> it = cameras->GetBegin(), end = cameras->GetEnd(); it != end; ++it) { | ||||
| { | KX_Camera *cam = *it; | ||||
| KX_Scene* scene = *sceneit; | if (cam->GetViewport()) { | ||||
| KX_Camera* cam = scene->GetActiveCamera(); | // do the rendering | ||||
| RenderFrame(scene, cam, pass++); | |||||
| } | |||||
| } | |||||
| // pass the scene's worldsettings to the rasterizer | // Process filters per eye off screen. | ||||
| scene->GetWorldInfo()->UpdateWorldSettings(); | if (renderpereye) { | ||||
| int target; | |||||
| if (scene->IsClearingZBuffer()) | if (m_rasterizer->GetOffScreenSamples(eyefboindex[eyepass]) > 0) { | ||||
| m_rasterizer->ClearDepthBuffer(); | /* Only RAS_OFFSCREEN_EYE_[LEFT/RIGHT]0 has possible multisamples so we target | ||||
| * RAS_OFFSCREEN_EYE_[LEFT/RIGHT]1 if it's the last scene. */ | |||||
| if (lastscene) { | |||||
| target = RAS_IRasterizer::NextEyeOffScreen(eyefboindex[eyepass]); | |||||
| } | |||||
| /* In case of multisamples and filters we're sure that a blit to RAS_OFFSCREEN_FILTER0 | |||||
| * will be done so we can target the same off screen than in input of the filter prossesing. */ | |||||
| else { | |||||
| target = eyefboindex[eyepass]; | |||||
| } | |||||
| } | |||||
| else { | |||||
| target = RAS_IRasterizer::NextEyeOffScreen(eyefboindex[eyepass]); | |||||
| } | |||||
| // pass the scene, for picking and raycasting (shadows) | PostRenderScene(scene, target); | ||||
| m_rasterizer->SetAuxilaryClientInfo(scene); | |||||
| // do the rendering | // If no filter was rendered the current used off screen can be unchanged. | ||||
| //RenderFrame(scene); | eyefboindex[eyepass] = m_rasterizer->GetCurrentOffScreenIndex(); | ||||
| RenderFrame(scene, cam); | } | ||||
| } | |||||
| list<class KX_Camera*>* cameras = scene->GetCameras(); | // Process filters for non-per eye off screen render. | ||||
| if (!renderpereye) { | |||||
| // Draw the scene once for each camera with an enabled viewport | /* Choose final render off screen target. If the current off screen is using multisamples we | ||||
| list<KX_Camera*>::iterator it = cameras->begin(); | * are sure that it will be copied to a non-multisamples off screen before render the filters. | ||||
| while (it != cameras->end()) { | * In this case the targeted off screen is the same as the current off screen. */ | ||||
| if ((*it)->GetViewport()) | int target; | ||||
| { | const short fboindex = m_rasterizer->GetCurrentOffScreenIndex(); | ||||
| if (scene->IsClearingZBuffer()) | if (m_rasterizer->GetOffScreenSamples(fboindex) > 0) { | ||||
| m_rasterizer->ClearDepthBuffer(); | /* If the last scene is rendered it's useless to specify a multisamples off screen, we use then | ||||
| * RAS_OFFSCREEN_FINAL and avoid an extra off screen blit. */ | |||||
| m_rasterizer->SetAuxilaryClientInfo(scene); | if (lastscene) { | ||||
| // Equivalent to RAS_IRasterizer::NextRenderOffScreen(fboindex). | |||||
| // do the rendering | target = RAS_IRasterizer::RAS_OFFSCREEN_FINAL; | ||||
| RenderFrame(scene, (*it)); | |||||
| } | } | ||||
| else { | |||||
| it++; | target = fboindex; | ||||
| } | |||||
| } | |||||
| /* In case of non-multisamples a ping pong per scene render is made between RAS_OFFSCREEN_RENDER | |||||
| * and RAS_OFFSCREEN_FINAL. */ | |||||
| else { | |||||
| target = RAS_IRasterizer::NextRenderOffScreen(fboindex); | |||||
| } | } | ||||
| PostRenderScene(scene); | |||||
| PostRenderScene(scene, target); | |||||
| } | } | ||||
| } // if (m_rasterizer->Stereo()) | } | ||||
| EndFrame(); | m_canvas->SetViewPort(0, 0, width, height); | ||||
| } | |||||
| // Compositing per eye off screens to screen. | |||||
| if (renderpereye) { | |||||
| m_rasterizer->DrawStereoOffScreen(m_canvas, eyefboindex[RAS_IRasterizer::RAS_STEREO_LEFTEYE], eyefboindex[RAS_IRasterizer::RAS_STEREO_RIGHTEYE]); | |||||
| } | |||||
| // Else simply draw the off screen to screen. | |||||
| else { | |||||
| const short fboindex = m_rasterizer->GetCurrentOffScreenIndex(); | |||||
| m_rasterizer->DrawOffScreen(m_canvas, fboindex); | |||||
| } | |||||
| EndFrame(); | |||||
| } | |||||
| void KX_KetsjiEngine::RequestExit(int exitrequestmode) | void KX_KetsjiEngine::RequestExit(int exitrequestmode) | ||||
| { | { | ||||
| m_exitcode = exitrequestmode; | m_exitcode = exitrequestmode; | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetNameNextGame(const std::string& nextgame) | |||||
| void KX_KetsjiEngine::SetNameNextGame(const STR_String& nextgame) | |||||
| { | { | ||||
| m_exitstring = nextgame; | m_exitstring = nextgame; | ||||
| } | } | ||||
| int KX_KetsjiEngine::GetExitCode() | int KX_KetsjiEngine::GetExitCode() | ||||
| { | { | ||||
| // if a game actuator has set an exit code or if there are no scenes left | // if a game actuator has set an exit code or if there are no scenes left | ||||
| if (!m_exitcode) | if (!m_exitcode) { | ||||
| { | if (m_scenes->GetCount() == 0) | ||||
| if (m_scenes.begin() == m_scenes.end()) | |||||
| m_exitcode = KX_EXIT_REQUEST_NO_SCENES_LEFT; | 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; | return m_exitcode; | ||||
| } | } | ||||
| const std::string& KX_KetsjiEngine::GetExitString() | |||||
| const STR_String& KX_KetsjiEngine::GetExitString() | |||||
| { | { | ||||
| return m_exitstring; | return m_exitstring; | ||||
| } | } | ||||
| void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene) | void KX_KetsjiEngine::EnableCameraOverride(const std::string& forscene) | ||||
| { | { | ||||
| m_overrideCam = true; | m_overrideCam = true; | ||||
| m_overrideSceneName = forscene; | m_overrideSceneName = forscene; | ||||
| Context not available. | |||||
| m_overrideCamZoom = camzoom; | m_overrideCamZoom = camzoom; | ||||
| } | } | ||||
| void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport) | 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 up-to-date. | // In this function we make sure the rasterizer settings are up-to-date. | ||||
| // We compute the viewport so that logic using this information is up-to-date. | // We compute the viewport so that logic using this information is up-to-date. | ||||
| Context not available. | |||||
| if (cam->GetViewport()) { | if (cam->GetViewport()) { | ||||
| RAS_Rect userviewport; | RAS_Rect userviewport; | ||||
| userviewport.SetLeft(cam->GetViewportLeft()); | userviewport.SetLeft(cam->GetViewportLeft()); | ||||
| userviewport.SetBottom(cam->GetViewportBottom()); | userviewport.SetBottom(cam->GetViewportBottom()); | ||||
| userviewport.SetRight(cam->GetViewportRight()); | userviewport.SetRight(cam->GetViewportRight()); | ||||
| userviewport.SetTop(cam->GetViewportTop()); | userviewport.SetTop(cam->GetViewportTop()); | ||||
| Context not available. | |||||
| settings.SetFrameType(RAS_FrameSettings::e_frame_extend); | settings.SetFrameType(RAS_FrameSettings::e_frame_extend); | ||||
| RAS_FramingManager::ComputeViewport( | RAS_FramingManager::ComputeViewport( | ||||
| scene->GetFramingType(), | scene->GetFramingType(), | ||||
| userviewport, | userviewport, | ||||
| viewport | viewport | ||||
| ); | ); | ||||
| area = userviewport; | area = userviewport; | ||||
| } | } | ||||
| else if ( !m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) { | else if (!m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho) { | ||||
| RAS_FramingManager::ComputeViewport( | RAS_FramingManager::ComputeViewport( | ||||
| scene->GetFramingType(), | scene->GetFramingType(), | ||||
| m_canvas->GetDisplayArea(), | m_canvas->GetDisplayArea(), | ||||
| viewport | viewport); | ||||
| ); | |||||
| area = m_canvas->GetDisplayArea(); | area = m_canvas->GetDisplayArea(); | ||||
| } else { | } | ||||
| viewport.SetLeft(0); | else { | ||||
| viewport.SetLeft(0); | |||||
| viewport.SetBottom(0); | viewport.SetBottom(0); | ||||
| viewport.SetRight(int(m_canvas->GetWidth())); | viewport.SetRight(int(m_canvas->GetWidth())); | ||||
| viewport.SetTop(int(m_canvas->GetHeight())); | viewport.SetTop(int(m_canvas->GetHeight())); | ||||
| Context not available. | |||||
| return; | return; | ||||
| } | } | ||||
| // Set scene total pause duration, used for animations played on scene which was suspended. | |||||
| m_suspendeddelta = scene->getSuspendedDelta(); | |||||
| // Handle the animations independently of the logic time step | // Handle the animations independently of the logic time step | ||||
| if (GetRestrictAnimationFPS()) { | if (GetRestrictAnimationFPS()) { | ||||
| double anim_timestep = 1.0 / KX_GetActiveScene()->GetAnimationFPS(); | double anim_timestep = 1.0 / scene->GetAnimationFPS(); | ||||
| if (m_frameTime - m_previousAnimTime > anim_timestep || m_frameTime == m_previousAnimTime) { | if (m_frameTime - m_previousAnimTime > anim_timestep || m_frameTime == m_previousAnimTime) { | ||||
| // Sanity/debug print to make sure we're actually going at the fps we want (should be close to 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_frameTime - m_previousAnimTime)); | // CM_Debug("Anim fps: " << 1.0/(m_frameTime - m_previousAnimTime)); | ||||
| m_previousAnimTime = m_frameTime; | m_previousAnimTime = m_frameTime; | ||||
| for (KX_SceneList::iterator sceneit = m_scenes.begin(); sceneit != m_scenes.end(); ++sceneit) | for (CListValue::iterator<KX_Scene> sceneit = m_scenes->GetBegin(), sceneend = m_scenes->GetEnd(); sceneit != sceneend; ++sceneit) | ||||
| (*sceneit)->UpdateAnimations(m_frameTime); | (*sceneit)->UpdateAnimations(m_frameTime); | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) | void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) | ||||
| { | { | ||||
| CListValue *lightlist = scene->GetLightList(); | CListValue *lightlist = scene->GetLightList(); | ||||
| int i, drawmode; | |||||
| m_rasterizer->SetAuxilaryClientInfo(scene); | m_rasterizer->SetAuxilaryClientInfo(scene); | ||||
| for (i=0; i<lightlist->GetCount(); i++) { | for (CListValue::iterator<KX_LightObject> it = lightlist->GetBegin(), end = lightlist->GetEnd(); it != end; ++it) { | ||||
| KX_GameObject *gameobj = (KX_GameObject*)lightlist->GetValue(i); | KX_LightObject *light = *it; | ||||
| KX_LightObject *light = (KX_LightObject*)gameobj; | |||||
| RAS_ILightObject *raslight = light->GetLightData(); | RAS_ILightObject *raslight = light->GetLightData(); | ||||
| raslight->Update(); | raslight->Update(); | ||||
| if (light->GetVisible() && m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED && | if (light->GetVisible() && m_rasterizer->GetDrawingMode() == RAS_IRasterizer::RAS_TEXTURED && | ||||
| raslight->HasShadowBuffer()) | raslight->HasShadowBuffer() && raslight->NeedShadowUpdate()) | ||||
| { | { | ||||
| /* make temporary camera */ | /* make temporary camera */ | ||||
| RAS_CameraData camdata = RAS_CameraData(); | RAS_CameraData camdata = RAS_CameraData(); | ||||
| Context not available. | |||||
| MT_Transform camtrans; | MT_Transform camtrans; | ||||
| /* switch drawmode for speed */ | /* switch drawmode for speed */ | ||||
| drawmode = m_rasterizer->GetDrawingMode(); | RAS_IRasterizer::DrawType drawmode = m_rasterizer->GetDrawingMode(); | ||||
| m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW); | m_rasterizer->SetDrawingMode(RAS_IRasterizer::RAS_SHADOW); | ||||
| /* binds framebuffer object, sets up camera .. */ | /* binds framebuffer object, sets up camera .. */ | ||||
| raslight->BindShadowBuffer(m_canvas, cam, camtrans); | raslight->BindShadowBuffer(m_canvas, cam, camtrans); | ||||
| Context not available. | |||||
| SG_SetActiveStage(SG_STAGE_RENDER); | SG_SetActiveStage(SG_STAGE_RENDER); | ||||
| /* render */ | /* render */ | ||||
| m_rasterizer->ClearDepthBuffer(); | m_rasterizer->Clear(RAS_IRasterizer::RAS_DEPTH_BUFFER_BIT | RAS_IRasterizer::RAS_COLOR_BUFFER_BIT); | ||||
| m_rasterizer->ClearColorBuffer(); | |||||
| scene->RenderBuckets(camtrans, m_rasterizer); | scene->RenderBuckets(camtrans, m_rasterizer); | ||||
| /* unbind framebuffer object, restore drawmode, free camera */ | /* unbind framebuffer object, restore drawmode, free camera */ | ||||
| Context not available. | |||||
| cam->Release(); | cam->Release(); | ||||
| } | } | ||||
| } | } | ||||
| /* remember that we have a valid shadow buffer for that scene */ | |||||
| scene->SetShadowDone(true); | |||||
| } | } | ||||
| // update graphics | // update graphics | ||||
| void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) | void KX_KetsjiEngine::RenderFrame(KX_Scene *scene, KX_Camera *cam, unsigned short pass) | ||||
| { | { | ||||
| bool override_camera; | bool override_camera; | ||||
| RAS_Rect viewport, area; | RAS_Rect viewport, area; | ||||
| float nearfrust, farfrust, focallength; | float nearfrust, farfrust, focallength; | ||||
| // KX_Camera* cam = scene->GetActiveCamera(); | |||||
| if (!cam) | if (!cam) | ||||
| return; | return; | ||||
| bool isfirstscene = (scene == m_scenes->GetFront()); | |||||
| KX_SetActiveScene(scene); | KX_SetActiveScene(scene); | ||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| scene->RunDrawingCallbacks(scene->GetPreDrawSetupCB()); | scene->RunDrawingCallbacks(KX_Scene::PRE_DRAW_SETUP, cam); | ||||
| #endif | #endif | ||||
| GetSceneViewport(scene, cam, area, viewport); | GetSceneViewport(scene, cam, area, viewport); | ||||
| // store the computed viewport in the scene | |||||
| scene->SetSceneViewport(viewport); | |||||
| // set the viewport for this frame and scene | // set the viewport for this frame and scene | ||||
| m_canvas->SetViewPort(viewport.GetLeft(), viewport.GetBottom(), | const int left = viewport.GetLeft(); | ||||
| viewport.GetRight(), viewport.GetTop()); | const int bottom = viewport.GetBottom(); | ||||
| const int width = viewport.GetWidth(); | |||||
| const int height = viewport.GetHeight(); | |||||
| m_rasterizer->SetViewport(left, bottom, width + 1, height + 1); | |||||
| m_rasterizer->SetScissor(left, bottom, width + 1, height + 1); | |||||
| /* Clear the depth after setting the scene viewport/scissor | |||||
| * if it's not the first render pass. */ | |||||
| if (pass > 0) { | |||||
| m_rasterizer->Clear(RAS_IRasterizer::RAS_DEPTH_BUFFER_BIT); | |||||
| } | |||||
| // see KX_BlenderMaterial::Activate | // see KX_BlenderMaterial::Activate | ||||
| //m_rasterizer->SetAmbient(); | //m_rasterizer->SetAmbient(); | ||||
| m_rasterizer->DisplayFog(); | m_rasterizer->DisplayFog(); | ||||
| override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName); | override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName) && | ||||
| override_camera = override_camera && (cam->GetName() == "__default__cam__"); | (cam->GetName() == "__default__cam__"); | ||||
| if (override_camera && m_overrideCamUseOrtho) { | if (override_camera && m_overrideCamUseOrtho) { | ||||
| m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat); | m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat); | ||||
| Context not available. | |||||
| projmat.setValue(m_overrideCamProjMat.getPointer()); | projmat.setValue(m_overrideCamProjMat.getPointer()); | ||||
| cam->SetProjectionMatrix(projmat); | cam->SetProjectionMatrix(projmat); | ||||
| } | } | ||||
| } else if (cam->hasValidProjectionMatrix()) | } | ||||
| { | else if (cam->hasValidProjectionMatrix()) { | ||||
| m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); | m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); | ||||
| } else | } | ||||
| { | else { | ||||
| RAS_FrameFrustum frustum; | RAS_FrameFrustum frustum; | ||||
| bool orthographic = !cam->GetCameraData()->m_perspective; | bool orthographic = !cam->GetCameraData()->m_perspective; | ||||
| nearfrust = cam->GetCameraNear(); | nearfrust = cam->GetCameraNear(); | ||||
| Context not available. | |||||
| if (orthographic) { | if (orthographic) { | ||||
| RAS_FramingManager::ComputeOrtho( | RAS_FramingManager::ComputeOrtho( | ||||
| scene->GetFramingType(), | scene->GetFramingType(), | ||||
| area, | area, | ||||
| viewport, | viewport, | ||||
| cam->GetScale(), | cam->GetScale(), | ||||
| nearfrust, | nearfrust, | ||||
| farfrust, | farfrust, | ||||
| cam->GetSensorFit(), | cam->GetSensorFit(), | ||||
| cam->GetShiftHorizontal(), | cam->GetShiftHorizontal(), | ||||
| cam->GetShiftVertical(), | cam->GetShiftVertical(), | ||||
| frustum | frustum); | ||||
| ); | |||||
| if (!cam->GetViewport()) { | if (!cam->GetViewport()) { | ||||
| frustum.x1 *= camzoom; | frustum.x1 *= camzoom; | ||||
| frustum.x2 *= camzoom; | frustum.x2 *= camzoom; | ||||
| Context not available. | |||||
| frustum.y2 *= camzoom; | frustum.y2 *= camzoom; | ||||
| } | } | ||||
| projmat = m_rasterizer->GetOrthoMatrix( | projmat = m_rasterizer->GetOrthoMatrix( | ||||
| frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); | frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); | ||||
| } else { | } | ||||
| else { | |||||
| RAS_FramingManager::ComputeFrustum( | RAS_FramingManager::ComputeFrustum( | ||||
| scene->GetFramingType(), | scene->GetFramingType(), | ||||
| area, | area, | ||||
| viewport, | viewport, | ||||
| cam->GetLens(), | cam->GetLens(), | ||||
| cam->GetSensorWidth(), | cam->GetSensorWidth(), | ||||
| cam->GetSensorHeight(), | cam->GetSensorHeight(), | ||||
| cam->GetSensorFit(), | cam->GetSensorFit(), | ||||
| cam->GetShiftHorizontal(), | cam->GetShiftHorizontal(), | ||||
| cam->GetShiftVertical(), | cam->GetShiftVertical(), | ||||
| nearfrust, | nearfrust, | ||||
| farfrust, | farfrust, | ||||
| frustum | frustum); | ||||
| ); | |||||
| if (!cam->GetViewport()) { | if (!cam->GetViewport()) { | ||||
| frustum.x1 *= camzoom; | frustum.x1 *= camzoom; | ||||
| Context not available. | |||||
| frustum.y2 *= camzoom; | frustum.y2 *= camzoom; | ||||
| } | } | ||||
| projmat = m_rasterizer->GetFrustumMatrix( | projmat = m_rasterizer->GetFrustumMatrix( | ||||
| frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength); | frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength); | ||||
| } | } | ||||
| cam->SetProjectionMatrix(projmat); | cam->SetProjectionMatrix(projmat); | ||||
| // Otherwise the projection matrix for each eye will be the same... | // Otherwise the projection matrix for each eye will be the same... | ||||
| if (!orthographic && m_rasterizer->Stereo()) | if (!orthographic && m_rasterizer->Stereo()) | ||||
| cam->InvalidateProjectionMatrix(); | cam->InvalidateProjectionMatrix(); | ||||
| Context not available. | |||||
| MT_Transform camtrans(cam->GetWorldToCamera()); | MT_Transform camtrans(cam->GetWorldToCamera()); | ||||
| MT_Matrix4x4 viewmat(camtrans); | MT_Matrix4x4 viewmat(camtrans); | ||||
| m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective); | m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective); | ||||
| cam->SetModelviewMatrix(viewmat); | cam->SetModelviewMatrix(viewmat); | ||||
| if (isfirstscene) { | |||||
| KX_WorldInfo *worldInfo = scene->GetWorldInfo(); | |||||
| // Update background and render it. | |||||
| worldInfo->UpdateBackGround(m_rasterizer); | |||||
| worldInfo->RenderBackground(m_rasterizer); | |||||
| } | |||||
| // The following actually reschedules all vertices to be | // The following actually reschedules all vertices to be | ||||
| // redrawn. There is a cache between the actual rescheduling | // redrawn. There is a cache between the actual rescheduling | ||||
| // and this call though. Visibility is imparted when this call | // and this call though. Visibility is imparted when this call | ||||
| Context not available. | |||||
| m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_CULLING); | SG_SetActiveStage(SG_STAGE_CULLING); | ||||
| scene->CalculateVisibleMeshes(m_rasterizer,cam); | scene->CalculateVisibleMeshes(m_rasterizer, cam); | ||||
| // update levels of detail | |||||
| scene->UpdateObjectLods(cam); | |||||
| m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); | SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); | ||||
| Context not available. | |||||
| m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); | m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); | ||||
| SG_SetActiveStage(SG_STAGE_RENDER); | SG_SetActiveStage(SG_STAGE_RENDER); | ||||
| // Draw debug infos like bouding box, armature ect.. if enabled. | |||||
| scene->DrawDebug(m_rasterizer); | |||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); | PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); | ||||
| // Run any pre-drawing python callbacks | // Run any pre-drawing python callbacks | ||||
| scene->RunDrawingCallbacks(scene->GetPreDrawCB()); | scene->RunDrawingCallbacks(KX_Scene::PRE_DRAW, cam); | ||||
| #endif | #endif | ||||
| scene->RenderBuckets(camtrans, m_rasterizer); | scene->RenderBuckets(camtrans, m_rasterizer); | ||||
| // render all the font objects for this scene | |||||
| scene->RenderFonts(); | |||||
| if (scene->GetPhysicsEnvironment()) | if (scene->GetPhysicsEnvironment()) | ||||
| scene->GetPhysicsEnvironment()->DebugDrawWorld(); | scene->GetPhysicsEnvironment()->DebugDrawWorld(); | ||||
| } | } | ||||
| Context not available. | |||||
| /* | /* | ||||
| * To run once per scene | * To run once per scene | ||||
| */ | */ | ||||
| void KX_KetsjiEngine::PostRenderScene(KX_Scene* scene) | void KX_KetsjiEngine::PostRenderScene(KX_Scene *scene, unsigned short target) | ||||
| { | { | ||||
| KX_SetActiveScene(scene); | KX_SetActiveScene(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_rasterizer->FlushDebugShapes(scene); | m_rasterizer->FlushDebugShapes(scene); | ||||
| scene->Render2DFilters(m_canvas); | |||||
| // We need to first make sure our viewport is correct (enabling multiple viewports can mess this up), only for filters. | |||||
| const int width = m_canvas->GetWidth(); | |||||
| const int height = m_canvas->GetHeight(); | |||||
| m_rasterizer->SetViewport(0, 0, width + 1, height + 1); | |||||
| m_rasterizer->SetScissor(0, 0, width + 1, height + 1); | |||||
| scene->Render2DFilters(m_rasterizer, m_canvas, target); | |||||
| #ifdef WITH_PYTHON | #ifdef WITH_PYTHON | ||||
| PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); | PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); | ||||
| scene->RunDrawingCallbacks(scene->GetPostDrawCB()); | /* We can't deduce what camera should be passed to the python callbacks | ||||
| * because the post draw callbacks are per scenes and not per cameras. | |||||
| */ | |||||
| scene->RunDrawingCallbacks(KX_Scene::POST_DRAW, NULL); | |||||
| // Python draw callback can also call debug draw functions, so we have to clear debug shapes. | // Python draw callback can also call debug draw functions, so we have to clear debug shapes. | ||||
| m_rasterizer->FlushDebugShapes(scene); | m_rasterizer->FlushDebugShapes(scene); | ||||
| Context not available. | |||||
| void KX_KetsjiEngine::StopEngine() | void KX_KetsjiEngine::StopEngine() | ||||
| { | { | ||||
| if (m_bInitialized) | if (m_bInitialized) { | ||||
| { | |||||
| m_sceneconverter->FinalizeAsyncLoads(); | m_sceneconverter->FinalizeAsyncLoads(); | ||||
| if (m_animation_record) | while (m_scenes->GetCount() > 0) { | ||||
| { | KX_Scene *scene = (KX_Scene *)m_scenes->GetFront(); | ||||
| // 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_sceneconverter->RemoveScene(scene); | ||||
| // WARNING: here the scene is a dangling pointer. | |||||
| m_scenes->Remove(0); | |||||
| } | } | ||||
| m_scenes.clear(); | |||||
| // cleanup all the stuff | // cleanup all the stuff | ||||
| m_rasterizer->Exit(); | m_rasterizer->Exit(); | ||||
| Context not available. | |||||
| // Scene Management is able to switch between scenes | // Scene Management is able to switch between scenes | ||||
| // and have several scenes running in parallel | // and have several scenes running in parallel | ||||
| void KX_KetsjiEngine::AddScene(KX_Scene* scene) | void KX_KetsjiEngine::AddScene(KX_Scene *scene) | ||||
| { | { | ||||
| m_scenes.push_back(scene); | m_scenes->Add(scene->AddRef()); | ||||
| PostProcessScene(scene); | PostProcessScene(scene); | ||||
| } | } | ||||
| void KX_KetsjiEngine::PostProcessScene(KX_Scene *scene) | |||||
| void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene) | |||||
| { | { | ||||
| bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName)); | bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName)); | ||||
| Context not available. | |||||
| // if there is no activecamera, or the camera is being | // if there is no activecamera, or the camera is being | ||||
| // overridden we need to construct a temporary camera | // overridden we need to construct a temporary camera | ||||
| if (!scene->GetActiveCamera() || override_camera) | if (!scene->GetActiveCamera() || override_camera) { | ||||
| { | KX_Camera *activecam = NULL; | ||||
| KX_Camera* activecam = NULL; | |||||
| RAS_CameraData camdata = RAS_CameraData(); | RAS_CameraData camdata = RAS_CameraData(); | ||||
| if (override_camera) | if (override_camera) { | ||||
| { | |||||
| camdata.m_lens = m_overrideCamLens; | camdata.m_lens = m_overrideCamLens; | ||||
| camdata.m_clipstart = m_overrideCamNear; | camdata.m_clipstart = m_overrideCamNear; | ||||
| camdata.m_clipend = m_overrideCamFar; | camdata.m_clipend = m_overrideCamFar; | ||||
| camdata.m_perspective= !m_overrideCamUseOrtho; | camdata.m_perspective = !m_overrideCamUseOrtho; | ||||
| } | } | ||||
| activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata); | activecam = new KX_Camera(scene, KX_Scene::m_callbacks, camdata); | ||||
| activecam->SetName("__default__cam__"); | activecam->SetName("__default__cam__"); | ||||
| // set transformation | // set transformation | ||||
| if (override_camera) { | if (override_camera) { | ||||
| const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat; | const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat; | ||||
| MT_Transform trans = MT_Transform(cammatdata.getPointer()); | MT_Transform trans = MT_Transform(cammatdata.getPointer()); | ||||
| MT_Transform camtrans; | MT_Transform camtrans; | ||||
| camtrans.invert(trans); | camtrans.invert(trans); | ||||
| activecam->NodeSetLocalPosition(camtrans.getOrigin()); | activecam->NodeSetLocalPosition(camtrans.getOrigin()); | ||||
| activecam->NodeSetLocalOrientation(camtrans.getBasis()); | activecam->NodeSetLocalOrientation(camtrans.getBasis()); | ||||
| activecam->NodeUpdateGS(0); | activecam->NodeUpdateGS(0.0f); | ||||
| } else { | } | ||||
| activecam->NodeSetLocalPosition(MT_Point3(0.0f, 0.0f, 0.0f)); | else { | ||||
| activecam->NodeSetLocalOrientation(MT_Vector3(0.0f, 0.0f, 0.0f)); | activecam->NodeSetLocalPosition(MT_Vector3(0.0f, 0.0f, 0.0f)); | ||||
| activecam->NodeUpdateGS(0); | activecam->NodeSetLocalOrientation(MT_Matrix3x3(MT_Vector3(0.0f, 0.0f, 0.0f))); | ||||
| activecam->NodeUpdateGS(0.0f); | |||||
| } | } | ||||
| scene->AddCamera(activecam); | scene->GetCameraList()->Add(activecam->AddRef()); | ||||
| scene->SetActiveCamera(activecam); | scene->SetActiveCamera(activecam); | ||||
| scene->GetObjectList()->Add(activecam->AddRef()); | scene->GetObjectList()->Add(activecam->AddRef()); | ||||
| scene->GetRootParentList()->Add(activecam->AddRef()); | scene->GetRootParentList()->Add(activecam->AddRef()); | ||||
| // done with activecam | // done with activecam | ||||
| activecam->Release(); | activecam->Release(); | ||||
| } | } | ||||
| scene->UpdateParents(0.0); | |||||
| } | |||||
| scene->UpdateParents(0.0f); | |||||
| } | |||||
| void KX_KetsjiEngine::RenderDebugProperties() | void KX_KetsjiEngine::RenderDebugProperties() | ||||
| { | { | ||||
| STR_String debugtxt; | std::string debugtxt; | ||||
| int title_xmargin = -7; | int title_xmargin = -7; | ||||
| int title_y_top_margin = 4; | int title_y_top_margin = 4; | ||||
| int title_y_bottom_margin = 2; | int title_y_bottom_margin = 2; | ||||
| Context not available. | |||||
| int const_xindent = 4; | int const_xindent = 4; | ||||
| int const_ysize = 14; | int const_ysize = 14; | ||||
| int xcoord = 12; // mmmm, these constants were taken from blender source | int xcoord = 12; // mmmm, these constants were taken from blender source | ||||
| int ycoord = 17; // to 'mimic' behavior | int ycoord = 17; // to 'mimic' behavior | ||||
| int profile_indent = 72; | int profile_indent = 72; | ||||
| float tottime = m_logger->GetAverage(); | float tottime = m_logger->GetAverage(); | ||||
| Context not available. | |||||
| 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())); | |||||
| if (m_show_framerate || m_show_profile) { | if (m_show_framerate || m_show_profile) { | ||||
| /* Title for profiling("Profile") */ | // Title for profiling("Profile") | ||||
| m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | ||||
| "Profile", | "Profile", | ||||
| xcoord + const_xindent + title_xmargin, // Adds the constant x indent (0 for now) to the title x margin | xcoord + const_xindent + title_xmargin, // Adds the constant x indent (0 for now) to the title x margin | ||||
| ycoord, | ycoord, | ||||
| m_canvas->GetWidth() /* RdV, TODO ?? */, | m_canvas->GetWidth() /* RdV, TODO ?? */, | ||||
| m_canvas->GetHeight() /* RdV, TODO ?? */); | m_canvas->GetHeight() /* RdV, TODO ?? */); | ||||
| // Increase the indent by default increase | // Increase the indent by default increase | ||||
| ycoord += const_ysize; | ycoord += const_ysize; | ||||
| Context not available. | |||||
| ycoord += title_y_bottom_margin; | ycoord += title_y_bottom_margin; | ||||
| } | } | ||||
| /* Framerate display */ | // Framerate display | ||||
| if (m_show_framerate) { | if (m_show_framerate) { | ||||
| m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | ||||
| "Frametime :", | "Frametime :", | ||||
| xcoord + const_xindent, | xcoord + const_xindent, | ||||
| ycoord, | ycoord, | ||||
| m_canvas->GetWidth() /* RdV, TODO ?? */, | m_canvas->GetWidth() /* RdV, TODO ?? */, | ||||
| m_canvas->GetHeight() /* RdV, TODO ?? */); | m_canvas->GetHeight() /* RdV, TODO ?? */); | ||||
| debugtxt.Format("%5.1fms (%.1ffps)", tottime * 1000.0f, 1.0f/tottime); | debugtxt = (boost::format("%5.2fms (%.1ffps)") % (tottime * 1000.0f) % (1.0f / tottime)).str(); | ||||
| m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | ||||
| debugtxt.ReadPtr(), | debugtxt, | ||||
| xcoord + const_xindent + profile_indent, | xcoord + const_xindent + profile_indent, | ||||
| ycoord, | ycoord, | ||||
| m_canvas->GetWidth() /* RdV, TODO ?? */, | m_canvas->GetWidth() /* RdV, TODO ?? */, | ||||
| m_canvas->GetHeight() /* RdV, TODO ?? */); | m_canvas->GetHeight() /* RdV, TODO ?? */); | ||||
| // Increase the indent by default increase | // Increase the indent by default increase | ||||
| ycoord += const_ysize; | ycoord += const_ysize; | ||||
| } | } | ||||
| /* Profile display */ | // Profile display | ||||
| if (m_show_profile) { | if (m_show_profile) { | ||||
| for (int j = tc_first; j < tc_numCategories; j++) { | for (int j = tc_first; j < tc_numCategories; j++) { | ||||
| m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | ||||
| m_profileLabels[j], | m_profileLabels[j], | ||||
| xcoord + const_xindent, | xcoord + const_xindent, | ||||
| ycoord, | ycoord, | ||||
| m_canvas->GetWidth(), | m_canvas->GetWidth(), | ||||
| m_canvas->GetHeight()); | m_canvas->GetHeight()); | ||||
| double time = m_logger->GetAverage((KX_TimeCategory)j); | double time = m_logger->GetAverage((KX_TimeCategory)j); | ||||
| debugtxt.Format("%5.2fms | %d%%", (float)time*1000.f, (int)((float)time/tottime * 100.f)); | debugtxt = (boost::format("%5.2fms | %d%%") % (time*1000.f) % (int)(time/tottime * 100.f)).str(); | ||||
| m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | ||||
| debugtxt.ReadPtr(), | debugtxt, | ||||
| xcoord + const_xindent + profile_indent, ycoord, | xcoord + const_xindent + profile_indent, ycoord, | ||||
| m_canvas->GetWidth(), | m_canvas->GetWidth(), | ||||
| m_canvas->GetHeight()); | m_canvas->GetHeight()); | ||||
| m_rasterizer->RenderBox2D(xcoord + (int)(2.2f * profile_indent), ycoord, m_canvas->GetWidth(), m_canvas->GetHeight(), (float)time/tottime); | m_rasterizer->RenderBox2D(xcoord + (int)(2.2 * profile_indent), ycoord, m_canvas->GetWidth(), m_canvas->GetHeight(), time/tottime); | ||||
| ycoord += const_ysize; | ycoord += const_ysize; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| /* Title for debugging("Debug properties") */ | /* Title for debugging("Debug properties") */ | ||||
| m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | ||||
| "Debug Properties", | "Debug Properties", | ||||
| xcoord + const_xindent + title_xmargin, // Adds the constant x indent (0 for now) to the title x margin | xcoord + const_xindent + title_xmargin, // Adds the constant x indent (0 for now) to the title x margin | ||||
| ycoord, | ycoord, | ||||
| m_canvas->GetWidth() /* RdV, TODO ?? */, | m_canvas->GetWidth() /* RdV, TODO ?? */, | ||||
| m_canvas->GetHeight() /* RdV, TODO ?? */); | m_canvas->GetHeight() /* RdV, TODO ?? */); | ||||
| // Increase the indent by default increase | // Increase the indent by default increase | ||||
| ycoord += const_ysize; | ycoord += const_ysize; | ||||
| Context not available. | |||||
| unsigned propsAct = 0; | unsigned propsAct = 0; | ||||
| unsigned propsMax = (m_canvas->GetHeight() - ycoord) / const_ysize; | unsigned propsMax = (m_canvas->GetHeight() - ycoord) / const_ysize; | ||||
| KX_SceneList::iterator sceneit; | for (CListValue::iterator<KX_Scene> sceit = m_scenes->GetBegin(), sceend = m_scenes->GetEnd(); sceit != sceend; ++sceit) { | ||||
| for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) { | KX_Scene *scene = *sceit; | ||||
| KX_Scene* scene = *sceneit; | |||||
| /* the 'normal' debug props */ | /* the 'normal' debug props */ | ||||
| vector<SCA_DebugProp*>& debugproplist = scene->GetDebugProperties(); | std::vector<SCA_DebugProp *>& debugproplist = scene->GetDebugProperties(); | ||||
| for (unsigned i=0; i < debugproplist.size() && propsAct < propsMax; i++) | for (unsigned i = 0; i < debugproplist.size() && propsAct < propsMax; i++) { | ||||
| { | |||||
| CValue *propobj = debugproplist[i]->m_obj; | CValue *propobj = debugproplist[i]->m_obj; | ||||
| STR_String objname = propobj->GetName(); | std::string objname = propobj->GetName(); | ||||
| STR_String propname = debugproplist[i]->m_name; | std::string propname = debugproplist[i]->m_name; | ||||
| propsAct++; | propsAct++; | ||||
| if (propname == "__state__") { | if (propname == "__state__") { | ||||
| // reserve name for object state | // reserve name for object state | ||||
| KX_GameObject* gameobj = static_cast<KX_GameObject*>(propobj); | KX_GameObject *gameobj = static_cast<KX_GameObject *>(propobj); | ||||
| unsigned int state = gameobj->GetState(); | unsigned int state = gameobj->GetState(); | ||||
| debugtxt = objname + "." + propname + " = "; | debugtxt = objname + "." + propname + " = "; | ||||
| bool first = true; | bool first = true; | ||||
| for (int statenum=1;state;state >>= 1, statenum++) | for (int statenum = 1; state; state >>= 1, statenum++) { | ||||
| { | if (state & 1) { | ||||
| if (state & 1) | if (!first) { | ||||
| { | |||||
| if (!first) | |||||
| { | |||||
| debugtxt += ","; | debugtxt += ","; | ||||
| } | } | ||||
| debugtxt += STR_String(statenum); | debugtxt += std::to_string(statenum); | ||||
| first = false; | first = false; | ||||
| } | } | ||||
| } | } | ||||
| m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | ||||
| debugtxt.ReadPtr(), | debugtxt, | ||||
| xcoord + const_xindent, | xcoord + const_xindent, | ||||
| ycoord, | ycoord, | ||||
| m_canvas->GetWidth(), | m_canvas->GetWidth(), | ||||
| m_canvas->GetHeight()); | m_canvas->GetHeight()); | ||||
| ycoord += const_ysize; | ycoord += const_ysize; | ||||
| } | } | ||||
| else { | else { | ||||
| CValue *propval = propobj->GetProperty(propname); | CValue *propval = propobj->GetProperty(propname); | ||||
| if (propval) { | if (propval) { | ||||
| STR_String text = propval->GetText(); | std::string text = propval->GetText(); | ||||
| debugtxt = objname + ": '" + propname + "' = " + text; | debugtxt = objname + ": '" + propname + "' = " + text; | ||||
| m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, | ||||
| debugtxt.ReadPtr(), | debugtxt, | ||||
| xcoord + const_xindent, | xcoord + const_xindent, | ||||
| ycoord, | ycoord, | ||||
| m_canvas->GetWidth(), | m_canvas->GetWidth(), | ||||
| m_canvas->GetHeight()); | m_canvas->GetHeight()); | ||||
| ycoord += const_ysize; | ycoord += const_ysize; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| CListValue *KX_KetsjiEngine::CurrentScenes() | |||||
| KX_SceneList* KX_KetsjiEngine::CurrentScenes() | |||||
| { | { | ||||
| return &m_scenes; | return m_scenes; | ||||
| } | } | ||||
| KX_Scene *KX_KetsjiEngine::FindScene(const std::string& scenename) | |||||
| KX_Scene* KX_KetsjiEngine::FindScene(const STR_String& scenename) | |||||
| { | { | ||||
| KX_SceneList::iterator sceneit = m_scenes.begin(); | return (KX_Scene *)m_scenes->FindValue(scenename); | ||||
| // 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 std::string& scenename, bool overlay) | |||||
| void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overlay) | |||||
| { | { | ||||
| // only add scene when it doesn't exist! | // only add scene when it doesn't exist! | ||||
| if (FindScene(scenename)) { | if (FindScene(scenename)) { | ||||
| printf("warning: scene %s already exists, not added!\n",scenename.ReadPtr()); | CM_Warning("scene " << scenename << " already exists, not added!"); | ||||
| } | } | ||||
| else { | else { | ||||
| if (overlay) { | if (overlay) { | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| void KX_KetsjiEngine::RemoveScene(const std::string& scenename) | |||||
| void KX_KetsjiEngine::RemoveScene(const STR_String& scenename) | |||||
| { | { | ||||
| if (FindScene(scenename)) | if (FindScene(scenename)) { | ||||
| { | |||||
| m_removingScenes.push_back(scenename); | m_removingScenes.push_back(scenename); | ||||
| } | } | ||||
| else | else { | ||||
| { | CM_Warning("scene " << scenename << " does not exist, not removed!"); | ||||
| // STR_String tmpname = scenename; | |||||
| std::cout << "warning: scene " << scenename << " does not exist, not removed!" << std::endl; | |||||
| } | } | ||||
| } | } | ||||
| void KX_KetsjiEngine::RemoveScheduledScenes() | void KX_KetsjiEngine::RemoveScheduledScenes() | ||||
| { | { | ||||
| if (m_removingScenes.size()) | if (m_removingScenes.size()) { | ||||
| { | std::vector<std::string>::iterator scenenameit; | ||||
| vector<STR_String>::iterator scenenameit; | for (scenenameit = m_removingScenes.begin(); scenenameit != m_removingScenes.end(); scenenameit++) { | ||||
| for (scenenameit=m_removingScenes.begin();scenenameit != m_removingScenes.end();scenenameit++) | std::string scenename = *scenenameit; | ||||
| { | |||||
| STR_String scenename = *scenenameit; | KX_Scene *scene = FindScene(scenename); | ||||
| if (scene) { | |||||
| KX_SceneList::iterator sceneit; | m_sceneconverter->RemoveScene(scene); | ||||
| for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) | m_scenes->RemoveValue(scene); | ||||
| { | |||||
| KX_Scene* scene = *sceneit; | |||||
| if (scene->GetName()==scenename) | |||||
| { | |||||
| m_sceneconverter->RemoveScene(scene); | |||||
| m_scenes.erase(sceneit); | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| m_removingScenes.clear(); | m_removingScenes.clear(); | ||||
| } | } | ||||
| } | } | ||||
| KX_Scene* KX_KetsjiEngine::CreateScene(Scene *scene, bool libloading) | KX_Scene *KX_KetsjiEngine::CreateScene(Scene *scene, bool libloading) | ||||
| { | { | ||||
| KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice, | KX_Scene *tmpscene = new KX_Scene(m_inputDevice, | ||||
| m_mousedevice, | scene->id.name + 2, | ||||
| m_networkdevice, | scene, | ||||
| scene->id.name+2, | m_canvas, | ||||
| scene, | m_networkMessageManager); | ||||
| m_canvas); | |||||
| m_sceneconverter->ConvertScene(tmpscene, | m_sceneconverter->ConvertScene(tmpscene, | ||||
| m_rasterizer, | m_rasterizer, | ||||
| m_canvas, | m_canvas, | ||||
| libloading); | libloading); | ||||
| return tmpscene; | return tmpscene; | ||||
| } | } | ||||
| KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename) | KX_Scene *KX_KetsjiEngine::CreateScene(const std::string& scenename) | ||||
| { | { | ||||
| Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename); | Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename); | ||||
| if (!scene) | if (!scene) | ||||
| return NULL; | return NULL; | ||||
| return CreateScene(scene); | return CreateScene(scene); | ||||
| } | } | ||||
| void KX_KetsjiEngine::AddScheduledScenes() | void KX_KetsjiEngine::AddScheduledScenes() | ||||
| { | { | ||||
| vector<STR_String>::iterator scenenameit; | std::vector<std::string>::iterator scenenameit; | ||||
| if (m_addingOverlayScenes.size()) | if (m_addingOverlayScenes.size()) { | ||||
| { | |||||
| for (scenenameit = m_addingOverlayScenes.begin(); | for (scenenameit = m_addingOverlayScenes.begin(); | ||||
| scenenameit != m_addingOverlayScenes.end(); | scenenameit != m_addingOverlayScenes.end(); | ||||
| scenenameit++) | scenenameit++) | ||||
| { | { | ||||
| STR_String scenename = *scenenameit; | std::string scenename = *scenenameit; | ||||
| KX_Scene* tmpscene = CreateScene(scenename); | KX_Scene *tmpscene = CreateScene(scenename); | ||||
| if (tmpscene) { | if (tmpscene) { | ||||
| m_scenes.push_back(tmpscene); | m_scenes->Add(tmpscene->AddRef()); | ||||
| PostProcessScene(tmpscene); | PostProcessScene(tmpscene); | ||||
| } else { | tmpscene->Release(); | ||||
| printf("warning: scene %s could not be found, not added!\n",scenename.ReadPtr()); | } | ||||
| else { | |||||
| CM_Warning("scene " << scenename << " could not be found, not added!"); | |||||
| } | } | ||||
| } | } | ||||
| m_addingOverlayScenes.clear(); | m_addingOverlayScenes.clear(); | ||||
| } | } | ||||
| if (m_addingBackgroundScenes.size()) | if (m_addingBackgroundScenes.size()) { | ||||
| { | |||||
| for (scenenameit = m_addingBackgroundScenes.begin(); | for (scenenameit = m_addingBackgroundScenes.begin(); | ||||
| scenenameit != m_addingBackgroundScenes.end(); | scenenameit != m_addingBackgroundScenes.end(); | ||||
| scenenameit++) | scenenameit++) | ||||
| { | { | ||||
| STR_String scenename = *scenenameit; | std::string scenename = *scenenameit; | ||||
| KX_Scene* tmpscene = CreateScene(scenename); | KX_Scene *tmpscene = CreateScene(scenename); | ||||
| if (tmpscene) { | if (tmpscene) { | ||||
| m_scenes.insert(m_scenes.begin(),tmpscene); | m_scenes->Insert(0, tmpscene->AddRef()); | ||||
| PostProcessScene(tmpscene); | PostProcessScene(tmpscene); | ||||
| } else { | tmpscene->Release(); | ||||
| printf("warning: scene %s could not be found, not added!\n",scenename.ReadPtr()); | } | ||||
| else { | |||||
| CM_Warning("scene " << scenename << " could not be found, not added!"); | |||||
| } | } | ||||
| } | } | ||||
| m_addingBackgroundScenes.clear(); | m_addingBackgroundScenes.clear(); | ||||
| } | } | ||||
| } | } | ||||
| bool KX_KetsjiEngine::ReplaceScene(const std::string& oldscene, const std::string& newscene) | |||||
| bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene) | |||||
| { | { | ||||
| // Don't allow replacement if the new scene doesn't exist. | // Don't allow replacement if the new scene doesn't exist. | ||||
| // Allows smarter game design (used to have no check here). | // Allows smarter game design (used to have no check here). | ||||
| Context not available. | |||||
| // new scene in the lib => it won't work anymore, the lib | // new scene in the lib => it won't work anymore, the lib | ||||
| // must be loaded before doing the replace. | // must be loaded before doing the replace. | ||||
| if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL) { | if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL) { | ||||
| m_replace_scenes.push_back(std::make_pair(oldscene,newscene)); | m_replace_scenes.push_back(std::make_pair(oldscene, newscene)); | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| Context not available. | |||||
| // stupid to rely on the mem allocation order... | // stupid to rely on the mem allocation order... | ||||
| void KX_KetsjiEngine::ReplaceScheduledScenes() | void KX_KetsjiEngine::ReplaceScheduledScenes() | ||||
| { | { | ||||
| if (m_replace_scenes.size()) | if (m_replace_scenes.size()) { | ||||
| { | std::vector<std::pair<std::string, std::string> >::iterator scenenameit; | ||||
| vector<pair<STR_String,STR_String> >::iterator scenenameit; | |||||
| for (scenenameit = m_replace_scenes.begin(); | for (scenenameit = m_replace_scenes.begin(); | ||||
| scenenameit != m_replace_scenes.end(); | scenenameit != m_replace_scenes.end(); | ||||
| scenenameit++) | scenenameit++) | ||||
| { | { | ||||
| STR_String oldscenename = (*scenenameit).first; | std::string oldscenename = (*scenenameit).first; | ||||
| STR_String newscenename = (*scenenameit).second; | std::string newscenename = (*scenenameit).second; | ||||
| int i=0; | |||||
| /* Scenes are not supposed to be included twice... I think */ | /* Scenes are not supposed to be included twice... I think */ | ||||
| KX_SceneList::iterator sceneit; | for (unsigned int sce_idx = 0; sce_idx < m_scenes->GetCount(); ++sce_idx) { | ||||
| for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) { | KX_Scene *scene = (KX_Scene *)m_scenes->GetValue(sce_idx); | ||||
| KX_Scene* scene = *sceneit; | |||||
| if (scene->GetName() == oldscenename) { | if (scene->GetName() == oldscenename) { | ||||
| // avoid crash if the new scene doesn't exist, just do nothing | // avoid crash if the new scene doesn't exist, just do nothing | ||||
| Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename); | Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename); | ||||
| if (blScene) { | if (blScene) { | ||||
| m_sceneconverter->RemoveScene(scene); | m_sceneconverter->RemoveScene(scene); | ||||
| KX_Scene* tmpscene = CreateScene(blScene); | |||||
| m_scenes[i]=tmpscene; | KX_Scene *tmpscene = CreateScene(blScene); | ||||
| m_scenes->SetValue(sce_idx, tmpscene->AddRef()); | |||||
| PostProcessScene(tmpscene); | PostProcessScene(tmpscene); | ||||
| tmpscene->Release(); | |||||
| } | } | ||||
| else { | else { | ||||
| printf("warning: scene %s could not be found, not replaced!\n",newscenename.ReadPtr()); | CM_Warning("scene " << newscenename << " could not be found, not replaced!"); | ||||
| } | } | ||||
| } | } | ||||
| i++; | |||||
| } | } | ||||
| } | } | ||||
| m_replace_scenes.clear(); | m_replace_scenes.clear(); | ||||
| } | } | ||||
| } | } | ||||
| void KX_KetsjiEngine::SuspendScene(const std::string& scenename) | |||||
| void KX_KetsjiEngine::SuspendScene(const STR_String& scenename) | |||||
| { | { | ||||
| KX_Scene* scene = FindScene(scenename); | KX_Scene *scene = FindScene(scenename); | ||||
| if (scene) scene->Suspend(); | if (scene) { | ||||
| scene->Suspend(); | |||||
| } | |||||
| } | } | ||||
| void KX_KetsjiEngine::ResumeScene(const std::string& scenename) | |||||
| void KX_KetsjiEngine::ResumeScene(const STR_String& scenename) | |||||
| { | { | ||||
| KX_Scene* scene = FindScene(scenename); | KX_Scene *scene = FindScene(scenename); | ||||
| if (scene) scene->Resume(); | if (scene) { | ||||
| scene->Resume(); | |||||
| } | |||||
| } | } | ||||
| void KX_KetsjiEngine::SetUseFixedFramerate(bool fixedFramerate) | |||||
| void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime) | |||||
| { | { | ||||
| m_bFixedTime = bUseFixedTime; | m_fixedFramerate = fixedFramerate; | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetUseExternalClock(bool useExternalClock) | void KX_KetsjiEngine::SetUseExternalClock(bool useExternalClock) | ||||
| Context not available. | |||||
| m_useExternalClock = useExternalClock; | m_useExternalClock = useExternalClock; | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetAnimRecordMode(bool animation_record, int startFrame) | bool KX_KetsjiEngine::GetUseFixedFramerate(void) const | ||||
| { | |||||
| 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; | |||||
| } | |||||
| int KX_KetsjiEngine::getAnimRecordFrame() const | |||||
| { | |||||
| return m_currentFrame; | |||||
| } | |||||
| void KX_KetsjiEngine::setAnimRecordFrame(int framenr) | |||||
| { | |||||
| m_currentFrame = framenr; | |||||
| } | |||||
| bool KX_KetsjiEngine::GetUseFixedTime(void) const | |||||
| { | { | ||||
| return m_bFixedTime; | return m_fixedFramerate; | ||||
| } | } | ||||
| bool KX_KetsjiEngine::GetUseExternalClock(void) const | bool KX_KetsjiEngine::GetUseExternalClock(void) const | ||||
| Context not available. | |||||
| m_show_debug_properties = properties; | m_show_debug_properties = properties; | ||||
| } | } | ||||
| void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const | void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const | ||||
| { | { | ||||
| frameRate = m_show_framerate; | frameRate = m_show_framerate; | ||||
| Context not available. | |||||
| properties = m_show_debug_properties; | properties = m_show_debug_properties; | ||||
| } | } | ||||
| void KX_KetsjiEngine::ProcessScheduledScenes(void) | void KX_KetsjiEngine::ProcessScheduledScenes(void) | ||||
| { | { | ||||
| // Check whether there will be changes to the list of scenes | // Check whether there will be changes to the list of scenes | ||||
| if (m_addingOverlayScenes.size() || | if (m_addingOverlayScenes.size() || | ||||
| m_addingBackgroundScenes.size() || | m_addingBackgroundScenes.size() || | ||||
| m_replace_scenes.size() || | m_replace_scenes.size() || | ||||
| m_removingScenes.size()) { | m_removingScenes.size()) { | ||||
| // Change the scene list | // Change the scene list | ||||
| ReplaceScheduledScenes(); | ReplaceScheduledScenes(); | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetHideCursor(bool hideCursor) | void KX_KetsjiEngine::SetHideCursor(bool hideCursor) | ||||
| { | { | ||||
| m_hideCursor = hideCursor; | m_hideCursor = hideCursor; | ||||
| } | } | ||||
| bool KX_KetsjiEngine::GetHideCursor(void) const | bool KX_KetsjiEngine::GetHideCursor(void) const | ||||
| { | { | ||||
| return m_hideCursor; | return m_hideCursor; | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetShowBoundingBox(bool show) | |||||
| { | |||||
| m_showBoundingBox = show; | |||||
| } | |||||
| bool KX_KetsjiEngine::GetShowBoundingBox() const | |||||
| { | |||||
| return m_showBoundingBox; | |||||
| } | |||||
| void KX_KetsjiEngine::SetShowArmatures(bool show) | |||||
| { | |||||
| m_showArmature = show; | |||||
| } | |||||
| bool KX_KetsjiEngine::GetShowArmatures() const | |||||
| { | |||||
| return m_showArmature; | |||||
| } | |||||
| void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor) | void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor) | ||||
| { | { | ||||
| m_overrideFrameColor = overrideFrameColor; | m_overrideFrameColor = overrideFrameColor; | ||||
| } | } | ||||
| bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const | bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const | ||||
| { | { | ||||
| return m_overrideFrameColor; | return m_overrideFrameColor; | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b, float a) | void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b, float a) | ||||
| { | { | ||||
| m_overrideFrameColorR = r; | m_overrideFrameColorR = r; | ||||
| Context not available. | |||||
| m_overrideFrameColorA = a; | m_overrideFrameColorA = a; | ||||
| } | } | ||||
| void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b, float& a) const | void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b, float& a) const | ||||
| { | { | ||||
| r = m_overrideFrameColorR; | r = m_overrideFrameColorR; | ||||
| Context not available. | |||||
| a = m_overrideFrameColorA; | a = m_overrideFrameColorA; | ||||
| } | } | ||||
| void KX_KetsjiEngine::Resize() | void KX_KetsjiEngine::Resize() | ||||
| { | { | ||||
| KX_SceneList::iterator sceneit; | KX_SceneList::iterator sceneit; | ||||
| /* extended mode needs to recalculate camera frusta when */ | /* extended mode needs to recalculate camera frusta when */ | ||||
| KX_Scene* firstscene = *m_scenes.begin(); | KX_Scene *firstscene = (KX_Scene *)m_scenes->GetFront(); | ||||
| const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); | const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); | ||||
| if (framesettings.FrameType() == RAS_FrameSettings::e_frame_extend) { | if (framesettings.FrameType() == RAS_FrameSettings::e_frame_extend) { | ||||
| for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++) { | for (CListValue::iterator<KX_Scene> sceit = m_scenes->GetBegin(), sceend = m_scenes->GetEnd(); sceit != sceend; ++sceit) { | ||||
| KX_Camera* cam = ((KX_Scene *)*sceneit)->GetActiveCamera(); | KX_Scene *scene = *sceit; | ||||
| KX_Camera *cam = scene->GetActiveCamera(); | |||||
| cam->InvalidateProjectionMatrix(); | cam->InvalidateProjectionMatrix(); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void KX_KetsjiEngine::SetGlobalSettings(GlobalSettings *gs) | |||||
| void KX_KetsjiEngine::SetGlobalSettings(GlobalSettings* gs) | |||||
| { | { | ||||
| m_globalsettings.matmode = gs->matmode; | |||||
| m_globalsettings.glslflag = gs->glslflag; | m_globalsettings.glslflag = gs->glslflag; | ||||
| } | } | ||||
| GlobalSettings* KX_KetsjiEngine::GetGlobalSettings(void) | GlobalSettings *KX_KetsjiEngine::GetGlobalSettings(void) | ||||
| { | { | ||||
| return &m_globalsettings; | return &m_globalsettings; | ||||
| } | } | ||||
| Context not available. | |||||