mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-02 06:59:13 +01:00
feat(track): the texture of a shared running surface blends into the texture of the rail it lies on: 2 cm on each side of the boundary both are drawn in tinted variants of their materials that fade per vertex into the mean colour of the two treads, sampled from the texture files, so the edge of the wheels of the other track leaves a soft band instead of a line
This commit is contained in:
@@ -662,6 +662,29 @@ material_manager::create_from_text( std::string const &Name, std::string const &
|
|||||||
return materialhandle;
|
return materialhandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
opengl_material
|
||||||
|
variant_of( opengl_material const &Source, std::string const &Suffix ) {
|
||||||
|
|
||||||
|
opengl_material variant;
|
||||||
|
variant.textures = Source.textures;
|
||||||
|
variant.texture_variants = Source.texture_variants;
|
||||||
|
variant.params = Source.params;
|
||||||
|
variant.params_state = Source.params_state;
|
||||||
|
variant.shader = Source.shader;
|
||||||
|
variant.opacity = Source.opacity;
|
||||||
|
variant.selfillum = Source.selfillum;
|
||||||
|
variant.shadow_rank = Source.shadow_rank;
|
||||||
|
variant.name = Source.name + Suffix;
|
||||||
|
variant.size = Source.size;
|
||||||
|
variant.is_good = Source.is_good;
|
||||||
|
variant.path = Source.path;
|
||||||
|
return variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
material_handle
|
material_handle
|
||||||
material_manager::create_matte( material_handle const Material ) {
|
material_manager::create_matte( material_handle const Material ) {
|
||||||
|
|
||||||
@@ -672,21 +695,8 @@ material_manager::create_matte( material_handle const Material ) {
|
|||||||
if( lookup != m_mattes.end() ) {
|
if( lookup != m_mattes.end() ) {
|
||||||
return lookup->second;
|
return lookup->second;
|
||||||
}
|
}
|
||||||
auto const &source { m_materials[ Material ] };
|
auto matte { variant_of( m_materials[ Material ], ":matte" ) };
|
||||||
opengl_material matte;
|
|
||||||
matte.textures = source.textures;
|
|
||||||
matte.texture_variants = source.texture_variants;
|
|
||||||
matte.params = source.params;
|
|
||||||
matte.params_state = source.params_state;
|
|
||||||
matte.shader = source.shader;
|
|
||||||
matte.opacity = source.opacity;
|
|
||||||
matte.selfillum = source.selfillum;
|
|
||||||
matte.glossiness = 0.1f;
|
matte.glossiness = 0.1f;
|
||||||
matte.shadow_rank = source.shadow_rank;
|
|
||||||
matte.name = source.name + ":matte";
|
|
||||||
matte.size = source.size;
|
|
||||||
matte.is_good = source.is_good;
|
|
||||||
matte.path = source.path;
|
|
||||||
if( matte.shader ) {
|
if( matte.shader ) {
|
||||||
for( auto const &[ key, value ] : std::vector<std::pair<std::string, glm::vec4>>{ { "weathering", glm::vec4{ 1.f } } } ) {
|
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 ) };
|
auto const entry { matte.shader->param_conf.find( key ) };
|
||||||
@@ -710,6 +720,42 @@ material_manager::create_matte( material_handle const Material ) {
|
|||||||
return mattehandle;
|
return mattehandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
material_handle
|
||||||
|
material_manager::create_tinted( material_handle const Material, glm::vec3 const &Colour ) {
|
||||||
|
|
||||||
|
if( Material == null_handle || Material >= m_materials.size() || !m_materials[ Material ].shader ) {
|
||||||
|
return Material;
|
||||||
|
}
|
||||||
|
auto const key { std::make_tuple( Material, Colour.r, Colour.g, Colour.b ) };
|
||||||
|
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; } ) ) {
|
||||||
|
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<material_handle>( m_materials.size() ) };
|
||||||
|
m_materials.emplace_back( std::move( tinted ) );
|
||||||
|
m_tints.emplace( key, tintedhandle );
|
||||||
|
return tintedhandle;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
material_manager::on_weather_change() {
|
material_manager::on_weather_change() {
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
// copy of provided material with its specular highlights and reflections damped. returns: handle to the copy, made once per material
|
||||||
material_handle
|
material_handle
|
||||||
create_matte( material_handle const Material );
|
create_matte( material_handle const Material );
|
||||||
|
material_handle
|
||||||
|
create_tinted( material_handle const Material, glm::vec3 const &Colour );
|
||||||
opengl_material const &
|
opengl_material const &
|
||||||
material( material_handle const Material ) const { return m_materials[ Material ]; }
|
material( material_handle const Material ) const { return m_materials[ Material ]; }
|
||||||
opengl_material &
|
opengl_material &
|
||||||
@@ -174,6 +176,7 @@ private:
|
|||||||
material_sequence m_materials;
|
material_sequence m_materials;
|
||||||
index_map m_materialmappings;
|
index_map m_materialmappings;
|
||||||
std::unordered_map<material_handle, material_handle> m_mattes;
|
std::unordered_map<material_handle, material_handle> m_mattes;
|
||||||
|
std::map<std::tuple<material_handle, float, float, float>, material_handle> m_tints;
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -2231,6 +2231,12 @@ material_handle opengl33_renderer::Matte_Material(material_handle const Material
|
|||||||
return m_materials.create_matte(Material);
|
return m_materials.create_matte(Material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
material_handle opengl33_renderer::Tinted_Material(material_handle const Material, glm::vec3 const &Colour)
|
||||||
|
{
|
||||||
|
|
||||||
|
return m_materials.create_tinted(Material, Colour);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<gl::program> opengl33_renderer::Fetch_Shader(const std::string &name)
|
std::shared_ptr<gl::program> opengl33_renderer::Fetch_Shader(const std::string &name)
|
||||||
{
|
{
|
||||||
auto it = m_shaders.find(name);
|
auto it = m_shaders.find(name);
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ class opengl33_renderer : public gfx_renderer {
|
|||||||
Fetch_Material( std::string const &Filename, bool const Loadnow = true ) override;
|
Fetch_Material( std::string const &Filename, bool const Loadnow = true ) override;
|
||||||
material_handle
|
material_handle
|
||||||
Matte_Material( material_handle const Material ) override;
|
Matte_Material( material_handle const Material ) override;
|
||||||
|
material_handle
|
||||||
|
Tinted_Material( material_handle const Material, glm::vec3 const &Colour ) override;
|
||||||
void
|
void
|
||||||
Bind_Material( material_handle const Material, TSubModel const *sm = nullptr, lighting_data const *lighting = nullptr ) override;
|
Bind_Material( material_handle const Material, TSubModel const *sm = nullptr, lighting_data const *lighting = nullptr ) override;
|
||||||
IMaterial const *
|
IMaterial const *
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ public:
|
|||||||
virtual auto Material( material_handle const Material ) const -> IMaterial const * = 0;
|
virtual auto Material( material_handle const Material ) const -> IMaterial const * = 0;
|
||||||
// the same material with its highlights damped, for faces which aren't polished like the surfaces they are cut from. backends which can't make one give back the material itself
|
// the same material with its highlights damped, for faces which aren't polished like the surfaces they are cut from. backends which can't make one give back the material itself
|
||||||
virtual auto Matte_Material( material_handle const Material ) -> material_handle { return Material; }
|
virtual auto Matte_Material( material_handle const Material ) -> material_handle { return Material; }
|
||||||
|
virtual auto Tinted_Material( material_handle const Material, glm::vec3 const &Colour ) -> material_handle { return Material; }
|
||||||
// heightmap terrain: material of a chunk blending the materials of up to 8 layers by their weights.
|
// heightmap terrain: material of a chunk blending the materials of up to 8 layers by their weights.
|
||||||
// Weights: (Samples + 1)^2 values per layer, planar, rows of growing z, the weights of a sample adding up to 255; null with a single layer.
|
// Weights: (Samples + 1)^2 values per layer, planar, rows of growing z, the weights of a sample adding up to 255; null with a single layer.
|
||||||
// Placement: corner of the chunk (x, z) in the texture coordinates of its mesh, and the size of the chunk.
|
// Placement: corner of the chunk (x, z) in the texture coordinates of its mesh, and the size of the chunk.
|
||||||
|
|||||||
@@ -288,11 +288,13 @@ vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float refl
|
|||||||
// Diffuse colour is applied once, to the albedo; the light terms below are not scaled by it again
|
// Diffuse colour is applied once, to the albedo; the light terms below are not scaled by it again
|
||||||
texturecolor *= material_diffuse();
|
texturecolor *= material_diffuse();
|
||||||
float weathered = (param[2].w > 0.0 ? clamp(param[2].w * UserData.x, 0.0, 1.0) : 0.0);
|
float weathered = (param[2].w > 0.0 ? clamp(param[2].w * UserData.x, 0.0, 1.0) : 0.0);
|
||||||
float polished = weathered * smoothstep(0.03, 0.12, dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)));
|
float tinted = (param[2].w < 0.0 ? clamp(-param[2].w * UserData.x, 0.0, 1.0) : 0.0);
|
||||||
|
float polished = max(weathered * smoothstep(0.03, 0.12, dot(texturecolor, vec3(0.2126, 0.7152, 0.0722))), tinted);
|
||||||
float weatheredluma = min(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 0.05);
|
float weatheredluma = min(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 0.05);
|
||||||
vec3 unused = texturecolor * (weatheredluma / max(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 1e-4));
|
vec3 unused = texturecolor * (weatheredluma / max(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 1e-4));
|
||||||
unused = mix(unused, vec3(1.0, 0.82, 0.74) * (weatheredluma / 0.8525), 0.5);
|
unused = mix(unused, vec3(1.0, 0.82, 0.74) * (weatheredluma / 0.8525), 0.5);
|
||||||
texturecolor = mix(texturecolor, unused, smoothstep(0.0, 0.4, weathered));
|
texturecolor = mix(texturecolor, unused, smoothstep(0.0, 0.4, weathered));
|
||||||
|
texturecolor = (tinted > 0.0 ? mix(texturecolor, param[2].rgb, tinted) : texturecolor);
|
||||||
specularity = mix(specularity, min(specularity, 0.03), smoothstep(0.0, 0.4, polished));
|
specularity = mix(specularity, min(specularity, 0.03), smoothstep(0.0, 0.4, polished));
|
||||||
metalic = mix(metalic, 0.0, polished);
|
metalic = mix(metalic, 0.0, polished);
|
||||||
glossiness = mix(glossiness, min(glossiness, 0.06 * abs(param[1].w)), polished);
|
glossiness = mix(glossiness, min(glossiness, 0.06 * abs(param[1].w)), polished);
|
||||||
|
|||||||
@@ -721,7 +721,7 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ring.emplace_back( pt, glm::normalize( norm ), glm::vec2{ shape.texture.x, 0.f } );
|
Ring.emplace_back( pt, glm::normalize( norm ), glm::vec2{ shape.texture.x, 0.f } );
|
||||||
Wear.push_back( Rampwidth > 0.0 ? static_cast<float>( std::clamp( ( outside - worn + Rampwidth ) / Rampwidth, 0.0, 1.0 ) ) : 1.f );
|
Wear.push_back( Rampwidth != 0.0 ? static_cast<float>( std::clamp( ( Rampwidth > 0.0 ? outside - worn : worn - outside ) / std::abs( Rampwidth ) + 1.0, 0.0, 1.0 ) ) : 1.f );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -197,15 +197,20 @@ material_handle cut_material( material_handle const Material ) {
|
|||||||
return unrolled ? GfxRenderer->Fetch_Material( "editor_unrolled" ) : GfxRenderer->Matte_Material( Material );
|
return unrolled ? GfxRenderer->Fetch_Material( "editor_unrolled" ) : GfxRenderer->Matte_Material( Material );
|
||||||
}
|
}
|
||||||
|
|
||||||
float tread_brightness( material_handle const Material, glm::vec2 const &Band ) {
|
material_handle tint_material( material_handle const Material, glm::vec3 const &Colour ) {
|
||||||
|
|
||||||
static std::map<std::tuple<material_handle, float, float>, float> brightness;
|
return GfxRenderer->Tinted_Material( Material, Colour );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<float, glm::vec3> const &tread_sample( material_handle const Material, glm::vec2 const &Band ) {
|
||||||
|
|
||||||
|
static std::map<std::tuple<material_handle, float, float>, std::pair<float, glm::vec3>> samples;
|
||||||
auto const key { std::make_tuple( Material, Band.x, Band.y ) };
|
auto const key { std::make_tuple( Material, Band.x, Band.y ) };
|
||||||
if( auto const lookup { brightness.find( key ) }; lookup != brightness.end() ) {
|
if( auto const lookup { samples.find( key ) }; lookup != samples.end() ) {
|
||||||
return lookup->second;
|
return lookup->second;
|
||||||
}
|
}
|
||||||
auto &result { brightness[ key ] };
|
auto &result { samples[ key ] };
|
||||||
result = -1.f;
|
result = { -1.f, glm::vec3{ 0.f } };
|
||||||
if( Material == null_handle ) {
|
if( Material == null_handle ) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -221,9 +226,11 @@ float tread_brightness( material_handle const Material, glm::vec2 const &Band )
|
|||||||
auto const last { std::clamp( static_cast<int>( std::ceil( std::max( Band.x, Band.y ) * Width ) ) - 1, first, Width - 1 ) };
|
auto const last { std::clamp( static_cast<int>( std::ceil( std::max( Band.x, Band.y ) * Width ) ) - 1, first, Width - 1 ) };
|
||||||
return std::pair{ first, last }; };
|
return std::pair{ first, last }; };
|
||||||
auto sum { 0.0 };
|
auto sum { 0.0 };
|
||||||
|
glm::dvec3 colour { 0.0 };
|
||||||
std::size_t count { 0 };
|
std::size_t count { 0 };
|
||||||
auto const add = [&]( float const Red, float const Green, float const Blue ) {
|
auto const add = [&]( float const Red, float const Green, float const Blue ) {
|
||||||
sum += 0.2126 * Red + 0.7152 * Green + 0.0722 * Blue;
|
sum += 0.2126 * Red + 0.7152 * Green + 0.0722 * Blue;
|
||||||
|
colour += glm::pow( glm::dvec3{ Red, Green, Blue } / 255.0, glm::dvec3{ 2.2 } );
|
||||||
++count; };
|
++count; };
|
||||||
if( type == ".dds" ) {
|
if( type == ".dds" ) {
|
||||||
std::ifstream input( file, std::ios::binary );
|
std::ifstream input( file, std::ios::binary );
|
||||||
@@ -283,11 +290,21 @@ float tread_brightness( material_handle const Material, glm::vec2 const &Band )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( count > 0 ) {
|
if( count > 0 ) {
|
||||||
result = static_cast<float>( sum / count );
|
result = { static_cast<float>( sum / count ), glm::vec3{ colour / static_cast<double>( count ) } };
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float tread_brightness( material_handle const Material, glm::vec2 const &Band ) {
|
||||||
|
|
||||||
|
return tread_sample( Material, Band ).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 tread_colour( material_handle const Material, glm::vec2 const &Band ) {
|
||||||
|
|
||||||
|
return tread_sample( Material, Band ).second;
|
||||||
|
}
|
||||||
|
|
||||||
// in the colour of the top of the rail foot
|
// in the colour of the top of the rail foot
|
||||||
void cap_loft( gfx::vertex_array const &Strip, std::size_t const Ring, bool const Start, bool const End, gfx::vertex_array &Triangles ) {
|
void cap_loft( gfx::vertex_array const &Strip, std::size_t const Ring, bool const Start, bool const End, gfx::vertex_array &Triangles ) {
|
||||||
|
|
||||||
@@ -1481,6 +1498,7 @@ bool TTrack::lay_rail( rail_layout const &Layout, rail_drawing const &Drawing, i
|
|||||||
auto const length { segment.GetLength() };
|
auto const length { segment.GetLength() };
|
||||||
auto const &treads { Layout.treads[ Path ][ Side > 0 ] };
|
auto const &treads { Layout.treads[ Path ][ Side > 0 ] };
|
||||||
material_handle current { null_handle };
|
material_handle current { null_handle };
|
||||||
|
std::vector<material_handle> tints;
|
||||||
auto const sink = [&]( bool const Matte ) -> geometryhandle_sequence & {
|
auto const sink = [&]( bool const Matte ) -> geometryhandle_sequence & {
|
||||||
if( current == null_handle ) {
|
if( current == null_handle ) {
|
||||||
return Matte ? Cuts : Geometry;
|
return Matte ? Cuts : Geometry;
|
||||||
@@ -1491,11 +1509,12 @@ bool TTrack::lay_rail( rail_layout const &Layout, rail_drawing const &Drawing, i
|
|||||||
if( eType == tt_Switch && current == m_material2 ) {
|
if( eType == tt_Switch && current == m_material2 ) {
|
||||||
return Matte ? GeometryCut2 : Geometry2;
|
return Matte ? GeometryCut2 : Geometry2;
|
||||||
}
|
}
|
||||||
|
auto const tinted { std::find( tints.begin(), tints.end(), current ) != tints.end() };
|
||||||
auto found { std::find_if( GeometryTreads.begin(), GeometryTreads.end(), [&]( tread_geometry const &Tread ) { return Tread.material == current; } ) };
|
auto found { std::find_if( GeometryTreads.begin(), GeometryTreads.end(), [&]( tread_geometry const &Tread ) { return Tread.material == current; } ) };
|
||||||
if( found == GeometryTreads.end() ) {
|
if( found == GeometryTreads.end() ) {
|
||||||
found = GeometryTreads.insert( GeometryTreads.end(), { current, cut_material( current ), {}, {} } );
|
found = GeometryTreads.insert( GeometryTreads.end(), { current, tinted ? current : cut_material( current ), {}, {} } );
|
||||||
}
|
}
|
||||||
return Matte ? found->cuts : found->geometry; };
|
return Matte && false == tinted ? found->cuts : found->geometry; };
|
||||||
auto const texturelength = [&]() {
|
auto const texturelength = [&]() {
|
||||||
return ( current == null_handle ? Texturelength : texture_length( current ) ); };
|
return ( current == null_handle ? Texturelength : texture_length( current ) ); };
|
||||||
auto const aim = [&]( std::vector<rail_tread> const &Spans, double const Middle ) -> rail_tread const * {
|
auto const aim = [&]( std::vector<rail_tread> const &Spans, double const Middle ) -> rail_tread const * {
|
||||||
@@ -1509,10 +1528,10 @@ bool TTrack::lay_rail( rail_layout const &Layout, rail_drawing const &Drawing, i
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
};
|
};
|
||||||
// parts no wheel rolls on go in the matte material of the cut faces
|
// parts no wheel rolls on go in the matte material of the cut faces
|
||||||
auto const piece = [&]( double const Start, double const End, std::vector<glm::dvec2> const &Offsets, std::vector<glm::dvec2> const &Extents, bool const Capstart, bool const Capend, gfx::vertex_array const &Shape, bool const Rolled, std::vector<glm::dvec2> const &Inner, std::vector<glm::dvec2> const &Ramp = {}, bool const Walls = false, float const Lift = 0.f, float const Wallu = -1.f ) {
|
auto const piece = [&]( double const Start, double const End, std::vector<glm::dvec2> const &Offsets, std::vector<glm::dvec2> const &Extents, bool const Capstart, bool const Capend, gfx::vertex_array const &Shape, bool const Rolled, std::vector<glm::dvec2> const &Inner, std::vector<glm::dvec2> const &Ramp = {}, bool const Walls = false, float const Lift = 0.f, float const Wallu = -1.f, double const Fade = blend ) {
|
||||||
gfx::vertex_array vertices;
|
gfx::vertex_array vertices;
|
||||||
gfx::userdata_array userdata;
|
gfx::userdata_array userdata;
|
||||||
if( Shape.size() > 1 && segment.RenderLoftSpan( vertices, m_origin, Shape, Side, halfwidth, texturelength(), Start, End, Offsets, Extents, Lift, Inner, Rolled ? nullptr : &userdata, Ramp, Ramp.empty() ? 0.0 : blend, Walls, Wallu ) ) {
|
if( Shape.size() > 1 && segment.RenderLoftSpan( vertices, m_origin, Shape, Side, halfwidth, texturelength(), Start, End, Offsets, Extents, Lift, Inner, Rolled ? nullptr : &userdata, Ramp, Ramp.empty() ? 0.0 : Fade, Walls, Wallu ) ) {
|
||||||
cut_faces( vertices, Shape.size(), Capstart, Capend, Drawing.bank, sink( true ) );
|
cut_faces( vertices, Shape.size(), Capstart, Capend, Drawing.bank, sink( true ) );
|
||||||
gfx::vertex_array triangles;
|
gfx::vertex_array triangles;
|
||||||
gfx::userdata_array triangleuserdata;
|
gfx::userdata_array triangleuserdata;
|
||||||
@@ -1643,8 +1662,40 @@ bool TTrack::lay_rail( rail_layout const &Layout, rail_drawing const &Drawing, i
|
|||||||
}
|
}
|
||||||
auto const &lower { Span.below ? Span.gauge : Span.edge };
|
auto const &lower { Span.below ? Span.gauge : Span.edge };
|
||||||
auto const &upper { Span.below ? Span.edge : Span.gauge };
|
auto const &upper { Span.below ? Span.edge : Span.gauge };
|
||||||
|
auto const own { rail_material( Path ) };
|
||||||
|
auto const colour { 0.5f * ( tread_colour( Span.material, tread_band() ) + tread_colour( own, tread_band() ) ) };
|
||||||
|
auto const tint = [&]( material_handle const Material ) {
|
||||||
|
auto const tinted { tint_material( Material, colour ) };
|
||||||
|
if( tinted != Material ) {
|
||||||
|
tints.push_back( tinted );
|
||||||
|
}
|
||||||
|
return tinted; };
|
||||||
|
auto const owntint { tint( own ) };
|
||||||
|
auto const sharedtint { tint( Span.material ) };
|
||||||
|
auto const shifted = []( std::vector<glm::dvec2> Knots, double const Lateral ) {
|
||||||
|
for( auto &knot : Knots ) {
|
||||||
|
knot.y += Lateral;
|
||||||
|
}
|
||||||
|
return Knots; };
|
||||||
|
std::vector<glm::dvec2> centre;
|
||||||
|
{
|
||||||
|
std::vector<double> stations;
|
||||||
|
for( auto const *knots : { &lower, &upper } ) {
|
||||||
|
for( auto const &knot : *knots ) {
|
||||||
|
stations.push_back( knot.x );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort( stations.begin(), stations.end() );
|
||||||
|
for( auto const station : stations ) {
|
||||||
|
centre.emplace_back( station, 0.5 * ( level( lower, station ) + level( upper, station ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto const beneath { shifted( lower, -tread_fade ) };
|
||||||
|
auto const beyond { shifted( upper, tread_fade ) };
|
||||||
|
auto const lowfade { bound( shifted( lower, tread_fade ), centre, true ) };
|
||||||
|
auto const highfade { bound( shifted( upper, -tread_fade ), centre, false ) };
|
||||||
std::vector<double> splits { Start, End };
|
std::vector<double> splits { Start, End };
|
||||||
for( auto const *knots : { &lower, &upper } ) {
|
for( auto const *knots : { &lower, &upper, &lowfade, &highfade, &beneath, &beyond } ) {
|
||||||
for( auto const edge : { low, high } ) {
|
for( auto const edge : { low, high } ) {
|
||||||
for( std::size_t i = 1; i < knots->size(); ++i ) {
|
for( std::size_t i = 1; i < knots->size(); ++i ) {
|
||||||
auto const &a { ( *knots )[ i - 1 ] };
|
auto const &a { ( *knots )[ i - 1 ] };
|
||||||
@@ -1659,22 +1710,41 @@ bool TTrack::lay_rail( rail_layout const &Layout, rail_drawing const &Drawing, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort( splits.begin(), splits.end() );
|
std::sort( splits.begin(), splits.end() );
|
||||||
auto const inside { bound( Extents, upper, true ) };
|
|
||||||
for( std::size_t i = 1; i < splits.size(); ++i ) {
|
for( std::size_t i = 1; i < splits.size(); ++i ) {
|
||||||
auto const middle { 0.5 * ( splits[ i - 1 ] + splits[ i ] ) };
|
auto const a { splits[ i - 1 ] };
|
||||||
|
auto const b { splits[ i ] };
|
||||||
|
auto const middle { 0.5 * ( a + b ) };
|
||||||
auto const from { level( lower, middle ) };
|
auto const from { level( lower, middle ) };
|
||||||
auto const to { level( upper, middle ) };
|
auto const to { level( upper, middle ) };
|
||||||
if( from > low ) {
|
auto const inner { level( lowfade, middle ) };
|
||||||
|
auto const outer { level( highfade, middle ) };
|
||||||
|
if( from - tread_fade > low ) {
|
||||||
current = null_handle;
|
current = null_handle;
|
||||||
piece( splits[ i - 1 ], splits[ i ], Offsets, bound( Extents, lower, true ), false, false, top, true, Inner );
|
piece( a, b, Offsets, bound( Extents, beneath, true ), false, false, top, true, Inner );
|
||||||
}
|
}
|
||||||
if( to > low && from < high ) {
|
if( from > low && from - tread_fade < high ) {
|
||||||
|
current = owntint;
|
||||||
|
piece( a, b, Offsets, bound( Extents, lower, true ), false, false, top, false, bound( Inner, beneath, false ), lower, false, 0.f, -1.f, tread_fade );
|
||||||
|
}
|
||||||
|
if( inner > low && from < high ) {
|
||||||
|
current = sharedtint;
|
||||||
|
piece( a, b, Offsets, bound( Extents, lowfade, true ), false, false, top, false, bound( Inner, lower, false ), lower, false, 0.f, -1.f, -tread_fade );
|
||||||
|
}
|
||||||
|
if( outer > low && inner < high ) {
|
||||||
current = Span.material;
|
current = Span.material;
|
||||||
piece( splits[ i - 1 ], splits[ i ], Offsets, inside, false, false, top, true, bound( Inner, lower, false ) );
|
piece( a, b, Offsets, bound( Extents, highfade, true ), false, false, top, true, bound( Inner, lowfade, false ) );
|
||||||
}
|
}
|
||||||
if( to < high ) {
|
if( to > low && outer < high ) {
|
||||||
|
current = sharedtint;
|
||||||
|
piece( a, b, Offsets, bound( Extents, upper, true ), false, false, top, false, bound( Inner, highfade, false ), upper, false, 0.f, -1.f, tread_fade );
|
||||||
|
}
|
||||||
|
if( to + tread_fade > low && to < high ) {
|
||||||
|
current = owntint;
|
||||||
|
piece( a, b, Offsets, bound( Extents, beyond, true ), false, false, top, false, bound( Inner, upper, false ), upper, false, 0.f, -1.f, -tread_fade );
|
||||||
|
}
|
||||||
|
if( to + tread_fade < high ) {
|
||||||
current = null_handle;
|
current = null_handle;
|
||||||
piece( splits[ i - 1 ], splits[ i ], Offsets, Extents, false, false, top, true, bound( Inner, upper, false ) );
|
piece( a, b, Offsets, Extents, false, false, top, true, bound( Inner, beyond, false ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current = null_handle;
|
current = null_handle;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace track_rails {
|
|||||||
|
|
||||||
double constexpr flangeway { 0.045 };
|
double constexpr flangeway { 0.045 };
|
||||||
double constexpr blend { 0.015 };
|
double constexpr blend { 0.015 };
|
||||||
|
double constexpr tread_fade { 0.02 };
|
||||||
double constexpr rolled_band { 0.1 };
|
double constexpr rolled_band { 0.1 };
|
||||||
double constexpr nose_tip { 0.012 };
|
double constexpr nose_tip { 0.012 };
|
||||||
double constexpr middle_angle { 0.35 };
|
double constexpr middle_angle { 0.35 };
|
||||||
@@ -30,6 +31,8 @@ int blade_steps( TTrack const &Track );
|
|||||||
double blade_length( TTrack const &Track, int const Path );
|
double blade_length( TTrack const &Track, int const Path );
|
||||||
material_handle cut_material( material_handle const Material );
|
material_handle cut_material( material_handle const Material );
|
||||||
float tread_brightness( material_handle const Material, glm::vec2 const &Band );
|
float tread_brightness( material_handle const Material, glm::vec2 const &Band );
|
||||||
|
glm::vec3 tread_colour( material_handle const Material, glm::vec2 const &Band );
|
||||||
|
material_handle tint_material( material_handle const Material, glm::vec3 const &Colour );
|
||||||
// triangles closing the first and/or the last cross-section of a lofted strip, made of pairs of points for each of Ring profile points, both sides of each
|
// triangles closing the first and/or the last cross-section of a lofted strip, made of pairs of points for each of Ring profile points, both sides of each
|
||||||
void cap_loft( gfx::vertex_array const &Strip, std::size_t const Ring, bool const Start, bool const End, gfx::vertex_array &Triangles );
|
void cap_loft( gfx::vertex_array const &Strip, std::size_t const Ring, bool const Start, bool const End, gfx::vertex_array &Triangles );
|
||||||
gfx::userdata_array worn_userdata( std::size_t const Count );
|
gfx::userdata_array worn_userdata( std::size_t const Count );
|
||||||
|
|||||||
Reference in New Issue
Block a user