Files
UnrealEngine/Engine/Plugins/Experimental/SkeletalReduction/Source/Private/SkeletalMeshReductionSkinnedMesh.h
2025-05-18 13:04:45 +08:00

234 lines
4.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "SkeletalSimplifierMeshManager.h"
namespace SkeletalSimplifier
{
/**
* Simple mesh class templated on vertex type
* that holds an index and vertex buffer.
*
* Has the ability to compact and remove unused vertices
* NB: here 'unused' means vertices that aren't referenced by the index buffer
*/
template <typename SimpVertexType>
class TSkinnedSkeletalMesh
{
public:
typedef SimpVertexType VertexType;
TSkinnedSkeletalMesh() :
IndexBuffer(NULL),
VertexBuffer(NULL),
NumTris(0),
NumVerts(0),
TexCoordNum(0)
{}
~TSkinnedSkeletalMesh()
{
Empty();
}
/**
* Constructor allocates index and vertex buffer.
*/
TSkinnedSkeletalMesh(int32 NumTriangles, int32 NumVertices) :
IndexBuffer(NULL),
VertexBuffer(NULL),
NumTris(0),
NumVerts(0),
TexCoordNum(0)
{
Resize(NumTriangles, NumVertices);
}
/**
* Resizes the mesh to new size.
* NB: Deletes data already held in mesh.
*/
void Resize(int32 NumTriangles, int32 NumVertices)
{
delete[] IndexBuffer;
delete[] VertexBuffer;
NumTris = NumTriangles;
NumVerts = NumVertices;
IndexBuffer = new uint32[NumTriangles * 3];
VertexBuffer = new SimpVertexType[NumVerts];
}
/**
* Resizes the mesh to size zero.
*/
void Empty()
{
delete[] IndexBuffer;
delete[] VertexBuffer;
IndexBuffer = NULL;
VertexBuffer = NULL;
NumTris = 0;
NumVerts = 0;
}
/**
* Size of index buffer
*/
int32 NumIndices() const { return NumTris * 3; }
/**
* Size of vertex buffer
*/
int32 NumVertices() const { return NumVerts; }
/**
* Number of texture coords on each vertex.
*/
int32 TexCoordCount() const { return TexCoordNum; }
void SetTexCoordCount(int32 c)
{
TexCoordNum = c;
}
/**
* Remove vertices that aren't referenced by the index buffer.
* Also rebuilds the index buffer to account for the removals.
* Optionally, VertexRemap will map the compact vert index to the original vert index
*/
void Compact(TArray<int32>* VertexRemap = nullptr)
{
if (IndexBuffer == NULL)
{
return;
}
int32* Mask = new int32[NumVerts];
for (int32 i = 0; i < NumVerts; ++i)
{
Mask[i] = 0;
}
// mark the verts that are being used
for (int32 i = 0; i < NumTris * 3; ++i)
{
uint32 VertId = IndexBuffer[i];
Mask[VertId] = 1;
}
// count the used verts.
int32 RequiredVertCount = 0;
for (int32 i = 0; i < NumVerts; ++i)
{
RequiredVertCount += Mask[i];
}
if (VertexRemap)
{
VertexRemap->Empty();
VertexRemap->SetNumUninitialized(RequiredVertCount);
}
// If all the verts are being used, there is nothing to do
if (RequiredVertCount == NumVerts)
{
if (VertexRemap)
{
for (int32 i = 0; i < RequiredVertCount; ++i)
{
(*VertexRemap)[i] = i;
}
}
delete[] Mask;
return;
}
// stash the pointers to the current buffers
uint32* OldIndexBuffer = IndexBuffer;
SimpVertexType* OldVertexBuffer = VertexBuffer;
if (OldVertexBuffer != NULL && OldIndexBuffer != NULL)
{
int32 OldNumTris = NumTris;
int32 OldNumVerts = NumVerts;
// null the pointers to keep the resize from deleting the arrays.
IndexBuffer = NULL;
VertexBuffer = NULL;
// Allocate memory for the compacted mesh.
Resize(NumTris, RequiredVertCount);
// Copy the verts into the new vertex array
for (int32 i = 0, j = 0; i < OldNumVerts; ++i)
{
if (Mask[i] == 0) continue;
checkSlow(j < RequiredVertCount);
VertexBuffer[j] = OldVertexBuffer[i];
if (VertexRemap)
{
(*VertexRemap)[j] = i;
}
j++;
}
// record offsets the Mask
// so that Mask[i] will be the number of voids prior to and including i.
{
int32 VoidCount = 0;
for (int32 i = 0; i < OldNumVerts; ++i)
{
VoidCount += (1 - Mask[i]);
Mask[i] = VoidCount;
}
}
check(OldNumTris == NumTris);
// translate the offsets in the index buffer
for (int32 i = 0; i < OldNumTris * 3; ++i)
{
int32 OldVertIdx = OldIndexBuffer[i];
int32 VoidCount = Mask[OldVertIdx];
int32 NewVertIdx = OldVertIdx - VoidCount;
checkSlow(NewVertIdx > -1);
IndexBuffer[i] = NewVertIdx;
}
// Clean up the temporary
delete[] OldVertexBuffer;
delete[] OldIndexBuffer;
}
delete[] Mask;
}
uint32* IndexBuffer;
SimpVertexType* VertexBuffer;
private:
TSkinnedSkeletalMesh(const TSkinnedSkeletalMesh&);
int32 NumTris;
int32 NumVerts;
int32 TexCoordNum;
};
typedef TSkinnedSkeletalMesh<SkeletalSimplifier::MeshVertType> FSkinnedSkeletalMesh;
}