diff --git a/Makefile b/Makefile index 07c8df3d..bb39b0ca 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC = $(shell cat "./bin/exe/default.config") TARGET_NAME = program TARGET_EXTENSION = exe TARGET_LIB_EXTENSION = dll -RENDERER = vulkan +RENDERER = opengl include makefiles/$(ARCH).$(CC).make diff --git a/bin/data/config.json b/bin/data/config.json index 09bc7dd9..cf66a80e 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -2,7 +2,7 @@ "engine": { "scenes": { "start": "SS2", - "meshes": { "interleaved": false }, + "meshes": { "interleaved": true }, "matrix": { "reverseInfinite": true }, "lights": { "max": 24, @@ -146,7 +146,7 @@ "debug draw": { "enabled": false, // "layer": "Gui", - "rate": 0.0125 + "rate": 0.06666666666 } }, "bullet": { diff --git a/bin/data/scenes/ss2/medsci.json b/bin/data/scenes/ss2/medsci.json index 14d4950e..89daa7a7 100644 --- a/bin/data/scenes/ss2/medsci.json +++ b/bin/data/scenes/ss2/medsci.json @@ -1,9 +1,9 @@ { "import": "/model.json", "assets": [ - { "filename": "./models/tiny_msci.glb", "delay": 0, "single threaded": false, "category": "models" } + // { "filename": "./models/tiny_msci.glb", "delay": 0, "single threaded": false, "category": "models" } // { "filename": "./models/tiny_msci/graph.json", "delay": 0, "single threaded": false, "category": "models" } - // { "filename": "./models/tiny_msci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + { "filename": "./models/tiny_msci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } // { "filename": "./models/micro_sci.glb", "delay": 0, "single threaded": false, "category": "models" } // { "filename": "./models/micro_sci/graph.json", "delay": 0, "single threaded": false, "category": "models" } diff --git a/bin/dreamcast/config.json b/bin/dreamcast/config.json index 4b8ae9e4..cb0c0a09 100644 --- a/bin/dreamcast/config.json +++ b/bin/dreamcast/config.json @@ -2,7 +2,7 @@ "engine": { "scenes": { "start": "SS2", - "meshes": { "interleaved": false }, + "meshes": { "interleaved": true }, "matrix": { "reverseInfinite": false }, "lights": { "max": 8, diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index 1101d028..da36bf61 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -64,7 +64,7 @@ namespace uf { uf::stl::vector attributes; size_t count = 0; // how many elements is the input using size_t first = 0; // base index to start from - size_t stride = 0; // size of one element in the input's buffer + size_t size = 0; // size of one element in the input's buffer size_t offset = 0; // bytes to offset from within the associated buffer int32_t interleaved = -1; // index to interleaved buffer if in bounds } vertex, index, instance, indirect; @@ -109,18 +109,39 @@ namespace uf { void initialize(); void destroy(); - uf::Mesh convert( bool ) const; + uf::Mesh convert() const; + uf::Mesh copy(bool) const; + uf::Mesh expand(); + uf::Mesh expand(bool); + void updateDescriptor(); void bind( const uf::Mesh& ); + void bind( const uf::Mesh&, bool ); void insert( const uf::Mesh& ); void generateIndices(); void generateIndirect(); + bool isInterleaved() const; bool isInterleaved( size_t ) const; - void print() const; + buffer_t& getBuffer( const uf::Mesh::Input&, size_t = 0 ); + buffer_t& getBuffer( const uf::Mesh::Input&, const uf::Mesh::Attribute& ); + + const buffer_t& getBuffer( const uf::Mesh::Input&, size_t = 0 ) const; + const buffer_t& getBuffer( const uf::Mesh::Input&, const uf::Mesh::Attribute& ) const; + + void print( bool = true ) const; + + std::string printVertices( bool = true ) const; + std::string printIndices( bool = true ) const; + std::string printInstances( bool = true ) const; + std::string printIndirects( bool = true ) const; + + uf::Mesh::Input remapInput( const uf::Mesh::Input&, size_t i = 0 ) const; + uf::Mesh::Input remapVertexInput( size_t i = 0 ) const; + uf::Mesh::Input remapIndexInput( size_t i = 0 ) const; inline bool hasVertex( const uf::stl::vector& descriptors ) const { return _hasV( vertex, descriptors ); } inline bool hasVertex( const uf::Mesh& mesh ) const { return _hasV( vertex, mesh.vertex ); } diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index afd3c52a..c2866b6c 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -188,33 +188,13 @@ namespace { uf::Mesh decodeMesh( ext::json::Value& json, pod::Graph& graph ) { uf::Mesh mesh; - /* - struct Attribute { - ext::RENDERER::AttributeDescriptor descriptor; - int32_t buffer = -1; - size_t offset = 0; - - size_t stride = 0; - size_t length = 0; - void* pointer = NULL; - }; - struct Input { - uf::stl::vector attributes; - size_t count = 0; // how many elements is the input using - size_t first = 0; // base index to start from - size_t stride = 0; // size of one element in the input's buffer - size_t offset = 0; // bytes to offset from within the associated buffer - int32_t interleaved = -1; // index to interleaved buffer if in bounds - } vertex, index, instance, indirect; - */ - #define DESERIALIZE_MESH(N) {\ auto& input = json["inputs"][#N];\ mesh.N.attributes.reserve( input["attributes"].size() );\ mesh.N.count = input["count"].as( mesh.N.count );\ mesh.N.first = input["first"].as( mesh.N.first );\ - mesh.N.stride = input["stride"].as( mesh.N.stride );\ - mesh.N.offset = input["stride"].as( mesh.N.offset );\ + mesh.N.size = input["size"].as( mesh.N.size );\ + mesh.N.offset = input["offset"].as( mesh.N.offset );\ mesh.N.interleaved = input["interleaved"].as( mesh.N.interleaved );\ ext::json::forEach( input["attributes"], [&]( ext::json::Value& value ){\ auto& attribute = mesh.N.attributes.emplace_back();\ @@ -244,6 +224,8 @@ namespace { }); mesh.updateDescriptor(); + // return mesh.expand(); + // if ( mesh.isInterleaved() != uf::Mesh::defaultInterleaved ) return mesh.copy(true); return mesh; } diff --git a/engine/src/engine/graph/encode.cpp b/engine/src/engine/graph/encode.cpp index bdd796a9..77a4d492 100644 --- a/engine/src/engine/graph/encode.cpp +++ b/engine/src/engine/graph/encode.cpp @@ -160,7 +160,7 @@ namespace { uf::stl::vector attributes; size_t count = 0; // how many elements is the input using size_t first = 0; // base index to start from - size_t stride = 0; // size of one element in the input's buffer + size_t size = 0; // size of one element in the input's buffer size_t offset = 0; // bytes to offset from within the associated buffer int32_t interleaved = -1; // index to interleaved buffer if in bounds } vertex, index, instance, indirect; @@ -170,7 +170,7 @@ namespace { auto& input = json["inputs"][#N];\ input["count"] = mesh.N.count;\ input["first"] = mesh.N.first;\ - input["stride"] = mesh.N.stride;\ + input["size"] = mesh.N.size;\ input["offset"] = mesh.N.offset;\ input["interleaved"] = mesh.N.interleaved;\ ext::json::reserve( input["attributes"], mesh.N.attributes.size() );\ @@ -193,84 +193,7 @@ namespace { SERIALIZE_MESH(index); SERIALIZE_MESH(instance); SERIALIZE_MESH(indirect); - - /* - json["inputs"]["vertex"]["count"] = mesh.vertex.count; - json["inputs"]["vertex"]["first"] = mesh.vertex.first; - json["inputs"]["vertex"]["stride"] = mesh.vertex.stride; - json["inputs"]["vertex"]["offset"] = mesh.vertex.offset; - json["inputs"]["vertex"]["interleaved"] = mesh.vertex.interleaved; - ext::json::reserve( json["inputs"]["vertex"]["attributes"], mesh.vertex.attributes.size() ); - for ( auto& attribute : mesh.vertex.attributes ) { - auto& a = json["inputs"]["vertex"]["attributes"].emplace_back(); - a["descriptor"]["offset"] = attribute.descriptor.offset; - a["descriptor"]["size"] = attribute.descriptor.size; - a["descriptor"]["format"] = attribute.descriptor.format; - a["descriptor"]["name"] = attribute.descriptor.name; - a["descriptor"]["type"] = attribute.descriptor.type; - a["descriptor"]["components"] = attribute.descriptor.components; - a["buffer"] = attribute.buffer; - a["offset"] = attribute.offset; - a["stride"] = attribute.stride; - } - json["inputs"]["index"]["count"] = mesh.index.count; - json["inputs"]["index"]["first"] = mesh.index.first; - json["inputs"]["index"]["stride"] = mesh.index.stride; - json["inputs"]["index"]["offset"] = mesh.index.offset; - json["inputs"]["index"]["interleaved"] = mesh.index.interleaved; - ext::json::reserve( json["inputs"]["index"]["attributes"], mesh.index.attributes.size() ); - for ( auto& attribute : mesh.index.attributes ) { - auto& a = json["inputs"]["index"]["attributes"].emplace_back(); - a["descriptor"]["offset"] = attribute.descriptor.offset; - a["descriptor"]["size"] = attribute.descriptor.size; - a["descriptor"]["format"] = attribute.descriptor.format; - a["descriptor"]["name"] = attribute.descriptor.name; - a["descriptor"]["type"] = attribute.descriptor.type; - a["descriptor"]["components"] = attribute.descriptor.components; - a["buffer"] = attribute.buffer; - a["offset"] = attribute.offset; - a["stride"] = attribute.stride; - } - - json["inputs"]["instance"]["count"] = mesh.instance.count; - json["inputs"]["instance"]["first"] = mesh.instance.first; - json["inputs"]["instance"]["stride"] = mesh.instance.stride; - json["inputs"]["instance"]["offset"] = mesh.instance.offset; - json["inputs"]["instance"]["interleaved"] = mesh.instance.interleaved; - ext::json::reserve( json["inputs"]["instance"]["attributes"], mesh.instance.attributes.size() ); - for ( auto& attribute : mesh.instance.attributes ) { - auto& a = json["inputs"]["instance"]["attributes"].emplace_back(); - a["descriptor"]["offset"] = attribute.descriptor.offset; - a["descriptor"]["size"] = attribute.descriptor.size; - a["descriptor"]["format"] = attribute.descriptor.format; - a["descriptor"]["name"] = attribute.descriptor.name; - a["descriptor"]["type"] = attribute.descriptor.type; - a["descriptor"]["components"] = attribute.descriptor.components; - a["buffer"] = attribute.buffer; - a["offset"] = attribute.offset; - a["stride"] = attribute.stride; - } - - json["inputs"]["indirect"]["count"] = mesh.indirect.count; - json["inputs"]["indirect"]["first"] = mesh.indirect.first; - json["inputs"]["indirect"]["stride"] = mesh.indirect.stride; - json["inputs"]["indirect"]["offset"] = mesh.indirect.offset; - json["inputs"]["indirect"]["interleaved"] = mesh.indirect.interleaved; - ext::json::reserve( json["inputs"]["indirect"]["attributes"], mesh.indirect.attributes.size() ); - for ( auto& attribute : mesh.indirect.attributes ) { - auto& a = json["inputs"]["indirect"]["attributes"].emplace_back(); - a["descriptor"]["offset"] = attribute.descriptor.offset; - a["descriptor"]["size"] = attribute.descriptor.size; - a["descriptor"]["format"] = attribute.descriptor.format; - a["descriptor"]["name"] = attribute.descriptor.name; - a["descriptor"]["type"] = attribute.descriptor.type; - a["descriptor"]["components"] = attribute.descriptor.components; - a["buffer"] = attribute.buffer; - a["offset"] = attribute.offset; - a["stride"] = attribute.stride; - } - */ ext::json::reserve( json["buffers"], mesh.buffers.size() ); for ( auto i = 0; i < mesh.buffers.size(); ++i ) { const uf::stl::string filename = settings.filename + ".buffer." + std::to_string(i) + "." + ( settings.compress ? "gz" : "bin" ); diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 5ab4642e..fd6d9b66 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -475,18 +475,34 @@ void uf::graph::process( pod::Graph& graph ) { graph.root.mesh = graph.meshes.size(); auto keyName = graph.name + "/" + graph.root.name; auto& mesh = uf::graph::storage.meshes[graph.meshes.emplace_back(keyName)]; + mesh.bindIndirect(); + mesh.bind(); + + uf::stl::vector drawCommands; + + size_t counts = 0; for ( auto& name : graph.meshes ) { if ( name == keyName ) continue; auto& m = uf::graph::storage.meshes.map[name]; - mesh.bindIndirect(); - mesh.bind(); - mesh.insert( m ); + m.updateDescriptor(); + + mesh.insertVertices( m ); + mesh.insertIndices( m ); + mesh.insertInstances( m ); + // mesh.insertIndirects( m ); + pod::DrawCommand* dc = (pod::DrawCommand*) m.getBuffer( m.indirect ).data(); + for ( size_t i = 0; i < m.indirect.count; ++i ) drawCommands.emplace_back( dc[i] ); } + mesh.insertIndirects( drawCommands ); + + mesh = mesh.expand(); + mesh = mesh.copy(true); + // fix up draw command for combined mesh { auto& attribute = mesh.indirect.attributes.front(); - auto& buffer = mesh.buffers[mesh.isInterleaved(mesh.indirect.interleaved) ? mesh.indirect.interleaved : attribute.buffer]; + auto& buffer = mesh.getBuffer(mesh.indirect); // mesh.buffers[mesh.isInterleaved(mesh.indirect.interleaved) ? mesh.indirect.interleaved : attribute.buffer]; pod::DrawCommand* drawCommands = (pod::DrawCommand*) buffer.data(); size_t totalIndices = 0; @@ -499,6 +515,17 @@ void uf::graph::process( pod::Graph& graph ) { totalIndices += drawCommand.indices; totalVertices += drawCommand.vertices; } + + /* + if ( totalIndices > mesh.index.count ) { + UF_MSG_ERROR("Calculated total indices exceed actual indices count: expecting " << mesh.index.count << ", got " << totalIndices); + UF_EXCEPTION("invalid drawCommand"); + } + if ( totalVertices > mesh.vertex.count ) { + UF_MSG_ERROR("Calculated total vertices exceed actual vertices count: expecting " << mesh.vertex.count << ", got " << totalVertices); + UF_EXCEPTION("invalid drawCommand"); + } + */ } { auto& graphic = graph.root.entity->getComponent(); diff --git a/engine/src/ext/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp index a3ab216b..79cbfc7c 100644 --- a/engine/src/ext/opengl/commands.cpp +++ b/engine/src/ext/opengl/commands.cpp @@ -242,8 +242,6 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: if ( ext::opengl::settings::experimental::culling && drawInfo.attributes.instance.pointer && drawInfo.attributes.instance.length == sizeof(pod::Instance) ) { pod::Instance& instance = *(pod::Instance*) drawInfo.attributes.instance.pointer; pod::Matrix4f mat = (*drawInfo.matrices.projection) * (*drawInfo.matrices.view) * (*drawInfo.matrices.model); - // pod::Matrix4f mat = (*drawInfo.matrices.projection) * (*drawInfo.matrices.view) * (instance.model); - // pod::Matrix4f mat = uf::matrix::multiply( projection, modelView ); bool visible = inside( instance, mat ); drawCommand.instances = visible ? 1 : 0; @@ -298,7 +296,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); GL_ERROR_CHECK(glBindTexture(drawInfo.textures.primary.viewType, drawInfo.textures.primary.image)); GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); - GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.uv.stride, drawInfo.attributes.uv.pointer)); + GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.uv.stride, (drawInfo.attributes.uv.pointer + drawInfo.attributes.uv.stride * drawInfo.descriptor.inputs.vertex.first))); if ( drawInfo.textures.secondary.image && drawInfo.attributes.st.pointer ) { // static GLuint previous = 0; @@ -313,15 +311,15 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: #if UF_ENV_DREAMCAST if ( blending ) GL_ERROR_CHECK(glDisable(GL_BLEND)); #endif - GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.st.stride, drawInfo.attributes.st.pointer)); + GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.st.stride, (drawInfo.attributes.st.pointer + drawInfo.attributes.st.stride * drawInfo.descriptor.inputs.vertex.first))); } } - if ( drawInfo.attributes.normal.pointer ) GL_ERROR_CHECK(glNormalPointer(GL_FLOAT, drawInfo.attributes.normal.stride, drawInfo.attributes.normal.pointer)); - if ( drawInfo.attributes.color.pointer ) GL_ERROR_CHECK(glColorPointer(4, GL_UNSIGNED_BYTE, drawInfo.attributes.color.stride, drawInfo.attributes.color.pointer)); - GL_ERROR_CHECK(glVertexPointer(3, GL_FLOAT, drawInfo.attributes.position.stride, drawInfo.attributes.position.pointer)); - GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, drawInfo.attributes.index.length / drawInfo.attributes.index.stride, indicesType, drawInfo.attributes.index.pointer)); + if ( drawInfo.attributes.normal.pointer ) GL_ERROR_CHECK(glNormalPointer(GL_FLOAT, drawInfo.attributes.normal.stride, (drawInfo.attributes.normal.pointer + drawInfo.attributes.normal.stride * drawInfo.descriptor.inputs.vertex.first))); + if ( drawInfo.attributes.color.pointer ) GL_ERROR_CHECK(glColorPointer(4, GL_UNSIGNED_BYTE, drawInfo.attributes.color.stride, (drawInfo.attributes.color.pointer + drawInfo.attributes.color.stride * drawInfo.descriptor.inputs.vertex.first))); + GL_ERROR_CHECK(glVertexPointer(3, GL_FLOAT, drawInfo.attributes.position.stride, (drawInfo.attributes.position.pointer + drawInfo.attributes.position.stride * drawInfo.descriptor.inputs.vertex.first))); + GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, drawInfo.descriptor.inputs.index.count, indicesType, (drawInfo.attributes.index.pointer + drawInfo.attributes.index.stride * drawInfo.descriptor.inputs.index.first))); if ( drawInfo.textures.secondary.image ) { #if UF_ENV_DREAMCAST diff --git a/engine/src/ext/opengl/graphic.cpp b/engine/src/ext/opengl/graphic.cpp index fdc17990..7c76de7f 100644 --- a/engine/src/ext/opengl/graphic.cpp +++ b/engine/src/ext/opengl/graphic.cpp @@ -43,7 +43,7 @@ void ext::opengl::Pipeline::initialize( const Graphic& graphic, const GraphicDes auto& attribute = descriptor.inputs.vertex.attributes[i]; GL_ERROR_CHECK(glEnableVertexAttribArray(i)); - GL_ERROR_CHECK(glVertexAttribPointer(0, attribute.descriptor.components, attribute.descriptor.type, false, descriptor.inputs.vertex.stride, attribute.descriptor.offset)); + GL_ERROR_CHECK(glVertexAttribPointer(0, attribute.descriptor.components, attribute.descriptor.type, false, descriptor.inputs.vertex.size, attribute.descriptor.offset)); } GL_ERROR_CHECK(glBindVertexArray(0)); } @@ -394,13 +394,16 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe drawCommandInfo.descriptor = descriptor; drawCommandInfo.attributes.index = descriptor.inputs.index.attributes.front(); - drawCommandInfo.attributes.index.pointer = (void*) ((uint8_t*) drawCommandInfo.attributes.index.pointer + drawCommand.indexID * drawCommandInfo.attributes.index.stride); - drawCommandInfo.attributes.index.length = drawCommand.indices * drawCommandInfo.attributes.index.stride; + drawCommandInfo.descriptor.inputs.index.first = drawCommand.indexID; + drawCommandInfo.descriptor.inputs.index.count = drawCommand.indices; + + drawCommandInfo.descriptor.inputs.vertex.first = drawCommand.vertexID; + drawCommandInfo.descriptor.inputs.vertex.count = drawCommand.vertices; + + // drawCommandInfo.attributes.index.pointer + drawCommandInfo.attributes.index.stride * drawCommandInfo.descriptor.inputs.index.first; for ( uf::Mesh::Attribute attribute : descriptor.inputs.vertex.attributes ) { - attribute.pointer += drawCommand.vertexID * attribute.stride; - attribute.length = drawCommand.vertices * attribute.stride; - // UF_MSG_DEBUG( attribute.descriptor.name << ": " << attribute.descriptor.offset << " " << attribute.pointer << " " << attribute.pointer - attribute.descriptor.offset ); + // attribute.pointer = attribute.pointer + attribute.stride * drawCommandInfo.descriptor.inputs.vertex.first; if ( attribute.descriptor.name == "position" ) drawCommandInfo.attributes.position = attribute; else if ( attribute.descriptor.name == "uv" ) drawCommandInfo.attributes.uv = attribute; @@ -408,14 +411,23 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe else if ( attribute.descriptor.name == "normal" ) drawCommandInfo.attributes.normal = attribute; else if ( attribute.descriptor.name == "color" ) drawCommandInfo.attributes.color = attribute; } + + /* + { + float* p = (float*) (drawCommandInfo.attributes.position.pointer + drawCommandInfo.attributes.position.stride * drawCommandInfo.descriptor.inputs.vertex.first); + // float* p = (float*) drawCommandInfo.attributes.position.pointer; + UF_MSG_DEBUG( "[" << i << "] [" << drawCommandInfo.descriptor.inputs.vertex.first << "] (" << p[0] << ", " << p[1] << ", " << p[2] << ")" ); + } + */ /* for ( size_t i = 0; i < drawCommand.vertices; ++i ) { - float* p = (float*) (drawCommandInfo.attributes.position.pointer + i * drawCommandInfo.attributes.position.stride); - float* uv = (float*) (drawCommandInfo.attributes.uv.pointer + i * drawCommandInfo.attributes.uv.stride); + float* p = (float*) (drawCommandInfo.attributes.position.pointer + drawCommandInfo.attributes.position.stride * (i + drawCommand.vertexID)); + float* uv = (float*) (drawCommandInfo.attributes.uv.pointer + drawCommandInfo.attributes.uv.stride * (i + drawCommand.vertexID)); std::cout << "(" << p[0] << ", " << p[1] << ", " << p[2] << "|" << uv[0] << ", " << uv[1] << ") "; } std::cout << std::endl; */ + drawCommandInfo.attributes.instance.pointer = &instance; drawCommandInfo.attributes.instance.length = sizeof(instance); diff --git a/engine/src/ext/reactphysics/reactphysics.cpp b/engine/src/ext/reactphysics/reactphysics.cpp index 9bef1f77..e59de3d3 100644 --- a/engine/src/ext/reactphysics/reactphysics.cpp +++ b/engine/src/ext/reactphysics/reactphysics.cpp @@ -174,8 +174,62 @@ void ext::reactphysics::detach( pod::PhysicsState& state ) { // collider for mesh (static or dynamic) pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh& mesh, bool dynamic ) { + UF_ASSERT( mesh.index.count ); + auto* rMesh = ::common.createTriangleMesh(); + mesh.print( false ); + + uf::Mesh::Input vertexInput = mesh.vertex; + uf::Mesh::Input indexInput = mesh.index; + + uf::Mesh::Attribute vertexAttribute = mesh.vertex.attributes.front(); + uf::Mesh::Attribute indexAttribute = mesh.index.attributes.front(); + + for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "position" ) { vertexAttribute = attribute; break; } + UF_ASSERT( vertexAttribute.descriptor.name == "position" ); + + rp3d::TriangleVertexArray::IndexDataType indexType = rp3d::TriangleVertexArray::IndexDataType::INDEX_INTEGER_TYPE; + rp3d::TriangleVertexArray::VertexDataType vertexType = rp3d::TriangleVertexArray::VertexDataType::VERTEX_FLOAT_TYPE; + switch ( mesh.index.size ) { + case sizeof(uint16_t): indexType = rp3d::TriangleVertexArray::IndexDataType::INDEX_SHORT_TYPE; break; + case sizeof(uint32_t): indexType = rp3d::TriangleVertexArray::IndexDataType::INDEX_INTEGER_TYPE; break; + default: UF_EXCEPTION("unsupported index type"); break; + } + + if ( mesh.indirect.count ) { + for ( auto i = 0; i < mesh.indirect.count; ++i ) { + vertexInput = mesh.remapVertexInput( i ); + indexInput = mesh.remapIndexInput( i ); + + rMesh->addSubpart(new rp3d::TriangleVertexArray( + vertexInput.count, + (const uint8_t*) (vertexAttribute.pointer + vertexAttribute.stride * vertexInput.first), + vertexAttribute.stride, + + indexInput.count / 3, + (const uint8_t*) (indexAttribute.pointer + indexAttribute.stride * indexInput.first), + indexAttribute.stride * 3, + + vertexType, + indexType + )); + } + } else { + rMesh->addSubpart(new rp3d::TriangleVertexArray( + vertexInput.count, + (const uint8_t*) (vertexAttribute.pointer + vertexAttribute.stride * vertexInput.first), + vertexAttribute.stride, + + indexInput.count / 3, + (const uint8_t*) (indexAttribute.pointer + indexAttribute.stride * indexInput.first), + indexAttribute.stride * 3, + + vertexType, + indexType + )); + } +/* if ( mesh.index.count ) { uf::Mesh::Attribute vertexAttribute; for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "position" ) { vertexAttribute = attribute; break; } @@ -184,7 +238,7 @@ pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh auto& indexAttribute = mesh.index.attributes.front(); rp3d::TriangleVertexArray::IndexDataType indexType = rp3d::TriangleVertexArray::IndexDataType::INDEX_INTEGER_TYPE; rp3d::TriangleVertexArray::VertexDataType vertexType = rp3d::TriangleVertexArray::VertexDataType::VERTEX_FLOAT_TYPE; - switch ( mesh.index.stride ) { + switch ( mesh.index.size ) { case sizeof(uint16_t): indexType = rp3d::TriangleVertexArray::IndexDataType::INDEX_SHORT_TYPE; break; case sizeof(uint32_t): indexType = rp3d::TriangleVertexArray::IndexDataType::INDEX_INTEGER_TYPE; break; default: UF_EXCEPTION("unsupported index type"); break; @@ -199,11 +253,11 @@ pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh remappedIndexAttribute = mesh.remapIndexAttribute( indexAttribute, i ); vArray = new rp3d::TriangleVertexArray( - remappedVertexAttribute.length / remappedVertexAttribute.stride, + remappedVertexAttribute.length / mesh.vertex.size, (const uint8_t*) remappedVertexAttribute.pointer, remappedVertexAttribute.stride, - remappedIndexAttribute.length / remappedIndexAttribute.stride / 3, + remappedIndexAttribute.length / mesh.index.size / 3, (const uint8_t*) remappedIndexAttribute.pointer, remappedIndexAttribute.stride * 3, @@ -230,6 +284,7 @@ pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh rMesh->addSubpart(vArray); } } else UF_EXCEPTION("to-do: not require indices for meshes"); +*/ auto& state = ext::reactphysics::create( object ); state.shape = ::common.createConcaveMeshShape( rMesh ); diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 96e1e35d..c183303d 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -219,7 +219,7 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes if ( 0 <= descriptor.inputs.vertex.interleaved ) { inputBindingDescriptions.emplace_back(ext::vulkan::initializers::vertexInputBindingDescription( vertexBindID, // descriptor.inputs.vertex.interleaved, - descriptor.inputs.vertex.stride, + descriptor.inputs.vertex.size, VK_VERTEX_INPUT_RATE_VERTEX )); for ( auto& attribute : descriptor.inputs.vertex.attributes ) { @@ -992,12 +992,12 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD if ( index.buffer ) { VkIndexType indicesType = VK_INDEX_TYPE_UINT32; - switch ( descriptor.inputs.index.stride ) { + switch ( descriptor.inputs.index.size ) { case 1: indicesType = VK_INDEX_TYPE_UINT8_EXT; break; case 2: indicesType = VK_INDEX_TYPE_UINT16; break; case 4: indicesType = VK_INDEX_TYPE_UINT32; break; default: - UF_EXCEPTION("invalid indices size of " << (int) descriptor.inputs.index.stride); + UF_EXCEPTION("invalid indices size of " << (int) descriptor.inputs.index.size); break; } vkCmdBindIndexBuffer(commandBuffer, index.buffer, index.offset, indicesType); @@ -1021,14 +1021,14 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer, descriptor.inputs.indirect.offset, // offset descriptor.inputs.indirect.count, // drawCount - descriptor.inputs.indirect.stride // stride + descriptor.inputs.indirect.size // stride ); } else { for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) { vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer, - descriptor.inputs.indirect.offset + i * descriptor.inputs.indirect.stride, // offset + descriptor.inputs.indirect.offset + i * descriptor.inputs.indirect.size, // offset 1, // drawCount - descriptor.inputs.indirect.stride // stride + descriptor.inputs.indirect.size // stride ); } } @@ -1044,7 +1044,7 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer, descriptor.inputs.indirect.offset, // offset descriptor.inputs.indirect.count, // drawCount - descriptor.inputs.indirect.stride // stride + descriptor.inputs.indirect.size // stride ); } else/* if ( !vertexInstance.buffer.empty() && !indirect.buffer ) */{ vkCmdDraw(commandBuffer, diff --git a/engine/src/ext/xatlas/xatlas.cpp b/engine/src/ext/xatlas/xatlas.cpp index 21f348c2..b1448885 100644 --- a/engine/src/ext/xatlas/xatlas.cpp +++ b/engine/src/ext/xatlas/xatlas.cpp @@ -2,47 +2,6 @@ #if UF_USE_XATLAS #include #endif -#if 0 -pod::Vector2ui UF_API ext::xatlas::unwrap( uf::stl::vector& vertices, uf::stl::vector& indices ) { -#if UF_USE_XATLAS - uf::stl::vector source = std::move(vertices); - ::xatlas::Atlas* atlas = ::xatlas::Create(); - - ::xatlas::MeshDecl decl; - decl.vertexCount = source.size(); - decl.vertexPositionData = source.data() + offsetof(uf::graph::mesh::Skinned, position); - decl.vertexPositionStride = sizeof(uf::graph::mesh::Skinned); - decl.vertexUvData = source.data() + offsetof(uf::graph::mesh::Skinned, uv); - decl.vertexUvStride = sizeof(uf::graph::mesh::Skinned); - - decl.indexCount = indices.size(); - decl.indexData = indices.data(); - decl.indexFormat = ::xatlas::IndexFormat::UInt32; - - ::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas, decl, 1); - if (error != ::xatlas::AddMeshError::Success) { - ::xatlas::Destroy(atlas); - UF_EXCEPTION(::xatlas::StringForEnum(error)); - } - - auto& xmesh = atlas->meshes[0]; - vertices.resize( xmesh.vertexCount ); - - for ( auto i = 0; i < xmesh.vertexCount; ++i ) { - auto& vertex = xmesh.vertexArray[i]; - - vertices[i] = source[vertex.xref]; - vertices[i].st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; - } - for ( auto i = 0; i < xmesh.indexCount; ++i ) indices[i] = xmesh.indexArray[i]; - - pod::Vector2ui size = pod::Vector2ui{ atlas->width, atlas->height }; - ::xatlas::Destroy(atlas); - - return size; -#endif -} -#endif pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { #if UF_USE_XATLAS struct Pair { @@ -58,52 +17,60 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { sources.reserve(graph.meshes.size()); ::xatlas::Atlas* atlas = ::xatlas::Create(); + for ( auto index = 0; index < graph.meshes.size(); ++index ) { auto& name = graph.meshes[index]; auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name]; + + UF_ASSERT( !mesh.isInterleaved() ); + sources.emplace_back(mesh).updateDescriptor(); - if ( mesh.index.count ) { - uf::Mesh::Attribute positionAttribute; - uf::Mesh::Attribute uvAttribute; - uf::Mesh::Attribute stAttribute; - for ( auto& attribute : mesh.vertex.attributes ) { - if ( attribute.descriptor.name == "position" ) positionAttribute = attribute; - else if ( attribute.descriptor.name == "uv" ) uvAttribute = attribute; - else if ( attribute.descriptor.name == "st" ) stAttribute = attribute; - } - UF_ASSERT( positionAttribute.descriptor.name == "position" && uvAttribute.descriptor.name == "uv" && stAttribute.descriptor.name == "st" ); + uf::Mesh::Input vertexInput = mesh.vertex; + + uf::Mesh::Attribute positionAttribute; + uf::Mesh::Attribute uvAttribute; + uf::Mesh::Attribute stAttribute; + + for ( auto& attribute : mesh.vertex.attributes ) { + if ( attribute.descriptor.name == "position" ) positionAttribute = attribute; + else if ( attribute.descriptor.name == "uv" ) uvAttribute = attribute; + else if ( attribute.descriptor.name == "st" ) stAttribute = attribute; + } + UF_ASSERT( positionAttribute.descriptor.name == "position" && uvAttribute.descriptor.name == "uv" && stAttribute.descriptor.name == "st" ); + + if ( mesh.index.count ) { + uf::Mesh::Input indexInput = mesh.index; + uf::Mesh::Attribute indexAttribute = mesh.index.attributes.front(); - auto& indexAttribute = mesh.index.attributes.front(); ::xatlas::IndexFormat indexType = ::xatlas::IndexFormat::UInt32; - switch ( mesh.index.stride ) { + switch ( mesh.index.size ) { case sizeof(uint16_t): indexType = ::xatlas::IndexFormat::UInt16; break; case sizeof(uint32_t): indexType = ::xatlas::IndexFormat::UInt32; break; default: UF_EXCEPTION("unsupported index type"); break; } if ( mesh.indirect.count ) { - uf::Mesh::Attribute remappedPositionAttribute; - uf::Mesh::Attribute remappedUvAttribute; - uf::Mesh::Attribute remappedIndexAttribute; for ( auto i = 0; i < mesh.indirect.count; ++i ) { - remappedPositionAttribute = mesh.remapVertexAttribute( positionAttribute, i ); - remappedUvAttribute = mesh.remapVertexAttribute( uvAttribute, i ); - remappedIndexAttribute = mesh.remapIndexAttribute( indexAttribute, i ); + vertexInput = mesh.remapVertexInput( i ); + indexInput = mesh.remapIndexInput( i ); auto& entry = entries.emplace_back(); entry.index = index; entry.command = i; auto& decl = entry.decl; - decl.vertexCount = remappedPositionAttribute.length / remappedPositionAttribute.stride; - decl.vertexPositionData = remappedPositionAttribute.pointer; - decl.vertexPositionStride = remappedPositionAttribute.stride; - decl.vertexUvData = remappedUvAttribute.pointer; - decl.vertexUvStride = remappedUvAttribute.stride; + + decl.vertexPositionData = positionAttribute.pointer + positionAttribute.stride * vertexInput.first; + decl.vertexPositionStride = positionAttribute.stride; - decl.indexCount = remappedIndexAttribute.length / remappedIndexAttribute.stride; - decl.indexData = remappedIndexAttribute.pointer; + decl.vertexUvData = uvAttribute.pointer + uvAttribute.stride * vertexInput.first; + decl.vertexUvStride = uvAttribute.stride; + + decl.vertexCount = vertexInput.count; + + decl.indexCount = indexInput.count; + decl.indexData = indexAttribute.pointer + indexAttribute.stride * indexInput.first; decl.indexFormat = indexType; } } else { @@ -111,20 +78,21 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { entry.index = index; auto& decl = entry.decl; - decl.vertexCount = mesh.vertex.count; - decl.vertexPositionData = positionAttribute.pointer; + decl.vertexPositionData = positionAttribute.pointer + positionAttribute.stride * vertexInput.first; decl.vertexPositionStride = positionAttribute.stride; - decl.vertexUvData = uvAttribute.pointer; + + decl.vertexUvData = uvAttribute.pointer + uvAttribute.stride * vertexInput.first; decl.vertexUvStride = uvAttribute.stride; - decl.indexCount = mesh.index.count; - decl.indexData = indexAttribute.pointer; - decl.indexFormat = indexType; - decl.indexFormat = indexType; + decl.vertexCount = vertexInput.count; + decl.indexCount = indexInput.count; + decl.indexData = indexAttribute.pointer + indexAttribute.stride * indexInput.first; + decl.indexFormat = indexType; } } else UF_EXCEPTION("to-do: not require indices for meshes"); } + for ( auto& mesh : entries ) { ::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas, mesh.decl, entries.size()); if (error != ::xatlas::AddMeshError::Success) { @@ -160,7 +128,7 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { if ( mesh.indirect.count ) { auto& primitive = /*graph.storage*/uf::graph::storage.primitives[name]; - pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.buffers[mesh.isInterleaved(mesh.indirect.interleaved) ? mesh.indirect.interleaved : mesh.indirect.attributes.front().buffer].data(); + pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data(); size_t vertexOffset = 0; for ( auto j = 0; j < atlas->meshCount; ++j ) { @@ -201,7 +169,7 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { pod::Vector2f& st = *(pod::Vector2f*) ( ((uint8_t*) dstAttribute.pointer) + dstAttribute.stride * j); st = pod::Vector2f{ vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; } else { - memcpy( ((uint8_t*) dstAttribute.pointer) + dstAttribute.stride * j, ((uint8_t*) srcAttribute.pointer) + srcAttribute.stride * ref, srcAttribute.stride ); + memcpy( dstAttribute.pointer + dstAttribute.stride * j, srcAttribute.pointer + srcAttribute.stride * ref, srcAttribute.stride ); } } } @@ -210,7 +178,7 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { uf::Mesh::Attribute indexAttribute = mesh.remapIndexAttribute( mesh.index.attributes.front(), entry.command ); uint8_t* pointer = (uint8_t*) indexAttribute.pointer; for ( auto index = 0; index < xmesh.indexCount; ++index ) { - switch ( mesh.index.stride ) { + switch ( mesh.index.size ) { case 1: (( uint8_t*) pointer)[index] = xmesh.indexArray[index]; break; case 2: ((uint16_t*) pointer)[index] = xmesh.indexArray[index]; break; case 4: ((uint32_t*) pointer)[index] = xmesh.indexArray[index]; break; @@ -227,11 +195,23 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { auto& vertex = xmesh.vertexArray[j]; auto ref = vertex.xref; - if ( mesh.isInterleaved( mesh.vertex.interleaved ) ) { - uint8_t* srcAttribute = source.buffers[mesh.vertex.interleaved].data() + j * mesh.vertex.stride; - uint8_t* dstAttribute = mesh.buffers[mesh.vertex.interleaved].data() + j * mesh.vertex.stride; + for ( auto k = 0; k < mesh.vertex.attributes.size(); ++k ) { + auto srcAttribute = source.vertex.attributes[k]; + auto dstAttribute = mesh.vertex.attributes[k]; - memcpy( dstAttribute, srcAttribute, mesh.vertex.stride ); + if ( dstAttribute.descriptor.name == "st" ) { + pod::Vector2f& st = *(pod::Vector2f*) ( ((uint8_t*) dstAttribute.pointer) + dstAttribute.stride * j); + st = pod::Vector2f{ vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; + } else { + memcpy( dstAttribute.pointer + dstAttribute.stride * j, srcAttribute.pointer + srcAttribute.stride * ref, srcAttribute.stride ); + } + } + /* + if ( mesh.isInterleaved( mesh.vertex.interleaved ) ) { + uint8_t* srcAttribute = source.buffers[mesh.vertex.interleaved].data() + j * mesh.vertex.size; + uint8_t* dstAttribute = mesh.buffers[mesh.vertex.interleaved].data() + j * mesh.vertex.size; + + memcpy( dstAttribute, srcAttribute, mesh.vertex.size ); pod::Vector2f& st = *(pod::Vector2f*) (dstAttribute + stAttribute.descriptor.offset); st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; @@ -246,12 +226,13 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { memcpy( dstAttribute, srcAttribute, attribute.descriptor.size ); } } + */ } // indices if ( mesh.index.count ) { uint8_t* pointer = (uint8_t*) mesh.buffers[mesh.isInterleaved(mesh.index.interleaved) ? mesh.index.interleaved : mesh.index.attributes.front().buffer].data(); for ( auto index = 0; index < xmesh.indexCount; ++index ) { - switch ( mesh.index.stride ) { + switch ( mesh.index.size ) { case 1: (( uint8_t*) pointer)[index] = xmesh.indexArray[index]; break; case 2: ((uint16_t*) pointer)[index] = xmesh.indexArray[index]; break; case 4: ((uint32_t*) pointer)[index] = xmesh.indexArray[index]; break; @@ -263,6 +244,93 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { mesh.updateDescriptor(); } +#if 0 + for ( auto i = 0; i < atlas->meshCount; i++ ) { + auto& xmesh = atlas->meshes[i]; + auto& entry = entries[i]; + auto& name = graph.meshes[entry.index]; + auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name]; + auto& source = sources[entry.index]; + + uf::Mesh::Input vertexInput = mesh.vertex; + + uf::Mesh::Attribute positionAttribute; + uf::Mesh::Attribute uvAttribute; + uf::Mesh::Attribute stAttribute; + + for ( auto& attribute : mesh.vertex.attributes ) { + if ( attribute.descriptor.name == "position" ) positionAttribute = attribute; + else if ( attribute.descriptor.name == "uv" ) uvAttribute = attribute; + else if ( attribute.descriptor.name == "st" ) stAttribute = attribute; + } + UF_ASSERT( positionAttribute.descriptor.name == "position" && uvAttribute.descriptor.name == "uv" && stAttribute.descriptor.name == "st" ); + + if ( mesh.index.count ) { + uf::Mesh::Input indexInput = mesh.index; + uf::Mesh::Attribute indexAttribute = mesh.index.attributes.front(); + + ::xatlas::IndexFormat indexType = ::xatlas::IndexFormat::UInt32; + switch ( mesh.index.size ) { + case sizeof(uint16_t): indexType = ::xatlas::IndexFormat::UInt16; break; + case sizeof(uint32_t): indexType = ::xatlas::IndexFormat::UInt32; break; + default: UF_EXCEPTION("unsupported index type"); break; + } + + if ( mesh.indirect.count ) { + for ( auto v = 0; v < xmesh.vertexCount; ++v ) { + auto& vertex = xmesh.vertexArray[v]; + auto ref = vertex.xref; + + vertexInput = mesh.remapVertexInput( entry.command ); + + for ( size_t _ = 0; _ < vertexInput.attributes.size(); ++_ ) { + auto& srcAttribute = source.vertex.attributes[_]; + auto& dstAttribute = mesh.vertex.attributes[_]; + + memcpy( dstAttribute.pointer + dstAttribute.stride * (vertexInput.first + v), srcAttribute.pointer + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride ); + } + + pod::Vector2f& st = *(pod::Vector2f*) (stAttribute.pointer + stAttribute.stride * (vertexInput.first + v)); + st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; + } + // indices + + indexInput = mesh.remapIndexInput( entry.command ); + for ( auto index = 0; index < xmesh.indexCount; ++index ) { + switch ( mesh.index.size ) { + case 1: (( uint8_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 2: ((uint16_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 4: ((uint32_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + } + } + } else { + for ( auto v = 0; v < xmesh.vertexCount; ++v ) { + auto& vertex = xmesh.vertexArray[v]; + auto ref = vertex.xref; + + for ( size_t _ = 0; _ < vertexInput.attributes.size(); ++_ ) { + auto& srcAttribute = source.vertex.attributes[_]; + auto& dstAttribute = mesh.vertex.attributes[_]; + + memcpy( dstAttribute.pointer + dstAttribute.stride * (vertexInput.first + v), srcAttribute.pointer + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride ); + } + + pod::Vector2f& st = *(pod::Vector2f*) (stAttribute.pointer + stAttribute.stride * (vertexInput.first + v)); + st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; + } + + for ( auto index = 0; index < xmesh.indexCount; ++index ) { + switch ( mesh.index.size ) { + case 1: (( uint8_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 2: ((uint16_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 4: ((uint32_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + } + } + } + } else UF_EXCEPTION("to-do: not require indices for meshes"); + } +#endif + pod::Vector2ui size = pod::Vector2ui{ atlas->width, atlas->height }; ::xatlas::Destroy(atlas); diff --git a/engine/src/utils/mesh/mesh.cpp b/engine/src/utils/mesh/mesh.cpp index 3fd2fb94..bdd5e00a 100644 --- a/engine/src/utils/mesh/mesh.cpp +++ b/engine/src/utils/mesh/mesh.cpp @@ -48,8 +48,7 @@ UF_VERTEX_DESCRIPTOR(pod::Vertex_3F, ) bool uf::Mesh::defaultInterleaved = false; -void uf::Mesh::initialize() { -} +void uf::Mesh::initialize() {} void uf::Mesh::destroy() { _destroy(vertex); _destroy(index); @@ -58,39 +57,15 @@ void uf::Mesh::destroy() { buffers.clear(); } -uf::Mesh uf::Mesh::convert( bool interleave ) const { +// implicitly convert to opposite interleaving +uf::Mesh uf::Mesh::convert() const { + return copy( !isInterleaved() ); +} +uf::Mesh uf::Mesh::copy( bool interleaved ) const { uf::Mesh res; - // overkill but I don't want to rewrite a bind<>(); - res.vertex.attributes = vertex.attributes; - res.vertex.count = 0; - res.vertex.stride = vertex.stride; - res.vertex.offset = vertex.offset; - - res.index.attributes = index.attributes; - res.index.count = 0; - res.index.interleaved = -1; - res.index.stride = index.stride; - res.index.offset = index.offset; - - res.instance.attributes = instance.attributes; - res.instance.count = 0; - res.index.interleaved = -1; - res.instance.stride = instance.stride; - res.instance.offset = instance.offset; - res.indirect.attributes = indirect.attributes; - - res.indirect.count = 0; - res.indirect.interleaved = -1; - res.indirect.stride = indirect.stride; - res.indirect.offset = indirect.offset; - res._bind( interleave ); - - res.insertVertices(*this); - res.insertIndices(*this); - res.insertInstances(*this); - res.insertIndirects(*this); - + res.bind( *this, interleaved ); + res.insert(*this); res.updateDescriptor(); return res; @@ -101,17 +76,14 @@ void uf::Mesh::updateDescriptor() { _updateDescriptor(instance); _updateDescriptor(indirect); } -void uf::Mesh::bind( const uf::Mesh& mesh ) { +void uf::Mesh::bind( const uf::Mesh& mesh ) { return bind( mesh, isInterleaved() ); } +void uf::Mesh::bind( const uf::Mesh& mesh, bool interleaved ) { vertex.attributes = mesh.vertex.attributes; - vertex.interleaved = mesh.vertex.interleaved; index.attributes = mesh.index.attributes; - index.interleaved = mesh.index.interleaved; instance.attributes = mesh.instance.attributes; - instance.interleaved = mesh.instance.interleaved; indirect.attributes = mesh.indirect.attributes; - indirect.interleaved = mesh.indirect.interleaved; - _bind(); + _bind( interleaved ); } void uf::Mesh::insert( const uf::Mesh& mesh ) { if ( vertex.attributes.empty() && index.attributes.empty() && instance.attributes.empty() && indirect.attributes.empty() ) bind( mesh ); @@ -120,6 +92,8 @@ void uf::Mesh::insert( const uf::Mesh& mesh ) { insertIndices(mesh); insertInstances(mesh); insertIndirects(mesh); + + updateDescriptor(); } void uf::Mesh::generateIndices() { // deduce type @@ -141,12 +115,92 @@ void uf::Mesh::generateIndices() { case 4: { uf::stl::vector indices( vertex.count ); std::iota( indices.begin(), indices.end(), 0 ); insertIndices( indices ); } break; } } +uf::Mesh uf::Mesh::expand() { return expand( isInterleaved() ); } +uf::Mesh uf::Mesh::expand( bool interleaved ) { + uf::Mesh res = copy( interleaved ); + + res.resizeVertices( index.count ); + res.vertex.count = index.count; + + + auto& srcIndex = index.attributes.front(); + auto& dstIndex = res.index.attributes.front(); + +#define GET_INDEX(T) {\ + index = *(const T*) (srcIndex.pointer + idx * srcIndex.stride);\ + *((T*) (dstIndex.pointer + idx * dstIndex.stride)) = idx;\ +} + + for ( size_t idx = 0; idx < index.count; ++idx ) { + size_t index = 0; + switch ( srcIndex.descriptor.size ) { + case 1: GET_INDEX(uint8_t); break; + case 2: GET_INDEX(uint16_t); break; + case 4: GET_INDEX(uint32_t); break; + } + + for ( size_t _ = 0; _ < vertex.attributes.size(); ++_ ) { + auto& srcInput = vertex.attributes[_]; + auto& dstInput = res.vertex.attributes[_]; + + memcpy( dstInput.pointer, srcInput.pointer + index * srcInput.stride, srcInput.descriptor.size ); + dstInput.pointer += dstInput.stride; + } + } + +#undef GET_INDEX + + if ( res.indirect.count ) { + pod::DrawCommand* drawCommands = (pod::DrawCommand*) res.getBuffer(res.indirect).data(); + for ( size_t i = 0, vertexID = 0; i < res.indirect.count; ++i ) { + auto& drawCommand = drawCommands[i]; + drawCommand.vertexID = vertexID; + drawCommand.vertices = drawCommand.indices; + vertexID += drawCommand.indices; + } + } + + res.updateDescriptor(); + + return res; +} +uf::Mesh::Input uf::Mesh::remapInput( const uf::Mesh::Input& input, size_t i ) const { + uf::Mesh::Input res = input; + UF_ASSERT( &input == &vertex || &input == &index ); + UF_ASSERT( i < indirect.count ); + + const auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect).data())[i]; + res.first = &input == &vertex ? drawCommand.vertexID : drawCommand.indexID; + res.count = &input == &vertex ? drawCommand.vertices : drawCommand.indices; + + return res; +} +uf::Mesh::Input uf::Mesh::remapVertexInput( size_t i ) const { + uf::Mesh::Input res = vertex; + UF_ASSERT( i < indirect.count ); + + const auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect).data())[i]; + res.first = drawCommand.vertexID; + res.count = drawCommand.vertices; + + return res; +} +uf::Mesh::Input uf::Mesh::remapIndexInput( size_t i ) const { + uf::Mesh::Input res = index; + UF_ASSERT( i < indirect.count ); + + const auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect).data())[i]; + res.first = drawCommand.indexID; + res.count = drawCommand.indices; + + return res; +} void uf::Mesh::generateIndirect() { if ( index.count == 0 ) generateIndices(); uf::stl::vector commands; for ( auto& attribute : index.attributes ) { - auto& buffer = buffers[isInterleaved(index.interleaved) ? index.interleaved : attribute.buffer]; + auto& buffer = getBuffer(index, attribute); commands.emplace_back(pod::DrawCommand{ .indices = buffer.size() / attribute.descriptor.size, .instances = instance.count == 0 && instance.attributes.empty() ? 1 : instance.count, @@ -164,97 +218,93 @@ void uf::Mesh::generateIndirect() { _bind(); insertIndirects( commands ); } +bool uf::Mesh::isInterleaved() const { return isInterleaved( vertex.interleaved ); } bool uf::Mesh::isInterleaved( size_t i ) const { return 0 <= i && i < buffers.size(); } -void uf::Mesh::print() const { - std::stringstream str; - str << "Buffers: " << buffers.size() << "\n"; - str << "Vertices: " << vertex.count << " | " << (isInterleaved(vertex.interleaved) ? "interleaved" : "deinterleaved") << "\n"; - for ( auto i = 0; i < vertex.count; ++i ) { - if ( isInterleaved(vertex.interleaved) ) { - auto& buffer = buffers[vertex.interleaved]; - uint8_t* e = (uint8_t*) &buffer[i * vertex.stride]; - for ( auto& attribute : vertex.attributes ) { - str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; - switch ( attribute.descriptor.type ) { - case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint32_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int32_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint16_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int16_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint8_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int8_t*) (e + attribute.descriptor.offset))[j] << " "; break; - } - str << ")\n"; - } - } else for ( auto& attribute : vertex.attributes ) { - auto& buffer = buffers[attribute.buffer]; - str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; - switch ( attribute.descriptor.type ) { - case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint32_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int32_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint16_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int16_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint8_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int8_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - } - str << ")\n"; - } - } +uf::Mesh::buffer_t& uf::Mesh::getBuffer( const uf::Mesh::Input& input, size_t i ) { + return getBuffer( input, input.attributes[i] ); +} +uf::Mesh::buffer_t& uf::Mesh::getBuffer( const uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute ) { + return buffers[isInterleaved(input.interleaved) ? input.interleaved : attribute.buffer]; +} +const uf::Mesh::buffer_t& uf::Mesh::getBuffer( const uf::Mesh::Input& input, size_t i ) const { + return getBuffer( input, input.attributes[i] ); +} +const uf::Mesh::buffer_t& uf::Mesh::getBuffer( const uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute ) const { + return buffers[isInterleaved(input.interleaved) ? input.interleaved : attribute.buffer]; +} +void uf::Mesh::print( bool full ) const { + std::cout << "Buffers: " << buffers.size() << "\n" << printVertices(full) << printIndices(full) << printInstances(full) << printIndirects() << std::endl; +} - str << "Indices: " << index.count << " | " << (isInterleaved(index.interleaved) ? "interleaved" : "deinterleaved") << "\n"; - for ( auto i = 0; i < index.count; ++i ) { - if ( isInterleaved(index.interleaved) ) { - auto& buffer = buffers[index.interleaved]; - switch ( index.stride ) { - case 1: str << "[" << i << "]: " << *(( uint8_t*) &buffer[i * index.stride]) << "\n"; break; - case 2: str << "[" << i << "]: " << *((uint16_t*) &buffer[i * index.stride]) << "\n"; break; - case 4: str << "[" << i << "]: " << *((uint32_t*) &buffer[i * index.stride]) << "\n"; break; - } - } else for ( auto& attribute : index.attributes ) { - auto& buffer = buffers[attribute.buffer]; - switch ( attribute.descriptor.size ) { - case 1: str << "[" << i << "]: " << *(( uint8_t*) &buffer[i * attribute.descriptor.size]) << "\n"; break; - case 2: str << "[" << i << "]: " << *((uint16_t*) &buffer[i * attribute.descriptor.size]) << "\n"; break; - case 4: str << "[" << i << "]: " << *((uint32_t*) &buffer[i * attribute.descriptor.size]) << "\n"; break; - } - } - } - str << "Instances: " << instance.count << " | " << (isInterleaved(instance.interleaved) ? "interleaved" : "deinterleaved") << "\n"; - for ( auto i = 0; i < instance.count; ++i ) { - if ( isInterleaved(instance.interleaved) ) { - auto& buffer = buffers[instance.interleaved]; - uint8_t* e = (uint8_t*) &buffer[i * instance.stride]; - for ( auto& attribute : instance.attributes ) { - str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; - switch ( attribute.descriptor.type ) { - case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint32_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int32_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint16_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int16_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint8_t*) (e + attribute.descriptor.offset))[j] << " "; break; - case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int8_t*) (e + attribute.descriptor.offset))[j] << " "; break; - } - str << ")\n"; - } - } else for ( auto& attribute : instance.attributes ) { - auto& buffer = buffers[attribute.buffer]; + +#define PRINT_HEADER(input) "Count: " << input.count << " | First: " << input.first << " | Size: " << input.size << " | Offset: " << input.offset << " | " << (isInterleaved(input.interleaved) ? "interleaved" : "deinterleaved") << "\n" + +std::string uf::Mesh::printVertices( bool full ) const { + std::stringstream str; + str << "Vertices: " << PRINT_HEADER( vertex ); + if ( full ) for ( auto i = 0; i < vertex.count; ++i ) { + for ( auto& attribute : vertex.attributes ) { str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; + uint8_t* e = (uint8_t*) attribute.pointer + i * attribute.stride; switch ( attribute.descriptor.type ) { - case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint32_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int32_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint16_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int16_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((uint8_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; - case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((int8_t*) &buffer[i * attribute.descriptor.size])[j] << " "; break; + case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint32_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int32_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint16_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int16_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint8_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int8_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) e)[j] << " "; break; + default: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) e)[j] << " "; break; } str << ")\n"; } } - str << "Indirect: " << indirect.count << " | " << (isInterleaved(indirect.interleaved) ? "interleaved" : "deinterleaved"); - std::cout << str.str() << std::endl; + return str.str(); +} +std::string uf::Mesh::printIndices( bool full ) const { + std::stringstream str; + str << "Indices: " << PRINT_HEADER( index ); + if ( full ) for ( auto i = 0; i < index.count; ++i ) { + auto& buffer = getBuffer( index ); + switch ( index.size ) { + case 1: str << "[" << i << "]: " << *(( uint8_t*) &buffer[i * index.size]) << "\n"; break; + case 2: str << "[" << i << "]: " << *((uint16_t*) &buffer[i * index.size]) << "\n"; break; + case 4: str << "[" << i << "]: " << *((uint32_t*) &buffer[i * index.size]) << "\n"; break; + } + } + return str.str(); +} +std::string uf::Mesh::printInstances( bool full ) const { + std::stringstream str; + str << "Instances: " << PRINT_HEADER( instance ); + if ( full ) for ( auto i = 0; i < instance.count; ++i ) { + for ( auto& attribute : vertex.attributes ) { + str << "[" << i << "][" << attribute.descriptor.name << "]: ( "; + uint8_t* e = (uint8_t*) attribute.pointer + i * attribute.stride; + switch ( attribute.descriptor.type ) { + case uf::renderer::enums::Type::UINT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint32_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::INT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int32_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::USHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint16_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::SHORT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int16_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::UBYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((uint8_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::BYTE: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << (int) ((int8_t*) e)[j] << " "; break; + case uf::renderer::enums::Type::FLOAT: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) e)[j] << " "; break; + default: for ( auto j = 0; j < attribute.descriptor.components; ++j ) str << ((float*) e)[j] << " "; break; + } + str << ")\n"; + } + } + return str.str(); +} +std::string uf::Mesh::printIndirects( bool full ) const { + std::stringstream str; + str << "Indirect: " << PRINT_HEADER( indirect ) << "{ indices, instances, indexID, vertexID, instanceID, padding1, padding2, vertices }\n"; + if ( full ) for ( auto i = 0; i < indirect.count; ++i ) { + auto& buffer = getBuffer( indirect ); + auto& drawCommand = *(const pod::DrawCommand*) (&buffer[i * indirect.size]); + str << "[" << i << "]: {" << drawCommand.indices << ", " << drawCommand.instances << ", " << drawCommand.indexID << ", " << drawCommand.vertexID << ", " << drawCommand.instanceID << ", " << drawCommand.padding1 << ", " << drawCommand.padding2 << ", " << drawCommand.vertices << "}\n"; + } + return str.str(); } // void uf::Mesh::_destroy( uf::Mesh::Input& input ) { @@ -266,52 +316,52 @@ void uf::Mesh::_destroy( uf::Mesh::Input& input ) { input.attributes.clear(); } void uf::Mesh::_bind( bool interleave ) { - size_t buffer = 0; + int32_t buffer = 0; #define PARSE_INPUT(INPUT, INTERLEAVED){\ - if ( INTERLEAVED ) INPUT.interleaved = buffer;\ - for ( auto i = 0; i < INPUT.attributes.size(); ++i ) INPUT.attributes[i].buffer = !INTERLEAVED ? buffer++ : buffer;\ + INPUT.interleaved = (INTERLEAVED ? buffer : -1);\ + for ( auto i = 0; i < INPUT.attributes.size(); ++i ) {\ + INPUT.attributes[i].buffer = !INTERLEAVED ? buffer++ : buffer;\ + INPUT.attributes[i].pointer = NULL;\ + }\ if ( !INPUT.attributes.empty() && INTERLEAVED ) ++buffer;\ } PARSE_INPUT(vertex, interleave) PARSE_INPUT(index, false) -// PARSE_INPUT(instance, interleave) - PARSE_INPUT(instance, false) + PARSE_INPUT(instance, interleave) PARSE_INPUT(indirect, false) buffers.resize( buffer ); updateDescriptor(); -// for ( auto& attribute : vertex.attributes ) UF_MSG_DEBUG( attribute.descriptor.name << "[" << attribute.descriptor.offset << "]: " << attribute.descriptor.size ); #undef PARSE_INPUT } void uf::Mesh::_updateDescriptor( uf::Mesh::Input& input ) { - input.stride = 0; + input.size = 0; for ( auto& attribute : input.attributes ) { const bool interleaved = isInterleaved(input.interleaved); auto& buffer = buffers[interleaved ? input.interleaved : attribute.buffer]; attribute.length = buffer.size(); - attribute.pointer = (void*) (buffer.data() + attribute.offset); - if ( !interleaved ) attribute.stride = attribute.descriptor.size; - else attribute.pointer += attribute.descriptor.offset; - input.stride += attribute.descriptor.size; + attribute.pointer = buffer.data() + attribute.offset; + input.size += attribute.descriptor.size; + if ( interleaved ) attribute.pointer += attribute.descriptor.offset; } for ( auto& attribute : input.attributes ) { - const bool interleaved = isInterleaved(input.interleaved); - if ( interleaved ) attribute.stride = input.stride; + attribute.stride = isInterleaved(input.interleaved) ? input.size : attribute.descriptor.size; } } uf::Mesh::Attribute uf::Mesh::_remapAttribute( const uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute, size_t i ) const { uf::Mesh::Attribute res = attribute; - if ( i < indirect.count ) { - auto& drawCommand = ((const pod::DrawCommand*) buffers[isInterleaved(indirect.interleaved) ? indirect.interleaved : indirect.attributes.front().buffer].data())[i]; - if ( &input == &vertex ) { - res.pointer += drawCommand.vertexID * res.stride; - res.length = drawCommand.vertices * res.stride; - } else if ( &input == &index ) { - res.pointer += drawCommand.indexID * res.stride; - res.length = drawCommand.indices * res.stride; - } + UF_ASSERT( i < indirect.count ); + UF_ASSERT( &input == &vertex || &input == &index ); + + auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect).data())[i]; + if ( &input == &vertex ) { + res.pointer += drawCommand.vertexID * res.stride; + res.length = drawCommand.vertices * res.stride; + } else if ( &input == &index ) { + res.pointer += drawCommand.indexID * res.stride; + res.length = drawCommand.indices * res.stride; } return res; } @@ -361,7 +411,7 @@ void uf::Mesh::_insertVs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const } } else if ( !isInterleaved(dstInput.interleaved) && isInterleaved(srcInput.interleaved) ) { // UF_EXCEPTION("to be implemented: interleaved -> deinterleaved"); - uf::Mesh::Input _srcInput = _srcInput; + uf::Mesh::Input _srcInput = srcInput; const uint8_t* src = (const uint8_t*) mesh.buffers.at(srcInput.interleaved).data(); size_t _ = 0; while ( _++ < _srcInput.count ) { @@ -385,23 +435,23 @@ void uf::Mesh::_insertIs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const // both meshes are interleaved, just copy directly if ( isInterleaved(dstInput.interleaved) && isInterleaved(srcInput.interleaved) ) { - auto& src = mesh.buffers[srcInput.interleaved]; - auto& dst = buffers[dstInput.interleaved]; + auto& src = mesh.getBuffer( srcInput ); + auto& dst = getBuffer( dstInput ); + dst.insert( dst.end(), src.begin(), src.end() ); // both meshes are de-interleaved, just copy directly } else if ( !isInterleaved(dstInput.interleaved) && !isInterleaved(srcInput.interleaved) ) { for ( auto i = 0; i < dstInput.attributes.size(); ++i ) { - auto& srcAttribute = srcInput.attributes[i]; - auto& dstAttribute = dstInput.attributes[i]; - auto& src = mesh.buffers[srcAttribute.buffer]; - auto& dst = buffers[dstAttribute.buffer]; + auto& src = mesh.getBuffer( srcInput ); + auto& dst = getBuffer( dstInput ); + dst.insert( dst.end(), src.begin(), src.end() ); } // not easy to convert, will implement later } else if ( isInterleaved(dstInput.interleaved) && !isInterleaved(srcInput.interleaved) ) { // UF_EXCEPTION("to be implemented: deinterleaved -> interleaved"); uf::Mesh::Input _srcInput = srcInput; - auto& dst = buffers.at(dstInput.interleaved); + auto& dst = getBuffer( dstInput ); size_t _ = 0; while ( _++ < _srcInput.count ) { for ( auto& srcAttribute : _srcInput.attributes ) { @@ -411,13 +461,13 @@ void uf::Mesh::_insertIs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const } } else if ( !isInterleaved(dstInput.interleaved) && isInterleaved(srcInput.interleaved) ) { // UF_EXCEPTION("to be implemented: interleaved -> deinterleaved"); - uf::Mesh::Input _srcInput = _srcInput; - const uint8_t* src = (const uint8_t*) mesh.buffers.at(srcInput.interleaved).data(); + uf::Mesh::Input _srcInput = srcInput; + const uint8_t* src = (const uint8_t*) mesh.getBuffer( srcInput ).data(); size_t _ = 0; while ( _++ < _srcInput.count ) { for ( size_t i = 0; i < dstInput.attributes.size(); ++i ) { - auto& srcAttribute = _srcInput.attributes.at(i); - auto& dstAttribute = dstInput.attributes.at(i); + auto& srcAttribute = _srcInput.attributes[i]; + auto& dstAttribute = dstInput.attributes[i]; auto& dst = buffers.at(dstAttribute.buffer); dst.insert( dst.end(), src, src + srcAttribute.descriptor.size ); @@ -436,7 +486,7 @@ bool uf::Mesh::_hasV( const uf::Mesh::Input& input, const uf::stl::vector