mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 10:03:45 +01:00
Rework drawtime and related timekeeping code to use microseconds
This commit is contained in:
parent
fc161e757c
commit
058846d687
@ -308,7 +308,7 @@ void Camera::addArmInertia(f32 player_yaw)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_reload_ratio)
|
void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio)
|
||||||
{
|
{
|
||||||
// Get player position
|
// Get player position
|
||||||
// Smooth the movement when walking up stairs
|
// Smooth the movement when walking up stairs
|
||||||
|
@ -140,9 +140,7 @@ public:
|
|||||||
void step(f32 dtime);
|
void step(f32 dtime);
|
||||||
|
|
||||||
// Update the camera from the local player's position.
|
// Update the camera from the local player's position.
|
||||||
// busytime is used to adjust the viewing range.
|
void update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio);
|
||||||
void update(LocalPlayer* player, f32 frametime, f32 busytime,
|
|
||||||
f32 tool_reload_ratio);
|
|
||||||
|
|
||||||
// Update render distance
|
// Update render distance
|
||||||
void updateViewingRange();
|
void updateViewingRange();
|
||||||
|
@ -575,10 +575,19 @@ public:
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
const float object_hit_delay = 0.2;
|
const static float object_hit_delay = 0.2;
|
||||||
|
|
||||||
struct FpsControl {
|
struct FpsControl {
|
||||||
u32 last_time, busy_time, sleep_time;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -712,7 +721,7 @@ protected:
|
|||||||
void updatePlayerControl(const CameraOrientation &cam);
|
void updatePlayerControl(const CameraOrientation &cam);
|
||||||
void step(f32 *dtime);
|
void step(f32 *dtime);
|
||||||
void processClientEvents(CameraOrientation *cam);
|
void processClientEvents(CameraOrientation *cam);
|
||||||
void updateCamera(u32 busy_time, f32 dtime);
|
void updateCamera(f32 dtime);
|
||||||
void updateSound(f32 dtime);
|
void updateSound(f32 dtime);
|
||||||
void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug);
|
void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug);
|
||||||
/*!
|
/*!
|
||||||
@ -743,8 +752,6 @@ protected:
|
|||||||
void updateShadows();
|
void updateShadows();
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
void limitFps(FpsControl *fps_timings, f32 *dtime);
|
|
||||||
|
|
||||||
void showOverlayMessage(const char *msg, float dtime, int percent,
|
void showOverlayMessage(const char *msg, float dtime, int percent,
|
||||||
bool draw_clouds = true);
|
bool draw_clouds = true);
|
||||||
|
|
||||||
@ -1056,14 +1063,14 @@ void Game::run()
|
|||||||
RunStats stats = { 0 };
|
RunStats stats = { 0 };
|
||||||
CameraOrientation cam_view_target = { 0 };
|
CameraOrientation cam_view_target = { 0 };
|
||||||
CameraOrientation cam_view = { 0 };
|
CameraOrientation cam_view = { 0 };
|
||||||
FpsControl draw_times = { 0 };
|
FpsControl draw_times;
|
||||||
f32 dtime; // in seconds
|
f32 dtime; // in seconds
|
||||||
|
|
||||||
/* Clear the profiler */
|
/* Clear the profiler */
|
||||||
Profiler::GraphValues dummyvalues;
|
Profiler::GraphValues dummyvalues;
|
||||||
g_profiler->graphGet(dummyvalues);
|
g_profiler->graphGet(dummyvalues);
|
||||||
|
|
||||||
draw_times.last_time = m_rendering_engine->get_timer_time();
|
draw_times.reset();
|
||||||
|
|
||||||
set_light_table(g_settings->getFloat("display_gamma"));
|
set_light_table(g_settings->getFloat("display_gamma"));
|
||||||
|
|
||||||
@ -1095,7 +1102,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
|
||||||
limitFps(&draw_times, &dtime);
|
draw_times.limit(device, &dtime);
|
||||||
|
|
||||||
// Prepare render data for next iteration
|
// Prepare render data for next iteration
|
||||||
|
|
||||||
@ -1125,7 +1132,7 @@ void Game::run()
|
|||||||
step(&dtime);
|
step(&dtime);
|
||||||
processClientEvents(&cam_view_target);
|
processClientEvents(&cam_view_target);
|
||||||
updateDebugState();
|
updateDebugState();
|
||||||
updateCamera(draw_times.busy_time, dtime);
|
updateCamera(dtime);
|
||||||
updateSound(dtime);
|
updateSound(dtime);
|
||||||
processPlayerInteraction(dtime, m_game_ui->m_flags.show_hud,
|
processPlayerInteraction(dtime, m_game_ui->m_flags.show_hud,
|
||||||
m_game_ui->m_flags.show_basic_debug);
|
m_game_ui->m_flags.show_basic_debug);
|
||||||
@ -1495,15 +1502,15 @@ bool Game::connectToServer(const GameStartData &start_data,
|
|||||||
try {
|
try {
|
||||||
input->clear();
|
input->clear();
|
||||||
|
|
||||||
FpsControl fps_control = { 0 };
|
FpsControl fps_control;
|
||||||
f32 dtime;
|
f32 dtime;
|
||||||
f32 wait_time = 0; // in seconds
|
f32 wait_time = 0; // in seconds
|
||||||
|
|
||||||
fps_control.last_time = m_rendering_engine->get_timer_time();
|
fps_control.reset();
|
||||||
|
|
||||||
while (m_rendering_engine->run()) {
|
while (m_rendering_engine->run()) {
|
||||||
|
|
||||||
limitFps(&fps_control, &dtime);
|
fps_control.limit(device, &dtime);
|
||||||
|
|
||||||
// Update client and server
|
// Update client and server
|
||||||
client->step(dtime);
|
client->step(dtime);
|
||||||
@ -1570,14 +1577,14 @@ bool Game::getServerContent(bool *aborted)
|
|||||||
{
|
{
|
||||||
input->clear();
|
input->clear();
|
||||||
|
|
||||||
FpsControl fps_control = { 0 };
|
FpsControl fps_control;
|
||||||
f32 dtime; // in seconds
|
f32 dtime; // in seconds
|
||||||
|
|
||||||
fps_control.last_time = m_rendering_engine->get_timer_time();
|
fps_control.reset();
|
||||||
|
|
||||||
while (m_rendering_engine->run()) {
|
while (m_rendering_engine->run()) {
|
||||||
|
|
||||||
limitFps(&fps_control, &dtime);
|
fps_control.limit(device, &dtime);
|
||||||
|
|
||||||
// Update client and server
|
// Update client and server
|
||||||
client->step(dtime);
|
client->step(dtime);
|
||||||
@ -1774,10 +1781,10 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update update graphs
|
// Update update graphs
|
||||||
g_profiler->graphAdd("Time non-rendering [ms]",
|
g_profiler->graphAdd("Time non-rendering [us]",
|
||||||
draw_times.busy_time - stats.drawtime);
|
draw_times.busy_time - stats.drawtime);
|
||||||
|
|
||||||
g_profiler->graphAdd("Sleep [ms]", draw_times.sleep_time);
|
g_profiler->graphAdd("Sleep [us]", draw_times.sleep_time);
|
||||||
g_profiler->graphAdd("FPS", 1.0f / dtime);
|
g_profiler->graphAdd("FPS", 1.0f / dtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1810,9 +1817,9 @@ void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
|
|||||||
/* Busytime average and jitter calculation
|
/* Busytime average and jitter calculation
|
||||||
*/
|
*/
|
||||||
jp = &stats->busy_time_jitter;
|
jp = &stats->busy_time_jitter;
|
||||||
jp->avg = jp->avg + draw_times.busy_time * 0.02;
|
jp->avg = jp->avg + draw_times.getBusyMs() * 0.02;
|
||||||
|
|
||||||
jitter = draw_times.busy_time - jp->avg;
|
jitter = draw_times.getBusyMs() - jp->avg;
|
||||||
|
|
||||||
if (jitter > jp->max)
|
if (jitter > jp->max)
|
||||||
jp->max = jitter;
|
jp->max = jitter;
|
||||||
@ -2932,7 +2939,7 @@ void Game::updateChat(f32 dtime)
|
|||||||
m_game_ui->updateChatSize();
|
m_game_ui->updateChatSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::updateCamera(u32 busy_time, f32 dtime)
|
void Game::updateCamera(f32 dtime)
|
||||||
{
|
{
|
||||||
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||||
|
|
||||||
@ -2971,7 +2978,7 @@ void Game::updateCamera(u32 busy_time, f32 dtime)
|
|||||||
float tool_reload_ratio = runData.time_from_last_punch / full_punch_interval;
|
float tool_reload_ratio = runData.time_from_last_punch / full_punch_interval;
|
||||||
|
|
||||||
tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
|
tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
|
||||||
camera->update(player, dtime, busy_time / 1000.0f, tool_reload_ratio);
|
camera->update(player, dtime, tool_reload_ratio);
|
||||||
camera->step(dtime);
|
camera->step(dtime);
|
||||||
|
|
||||||
v3f camera_position = camera->getPosition();
|
v3f camera_position = camera->getPosition();
|
||||||
@ -3847,6 +3854,24 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Damage camera tilt
|
||||||
|
*/
|
||||||
|
if (player->hurt_tilt_timer > 0.0f) {
|
||||||
|
player->hurt_tilt_timer -= dtime * 6.0f;
|
||||||
|
|
||||||
|
if (player->hurt_tilt_timer < 0.0f)
|
||||||
|
player->hurt_tilt_strength = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Update minimap pos and rotation
|
||||||
|
*/
|
||||||
|
if (mapper && m_game_ui->m_flags.show_hud) {
|
||||||
|
mapper->setPos(floatToInt(player->getPosition(), BS));
|
||||||
|
mapper->setAngle(player->getYaw());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get chat messages from client
|
Get chat messages from client
|
||||||
*/
|
*/
|
||||||
@ -3920,11 +3945,11 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Drawing begins
|
==================== Drawing begins ====================
|
||||||
*/
|
*/
|
||||||
const video::SColor &skycolor = sky->getSkyColor();
|
const video::SColor skycolor = sky->getSkyColor();
|
||||||
|
|
||||||
TimeTaker tt_draw("Draw scene");
|
TimeTaker tt_draw("Draw scene", nullptr, PRECISION_MICRO);
|
||||||
driver->beginScene(true, true, skycolor);
|
driver->beginScene(true, true, skycolor);
|
||||||
|
|
||||||
bool draw_wield_tool = (m_game_ui->m_flags.show_hud &&
|
bool draw_wield_tool = (m_game_ui->m_flags.show_hud &&
|
||||||
@ -3963,25 +3988,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Damage camera tilt
|
==================== End scene ====================
|
||||||
*/
|
|
||||||
if (player->hurt_tilt_timer > 0.0f) {
|
|
||||||
player->hurt_tilt_timer -= dtime * 6.0f;
|
|
||||||
|
|
||||||
if (player->hurt_tilt_timer < 0.0f)
|
|
||||||
player->hurt_tilt_strength = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Update minimap pos and rotation
|
|
||||||
*/
|
|
||||||
if (mapper && m_game_ui->m_flags.show_hud) {
|
|
||||||
mapper->setPos(floatToInt(player->getPosition(), BS));
|
|
||||||
mapper->setAngle(player->getYaw());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
End scene
|
|
||||||
*/
|
*/
|
||||||
if (++m_reset_HW_buffer_counter > 500) {
|
if (++m_reset_HW_buffer_counter > 500) {
|
||||||
/*
|
/*
|
||||||
@ -4004,11 +4011,12 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||||||
driver->removeAllHardwareBuffers();
|
driver->removeAllHardwareBuffers();
|
||||||
m_reset_HW_buffer_counter = 0;
|
m_reset_HW_buffer_counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
driver->endScene();
|
driver->endScene();
|
||||||
|
|
||||||
stats->drawtime = tt_draw.stop(true);
|
stats->drawtime = tt_draw.stop(true);
|
||||||
g_profiler->avg("Game::updateFrame(): draw scene [ms]", stats->drawtime);
|
g_profiler->graphAdd("Draw scene [us]", stats->drawtime);
|
||||||
g_profiler->graphAdd("Update frame [ms]", tt_update.stop(true));
|
g_profiler->avg("Game::updateFrame(): update frame [ms]", tt_update.stop(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Log times and stuff for visualization */
|
/* Log times and stuff for visualization */
|
||||||
@ -4052,47 +4060,46 @@ void Game::updateShadows()
|
|||||||
Misc
|
Misc
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* On some computers framerate doesn't seem to be automatically limited
|
void FpsControl::reset()
|
||||||
*/
|
|
||||||
inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
|
|
||||||
{
|
{
|
||||||
// not using getRealTime is necessary for wine
|
last_time = porting::getTimeUs();
|
||||||
device->getTimer()->tick(); // Maker sure device time is up-to-date
|
}
|
||||||
u32 time = device->getTimer()->getTime();
|
|
||||||
u32 last_time = fps_timings->last_time;
|
|
||||||
|
|
||||||
if (time > last_time) // Make sure time hasn't overflowed
|
/*
|
||||||
fps_timings->busy_time = time - last_time;
|
* On some computers framerate doesn't seem to be automatically limited
|
||||||
else
|
*/
|
||||||
fps_timings->busy_time = 0;
|
void FpsControl::limit(IrrlichtDevice *device, f32 *dtime)
|
||||||
|
{
|
||||||
u32 frametime_min = 1000 / (
|
const u64 frametime_min = 1000000.0f / (
|
||||||
device->isWindowFocused() && !g_menumgr.pausesGame()
|
device->isWindowFocused() && !g_menumgr.pausesGame()
|
||||||
? g_settings->getFloat("fps_max")
|
? g_settings->getFloat("fps_max")
|
||||||
: g_settings->getFloat("fps_max_unfocused"));
|
: g_settings->getFloat("fps_max_unfocused"));
|
||||||
|
|
||||||
if (fps_timings->busy_time < frametime_min) {
|
u64 time = porting::getTimeUs();
|
||||||
fps_timings->sleep_time = frametime_min - fps_timings->busy_time;
|
|
||||||
device->sleep(fps_timings->sleep_time);
|
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 > 1000)
|
||||||
|
sleep_ms(sleep_time / 1000);
|
||||||
} else {
|
} else {
|
||||||
fps_timings->sleep_time = 0;
|
sleep_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the new value of the device timer. Note that device->sleep() may
|
// Read the timer again to accurately determine how long we actually slept,
|
||||||
* not sleep for the entire requested time as sleep may be interrupted and
|
// rather than calculating it by adding sleep_time to time.
|
||||||
* therefore it is arguably more accurate to get the new time from the
|
time = porting::getTimeUs();
|
||||||
* device rather than calculating it by adding sleep_time to time.
|
|
||||||
*/
|
|
||||||
|
|
||||||
device->getTimer()->tick(); // Update device timer
|
|
||||||
time = device->getTimer()->getTime();
|
|
||||||
|
|
||||||
if (time > last_time) // Make sure last_time hasn't overflowed
|
if (time > last_time) // Make sure last_time hasn't overflowed
|
||||||
*dtime = (time - last_time) / 1000.0;
|
*dtime = (time - last_time) / 1000000.0f;
|
||||||
else
|
else
|
||||||
*dtime = 0;
|
*dtime = 0;
|
||||||
|
|
||||||
fps_timings->last_time = time;
|
last_time = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_clouds)
|
void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_clouds)
|
||||||
|
@ -33,7 +33,7 @@ struct Jitter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RunStats {
|
struct RunStats {
|
||||||
u32 drawtime;
|
u64 drawtime; // (us)
|
||||||
|
|
||||||
Jitter dtime_jitter, busy_time_jitter;
|
Jitter dtime_jitter, busy_time_jitter;
|
||||||
};
|
};
|
||||||
|
@ -104,16 +104,16 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
|||||||
|
|
||||||
// Minimal debug text must only contain info that can't give a gameplay advantage
|
// Minimal debug text must only contain info that can't give a gameplay advantage
|
||||||
if (m_flags.show_minimal_debug) {
|
if (m_flags.show_minimal_debug) {
|
||||||
static float drawtime_avg = 0;
|
const u16 fps = 1.0 / stats.dtime_jitter.avg;
|
||||||
drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
|
m_drawtime_avg *= 0.95f;
|
||||||
u16 fps = 1.0 / stats.dtime_jitter.avg;
|
m_drawtime_avg += 0.05f * (stats.drawtime / 1000);
|
||||||
|
|
||||||
std::ostringstream os(std::ios_base::binary);
|
std::ostringstream os(std::ios_base::binary);
|
||||||
os << std::fixed
|
os << std::fixed
|
||||||
<< PROJECT_NAME_C " " << g_version_hash
|
<< PROJECT_NAME_C " " << g_version_hash
|
||||||
<< " | FPS: " << fps
|
<< " | FPS: " << fps
|
||||||
<< std::setprecision(0)
|
<< std::setprecision(0)
|
||||||
<< " | drawtime: " << drawtime_avg << "ms"
|
<< " | drawtime: " << m_drawtime_avg << "ms"
|
||||||
<< std::setprecision(1)
|
<< std::setprecision(1)
|
||||||
<< " | dtime jitter: "
|
<< " | dtime jitter: "
|
||||||
<< (stats.dtime_jitter.max_fraction * 100.0) << "%"
|
<< (stats.dtime_jitter.max_fraction * 100.0) << "%"
|
||||||
|
@ -110,6 +110,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
Flags m_flags;
|
Flags m_flags;
|
||||||
|
|
||||||
|
float m_drawtime_avg = 0;
|
||||||
|
|
||||||
gui::IGUIStaticText *m_guitext = nullptr; // First line of debug text
|
gui::IGUIStaticText *m_guitext = nullptr; // First line of debug text
|
||||||
gui::IGUIStaticText *m_guitext2 = nullptr; // Second line of debug text
|
gui::IGUIStaticText *m_guitext2 = nullptr; // Second line of debug text
|
||||||
|
|
||||||
|
@ -94,20 +94,29 @@ void ProfilerGraph::draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
|
|||||||
show_min = 0;
|
show_min = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 texth = 15;
|
const s32 texth = 15;
|
||||||
char buf[10];
|
char buf[10];
|
||||||
|
if (floorf(show_max) == show_max)
|
||||||
|
porting::mt_snprintf(buf, sizeof(buf), "%.5g", show_max);
|
||||||
|
else
|
||||||
porting::mt_snprintf(buf, sizeof(buf), "%.3g", show_max);
|
porting::mt_snprintf(buf, sizeof(buf), "%.3g", show_max);
|
||||||
font->draw(utf8_to_wide(buf).c_str(),
|
font->draw(utf8_to_wide(buf).c_str(),
|
||||||
core::rect<s32>(textx, y - graphh, textx2,
|
core::rect<s32>(textx, y - graphh, textx2,
|
||||||
y - graphh + texth),
|
y - graphh + texth),
|
||||||
meta.color);
|
meta.color);
|
||||||
|
|
||||||
|
if (floorf(show_min) == show_min)
|
||||||
|
porting::mt_snprintf(buf, sizeof(buf), "%.5g", show_min);
|
||||||
|
else
|
||||||
porting::mt_snprintf(buf, sizeof(buf), "%.3g", show_min);
|
porting::mt_snprintf(buf, sizeof(buf), "%.3g", show_min);
|
||||||
font->draw(utf8_to_wide(buf).c_str(),
|
font->draw(utf8_to_wide(buf).c_str(),
|
||||||
core::rect<s32>(textx, y - texth, textx2, y), meta.color);
|
core::rect<s32>(textx, y - texth, textx2, y), meta.color);
|
||||||
|
|
||||||
font->draw(utf8_to_wide(id).c_str(),
|
font->draw(utf8_to_wide(id).c_str(),
|
||||||
core::rect<s32>(textx, y - graphh / 2 - texth / 2, textx2,
|
core::rect<s32>(textx, y - graphh / 2 - texth / 2, textx2,
|
||||||
y - graphh / 2 + texth / 2),
|
y - graphh / 2 + texth / 2),
|
||||||
meta.color);
|
meta.color);
|
||||||
|
|
||||||
s32 graph1y = y;
|
s32 graph1y = y;
|
||||||
s32 graph1h = graphh;
|
s32 graph1h = graphh;
|
||||||
bool relativegraph = (show_min != 0 && show_min != show_max);
|
bool relativegraph = (show_min != 0 && show_min != show_max);
|
||||||
|
Loading…
Reference in New Issue
Block a user