BGE: GUI control over frame rate, logic rate, physics rate and physics subrate.
authorBenoit Bolsee <benoit.bolsee@online.be>
Thu, 21 May 2009 18:10:19 +0000 (18:10 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Thu, 21 May 2009 18:10:19 +0000 (18:10 +0000)
Four new buttons in World settings to control frame rate:
fps:  Nominal frame rate in frame per second.
      Also sets the physics timestep = 1/fps
phys: Maximum number of physics timestep per game frame in case
      the actual fps is less than nominal. This allows the
      physics to keep up with real time even if the graphics slows
      down the game.
sub:  Fixed number of simulation substeps per physic timestep.
      Improves the precision of the physics simulation. Useful for
      fast moving objects for example.
log:  Maximum number of logic steps per game frame in case the
      actual fps is less than nominal. This allows the logic
      system to follow the physics simulation.
      Upper bound = phys
      (setting the value higher than phys has no effect).
      On games with heavy logic system, it is useful to set this
      value to 1, to keep logic time under control.

All these values were already accessible from Python except phys:

GameLogic.getMaxPhysicsFrame():
Gets the maximum number of physics frame per render frame.

GameLogic.setMaxPhysicsFrame(phys):
Sets the maximum number of physics timestep that are executed per render frame.
Higher value allows physics to keep up with realtime even if graphics slows down the game.
Physics timestep is fixed and equal to 1/tickrate (see setLogicTicRate)
maxphysics/ticrate is the maximum delay of the renderer that physics can compensate.
      phys: integer

source/blender/blenkernel/intern/world.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_world_types.h
source/blender/src/buttons_shading.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
source/gameengine/Ketsji/KX_KetsjiEngine.h
source/gameengine/Ketsji/KX_PythonInit.cpp
source/gameengine/PyDoc/GameLogic.py

index 6635ef29d51f50d830f728f3c185990184cecfdd..d47f4efeb4e14698457b10b812701aa9428ec788 100644 (file)
@@ -109,6 +109,10 @@ World *add_world(char *name)
        wrld->mode = WO_DBVT_CULLING;   // DBVT culling by default
        wrld->occlusionRes = 128;
        wrld->preview = NULL;
        wrld->mode = WO_DBVT_CULLING;   // DBVT culling by default
        wrld->occlusionRes = 128;
        wrld->preview = NULL;
+       wrld->ticrate = 60;
+       wrld->maxlogicstep = 5;
+       wrld->physubstep = 1;
+       wrld->maxphystep = 5;
 
        return wrld;
 }
 
        return wrld;
 }
