add user data vector to basic_vertex

update t3d, e3d & sbt specs accordingly
update node model to shape conversion to support indexed meshes
This commit is contained in:
Wls50
2024-06-30 16:13:19 +02:00
parent 633be40ef4
commit dba0a035fd
10 changed files with 162 additions and 67 deletions

View File

@@ -209,6 +209,21 @@ inline void readMatrix(cParser &parser, float4x4 &matrix)
parser >> matrix(x)[y];
};
template <typename T> 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<int, int> TSubModel::Load( cParser &parser, bool dynamic )
{ // Ra: VBO tworzone na poziomie modelu, a nie submodeli
auto token { parser.getToken<std::string>() };
@@ -479,6 +494,30 @@ std::pair<int, int> TSubModel::Load( cParser &parser, bool dynamic )
if (eType < TP_ROTATOR)
{ // wczytywanie wierzchołków
token = parser.getToken<std::string>();
enum class UserDataType
{
None,
Float,
Int,
UInt,
Count
} user_data = UserDataType::None;
if (token == "userdata:")
{
const static std::map<std::string, UserDataType> type_mapping{{"float", UserDataType::Float}, {"int", UserDataType::Int}, {"uint", UserDataType::UInt}};
const std::string type = parser.getToken<std::string>();
if (auto it = type_mapping.find(type); it != type_mapping.end())
{
user_data = it->second;
}
else
{
user_data = UserDataType::None;
}
token = parser.getToken<std::string>();
}
if( token == "numindices:" ) // optional block, potentially preceeding vertex list
{
m_geometry.index_count = parser.getToken<int>( false );
@@ -661,6 +700,16 @@ std::pair<int, int> TSubModel::Load( cParser &parser, bool dynamic )
// update values potentially changed by indexing
m_geometry.index_count = Indices.size();
m_geometry.vertex_count = Vertices.size();
}
if (user_data != UserDataType::None)
{
const static std::array<void (*)(cParser &, gfx::basic_vertex &), static_cast<size_t>(UserDataType::Count)> parsers{nullptr, &UserdataParse<float>, &UserdataParse<int32_t>,
&UserdataParse<uint32_t>};
auto vertices { std::begin( Vertices ) };
for( auto idx = 0; idx < m_geometry.vertex_count; ++idx ) {
auto vertex { vertices + idx };
parsers[static_cast<size_t>(user_data)](parser, *vertex);
}
}
}
else // gdy brak wierzchołków
@@ -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;
}

View File

@@ -243,7 +243,7 @@ public:
std::vector<std::string>&,
std::vector<std::string>&,
std::vector<float4x4>&);
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

View File

@@ -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<glm::vec3>(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<glm::dvec3>(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

View File

@@ -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

View File

@@ -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

View File

@@ -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<void const *>( sizeof( gfx::basic_vertex ) * offset ) );
::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( 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<void const *>( 12 + sizeof( gfx::basic_vertex ) * offset ) );
::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( 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<void const *>( 12 + sizeof( gfx::basic_vertex ) * offset ) );
::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( 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<void const *>( 24 + sizeof( gfx::basic_vertex ) * offset ) );
::glTexCoordPointer( 2, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( offsetof(gfx::basic_vertex, texture) + sizeof( gfx::basic_vertex ) * offset ) );
::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
}
m_activetexturearrays = Units.texture;

View File

@@ -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

View File

@@ -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,10 +348,16 @@ shape_node::convert( TSubModel const *Submodel ) {
int vertexcount { 0 };
std::vector<world_vertex> importedvertices;
world_vertex vertex, vertex1, vertex2;
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.position = sourcevertex.position;
vertex.normal = sourcevertex.normal;
vertex.texture = sourcevertex.texture;
vertex = sourcevertex.to_world();
if( vertexcount == 0 ) { vertex1 = vertex; }
else if( vertexcount == 1 ) { vertex2 = vertex; }
else if( vertexcount >= 2 ) {
@@ -370,6 +371,7 @@ shape_node::convert( TSubModel const *Submodel ) {
}
++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<world_vertex>().swap( m_data.vertices ); // hipster shrink_to_fit

View File

@@ -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 <common>
@@ -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;
}

View File

@@ -18,6 +18,7 @@ struct world_vertex {
glm::dvec3 position;
glm::vec3 normal;
glm::vec2 texture;
glm::vec4 user_data;
// overloads
// operator+