17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-08 22:07:20 +01:00

Merge branch 'master' into feat/renderers-cleanup

This commit is contained in:
2026-11-07 16:44:51 +01:00
177 changed files with 11657 additions and 833 deletions

View File

@@ -505,6 +505,8 @@ bool anim_type_shared_by_instances( TAnimType a ) {
// instanced path (one shared submodel tree across all instances) cannot serve.
bool submodel_tree_blocks_instancing( TSubModel const *Sub ) {
if( Sub == nullptr ) { return false; }
// a text display shows the text of its instance, a tree shared by all instances can't do that
if( Sub->eType == TP_TEXT ) { return true; }
if( anim_type_unsafe_for_instancing( Sub->b_Anim ) ) { return true; }
if( ( ( Sub->iFlags & 0x4000 ) != 0 ) && ( false == anim_type_shared_by_instances( Sub->b_Anim ) ) ) { return true; }
if( submodel_tree_blocks_instancing( Sub->Child ) ) { return true; }
@@ -524,6 +526,7 @@ bool submodel_tree_faces_camera( TSubModel const *Sub ) {
} // anonymous namespace
int TAnimModel::s_instanceable_total = 0;
unsigned int TAnimModel::s_instanceable_revoked = 0;
int TAnimModel::s_classified_total = 0;
int TAnimModel::s_rejected_no_pmodel = 0;
int TAnimModel::s_rejected_lights = 0;
@@ -562,6 +565,7 @@ std::shared_ptr<TAnimContainer> TAnimModel::AddContainer(std::string const &Name
m_animlist.push_back(tmp);
// containers are added by events after the instance was loaded and bucketed;
// the instanced path skips RaAnimate(), so this instance has to be drawn on its own
if( m_instanceable ) { ++s_instanceable_revoked; }
m_instanceable = false;
++scene::node_state_version;
return tmp;
@@ -797,6 +801,7 @@ void TAnimModel::SkinSet( int const Index, material_handle const Material ) {
m_materialdata.replacable_skins[ std::clamp( Index, 1, 4 ) ] = Material;
// the instance stays in the bucket of its old skin set, where it would get the textures of the batch
if( m_instanceable ) { ++s_instanceable_revoked; }
m_instanceable = false;
++scene::node_state_version;
}

View File

@@ -241,6 +241,9 @@ public:
// diagnostic counters (process-wide). Updated inside update_instanceable_flag()
// so the renderer can surface load-time classification stats in the debug overlay.
static int s_instanceable_total; // count of TAnimModel*'s classified instanceable
// bumped whenever an instance loses its instanceable status after it was put in a scene cell (an event adds
// an animation container, or changes a skin); the cells rebuild their lists of instances drawn one by one then
static unsigned int s_instanceable_revoked;
static int s_classified_total; // count of TAnimModel*'s that ran through the classifier
static int s_rejected_no_pmodel;
static int s_rejected_lights;

View File

@@ -955,8 +955,7 @@ std::vector<TSubModel *> const &TSubModel::text_letters(std::string const &Text)
{
// the sequence is prepared once for each text the display shows. the texts of the model instances don't change,
// so drawing a display afterwards costs a single lookup, however many instances and passes take turns
auto const prepared{m_textlayouts.find(Text)};
if (prepared != m_textlayouts.end())
if (auto const prepared{m_textlayouts.find(Text)}; prepared != m_textlayouts.end())
{
return prepared->second;
}

View File

@@ -15,6 +15,8 @@ http://mozilla.org/MPL/2.0/.
#include "model/material.h"
#include "gl/query.h"
#include <string_view>
#define EU07_USE_GEOMETRYINDEXING
// Ra: specjalne typy submodeli, poza tym GL_TRIANGLES itp.
@@ -164,7 +166,12 @@ public: // chwilowo
// text display (TP_TEXT) data, filled on first use
std::unordered_map<char32_t, TSubModel *> m_letters; // sub-models of the available characters, by unicode code point
bool m_lettersready { false }; // whether the character lookup was built yet
std::unordered_map<std::string, std::vector<TSubModel *>> m_textlayouts; // sub-models of consecutive characters, for each text shown
// transparent hasher, so the text layouts can be looked up with any string type without a temporary std::string
struct text_hash {
using is_transparent = void;
std::size_t operator()( std::string_view const Text ) const noexcept { return std::hash<std::string_view>{}( Text ); }
};
std::unordered_map<std::string, std::vector<TSubModel *>, text_hash, std::equal_to<>> m_textlayouts; // sub-models of consecutive characters, for each text shown
TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy
int iVisible { 1 }; // roboczy stan widoczności
float fVisible { 1.f }; // visibility level

View File

@@ -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;
@@ -683,6 +684,89 @@ variant_of( opengl_material const &Source, std::string const &Suffix ) {
return variant;
}
// the params of a shader, as the shader keeps them
using param_confs = gfx::shader_param_conf;
// whether another param of the shader lies on a component of the named one, which a value set for that one would change too
bool
shares_slot( param_confs const &Conf, std::string const &Name ) {
auto const own { Conf.find( Name ) };
if( own == Conf.end() ) {
return false;
}
return std::ranges::any_of(
Conf,
[ &Name, &own ]( auto const &Entry ) {
return Entry.first != Name
&& Entry.second.location == own->second.location
&& Entry.second.offset < own->second.offset + own->second.size
&& 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<std::pair<std::string, glm::vec4>>{ { "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;
}
auto &slot { Variant.params[ entry->second.location ] };
auto const offset { static_cast<glm::length_t>( entry->second.offset ) };
auto const size { static_cast<glm::length_t>( entry->second.size ) };
for( glm::length_t i = 0; i < size; ++i ) {
slot[ offset + i ] = value[ i ];
}
std::erase_if(
Variant.params_state,
[ &entry ]( gfx::shader_param_entry const &State ) {
return State.location == entry->second.location && State.offset == entry->second.offset; } );
}
}
// 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" ) };
if( weathering == conf.end()
|| weathering->second.offset != 3 ) {
return false;
}
// the shaders that declare the tint keep it in the rgb of the slot; those that don't, take it from there all the same
auto const tint { conf.find( "tint" ) };
if( tint != conf.end()
&& ( tint->second.location != weathering->second.location
|| tint->second.offset != 0 ) ) {
return false;
}
if( std::ranges::any_of(
conf,
[ &weathering ]( auto const &Entry ) {
return Entry.first != weathering->first && Entry.first != "tint" && Entry.second.location == weathering->second.location; } ) ) {
return false;
}
auto const location { weathering->second.location };
Variant.params[ location ] = glm::vec4{ Colour, -1.f };
std::erase_if(
Variant.params_state,
[ location ]( gfx::shader_param_entry const &State ) {
return State.location == location; } );
return true;
}
} // namespace
material_handle
@@ -691,29 +775,11 @@ material_manager::create_matte( material_handle const Material ) {
if( Material == null_handle || Material >= m_materials.size() ) {
return Material;
}
auto const lookup { m_mattes.find( Material ) };
if( lookup != m_mattes.end() ) {
if( auto const lookup { m_mattes.find( Material ) }; lookup != m_mattes.end() ) {
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<std::pair<std::string, glm::vec4>>{ { "weathering", glm::vec4{ 1.f } } } ) {
auto const entry { matte.shader->param_conf.find( key ) };
if( entry == matte.shader->param_conf.end() ) {
continue;
}
for( std::size_t i = 0; i < entry->second.size; ++i ) {
matte.params[ entry->second.location ][ entry->second.offset + i ] = value[ static_cast<glm::length_t>( i ) ];
}
matte.params_state.erase(
std::remove_if(
std::begin( matte.params_state ), std::end( matte.params_state ),
[&]( gfx::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<material_handle>( m_materials.size() ) };
m_materials.emplace_back( std::move( matte ) );
m_mattes.emplace( Material, mattehandle );
@@ -730,32 +796,40 @@ 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;
}
auto const &conf { m_materials[ Material ].shader->param_conf };
auto const weathering { conf.find( "weathering" ) };
if( weathering == conf.end()
|| weathering->second.offset != 3
|| std::any_of(
std::begin( conf ), std::end( conf ),
[&]( auto const &Entry ) {
return Entry.first != weathering->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 ),
[&]( gfx::shader_param_entry const &State ) {
return State.location == location; } ),
std::end( tinted.params_state ) );
auto const tintedhandle { static_cast<material_handle>( 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 );
}
}
}
namespace {
// the shaders a material is lit by which the blending shaders can light the same way, by the names they're fetched by, in the
@@ -967,6 +1041,7 @@ material_manager::on_weather_change() {
for( auto &material : m_materials ) {
if( material.update_on_weather_change ) { material.update(); }
}
update_variants( true );
rebuild_blends();
}
@@ -976,6 +1051,7 @@ material_manager::on_season_change() {
for( auto &material : m_materials ) {
if( material.update_on_season_change ) { material.update(); }
}
update_variants( false );
rebuild_blends();
}

View File

@@ -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 );
// the material of a track blending its texture with those of up to three others (null: none) by the weights in y, z and w of
@@ -177,6 +179,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 );
// how the material is lit, of the materials a track blends: 0 as mat_default, 1 normalmap, 2 sunlessnormalmap,
// 3 shadowlessnormalmap, 4 more for their _specgloss, 9 parallax; -1 where it can't be blended
int