renderer changes, time and environment window

This commit is contained in:
milek7
2019-03-09 14:18:10 +01:00
parent 748e7b1dda
commit 3693c1660e
30 changed files with 299 additions and 93 deletions

View File

@@ -127,6 +127,7 @@ set(SOURCES
"widgets/map.cpp"
"widgets/map_objects.cpp"
"widgets/popup.cpp"
"widgets/time.cpp"
"ref/glad/src/glad.c"

View File

@@ -29,6 +29,7 @@ struct global_settings {
std::mt19937 random_engine;
std::mt19937 local_random_engine;
bool ready_to_load { false };
std::time_t starting_timestamp = 0; // starting time, in local timezone
uint32_t random_seed = 0;
TCamera pCamera; // parametry kamery
TCamera pDebugCamera;
@@ -73,8 +74,7 @@ struct global_settings {
float FrictionWeatherFactor { 1.f };
bool bLiveTraction{ true };
float Overcast{ 0.1f }; // NOTE: all this weather stuff should be moved elsewhere
glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f };
double fFogStart{ 1700 };
glm::vec3 FogColor = { 0.6f, 0.7f, 0.8f };
double fFogEnd{ 2000 };
std::string Season{}; // season of the year, based on simulation date
std::string Weather{ "cloudy:" }; // current weather

View File

@@ -63,7 +63,7 @@ void UpdateTimers(bool pause)
QueryPerformanceCounter((LARGE_INTEGER *)&count);
#elif __linux__
timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
clock_gettime(CLOCK_MONOTONIC, &ts);
count = (uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec;
fr = 1000000000;
#endif

View File

@@ -767,6 +767,12 @@ bool eu07_application::init_network() {
if (!Global.random_seed)
Global.random_seed = std::random_device{}();
Global.random_engine.seed(Global.random_seed);
// TODO: sort out this timezone mess
std::time_t utc_now = std::time(nullptr);
std::time_t local_now = utc_now + (std::mktime(std::localtime(&utc_now)) - std::mktime(std::gmtime(&utc_now)));
Global.starting_timestamp = local_now;
Global.ready_to_load = true;
}

View File

@@ -227,6 +227,9 @@ commanddescription_sequence Commands_descriptions = {
{ "timejump", command_target::simulation, command_mode::oneoff },
{ "timejumplarge", command_target::simulation, command_mode::oneoff },
{ "timejumpsmall", command_target::simulation, command_mode::oneoff },
{ "setdatetime", command_target::simulation, command_mode::oneoff },
{ "setweather", command_target::simulation, command_mode::oneoff },
{ "settemperature", command_target::simulation, command_mode::oneoff },
{ "vehiclemove", command_target::vehicle, command_mode::oneoff },
{ "vehiclemoveforwards", command_target::vehicle, command_mode::oneoff },
{ "vehiclemovebackwards", command_target::vehicle, command_mode::oneoff },

View File

@@ -221,6 +221,9 @@ enum class user_command {
timejump,
timejumplarge,
timejumpsmall,
setdatetime,
setweather,
settemperature,
vehiclemove,
vehiclemoveforwards,
vehiclemovebackwards,

View File

@@ -28,6 +28,7 @@ driver_ui::driver_ui() {
push_back( &m_transcriptspanel );
//push_back( &m_vehiclelist );
push_back( &m_timepanel );
push_back( &m_mappanel );
push_back( &m_logpanel );
m_logpanel.is_open = false;
@@ -52,6 +53,10 @@ void driver_ui::render_menu_contents() {
ImGui::MenuItem(m_timetablepanel.title.c_str(), "F2", &m_timetablepanel.is_open);
ImGui::MenuItem(m_debugpanel.get_name().c_str(), "F12", &m_debugpanel.is_open);
ImGui::MenuItem(m_mappanel.get_name().c_str(), "Tab", &m_mappanel.is_open);
if (ImGui::MenuItem(m_timepanel.get_name().c_str()))
m_timepanel.open();
ImGui::EndMenu();
}
}

View File

@@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/.
#include "widgets/vehiclelist.h"
#include "widgets/map.h"
#include "widgets/time.h"
class driver_ui : public ui_layer {
@@ -58,4 +59,5 @@ private:
command_relay m_relay;
ui::vehiclelist_panel m_vehiclelist;
ui::map_panel m_mappanel;
ui::time_panel m_timepanel;
};

View File

@@ -16,11 +16,13 @@ void network::client_hello::deserialize(std::istream &stream)
void network::server_hello::serialize(std::ostream &stream) const
{
sn_utils::ls_uint32(stream, seed);
sn_utils::ls_int64(stream, timestamp);
}
void network::server_hello::deserialize(std::istream &stream)
{
seed = sn_utils::ld_uint32(stream);
timestamp = sn_utils::ld_int64(stream);
}
void ::network::request_command::serialize(std::ostream &stream) const

View File

@@ -39,6 +39,7 @@ struct server_hello : public message
server_hello() : message(SERVER_HELLO) {}
uint32_t seed;
int64_t timestamp;
virtual void serialize(std::ostream &stream) const override;
virtual void deserialize(std::istream &stream) override;

View File

@@ -122,6 +122,7 @@ void network::server::handle_message(std::shared_ptr<connection> conn, const mes
server_hello reply;
reply.seed = Global.random_seed;
reply.timestamp = Global.starting_timestamp;
conn->state = connection::CATCHING_UP;
conn->backbuffer = backbuffer;
conn->backbuffer_pos = 0;
@@ -229,6 +230,7 @@ void network::client::handle_message(std::shared_ptr<connection> conn, const mes
if (!Global.ready_to_load) {
Global.random_seed = cmd.seed;
Global.random_engine.seed(Global.random_seed);
Global.starting_timestamp = cmd.timestamp;
Global.ready_to_load = true;
} else if (Global.random_seed != cmd.seed) {
ErrorLog("net: seed mismatch", logtype::net);

View File

@@ -90,24 +90,28 @@ basic_precipitation::init() {
create( 18 );
// TODO: select texture based on current overcast level
// TODO: when the overcast level dynamic change is in check the current level during render and pick the appropriate texture on the fly
std::string const densitysuffix { (
Global.Overcast < 1.35 ?
"_light" :
"_medium" ) };
if( Global.Weather == "rain:" ) {
m_moverateweathertypefactor = 2.f;
m_texture = GfxRenderer.Fetch_Texture( "fx/rain" + densitysuffix );
}
else if( Global.Weather == "snow:" ) {
m_moverateweathertypefactor = 1.25f;
m_texture = GfxRenderer.Fetch_Texture( "fx/snow" + densitysuffix );
}
return true;
}
void
basic_precipitation::update_weather() {
// TODO: select texture based on current overcast level
// TODO: when the overcast level dynamic change is in check the current level during render and pick the appropriate texture on the fly
std::string const densitysuffix { (
Global.Overcast < 1.35 ?
"_light" :
"_medium" ) };
if( Global.Weather == "rain:" ) {
m_moverateweathertypefactor = 2.f;
m_texture = GfxRenderer.Fetch_Texture( "fx/rain" + densitysuffix );
}
else if( Global.Weather == "snow:" ) {
m_moverateweathertypefactor = 1.25f;
m_texture = GfxRenderer.Fetch_Texture( "fx/snow" + densitysuffix );
}
}
void
basic_precipitation::update() {

View File

@@ -26,11 +26,14 @@ public:
// methods
bool
init();
void
update_weather();
void
update();
void
render();
float get_textureoffset();
float
get_textureoffset();
glm::dvec3 m_cameramove{ 0.0 };

View File

@@ -195,9 +195,26 @@ bool opengl_renderer::Init(GLFWwindow *Window)
m_empty_cubemap = std::make_unique<gl::cubemap>();
m_empty_cubemap->alloc(Global.gfx_format_color, 16, 16, GL_RGB, GL_FLOAT);
m_current_viewport = &default_viewport;
if (!init_viewport(default_viewport))
return false;
m_viewports.push_back(std::make_unique<viewport_config>());
viewport_config &default_viewport = *m_viewports.front().get();
default_viewport.width = Global.gfx_framebuffer_width;
default_viewport.height = Global.gfx_framebuffer_height;
/*
default_viewport.camera_transform = glm::rotate(glm::mat4(), 0.5f, glm::vec3(1.0f, 0.0f, 0.f));
m_viewports.push_back(std::make_unique<viewport_config>());
viewport_config &vp2 = *m_viewports.back().get();
vp2.width = Global.gfx_framebuffer_width;
vp2.height = Global.gfx_framebuffer_height;
vp2.camera_transform = glm::rotate(glm::mat4(), -0.5f, glm::vec3(1.0f, 0.0f, 0.f));
*/
for (auto &viewport : m_viewports) {
if (!init_viewport(*viewport.get()))
return false;
}
m_pick_tex = std::make_unique<opengl_texture>();
m_pick_tex->alloc_rendertarget(GL_RGB8, GL_RGB, EU07_PICKBUFFERSIZE, EU07_PICKBUFFERSIZE);
@@ -271,17 +288,17 @@ bool opengl_renderer::Init(GLFWwindow *Window)
return true;
}
bool opengl_renderer::init_viewport(viewport_data &vp)
bool opengl_renderer::init_viewport(viewport_config &vp)
{
int samples = 1 << Global.iMultisampling;
if (!Global.gfx_skippipeline)
{
vp.msaa_rbc = std::make_unique<gl::renderbuffer>();
vp.msaa_rbc->alloc(Global.gfx_format_color, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, samples);
vp.msaa_rbc->alloc(Global.gfx_format_color, vp.width, vp.height, samples);
vp.msaa_rbd = std::make_unique<gl::renderbuffer>();
vp.msaa_rbd->alloc(Global.gfx_format_depth, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, samples);
vp.msaa_rbd->alloc(Global.gfx_format_depth, vp.width, vp.height, samples);
vp.msaa_fb = std::make_unique<gl::framebuffer>();
vp.msaa_fb->attach(*vp.msaa_rbc, GL_COLOR_ATTACHMENT0);
@@ -290,17 +307,17 @@ bool opengl_renderer::init_viewport(viewport_data &vp)
if (Global.gfx_postfx_motionblur_enabled)
{
vp.msaa_rbv = std::make_unique<gl::renderbuffer>();
vp.msaa_rbv->alloc(Global.gfx_postfx_motionblur_format, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, samples);
vp.msaa_rbv->alloc(Global.gfx_postfx_motionblur_format, vp.width, vp.height, samples);
vp.msaa_fb->attach(*vp.msaa_rbv, GL_COLOR_ATTACHMENT1);
vp.main_tex = std::make_unique<opengl_texture>();
vp.main_tex->alloc_rendertarget(Global.gfx_format_color, GL_RGB, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, 1, GL_CLAMP_TO_EDGE);
vp.main_tex->alloc_rendertarget(Global.gfx_format_color, GL_RGB, vp.width, vp.height, 1, GL_CLAMP_TO_EDGE);
vp.main_fb = std::make_unique<gl::framebuffer>();
vp.main_fb->attach(*vp.main_tex, GL_COLOR_ATTACHMENT0);
vp.main_texv = std::make_unique<opengl_texture>();
vp.main_texv->alloc_rendertarget(Global.gfx_postfx_motionblur_format, GL_RG, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height);
vp.main_texv->alloc_rendertarget(Global.gfx_postfx_motionblur_format, GL_RG, vp.width, vp.height);
vp.main_fb->attach(*vp.main_texv, GL_COLOR_ATTACHMENT1);
vp.main_fb->setup_drawing(2);
@@ -314,7 +331,7 @@ bool opengl_renderer::init_viewport(viewport_data &vp)
return false;
vp.main2_tex = std::make_unique<opengl_texture>();
vp.main2_tex->alloc_rendertarget(Global.gfx_format_color, GL_RGB, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height);
vp.main2_tex->alloc_rendertarget(Global.gfx_format_color, GL_RGB, vp.width, vp.height);
vp.main2_fb = std::make_unique<gl::framebuffer>();
vp.main2_fb->attach(*vp.main2_tex, GL_COLOR_ATTACHMENT0);
@@ -412,7 +429,10 @@ bool opengl_renderer::Render()
m_renderpass.draw_mode = rendermode::none; // force setup anew
m_debugstats = debug_stats();
Render_pass(default_viewport, rendermode::color);
for (auto &viewport : m_viewports) {
Render_pass(*viewport.get(), rendermode::color);
}
//Render_pass(*m_viewports.front().get(), rendermode::color);
m_drawcount = m_cellqueue.size();
m_debugtimestext.clear();
@@ -475,9 +495,9 @@ void opengl_renderer::draw_debug_ui()
}
// runs jobs needed to generate graphics for specified render pass
void opengl_renderer::Render_pass(viewport_data &vp, rendermode const Mode)
void opengl_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
{
setup_pass(m_renderpass, Mode);
setup_pass(vp, m_renderpass, Mode);
switch (m_renderpass.draw_mode)
{
@@ -520,7 +540,7 @@ void opengl_renderer::Render_pass(viewport_data &vp, rendermode const Mode)
Render_pass(vp, rendermode::shadows);
if (!FreeFlyModeFlag)
Render_pass(vp, rendermode::cabshadows);
setup_pass(m_renderpass, Mode); // restore draw mode. TBD, TODO: render mode stack
setup_pass(vp, m_renderpass, Mode); // restore draw mode. TBD, TODO: render mode stack
Timer::subsystem.gfx_shadows.stop();
glDebug("render shadowmap end");
@@ -530,7 +550,7 @@ void opengl_renderer::Render_pass(viewport_data &vp, rendermode const Mode)
{
// potentially update environmental cube map
if (Render_reflections(vp))
setup_pass(m_renderpass, Mode); // restore color pass settings
setup_pass(vp, m_renderpass, Mode); // restore color pass settings
setup_env_map(vp.env_tex.get());
}
@@ -851,7 +871,7 @@ void opengl_renderer::Render_pass(viewport_data &vp, rendermode const Mode)
}
// creates dynamic environment cubemap
bool opengl_renderer::Render_reflections(viewport_data &vp)
bool opengl_renderer::Render_reflections(viewport_config &vp)
{
if (Global.ReflectionUpdatesPerSecond == 0)
return false;
@@ -943,7 +963,8 @@ glm::mat4 opengl_renderer::ortho_frustumtest_projection(float l, float r, float
return glm::ortho(l, r, b, t, znear, zfar);
}
void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mode, float const Znear, float const Zfar, bool const Ignoredebug)
void opengl_renderer::setup_pass(viewport_config &Viewport, renderpass_config &Config, rendermode const Mode,
float const Znear, float const Zfar, bool const Ignoredebug)
{
Config.draw_mode = Mode;
@@ -1001,10 +1022,14 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
float const fovy = glm::radians(Global.FieldOfView / Global.ZoomFactor);
float const aspect = std::max(1.f, (float)Global.iWindowWidth) / std::max(1.f, (float)Global.iWindowHeight);
Config.viewport_camera.position() = Global.pCamera.Pos;
switch (Mode)
{
case rendermode::color:
{
viewmatrix = glm::dmat4(Viewport.camera_transform);
// modelview
if ((false == DebugCameraFlag) || (true == Ignoredebug))
{
@@ -1016,6 +1041,7 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
camera.position() = Global.pDebugCamera.Pos;
Global.pDebugCamera.SetMatrix(viewmatrix);
}
// projection
auto const zfar = Config.draw_range * Global.fDistanceFactor * Zfar;
auto const znear = (Znear > 0.f ? Znear * zfar : 0.1f * Global.ZoomFactor);
@@ -1030,7 +1056,7 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
// ...setup chunk of frustum we're interested in...
auto const zfar = std::min(1.f, Global.shadowtune.depth / (Global.BaseDrawRange * Global.fDistanceFactor) * std::max(1.f, Global.ZoomFactor * 0.5f));
renderpass_config worldview;
setup_pass(worldview, rendermode::color, 0.f, zfar, true);
setup_pass(Viewport, worldview, rendermode::color, 0.f, zfar, true);
auto &frustumchunkshapepoints = worldview.pass_camera.frustum_points();
// ...modelview matrix: determine the centre of frustum chunk in world space...
glm::vec3 frustumchunkmin, frustumchunkmax;
@@ -1110,9 +1136,12 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
case rendermode::pickcontrols:
case rendermode::pickscenery:
{
viewmatrix = glm::dmat4(Viewport.camera_transform);
// modelview
camera.position() = Global.pCamera.Pos;
Global.pCamera.SetMatrix(viewmatrix);
// projection
float znear = 0.1f * Global.ZoomFactor;
float zfar = Config.draw_range * Global.fDistanceFactor;
@@ -1998,7 +2027,7 @@ void opengl_renderer::Render(scene::shape_node const &Shape, bool const Ignorera
case rendermode::shadows:
{
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = Math3D::SquareMagnitude((data.area.center - Global.pCamera.Pos) / Global.ZoomFactor) / Global.fDistanceFactor;
distancesquared = Math3D::SquareMagnitude((data.area.center - m_renderpass.viewport_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
break;
}
default:
@@ -2052,7 +2081,7 @@ void opengl_renderer::Render(TAnimModel *Instance)
case rendermode::shadows:
{
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = Math3D::SquareMagnitude((Instance->location() - Global.pCamera.Pos) / Global.ZoomFactor) / Global.fDistanceFactor;
distancesquared = Math3D::SquareMagnitude((Instance->location() - m_renderpass.viewport_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
break;
}
default:
@@ -2110,7 +2139,7 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
{
case rendermode::shadows:
{
squaredistance = glm::length2(glm::vec3{glm::dvec3{Dynamic->vPosition - Global.pCamera.Pos}} / Global.ZoomFactor) / Global.fDistanceFactor;
squaredistance = glm::length2(glm::vec3{glm::dvec3{Dynamic->vPosition - m_renderpass.viewport_camera.position()}} / Global.ZoomFactor) / Global.fDistanceFactor;
break;
}
default:
@@ -3430,7 +3459,7 @@ void opengl_renderer::Update_Pick_Control()
pickbufferpos = glm::ivec2{mousepos.x * EU07_PICKBUFFERSIZE / std::max(1, Global.iWindowWidth), mousepos.y * EU07_PICKBUFFERSIZE / std::max(1, Global.iWindowHeight)};
pickbufferpos = glm::clamp(pickbufferpos, glm::ivec2(0, 0), glm::ivec2(EU07_PICKBUFFERSIZE - 1, EU07_PICKBUFFERSIZE - 1));
Render_pass(default_viewport, rendermode::pickcontrols);
Render_pass(*m_viewports.front().get(), rendermode::pickcontrols);
m_pick_fb->bind();
m_picking_pbo->request_read(pickbufferpos.x, pickbufferpos.y, 1, 1);
m_pick_fb->unbind();
@@ -3469,7 +3498,7 @@ void opengl_renderer::Update_Pick_Node()
pickbufferpos = glm::ivec2{mousepos.x * EU07_PICKBUFFERSIZE / std::max(1, Global.iWindowWidth), mousepos.y * EU07_PICKBUFFERSIZE / std::max(1, Global.iWindowHeight)};
pickbufferpos = glm::clamp(pickbufferpos, glm::ivec2(0, 0), glm::ivec2(EU07_PICKBUFFERSIZE - 1, EU07_PICKBUFFERSIZE - 1));
Render_pass(default_viewport, rendermode::pickscenery);
Render_pass(*m_viewports.front().get(), rendermode::pickscenery);
m_pick_fb->bind();
m_picking_node_pbo->request_read(pickbufferpos.x, pickbufferpos.y, 1, 1);
m_pick_fb->unbind();

View File

@@ -235,7 +235,12 @@ class opengl_renderer
float draw_range{0.0f};
};
struct viewport_data {
struct viewport_config {
int width;
int height;
glm::mat4 camera_transform;
std::unique_ptr<gl::framebuffer> msaa_fb;
std::unique_ptr<gl::renderbuffer> msaa_rbc;
std::unique_ptr<gl::renderbuffer> msaa_rbv;
@@ -264,16 +269,16 @@ class opengl_renderer
// methods
std::unique_ptr<gl::program> make_shader(std::string v, std::string f);
bool Init_caps();
void setup_pass(renderpass_config &Config, rendermode const Mode, float const Znear = 0.f, float const Zfar = 1.f, bool const Ignoredebug = false);
void setup_pass(viewport_config &Viewport, renderpass_config &Config, rendermode const Mode, float const Znear = 0.f, float const Zfar = 1.f, bool const Ignoredebug = false);
void setup_matrices();
void setup_drawing(bool const Alpha = false);
void setup_shadow_map(opengl_texture *tex, renderpass_config conf);
void setup_env_map(gl::cubemap *tex);
void setup_environment_light(TEnvironmentType const Environment = e_flat);
// runs jobs needed to generate graphics for specified render pass
void Render_pass(viewport_data &vp, rendermode const Mode);
void Render_pass(viewport_config &vp, rendermode const Mode);
// creates dynamic environment cubemap
bool Render_reflections(viewport_data &vp);
bool Render_reflections(viewport_config &vp);
bool Render(world_environment *Environment);
void Render(scene::basic_region *Region);
void Render(section_sequence::iterator First, section_sequence::iterator Last);
@@ -302,7 +307,7 @@ class opengl_renderer
glm::vec3 pick_color(std::size_t const Index);
std::size_t pick_index(glm::ivec3 const &Color);
bool init_viewport(viewport_data &vp);
bool init_viewport(viewport_config &vp);
void draw(const gfx::geometry_handle &handle);
void draw(std::vector<gfx::geometrybank_handle>::iterator begin, std::vector<gfx::geometrybank_handle>::iterator end);
@@ -350,7 +355,7 @@ class opengl_renderer
float m_fogrange = 2000.0f;
renderpass_config m_renderpass; // parameters for current render pass
viewport_data *m_current_viewport; // active viewport
viewport_config *m_current_viewport; // active viewport
section_sequence m_sectionqueue; // list of sections in current render pass
cell_sequence m_cellqueue;
renderpass_config m_colorpass; // parametrs of most recent color pass
@@ -395,7 +400,7 @@ class opengl_renderer
std::unique_ptr<gl::vao> m_empty_vao;
viewport_data default_viewport;
std::vector<std::unique_ptr<viewport_config>> m_viewports;
std::unique_ptr<gl::postfx> m_pfx_motionblur;
std::unique_ptr<gl::postfx> m_pfx_tonemapping;

View File

@@ -91,6 +91,6 @@ scenarioloader_mode::enter() {
void
scenarioloader_mode::exit() {
simulation::Time.init();
simulation::Time.init(Global.starting_timestamp);
simulation::Environment.init();
}

View File

@@ -130,7 +130,7 @@ void state_manager::process_commands() {
if (commanddata.command == user_command::queueevent) {
uint32_t id = std::round(commanddata.param1);
basic_event *ev = Events.FindEventById(id);
basic_event *ev = Events.FindEventById(id); // TODO: depends on vector position
Events.AddToQuery(ev, nullptr);
}
@@ -139,7 +139,26 @@ void state_manager::process_commands() {
int light = std::round(commanddata.param1);
float state = commanddata.param2;
if (id < simulation::Instances.sequence().size())
simulation::Instances.sequence()[id]->LightSet(light, state);
simulation::Instances.sequence()[id]->LightSet(light, state); // TODO: depends on vector position
}
if (commanddata.command == user_command::setdatetime) {
int yearday = std::round(commanddata.param1);
int minute = std::round(commanddata.param2 * 60.0);
simulation::Time.set_time(yearday, minute);
simulation::Environment.compute_season(yearday);
}
if (commanddata.command == user_command::setweather) {
Global.fFogEnd = commanddata.param1;
Global.Overcast = commanddata.param2;
simulation::Environment.compute_weather();
}
if (commanddata.command == user_command::settemperature) {
Global.AirTemperature = commanddata.param1;
}
if (DebugModeFlag) {

View File

@@ -35,7 +35,7 @@ world_environment::toggle_daylight() {
// calculates current season of the year based on set simulation date
void
world_environment::compute_season( int const Yearday ) const {
world_environment::compute_season( int const Yearday ) {
using dayseasonpair = std::pair<int, std::string>;
@@ -59,7 +59,7 @@ world_environment::compute_season( int const Yearday ) const {
// calculates current weather
void
world_environment::compute_weather() const {
world_environment::compute_weather() {
Global.Weather = (
Global.Overcast <= 0.25 ? "clear:" :
@@ -67,6 +67,8 @@ world_environment::compute_weather() const {
( Global.Season != "winter:" ?
"rain:" :
"snow:" ) );
m_precipitation.update_weather();
}
void
@@ -161,7 +163,11 @@ world_environment::update() {
else if( Global.Weather == "snow:" ) {
// reduce friction due to snow
Global.FrictionWeatherFactor = 0.75f;
m_precipitationsound.stop();
}
else {
m_precipitationsound.stop();
}
}
void

View File

@@ -33,9 +33,9 @@ public:
// switches between static and dynamic daylight calculation
void toggle_daylight();
// calculates current season of the year based on set simulation date
void compute_season( int const Yearday ) const;
void compute_season( int const Yearday );
// calculates current weather
void compute_weather() const;
void compute_weather();
private:
// members

View File

@@ -150,10 +150,9 @@ state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratch
// atmosphere color; legacy parameter, no longer used
Input.getTokens( 3 );
// fog range
Input.getTokens( 2 );
Input
>> Global.fFogStart
>> Global.fFogEnd;
Input.getTokens( 1 ); // fog start ignored
Input.getTokens( 1 );
Input >> Global.fFogEnd;
if( Global.fFogEnd > 0.0 ) {
// fog colour; optional legacy parameter, no longer used
@@ -297,9 +296,24 @@ state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Sc
simulation::Events.InitLaunchers();
simulation::Memory.InitCells();
init_time();
Scratchpad.initialized = true;
}
void state_serializer::init_time() {
auto &time = simulation::Time.data();
if( true == Global.ScenarioTimeCurrent ) {
// calculate time shift required to match scenario time with local clock
auto const *localtime = std::gmtime( &Global.starting_timestamp );
Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
}
else if( false == std::isnan( Global.ScenarioTimeOverride ) ) {
// scenario time override takes precedence over scenario time offset
Global.ScenarioTimeOffset = ( ( Global.ScenarioTimeOverride * 60 ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
}
}
void
state_serializer::deserialize_group( cParser &Input, scene::scratch_data &Scratchpad ) {
@@ -583,17 +597,6 @@ state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratch
>> time.wHour
>> time.wMinute;
if( true == Global.ScenarioTimeCurrent ) {
// calculate time shift required to match scenario time with local clock
auto timenow = std::time( 0 );
auto const *localtime = std::localtime( &timenow );
Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
}
else if( false == std::isnan( Global.ScenarioTimeOverride ) ) {
// scenario time override takes precedence over scenario time offset
Global.ScenarioTimeOffset = ( ( Global.ScenarioTimeOverride * 60 ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
}
// remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically
// anything else left in the section has no defined meaning
skip_until( Input, "endtime" );

View File

@@ -73,6 +73,7 @@ private:
TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
void init_time();
// skips content of stream until specified token
void skip_until( cParser &Input, std::string const &Token );
// transforms provided location by specifed rotation and offset

View File

@@ -20,7 +20,7 @@ scenario_time Time;
} // simulation
void
scenario_time::init() {
scenario_time::init(std::time_t timestamp) {
char monthdaycounts[ 2 ][ 13 ] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
@@ -32,10 +32,7 @@ scenario_time::init() {
auto const requestedminute { requestedtime % 60 };
// cache requested elements, if any
#ifdef __linux__
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
tm *tms = localtime(&ts.tv_sec);
std::tm *tms = std::gmtime(&timestamp);
m_time.wYear = tms->tm_year;
m_time.wMonth = tms->tm_mon;
m_time.wDayOfWeek = tms->tm_wday;
@@ -43,16 +40,7 @@ scenario_time::init() {
m_time.wHour = tms->tm_hour;
m_time.wMinute = tms->tm_min;
m_time.wSecond = tms->tm_sec;
m_time.wMilliseconds = ts.tv_nsec / 1000000;
/*
time_t local = mktime(localtime(&ts.tv_sec));
time_t utc = mktime(gmtime(&ts.tv_sec));
m_timezonebias = (double)(local - utc) / 3600.0f;
*/
#elif _WIN32
::GetLocalTime( &m_time );
#endif
m_time.wMilliseconds = 0;
if( Global.fMoveLight > 0.0 ) {
// day and month of the year can be overriden by scenario setup
@@ -94,7 +82,7 @@ scenario_time::init() {
zonebias += timezoneinfo.StandardBias;
}
m_timezonebias = ( zonebias / 60.0 );
m_timezonebias = ( zonebias / 60.0 );
}
void
@@ -197,6 +185,12 @@ scenario_time::julian_day() const {
return JD;
}
void scenario_time::set_time(int yearday, int minute) {
daymonth(m_time.wDay, m_time.wMonth, m_time.wYear, yearday);
m_time.wHour = minute / 60;
m_time.wMinute = minute % 60;
}
// calculates day of week for provided date
int
scenario_time::day_of_week( int const Day, int const Month, int const Year ) const {

View File

@@ -20,7 +20,7 @@ public:
scenario_time() {
m_time.wHour = 10; m_time.wMinute = 30; }
void
init();
init(time_t timestamp);
void
update( double const Deltatime );
inline
@@ -45,6 +45,8 @@ public:
double
zone_bias() const {
return m_timezonebias; }
void
set_time(int yearday, int minute);
/** Returns std::string in format: `"mm:ss"`. */
operator std::string();

View File

@@ -38,6 +38,18 @@ int32_t sn_utils::ld_int32(std::istream &s)
return reinterpret_cast<int32_t&>(v);
}
// deserialize little endian int64
int64_t sn_utils::ld_int64(std::istream &s)
{
uint8_t buf[8];
s.read((char*)buf, 8);
uint64_t v = ((uint64_t)buf[7] << 56) | ((uint64_t)buf[6] << 48) |
((uint64_t)buf[5] << 40) | ((uint64_t)buf[4] << 32) |
((uint64_t)buf[3] << 24) | ((uint64_t)buf[2] << 16) |
((uint64_t)buf[1] << 8) | (uint64_t)buf[0];
return reinterpret_cast<int64_t&>(v);
}
// deserialize little endian ieee754 float32
float sn_utils::ld_float32(std::istream &s)
{
@@ -133,6 +145,20 @@ void sn_utils::ls_int32(std::ostream &s, int32_t v)
s.write((char*)buf, 4);
}
void sn_utils::ls_int64(std::ostream &s, int64_t v)
{
uint8_t buf[8];
buf[0] = v;
buf[1] = v >> 8;
buf[2] = v >> 16;
buf[3] = v >> 24;
buf[4] = v >> 32;
buf[5] = v >> 40;
buf[6] = v >> 48;
buf[7] = v >> 56;
s.write((char*)buf, 8);
}
void sn_utils::ls_float32(std::ostream &s, float t)
{
uint32_t v = reinterpret_cast<uint32_t&>(t);

View File

@@ -10,6 +10,7 @@ public:
static uint16_t ld_uint16(std::istream&);
static uint32_t ld_uint32(std::istream&);
static int32_t ld_int32(std::istream&);
static int64_t ld_int64(std::istream&);
static float ld_float32(std::istream&);
static double ld_float64(std::istream&);
static std::string d_str(std::istream&);
@@ -21,6 +22,7 @@ public:
static void ls_uint16(std::ostream&, uint16_t);
static void ls_uint32(std::ostream&, uint32_t);
static void ls_int32(std::ostream&, int32_t);
static void ls_int64(std::ostream&, int64_t);
static void ls_float32(std::ostream&, float);
static void ls_float64(std::ostream&, double);
static void s_str(std::ostream&, std::string);

View File

@@ -79,6 +79,14 @@ init() {
"Map",
"Mode windows",
"Time and environment",
"Time",
"Day in year",
"Visibility",
"Overcast and precipitation",
"Temperature",
"Apply",
"Straight |",
"Divert /",
@@ -242,6 +250,14 @@ init() {
u8"Mapa",
u8"Okna trybu",
u8"Czas i środowisko",
u8"Czas",
u8"Dzień w roku",
u8"Widoczność",
u8"Zachmurzenie i opady",
u8"Temperatura",
u8"Zastosuj",
u8"Prosto |",
u8"W bok /",

View File

@@ -68,6 +68,14 @@ enum string {
ui_map,
ui_mode_windows,
time_window,
time_time,
time_yearday,
time_visibility,
time_weather,
time_temperature,
time_apply,
map_straight,
map_divert,

View File

@@ -133,8 +133,10 @@ void ui::map_panel::render_labels(glm::mat4 transform, ImVec2 origin, glm::vec2
for (TDynamicObject *vehicle : simulation::Vehicles.sequence()) {
if (vehicle->Prev() || !vehicle->Mechanik)
continue;
if (vehicle->Mechanik->TrainName().empty())
continue;
std::string label = vehicle->Mechanik->TrainName();
if (label.empty() || label == "none")
label = ToUpper(vehicle->name());
glm::vec4 ndc_pos = transform * glm::vec4(glm::vec3(vehicle->GetPosition()), 1.0f);
if (glm::abs(ndc_pos.x) > 1.0f || glm::abs(ndc_pos.z) > 1.0f)
@@ -144,11 +146,10 @@ void ui::map_panel::render_labels(glm::mat4 transform, ImVec2 origin, glm::vec2
TDynamicObject *veh = vehicle;
const char *desc = vehicle->Mechanik->TrainName().c_str();
ImVec2 textsize = ImGui::CalcTextSize(desc);
ImVec2 textsize = ImGui::CalcTextSize(label.c_str());
ImGui::SetCursorPos(ImVec2(origin.x + gui_pos.x - textsize.x / 2.0f,
origin.y + gui_pos.y - textsize.y / 2.0f));
ImGui::TextUnformatted(desc);
ImGui::TextUnformatted(label.c_str());
}
ImGui::PopStyleColor();

41
widgets/time.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "stdafx.h"
#include "widgets/time.h"
#include "simulationtime.h"
#include "Globals.h"
ui::time_panel::time_panel()
: ui_panel(LOC_STR(time_window), false)
{
size.x = 450;
}
void ui::time_panel::render_contents()
{
ImGui::SliderFloat(LOC_STR(time_time), &time, 0.0f, 24.0f, "%.1f");
ImGui::SliderInt(LOC_STR(time_yearday), &yearday, 1, 365);
ImGui::SliderFloat(LOC_STR(time_visibility), &fog, 50.0f, 3000.0f, "%.0f");
ImGui::SliderFloat(LOC_STR(time_weather), &overcast, 0.0f, 2.0f, "%.1f");
ImGui::SliderFloat(LOC_STR(time_temperature), &temperature, -20.0f, 40.0f, "%.0f");
if (ImGui::Button(LOC_STR(time_apply))) {
m_relay.post(user_command::setdatetime, (double)yearday, time, 1, 0);
m_relay.post(user_command::setweather, fog, overcast, 1, 0);
m_relay.post(user_command::settemperature, temperature, 0.0, 1, 0);
is_open = false;
}
}
void ui::time_panel::open()
{
auto &data = simulation::Time.data();
time = (float)data.wHour + (float)data.wMinute / 60.0f;
yearday = simulation::Time.year_day();
fog = Global.fFogEnd;
overcast = Global.Overcast;
temperature = Global.AirTemperature;
is_open = true;
}

21
widgets/time.h Normal file
View File

@@ -0,0 +1,21 @@
#include "uilayer.h"
#include "translation.h"
#include "command.h"
namespace ui {
class time_panel : public ui_panel {
command_relay m_relay;
float time;
int yearday;
float fog;
float overcast;
float temperature;
public:
time_panel();
void render_contents() override;
void open();
};
}