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