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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/python_api/rst/bge.logic.rst70
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp77
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.h47
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp70
4 files changed, 248 insertions, 16 deletions
diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst
index b119bdd1ba1..3f35901234a 100644
--- a/doc/python_api/rst/bge.logic.rst
+++ b/doc/python_api/rst/bge.logic.rst
@@ -378,6 +378,76 @@ General functions
Render next frame (if Python has control)
+**********************
+Time related functions
+**********************
+
+.. function:: getClockTime()
+
+ Get the current BGE render time, in seconds. The BGE render time is the
+ simulation time corresponding to the next scene that will be rendered.
+
+ :rtype: double
+
+.. function:: getFrameTime()
+
+ Get the current BGE frame time, in seconds. The BGE frame time is the
+ simulation time corresponding to the current call of the logic system.
+ Generally speaking, it is what the user is interested in.
+
+ :rtype: double
+
+.. function:: getRealTime()
+
+ Get the number of real (system-clock) seconds elapsed since the beginning
+ of the simulation.
+
+ :rtype: double
+
+.. function:: getTimeScale()
+
+ Get the time multiplier between real-time and simulation time. The default
+ value is 1.0. A value greater than 1.0 means that the simulation is going
+ faster than real-time, a value lower than 1.0 means that the simulation is
+ going slower than real-time.
+
+ :rtype: double
+
+.. function:: setTimeScale(time_scale)
+
+ Set the time multiplier between real-time and simulation time. A value
+ greater than 1.0 means that the simulation is going faster than real-time,
+ a value lower than 1.0 means that the simulation is going slower than
+ real-time. Note that a too large value may lead to some physics
+ instabilities.
+
+ :arg time_scale: The new time multiplier.
+
+.. function:: getUseExternalClock()
+
+ Get if the BGE use the inner BGE clock, or rely or on an external
+ clock. The default is to use the inner BGE clock.
+
+ :rtype: bool
+
+.. function:: setUseExternalClock(use_external_clock)
+
+ Set if the BGE use the inner BGE clock, or rely or on an external
+ clock. If the user selects the use of an external clock, he should call
+ regularly the setClockTime method.
+
+ :arg use_external_clock: the new setting
+
+.. function:: setClockTime(new_time)
+
+ Set the next value of the simulation clock. It is preferable to use this
+ method from a custom main function in python, as calling it in the logic
+ block can easily lead to a blocked system (if the time does not advance
+ enough to run at least the next logic step).
+
+ :arg new_time: the next value of the BGE clock (in second).
+
+
*****************
Utility functions
*****************
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index 5f36a980a53..fa924f74290 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -128,6 +128,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_bInitialized(false),
m_activecam(0),
m_bFixedTime(false),
+ m_useExternalClock(false),
m_firstframe(true),
@@ -135,6 +136,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_clockTime(0.f),
m_previousClockTime(0.f),
m_previousAnimTime(0.f),
+ m_timescale(1.0f),
+ m_previousRealTime(0.0f),
m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
@@ -411,6 +414,7 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo)
m_clockTime = m_kxsystem->GetTimeInSeconds();
m_frameTime = m_kxsystem->GetTimeInSeconds();
m_previousClockTime = m_kxsystem->GetTimeInSeconds();
+ m_previousRealTime = m_kxsystem->GetTimeInSeconds();
m_firstframe = true;
m_bInitialized = true;
@@ -554,7 +558,7 @@ void KX_KetsjiEngine::EndFrame()
bool KX_KetsjiEngine::NextFrame()
{
- double timestep = 1.0/m_ticrate;
+ double timestep = m_timescale / m_ticrate;
double framestep = timestep;
// static hidden::Clock sClock;
@@ -563,12 +567,43 @@ bool KX_KetsjiEngine::NextFrame()
//float dt = sClock.getTimeMicroseconds() * 0.000001f;
//sClock.reset();
- if (m_bFixedTime) {
- m_clockTime += timestep;
- }
- else {
- // m_clockTime += dt;
- m_clockTime = m_kxsystem->GetTimeInSeconds();
+ /*
+ * Clock advancement. There is basically three case:
+ * - m_useExternalClock is true, the user is responsible to advance the time
+ * manually using setClockTime, so here, we do not do anything.
+ * - m_useExternalClock is false, m_bFixedTime is true, we advance for one
+ * 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
+ * scaling parameter. If m_timescale is 1.0 (default value), the clock
+ * corresponds to the computer clock.
+ *
+ * Once clockTime has been computed, we will compute how many logic frames
+ * will be executed before the next rendering phase (which will occur at "clockTime").
+ * The game time elapsing between two logic frames (called framestep)
+ * depends on several variables:
+ * - ticrate
+ * - max_physic_frame
+ * - max_logic_frame
+ * 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
+ * than max_physics_frame, we are doing a jump in game time, but keeping
+ * framestep = 1 / ticrate, while if frames is greater than
+ * max_logic_frame, we increase framestep.
+ *
+ * XXX render.fps is not considred anywhere.
+ */
+ if (!m_useExternalClock) {
+ if (m_bFixedTime) {
+ m_clockTime += timestep;
+ }
+ else {
+ double current_time = m_kxsystem->GetTimeInSeconds();
+ double dt = current_time - m_previousRealTime;
+ m_previousRealTime = current_time;
+ // m_clockTime += dt;
+ m_clockTime += dt * m_timescale;
+ }
}
double deltatime = m_clockTime - m_frameTime;
@@ -579,16 +614,14 @@ bool KX_KetsjiEngine::NextFrame()
return false;
}
-
// Compute the number of logic frames to do each update (fixed tic bricks)
- int frames =int(deltatime*m_ticrate+1e-6);
+ int frames = int(deltatime * m_ticrate / m_timescale + 1e-6);
// if (frames>1)
// printf("****************************************");
// printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
// if (!frames)
// PIL_sleep_ms(1);
-
KX_SceneList::iterator sceneit;
if (frames>m_maxPhysicsFrame)
@@ -1756,6 +1789,10 @@ void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
m_bFixedTime = bUseFixedTime;
}
+void KX_KetsjiEngine::SetUseExternalClock(bool useExternalClock)
+{
+ m_useExternalClock = useExternalClock;
+}
void KX_KetsjiEngine::SetAnimRecordMode(bool animation_record, int startFrame)
{
@@ -1783,6 +1820,11 @@ bool KX_KetsjiEngine::GetUseFixedTime(void) const
return m_bFixedTime;
}
+bool KX_KetsjiEngine::GetUseExternalClock(void) const
+{
+ return m_useExternalClock;
+}
+
double KX_KetsjiEngine::GetSuspendedDelta()
{
return m_suspendeddelta;
@@ -1798,6 +1840,16 @@ void KX_KetsjiEngine::SetTicRate(double ticrate)
m_ticrate = ticrate;
}
+double KX_KetsjiEngine::GetTimeScale() const
+{
+ return m_timescale;
+}
+
+void KX_KetsjiEngine::SetTimeScale(double timescale)
+{
+ m_timescale = timescale;
+}
+
int KX_KetsjiEngine::GetMaxLogicFrame()
{
return m_maxLogicFrame;
@@ -1838,6 +1890,11 @@ double KX_KetsjiEngine::GetClockTime(void) const
return m_clockTime;
}
+void KX_KetsjiEngine::SetClockTime(double externalClockTime)
+{
+ m_clockTime = externalClockTime;
+}
+
double KX_KetsjiEngine::GetFrameTime(void) const
{
return m_frameTime;
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h
index ec855be3212..3b8cec2ac82 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.h
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h
@@ -103,16 +103,19 @@ private:
bool m_bInitialized;
int m_activecam;
bool m_bFixedTime;
+ bool m_useExternalClock;
bool m_firstframe;
int m_currentFrame;
- double m_frameTime;//discrete timestamp of the 'game logic frame'
- double m_clockTime;//current time
- double m_previousClockTime;//previous clock time
- double m_previousAnimTime; //the last time animations were updated
+ double m_frameTime; // current logic game time
+ double m_clockTime; // game time for the next rendering step
+ double m_previousClockTime; // game time of the previous rendering step
+ double m_previousAnimTime; //game time when the animations were last updated
double m_remainingTime;
+ double m_timescale; // time scaling parameter. if > 1.0, time goes faster than real-time. If < 1.0, times goes slower than real-time.
+ double m_previousRealTime;
static int m_maxLogicFrame; /* maximum number of consecutive logic frame */
static int m_maxPhysicsFrame; /* maximum number of consecutive physics frame */
@@ -297,15 +300,37 @@ public:
bool GetUseFixedTime(void) const;
/**
- * Returns current render frame clock time
+ * Sets if the BGE relies on a external clock or its own internal clock
+ */
+ void SetUseExternalClock(bool bUseExternalClock);
+
+ /**
+ * Returns if we rely on an external clock
+ * \return Current setting
+ */
+ bool GetUseExternalClock(void) const;
+
+ /**
+ * Returns next render frame game time
*/
double GetClockTime(void) const;
+
+ /**
+ * Set the next render frame game time. It will impact also frame time, as
+ * this one is derived from clocktime
+ */
+ void SetClockTime(double externalClockTime);
+
/**
- * Returns current logic frame clock time
+ * Returns current logic frame game time
*/
double GetFrameTime(void) const;
+ /**
+ * Returns the real (system) time
+ */
double GetRealTime(void) const;
+
/**
* Returns the difference between the local time of the scene (when it
* was running and not suspended) and the "curtime"
@@ -361,6 +386,16 @@ public:
*/
static double GetAverageFrameRate();
+ /**
+ * Gets the time scale multiplier
+ */
+ double GetTimeScale() const;
+
+ /**
+ * Sets the time scale multiplier
+ */
+ void SetTimeScale(double scale);
+
static void SetExitKey(short key);
static short GetExitKey();
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index d35f09dd820..8a010726bba 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -548,6 +548,64 @@ static PyObject *gPyGetAverageFrameRate(PyObject *)
return PyFloat_FromDouble(KX_KetsjiEngine::GetAverageFrameRate());
}
+static PyObject *gPyGetUseExternalClock(PyObject *)
+{
+ return PyBool_FromLong(gp_KetsjiEngine->GetUseExternalClock());
+}
+
+static PyObject *gPySetUseExternalClock(PyObject *, PyObject *args)
+{
+ bool bUseExternalClock;
+
+ if (!PyArg_ParseTuple(args, "p:setUseExternalClock", &bUseExternalClock))
+ return NULL;
+
+ gp_KetsjiEngine->SetUseExternalClock(bUseExternalClock);
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyGetClockTime(PyObject *)
+{
+ return PyFloat_FromDouble(gp_KetsjiEngine->GetClockTime());
+}
+
+static PyObject *gPySetClockTime(PyObject *, PyObject *args)
+{
+ double externalClockTime;
+
+ if (!PyArg_ParseTuple(args, "d:setClockTime", &externalClockTime))
+ return NULL;
+
+ gp_KetsjiEngine->SetClockTime(externalClockTime);
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyGetFrameTime(PyObject *)
+{
+ return PyFloat_FromDouble(gp_KetsjiEngine->GetFrameTime());
+}
+
+static PyObject *gPyGetRealTime(PyObject *)
+{
+ return PyFloat_FromDouble(gp_KetsjiEngine->GetRealTime());
+}
+
+static PyObject *gPyGetTimeScale(PyObject *)
+{
+ return PyFloat_FromDouble(gp_KetsjiEngine->GetTimeScale());
+}
+
+static PyObject *gPySetTimeScale(PyObject *, PyObject *args)
+{
+ double time_scale;
+
+ if (!PyArg_ParseTuple(args, "d:setTimeScale", &time_scale))
+ return NULL;
+
+ gp_KetsjiEngine->SetTimeScale(time_scale);
+ Py_RETURN_NONE;
+}
+
static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args)
{
char cpath[sizeof(gp_GamePythonPath)];
@@ -847,7 +905,19 @@ static struct PyMethodDef game_methods[] = {
{"setAnimRecordFrame", (PyCFunction) gPySetAnimRecordFrame, METH_VARARGS, (const char *)"Sets the current frame number used for animation recording"},
{"getExitKey", (PyCFunction) gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"},
{"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"},
+ {"getUseExternalClock", (PyCFunction) gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"},
+ {"setUseExternalClock", (PyCFunction) gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"},
+ {"getClockTime", (PyCFunction) gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. "
+ "The BGE render time is the simulated time corresponding to the next scene that will be renderered"},
+ {"setClockTime", (PyCFunction) gPySetClockTime, METH_VARARGS, (const char *)"Set the BGE render time. "
+ "The BGE render time is the simulated time corresponding to the next scene that will be rendered"},
+ {"getFrameTime", (PyCFunction) gPyGetFrameTime, METH_NOARGS, (const char *)"Get the BGE last frametime. "
+ "The BGE frame time is the simulated time corresponding to the last call of the logic system"},
+ {"getRealTime", (PyCFunction) gPyGetRealTime, METH_NOARGS, (const char *)"Get the real system time. "
+ "The real-time corresponds to the system time" },
{"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"},
+ {"getTimeScale", (PyCFunction) gPyGetTimeScale, METH_NOARGS, (const char *)"Get the time multiplier"},
+ {"setTimeScale", (PyCFunction) gPySetTimeScale, METH_VARARGS, (const char *)"Set the time multiplier"},
{"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (const char *)"Gets a list of blend files in the same directory as the current blend file"},
{"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (const char *)"Prints GL Extension Info"},
{"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine statistics"},