636 lines
23 KiB
C++
636 lines
23 KiB
C++
#include <uf/utils/mesh/mesh.h>
|
|
#include <uf/engine/graph/graph.h>
|
|
|
|
// Used for per-vertex colors
|
|
UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F4F,
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F4F, R32G32B32_SFLOAT, position)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F4F, R32G32_SFLOAT, uv)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F4F, R32G32B32_SFLOAT, normal)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F4F, R32_UINT, color)
|
|
)
|
|
UF_VERTEX_INTERPOLATE(pod::Vertex_3F2F3F4F, {
|
|
return {
|
|
uf::vector::lerp( p1.position, p2.position, t ),
|
|
uf::vector::lerp( p1.uv, p2.uv, t ),
|
|
uf::vector::normalize( uf::vector::lerp( p1.normal, p2.normal, t ) ),
|
|
uf::vector::lerp( p1.color, p2.color, t ),
|
|
};
|
|
})
|
|
// Used for terrain
|
|
UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F32B,
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F32B, R32G32B32_SFLOAT, position)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F32B, R32G32_SFLOAT, uv)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F32B, R32G32B32_SFLOAT, normal)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F32B, R32_UINT, color)
|
|
)
|
|
UF_VERTEX_INTERPOLATE(pod::Vertex_3F2F3F32B, {
|
|
return {
|
|
uf::vector::lerp( p1.position, p2.position, t ),
|
|
uf::vector::lerp( p1.uv, p2.uv, t ),
|
|
uf::vector::normalize( uf::vector::lerp( p1.normal, p2.normal, t ) ),
|
|
t < 0.5 ? p1.color : p2.color,
|
|
//uf::vector::lerp( p1.color, p2.color, t ),
|
|
};
|
|
})
|
|
// Used for normal meshses
|
|
UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F,
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F, R32G32B32_SFLOAT, position)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F, R32G32_SFLOAT, uv)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F, R32G32B32_SFLOAT, normal)
|
|
)
|
|
UF_VERTEX_INTERPOLATE(pod::Vertex_3F3F3F, {
|
|
return {
|
|
uf::vector::lerp( p1.position, p2.position, t ),
|
|
uf::vector::lerp( p1.uv, p2.uv, t ),
|
|
uf::vector::normalize( uf::vector::lerp( p1.normal, p2.normal, t ) ),
|
|
};
|
|
})
|
|
// (Typically) used for displaying textures
|
|
UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F,
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F, R32G32B32_SFLOAT, position)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F, R32G32_SFLOAT, uv)
|
|
)
|
|
UF_VERTEX_INTERPOLATE(pod::Vertex_3F2F3F1UI, {
|
|
return {
|
|
uf::vector::lerp( p1.position, p2.position, t ),
|
|
uf::vector::lerp( p1.uv, p2.uv, t ),
|
|
uf::vector::normalize( uf::vector::lerp( p1.normal, p2.normal, t ) ),
|
|
uf::vector::lerp( p1.id, p2.id, t ),
|
|
};
|
|
})
|
|
UF_VERTEX_DESCRIPTOR(pod::Vertex_2F2F,
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_2F2F, R32G32B32_SFLOAT, position)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_2F2F, R32G32_SFLOAT, uv)
|
|
)
|
|
UF_VERTEX_INTERPOLATE(pod::Vertex_3F2F3F, {
|
|
return {
|
|
uf::vector::lerp( p1.position, p2.position, t ),
|
|
uf::vector::lerp( p1.uv, p2.uv, t ),
|
|
uf::vector::normalize( uf::vector::lerp( p1.normal, p2.normal, t ) ),
|
|
};
|
|
})
|
|
// used for texture arrays
|
|
UF_VERTEX_DESCRIPTOR(pod::Vertex_3F3F3F,
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F3F3F, R32G32B32_SFLOAT, position)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F3F3F, R32G32B32_SFLOAT, uv)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F3F3F, R32G32B32_SFLOAT, normal)
|
|
)
|
|
UF_VERTEX_INTERPOLATE(pod::Vertex_3F2F, {
|
|
return {
|
|
uf::vector::lerp( p1.position, p2.position, t ),
|
|
uf::vector::lerp( p1.uv, p2.uv, t ),
|
|
};
|
|
})
|
|
UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F1UI,
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F1UI, R32G32B32_SFLOAT, position)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F1UI, R32G32_SFLOAT, uv)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F1UI, R32G32B32_SFLOAT, normal)
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F1UI, R32_UINT, id)
|
|
)
|
|
UF_VERTEX_INTERPOLATE(pod::Vertex_2F2F, {
|
|
return {
|
|
uf::vector::lerp( p1.position, p2.position, t ),
|
|
uf::vector::lerp( p1.uv, p2.uv, t ),
|
|
};
|
|
})
|
|
// Basic
|
|
UF_VERTEX_DESCRIPTOR(pod::Vertex_3F,
|
|
UF_VERTEX_DESCRIPTION(pod::Vertex_3F, R32G32B32_SFLOAT, position)
|
|
)
|
|
UF_VERTEX_INTERPOLATE(pod::Vertex_3F, {
|
|
return {
|
|
uf::vector::lerp( p1.position, p2.position, t ),
|
|
};
|
|
})
|
|
|
|
void uf::Mesh::initialize() {}
|
|
void uf::Mesh::destroy() {
|
|
_destroy(vertex);
|
|
_destroy(index);
|
|
_destroy(instance);
|
|
_destroy(indirect);
|
|
|
|
buffers.clear();
|
|
}
|
|
uf::Mesh uf::Mesh::copy() const {
|
|
uf::Mesh res;
|
|
|
|
res.bind( *this );
|
|
res.insert(*this);
|
|
res.updateDescriptor();
|
|
|
|
return res;
|
|
}
|
|
uf::Mesh& uf::Mesh::copy( const uf::Mesh& src ) {
|
|
if ( src.buffers.empty() ) return *this;
|
|
|
|
bind( src );
|
|
insert( src );
|
|
updateDescriptor();
|
|
|
|
return *this;
|
|
}
|
|
uf::Mesh uf::Mesh::alias() const {
|
|
uf::Mesh alias = *this;
|
|
for ( auto& buf : alias.buffers ) buf.clear();
|
|
alias.updateDescriptor();
|
|
return alias;
|
|
}
|
|
void uf::Mesh::updateDescriptor() {
|
|
_updateDescriptor(vertex);
|
|
_updateDescriptor(index);
|
|
_updateDescriptor(instance);
|
|
_updateDescriptor(indirect);
|
|
_updateViews();
|
|
}
|
|
void uf::Mesh::bind( const uf::Mesh& mesh ) {
|
|
vertex.attributes = mesh.vertex.attributes;
|
|
index.attributes = mesh.index.attributes;
|
|
instance.attributes = mesh.instance.attributes;
|
|
indirect.attributes = mesh.indirect.attributes;
|
|
|
|
_bind();
|
|
}
|
|
void uf::Mesh::insert( const uf::Mesh& mesh ) {
|
|
if ( vertex.attributes.empty() && index.attributes.empty() && instance.attributes.empty() && indirect.attributes.empty() ) bind( mesh );
|
|
|
|
insertVertices(mesh);
|
|
insertIndices(mesh);
|
|
// insertInstances(mesh);
|
|
insertIndirects(mesh);
|
|
|
|
updateDescriptor();
|
|
}
|
|
void uf::Mesh::generateIndices() {
|
|
// deduce type
|
|
size_t size = sizeof(uint32_t);
|
|
uf::renderer::enums::Type::type_t type{};
|
|
/*if ( vertex.count <= std::numeric_limits<uint8_t>::max() ) { size = sizeof(uint8_t); type = uf::renderer::typeToEnum<uint8_t>(); }
|
|
else*/ if ( vertex.count <= std::numeric_limits<uint16_t>::max() ) { size = sizeof(uint16_t); type = uf::renderer::typeToEnum<uint16_t>(); }
|
|
else if ( vertex.count <= std::numeric_limits<uint32_t>::max() ) { size = sizeof(uint32_t); type = uf::renderer::typeToEnum<uint32_t>(); }
|
|
|
|
if ( !index.attributes.empty() ) {
|
|
_destroy( index );
|
|
}
|
|
_bindI( index, size, type );
|
|
_bind();
|
|
|
|
switch ( size ) {
|
|
case 1: { uf::stl::vector<uint8_t> indices( vertex.count ); std::iota( indices.begin(), indices.end(), 0 ); insertIndices( indices ); } break;
|
|
case 2: { uf::stl::vector<uint16_t> indices( vertex.count ); std::iota( indices.begin(), indices.end(), 0 ); insertIndices( indices ); } break;
|
|
case 4: { uf::stl::vector<uint32_t> indices( vertex.count ); std::iota( indices.begin(), indices.end(), 0 ); insertIndices( indices ); } break;
|
|
}
|
|
}
|
|
uf::Mesh uf::Mesh::expand( ) {
|
|
uf::Mesh res = copy();
|
|
|
|
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*) (static_cast<uint8_t*>(srcIndex.pointer) + idx * srcIndex.stride);\
|
|
*((T*) (static_cast<uint8_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[_];
|
|
|
|
uint8_t* srcAddr = static_cast<uint8_t*>(srcInput.pointer) + index * srcInput.stride;
|
|
uint8_t* dstAddr = static_cast<uint8_t*>(dstInput.pointer) + idx * dstInput.stride;
|
|
|
|
memcpy( dstAddr, srcAddr, srcInput.descriptor.size );
|
|
}
|
|
}
|
|
|
|
#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;
|
|
}
|
|
|
|
void uf::Mesh::clearAttribute( uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute ) {
|
|
for ( size_t i = 0; i < input.attributes.size(); ++i ) if ( input.attributes[i].descriptor == attribute.descriptor ) return clearAttribute( input, i );
|
|
}
|
|
void uf::Mesh::clearAttribute( uf::Mesh::Input& input, size_t i ) {
|
|
auto attribute = input.attributes[i];
|
|
buffers[attribute.buffer].clear();
|
|
}
|
|
void uf::Mesh::clear() {
|
|
for ( size_t i = 0; i < vertex.attributes.size(); ++i ) clearAttribute( vertex, i );
|
|
for ( size_t i = 0; i < index.attributes.size(); ++i ) clearAttribute( index, i );
|
|
for ( size_t i = 0; i < instance.attributes.size(); ++i ) clearAttribute( instance, i );
|
|
for ( size_t i = 0; i < indirect.attributes.size(); ++i ) clearAttribute( indirect, i );
|
|
|
|
vertex.count = 0;
|
|
index.count = 0;
|
|
instance.count = 0;
|
|
indirect.count = 0;
|
|
}
|
|
|
|
void uf::Mesh::generateIndirect() {
|
|
if ( index.count == 0 ) generateIndices();
|
|
|
|
uf::stl::vector<pod::DrawCommand> commands;
|
|
for ( auto& attribute : index.attributes ) {
|
|
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,
|
|
.indexID = 0,
|
|
.vertexID = 0,
|
|
.instanceID = 0,
|
|
// .materialID = 0,
|
|
// .objectID = 0,
|
|
.vertices = vertex.count,
|
|
});
|
|
}
|
|
|
|
_destroy( indirect );
|
|
bindIndirect<pod::DrawCommand>();
|
|
_bind();
|
|
insertIndirects( commands );
|
|
}
|
|
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[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[attribute.buffer];
|
|
}
|
|
|
|
uf::Mesh::View uf::Mesh::makeView( const uf::stl::vector<uf::stl::string>& wanted, size_t lod ) const {
|
|
uf::Mesh::View view;
|
|
view.vertex = vertex;
|
|
view.index = index;
|
|
|
|
if ( wanted.size() ) {
|
|
for ( auto& attr : vertex.attributes ) {
|
|
if ( std::find(wanted.begin(), wanted.end(), attr.descriptor.name ) == wanted.end() ) continue;
|
|
view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
|
}
|
|
} else {
|
|
for ( auto& attr : vertex.attributes ) {
|
|
view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
|
}
|
|
}
|
|
|
|
if ( !index.attributes.empty() ) {
|
|
view.attributes["index"_hash] = { index.attributes[lod] };
|
|
}
|
|
|
|
return view;
|
|
}
|
|
uf::Mesh::View uf::Mesh::makeView( size_t i, const uf::stl::vector<uf::stl::string>& wanted, size_t lod ) const {
|
|
uf::Mesh::View view;
|
|
view.vertex = remapVertexInput(i, lod);
|
|
view.index = remapIndexInput(i, lod);
|
|
view.indirectIndex = i;
|
|
|
|
if ( wanted.size() ) {
|
|
for (auto& attr : vertex.attributes) {
|
|
if ( std::find(wanted.begin(), wanted.end(), attr.descriptor.name ) == wanted.end() ) continue;
|
|
view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
|
}
|
|
} else {
|
|
for ( auto& attr : vertex.attributes ) view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
|
}
|
|
|
|
if ( !index.attributes.empty() ) {
|
|
view.attributes["index"_hash] = { index.attributes[lod] };
|
|
}
|
|
|
|
return view;
|
|
}
|
|
uf::stl::vector<uf::Mesh::View> uf::Mesh::makeViews( const uf::stl::vector<uf::stl::string>& wanted, size_t lod ) const {
|
|
uf::stl::vector<uf::Mesh::View> views;
|
|
if ( indirect.count > 0 ) {
|
|
for ( auto i = 0; i < indirect.count; i++ ) {
|
|
auto view = makeView( i, wanted, lod );
|
|
if ( view.index.count == 0 && view.vertex.count == 0 ) continue;
|
|
views.emplace_back( view );
|
|
}
|
|
} else {
|
|
views.emplace_back( makeView(wanted, lod) );
|
|
}
|
|
return views;
|
|
}
|
|
|
|
uf::Mesh::Input uf::Mesh::remapInput( const uf::Mesh::Input& input, size_t i, size_t lod ) 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, lod).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, size_t lod ) const {
|
|
uf::Mesh::Input res = vertex;
|
|
UF_ASSERT( i < indirect.count );
|
|
|
|
const auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect, lod).data())[i];
|
|
res.first = drawCommand.vertexID;
|
|
res.count = drawCommand.vertices;
|
|
|
|
return res;
|
|
}
|
|
uf::Mesh::Input uf::Mesh::remapIndexInput( size_t i, size_t lod ) const {
|
|
uf::Mesh::Input res = index;
|
|
UF_ASSERT( i < indirect.count );
|
|
|
|
const auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect, lod).data())[i];
|
|
res.first = drawCommand.indexID;
|
|
res.count = drawCommand.indices;
|
|
|
|
return res;
|
|
}
|
|
//
|
|
void uf::Mesh::_destroy( uf::Mesh::Input& input ) {
|
|
for ( auto& attribute : input.attributes ) {
|
|
attribute.length = 0;
|
|
attribute.pointer = NULL;
|
|
attribute.buffer = 0;
|
|
}
|
|
input.attributes.clear();
|
|
}
|
|
void uf::Mesh::_bind() {
|
|
int32_t buffer = 0;
|
|
|
|
auto parse_input = [&](uf::Mesh::Input& input) {
|
|
for ( auto& attribute : input.attributes ) {
|
|
attribute.buffer = buffer++;
|
|
attribute.pointer = NULL;
|
|
}
|
|
};
|
|
|
|
parse_input(vertex);
|
|
parse_input(index);
|
|
parse_input(instance);
|
|
parse_input(indirect);
|
|
|
|
buffers.resize( buffer );
|
|
updateDescriptor();
|
|
}
|
|
void uf::Mesh::_updateDescriptor( uf::Mesh::Input& input ) {
|
|
input.size = 0;
|
|
for ( auto& attribute : input.attributes ) {
|
|
if ( attribute.buffer >= 0 && attribute.buffer < buffers.size() && !buffers[attribute.buffer].empty() ) {
|
|
auto& buffer = buffers[attribute.buffer];
|
|
attribute.length = buffer.size();
|
|
attribute.pointer = buffer.data() + attribute.offset;
|
|
}
|
|
|
|
if ( &input == &index || &input == &indirect ) input.size = attribute.descriptor.size;
|
|
else input.size += attribute.descriptor.size;
|
|
|
|
attribute.stride = attribute.descriptor.size;
|
|
}
|
|
}
|
|
void uf::Mesh::_updateViews() {
|
|
buffer_views = makeViews();
|
|
}
|
|
uf::Mesh::Attribute uf::Mesh::_remapAttribute( const uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute, size_t i ) const {
|
|
UF_ASSERT( i < indirect.count );
|
|
UF_ASSERT( &input == &vertex || &input == &index );
|
|
UF_MSG_WARNING( "deprecated, please use remapInput" );
|
|
|
|
uf::Mesh::Attribute res = attribute;
|
|
|
|
auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect).data())[i];
|
|
if ( &input == &vertex ) {
|
|
res.pointer = static_cast<uint8_t*>(res.pointer) + drawCommand.vertexID * res.stride;
|
|
res.length = drawCommand.vertices * res.stride;
|
|
} else if ( &input == &index ) {
|
|
res.pointer = static_cast<uint8_t*>(res.pointer) + drawCommand.indexID * res.stride;
|
|
res.length = drawCommand.indices * res.stride;
|
|
}
|
|
return res;
|
|
}
|
|
void uf::Mesh::_insertVs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) {
|
|
_reserveVs( dstInput, dstInput.count += srcInput.count );
|
|
|
|
if ( _hasV( dstInput, srcInput ) ) {
|
|
for ( auto i = 0; i < dstInput.attributes.size(); ++i ) {
|
|
auto& src = mesh.buffers[srcInput.attributes[i].buffer];
|
|
auto& dst = buffers[dstInput.attributes[i].buffer];
|
|
dst.insert( dst.end(), src.begin(), src.end() );
|
|
}
|
|
} else {
|
|
for ( auto& dstAttribute : dstInput.attributes ) {
|
|
for ( auto& srcAttribute : srcInput.attributes ) {
|
|
if ( srcAttribute.descriptor != dstAttribute.descriptor ) continue;
|
|
|
|
auto& src = mesh.buffers[srcAttribute.buffer];
|
|
auto& dst = buffers[dstAttribute.buffer];
|
|
dst.insert( dst.end(), src.begin(), src.end() );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_updateDescriptor( dstInput );
|
|
}
|
|
void uf::Mesh::_insertIs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) {
|
|
_reserveIs( dstInput, dstInput.count += srcInput.count );
|
|
|
|
for ( auto i = 0; i < dstInput.attributes.size(); ++i ) {
|
|
auto& src = mesh.getBuffer( srcInput, i );
|
|
auto& dst = getBuffer( dstInput, i );
|
|
|
|
dst.insert( dst.end(), src.begin(), src.end() );
|
|
}
|
|
_updateDescriptor( dstInput );
|
|
}
|
|
// Vertices
|
|
bool uf::Mesh::_hasV( const uf::Mesh::Input& input, const uf::stl::vector<ext::RENDERER::AttributeDescriptor>& descriptors ) const {
|
|
if ( input.attributes.size() != descriptors.size() ) return false;
|
|
for ( auto i = 0; i < input.attributes.size(); ++i ) if ( input.attributes[i].descriptor != descriptors[i] ) return false;
|
|
return true;
|
|
}
|
|
bool uf::Mesh::_hasV( const uf::Mesh::Input& input, const uf::Mesh::Input& srcInput ) const {
|
|
if ( input.attributes.size() != srcInput.attributes.size() || input.size != srcInput.size ) return false;
|
|
for ( auto i = 0; i < input.attributes.size(); ++i ) if ( input.attributes[i].descriptor != srcInput.attributes[i].descriptor ) return false;
|
|
return true;
|
|
}
|
|
void uf::Mesh::_bindV( uf::Mesh::Input& input, const uf::stl::vector<uf::renderer::AttributeDescriptor>& descriptors ) {
|
|
input.attributes.resize( descriptors.size() );
|
|
for ( auto i = 0; i < descriptors.size(); ++i ) {
|
|
auto& attribute = input.attributes[i];
|
|
attribute.descriptor = descriptors[i];
|
|
input.size += attribute.descriptor.size;
|
|
}
|
|
}
|
|
void uf::Mesh::_reserveVs( uf::Mesh::Input& input, size_t count ) {
|
|
for ( auto& attribute : input.attributes ) {
|
|
buffers[attribute.buffer].reserve( count * attribute.descriptor.size );
|
|
attribute.length = buffers[attribute.buffer].size();
|
|
attribute.pointer = (uint8_t*) (buffers[attribute.buffer].data());
|
|
}
|
|
}
|
|
void uf::Mesh::_resizeVs( uf::Mesh::Input& input, size_t count ) {
|
|
for ( auto& attribute : input.attributes ) {
|
|
buffers[attribute.buffer].resize( count * attribute.descriptor.size );
|
|
attribute.length = buffers[attribute.buffer].size();
|
|
attribute.pointer = (uint8_t*) (buffers[attribute.buffer].data());
|
|
}
|
|
}
|
|
void uf::Mesh::_insertV( uf::Mesh::Input& input, const void* data ) {
|
|
_reserveVs( input, ++input.count );
|
|
const uint8_t* pointer = (const uint8_t*) data;
|
|
|
|
for ( auto& attribute : input.attributes ) {
|
|
buffers[attribute.buffer].insert(
|
|
buffers[attribute.buffer].end(),
|
|
pointer + attribute.descriptor.offset,
|
|
pointer + attribute.descriptor.offset + attribute.descriptor.size
|
|
);
|
|
}
|
|
}
|
|
void uf::Mesh::_insertVs( uf::Mesh::Input& input, const void* data, size_t size ) {
|
|
size_t count = input.count;
|
|
input.count += size;
|
|
|
|
_resizeVs( input, input.count );
|
|
|
|
const uint8_t* pointer = static_cast<const uint8_t*>(data);
|
|
for ( auto& attribute : input.attributes ) {
|
|
uint8_t* dstBase = buffers[attribute.buffer].data() + (count * attribute.descriptor.size);
|
|
|
|
size_t srcOffset = attribute.descriptor.offset;
|
|
size_t attrSize = attribute.descriptor.size;
|
|
|
|
for ( size_t i = 0; i < size; ++i ) {
|
|
const uint8_t* srcAddr = pointer + (i * input.size) + srcOffset;
|
|
uint8_t* dstAddr = dstBase + (i * attrSize);
|
|
|
|
memcpy( dstAddr, srcAddr, attrSize );
|
|
}
|
|
}
|
|
}
|
|
// Indices
|
|
void uf::Mesh::_bindI( uf::Mesh::Input& input, size_t size, ext::RENDERER::enums::Type::type_t type, size_t count ) {
|
|
input.attributes.resize( count );
|
|
input.size = size;
|
|
for ( auto i = 0; i < count; ++i ) {
|
|
auto& attribute = input.attributes[i];
|
|
attribute.descriptor.offset = 0;
|
|
attribute.descriptor.size = size;
|
|
attribute.descriptor.components = 1;
|
|
attribute.descriptor.type = type;
|
|
}
|
|
}
|
|
void uf::Mesh::_reserveIs( uf::Mesh::Input& input, size_t count, size_t i ) {
|
|
auto& attribute = input.attributes[i];
|
|
buffers[attribute.buffer].reserve( count * attribute.descriptor.size );
|
|
attribute.length = buffers[attribute.buffer].size();
|
|
attribute.pointer = (uint8_t*) (buffers[attribute.buffer].data());
|
|
}
|
|
void uf::Mesh::_resizeIs( uf::Mesh::Input& input, size_t count, size_t i ) {
|
|
auto& attribute = input.attributes[i];
|
|
buffers[attribute.buffer].resize( count * attribute.descriptor.size );
|
|
attribute.length = buffers[attribute.buffer].size();
|
|
attribute.pointer = (uint8_t*) (buffers[attribute.buffer].data());
|
|
}
|
|
void uf::Mesh::_insertI( uf::Mesh::Input& input, const void* data, size_t i ) {
|
|
auto& attribute = input.attributes[i];
|
|
_reserveIs( input, ++input.count );
|
|
const uint8_t* pointer = (const uint8_t*) data;
|
|
|
|
buffers[attribute.buffer].insert( buffers[attribute.buffer].end(), pointer, pointer + attribute.descriptor.size );
|
|
}
|
|
void uf::Mesh::_insertIs( uf::Mesh::Input& input, const void* data, size_t size, size_t i ) {
|
|
auto& attribute = input.attributes[i];
|
|
_reserveIs( input, input.count += size );
|
|
const uint8_t* pointer = (const uint8_t*) data;
|
|
for ( const uint8_t* p = pointer; p < pointer + size * attribute.descriptor.size; p += attribute.descriptor.size )
|
|
buffers[attribute.buffer].insert( buffers[attribute.buffer].end(), p + attribute.descriptor.offset, p + attribute.descriptor.offset + attribute.descriptor.size );
|
|
}
|
|
|
|
////
|
|
void uf::mesh::setIndex( void* pointer, size_t stride, size_t index, size_t value ) {
|
|
switch ( stride ) {
|
|
case 1: ((uint8_t*) pointer)[index] = static_cast<uint8_t>(value); break;
|
|
case 2: ((uint16_t*) pointer)[index] = static_cast<uint16_t>(value); break;
|
|
case 4: ((uint32_t*) pointer)[index] = static_cast<uint32_t>(value); break;
|
|
default: {
|
|
UF_EXCEPTION("invalid stride type: {}", stride);
|
|
} break;
|
|
}
|
|
}
|
|
size_t uf::mesh::fetchIndex( const void* pointer, size_t stride, size_t index ) {
|
|
#define CAST_INDEX(T) case sizeof(T): return ((T*) pointer)[index];
|
|
switch ( stride ) {
|
|
CAST_INDEX(uint8_t);
|
|
CAST_INDEX(uint16_t);
|
|
CAST_INDEX(uint32_t);
|
|
default: {
|
|
UF_EXCEPTION("invalid stride type: {}", stride);
|
|
} break;
|
|
}
|
|
}
|
|
pod::Vector3f uf::mesh::fetchVertex( const uf::Mesh::View& view, const uf::Mesh::AttributeView& positions, size_t index ) {
|
|
return uf::mesh::fetchVertexAttribute<pod::Vector3f>( view, positions, index );
|
|
}
|
|
|
|
pod::Triangle uf::mesh::fetchTriangle( const uf::Mesh::View& view, const uf::Mesh::AttributeView& indices, const uf::Mesh::AttributeView& positions, size_t triID ) {
|
|
auto index = triID * 3;
|
|
pod::Triangle tri;
|
|
FOR_EACH(3, {
|
|
tri.points[i] = uf::mesh::fetchVertex( view, positions, uf::mesh::fetchIndex( view, indices, index + i ) );
|
|
});
|
|
return tri;
|
|
}
|
|
|
|
pod::TriangleWithNormal uf::mesh::fetchTriangle( const uf::Mesh& mesh, size_t triID ) {
|
|
const auto& views = mesh.buffer_views;
|
|
UF_ASSERT(!views.empty());
|
|
|
|
// find which view contains this triangle index.
|
|
size_t triBase = 0;
|
|
const uf::Mesh::View* view = nullptr;
|
|
for ( auto& v : views ) {
|
|
auto trisInView = v.index.count / 3;
|
|
if (triID < triBase + trisInView) {
|
|
view = &v;
|
|
triID -= triBase; // local triangle index inside this view
|
|
break;
|
|
}
|
|
triBase += trisInView;
|
|
}
|
|
UF_ASSERT( view );
|
|
|
|
pod::TriangleWithNormal tri = { uf::mesh::fetchTriangle( *view, triID ) };
|
|
tri.normal = uf::vector::normalize(uf::vector::cross(tri.points[1] - tri.points[0], tri.points[2] - tri.points[0]));
|
|
|
|
return tri;
|
|
} |