From 4dddf2dc45247f0b2448a697bbb97c5cbc282f2c Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 20 Aug 2019 12:37:24 +0200 Subject: [PATCH] heating power source fix, particle color support --- DynObj.h | 2 +- McZapkie/Mover.cpp | 8 +++++++- particles.cpp | 30 +++++++++++++++++++++--------- particles.h | 13 ++++++------- renderer.cpp | 16 +++++++++++++--- 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/DynObj.h b/DynObj.h index 4b89c201..77805888 100644 --- a/DynObj.h +++ b/DynObj.h @@ -619,7 +619,7 @@ private: Axle1.GetTranslation() : Axle0.GetTranslation(); }; // zwraca tor z aktywnÄ… osiÄ… - inline TTrack * RaTrackGet() const { + inline TTrack const * RaTrackGet() const { return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack(); }; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 0bcd388d..be2cadb2 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1410,7 +1410,13 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) { break; } case TPowerSource::Main: { - localvoltage = ( true == Mains ? Voltage : 0.0 ); + // HACK: main circuit can be fed through couplers, so we explicitly check pantograph supply here + localvoltage = ( + true == Mains ? + std::max( + PantFrontVolt, + PantRearVolt ) : + 0.0 ); break; } default: { diff --git a/particles.cpp b/particles.cpp index 3f186f3f..9ca737ef 100644 --- a/particles.cpp +++ b/particles.cpp @@ -21,7 +21,7 @@ smoke_source::particle_emitter::deserialize( cParser &Input ) { if( Input.getToken() != "{" ) { return; } - std::unordered_map const variablemap{ + std::unordered_map const variablemap { { "min_inclination:", inclination[ value_limit::min ] }, { "max_inclination:", inclination[ value_limit::max ] }, { "min_velocity:", velocity[ value_limit::min ] }, @@ -35,10 +35,22 @@ smoke_source::particle_emitter::deserialize( cParser &Input ) { while( ( false == ( ( key = Input.getToken( true, "\n\r\t ,;[]" ) ).empty() ) ) && ( key != "}" ) ) { - auto const lookup { variablemap.find( key ) }; - if( lookup == variablemap.end() ) { continue; } - - lookup->second = Input.getToken( true, "\n\r\t ,;[]" ); + if( key == "color:" ) { + // special case, vec3 attribute type + // TODO: variable table, if amount of vector attributes increases + color = Input.getToken( true, "\n\r\t ,;[]" ); + color = + glm::clamp( + color / 255.f, + glm::vec3{ 0.f }, glm::vec3{ 1.f } ); + } + else { + // float type attributes + auto const lookup { variablemap.find( key ) }; + if( lookup != variablemap.end() ) { + lookup->second = Input.getToken( true, "\n\r\t ,;[]" ); + } + } } } @@ -109,14 +121,14 @@ smoke_source::deserialize_mapping( cParser &Input ) { void smoke_source::initialize() { - m_particles.reserve( + m_max_particles = // put a cap on number of particles in a single source. TBD, TODO: make it part of he source configuration? std::min( static_cast( 500 * Global.SmokeFidelity ), // NOTE: given nature of the smoke we're presuming opacity decreases over time and the particle is killed when it reaches 0 // this gives us estimate of longest potential lifespan of single particle, and how many particles total can there be at any given time // TBD, TODO: explicit lifespan variable as part of the source configuration? - static_cast( m_spawnrate / std::abs( m_opacitymodifier.value_change() ) ) ) ); + static_cast( m_spawnrate / std::abs( m_opacitymodifier.value_change() ) ) ); } void @@ -154,7 +166,7 @@ smoke_source::update( double const Timedelta, bool const Onlydespawn ) { 0.f : std::min( m_spawncount + ( m_spawnrate * Timedelta * Global.SmokeFidelity ), - m_particles.capacity() ) ); + m_max_particles ) ); // update spawned particles for( auto particleiterator { std::begin( m_particles ) }; particleiterator != std::end( m_particles ); ++particleiterator ) { @@ -185,7 +197,7 @@ smoke_source::update( double const Timedelta, bool const Onlydespawn ) { } // spawn pending particles in remaining container slots while( ( m_spawncount >= 1.f ) - && ( m_particles.size() < m_particles.capacity() ) ) { + && ( m_particles.size() < m_max_particles ) ) { m_spawncount -= 1.f; // work with a temporary copy in case initial update renders the particle dead diff --git a/particles.h b/particles.h index b8448817..63214c3d 100644 --- a/particles.h +++ b/particles.h @@ -93,6 +93,9 @@ public: // updates state of owned particles void update( double const Timedelta, bool const Onlydespawn ); + glm::vec3 const & + color() const { + return m_emitter.color; } glm::dvec3 location() const; // provides access to bounding area data @@ -116,6 +119,7 @@ private: float velocity[ 2 ] { 1.f, 1.f }; float size[ 2 ] { 1.f, 1.f }; float opacity[ 2 ] { 1.f, 1.f }; + glm::vec3 color { 16.f / 255.f }; void deserialize( cParser &Input ); void initialize( smoke_particle &Particle ); @@ -145,19 +149,14 @@ private: particle_emitter m_emitter; // bool m_inheritvelocity { false }; // whether spawned particle should receive velocity of its owner // TODO: replace modifiers with configurable interpolator item allowing keyframe-based changes over time -// fixedstep_modifier m_velocitymodifier; // particle velocity fixedstep_modifier m_sizemodifier; // particle billboard size -// fixedstep_modifier m_colormodifier; // particle billboard color and opacity +// fixedstep_modifier m_colormodifier; // particle billboard color and opacity fixedstep_modifier m_opacitymodifier; // texture_handle m_texture { -1 }; // texture assigned to particle billboards // current state float m_spawncount { 0.f }; // number of particles to spawn during next update particle_sequence m_particles; // collection of spawned particles -/* - smoke_sequence::iterator // helpers, iterators marking currently used part of the particle container - m_particlehead, - m_particletail; -*/ + std::size_t m_max_particles; // maximum number of particles existing scene::bounding_area m_area; // bounding sphere of owned particles }; diff --git a/renderer.cpp b/renderer.cpp index 557d1f53..58de9245 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -142,6 +142,12 @@ opengl_particles::update( opengl_camera const &Camera ) { particle_vertex vertex; for( auto const &source : sources ) { + auto const particlecolor { + glm::clamp( + source.second.color() + * ( glm::vec3 { Global.DayLight.ambient } + 0.35f * glm::vec3{ Global.DayLight.diffuse } ) + * 255.f, + glm::vec3{ 0.f }, glm::vec3{ 255.f } ) }; auto const &particles { source.second.sequence() }; // TODO: put sanity cap on the overall amount of particles that can be drawn auto const sizestep { 256.0 * billboard_vertices.size() }; @@ -149,9 +155,9 @@ opengl_particles::update( opengl_camera const &Camera ) { sizestep * std::ceil( m_particlevertices.size() + ( particles.size() * billboard_vertices.size() ) / sizestep ) ); for( auto const &particle : particles ) { // TODO: particle color support - vertex.color[ 0 ] = - vertex.color[ 1 ] = - vertex.color[ 2 ] = static_cast( Global.fLuminance * 32 ); + vertex.color[ 0 ] = static_cast( particlecolor.r ); + vertex.color[ 1 ] = static_cast( particlecolor.g ); + vertex.color[ 2 ] = static_cast( particlecolor.b ); vertex.color[ 3 ] = clamp( particle.opacity * 255, 0, 255 ); auto const offset { glm::vec3{ particle.position - Camera.position() } }; @@ -3157,6 +3163,10 @@ opengl_renderer::Render_particles() { Bind_Texture( m_smoketexture ); m_particlerenderer.render( m_diffusetextureunit ); + if( Global.bUseVBO ) { + // shouldn't be strictly necessary but, eh + gfx::opengl_vbogeometrybank::reset(); + } ::glDepthMask( GL_TRUE ); ::glEnable( GL_LIGHTING );