From 48af69cbf19e475d4472d6347e64f29b770a1ddf Mon Sep 17 00:00:00 2001 From: maj00r Date: Tue, 3 Nov 2026 22:00:48 +0100 Subject: [PATCH] fix(render): the matte and tinted copies of a material made again with its season and weather, the primitive of a handle to no chunk told as none The copies don't update themselves, their names aren't files to read again: after a change of the weather or the season the material got its new textures and its copies kept the old ones. They are made again from it then, under their handles. primitive() of an empty handle or one past the banks read out of the bank list; it gives no_primitive there, -1 from the renderer. --- model/material.cpp | 131 ++++++++++++++++++++++----------- model/material.h | 5 ++ rendering/geometrybank.cpp | 4 + rendering/geometrybank.h | 3 +- rendering/opengl33renderer.cpp | 3 +- 5 files changed, 102 insertions(+), 44 deletions(-) diff --git a/model/material.cpp b/model/material.cpp index ddc521e59..2b92986d0 100644 --- a/model/material.cpp +++ b/model/material.cpp @@ -676,6 +676,7 @@ variant_of( opengl_material const &Source, std::string const &Suffix ) { variant.opacity = Source.opacity; variant.selfillum = Source.selfillum; variant.shadow_rank = Source.shadow_rank; + variant.glossiness = Source.glossiness; variant.name = Source.name + Suffix; variant.size = Source.size; variant.is_good = Source.is_good; @@ -700,6 +701,65 @@ shares_slot( std::unordered_map const &Con && own->second.offset < Entry.second.offset + Entry.second.size; } ); } +// the highlights of a copy of a material damped and its weathering on +void +make_matte( opengl_material &Variant ) { + + Variant.glossiness = 0.1f; + if( !Variant.shader ) { + return; + } + for( auto const &[ key, value ] : std::vector>{ { "weathering", glm::vec4{ 1.f } } } ) { + auto const entry { Variant.shader->param_conf.find( key ) }; + if( entry == Variant.shader->param_conf.end() + || shares_slot( Variant.shader->param_conf, key ) ) { + continue; + } + for( std::size_t i = 0; i < entry->second.size; ++i ) { + Variant.params[ entry->second.location ][ entry->second.offset + i ] = value[ static_cast( i ) ]; + } + Variant.params_state.erase( + std::remove_if( + std::begin( Variant.params_state ), std::end( Variant.params_state ), + [&]( gl::shader::param_entry const &State ) { + return State.location == entry->second.location && State.offset == entry->second.offset; } ), + std::end( Variant.params_state ) ); + } +} + +// the colour in the rgb of the slot of the weathering of a copy of a material, which tells the shader to tint by its sign. returns: +// whether the shader can tint it, the weathering and the tint alone in that slot +bool +make_tinted( opengl_material &Variant, glm::vec3 const &Colour ) { + + if( !Variant.shader ) { + return false; + } + auto const &conf { Variant.shader->param_conf }; + auto const weathering { conf.find( "weathering" ) }; + auto const tint { conf.find( "tint" ) }; + if( weathering == conf.end() + || tint == conf.end() + || weathering->second.offset != 3 + || tint->second.location != weathering->second.location + || tint->second.offset != 0 + || std::any_of( + std::begin( conf ), std::end( conf ), + [&]( auto const &Entry ) { + return Entry.first != weathering->first && Entry.first != tint->first && Entry.second.location == weathering->second.location; } ) ) { + return false; + } + auto const location { weathering->second.location }; + Variant.params[ location ] = glm::vec4{ Colour, -1.f }; + Variant.params_state.erase( + std::remove_if( + std::begin( Variant.params_state ), std::end( Variant.params_state ), + [&]( gl::shader::param_entry const &State ) { + return State.location == location; } ), + std::end( Variant.params_state ) ); + return true; +} + } // namespace material_handle @@ -713,25 +773,7 @@ material_manager::create_matte( material_handle const Material ) { return lookup->second; } auto matte { variant_of( m_materials[ Material ], ":matte" ) }; - matte.glossiness = 0.1f; - if( matte.shader ) { - for( auto const &[ key, value ] : std::vector>{ { "weathering", glm::vec4{ 1.f } } } ) { - auto const entry { matte.shader->param_conf.find( key ) }; - if( entry == matte.shader->param_conf.end() - || shares_slot( matte.shader->param_conf, key ) ) { - continue; - } - for( std::size_t i = 0; i < entry->second.size; ++i ) { - matte.params[ entry->second.location ][ entry->second.offset + i ] = value[ static_cast( i ) ]; - } - matte.params_state.erase( - std::remove_if( - std::begin( matte.params_state ), std::end( matte.params_state ), - [&]( gl::shader::param_entry const &State ) { - return State.location == entry->second.location && State.offset == entry->second.offset; } ), - std::end( matte.params_state ) ); - } - } + make_matte( matte ); auto const mattehandle { static_cast( m_materials.size() ) }; m_materials.emplace_back( std::move( matte ) ); m_mattes.emplace( Material, mattehandle ); @@ -748,43 +790,47 @@ material_manager::create_tinted( material_handle const Material, glm::vec3 const if( auto const lookup { m_tints.find( key ) }; lookup != m_tints.end() ) { return lookup->second; } - // the colour in the rgb of the slot of the weathering, which tells the shader to tint by its sign; nothing else in that slot - auto const &conf { m_materials[ Material ].shader->param_conf }; - auto const weathering { conf.find( "weathering" ) }; - auto const tint { conf.find( "tint" ) }; - if( weathering == conf.end() - || tint == conf.end() - || weathering->second.offset != 3 - || tint->second.location != weathering->second.location - || tint->second.offset != 0 - || std::any_of( - std::begin( conf ), std::end( conf ), - [&]( auto const &Entry ) { - return Entry.first != weathering->first && Entry.first != tint->first && Entry.second.location == weathering->second.location; } ) ) { + auto tinted { variant_of( m_materials[ Material ], ":tinted" ) }; + if( false == make_tinted( tinted, Colour ) ) { return Material; } - auto tinted { variant_of( m_materials[ Material ], ":tinted" ) }; - tinted.glossiness = m_materials[ Material ].glossiness; - auto const location { weathering->second.location }; - tinted.params[ location ] = glm::vec4{ Colour, -1.f }; - tinted.params_state.erase( - std::remove_if( - std::begin( tinted.params_state ), std::end( tinted.params_state ), - [&]( gl::shader::param_entry const &State ) { - return State.location == location; } ), - std::end( tinted.params_state ) ); auto const tintedhandle { static_cast( m_materials.size() ) }; m_materials.emplace_back( std::move( tinted ) ); m_tints.emplace( key, tintedhandle ); return tintedhandle; } +void +material_manager::update_variants( bool const Weather ) { + + // the copies don't update themselves, their names aren't files to read again + auto const changed = [&]( material_handle const Source ) { + auto const &source { m_materials[ Source ] }; + return Weather ? source.update_on_weather_change : source.update_on_season_change; }; + for( auto const &[ source, matte ] : m_mattes ) { + if( changed( source ) ) { + auto variant { variant_of( m_materials[ source ], ":matte" ) }; + make_matte( variant ); + m_materials[ matte ] = std::move( variant ); + } + } + for( auto const &[ key, tinted ] : m_tints ) { + auto const source { std::get<0>( key ) }; + if( changed( source ) ) { + auto variant { variant_of( m_materials[ source ], ":tinted" ) }; + make_tinted( variant, glm::vec3 { std::get<1>( key ), std::get<2>( key ), std::get<3>( key ) } ); + m_materials[ tinted ] = std::move( variant ); + } + } +} + void material_manager::on_weather_change() { for( auto &material : m_materials ) { if( material.update_on_weather_change ) { material.update(); } } + update_variants( true ); } void @@ -793,6 +839,7 @@ material_manager::on_season_change() { for( auto &material : m_materials ) { if( material.update_on_season_change ) { material.update(); } } + update_variants( false ); } // checks whether specified material is in the material bank. returns handle to the material, or a null handle diff --git a/model/material.h b/model/material.h index 05a68880f..82d14557c 100644 --- a/model/material.h +++ b/model/material.h @@ -145,6 +145,8 @@ public: // copy of provided material with its specular highlights and reflections damped. returns: handle to the copy, made once per material material_handle create_matte( material_handle const Material ); + // copy of provided material with its texture tinted to the colour as far as the userdata of the vertices says. returns: handle to + // the copy, made once per material and colour; the material itself when its shader can't tint it material_handle create_tinted( material_handle const Material, glm::vec3 const &Colour ); opengl_material const & @@ -166,6 +168,9 @@ private: // checks whether specified texture is in the texture bank. returns texture id, or npos. material_handle find_in_databank( std::string const &Materialname ) const; + // the matte and tinted copies of the materials changed with the weather or the season made again from them, under their handles + void + update_variants( bool const Weather ); public: // checks whether specified file exists. returns name of the located file, or empty string. static std::pair diff --git a/rendering/geometrybank.cpp b/rendering/geometrybank.cpp index 2a1ff5ee6..aa7c1f8b5 100644 --- a/rendering/geometrybank.cpp +++ b/rendering/geometrybank.cpp @@ -378,6 +378,8 @@ geometry_bank::vertices( gfx::geometry_handle const &Geometry ) const { unsigned int geometry_bank::primitive( gfx::geometry_handle const &Geometry ) const { + if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return no_primitive; } + return geometry_bank::chunk( Geometry ).type; } @@ -516,6 +518,8 @@ geometrybank_manager::vertices( gfx::geometry_handle const &Geometry ) const { unsigned int geometrybank_manager::primitive( gfx::geometry_handle const &Geometry ) const { + if( ( Geometry.bank == 0 ) || ( Geometry.bank > m_geometrybanks.size() ) ) { return geometry_bank::no_primitive; } + return bank( Geometry ).first->primitive( Geometry ); } diff --git a/rendering/geometrybank.h b/rendering/geometrybank.h index 537c79ba2..c01e46fe3 100644 --- a/rendering/geometrybank.h +++ b/rendering/geometrybank.h @@ -139,8 +139,9 @@ public: auto vertices( gfx::geometry_handle const &Geometry ) const -> gfx::vertex_array const &; // provides direct access to vertex user data of specfied chunk auto userdata( gfx::geometry_handle const &Geometry ) const -> gfx::userdata_array const &; - // kind of geometry of specified chunk, GL_TRIANGLES, GL_TRIANGLE_STRIP... + // kind of geometry of specified chunk, GL_TRIANGLES, GL_TRIANGLE_STRIP...; no_primitive for a handle to no chunk auto primitive( gfx::geometry_handle const &Geometry ) const -> unsigned int; + static constexpr unsigned int no_primitive { ~0u }; protected: // types: diff --git a/rendering/opengl33renderer.cpp b/rendering/opengl33renderer.cpp index 97b2fa8d2..9b42bb280 100644 --- a/rendering/opengl33renderer.cpp +++ b/rendering/opengl33renderer.cpp @@ -2225,7 +2225,8 @@ gfx::userdata_array const &opengl33_renderer::UserData(const gfx::geometry_handl int opengl33_renderer::Primitive(gfx::geometry_handle const &Geometry) const { - return static_cast(m_geometry.primitive(Geometry)); + auto const primitive{m_geometry.primitive(Geometry)}; + return primitive == gfx::geometry_bank::no_primitive ? -1 : static_cast(primitive); } // material methods