index 25c8a928a3be605ead1d974ff0f6bc53c4cbabd4..bda0348f2ca4ea587cee5ae0ef0d17e03e112f55 100644 (file)
@@ -8108,6 +8108,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                
        if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 5)) {
                Object *ob;
                
        if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 5)) {
                Object *ob;
+               World *wrld;
                for(ob = main->object.first; ob; ob= ob->id.next) {
                        if(ob->parent) {
                                /* check if top parent has compound shape set and if yes, set this object
                for(ob = main->object.first; ob; ob= ob->id.next) {
                        if(ob->parent) {
                                /* check if top parent has compound shape set and if yes, set this object
@@ -8120,6 +8121,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                                        ob->gameflag |= OB_CHILD;
                        }
                }
                                        ob->gameflag |= OB_CHILD;
                        }
                }
+               for(wrld=main->world.first; wrld; wrld= wrld->id.next) {
+                       wrld->ticrate = 60;
+                       wrld->maxlogicstep = 5;
+                       wrld->physubstep = 1;
+                       wrld->maxphystep = 5;
+               }
        }
 
        if (main->versionfile < 249) {
        }
 
        if (main->versionfile < 249) {
index f599364ed66aa4b6593410ebc057bd5d2067e01b..5f6e47acac42b6cd1d25391e10d656c1123d8507 100644 (file)
@@ -90,6 +90,7 @@ typedef struct World {
        short mode;
        short occlusionRes;             /* resolution of occlusion Z buffer in pixel */
        short physicsEngine;    /* here it's aligned */
        short mode;
        short occlusionRes;             /* resolution of occlusion Z buffer in pixel */
        short physicsEngine;    /* here it's aligned */
+       short ticrate, maxlogicstep, physubstep, maxphystep;
        
        float misi, miststa, mistdist, misthi;
        
        
        float misi, miststa, mistdist, misthi;
        
index 79f95d1bf5f412bb9e7a5687f2440bd0c718d037..12219944945c024885d4e177f8aa40ed30e3f4f0 100644 (file)
@@ -2198,16 +2198,25 @@ static void world_panel_mistaph(World *wrld)
        
        /* Gravitation for the game worlds */
        uiDefButF(block, NUMSLI,0, "Grav ", 150,180,150,19,     &(wrld->gravity), 0.0, 25.0, 0, 0,  "Sets the gravitation constant of the game world");
        
        /* Gravitation for the game worlds */
        uiDefButF(block, NUMSLI,0, "Grav ", 150,180,150,19,     &(wrld->gravity), 0.0, 25.0, 0, 0,  "Sets the gravitation constant of the game world");
+       uiDefButS(block, NUM, B_REDR, "fps:",
+                               10,  160, 70, 19, &wrld->ticrate, 1.0, 120.0, 0, 0, "Sets the nominal number of game frames per second. Physics fixed timestep = 1/fps, independently of actual frame rate");
+       uiDefButS(block, NUM, B_REDR, "log:",
+                               80,  160, 70, 19, &wrld->maxlogicstep, 1.0, 5.0, 0, 0, "Sets the maxmimum number of logic frame per game frame if graphics slows down the game, higher value allows better synchronization with physics");
+       uiDefButS(block, NUM, B_REDR, "phys:",
+                               150, 160, 75, 19, &wrld->maxphystep, 1.0, 5.0, 0, 0, "Sets the maximum number of physics step per game frame if graphics slows down the game, higher value allows physics to keep up with realtime");
+       uiDefButS(block, NUM, B_REDR, "sub:",
+                               225, 160, 75, 19, &wrld->physubstep, 1.0, 5.0, 0, 0, "Sets the number of simulation substep per physic timestep, higher value give better physics precision");
+
        if (wrld->physicsEngine == WOPHY_BULLET) {
        if (wrld->physicsEngine == WOPHY_BULLET) {
-               uiDefButBitS(block, TOG, WO_DBVT_CULLING, B_REDR, "DBVT culling",       10,160,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles use of optimized Bullet DBVT tree for view frustrum and occlusion culling");
+               uiDefButBitS(block, TOG, WO_DBVT_CULLING, B_REDR, "DBVT culling",       10,140,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles use of optimized Bullet DBVT tree for view frustrum and occlusion culling");
                if (wrld->mode & WO_DBVT_CULLING)
                        uiDefButS(block, NUM, B_REDR, "Occlu Res:",
                if (wrld->mode & WO_DBVT_CULLING)
                        uiDefButS(block, NUM, B_REDR, "Occlu Res:",
-                               150, 160, 150, 19, &wrld->occlusionRes, 128.0, 1024.0, 0, 0, "Sets the size of the occlusion buffer in pixel, use higher value for better precsion (slower)");
+                               150, 140, 150, 19, &wrld->occlusionRes, 128.0, 1024.0, 0, 0, "Sets the size of the occlusion buffer in pixel, use higher value for better precsion (slower)");
        }
 #endif
 
        uiBlockSetCol(block, TH_BUT_SETTING1);
        }
 #endif
 
        uiBlockSetCol(block, TH_BUT_SETTING1);
-       uiDefButBitS(block, TOG, WO_MIST, B_WORLDPRV2,"Mist",   10,120,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles mist simulation");
+       uiDefButBitS(block, TOG, WO_MIST, B_WORLDPRV2,"Mist",   10,115,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles mist simulation");
        uiBlockSetCol(block, TH_AUTO);
 
        uiBlockBeginAlign(block);
        uiBlockSetCol(block, TH_AUTO);
 
        uiBlockBeginAlign(block);
@@ -2222,7 +2231,7 @@ static void world_panel_mistaph(World *wrld)
        uiBlockEndAlign(block);
 
        uiBlockSetCol(block, TH_BUT_SETTING1);
        uiBlockEndAlign(block);
 
        uiBlockSetCol(block, TH_BUT_SETTING1);
-       uiDefButBitS(block, TOG, WO_STARS, B_WORLDPRV2, "Stars",160,120,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles starfield generation");
+       uiDefButBitS(block, TOG, WO_STARS, B_WORLDPRV2, "Stars",160,115,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles starfield generation");
        uiBlockSetCol(block, TH_AUTO);
        
        uiBlockBeginAlign(block);
        uiBlockSetCol(block, TH_AUTO);
        
        uiBlockBeginAlign(block);
index 82edd4f218b39da85427a9b1ce8b5c7f6312c740..f3024197a8a1aef77ed9cc1441cef6d519535c23 100644 (file)
@@ -2499,6 +2499,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                if (occlusion)
                        kxscene->SetDbvtOcclusionRes(blenderscene->world->occlusionRes);
        }
                if (occlusion)
                        kxscene->SetDbvtOcclusionRes(blenderscene->world->occlusionRes);
        }
+       if (blenderscene->world)
+               kxscene->GetPhysicsEnvironment()->setNumTimeSubSteps(blenderscene->world->physubstep);
 
        // now that the scenegraph is complete, let's instantiate the deformers.
        // We need that to create reusable derived mesh and physic shapes
 
        // now that the scenegraph is complete, let's instantiate the deformers.
        // We need that to create reusable derived mesh and physic shapes
index 4107ed7d82e7e0463ea94610986267cdd8c24100..983059d0c70cd0f1862fe4f58d2e3fa957f8bdef 100644 (file)
@@ -77,6 +77,8 @@
 
 #include "RAS_FramingManager.h"
 #include "stdio.h"
 
 #include "RAS_FramingManager.h"
 #include "stdio.h"
+#include "DNA_world_types.h"
+#include "DNA_scene_types.h"
 
 // If define: little test for Nzc: guarded drawing. If the canvas is
 // not valid, skip rendering this frame.
 
 // If define: little test for Nzc: guarded drawing. If the canvas is
 // not valid, skip rendering this frame.
@@ -98,6 +100,7 @@ const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
 
 double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;
 int       KX_KetsjiEngine::m_maxLogicFrame = 5;
 
 double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;
 int       KX_KetsjiEngine::m_maxLogicFrame = 5;
+int       KX_KetsjiEngine::m_maxPhysicsFrame = 5;
 double KX_KetsjiEngine::m_anim_framerate = 25.0;
 double KX_KetsjiEngine::m_suspendedtime = 0.0;
 double KX_KetsjiEngine::m_suspendeddelta = 0.0;
 double KX_KetsjiEngine::m_anim_framerate = 25.0;
 double KX_KetsjiEngine::m_suspendedtime = 0.0;
 double KX_KetsjiEngine::m_suspendeddelta = 0.0;
@@ -393,8 +396,20 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo)
 
        m_firstframe = true;
        m_bInitialized = true;
 
        m_firstframe = true;
        m_bInitialized = true;
-       m_ticrate = DEFAULT_LOGIC_TIC_RATE;
-       m_maxLogicFrame = 5;
+       // there is always one scene enabled at startup
+       World* world = m_scenes[0]->GetBlenderScene()->world;
+       if (world)
+       {
+               m_ticrate = world->ticrate;
+               m_maxLogicFrame = world->maxlogicstep;
+               m_maxPhysicsFrame = world->maxphystep;
+       }
+       else
+       {
+               m_ticrate = DEFAULT_LOGIC_TIC_RATE;
+               m_maxLogicFrame = 5;
+               m_maxPhysicsFrame = 5;
+       }
        
        if (m_game2ipo)
        {
        
        if (m_game2ipo)
        {
@@ -545,14 +560,13 @@ else
 //             PIL_sleep_ms(1);
        
        KX_SceneList::iterator sceneit;
 //             PIL_sleep_ms(1);
        
        KX_SceneList::iterator sceneit;
-       int frameOut = 5;
        
        
-       if (frames>frameOut)
+       if (frames>m_maxPhysicsFrame)
        {
        
        //      printf("framedOut: %d\n",frames);
        {
        
        //      printf("framedOut: %d\n",frames);
-               m_frameTime+=(frames-frameOut)*timestep;
-               frames = frameOut;
+               m_frameTime+=(frames-m_maxPhysicsFrame)*timestep;
+               frames = m_maxPhysicsFrame;
        }
        
 
        }
        
 
@@ -1736,6 +1750,16 @@ void KX_KetsjiEngine::SetMaxLogicFrame(int frame)
        m_maxLogicFrame = frame;
 }
 
        m_maxLogicFrame = frame;
 }
 
+int KX_KetsjiEngine::GetMaxPhysicsFrame()
+{
+       return m_maxPhysicsFrame;
+}
+
+void KX_KetsjiEngine::SetMaxPhysicsFrame(int frame)
+{
+       m_maxPhysicsFrame = frame;
+}
+
 double KX_KetsjiEngine::GetAnimFrameRate()
 {
        return m_anim_framerate;
 double KX_KetsjiEngine::GetAnimFrameRate()
 {
        return m_anim_framerate;
index cc9b9198db7851363ab831b69919b4a345bc5c9d..5c14c63dd047891f66edbbdba7a71f22ebcf97aa 100644 (file)
@@ -104,6 +104,7 @@ private:
        double                          m_remainingTime;
 
        static int                              m_maxLogicFrame;        /* maximum number of consecutive logic frame */
        double                          m_remainingTime;
 
        static int                              m_maxLogicFrame;        /* maximum number of consecutive logic frame */
+       static int                              m_maxPhysicsFrame;      /* maximum number of consecutive physics frame */
        static double                   m_ticrate;
        static double                   m_anim_framerate; /* for animation playback only - ipo and action */
 
        static double                   m_ticrate;
        static double                   m_anim_framerate; /* for animation playback only - ipo and action */
 
@@ -292,6 +293,14 @@ public:
         * Sets the maximum number of logic frame before render frame
         */
        static void SetMaxLogicFrame(int frame);
         * Sets the maximum number of logic frame before render frame
         */
        static void SetMaxLogicFrame(int frame);
+       /**
+        * Gets the maximum number of physics frame before render frame
+        */
+       static int GetMaxPhysicsFrame();
+       /**
+        * Sets the maximum number of physics frame before render frame
+        */
+       static void SetMaxPhysicsFrame(int frame);
 
        /**
         * Gets the framerate for playing animations. (actions and ipos)
 
        /**
         * Gets the framerate for playing animations. (actions and ipos)
index fb99eab7747f3c008b2637f4e99305e0a84c112e..3626d7baa9a5eb696abddea6d31311d601e5462e 100644 (file)
@@ -308,6 +308,21 @@ static PyObject* gPyGetMaxLogicFrame(PyObject*)
        return PyInt_FromLong(KX_KetsjiEngine::GetMaxLogicFrame());
 }
 
        return PyInt_FromLong(KX_KetsjiEngine::GetMaxLogicFrame());
 }
 
+static PyObject* gPySetMaxPhysicsFrame(PyObject*, PyObject* args)
+{
+       int frame;
+       if (!PyArg_ParseTuple(args, "i:setMaxPhysicsFrame", &frame))
+               return NULL;
+       
+       KX_KetsjiEngine::SetMaxPhysicsFrame(frame);
+       Py_RETURN_NONE;
+}
+
+static PyObject* gPyGetMaxPhysicsFrame(PyObject*)
+{
+       return PyInt_FromLong(KX_KetsjiEngine::GetMaxPhysicsFrame());
+}
+
 static PyObject* gPySetPhysicsTicRate(PyObject*, PyObject* args)
 {
        float ticrate;
 static PyObject* gPySetPhysicsTicRate(PyObject*, PyObject* args)
 {
        float ticrate;
@@ -501,6 +516,8 @@ static struct PyMethodDef game_methods[] = {
        {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS, (PY_METHODCHAR)"stop using the audio dsp (for performance reasons)"},
        {"getMaxLogicFrame", (PyCFunction) gPyGetMaxLogicFrame, METH_NOARGS, (PY_METHODCHAR)"Gets the max number of logic frame per render frame"},
        {"setMaxLogicFrame", (PyCFunction) gPySetMaxLogicFrame, METH_VARARGS, (PY_METHODCHAR)"Sets the max number of logic frame per render frame"},
        {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS, (PY_METHODCHAR)"stop using the audio dsp (for performance reasons)"},
        {"getMaxLogicFrame", (PyCFunction) gPyGetMaxLogicFrame, METH_NOARGS, (PY_METHODCHAR)"Gets the max number of logic frame per render frame"},
        {"setMaxLogicFrame", (PyCFunction) gPySetMaxLogicFrame, METH_VARARGS, (PY_METHODCHAR)"Sets the max number of logic frame per render frame"},
+       {"getMaxPhysicsFrame", (PyCFunction) gPyGetMaxPhysicsFrame, METH_NOARGS, (PY_METHODCHAR)"Gets the max number of physics frame per render frame"},
+       {"setMaxPhysicsFrame", (PyCFunction) gPySetMaxPhysicsFrame, METH_VARARGS, (PY_METHODCHAR)"Sets the max number of physics farme per render frame"},
        {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the logic tic rate"},
        {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the logic tic rate"},
        {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the physics tic rate"},
        {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the logic tic rate"},
        {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the logic tic rate"},
        {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the physics tic rate"},
index 1bc406daf09b4a033cacc93bf61260392cb120c7..3ec30a63c58622a043c0f8dbf5764fb55b00958f 100644 (file)
@@ -387,6 +387,23 @@ def setMaxLogicFrame(maxlogic):
        @param maxlogic: The new maximum number of logic frame per render frame. Valid values: 1..5
        @type maxlogic: integer
        """
        @param maxlogic: The new maximum number of logic frame per render frame. Valid values: 1..5
        @type maxlogic: integer
        """
+def getMaxPhysicsFrame():
+       """
+       Gets the maximum number of physics frame per render frame.
+       
+       @return: The maximum number of physics frame per render frame
+       @rtype: interger
+       """
+def setMaxPhysicsFrame(maxphysics):
+       """
+       Sets the maximum number of physics timestep that are executed per render frame.
+       Higher value allows physics to keep up with realtime even if graphics slows down the game.
+       Physics timestep is fixed and equal to 1/tickrate (see setLogicTicRate)
+       maxphysics/ticrate is the maximum delay of the renderer that physics can compensate.
+        
+       @param maxphysics: The new maximum number of physics timestep per render frame. Valid values: 1..5.
+       @type maxphysics: integer
+       """
 def getLogicTicRate():
        """
        Gets the logic update frequency.
 def getLogicTicRate():
        """
        Gets the logic update frequency.
@@ -406,6 +423,7 @@ def setLogicTicRate(ticrate):
        """
 def getPhysicsTicRate():
        """
        """
 def getPhysicsTicRate():
        """
+       NOT IMPLEMENTED
        Gets the physics update frequency
        
        @return: The physics update frequency in Hz
        Gets the physics update frequency
        
        @return: The physics update frequency in Hz
@@ -413,6 +431,7 @@ def getPhysicsTicRate():
        """
 def setPhysicsTicRate(ticrate):
        """
        """
 def setPhysicsTicRate(ticrate):
        """
+       NOT IMPLEMENTED
        Sets the physics update frequency
        
        The physics update frequency is the number of times the physics system is executed every second.
        Sets the physics update frequency
        
        The physics update frequency is the number of times the physics system is executed every second.