mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-18 03:09:18 +02:00
semaphores controllable on minimap
This commit is contained in:
@@ -591,6 +591,24 @@ void TAnimModel::LightSet(int const n, float const v)
|
||||
lsLights[ n ] = v;
|
||||
};
|
||||
|
||||
std::optional<std::tuple<float, float, std::optional<glm::vec3>> > TAnimModel::LightGet(const int n)
|
||||
{
|
||||
if (n >= iMaxNumLights)
|
||||
return std::nullopt;
|
||||
if (!LightsOn[n] && !LightsOff[n])
|
||||
return std::nullopt;
|
||||
|
||||
std::optional<glm::vec3> color;
|
||||
|
||||
if (m_lightcolors[n].r >= 0.0f)
|
||||
color.emplace(m_lightcolors[n]);
|
||||
|
||||
if (!color && LightsOn[n])
|
||||
color = LightsOn[n]->GetDiffuse();
|
||||
|
||||
return std::make_tuple(lsLights[n], m_lightopacities[n], color);
|
||||
}
|
||||
|
||||
void TAnimModel::AnimUpdate(double dt)
|
||||
{ // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane
|
||||
TAnimContainer *p = TAnimModel::acAnimList;
|
||||
|
||||
@@ -121,6 +121,7 @@ public:
|
||||
TAnimContainer * AddContainer(std::string const &Name);
|
||||
TAnimContainer * GetContainer(std::string const &Name = "");
|
||||
void LightSet( int const n, float const v );
|
||||
std::optional<std::tuple<float, float, std::optional<glm::vec3> > > LightGet( int const n );
|
||||
int TerrainCount();
|
||||
TSubModel * TerrainSquare(int n);
|
||||
int Flags();
|
||||
|
||||
@@ -126,6 +126,7 @@ set(SOURCES
|
||||
"widgets/vehiclelist.cpp"
|
||||
"widgets/map.cpp"
|
||||
"widgets/map_objects.cpp"
|
||||
"widgets/popup.cpp"
|
||||
|
||||
"ref/glad/src/glad.c"
|
||||
|
||||
|
||||
24
Model3d.cpp
24
Model3d.cpp
@@ -91,6 +91,30 @@ TSubModel::SetDiffuseOverride( glm::vec3 const &Color, bool const Includechildre
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<glm::vec3>
|
||||
TSubModel::GetDiffuse(float Includesiblings) {
|
||||
if (eType == TP_FREESPOTLIGHT) {
|
||||
if (DiffuseOverride.x >= 0.0f)
|
||||
return DiffuseOverride;
|
||||
else
|
||||
return glm::vec3(f4Diffuse);
|
||||
}
|
||||
|
||||
if (Includesiblings) {
|
||||
auto sibling = this;
|
||||
while ((sibling = sibling->Next)) {
|
||||
auto result = sibling->GetDiffuse(true);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (Child)
|
||||
return Child->GetDiffuse(true);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// sets visibility level (alpha component) to specified value
|
||||
void
|
||||
TSubModel::SetVisibilityLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
|
||||
|
||||
@@ -196,6 +196,8 @@ public:
|
||||
void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular );
|
||||
// sets rgb components of diffuse color override to specified value
|
||||
void SetDiffuseOverride( glm::vec3 const &Color, bool const Includechildren = false, bool const Includesiblings = false );
|
||||
// gets rgb components of any freespot diffuse color (searches also in children)
|
||||
std::optional<glm::vec3> GetDiffuse(float Includesiblings = false);
|
||||
// sets visibility level (alpha component) to specified value
|
||||
void SetVisibilityLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
|
||||
// sets light level (alpha component of illumination color) to specified value
|
||||
|
||||
7
Names.h
7
Names.h
@@ -62,6 +62,13 @@ public:
|
||||
|
||||
m_itemmap.erase(lookup);
|
||||
}
|
||||
uint32_t find_id( std::string const &Name) const {
|
||||
auto lookup = m_itemmap.find( Name );
|
||||
return (
|
||||
lookup != m_itemmap.end() ?
|
||||
lookup->second :
|
||||
-1 );
|
||||
}
|
||||
// locates item with specified name. returns pointer to the item, or nullptr
|
||||
Type_ *
|
||||
find( std::string const &Name ) const {
|
||||
|
||||
@@ -236,6 +236,7 @@ commanddescription_sequence Commands_descriptions = {
|
||||
{ "pausetoggle", command_target::simulation, command_mode::oneoff },
|
||||
{ "entervehicle", command_target::simulation, command_mode::oneoff },
|
||||
{ "queueevent", command_target::simulation, command_mode::oneoff },
|
||||
{ "setlight", command_target::simulation, command_mode::oneoff },
|
||||
};
|
||||
|
||||
} // simulation
|
||||
|
||||
@@ -230,6 +230,7 @@ enum class user_command {
|
||||
pausetoggle,
|
||||
entervehicle,
|
||||
queueevent,
|
||||
setlight,
|
||||
|
||||
none = -1
|
||||
};
|
||||
|
||||
358
renderer.cpp
358
renderer.cpp
@@ -189,77 +189,15 @@ bool opengl_renderer::Init(GLFWwindow *Window)
|
||||
if (!Global.gfx_usegles && samples > 1)
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
if (!Global.gfx_skippipeline)
|
||||
{
|
||||
m_msaa_rbc = std::make_unique<gl::renderbuffer>();
|
||||
m_msaa_rbc->alloc(Global.gfx_format_color, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, samples);
|
||||
m_pfx_motionblur = std::make_unique<gl::postfx>("motionblur");
|
||||
m_pfx_tonemapping = std::make_unique<gl::postfx>("tonemapping");
|
||||
|
||||
m_msaa_rbd = std::make_unique<gl::renderbuffer>();
|
||||
m_msaa_rbd->alloc(Global.gfx_format_depth, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, samples);
|
||||
m_empty_cubemap = std::make_unique<gl::cubemap>();
|
||||
m_empty_cubemap->alloc(Global.gfx_format_color, 16, 16, GL_RGB, GL_FLOAT);
|
||||
|
||||
m_msaa_fb = std::make_unique<gl::framebuffer>();
|
||||
m_msaa_fb->attach(*m_msaa_rbc, GL_COLOR_ATTACHMENT0);
|
||||
m_msaa_fb->attach(*m_msaa_rbd, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
if (Global.gfx_postfx_motionblur_enabled)
|
||||
{
|
||||
m_msaa_rbv = std::make_unique<gl::renderbuffer>();
|
||||
m_msaa_rbv->alloc(Global.gfx_postfx_motionblur_format, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, samples);
|
||||
m_msaa_fb->attach(*m_msaa_rbv, GL_COLOR_ATTACHMENT1);
|
||||
|
||||
m_main_tex = std::make_unique<opengl_texture>();
|
||||
m_main_tex->alloc_rendertarget(Global.gfx_format_color, GL_RGB, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, 1, GL_CLAMP_TO_EDGE);
|
||||
|
||||
m_main_fb = std::make_unique<gl::framebuffer>();
|
||||
m_main_fb->attach(*m_main_tex, GL_COLOR_ATTACHMENT0);
|
||||
|
||||
m_main_texv = std::make_unique<opengl_texture>();
|
||||
m_main_texv->alloc_rendertarget(Global.gfx_postfx_motionblur_format, GL_RG, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height);
|
||||
m_main_fb->attach(*m_main_texv, GL_COLOR_ATTACHMENT1);
|
||||
m_main_fb->setup_drawing(2);
|
||||
|
||||
if (!m_main_fb->is_complete())
|
||||
return false;
|
||||
|
||||
m_pfx_motionblur = std::make_unique<gl::postfx>("motionblur");
|
||||
|
||||
WriteLog("motion blur enabled");
|
||||
}
|
||||
|
||||
if (!m_msaa_fb->is_complete())
|
||||
return false;
|
||||
|
||||
m_main2_tex = std::make_unique<opengl_texture>();
|
||||
m_main2_tex->alloc_rendertarget(Global.gfx_format_color, GL_RGB, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height);
|
||||
|
||||
m_main2_fb = std::make_unique<gl::framebuffer>();
|
||||
m_main2_fb->attach(*m_main2_tex, GL_COLOR_ATTACHMENT0);
|
||||
if (!m_main2_fb->is_complete())
|
||||
return false;
|
||||
|
||||
m_pfx_tonemapping = std::make_unique<gl::postfx>("tonemapping");
|
||||
}
|
||||
|
||||
if (Global.gfx_shadowmap_enabled)
|
||||
{
|
||||
m_shadow_fb = std::make_unique<gl::framebuffer>();
|
||||
m_shadow_tex = std::make_unique<opengl_texture>();
|
||||
m_shadow_tex->alloc_rendertarget(Global.gfx_format_depth, GL_DEPTH_COMPONENT, m_shadowbuffersize, m_shadowbuffersize);
|
||||
m_shadow_fb->attach(*m_shadow_tex, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
if (!m_shadow_fb->is_complete())
|
||||
return false;
|
||||
|
||||
m_cabshadows_fb = std::make_unique<gl::framebuffer>();
|
||||
m_cabshadows_tex = std::make_unique<opengl_texture>();
|
||||
m_cabshadows_tex->alloc_rendertarget(Global.gfx_format_depth, GL_DEPTH_COMPONENT, m_shadowbuffersize, m_shadowbuffersize);
|
||||
m_cabshadows_fb->attach(*m_cabshadows_tex, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
if (!m_cabshadows_fb->is_complete())
|
||||
return false;
|
||||
|
||||
WriteLog("shadows enabled");
|
||||
}
|
||||
m_current_viewport = &default_viewport;
|
||||
if (!init_viewport(default_viewport))
|
||||
return false;
|
||||
|
||||
m_pick_tex = std::make_unique<opengl_texture>();
|
||||
m_pick_tex->alloc_rendertarget(GL_RGB8, GL_RGB, EU07_PICKBUFFERSIZE, EU07_PICKBUFFERSIZE);
|
||||
@@ -272,30 +210,6 @@ bool opengl_renderer::Init(GLFWwindow *Window)
|
||||
if (!m_pick_fb->is_complete())
|
||||
return false;
|
||||
|
||||
if (Global.gfx_envmap_enabled)
|
||||
{
|
||||
m_env_rb = std::make_unique<gl::renderbuffer>();
|
||||
m_env_rb->alloc(Global.gfx_format_depth, gl::ENVMAP_SIZE, gl::ENVMAP_SIZE);
|
||||
m_env_tex = std::make_unique<gl::cubemap>();
|
||||
m_env_tex->alloc(Global.gfx_format_color, gl::ENVMAP_SIZE, gl::ENVMAP_SIZE, GL_RGB, GL_FLOAT);
|
||||
m_empty_cubemap = std::make_unique<gl::cubemap>();
|
||||
m_empty_cubemap->alloc(Global.gfx_format_color, 16, 16, GL_RGB, GL_FLOAT);
|
||||
|
||||
m_env_fb = std::make_unique<gl::framebuffer>();
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_env_fb->attach(*m_empty_cubemap, i, GL_COLOR_ATTACHMENT0);
|
||||
m_env_fb->clear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
m_env_fb->detach(GL_COLOR_ATTACHMENT0);
|
||||
m_env_fb->attach(*m_env_rb, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
WriteLog("envmap enabled");
|
||||
}
|
||||
|
||||
m_picking_pbo = std::make_unique<gl::pbo>();
|
||||
m_picking_node_pbo = std::make_unique<gl::pbo>();
|
||||
|
||||
@@ -357,6 +271,103 @@ bool opengl_renderer::Init(GLFWwindow *Window)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool opengl_renderer::init_viewport(viewport_data &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_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_fb = std::make_unique<gl::framebuffer>();
|
||||
vp.msaa_fb->attach(*vp.msaa_rbc, GL_COLOR_ATTACHMENT0);
|
||||
vp.msaa_fb->attach(*vp.msaa_rbd, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
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_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_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_fb->attach(*vp.main_texv, GL_COLOR_ATTACHMENT1);
|
||||
vp.main_fb->setup_drawing(2);
|
||||
|
||||
if (!vp.main_fb->is_complete())
|
||||
return false;
|
||||
|
||||
WriteLog("motion blur enabled");
|
||||
}
|
||||
|
||||
if (!vp.msaa_fb->is_complete())
|
||||
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_fb = std::make_unique<gl::framebuffer>();
|
||||
vp.main2_fb->attach(*vp.main2_tex, GL_COLOR_ATTACHMENT0);
|
||||
if (!vp.main2_fb->is_complete())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Global.gfx_shadowmap_enabled)
|
||||
{
|
||||
vp.shadow_fb = std::make_unique<gl::framebuffer>();
|
||||
vp.shadow_tex = std::make_unique<opengl_texture>();
|
||||
vp.shadow_tex->alloc_rendertarget(Global.gfx_format_depth, GL_DEPTH_COMPONENT, m_shadowbuffersize, m_shadowbuffersize);
|
||||
vp.shadow_fb->attach(*vp.shadow_tex, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
if (!vp.shadow_fb->is_complete())
|
||||
return false;
|
||||
|
||||
vp.cabshadows_fb = std::make_unique<gl::framebuffer>();
|
||||
vp.cabshadows_tex = std::make_unique<opengl_texture>();
|
||||
vp.cabshadows_tex->alloc_rendertarget(Global.gfx_format_depth, GL_DEPTH_COMPONENT, m_shadowbuffersize, m_shadowbuffersize);
|
||||
vp.cabshadows_fb->attach(*vp.cabshadows_tex, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
if (!vp.cabshadows_fb->is_complete())
|
||||
return false;
|
||||
|
||||
WriteLog("shadows enabled");
|
||||
}
|
||||
|
||||
if (Global.gfx_envmap_enabled)
|
||||
{
|
||||
vp.env_rb = std::make_unique<gl::renderbuffer>();
|
||||
vp.env_rb->alloc(Global.gfx_format_depth, gl::ENVMAP_SIZE, gl::ENVMAP_SIZE);
|
||||
vp.env_tex = std::make_unique<gl::cubemap>();
|
||||
vp.env_tex->alloc(Global.gfx_format_color, gl::ENVMAP_SIZE, gl::ENVMAP_SIZE, GL_RGB, GL_FLOAT);
|
||||
|
||||
vp.env_fb = std::make_unique<gl::framebuffer>();
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
vp.env_fb->attach(*m_empty_cubemap, i, GL_COLOR_ATTACHMENT0);
|
||||
vp.env_fb->clear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
vp.env_fb->detach(GL_COLOR_ATTACHMENT0);
|
||||
vp.env_fb->attach(*vp.env_rb, GL_DEPTH_ATTACHMENT);
|
||||
|
||||
WriteLog("envmap enabled");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<gl::program> opengl_renderer::make_shader(std::string v, std::string f)
|
||||
{
|
||||
gl::shader vert(v);
|
||||
@@ -401,7 +412,7 @@ bool opengl_renderer::Render()
|
||||
m_renderpass.draw_mode = rendermode::none; // force setup anew
|
||||
m_debugstats = debug_stats();
|
||||
|
||||
Render_pass(rendermode::color);
|
||||
Render_pass(default_viewport, rendermode::color);
|
||||
|
||||
m_drawcount = m_cellqueue.size();
|
||||
m_debugtimestext.clear();
|
||||
@@ -464,7 +475,7 @@ void opengl_renderer::draw_debug_ui()
|
||||
}
|
||||
|
||||
// runs jobs needed to generate graphics for specified render pass
|
||||
void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
void opengl_renderer::Render_pass(viewport_data &vp, rendermode const Mode)
|
||||
{
|
||||
setup_pass(m_renderpass, Mode);
|
||||
switch (m_renderpass.draw_mode)
|
||||
@@ -506,9 +517,9 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
glDebug("render shadowmap start");
|
||||
Timer::subsystem.gfx_shadows.start();
|
||||
|
||||
Render_pass(rendermode::shadows);
|
||||
Render_pass(vp, rendermode::shadows);
|
||||
if (!FreeFlyModeFlag)
|
||||
Render_pass(rendermode::cabshadows);
|
||||
Render_pass(vp, rendermode::cabshadows);
|
||||
setup_pass(m_renderpass, Mode); // restore draw mode. TBD, TODO: render mode stack
|
||||
|
||||
Timer::subsystem.gfx_shadows.stop();
|
||||
@@ -518,9 +529,9 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
if (Global.gfx_envmap_enabled)
|
||||
{
|
||||
// potentially update environmental cube map
|
||||
if (Render_reflections())
|
||||
if (Render_reflections(vp))
|
||||
setup_pass(m_renderpass, Mode); // restore color pass settings
|
||||
setup_env_map(m_env_tex.get());
|
||||
setup_env_map(vp.env_tex.get());
|
||||
}
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
@@ -528,16 +539,16 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
setup_drawing(false);
|
||||
if (!Global.gfx_skippipeline)
|
||||
{
|
||||
m_msaa_fb->bind();
|
||||
vp.msaa_fb->bind();
|
||||
|
||||
if (Global.gfx_postfx_motionblur_enabled)
|
||||
m_msaa_fb->setup_drawing(2);
|
||||
vp.msaa_fb->setup_drawing(2);
|
||||
else
|
||||
m_msaa_fb->setup_drawing(1);
|
||||
vp.msaa_fb->setup_drawing(1);
|
||||
|
||||
glViewport(0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height);
|
||||
|
||||
m_msaa_fb->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
vp.msaa_fb->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -579,7 +590,7 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
{
|
||||
glDebug("render cab opaque");
|
||||
if (Global.gfx_shadowmap_enabled)
|
||||
setup_shadow_map(m_cabshadows_tex.get(), m_cabshadowpass);
|
||||
setup_shadow_map(vp.cabshadows_tex.get(), m_cabshadowpass);
|
||||
|
||||
auto const *vehicle = simulation::Train->Dynamic();
|
||||
Render_cab(vehicle, vehicle->InteriorLightLevel, false);
|
||||
@@ -590,7 +601,7 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
model_ubs.future = future;
|
||||
|
||||
if (Global.gfx_shadowmap_enabled)
|
||||
setup_shadow_map(m_shadow_tex.get(), m_shadowpass);
|
||||
setup_shadow_map(vp.shadow_tex.get(), m_shadowpass);
|
||||
|
||||
Render(simulation::Region);
|
||||
|
||||
@@ -608,7 +619,7 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
glDebug("render translucent cab");
|
||||
model_ubs.future = glm::mat4();
|
||||
if (Global.gfx_shadowmap_enabled)
|
||||
setup_shadow_map(m_cabshadows_tex.get(), m_cabshadowpass);
|
||||
setup_shadow_map(vp.cabshadows_tex.get(), m_cabshadowpass);
|
||||
// cache shadow colour in case we need to account for cab light
|
||||
auto const *vehicle{simulation::Train->Dynamic()};
|
||||
if (Global.Overcast > 1.0f)
|
||||
@@ -633,24 +644,24 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
{
|
||||
if (Global.gfx_postfx_motionblur_enabled)
|
||||
{
|
||||
m_main_fb->clear(GL_COLOR_BUFFER_BIT);
|
||||
m_msaa_fb->blit_to(m_main_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0);
|
||||
m_msaa_fb->blit_to(m_main_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT1);
|
||||
vp.main_fb->clear(GL_COLOR_BUFFER_BIT);
|
||||
vp.msaa_fb->blit_to(vp.main_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0);
|
||||
vp.msaa_fb->blit_to(vp.main_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT1);
|
||||
|
||||
model_ubs.param[0].x = m_framerate / (1.0 / Global.gfx_postfx_motionblur_shutter);
|
||||
model_ubo->update(model_ubs);
|
||||
m_pfx_motionblur->apply({m_main_tex.get(), m_main_texv.get()}, m_main2_fb.get());
|
||||
m_pfx_motionblur->apply({vp.main_tex.get(), vp.main_texv.get()}, vp.main2_fb.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_main2_fb->clear(GL_COLOR_BUFFER_BIT);
|
||||
m_msaa_fb->blit_to(m_main2_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0);
|
||||
vp.main2_fb->clear(GL_COLOR_BUFFER_BIT);
|
||||
vp.msaa_fb->blit_to(vp.main2_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0);
|
||||
}
|
||||
|
||||
if (!Global.gfx_usegles && !Global.gfx_shadergamma)
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
glViewport(0, 0, Global.iWindowWidth, Global.iWindowHeight);
|
||||
m_pfx_tonemapping->apply(*m_main2_tex, nullptr);
|
||||
m_pfx_tonemapping->apply(*vp.main2_tex, nullptr);
|
||||
opengl_texture::reset_unit_cache();
|
||||
}
|
||||
|
||||
@@ -685,8 +696,8 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glViewport(0, 0, m_shadowbuffersize, m_shadowbuffersize);
|
||||
m_shadow_fb->bind();
|
||||
m_shadow_fb->clear(GL_DEPTH_BUFFER_BIT);
|
||||
vp.shadow_fb->bind();
|
||||
vp.shadow_fb->clear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
setup_matrices();
|
||||
setup_drawing(false);
|
||||
@@ -703,7 +714,7 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
m_shadow_fb->unbind();
|
||||
vp.shadow_fb->unbind();
|
||||
|
||||
glDebug("rendermodeshadows ::end");
|
||||
|
||||
@@ -720,8 +731,8 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glViewport(0, 0, m_shadowbuffersize, m_shadowbuffersize);
|
||||
m_cabshadows_fb->bind();
|
||||
m_cabshadows_fb->clear(GL_DEPTH_BUFFER_BIT);
|
||||
vp.cabshadows_fb->bind();
|
||||
vp.cabshadows_fb->clear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
setup_matrices();
|
||||
setup_drawing(false);
|
||||
@@ -735,7 +746,7 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
m_cabshadows_fb->unbind();
|
||||
vp.cabshadows_fb->unbind();
|
||||
|
||||
glDebug("rendermode::cabshadows end");
|
||||
|
||||
@@ -752,8 +763,8 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
// NOTE: buffer attachment and viewport setup in this mode is handled by the wrapper method
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
m_env_fb->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
m_env_fb->bind();
|
||||
vp.env_fb->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
vp.env_fb->bind();
|
||||
|
||||
setup_env_map(m_empty_cubemap.get());
|
||||
|
||||
@@ -769,13 +780,13 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
|
||||
// opaque parts...
|
||||
setup_drawing(false);
|
||||
setup_shadow_map(m_shadow_tex.get(), m_shadowpass);
|
||||
setup_shadow_map(vp.shadow_tex.get(), m_shadowpass);
|
||||
|
||||
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
|
||||
scene_ubo->update(scene_ubs);
|
||||
Render(simulation::Region);
|
||||
|
||||
m_env_fb->unbind();
|
||||
vp.env_fb->unbind();
|
||||
|
||||
glDebug("rendermode::reflections end");
|
||||
|
||||
@@ -840,7 +851,7 @@ void opengl_renderer::Render_pass(rendermode const Mode)
|
||||
}
|
||||
|
||||
// creates dynamic environment cubemap
|
||||
bool opengl_renderer::Render_reflections()
|
||||
bool opengl_renderer::Render_reflections(viewport_data &vp)
|
||||
{
|
||||
if (Global.ReflectionUpdatesPerSecond == 0)
|
||||
return false;
|
||||
@@ -849,23 +860,23 @@ bool opengl_renderer::Render_reflections()
|
||||
auto const timestamp = time.wMilliseconds + time.wSecond * 1000 + time.wMinute * 1000 * 60 + time.wHour * 1000 * 60 * 60;
|
||||
|
||||
if ((timestamp - m_environmentupdatetime < Global.ReflectionUpdatesPerSecond)
|
||||
&& (glm::length(m_renderpass.camera.position() - m_environmentupdatelocation) < 1000.0))
|
||||
&& (glm::length(m_renderpass.pass_camera.position() - m_environmentupdatelocation) < 1000.0))
|
||||
{
|
||||
// run update every 5+ mins of simulation time, or at least 1km from the last location
|
||||
return false;
|
||||
}
|
||||
m_environmentupdatetime = timestamp;
|
||||
m_environmentupdatelocation = m_renderpass.camera.position();
|
||||
m_environmentupdatelocation = m_renderpass.pass_camera.position();
|
||||
|
||||
glViewport(0, 0, gl::ENVMAP_SIZE, gl::ENVMAP_SIZE);
|
||||
for (m_environmentcubetextureface = 0; m_environmentcubetextureface < 6; ++m_environmentcubetextureface)
|
||||
{
|
||||
m_env_fb->attach(*m_env_tex, m_environmentcubetextureface, GL_COLOR_ATTACHMENT0);
|
||||
if (m_env_fb->is_complete())
|
||||
Render_pass(rendermode::reflections);
|
||||
vp.env_fb->attach(*vp.env_tex, m_environmentcubetextureface, GL_COLOR_ATTACHMENT0);
|
||||
if (vp.env_fb->is_complete())
|
||||
Render_pass(vp, rendermode::reflections);
|
||||
}
|
||||
m_env_tex->generate_mipmaps();
|
||||
m_env_fb->detach(GL_COLOR_ATTACHMENT0);
|
||||
vp.env_tex->generate_mipmaps();
|
||||
vp.env_fb->detach(GL_COLOR_ATTACHMENT0);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -981,7 +992,7 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
|
||||
}
|
||||
}
|
||||
// setup camera
|
||||
auto &camera = Config.camera;
|
||||
auto &camera = Config.pass_camera;
|
||||
|
||||
glm::dmat4 viewmatrix(1.0);
|
||||
|
||||
@@ -1020,7 +1031,7 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
|
||||
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);
|
||||
auto &frustumchunkshapepoints = worldview.camera.frustum_points();
|
||||
auto &frustumchunkshapepoints = worldview.pass_camera.frustum_points();
|
||||
// ...modelview matrix: determine the centre of frustum chunk in world space...
|
||||
glm::vec3 frustumchunkmin, frustumchunkmax;
|
||||
bounding_box(frustumchunkmin, frustumchunkmax, std::begin(frustumchunkshapepoints), std::end(frustumchunkshapepoints));
|
||||
@@ -1028,7 +1039,7 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
|
||||
// ...cap the vertical angle to keep shadows from getting too long...
|
||||
auto const lightvector = glm::normalize(glm::vec3{m_sunlight.direction.x, std::min(m_sunlight.direction.y, -0.2f), m_sunlight.direction.z});
|
||||
// ...place the light source at the calculated centre and setup world space light view matrix...
|
||||
camera.position() = worldview.camera.position() + glm::dvec3{frustumchunkcentre};
|
||||
camera.position() = worldview.pass_camera.position() + glm::dvec3{frustumchunkcentre};
|
||||
viewmatrix *= glm::lookAt(camera.position(), camera.position() + glm::dvec3{lightvector}, glm::dvec3{0.f, 1.f, 0.f});
|
||||
// ...projection matrix: calculate boundaries of the frustum chunk in light space...
|
||||
auto const lightviewmatrix = glm::translate(glm::mat4{glm::mat3{viewmatrix}}, -frustumchunkcentre);
|
||||
@@ -1136,11 +1147,11 @@ void opengl_renderer::setup_pass(renderpass_config &Config, rendermode const Mod
|
||||
void opengl_renderer::setup_matrices()
|
||||
{
|
||||
::glMatrixMode(GL_PROJECTION);
|
||||
OpenGLMatrices.load_matrix(m_renderpass.camera.projection());
|
||||
OpenGLMatrices.load_matrix(m_renderpass.pass_camera.projection());
|
||||
|
||||
// trim modelview matrix just to rotation, since rendering is done in camera-centric world space
|
||||
::glMatrixMode(GL_MODELVIEW);
|
||||
OpenGLMatrices.load_matrix(glm::mat4(glm::mat3(m_renderpass.camera.modelview())));
|
||||
OpenGLMatrices.load_matrix(glm::mat4(glm::mat3(m_renderpass.pass_camera.modelview())));
|
||||
}
|
||||
|
||||
void opengl_renderer::setup_drawing(bool const Alpha)
|
||||
@@ -1213,9 +1224,9 @@ void opengl_renderer::setup_shadow_map(opengl_texture *tex, renderpass_config co
|
||||
0.0, 0.0, 0.5, 0.0, //
|
||||
0.5, 0.5, 0.5, 1.0 //
|
||||
);
|
||||
glm::mat4 depthproj = conf.camera.projection();
|
||||
glm::mat4 depthcam = conf.camera.modelview();
|
||||
glm::mat4 worldcam = m_renderpass.camera.modelview();
|
||||
glm::mat4 depthproj = conf.pass_camera.projection();
|
||||
glm::mat4 depthcam = conf.pass_camera.modelview();
|
||||
glm::mat4 worldcam = m_renderpass.pass_camera.modelview();
|
||||
|
||||
scene_ubs.lightview = coordmove * depthproj * depthcam * glm::inverse(worldcam);
|
||||
scene_ubo->update(scene_ubs);
|
||||
@@ -1626,13 +1637,18 @@ opengl_texture &opengl_renderer::Texture(texture_handle const Texture) const
|
||||
return m_textures.texture(Texture);
|
||||
}
|
||||
|
||||
void opengl_renderer::Update_AnimModel(TAnimModel *model)
|
||||
{
|
||||
model->RaAnimate(m_framestamp);
|
||||
}
|
||||
|
||||
void opengl_renderer::Render(scene::basic_region *Region)
|
||||
{
|
||||
|
||||
m_sectionqueue.clear();
|
||||
m_cellqueue.clear();
|
||||
// build a list of region sections to render
|
||||
glm::vec3 const cameraposition{m_renderpass.camera.position()};
|
||||
glm::vec3 const cameraposition{m_renderpass.pass_camera.position()};
|
||||
auto const camerax = static_cast<int>(std::floor(cameraposition.x / scene::EU07_SECTIONSIZE + scene::EU07_REGIONSIDESECTIONCOUNT / 2));
|
||||
auto const cameraz = static_cast<int>(std::floor(cameraposition.z / scene::EU07_SECTIONSIZE + scene::EU07_REGIONSIDESECTIONCOUNT / 2));
|
||||
int const segmentcount = 2 * static_cast<int>(std::ceil(m_renderpass.draw_range * Global.fDistanceFactor / scene::EU07_SECTIONSIZE));
|
||||
@@ -1660,7 +1676,7 @@ void opengl_renderer::Render(scene::basic_region *Region)
|
||||
break;
|
||||
}
|
||||
auto *section{Region->m_sections[row * scene::EU07_REGIONSIDESECTIONCOUNT + column]};
|
||||
if ((section != nullptr) && (m_renderpass.camera.visible(section->m_area)))
|
||||
if ((section != nullptr) && (m_renderpass.pass_camera.visible(section->m_area)))
|
||||
{
|
||||
m_sectionqueue.emplace_back(section);
|
||||
}
|
||||
@@ -1746,7 +1762,7 @@ void opengl_renderer::Render(section_sequence::iterator First, section_sequence:
|
||||
{
|
||||
// since all shapes of the section share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset{section->m_area.center - m_renderpass.camera.position()};
|
||||
auto const originoffset{section->m_area.center - m_renderpass.pass_camera.position()};
|
||||
::glTranslated(originoffset.x, originoffset.y, originoffset.z);
|
||||
// render
|
||||
for (auto const &shape : section->m_shapes)
|
||||
@@ -1774,10 +1790,10 @@ void opengl_renderer::Render(section_sequence::iterator First, section_sequence:
|
||||
{
|
||||
for (auto &cell : section->m_cells)
|
||||
{
|
||||
if ((true == cell.m_active) && (m_renderpass.camera.visible(cell.m_area)))
|
||||
if ((true == cell.m_active) && (m_renderpass.pass_camera.visible(cell.m_area)))
|
||||
{
|
||||
// store visible cells with content as well as their current distance, for sorting later
|
||||
m_cellqueue.emplace_back(glm::length2(m_renderpass.camera.position() - cell.m_area.center), &cell);
|
||||
m_cellqueue.emplace_back(glm::length2(m_renderpass.pass_camera.position() - cell.m_area.center), &cell);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1825,7 +1841,7 @@ void opengl_renderer::Render(cell_sequence::iterator First, cell_sequence::itera
|
||||
{
|
||||
// since all shapes of the section share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.camera.position()};
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.pass_camera.position()};
|
||||
::glTranslated(originoffset.x, originoffset.y, originoffset.z);
|
||||
|
||||
// render
|
||||
@@ -1846,7 +1862,7 @@ void opengl_renderer::Render(cell_sequence::iterator First, cell_sequence::itera
|
||||
{
|
||||
// since all shapes of the section share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.camera.position()};
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.pass_camera.position()};
|
||||
::glTranslated(originoffset.x, originoffset.y, originoffset.z);
|
||||
|
||||
// render
|
||||
@@ -1866,7 +1882,7 @@ void opengl_renderer::Render(cell_sequence::iterator First, cell_sequence::itera
|
||||
// same procedure like with regular render, but editor-enabled nodes receive custom colour used for picking
|
||||
// since all shapes of the section share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.camera.position()};
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.pass_camera.position()};
|
||||
::glTranslated(originoffset.x, originoffset.y, originoffset.z);
|
||||
// render
|
||||
// opaque non-instanced shapes
|
||||
@@ -1987,7 +2003,7 @@ void opengl_renderer::Render(scene::shape_node const &Shape, bool const Ignorera
|
||||
}
|
||||
default:
|
||||
{
|
||||
distancesquared = glm::length2((data.area.center - m_renderpass.camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
|
||||
distancesquared = glm::length2((data.area.center - m_renderpass.pass_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2041,7 +2057,7 @@ void opengl_renderer::Render(TAnimModel *Instance)
|
||||
}
|
||||
default:
|
||||
{
|
||||
distancesquared = Math3D::SquareMagnitude((Instance->location() - m_renderpass.camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
|
||||
distancesquared = Math3D::SquareMagnitude((Instance->location() - m_renderpass.pass_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2069,7 +2085,7 @@ void opengl_renderer::Render(TAnimModel *Instance)
|
||||
if (Instance->pModel)
|
||||
{
|
||||
// renderowanie rekurencyjne submodeli
|
||||
Render(Instance->pModel, Instance->Material(), distancesquared, Instance->location() - m_renderpass.camera.position(), Instance->vAngle);
|
||||
Render(Instance->pModel, Instance->Material(), distancesquared, Instance->location() - m_renderpass.pass_camera.position(), Instance->vAngle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2077,7 +2093,7 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
|
||||
{
|
||||
glDebug("Render TDynamicObject");
|
||||
|
||||
Dynamic->renderme = m_renderpass.camera.visible(Dynamic);
|
||||
Dynamic->renderme = m_renderpass.pass_camera.visible(Dynamic);
|
||||
if (false == Dynamic->renderme)
|
||||
{
|
||||
return false;
|
||||
@@ -2087,7 +2103,7 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
|
||||
|
||||
// setup
|
||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>(Dynamic); //żeby nie robić cudzych animacji
|
||||
glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position();
|
||||
glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.pass_camera.position();
|
||||
// lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom
|
||||
float squaredistance;
|
||||
switch (m_renderpass.draw_mode)
|
||||
@@ -2208,7 +2224,7 @@ bool opengl_renderer::Render_cab(TDynamicObject const *Dynamic, float const Ligh
|
||||
// setup shared by all render paths
|
||||
::glPushMatrix();
|
||||
|
||||
auto const originoffset = Dynamic->GetPosition() - m_renderpass.camera.position();
|
||||
auto const originoffset = Dynamic->GetPosition() - m_renderpass.pass_camera.position();
|
||||
::glTranslated(originoffset.x, originoffset.y, originoffset.z);
|
||||
::glMultMatrixd(Dynamic->mMatrix.readArray());
|
||||
|
||||
@@ -2805,7 +2821,7 @@ void opengl_renderer::Render(TMemCell *Memcell)
|
||||
{
|
||||
|
||||
::glPushMatrix();
|
||||
auto const position = Memcell->location() - m_renderpass.camera.position();
|
||||
auto const position = Memcell->location() - m_renderpass.pass_camera.position();
|
||||
::glTranslated(position.x, position.y + 0.5, position.z);
|
||||
|
||||
switch (m_renderpass.draw_mode)
|
||||
@@ -2912,7 +2928,7 @@ void opengl_renderer::Render_Alpha(cell_sequence::reverse_iterator First, cell_s
|
||||
{
|
||||
// since all shapes of the cell share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.camera.position()};
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.pass_camera.position()};
|
||||
::glTranslated(originoffset.x, originoffset.y, originoffset.z);
|
||||
// render
|
||||
// NOTE: we can reuse the method used to draw opaque geometry
|
||||
@@ -2965,7 +2981,7 @@ void opengl_renderer::Render_Alpha(cell_sequence::reverse_iterator First, cell_s
|
||||
{
|
||||
// since all shapes of the cell share center point we can optimize out a few calls here
|
||||
::glPushMatrix();
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.camera.position()};
|
||||
auto const originoffset{cell->m_area.center - m_renderpass.pass_camera.position()};
|
||||
::glTranslated(originoffset.x, originoffset.y, originoffset.z);
|
||||
Bind_Material(null_handle);
|
||||
// render
|
||||
@@ -3000,7 +3016,7 @@ void opengl_renderer::Render_Alpha(TAnimModel *Instance)
|
||||
case rendermode::shadows:
|
||||
default:
|
||||
{
|
||||
distancesquared = glm::length2((Instance->location() - m_renderpass.camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
|
||||
distancesquared = glm::length2((Instance->location() - m_renderpass.pass_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3013,7 +3029,7 @@ void opengl_renderer::Render_Alpha(TAnimModel *Instance)
|
||||
if (Instance->pModel)
|
||||
{
|
||||
// renderowanie rekurencyjne submodeli
|
||||
Render_Alpha(Instance->pModel, Instance->Material(), distancesquared, Instance->location() - m_renderpass.camera.position(), Instance->vAngle);
|
||||
Render_Alpha(Instance->pModel, Instance->Material(), distancesquared, Instance->location() - m_renderpass.pass_camera.position(), Instance->vAngle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3021,7 +3037,7 @@ void opengl_renderer::Render_Alpha(TTraction *Traction)
|
||||
{
|
||||
glDebug("Render_Alpha TTraction");
|
||||
|
||||
auto const distancesquared { glm::length2( ( Traction->location() - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor };
|
||||
auto const distancesquared { glm::length2( ( Traction->location() - m_renderpass.pass_camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor };
|
||||
if ((distancesquared < Traction->m_rangesquaredmin) || (distancesquared >= Traction->m_rangesquaredmax))
|
||||
{
|
||||
return;
|
||||
@@ -3065,7 +3081,7 @@ void opengl_renderer::Render_Alpha(scene::lines_node const &Lines)
|
||||
|
||||
auto const &data{Lines.data()};
|
||||
|
||||
auto const distancesquared { glm::length2( ( data.area.center - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor };
|
||||
auto const distancesquared { glm::length2( ( data.area.center - m_renderpass.pass_camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor };
|
||||
if ((distancesquared < data.rangesquared_min) || (distancesquared >= data.rangesquared_max))
|
||||
{
|
||||
return;
|
||||
@@ -3099,7 +3115,7 @@ bool opengl_renderer::Render_Alpha(TDynamicObject *Dynamic)
|
||||
|
||||
// setup
|
||||
TSubModel::iInstance = (size_t)Dynamic; //żeby nie robić cudzych animacji
|
||||
glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.camera.position();
|
||||
glm::dvec3 const originoffset = Dynamic->vPosition - m_renderpass.pass_camera.position();
|
||||
// lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom
|
||||
float squaredistance;
|
||||
switch (m_renderpass.draw_mode)
|
||||
@@ -3414,7 +3430,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(rendermode::pickcontrols);
|
||||
Render_pass(default_viewport, rendermode::pickcontrols);
|
||||
m_pick_fb->bind();
|
||||
m_picking_pbo->request_read(pickbufferpos.x, pickbufferpos.y, 1, 1);
|
||||
m_pick_fb->unbind();
|
||||
@@ -3453,7 +3469,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(rendermode::pickscenery);
|
||||
Render_pass(default_viewport, rendermode::pickscenery);
|
||||
m_pick_fb->bind();
|
||||
m_picking_node_pbo->request_read(pickbufferpos.x, pickbufferpos.y, 1, 1);
|
||||
m_pick_fb->unbind();
|
||||
@@ -3503,11 +3519,11 @@ glm::dvec3 opengl_renderer::get_mouse_depth()
|
||||
}
|
||||
else
|
||||
{
|
||||
gl::framebuffer::blit(m_msaa_fb.get(), m_depth_pointer_fb.get(), bufferpos.x, bufferpos.y, 1, 1, GL_DEPTH_BUFFER_BIT, 0);
|
||||
gl::framebuffer::blit(m_current_viewport->msaa_fb.get(), m_depth_pointer_fb.get(), bufferpos.x, bufferpos.y, 1, 1, GL_DEPTH_BUFFER_BIT, 0);
|
||||
|
||||
m_depth_pointer_fb->bind();
|
||||
m_depth_pointer_pbo->request_read(0, 0, 1, 1, 4, GL_DEPTH_COMPONENT, GL_FLOAT);
|
||||
m_msaa_fb->bind();
|
||||
m_current_viewport->msaa_fb->bind();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -3532,7 +3548,7 @@ glm::dvec3 opengl_renderer::get_mouse_depth()
|
||||
}
|
||||
else
|
||||
{
|
||||
gl::framebuffer::blit(m_msaa_fb.get(), m_depth_pointer_fb.get(), 0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_DEPTH_BUFFER_BIT, 0);
|
||||
gl::framebuffer::blit(m_current_viewport->msaa_fb.get(), m_depth_pointer_fb.get(), 0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_DEPTH_BUFFER_BIT, 0);
|
||||
|
||||
m_empty_vao->bind();
|
||||
m_depth_pointer_tex->bind(0);
|
||||
@@ -3542,7 +3558,7 @@ glm::dvec3 opengl_renderer::get_mouse_depth()
|
||||
m_depth_pointer_pbo->request_read(bufferpos.x, bufferpos.y, 1, 1, 16, GL_RGBA_INTEGER, GL_UNSIGNED_INT);
|
||||
m_depth_pointer_shader->unbind();
|
||||
m_empty_vao->unbind();
|
||||
m_msaa_fb->bind();
|
||||
m_current_viewport->msaa_fb->bind();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3550,15 +3566,15 @@ glm::dvec3 opengl_renderer::get_mouse_depth()
|
||||
{
|
||||
if (GLAD_GL_ARB_clip_control || GLAD_GL_EXT_clip_control) {
|
||||
if (pointdepth > 0.0f)
|
||||
m_worldmousecoordinates = glm::unProjectZO(glm::vec3(bufferpos, pointdepth), glm::mat4(glm::mat3(m_colorpass.camera.modelview())), m_colorpass.camera.projection(),
|
||||
m_worldmousecoordinates = glm::unProjectZO(glm::vec3(bufferpos, pointdepth), glm::mat4(glm::mat3(m_colorpass.pass_camera.modelview())), m_colorpass.pass_camera.projection(),
|
||||
glm::vec4(0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height));
|
||||
} else if (pointdepth < 1.0f)
|
||||
m_worldmousecoordinates = glm::unProjectNO(glm::vec3(bufferpos, pointdepth), glm::mat4(glm::mat3(m_colorpass.camera.modelview())), m_colorpass.camera.projection(),
|
||||
m_worldmousecoordinates = glm::unProjectNO(glm::vec3(bufferpos, pointdepth), glm::mat4(glm::mat3(m_colorpass.pass_camera.modelview())), m_colorpass.pass_camera.projection(),
|
||||
glm::vec4(0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height));
|
||||
}
|
||||
}
|
||||
|
||||
return m_colorpass.camera.position() + glm::dvec3{m_worldmousecoordinates};
|
||||
return m_colorpass.pass_camera.position() + glm::dvec3{m_worldmousecoordinates};
|
||||
}
|
||||
|
||||
void opengl_renderer::Update(double const Deltatime)
|
||||
@@ -3659,7 +3675,7 @@ void opengl_renderer::Update_Lights(light_array &Lights)
|
||||
glDebug("Update_Lights");
|
||||
|
||||
// arrange the light array from closest to farthest from current position of the camera
|
||||
auto const camera = m_renderpass.camera.position();
|
||||
auto const camera = m_renderpass.pass_camera.position();
|
||||
std::sort(std::begin(Lights.data), std::end(Lights.data), [&camera](light_array::light_record const &Left, light_array::light_record const &Right) {
|
||||
// move lights which are off at the end...
|
||||
if (Left.intensity == 0.f)
|
||||
|
||||
65
renderer.h
65
renderer.h
@@ -179,6 +179,7 @@ class opengl_renderer
|
||||
{
|
||||
return m_worldmousecoordinates;
|
||||
}
|
||||
void Update_AnimModel(TAnimModel *model);
|
||||
// maintenance methods
|
||||
void Update(double const Deltatime);
|
||||
void Update_Pick_Control();
|
||||
@@ -228,12 +229,36 @@ class opengl_renderer
|
||||
|
||||
struct renderpass_config
|
||||
{
|
||||
|
||||
opengl_camera camera;
|
||||
opengl_camera pass_camera;
|
||||
opengl_camera viewport_camera;
|
||||
rendermode draw_mode{rendermode::none};
|
||||
float draw_range{0.0f};
|
||||
};
|
||||
|
||||
struct viewport_data {
|
||||
std::unique_ptr<gl::framebuffer> msaa_fb;
|
||||
std::unique_ptr<gl::renderbuffer> msaa_rbc;
|
||||
std::unique_ptr<gl::renderbuffer> msaa_rbv;
|
||||
std::unique_ptr<gl::renderbuffer> msaa_rbd;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> main_fb;
|
||||
std::unique_ptr<opengl_texture> main_texv;
|
||||
std::unique_ptr<opengl_texture> main_tex;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> main2_fb;
|
||||
std::unique_ptr<opengl_texture> main2_tex;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> shadow_fb;
|
||||
std::unique_ptr<opengl_texture> shadow_tex;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> cabshadows_fb;
|
||||
std::unique_ptr<opengl_texture> cabshadows_tex;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> env_fb;
|
||||
std::unique_ptr<gl::renderbuffer> env_rb;
|
||||
std::unique_ptr<gl::cubemap> env_tex;
|
||||
};
|
||||
|
||||
typedef std::vector<opengl_light> opengllight_array;
|
||||
|
||||
// methods
|
||||
@@ -246,9 +271,9 @@ class opengl_renderer
|
||||
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(rendermode const Mode);
|
||||
void Render_pass(viewport_data &vp, rendermode const Mode);
|
||||
// creates dynamic environment cubemap
|
||||
bool Render_reflections();
|
||||
bool Render_reflections(viewport_data &vp);
|
||||
bool Render(world_environment *Environment);
|
||||
void Render(scene::basic_region *Region);
|
||||
void Render(section_sequence::iterator First, section_sequence::iterator Last);
|
||||
@@ -277,6 +302,8 @@ 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);
|
||||
|
||||
void draw(const gfx::geometry_handle &handle);
|
||||
void draw(std::vector<gfx::geometrybank_handle>::iterator begin, std::vector<gfx::geometrybank_handle>::iterator end);
|
||||
|
||||
@@ -323,6 +350,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
|
||||
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
|
||||
@@ -367,39 +395,20 @@ class opengl_renderer
|
||||
|
||||
std::unique_ptr<gl::vao> m_empty_vao;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> m_msaa_fb;
|
||||
std::unique_ptr<gl::renderbuffer> m_msaa_rbc;
|
||||
std::unique_ptr<gl::renderbuffer> m_msaa_rbv;
|
||||
std::unique_ptr<gl::renderbuffer> m_msaa_rbd;
|
||||
viewport_data default_viewport;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> m_main_fb;
|
||||
std::unique_ptr<opengl_texture> m_main_texv;
|
||||
std::unique_ptr<opengl_texture> m_main_tex;
|
||||
std::unique_ptr<gl::postfx> m_pfx_motionblur;
|
||||
std::unique_ptr<gl::postfx> m_pfx_tonemapping;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> m_main2_fb;
|
||||
std::unique_ptr<opengl_texture> m_main2_tex;
|
||||
|
||||
std::unique_ptr<gl::postfx> m_pfx_motionblur;
|
||||
std::unique_ptr<gl::postfx> m_pfx_tonemapping;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> m_shadow_fb;
|
||||
std::unique_ptr<opengl_texture> m_shadow_tex;
|
||||
std::unique_ptr<gl::program> m_shadow_shader;
|
||||
std::unique_ptr<gl::program> m_alpha_shadow_shader;
|
||||
std::unique_ptr<gl::program> m_alpha_shadow_shader;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> m_pick_fb;
|
||||
std::unique_ptr<opengl_texture> m_pick_tex;
|
||||
std::unique_ptr<gl::renderbuffer> m_pick_rb;
|
||||
std::unique_ptr<gl::program> m_pick_shader;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> m_cabshadows_fb;
|
||||
std::unique_ptr<opengl_texture> m_cabshadows_tex;
|
||||
|
||||
std::unique_ptr<gl::framebuffer> m_env_fb;
|
||||
std::unique_ptr<gl::renderbuffer> m_env_rb;
|
||||
std::unique_ptr<gl::cubemap> m_env_tex;
|
||||
|
||||
std::unique_ptr<gl::cubemap> m_empty_cubemap;
|
||||
std::unique_ptr<gl::cubemap> m_empty_cubemap;
|
||||
|
||||
std::unique_ptr<gl::pbo> m_picking_pbo;
|
||||
std::unique_ptr<gl::pbo> m_picking_node_pbo;
|
||||
|
||||
27
scene.cpp
27
scene.cpp
@@ -624,6 +624,24 @@ void basic_cell::get_map_active_switches(std::vector<gfx::geometrybank_handle> &
|
||||
path->get_map_active_switches(handles);
|
||||
}
|
||||
|
||||
TTrack* basic_cell::find_nearest_track_point(const glm::dvec3 &pos)
|
||||
{
|
||||
float min = std::numeric_limits<float>::max();
|
||||
TTrack *nearest = nullptr;
|
||||
|
||||
for (auto *path : m_paths) {
|
||||
for (auto &ep : path->endpoints()) {
|
||||
float dist2 = glm::distance2(ep, pos);
|
||||
if (dist2 < min) {
|
||||
min = dist2;
|
||||
nearest = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
// executes event assigned to specified launcher
|
||||
void
|
||||
basic_cell::launch_event( TEventLauncher *Launcher, bool local_only ) {
|
||||
@@ -1671,12 +1689,13 @@ void basic_region::create_map_geometry()
|
||||
s->create_map_geometry(m_map_geometrybank);
|
||||
}
|
||||
|
||||
std::vector<gfx::basic_vertex> vertices;
|
||||
for (const auto sem : map::Semaphores) {
|
||||
vertices.push_back(gfx::basic_vertex(sem->location, glm::vec3(), glm::vec3()));
|
||||
std::vector<gfx::basic_vertex> poi_vertices;
|
||||
for (const auto sem : map::Objects.entries) {
|
||||
poi_vertices.push_back(gfx::basic_vertex(sem->location, glm::vec3(), glm::vec3()));
|
||||
}
|
||||
|
||||
gfx::geometrybank_handle poibank = GfxRenderer.Create_Bank();
|
||||
m_map_poipoints = GfxRenderer.Insert(vertices, poibank, GL_POINTS);
|
||||
m_map_poipoints = GfxRenderer.Insert(poi_vertices, poibank, GL_POINTS);
|
||||
}
|
||||
|
||||
} // scene
|
||||
|
||||
19
scene.h
19
scene.h
@@ -157,6 +157,7 @@ public:
|
||||
create_map_geometry(std::vector<gfx::basic_vertex> &Bank, const gfx::geometrybank_handle Extra);
|
||||
void
|
||||
get_map_active_switches(std::vector<gfx::geometrybank_handle> &handles);
|
||||
TTrack *find_nearest_track_point(const glm::dvec3 &pos);
|
||||
// provides access to bounding area data
|
||||
bounding_area const &
|
||||
area() const {
|
||||
@@ -289,9 +290,9 @@ public:
|
||||
area() const {
|
||||
return m_area; }
|
||||
const gfx::geometrybank_handle get_map_geometry()
|
||||
{
|
||||
return m_map_geometryhandle;
|
||||
}
|
||||
{ return m_map_geometryhandle;}
|
||||
TTrack* find_nearest_track_point(const glm::dvec3 &pos)
|
||||
{ return cell(pos).find_nearest_track_point(pos); }
|
||||
|
||||
private:
|
||||
// types
|
||||
@@ -406,11 +407,11 @@ public:
|
||||
void
|
||||
create_map_geometry();
|
||||
basic_section* get_section(size_t section)
|
||||
{
|
||||
return m_sections[section];
|
||||
}
|
||||
{ return m_sections[section]; }
|
||||
gfx::geometrybank_handle
|
||||
get_map_poi_geometry() { return m_map_poipoints; }
|
||||
TTrack* find_nearest_track_point(const glm::dvec3 &pos)
|
||||
{ return section(pos).find_nearest_track_point(pos); }
|
||||
|
||||
private:
|
||||
// types
|
||||
@@ -432,9 +433,9 @@ private:
|
||||
static
|
||||
bool
|
||||
RaTriangleDivider( shape_node &Shape, std::deque<shape_node> &Shapes );
|
||||
// provides access to section enclosing specified point
|
||||
basic_section &
|
||||
section( glm::dvec3 const &Location );
|
||||
// provides access to section enclosing specified point
|
||||
basic_section &
|
||||
section( glm::dvec3 const &Location );
|
||||
|
||||
// members
|
||||
section_array m_sections;
|
||||
|
||||
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Event.h"
|
||||
#include "MemCell.h"
|
||||
|
||||
#include "AnimModel.h"
|
||||
#include "widgets/map_objects.h"
|
||||
|
||||
namespace scene {
|
||||
@@ -32,29 +33,6 @@ node_groups::create() {
|
||||
scene::group_handle
|
||||
node_groups::close()
|
||||
{
|
||||
if (!m_activegroup.empty()) {
|
||||
for (basic_node *node : m_groupmap[m_activegroup.top()].nodes) {
|
||||
std::string postfix { "sem_mem" };
|
||||
|
||||
if (typeid(TMemCell) == typeid(*node) && string_ends_with(node->name(), postfix)) {
|
||||
std::string sem_name = node->name().substr(0, node->name().length() - postfix.length());
|
||||
|
||||
map::Semaphores.push_back(std::make_shared<map::semaphore>());
|
||||
auto sem_info = map::Semaphores.back();
|
||||
|
||||
sem_info->location = node->location();
|
||||
sem_info->name = sem_name;
|
||||
|
||||
for (basic_event *event : m_groupmap[m_activegroup.top()].events) {
|
||||
if (string_starts_with(event->name(), sem_name)
|
||||
&& event->name().substr(sem_name.length()).find("sem") == std::string::npos) {
|
||||
sem_info->events.push_back(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( false == m_activegroup.empty() ) {
|
||||
|
||||
auto const closinggroup { m_activegroup.top() };
|
||||
@@ -75,6 +53,54 @@ node_groups::close()
|
||||
return handle();
|
||||
}
|
||||
|
||||
void
|
||||
node_groups::update_map()
|
||||
{
|
||||
map::Objects.entries.clear();
|
||||
|
||||
for (auto const &pair : m_groupmap) {
|
||||
auto const &group = pair.second;
|
||||
|
||||
for (basic_node *node : group.nodes) {
|
||||
std::string postfix { "_sem_mem" };
|
||||
|
||||
if (typeid(*node) == typeid(TMemCell) && string_ends_with(node->name(), postfix)) {
|
||||
std::string sem_name = node->name().substr(0, node->name().length() - postfix.length());
|
||||
|
||||
auto sem_info = std::make_shared<map::semaphore>();
|
||||
map::Objects.entries.push_back(sem_info);
|
||||
|
||||
sem_info->location = node->location();
|
||||
sem_info->name = sem_name;
|
||||
|
||||
for (basic_event *event : group.events) {
|
||||
if (string_starts_with(event->name(), sem_name)
|
||||
&& event->name().substr(sem_name.length()).find("sem") == std::string::npos) {
|
||||
sem_info->events.push_back(event);
|
||||
}
|
||||
}
|
||||
|
||||
for (basic_node *node : group.nodes)
|
||||
if (auto *model = dynamic_cast<TAnimModel*>(node))
|
||||
if (string_starts_with(model->name(), sem_name))
|
||||
sem_info->models.push_back(model);
|
||||
}
|
||||
if (TEventLauncher *launcher = dynamic_cast<TEventLauncher*>(node)) {
|
||||
if (!launcher || !launcher->Event1 || !launcher->Event2)
|
||||
continue;
|
||||
|
||||
auto track_switch = std::make_shared<map::track_switch>();
|
||||
map::Objects.entries.push_back(track_switch);
|
||||
|
||||
track_switch->location = node->location();
|
||||
track_switch->name = node->name();
|
||||
track_switch->straight_event = launcher->Event1;
|
||||
track_switch->divert_event = launcher->Event2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns current active group, or null_handle if group stack is empty
|
||||
group_handle
|
||||
node_groups::handle() const {
|
||||
|
||||
@@ -33,6 +33,9 @@ public:
|
||||
// indicates creation of current group ended. returns: handle to the parent group or null_handle if group stack is empty
|
||||
group_handle
|
||||
close();
|
||||
// update minimap objects
|
||||
void
|
||||
update_map();
|
||||
// returns current active group, or null_handle if group stack is empty
|
||||
group_handle
|
||||
handle() const;
|
||||
|
||||
@@ -134,6 +134,14 @@ void state_manager::process_commands() {
|
||||
Events.AddToQuery(ev, nullptr);
|
||||
}
|
||||
|
||||
if (commanddata.command == user_command::setlight) {
|
||||
uint32_t id = commanddata.action;
|
||||
int light = std::round(commanddata.param1);
|
||||
float state = commanddata.param2;
|
||||
if (id < simulation::Instances.sequence().size())
|
||||
simulation::Instances.sequence()[id]->LightSet(light, state);
|
||||
}
|
||||
|
||||
if (DebugModeFlag) {
|
||||
if (commanddata.command == user_command::timejump) {
|
||||
Time.update(commanddata.param1);
|
||||
|
||||
@@ -116,6 +116,7 @@ state_serializer::deserialize_continue(std::shared_ptr<deserializer_state> state
|
||||
deserialize_firstinit( Input, Scratchpad );
|
||||
}
|
||||
|
||||
scene::Groups.update_map();
|
||||
Region->create_map_geometry();
|
||||
|
||||
if( ( false == state->scratchpad.binary.terrain )
|
||||
|
||||
@@ -79,6 +79,9 @@ init() {
|
||||
"Map",
|
||||
"Mode windows",
|
||||
|
||||
"Straight |",
|
||||
"Divert /",
|
||||
|
||||
"master controller",
|
||||
"second controller",
|
||||
"shunt mode power",
|
||||
@@ -239,6 +242,9 @@ init() {
|
||||
u8"Mapa",
|
||||
u8"Okna trybu",
|
||||
|
||||
u8"Prosto |",
|
||||
u8"W bok /",
|
||||
|
||||
u8"nastawnik jazdy",
|
||||
u8"nastawnik dodatkowy",
|
||||
u8"sterowanie analogowe",
|
||||
|
||||
@@ -68,6 +68,9 @@ enum string {
|
||||
ui_map,
|
||||
ui_mode_windows,
|
||||
|
||||
map_straight,
|
||||
map_divert,
|
||||
|
||||
cab_mainctrl,
|
||||
cab_scndctrl,
|
||||
cab_shuntmodepower,
|
||||
|
||||
16
uilayer.cpp
16
uilayer.cpp
@@ -50,8 +50,15 @@ void ui_panel::render()
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(size_min.x, size_min.y), ImVec2(size_max.x, size_max.y));
|
||||
|
||||
auto const panelname{(title.empty() ? name : title) + "###" + name};
|
||||
if (true == ImGui::Begin(panelname.c_str(), &is_open, flags))
|
||||
if (ImGui::Begin(panelname.c_str(), &is_open, flags)) {
|
||||
render_contents();
|
||||
|
||||
popups.remove_if([](std::unique_ptr<ui::popup> &popup)
|
||||
{
|
||||
return popup->render();
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -63,6 +70,11 @@ void ui_panel::render_contents()
|
||||
}
|
||||
}
|
||||
|
||||
void ui_panel::register_popup(std::unique_ptr<ui::popup> &&popup)
|
||||
{
|
||||
popups.push_back(std::move(popup));
|
||||
}
|
||||
|
||||
void ui_expandable_panel::render_contents()
|
||||
{
|
||||
ImGui::Checkbox(LOC_STR(ui_expand), &is_expanded);
|
||||
@@ -317,7 +329,7 @@ void ui_layer::render_panels()
|
||||
|
||||
void ui_layer::render_tooltip()
|
||||
{
|
||||
if (!m_cursorvisible || m_tooltip.empty())
|
||||
if (!m_cursorvisible || m_imguiio->WantCaptureMouse || m_tooltip.empty())
|
||||
return;
|
||||
|
||||
ImGui::BeginTooltip();
|
||||
|
||||
@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <string>
|
||||
#include "Texture.h"
|
||||
#include "translation.h"
|
||||
#include "widgets/popup.h"
|
||||
|
||||
// GuiLayer -- basic user interface class. draws requested information on top of openGL screen
|
||||
|
||||
@@ -48,10 +49,12 @@ public:
|
||||
int window_flags = -1;
|
||||
|
||||
const std::string& get_name() { return name; }
|
||||
void register_popup(std::unique_ptr<ui::popup> &&popup);
|
||||
|
||||
protected:
|
||||
// members
|
||||
std::string name;
|
||||
std::list<std::unique_ptr<ui::popup>> popups;
|
||||
};
|
||||
|
||||
class ui_expandable_panel : public ui_panel {
|
||||
|
||||
218
widgets/map.cpp
218
widgets/map.cpp
@@ -7,6 +7,7 @@
|
||||
#include "Camera.h"
|
||||
#include "simulation.h"
|
||||
#include "Driver.h"
|
||||
#include "AnimModel.h"
|
||||
|
||||
ui::map_panel::map_panel() : ui_panel(LOC_STR(ui_map), false)
|
||||
{
|
||||
@@ -115,8 +116,8 @@ void ui::map_panel::render_map_texture(glm::mat4 transform, glm::vec2 surface_si
|
||||
scene_ubo->update(scene_ubs);
|
||||
GfxRenderer.Draw_Geometry(m_switch_handles.begin(), m_switch_handles.end());
|
||||
|
||||
glPointSize(3.0f);
|
||||
scene_ubs.time = 0.0f;
|
||||
glPointSize(5.0f);
|
||||
scene_ubs.time = 1.0f;
|
||||
scene_ubo->update(scene_ubs);
|
||||
GfxRenderer.Draw_Geometry(simulation::Region->get_map_poi_geometry());
|
||||
|
||||
@@ -153,21 +154,7 @@ void ui::map_panel::render_labels(glm::mat4 transform, ImVec2 origin, glm::vec2
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if (zoom > 0.005f) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.7f, 1.0f, 1.0f, 0.7f));
|
||||
for (auto sem : map::Semaphores) {
|
||||
glm::vec4 ndc_pos = transform * glm::vec4(sem->location, 1.0f);
|
||||
if (glm::abs(ndc_pos.x) > 1.0f || glm::abs(ndc_pos.z) > 1.0f)
|
||||
continue;
|
||||
|
||||
glm::vec2 gui_pos = (glm::vec2(ndc_pos.x, -ndc_pos.z) / 2.0f + 0.5f) * glm::vec2(surface_size.x, surface_size.y);
|
||||
|
||||
const char *desc = sem->name.c_str();
|
||||
ImVec2 textsize = ImGui::CalcTextSize(desc);
|
||||
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::PopStyleColor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,19 +163,6 @@ void ui::map_panel::render_contents()
|
||||
if (!init_done)
|
||||
return;
|
||||
|
||||
if (active) {
|
||||
if (ImGui::BeginPopup("Sem")) {
|
||||
for (auto ev : active->events)
|
||||
if (ImGui::Button(ev->name().c_str())) {
|
||||
active.reset();
|
||||
command_relay relay;
|
||||
relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(ev), 0.0, GLFW_PRESS, 0);
|
||||
break;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
float prev_zoom = zoom;
|
||||
|
||||
if (ImGui::Button("-"))
|
||||
@@ -271,53 +245,169 @@ void ui::map_panel::render_contents()
|
||||
|
||||
translate -= delta * 2.0f;
|
||||
}
|
||||
if (ImGui::IsMouseClicked(1)) {
|
||||
else {
|
||||
ImVec2 screen_pos = ImGui::GetMousePos();
|
||||
glm::vec2 surface_pos(screen_pos.x - screen_origin.x, screen_pos.y - screen_origin.y);
|
||||
glm::vec2 ndc_pos = surface_pos / surface_size * 2.0f - 1.0f;
|
||||
glm::vec3 world_pos = glm::inverse(transform) * glm::vec4(ndc_pos.x, 0.0f, -ndc_pos.y, 1.0f);
|
||||
|
||||
std::vector<TEventLauncher *> launchers = simulation::Events.find_eventlaunchers(glm::vec2(world_pos.x, world_pos.z), 10.0f);
|
||||
map::sorted_object_list objects =
|
||||
map::Objects.find_in_range(glm::vec3(world_pos.x, NAN, world_pos.z), 0.03f / zoom);
|
||||
|
||||
float distx = 1000000.0f;
|
||||
if (ImGui::IsMouseClicked(1)) {
|
||||
if (objects.size() > 1)
|
||||
register_popup(std::make_unique<ui::disambiguation_popup>(*this, std::move(objects)));
|
||||
else if (objects.size() == 1)
|
||||
handle_map_object_click(*this, objects.begin()->second);
|
||||
|
||||
TEventLauncher *lau = nullptr;
|
||||
for (auto launcher : launchers) {
|
||||
float distance = glm::distance2(glm::vec2(launcher->location().x, launcher->location().z),
|
||||
glm::vec2(world_pos.x, world_pos.z));
|
||||
if (distance < distx) {
|
||||
lau = launcher;
|
||||
distx = distance;
|
||||
TTrack *nearest = simulation::Region->find_nearest_track_point(world_pos);
|
||||
if (nearest) {
|
||||
WriteLog(nearest->name());
|
||||
}
|
||||
//scene::basic_section &clicked_section = simulation::Region->section(world_pos);
|
||||
//clicked_section.
|
||||
}
|
||||
|
||||
if (lau) {
|
||||
command_relay relay;
|
||||
if (!Global.shiftState && lau->Event1)
|
||||
relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(lau->Event1), 0.0, GLFW_PRESS, 0);
|
||||
else if (lau->Event2)
|
||||
relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(lau->Event2), 0.0, GLFW_PRESS, 0);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<map::semaphore>> list;
|
||||
|
||||
for (auto entry : map::Semaphores) {
|
||||
float distance = glm::distance2(glm::vec2(entry->location.x, entry->location.z),
|
||||
glm::vec2(world_pos.x, world_pos.z));
|
||||
if (distance < 100.0f) {
|
||||
if (distance < distx) {
|
||||
list.clear();
|
||||
list.push_back(entry);
|
||||
distx = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!list.empty()) {
|
||||
ImGui::OpenPopup("Sem");
|
||||
active.emplace(*list[0].get());
|
||||
else if (!objects.empty()) {
|
||||
handle_map_object_hover(objects.begin()->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render_labels(transform, window_origin, surface_size);
|
||||
}
|
||||
|
||||
void ui::handle_map_object_click(ui_panel &parent, std::shared_ptr<map::map_object> &obj)
|
||||
{
|
||||
if (auto sem = std::dynamic_pointer_cast<map::semaphore>(obj)) {
|
||||
parent.register_popup(std::make_unique<semaphore_window>(parent, std::move(sem)));
|
||||
}
|
||||
else if (auto track = std::dynamic_pointer_cast<map::track_switch>(obj)) {
|
||||
parent.register_popup(std::make_unique<switch_window>(parent, std::move(track)));
|
||||
}
|
||||
}
|
||||
|
||||
void ui::handle_map_object_hover(std::shared_ptr<map::map_object> &obj)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
|
||||
if (auto sem = std::dynamic_pointer_cast<map::semaphore>(obj)) {
|
||||
for (auto &model : sem->models) {
|
||||
ImGui::PushID(model);
|
||||
ImGui::TextUnformatted(model->name().c_str());
|
||||
|
||||
for (int i = 0; i < iMaxNumLights; i++) {
|
||||
GfxRenderer.Update_AnimModel(model); // update lamp opacities
|
||||
auto state = model->LightGet(i);
|
||||
if (!state)
|
||||
continue;
|
||||
|
||||
glm::vec3 current_color = std::get<2>(*state).value_or(glm::vec3(0.5f)) * std::get<1>(*state);
|
||||
if (std::get<0>(*state) < 0.0f)
|
||||
continue;
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(current_color.x, current_color.y, current_color.z, 1.0f));
|
||||
|
||||
std::string res = " ##" + std::to_string(i);
|
||||
ImGui::Button(res.c_str());
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
else if (auto sw = std::dynamic_pointer_cast<map::track_switch>(obj)) {
|
||||
ImGui::TextUnformatted(sw->name.c_str());
|
||||
}
|
||||
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ui::disambiguation_popup::disambiguation_popup(ui_panel &panel, map::sorted_object_list &&list)
|
||||
: popup(panel), m_list(list) { }
|
||||
|
||||
void ui::disambiguation_popup::render_content()
|
||||
{
|
||||
for (auto &item : m_list) {
|
||||
if (ImGui::Button(item.second->name.c_str())) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
handle_map_object_click(m_parent, item.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui::semaphore_window::semaphore_window(ui_panel &panel, std::shared_ptr<map::semaphore> &&sem)
|
||||
: popup(panel), m_sem(sem) { }
|
||||
|
||||
void ui::semaphore_window::render_content()
|
||||
{
|
||||
for (auto &model : m_sem->models) {
|
||||
ImGui::PushID(model);
|
||||
ImGui::TextUnformatted(model->name().c_str());
|
||||
|
||||
for (int i = 0; i < iMaxNumLights; i++) {
|
||||
GfxRenderer.Update_AnimModel(model); // update lamp opacities
|
||||
auto state = model->LightGet(i);
|
||||
if (!state)
|
||||
continue;
|
||||
|
||||
glm::vec3 lamp_color = std::get<2>(*state).value_or(glm::vec3(0.5f));
|
||||
glm::vec3 current_color = lamp_color * std::get<1>(*state);
|
||||
float level = std::get<0>(*state);
|
||||
|
||||
if (level < 0.0f)
|
||||
continue;
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(lamp_color.x, lamp_color.y, lamp_color.z, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(current_color.x, current_color.y, current_color.z, 1.0f));
|
||||
|
||||
std::string res = " ##" + std::to_string(i);
|
||||
if (ImGui::Button(res.c_str())) {
|
||||
level += 1.0f;
|
||||
if (level >= 3.0f)
|
||||
level = 0.0f;
|
||||
|
||||
int id = simulation::Instances.find_id(model->name());
|
||||
m_relay.post(user_command::setlight, (double)i, level, id, 0);
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
for (auto &item : m_sem->events) {
|
||||
std::string displayname = item->name().substr(m_sem->name.size());
|
||||
|
||||
if (displayname.size() < 2)
|
||||
continue;
|
||||
|
||||
displayname[1] = std::toupper(displayname[1]);
|
||||
|
||||
if (ImGui::Button(displayname.c_str())) {
|
||||
m_relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(item), 0.0, GLFW_PRESS, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui::switch_window::switch_window(ui_panel &panel, std::shared_ptr<map::track_switch> &&sw)
|
||||
: popup(panel), m_switch(sw) { }
|
||||
|
||||
void ui::switch_window::render_content()
|
||||
{
|
||||
ImGui::TextUnformatted(m_switch->name.c_str());
|
||||
|
||||
if (ImGui::Button(LOC_STR(map_straight))) {
|
||||
m_relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(m_switch->straight_event), 0.0, GLFW_PRESS, 0);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if (ImGui::Button(LOC_STR(map_divert))) {
|
||||
m_relay.post(user_command::queueevent, (double)simulation::Events.GetEventId(m_switch->divert_event), 0.0, GLFW_PRESS, 0);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,37 @@
|
||||
#include "Texture.h"
|
||||
#include "uilayer.h"
|
||||
#include "widgets/map_objects.h"
|
||||
#include "widgets/popup.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class disambiguation_popup {
|
||||
std::string m_id;
|
||||
std::vector<map::semaphore> m_list;
|
||||
class disambiguation_popup : public popup {
|
||||
map::sorted_object_list m_list;
|
||||
|
||||
public:
|
||||
disambiguation_popup(std::string &&id, std::vector<map::semaphore> &&list)
|
||||
: m_id(id), m_list(list) {}
|
||||
disambiguation_popup(ui_panel &panel, map::sorted_object_list &&list);
|
||||
|
||||
void render();
|
||||
virtual void render_content() override;
|
||||
};
|
||||
|
||||
class semaphore_window : public popup {
|
||||
std::shared_ptr<map::semaphore> m_sem;
|
||||
command_relay m_relay;
|
||||
|
||||
public:
|
||||
semaphore_window(ui_panel &panel, std::shared_ptr<map::semaphore> &&sem);
|
||||
|
||||
virtual void render_content() override;
|
||||
};
|
||||
|
||||
class switch_window : public popup {
|
||||
std::shared_ptr<map::track_switch> m_switch;
|
||||
command_relay m_relay;
|
||||
|
||||
public:
|
||||
switch_window(ui_panel &panel, std::shared_ptr<map::track_switch> &&sw);
|
||||
|
||||
virtual void render_content() override;
|
||||
};
|
||||
|
||||
class map_panel : public ui_panel {
|
||||
@@ -50,4 +69,6 @@ public:
|
||||
void render_contents() override;
|
||||
};
|
||||
|
||||
void handle_map_object_click(ui_panel &parent, std::shared_ptr<map::map_object> &obj);
|
||||
void handle_map_object_hover(std::shared_ptr<map::map_object> &obj);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,27 @@
|
||||
#include "widgets/map_objects.h"
|
||||
|
||||
std::vector<std::shared_ptr<map::semaphore>> map::Semaphores;
|
||||
std::vector<std::shared_ptr<map::track_switch>> map::Switches;
|
||||
map::objects map::Objects;
|
||||
|
||||
map::sorted_object_list map::objects::find_in_range(glm::vec3 from, float distance)
|
||||
{
|
||||
sorted_object_list items;
|
||||
|
||||
float max_distance2 = distance * distance;
|
||||
|
||||
for (auto const entry : entries) {
|
||||
glm::vec3 entry_location = entry->location;
|
||||
glm::vec3 search_point = from;
|
||||
|
||||
if (glm::isnan(from.y)) {
|
||||
entry_location.y = 0.0f;
|
||||
search_point.y = 0.0f;
|
||||
}
|
||||
|
||||
float dist = glm::distance2(entry_location, search_point);
|
||||
if (dist < max_distance2) {
|
||||
items.emplace(dist, std::move(entry));
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -6,19 +6,35 @@
|
||||
|
||||
namespace map {
|
||||
|
||||
// semaphore description (only for minimap purposes)
|
||||
struct semaphore {
|
||||
struct map_object {
|
||||
std::string name;
|
||||
glm::vec3 location;
|
||||
|
||||
virtual ~map_object() = default;
|
||||
};
|
||||
|
||||
using object_list = std::vector<std::shared_ptr<map::map_object>>;
|
||||
using sorted_object_list = std::map<float, std::shared_ptr<map::map_object>>;
|
||||
|
||||
// semaphore description (only for minimap purposes)
|
||||
struct semaphore : public map_object {
|
||||
std::vector<TAnimModel *> models;
|
||||
|
||||
std::vector<basic_event *> events;
|
||||
};
|
||||
|
||||
// switch description (only for minimap purposes)
|
||||
struct track_switch {
|
||||
glm::vec3 location;
|
||||
struct track_switch : public map_object {
|
||||
basic_event *straight_event = nullptr;
|
||||
basic_event *divert_event = nullptr;
|
||||
};
|
||||
|
||||
extern std::vector<std::shared_ptr<semaphore>> Semaphores;
|
||||
extern std::vector<std::shared_ptr<track_switch>> Switches;
|
||||
struct objects {
|
||||
std::vector<std::shared_ptr<map_object>> entries;
|
||||
|
||||
// returns objects in range from vec3, NaN in Y ignores it
|
||||
sorted_object_list find_in_range(glm::vec3 from, float distance);
|
||||
};
|
||||
|
||||
extern objects Objects;
|
||||
}
|
||||
|
||||
29
widgets/popup.cpp
Normal file
29
widgets/popup.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "widgets/popup.h"
|
||||
|
||||
ui::popup::popup(ui_panel &panel)
|
||||
: m_parent(panel)
|
||||
{
|
||||
}
|
||||
|
||||
ui::popup::~popup()
|
||||
{
|
||||
}
|
||||
|
||||
bool ui::popup::render()
|
||||
{
|
||||
if (!m_id.size()) {
|
||||
m_id = "popup:" + std::to_string(id++);
|
||||
ImGui::OpenPopup(m_id.c_str());
|
||||
}
|
||||
|
||||
if (!ImGui::BeginPopup(m_id.c_str()))
|
||||
return true;
|
||||
|
||||
render_content();
|
||||
|
||||
ImGui::EndPopup();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ui::popup::id = 0;
|
||||
22
widgets/popup.h
Normal file
22
widgets/popup.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
class ui_panel;
|
||||
|
||||
namespace ui {
|
||||
|
||||
class popup {
|
||||
std::string m_id;
|
||||
static int id;
|
||||
|
||||
public:
|
||||
popup(ui_panel &panel);
|
||||
~popup();
|
||||
|
||||
bool render();
|
||||
|
||||
protected:
|
||||
ui_panel &m_parent;
|
||||
virtual void render_content() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user