mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 03:59:19 +02:00
refactor(track): the plates, fillers and check rails of a rail drawing are made from one box_profile and one helper for both sides, and the colour of a tread is sampled by sample_dds and sample_image into one colour_mean, a block of a DXT texture decoded by add_dxt_block, instead of one function
This commit is contained in:
@@ -149,8 +149,28 @@ void cut_faces( gfx::vertex_array const &Strip, std::size_t const Ring, bool con
|
||||
|
||||
using namespace track_rails;
|
||||
|
||||
namespace {
|
||||
|
||||
gfx::vertex_array box_profile( float const Bottom, float const Top, float const Texture ) {
|
||||
|
||||
return {
|
||||
{{ 1.f, Bottom, 0.f }, { 1.f, 0.f, 0.f }, { Texture, 0.f }},
|
||||
{{ 1.f, Top, 0.f }, { 1.f, 0.f, 0.f }, { Texture, 0.f }},
|
||||
{{ 1.f, Top, 0.f }, { 0.f, 1.f, 0.f }, { Texture, 0.f }},
|
||||
{{ -1.f, Top, 0.f }, { 0.f, 1.f, 0.f }, { Texture, 0.f }},
|
||||
{{ -1.f, Top, 0.f }, { -1.f, 0.f, 0.f }, { Texture, 0.f }},
|
||||
{{ -1.f, Bottom, 0.f }, { -1.f, 0.f, 0.f }, { Texture, 0.f }} };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TTrack::rail_drawing TTrack::make_rail_drawing( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
auto const sides = [&]( gfx::vertex_array const &Shape, gfx::vertex_array ( &Sides )[ 2 ] ) {
|
||||
create_track_rail_profile( Sides[ 0 ], Sides[ 1 ], &Shape );
|
||||
for( auto &side : Sides ) {
|
||||
side.resize( Shape.size() );
|
||||
} };
|
||||
rail_drawing drawing;
|
||||
drawing.bank = Bank;
|
||||
drawing.size = rail_dimensions();
|
||||
@@ -170,10 +190,7 @@ TTrack::rail_drawing TTrack::make_rail_drawing( gfx::geometrybank_handle const &
|
||||
point.position.x = -0.041f + ( point.position.x + 0.041f ) * static_cast<float>( drawing.size.head / 0.0735 );
|
||||
point.position.y *= static_cast<float>( drawing.size.height / 0.172 );
|
||||
}
|
||||
create_track_rail_profile( drawing.checkshapes[ 0 ], drawing.checkshapes[ 1 ], &checkshape );
|
||||
for( auto &shape : drawing.checkshapes ) {
|
||||
shape.resize( checkshape.size() );
|
||||
}
|
||||
sides( checkshape, drawing.checkshapes );
|
||||
if( false == m_profiles.empty() ) {
|
||||
auto const &outline { track_rail_profile( m_profile1.second ) };
|
||||
auto texture { 0.f };
|
||||
@@ -197,18 +214,8 @@ TTrack::rail_drawing TTrack::make_rail_drawing( gfx::geometrybank_handle const &
|
||||
}
|
||||
auto const top { static_cast<float>( ( drawing.size.grooved ? drawing.size.liptop : highest ) - 0.0005 ) };
|
||||
auto const bottom { static_cast<float>( -drawing.size.height ) };
|
||||
gfx::vertex_array plate {
|
||||
{{ 1.f, bottom, 0.f }, { 1.f, 0.f, 0.f }, { texture, 0.f }},
|
||||
{{ 1.f, top, 0.f }, { 1.f, 0.f, 0.f }, { texture, 0.f }},
|
||||
{{ 1.f, top, 0.f }, { 0.f, 1.f, 0.f }, { texture, 0.f }},
|
||||
{{ -1.f, top, 0.f }, { 0.f, 1.f, 0.f }, { texture, 0.f }},
|
||||
{{ -1.f, top, 0.f }, { -1.f, 0.f, 0.f }, { texture, 0.f }},
|
||||
{{ -1.f, bottom, 0.f }, { -1.f, 0.f, 0.f }, { texture, 0.f }} };
|
||||
drawing.platetexture = texture;
|
||||
create_track_rail_profile( drawing.plates[ 0 ], drawing.plates[ 1 ], &plate );
|
||||
for( auto &shape : drawing.plates ) {
|
||||
shape.resize( plate.size() );
|
||||
}
|
||||
sides( box_profile( bottom, top, texture ), drawing.plates );
|
||||
auto const neck { static_cast<float>( drawing.size.neck ) };
|
||||
auto webtexture { texture };
|
||||
for( std::size_t i = 0; i < outline.size() / 2; ++i ) {
|
||||
@@ -218,17 +225,7 @@ TTrack::rail_drawing TTrack::make_rail_drawing( gfx::geometrybank_handle const &
|
||||
break;
|
||||
}
|
||||
}
|
||||
gfx::vertex_array filler {
|
||||
{{ 1.f, bottom, 0.f }, { 1.f, 0.f, 0.f }, { webtexture, 0.f }},
|
||||
{{ 1.f, neck, 0.f }, { 1.f, 0.f, 0.f }, { webtexture, 0.f }},
|
||||
{{ 1.f, neck, 0.f }, { 0.f, 1.f, 0.f }, { webtexture, 0.f }},
|
||||
{{ -1.f, neck, 0.f }, { 0.f, 1.f, 0.f }, { webtexture, 0.f }},
|
||||
{{ -1.f, neck, 0.f }, { -1.f, 0.f, 0.f }, { webtexture, 0.f }},
|
||||
{{ -1.f, bottom, 0.f }, { -1.f, 0.f, 0.f }, { webtexture, 0.f }} };
|
||||
create_track_rail_profile( drawing.fillers[ 0 ], drawing.fillers[ 1 ], &filler );
|
||||
for( auto &shape : drawing.fillers ) {
|
||||
shape.resize( filler.size() );
|
||||
}
|
||||
sides( box_profile( bottom, neck, webtexture ), drawing.fillers );
|
||||
}
|
||||
return drawing;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,101 @@ material_handle tint_material( material_handle const Material, glm::vec3 const &
|
||||
return GfxRenderer->Tinted_Material( Material, Colour );
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct colour_mean {
|
||||
double sum { 0.0 };
|
||||
glm::dvec3 colour { 0.0 };
|
||||
std::size_t count { 0 };
|
||||
|
||||
void add( float const Red, float const Green, float const 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; }
|
||||
};
|
||||
|
||||
std::pair<int, int> band_columns( glm::vec2 const &Band, int const Width ) {
|
||||
|
||||
auto const first { std::clamp( static_cast<int>( std::floor( std::min( Band.x, Band.y ) * Width ) ), 0, Width - 1 ) };
|
||||
auto const last { std::clamp( static_cast<int>( std::ceil( std::max( Band.x, Band.y ) * Width ) ) - 1, first, Width - 1 ) };
|
||||
return { first, last };
|
||||
}
|
||||
|
||||
glm::vec3 unpack_565( unsigned const Color ) {
|
||||
|
||||
return glm::vec3{ ( ( Color >> 11 ) & 31 ) * 255.f / 31.f, ( ( Color >> 5 ) & 63 ) * 255.f / 63.f, ( Color & 31 ) * 255.f / 31.f };
|
||||
}
|
||||
|
||||
void add_dxt_block( unsigned char const *Block, bool const Alpha, int const Column, int const First, int const Last, colour_mean &Mean ) {
|
||||
|
||||
auto const low { static_cast<unsigned>( Block[ 0 ] | Block[ 1 ] << 8 ) };
|
||||
auto const top { static_cast<unsigned>( Block[ 2 ] | Block[ 3 ] << 8 ) };
|
||||
auto const opaque { Alpha || low > top };
|
||||
glm::vec3 const colors[ 4 ] {
|
||||
unpack_565( low ),
|
||||
unpack_565( top ),
|
||||
opaque ? ( 2.f * unpack_565( low ) + unpack_565( top ) ) / 3.f : 0.5f * ( unpack_565( low ) + unpack_565( top ) ),
|
||||
opaque ? ( unpack_565( low ) + 2.f * unpack_565( top ) ) / 3.f : glm::vec3{ 0.f } };
|
||||
auto const bits { static_cast<std::uint32_t>( Block[ 4 ] ) | static_cast<std::uint32_t>( Block[ 5 ] ) << 8 | static_cast<std::uint32_t>( Block[ 6 ] ) << 16 | static_cast<std::uint32_t>( Block[ 7 ] ) << 24 };
|
||||
for( int texel = 0; texel < 16; ++texel ) {
|
||||
auto const x { Column * 4 + texel % 4 };
|
||||
auto const index { ( bits >> ( 2 * texel ) ) & 3 };
|
||||
if( x < First || x > Last || ( false == opaque && index == 3 ) ) {
|
||||
continue;
|
||||
}
|
||||
Mean.add( colors[ index ].r, colors[ index ].g, colors[ index ].b );
|
||||
}
|
||||
}
|
||||
|
||||
void sample_dds( std::string const &File, glm::vec2 const &Band, colour_mean &Mean ) {
|
||||
|
||||
std::ifstream input( File, std::ios::binary );
|
||||
std::array<unsigned char, 128> header {};
|
||||
if( !input.read( reinterpret_cast<char *>( header.data() ), header.size() ) || false == std::equal( header.begin(), header.begin() + 4, "DDS " ) ) {
|
||||
return;
|
||||
}
|
||||
auto const word = [&]( std::size_t const Offset ) {
|
||||
return static_cast<std::uint32_t>( header[ Offset ] ) | static_cast<std::uint32_t>( header[ Offset + 1 ] ) << 8 | static_cast<std::uint32_t>( header[ Offset + 2 ] ) << 16 | static_cast<std::uint32_t>( header[ Offset + 3 ] ) << 24; };
|
||||
auto const height { static_cast<int>( word( 12 ) ) };
|
||||
auto const width { static_cast<int>( word( 16 ) ) };
|
||||
auto const fourcc { word( 84 ) };
|
||||
auto const blocksize { fourcc == 0x31545844u ? 8 : ( fourcc == 0x33545844u || fourcc == 0x35545844u ) ? 16 : 0 };
|
||||
if( blocksize == 0 || width <= 0 || height <= 0 ) {
|
||||
return;
|
||||
}
|
||||
auto const wide { ( width + 3 ) / 4 };
|
||||
auto const high { ( height + 3 ) / 4 };
|
||||
std::vector<unsigned char> data( static_cast<std::size_t>( wide ) * high * blocksize );
|
||||
if( !input.read( reinterpret_cast<char *>( data.data() ), data.size() ) ) {
|
||||
return;
|
||||
}
|
||||
auto const [ first, last ] { band_columns( Band, width ) };
|
||||
for( int row = 0; row < high; ++row ) {
|
||||
for( int column = first / 4; column <= last / 4; ++column ) {
|
||||
add_dxt_block( &data[ ( static_cast<std::size_t>( row ) * wide + column ) * blocksize + ( blocksize - 8 ) ], blocksize == 16, column, first, last, Mean );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sample_image( std::string const &File, glm::vec2 const &Band, colour_mean &Mean ) {
|
||||
|
||||
int width, height, components;
|
||||
auto *pixels { stbi_load( File.c_str(), &width, &height, &components, 4 ) };
|
||||
if( pixels == nullptr ) {
|
||||
return;
|
||||
}
|
||||
auto const [ first, last ] { band_columns( Band, width ) };
|
||||
for( int y = 0; y < height; ++y ) {
|
||||
for( int x = first; x <= last; ++x ) {
|
||||
auto const *pixel { &pixels[ ( static_cast<std::size_t>( y ) * width + x ) * 4 ] };
|
||||
Mean.add( pixel[ 0 ], pixel[ 1 ], pixel[ 2 ] );
|
||||
}
|
||||
}
|
||||
stbi_image_free( pixels );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
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;
|
||||
@@ -45,76 +140,15 @@ std::pair<float, glm::vec3> const &tread_sample( material_handle const Material,
|
||||
auto const &image { GfxRenderer->Texture( texture ) };
|
||||
auto const type { std::string( image.get_type() ) };
|
||||
auto const file { std::string( image.get_name() ) + type };
|
||||
auto const columns = [&]( int const Width ) {
|
||||
auto const first { std::clamp( static_cast<int>( std::floor( std::min( Band.x, Band.y ) * Width ) ), 0, 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 }; };
|
||||
auto sum { 0.0 };
|
||||
glm::dvec3 colour { 0.0 };
|
||||
std::size_t count { 0 };
|
||||
auto const add = [&]( float const Red, float const Green, float const 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; };
|
||||
colour_mean mean;
|
||||
if( type == ".dds" ) {
|
||||
std::ifstream input( file, std::ios::binary );
|
||||
std::array<unsigned char, 128> header {};
|
||||
if( input.read( reinterpret_cast<char *>( header.data() ), header.size() ) && std::equal( header.begin(), header.begin() + 4, "DDS " ) ) {
|
||||
auto const word = [&]( std::size_t const Offset ) {
|
||||
return static_cast<std::uint32_t>( header[ Offset ] ) | static_cast<std::uint32_t>( header[ Offset + 1 ] ) << 8 | static_cast<std::uint32_t>( header[ Offset + 2 ] ) << 16 | static_cast<std::uint32_t>( header[ Offset + 3 ] ) << 24; };
|
||||
auto const height { static_cast<int>( word( 12 ) ) };
|
||||
auto const width { static_cast<int>( word( 16 ) ) };
|
||||
auto const fourcc { word( 84 ) };
|
||||
auto const blocksize { fourcc == 0x31545844u ? 8 : ( fourcc == 0x33545844u || fourcc == 0x35545844u ) ? 16 : 0 };
|
||||
if( blocksize > 0 && width > 0 && height > 0 ) {
|
||||
auto const wide { ( width + 3 ) / 4 };
|
||||
auto const high { ( height + 3 ) / 4 };
|
||||
std::vector<unsigned char> data( static_cast<std::size_t>( wide ) * high * blocksize );
|
||||
if( input.read( reinterpret_cast<char *>( data.data() ), data.size() ) ) {
|
||||
auto const [ first, last ] { columns( width ) };
|
||||
auto const unpack = []( unsigned const Color ) {
|
||||
return glm::vec3{ ( ( Color >> 11 ) & 31 ) * 255.f / 31.f, ( ( Color >> 5 ) & 63 ) * 255.f / 63.f, ( Color & 31 ) * 255.f / 31.f }; };
|
||||
for( int row = 0; row < high; ++row ) {
|
||||
for( int column = first / 4; column <= last / 4; ++column ) {
|
||||
auto const *block { &data[ ( static_cast<std::size_t>( row ) * wide + column ) * blocksize + ( blocksize - 8 ) ] };
|
||||
auto const low { static_cast<unsigned>( block[ 0 ] | block[ 1 ] << 8 ) };
|
||||
auto const top { static_cast<unsigned>( block[ 2 ] | block[ 3 ] << 8 ) };
|
||||
auto const opaque { blocksize == 16 || low > top };
|
||||
glm::vec3 const colors[ 4 ] {
|
||||
unpack( low ),
|
||||
unpack( top ),
|
||||
opaque ? ( 2.f * unpack( low ) + unpack( top ) ) / 3.f : 0.5f * ( unpack( low ) + unpack( top ) ),
|
||||
opaque ? ( unpack( low ) + 2.f * unpack( top ) ) / 3.f : glm::vec3{ 0.f } };
|
||||
auto const bits { static_cast<std::uint32_t>( block[ 4 ] ) | static_cast<std::uint32_t>( block[ 5 ] ) << 8 | static_cast<std::uint32_t>( block[ 6 ] ) << 16 | static_cast<std::uint32_t>( block[ 7 ] ) << 24 };
|
||||
for( int texel = 0; texel < 16; ++texel ) {
|
||||
auto const x { column * 4 + texel % 4 };
|
||||
auto const index { ( bits >> ( 2 * texel ) ) & 3 };
|
||||
if( x < first || x > last || ( false == opaque && index == 3 ) ) {
|
||||
continue;
|
||||
}
|
||||
add( colors[ index ].r, colors[ index ].g, colors[ index ].b );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sample_dds( file, Band, mean );
|
||||
}
|
||||
else {
|
||||
int width, height, components;
|
||||
if( auto *pixels { stbi_load( file.c_str(), &width, &height, &components, 4 ) } ) {
|
||||
auto const [ first, last ] { columns( width ) };
|
||||
for( int y = 0; y < height; ++y ) {
|
||||
for( int x = first; x <= last; ++x ) {
|
||||
auto const *pixel { &pixels[ ( static_cast<std::size_t>( y ) * width + x ) * 4 ] };
|
||||
add( pixel[ 0 ], pixel[ 1 ], pixel[ 2 ] );
|
||||
}
|
||||
}
|
||||
stbi_image_free( pixels );
|
||||
}
|
||||
sample_image( file, Band, mean );
|
||||
}
|
||||
if( count > 0 ) {
|
||||
result = { static_cast<float>( sum / count ), glm::vec3{ colour / static_cast<double>( count ) } };
|
||||
if( mean.count > 0 ) {
|
||||
result = { static_cast<float>( mean.sum / mean.count ), glm::vec3{ mean.colour / static_cast<double>( mean.count ) } };
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user