mirror of
https://github.com/minetest/minetest.git
synced 2024-09-12 00:26:50 +02:00
Share FpsControl code between game and menu
This commit is contained in:
parent
0c3a4cc7b9
commit
13a0e5fb4a
@ -650,20 +650,6 @@ public:
|
|||||||
|
|
||||||
const static float object_hit_delay = 0.2;
|
const static float object_hit_delay = 0.2;
|
||||||
|
|
||||||
struct FpsControl {
|
|
||||||
FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void limit(IrrlichtDevice *device, f32 *dtime);
|
|
||||||
|
|
||||||
u32 getBusyMs() const { return busy_time / 1000; }
|
|
||||||
|
|
||||||
// all values in microseconds (us)
|
|
||||||
u64 last_time, busy_time, sleep_time;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* The reason the following structs are not anonymous structs within the
|
/* The reason the following structs are not anonymous structs within the
|
||||||
* class is that they are not used by the majority of member functions and
|
* class is that they are not used by the majority of member functions and
|
||||||
* many functions that do require objects of thse types do not modify them
|
* many functions that do require objects of thse types do not modify them
|
||||||
@ -1201,7 +1187,7 @@ void Game::run()
|
|||||||
// Calculate dtime =
|
// Calculate dtime =
|
||||||
// m_rendering_engine->run() from this iteration
|
// m_rendering_engine->run() from this iteration
|
||||||
// + Sleep time until the wanted FPS are reached
|
// + Sleep time until the wanted FPS are reached
|
||||||
draw_times.limit(device, &dtime);
|
draw_times.limit(device, &dtime, g_menumgr.pausesGame());
|
||||||
|
|
||||||
const auto current_dynamic_info = ClientDynamicInfo::getCurrent();
|
const auto current_dynamic_info = ClientDynamicInfo::getCurrent();
|
||||||
if (!current_dynamic_info.equal(client_display_info)) {
|
if (!current_dynamic_info.equal(client_display_info)) {
|
||||||
@ -4330,48 +4316,6 @@ void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
|
|||||||
Misc
|
Misc
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void FpsControl::reset()
|
|
||||||
{
|
|
||||||
last_time = porting::getTimeUs();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* On some computers framerate doesn't seem to be automatically limited
|
|
||||||
*/
|
|
||||||
void FpsControl::limit(IrrlichtDevice *device, f32 *dtime)
|
|
||||||
{
|
|
||||||
const float fps_limit = (device->isWindowFocused() && !g_menumgr.pausesGame())
|
|
||||||
? g_settings->getFloat("fps_max")
|
|
||||||
: g_settings->getFloat("fps_max_unfocused");
|
|
||||||
const u64 frametime_min = 1000000.0f / std::max(fps_limit, 1.0f);
|
|
||||||
|
|
||||||
u64 time = porting::getTimeUs();
|
|
||||||
|
|
||||||
if (time > last_time) // Make sure time hasn't overflowed
|
|
||||||
busy_time = time - last_time;
|
|
||||||
else
|
|
||||||
busy_time = 0;
|
|
||||||
|
|
||||||
if (busy_time < frametime_min) {
|
|
||||||
sleep_time = frametime_min - busy_time;
|
|
||||||
if (sleep_time > 0)
|
|
||||||
sleep_us(sleep_time);
|
|
||||||
} else {
|
|
||||||
sleep_time = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the timer again to accurately determine how long we actually slept,
|
|
||||||
// rather than calculating it by adding sleep_time to time.
|
|
||||||
time = porting::getTimeUs();
|
|
||||||
|
|
||||||
if (time > last_time) // Make sure last_time hasn't overflowed
|
|
||||||
*dtime = (time - last_time) / 1000000.0f;
|
|
||||||
else
|
|
||||||
*dtime = 0;
|
|
||||||
|
|
||||||
last_time = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_sky)
|
void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_sky)
|
||||||
{
|
{
|
||||||
m_rendering_engine->draw_load_screen(wstrgettext(msg), guienv, texture_src,
|
m_rendering_engine->draw_load_screen(wstrgettext(msg), guienv, texture_src,
|
||||||
|
@ -44,6 +44,46 @@ RenderingEngine *RenderingEngine::s_singleton = nullptr;
|
|||||||
const video::SColor RenderingEngine::MENU_SKY_COLOR = video::SColor(255, 140, 186, 250);
|
const video::SColor RenderingEngine::MENU_SKY_COLOR = video::SColor(255, 140, 186, 250);
|
||||||
const float RenderingEngine::BASE_BLOOM_STRENGTH = 1.0f;
|
const float RenderingEngine::BASE_BLOOM_STRENGTH = 1.0f;
|
||||||
|
|
||||||
|
/* Helper stuff */
|
||||||
|
|
||||||
|
void FpsControl::reset()
|
||||||
|
{
|
||||||
|
last_time = porting::getTimeUs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FpsControl::limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused)
|
||||||
|
{
|
||||||
|
const float fps_limit = (device->isWindowFocused() && !assume_paused)
|
||||||
|
? g_settings->getFloat("fps_max")
|
||||||
|
: g_settings->getFloat("fps_max_unfocused");
|
||||||
|
const u64 frametime_min = 1000000.0f / std::max(fps_limit, 1.0f);
|
||||||
|
|
||||||
|
u64 time = porting::getTimeUs();
|
||||||
|
|
||||||
|
if (time > last_time) // Make sure time hasn't overflowed
|
||||||
|
busy_time = time - last_time;
|
||||||
|
else
|
||||||
|
busy_time = 0;
|
||||||
|
|
||||||
|
if (busy_time < frametime_min) {
|
||||||
|
sleep_time = frametime_min - busy_time;
|
||||||
|
if (sleep_time > 0)
|
||||||
|
sleep_us(sleep_time);
|
||||||
|
} else {
|
||||||
|
sleep_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the timer again to accurately determine how long we actually slept,
|
||||||
|
// rather than calculating it by adding sleep_time to time.
|
||||||
|
time = porting::getTimeUs();
|
||||||
|
|
||||||
|
if (time > last_time) // Make sure last_time hasn't overflowed
|
||||||
|
*dtime = (time - last_time) / 1000000.0f;
|
||||||
|
else
|
||||||
|
*dtime = 0;
|
||||||
|
|
||||||
|
last_time = time;
|
||||||
|
}
|
||||||
|
|
||||||
static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment,
|
static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment,
|
||||||
gui::EGUI_SKIN_TYPE type, video::IVideoDriver *driver)
|
gui::EGUI_SKIN_TYPE type, video::IVideoDriver *driver)
|
||||||
@ -66,7 +106,6 @@ static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment,
|
|||||||
return skin;
|
return skin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::optional<video::E_DRIVER_TYPE> chooseVideoDriver()
|
static std::optional<video::E_DRIVER_TYPE> chooseVideoDriver()
|
||||||
{
|
{
|
||||||
auto &&configured_name = g_settings->get("video_driver");
|
auto &&configured_name = g_settings->get("video_driver");
|
||||||
@ -106,6 +145,8 @@ static irr::IrrlichtDevice *createDevice(SIrrlichtCreationParameters params, std
|
|||||||
throw std::runtime_error("Could not initialize the device with any supported video driver");
|
throw std::runtime_error("Could not initialize the device with any supported video driver");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RenderingEngine class */
|
||||||
|
|
||||||
RenderingEngine::RenderingEngine(IEventReceiver *receiver)
|
RenderingEngine::RenderingEngine(IEventReceiver *receiver)
|
||||||
{
|
{
|
||||||
sanity_check(!s_singleton);
|
sanity_check(!s_singleton);
|
||||||
|
@ -46,6 +46,19 @@ class RenderingCore;
|
|||||||
// Instead of a mechanism to disable fog we just set it to be really far away
|
// Instead of a mechanism to disable fog we just set it to be really far away
|
||||||
#define FOG_RANGE_ALL (100000 * BS)
|
#define FOG_RANGE_ALL (100000 * BS)
|
||||||
|
|
||||||
|
struct FpsControl {
|
||||||
|
FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused = false);
|
||||||
|
|
||||||
|
u32 getBusyMs() const { return busy_time / 1000; }
|
||||||
|
|
||||||
|
// all values in microseconds (us)
|
||||||
|
u64 last_time, busy_time, sleep_time;
|
||||||
|
};
|
||||||
|
|
||||||
class RenderingEngine
|
class RenderingEngine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -103,11 +116,6 @@ public:
|
|||||||
return s_singleton->m_device;
|
return s_singleton->m_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 get_timer_time()
|
|
||||||
{
|
|
||||||
return m_device->getTimer()->getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
gui::IGUIEnvironment *get_gui_env()
|
gui::IGUIEnvironment *get_gui_env()
|
||||||
{
|
{
|
||||||
return m_device->getGUIEnvironment();
|
return m_device->getGUIEnvironment();
|
||||||
|
@ -315,10 +315,15 @@ void GUIEngine::run()
|
|||||||
);
|
);
|
||||||
const bool initial_window_maximized = g_settings->getBool("window_maximized");
|
const bool initial_window_maximized = g_settings->getBool("window_maximized");
|
||||||
|
|
||||||
u64 t_last_frame = porting::getTimeUs();
|
FpsControl fps_control;
|
||||||
f32 dtime = 0.0f;
|
f32 dtime = 0.0f;
|
||||||
|
|
||||||
while (m_rendering_engine->run() && (!m_startgame) && (!m_kill)) {
|
fps_control.reset();
|
||||||
|
|
||||||
|
while (m_rendering_engine->run() && !m_startgame && !m_kill) {
|
||||||
|
|
||||||
|
fps_control.limit(device, &dtime);
|
||||||
|
|
||||||
if (device->isWindowVisible()) {
|
if (device->isWindowVisible()) {
|
||||||
// check if we need to update the "upper left corner"-text
|
// check if we need to update the "upper left corner"-text
|
||||||
if (text_height != g_fontengine->getTextHeight()) {
|
if (text_height != g_fontengine->getTextHeight()) {
|
||||||
@ -328,13 +333,12 @@ void GUIEngine::run()
|
|||||||
|
|
||||||
driver->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR);
|
driver->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR);
|
||||||
|
|
||||||
if (m_clouds_enabled)
|
if (m_clouds_enabled) {
|
||||||
{
|
drawClouds(dtime);
|
||||||
cloudPreProcess();
|
|
||||||
drawOverlay(driver);
|
drawOverlay(driver);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
drawBackground(driver);
|
drawBackground(driver);
|
||||||
|
}
|
||||||
|
|
||||||
drawFooter(driver);
|
drawFooter(driver);
|
||||||
|
|
||||||
@ -349,22 +353,9 @@ void GUIEngine::run()
|
|||||||
driver->endScene();
|
driver->endScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 frametime_min = 1000 / (device->isWindowFocused()
|
|
||||||
? g_settings->getFloat("fps_max")
|
|
||||||
: g_settings->getFloat("fps_max_unfocused"));
|
|
||||||
if (m_clouds_enabled)
|
|
||||||
cloudPostProcess(frametime_min, device);
|
|
||||||
else
|
|
||||||
sleep_ms(frametime_min);
|
|
||||||
|
|
||||||
u64 t_now = porting::getTimeUs();
|
|
||||||
dtime = static_cast<f32>(t_now - t_last_frame) * 1.0e-6f;
|
|
||||||
t_last_frame = t_now;
|
|
||||||
|
|
||||||
m_script->step();
|
m_script->step();
|
||||||
|
|
||||||
sound_volume_control(m_sound_manager.get(), device->isWindowActive());
|
sound_volume_control(m_sound_manager.get(), device->isWindowActive());
|
||||||
|
|
||||||
m_sound_manager->step(dtime);
|
m_sound_manager->step(dtime);
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
@ -407,47 +398,16 @@ void GUIEngine::cloudInit()
|
|||||||
m_cloud.camera = m_smgr->addCameraSceneNode(0,
|
m_cloud.camera = m_smgr->addCameraSceneNode(0,
|
||||||
v3f(0,0,0), v3f(0, 60, 100));
|
v3f(0,0,0), v3f(0, 60, 100));
|
||||||
m_cloud.camera->setFarValue(10000);
|
m_cloud.camera->setFarValue(10000);
|
||||||
|
|
||||||
m_cloud.lasttime = m_rendering_engine->get_timer_time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void GUIEngine::cloudPreProcess()
|
void GUIEngine::drawClouds(float dtime)
|
||||||
{
|
{
|
||||||
u32 time = m_rendering_engine->get_timer_time();
|
m_cloud.clouds->step(dtime*3);
|
||||||
|
|
||||||
if(time > m_cloud.lasttime)
|
|
||||||
m_cloud.dtime = (time - m_cloud.lasttime) / 1000.0;
|
|
||||||
else
|
|
||||||
m_cloud.dtime = 0;
|
|
||||||
|
|
||||||
m_cloud.lasttime = time;
|
|
||||||
|
|
||||||
m_cloud.clouds->step(m_cloud.dtime*3);
|
|
||||||
m_cloud.clouds->render();
|
m_cloud.clouds->render();
|
||||||
m_smgr->drawAll();
|
m_smgr->drawAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
void GUIEngine::cloudPostProcess(u32 frametime_min, IrrlichtDevice *device)
|
|
||||||
{
|
|
||||||
// Time of frame without fps limit
|
|
||||||
u32 busytime_u32;
|
|
||||||
|
|
||||||
// not using getRealTime is necessary for wine
|
|
||||||
u32 time = m_rendering_engine->get_timer_time();
|
|
||||||
if(time > m_cloud.lasttime)
|
|
||||||
busytime_u32 = time - m_cloud.lasttime;
|
|
||||||
else
|
|
||||||
busytime_u32 = 0;
|
|
||||||
|
|
||||||
// FPS limit
|
|
||||||
if (busytime_u32 < frametime_min) {
|
|
||||||
u32 sleeptime = frametime_min - busytime_u32;
|
|
||||||
device->sleep(sleeptime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void GUIEngine::setFormspecPrepend(const std::string &fs)
|
void GUIEngine::setFormspecPrepend(const std::string &fs)
|
||||||
{
|
{
|
||||||
|
@ -280,16 +280,10 @@ private:
|
|||||||
/** initialize cloud subsystem */
|
/** initialize cloud subsystem */
|
||||||
void cloudInit();
|
void cloudInit();
|
||||||
/** do preprocessing for cloud subsystem */
|
/** do preprocessing for cloud subsystem */
|
||||||
void cloudPreProcess();
|
void drawClouds(float dtime);
|
||||||
/** do postprocessing for cloud subsystem */
|
|
||||||
void cloudPostProcess(u32 frametime_min, IrrlichtDevice *device);
|
|
||||||
|
|
||||||
/** internam data required for drawing clouds */
|
/** internam data required for drawing clouds */
|
||||||
struct clouddata {
|
struct clouddata {
|
||||||
/** delta time since last cloud processing */
|
|
||||||
f32 dtime;
|
|
||||||
/** absolute time of last cloud processing */
|
|
||||||
u32 lasttime;
|
|
||||||
/** pointer to cloud class */
|
/** pointer to cloud class */
|
||||||
irr_ptr<Clouds> clouds;
|
irr_ptr<Clouds> clouds;
|
||||||
/** camera required for drawing clouds */
|
/** camera required for drawing clouds */
|
||||||
|
Loading…
Reference in New Issue
Block a user