From dba0a035fd0d5e110b7a61e1b2bb0d62736dfac9 Mon Sep 17 00:00:00 2001 From: Wls50 <167411000+wls50@users.noreply.github.com> Date: Sun, 30 Jun 2024 16:13:19 +0200 Subject: [PATCH] add user data vector to basic_vertex update t3d, e3d & sbt specs accordingly update node model to shape conversion to support indexed meshes --- Model3d.cpp | 89 +++++++++++++++++++++++++++++++--------- Model3d.h | 2 +- geometrybank.cpp | 43 +++++++++++++++++-- geometrybank.h | 13 ++++-- opengl33geometrybank.cpp | 9 ++-- openglgeometrybank.cpp | 8 ++-- scene.cpp | 2 +- scenenode.cpp | 59 +++++++++++++------------- shaders/vertex.vert | 3 ++ vertex.h | 1 + 10 files changed, 162 insertions(+), 67 deletions(-) diff --git a/Model3d.cpp b/Model3d.cpp index 7fbd655a..3cbdae24 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -209,6 +209,21 @@ inline void readMatrix(cParser &parser, float4x4 &matrix) parser >> matrix(x)[y]; }; +template void UserdataParse(cParser &parser, gfx::basic_vertex &vertex) +{ + parser.getTokens(4); + union + { + T InType; + float FloatType; + } buf{}; + for (int i = 0; i < 4; ++i) + { + parser >> buf.InType; + vertex.user_data[i] = buf.FloatType; + } +} + std::pair TSubModel::Load( cParser &parser, bool dynamic ) { // Ra: VBO tworzone na poziomie modelu, a nie submodeli auto token { parser.getToken() }; @@ -478,8 +493,32 @@ std::pair TSubModel::Load( cParser &parser, bool dynamic ) } if (eType < TP_ROTATOR) { // wczytywanie wierzchołków - token = parser.getToken(); - if( token == "numindices:" ) // optional block, potentially preceeding vertex list + token = parser.getToken(); + enum class UserDataType + { + None, + Float, + Int, + UInt, + Count + } user_data = UserDataType::None; + if (token == "userdata:") + { + const static std::map type_mapping{{"float", UserDataType::Float}, {"int", UserDataType::Int}, {"uint", UserDataType::UInt}}; + const std::string type = parser.getToken(); + + if (auto it = type_mapping.find(type); it != type_mapping.end()) + { + user_data = it->second; + } + else + { + user_data = UserDataType::None; + } + + token = parser.getToken(); + } + if( token == "numindices:" ) // optional block, potentially preceeding vertex list { m_geometry.index_count = parser.getToken( false ); Indices.resize( m_geometry.index_count ); @@ -662,7 +701,17 @@ std::pair TSubModel::Load( cParser &parser, bool dynamic ) m_geometry.index_count = Indices.size(); m_geometry.vertex_count = Vertices.size(); } - } + if (user_data != UserDataType::None) + { + const static std::array(UserDataType::Count)> parsers{nullptr, &UserdataParse, &UserdataParse, + &UserdataParse}; + auto vertices { std::begin( Vertices ) }; + for( auto idx = 0; idx < m_geometry.vertex_count; ++idx ) { + auto vertex { vertices + idx }; + parsers[static_cast(user_data)](parser, *vertex); + } + } + } else // gdy brak wierzchołków { eType = TP_ROTATOR; // submodel pomocniczy, ma tylko macierz przekształcenia @@ -1163,25 +1212,25 @@ void TSubModel::RaAnimation(glm::mat4 &m, TAnimType a) //--------------------------------------------------------------------------- -void TSubModel::serialize_geometry( std::ostream &Output, bool const Packed, bool const Indexed ) const { +void TSubModel::serialize_geometry( std::ostream &Output, bool const Packed, bool const Indexed, bool const UserData ) const { if( Child ) { - Child->serialize_geometry( Output, Packed, Indexed ); + Child->serialize_geometry( Output, Packed, Indexed, UserData ); } if( m_geometry.handle != null_handle ) { if( Packed ) { for( auto const &vertex : GfxRenderer->Vertices( m_geometry.handle ) ) { - vertex.serialize_packed( Output, Indexed ); + vertex.serialize_packed( Output, Indexed, UserData ); } } else { for( auto const &vertex : GfxRenderer->Vertices( m_geometry.handle ) ) { - vertex.serialize( Output, Indexed ); + vertex.serialize( Output, Indexed, UserData ); } } } if( Next ) { - Next->serialize_geometry( Output, Packed, Indexed ); + Next->serialize_geometry( Output, Packed, Indexed, UserData ); } }; @@ -1682,20 +1731,20 @@ void TModel3d::SaveToBinFile(std::string const &FileName) Root->serialize_indices( s, indexsize ); if (!(Global.iConvertModels & 8)) { - sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '1' ) ); + sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '1' + 4 ) ); sn_utils::ls_uint32( s, 8 + m_vertexcount * 20 ); - Root->serialize_geometry( s, true, true ); + Root->serialize_geometry( s, true, true, true ); } else { - sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '2' ) ); + sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '2' + 4 ) ); sn_utils::ls_uint32( s, 8 + m_vertexcount * 48 ); - Root->serialize_geometry( s, false, true ); + Root->serialize_geometry( s, false, true, true ); } } else { - sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '0' ) ); + sn_utils::ls_uint32( s, MAKE_ID4( 'V', 'N', 'T', '0' + 4 ) ); sn_utils::ls_uint32( s, 8 + m_vertexcount * 32 ); - Root->serialize_geometry( s, false, false ); + Root->serialize_geometry( s, false, false, true ); } if (textures.size()) @@ -1785,6 +1834,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) std::streampos end = s.tellg() + (std::streampos)size; bool hastangents { false }; + bool hasuserdata {false}; while (s.tellg() < end) { @@ -1828,17 +1878,18 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) return (Left.first) < (Right.first); } ); // once sorted we can grab geometry as it comes, and assign it to the chunks it belongs to size_t const vertextype { ( ( ( type & 0xFF000000 ) >> 24 ) - '0' ) }; - hastangents = ( vertextype > 0 ); + hastangents = ( (vertextype & 3) > 0 ); + hasuserdata = (vertextype & 4); for( auto const &submodeloffset : submodeloffsets ) { auto &submodel { Root[ submodeloffset.second ] }; auto const &submodelgeometry { submodel.m_geometry }; submodel.Vertices.resize( submodelgeometry.vertex_count ); m_vertexcount += submodelgeometry.vertex_count; - switch( vertextype ) { + switch( vertextype & 3 ) { case 0: { // legacy vnt0 format for( auto &vertex : submodel.Vertices ) { - vertex.deserialize( s, hastangents ); + vertex.deserialize( s, hastangents, hasuserdata ); if( submodel.eType < TP_ROTATOR ) { // normal vectors debug routine if( ( false == submodel.m_normalizenormals ) @@ -1853,14 +1904,14 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) case 1: { // expanded chunk formats for( auto &vertex : submodel.Vertices ) { - vertex.deserialize_packed( s, hastangents ); + vertex.deserialize_packed( s, hastangents, hasuserdata ); } break; } case 2: { // expanded chunk formats for( auto &vertex : submodel.Vertices ) { - vertex.deserialize( s, hastangents ); + vertex.deserialize( s, hastangents, hasuserdata ); } break; } diff --git a/Model3d.h b/Model3d.h index 256c583a..e31425ad 100644 --- a/Model3d.h +++ b/Model3d.h @@ -243,7 +243,7 @@ public: std::vector&, std::vector&, std::vector&); - void serialize_geometry( std::ostream &Output, bool const Packed, bool const Indexed ) const; + void serialize_geometry( std::ostream &Output, bool const Packed, bool const Indexed, bool const UserData ) const; int index_size() const; void serialize_indices( std::ostream &Output, int const Size ) const; // places contained geometry in provided ground node diff --git a/geometrybank.cpp b/geometrybank.cpp index 47dd316c..cb6b3c1e 100644 --- a/geometrybank.cpp +++ b/geometrybank.cpp @@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "geometrybank.h" +#include "vertex.h" #include "sn_utils.h" #include "Logs.h" @@ -16,8 +17,30 @@ http://mozilla.org/MPL/2.0/. namespace gfx { +basic_vertex basic_vertex::convert(world_vertex const &world, glm::dvec3 const& origin) +{ + basic_vertex vertex{}; + vertex.position = static_cast(world.position - origin); + vertex.normal = world.normal; + vertex.texture = world.texture; + vertex.user_data = world.user_data; + return vertex; +} + +world_vertex basic_vertex::to_world(const glm::dvec3 &origin) const +{ + world_vertex vertex{}; + + vertex.position = static_cast(position) + origin; + vertex.normal = normal; + vertex.texture = texture; + vertex.user_data = user_data; + + return vertex; +} + void -basic_vertex::serialize( std::ostream &s, bool const Tangent ) const { +basic_vertex::serialize( std::ostream &s, bool const Tangent, bool const UserData ) const { sn_utils::s_vec3( s, position ); sn_utils::s_vec3( s, normal ); @@ -26,10 +49,13 @@ basic_vertex::serialize( std::ostream &s, bool const Tangent ) const { if( Tangent ) { sn_utils::s_vec4( s, tangent ); } + if( UserData ) { + sn_utils::s_vec4( s, user_data ); + } } void -basic_vertex::deserialize( std::istream &s, bool const Tangent ) { +basic_vertex::deserialize( std::istream &s, bool const Tangent, bool const UserData ) { position = sn_utils::d_vec3( s ); normal = sn_utils::d_vec3( s ); @@ -38,10 +64,13 @@ basic_vertex::deserialize( std::istream &s, bool const Tangent ) { if( Tangent ) { tangent = sn_utils::d_vec4( s ); } + if( UserData ) { + user_data = sn_utils::d_vec4( s ); + } } void -basic_vertex::serialize_packed( std::ostream &s, bool const Tangent ) const { +basic_vertex::serialize_packed( std::ostream &s, bool const Tangent, bool const UserData ) const { sn_utils::ls_uint64( s, glm::packHalf4x16( { position, 0.f } ) ); sn_utils::ls_uint32( s, glm::packSnorm3x10_1x2( { normal, 0.f } ) ); @@ -50,10 +79,13 @@ basic_vertex::serialize_packed( std::ostream &s, bool const Tangent ) const { if( Tangent ) { sn_utils::ls_uint32( s, glm::packSnorm3x10_1x2( tangent ) ); } + if( UserData ) { + sn_utils::ls_uint64( s, glm::packHalf4x16( user_data )); + } } void -basic_vertex::deserialize_packed( std::istream &s, bool const Tangent ) { +basic_vertex::deserialize_packed( std::istream &s, bool const Tangent, bool const UserData ) { position = glm::unpackHalf4x16( sn_utils::ld_uint64( s ) ); normal = glm::unpackSnorm3x10_1x2( sn_utils::ld_uint32( s ) ); @@ -62,6 +94,9 @@ basic_vertex::deserialize_packed( std::istream &s, bool const Tangent ) { if( Tangent ) { tangent = glm::unpackSnorm3x10_1x2( sn_utils::ld_uint32( s ) ); } + if( UserData ) { + user_data = glm::unpackHalf4x16( sn_utils::ld_uint64( s ) ); + } } // based on diff --git a/geometrybank.h b/geometrybank.h index 2f067388..5f54146a 100644 --- a/geometrybank.h +++ b/geometrybank.h @@ -11,6 +11,8 @@ http://mozilla.org/MPL/2.0/. #include "ResourceManager.h" +struct world_vertex; + namespace gfx { struct basic_vertex { @@ -19,15 +21,18 @@ struct basic_vertex { glm::vec3 normal; // 3d space glm::vec2 texture; // uv space glm::vec4 tangent; // xyz - tangent, w - handedness + glm::vec4 user_data; // user data (for color or additional uv channels, not subject to post-processing) basic_vertex() = default; basic_vertex( glm::vec3 Position, glm::vec3 Normal, glm::vec2 Texture ) : position( Position ), normal( Normal ), texture( Texture ) {} - void serialize( std::ostream&, bool const Tangent = false ) const; - void deserialize( std::istream&, bool const Tangent = false ); - void serialize_packed( std::ostream&, bool const Tangent = false ) const; - void deserialize_packed( std::istream&, bool const Tangent = false ); + static basic_vertex convert(world_vertex const &world, glm::dvec3 const &origin); + world_vertex to_world(glm::dvec3 const &origin = glm::dvec3(0.)) const; + void serialize( std::ostream&, bool const Tangent = false, bool const UserData = false ) const; + void deserialize( std::istream&, bool const Tangent = false, bool const UserData = false ); + void serialize_packed( std::ostream&, bool const Tangent = false, bool const UserData = false ) const; + void deserialize_packed( std::istream&, bool const Tangent = false, bool const UserData = false ); }; // data streams carried in a vertex diff --git a/opengl33geometrybank.cpp b/opengl33geometrybank.cpp index 62ff4f47..e5dd6f31 100644 --- a/opengl33geometrybank.cpp +++ b/opengl33geometrybank.cpp @@ -101,11 +101,12 @@ void opengl33_vaogeometrybank::setup_buffer() void opengl33_vaogeometrybank::setup_attrib(size_t offset) { - m_vao->setup_attrib( *m_vertexbuffer, 0, 3, GL_FLOAT, sizeof( basic_vertex ), 0 * sizeof( float ) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 0, 3, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, position) + offset * sizeof( basic_vertex ) ); // NOTE: normal and color streams share the data - m_vao->setup_attrib( *m_vertexbuffer, 1, 3, GL_FLOAT, sizeof( basic_vertex ), 3 * sizeof( float ) + offset * sizeof( basic_vertex ) ); - m_vao->setup_attrib( *m_vertexbuffer, 2, 2, GL_FLOAT, sizeof( basic_vertex ), 6 * sizeof( float ) + offset * sizeof( basic_vertex ) ); - m_vao->setup_attrib( *m_vertexbuffer, 3, 4, GL_FLOAT, sizeof( basic_vertex ), 8 * sizeof( float ) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 1, 3, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, normal) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 2, 2, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, texture) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 3, 4, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, tangent) + offset * sizeof( basic_vertex ) ); + m_vao->setup_attrib( *m_vertexbuffer, 4, 4, GL_FLOAT, sizeof( basic_vertex ), offsetof(basic_vertex, user_data) + offset * sizeof( basic_vertex ) ); } // draw() subclass details diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index 961b2716..43aeb0f3 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -227,7 +227,7 @@ void opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned int const Streams, size_t offset ) { if( Streams & gfx::stream::position ) { - ::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( sizeof( gfx::basic_vertex ) * offset ) ); + ::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( offsetof(gfx::basic_vertex, position) + sizeof( gfx::basic_vertex ) * offset ) ); ::glEnableClientState( GL_VERTEX_ARRAY ); } else { @@ -235,14 +235,14 @@ opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned i } // NOTE: normal and color streams share the data, making them effectively mutually exclusive if( Streams & gfx::stream::normal ) { - ::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( 12 + sizeof( gfx::basic_vertex ) * offset ) ); + ::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( offsetof(gfx::basic_vertex, normal) + sizeof( gfx::basic_vertex ) * offset ) ); ::glEnableClientState( GL_NORMAL_ARRAY ); } else { ::glDisableClientState( GL_NORMAL_ARRAY ); } if( Streams & gfx::stream::color ) { - ::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( 12 + sizeof( gfx::basic_vertex ) * offset ) ); + ::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( offsetof(gfx::basic_vertex, normal) + sizeof( gfx::basic_vertex ) * offset ) ); ::glEnableClientState( GL_COLOR_ARRAY ); } else { @@ -251,7 +251,7 @@ opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned i if( Streams & gfx::stream::texture ) { for( auto unit : Units.texture ) { ::glClientActiveTexture( GL_TEXTURE0 + unit ); - ::glTexCoordPointer( 2, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( 24 + sizeof( gfx::basic_vertex ) * offset ) ); + ::glTexCoordPointer( 2, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast( offsetof(gfx::basic_vertex, texture) + sizeof( gfx::basic_vertex ) * offset ) ); ::glEnableClientState( GL_TEXTURE_COORD_ARRAY ); } m_activetexturearrays = Units.texture; diff --git a/scene.cpp b/scene.cpp index 6ca35dc0..9eac1af6 100644 --- a/scene.cpp +++ b/scene.cpp @@ -26,7 +26,7 @@ namespace scene { std::string const EU07_FILEEXTENSION_REGION { ".sbt" }; std::uint32_t const EU07_FILEHEADER { MAKE_ID4( 'E','U','0','7' ) }; -std::uint32_t const EU07_FILEVERSION_REGION { MAKE_ID4( 'S', 'B', 'T', 1 ) }; +std::uint32_t const EU07_FILEVERSION_REGION { MAKE_ID4( 'S', 'B', 'T', '2' ) }; // potentially activates event handler with the same name as provided node, and within handler activation range void diff --git a/scenenode.cpp b/scenenode.cpp index a8f186b7..9d809d7a 100644 --- a/scenenode.cpp +++ b/scenenode.cpp @@ -81,11 +81,8 @@ shape_node::shapenode_data::serialize( std::ostream &Output ) const { // vertex count, followed by vertex data sn_utils::ls_uint32( Output, vertices.size() ); for( auto const &vertex : vertices ) { - gfx::basic_vertex( - glm::vec3{ vertex.position - origin }, - vertex.normal, - vertex.texture ) - .serialize( Output ); + gfx::basic_vertex::convert(vertex, origin) + .serialize( Output, false, true ); } } @@ -112,10 +109,8 @@ shape_node::shapenode_data::deserialize( std::istream &Input ) { vertices.resize( sn_utils::ld_uint32( Input ) ); gfx::basic_vertex localvertex; for( auto &vertex : vertices ) { - localvertex.deserialize( Input ); - vertex.position = origin + glm::dvec3{ localvertex.position }; - vertex.normal = localvertex.normal; - vertex.texture = localvertex.texture; + localvertex.deserialize( Input, false, true ); + vertex = localvertex.to_world(origin); } } @@ -353,23 +348,30 @@ shape_node::convert( TSubModel const *Submodel ) { int vertexcount { 0 }; std::vector importedvertices; world_vertex vertex, vertex1, vertex2; - for( auto const &sourcevertex : GfxRenderer->Vertices( Submodel->m_geometry.handle ) ) { - vertex.position = sourcevertex.position; - vertex.normal = sourcevertex.normal; - vertex.texture = sourcevertex.texture; - if( vertexcount == 0 ) { vertex1 = vertex; } - else if( vertexcount == 1 ) { vertex2 = vertex; } - else if( vertexcount >= 2 ) { - if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) { - importedvertices.emplace_back( vertex1 ); - importedvertices.emplace_back( vertex2 ); - importedvertices.emplace_back( vertex ); - } - // start a new triangle - vertexcount = -1; - } - ++vertexcount; - } + if(!GfxRenderer->Indices(Submodel->m_geometry.handle).empty()){ + const auto& vertices = GfxRenderer->Vertices(Submodel->m_geometry.handle); + for(const auto index : GfxRenderer->Indices(Submodel->m_geometry.handle)){ + vertex = vertices[index].to_world(); + importedvertices.emplace_back(vertex); + } + } + else{ + for( auto const &sourcevertex : GfxRenderer->Vertices( Submodel->m_geometry.handle ) ) { + vertex = sourcevertex.to_world(); + if( vertexcount == 0 ) { vertex1 = vertex; } + else if( vertexcount == 1 ) { vertex2 = vertex; } + else if( vertexcount >= 2 ) { + if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) { + importedvertices.emplace_back( vertex1 ); + importedvertices.emplace_back( vertex2 ); + importedvertices.emplace_back( vertex ); + } + // start a new triangle + vertexcount = -1; + } + ++vertexcount; + } + } if( true == importedvertices.empty() ) { return *this; } @@ -423,10 +425,7 @@ shape_node::create_geometry( gfx::geometrybank_handle const &Bank ) { gfx::vertex_array vertices; vertices.reserve( m_data.vertices.size() ); for( auto const &vertex : m_data.vertices ) { - vertices.emplace_back( - vertex.position - m_data.origin, - vertex.normal, - vertex.texture ); + vertices.emplace_back(gfx::basic_vertex::convert(vertex, m_data.origin)); } m_data.geometry = GfxRenderer->Insert( vertices, Bank, GL_TRIANGLES ); std::vector().swap( m_data.vertices ); // hipster shrink_to_fit diff --git a/shaders/vertex.vert b/shaders/vertex.vert index 4d274e71..feadbe1e 100644 --- a/shaders/vertex.vert +++ b/shaders/vertex.vert @@ -2,6 +2,7 @@ layout(location = 0) in vec3 v_vert; layout(location = 1) in vec3 v_normal; layout(location = 2) in vec2 v_coord; layout(location = 3) in vec4 v_tangent; +layout(location = 4) in vec4 v_userdata; #include @@ -18,6 +19,7 @@ out vec4 f_clip_future_pos; //out vec3 TangentLightPos; //out vec3 TangentViewPos; out vec3 TangentFragPos; +out vec4 UserData; void main() { @@ -43,4 +45,5 @@ void main() // TangentLightPos = TBN * f_light_pos.xyz; // TangentViewPos = TBN * vec3(0.0, 0.0, 0.0); TangentFragPos = TBN * f_pos.xyz; + UserData = v_userdata; } diff --git a/vertex.h b/vertex.h index 91bf1ca0..849b3f1b 100644 --- a/vertex.h +++ b/vertex.h @@ -18,6 +18,7 @@ struct world_vertex { glm::dvec3 position; glm::vec3 normal; glm::vec2 texture; + glm::vec4 user_data; // overloads // operator+