mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-22 10:16:01 +08:00
179 lines
4.0 KiB
C++
179 lines
4.0 KiB
C++
// Copyright 2016 Chris Conway (Koderz). All Rights Reserved.
|
|
|
|
#pragma once
|
|
#include "RuntimeMeshBuilder.h"
|
|
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
class TessellationUtilities
|
|
{
|
|
public:
|
|
static void CalculateTessellationIndices(const IRuntimeMeshVerticesBuilder* Vertices, const FRuntimeMeshIndicesBuilder* Indices, FRuntimeMeshIndicesBuilder* TessellationIndices);
|
|
|
|
|
|
|
|
|
|
private:
|
|
struct Vertex
|
|
{
|
|
FVector Position;
|
|
FVector2D TexCoord;
|
|
|
|
Vertex() { }
|
|
Vertex(const FVector& InPosition, const FVector2D& InTexCoord)
|
|
: Position(InPosition), TexCoord(InTexCoord)
|
|
{ }
|
|
|
|
FORCEINLINE bool operator==(const Vertex& Other) const
|
|
{
|
|
return Position == Other.Position;
|
|
}
|
|
FORCEINLINE bool operator<(const Vertex& Other) const
|
|
{
|
|
return Position.X < Other.Position.X
|
|
|| Position.Y < Other.Position.Y
|
|
|| Position.Z < Other.Position.Z;
|
|
}
|
|
};
|
|
|
|
static FORCEINLINE uint32 HashValue(const FVector& Vec)
|
|
{
|
|
return 31337 * GetTypeHash(Vec.X) + 13 * GetTypeHash(Vec.Y) + 3 * GetTypeHash(Vec.Z);
|
|
}
|
|
|
|
static FORCEINLINE uint32 HashValue(const Vertex& Vert)
|
|
{
|
|
return HashValue(Vert.Position);
|
|
}
|
|
|
|
struct Edge
|
|
{
|
|
private:
|
|
uint32 IndexFrom;
|
|
uint32 IndexTo;
|
|
|
|
Vertex VertexFrom;
|
|
Vertex VertexTo;
|
|
|
|
uint32 CachedHash;
|
|
|
|
public:
|
|
Edge() : CachedHash(0) { }
|
|
Edge(uint32 InIndexFrom, uint32 InIndexTo, const Vertex& InVertexFrom, const Vertex& InVertexTo)
|
|
: IndexFrom(InIndexFrom), IndexTo(InIndexTo), VertexFrom(InVertexFrom), VertexTo(InVertexTo)
|
|
{
|
|
// Hash should only consider position, not index.
|
|
// We want values with different indices to compare true.
|
|
CachedHash = 7 * HashValue(VertexFrom) + 2 * HashValue(VertexTo);
|
|
}
|
|
|
|
Vertex GetVertex(uint32 I) const
|
|
{
|
|
switch (I)
|
|
{
|
|
case 0:
|
|
return VertexFrom;
|
|
case 1:
|
|
return VertexTo;
|
|
default:
|
|
checkNoEntry();
|
|
return Vertex();
|
|
}
|
|
}
|
|
|
|
uint32 GetIndex(uint32 I) const
|
|
{
|
|
switch (I)
|
|
{
|
|
case 0:
|
|
return IndexFrom;
|
|
case 1:
|
|
return IndexTo;
|
|
default:
|
|
checkNoEntry();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Edge GetReverse() const
|
|
{
|
|
return Edge(IndexTo, IndexFrom, VertexTo, VertexFrom);
|
|
}
|
|
|
|
FORCEINLINE bool operator<(const Edge& Other) const
|
|
{
|
|
// Quick out, otherwise we have to compare vertices
|
|
if (IndexFrom == Other.IndexFrom && IndexTo == Other.IndexTo)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return VertexFrom < Other.VertexFrom || VertexTo < Other.VertexTo;
|
|
}
|
|
|
|
FORCEINLINE bool operator==(const Edge& Other) const
|
|
{
|
|
return (IndexFrom == Other.IndexFrom && IndexTo == Other.IndexTo) ||
|
|
(VertexFrom == Other.VertexFrom && VertexTo == Other.VertexTo);
|
|
}
|
|
|
|
friend FORCEINLINE uint32 GetTypeHash(const Edge& E)
|
|
{
|
|
return E.CachedHash;
|
|
}
|
|
};
|
|
|
|
struct Corner
|
|
{
|
|
uint32 Index;
|
|
FVector2D TexCoord;
|
|
|
|
Corner() : Index(0) { }
|
|
Corner(uint32 InIndex, FVector2D InTexCoord)
|
|
: Index(InIndex), TexCoord(InTexCoord)
|
|
{ }
|
|
};
|
|
|
|
class Triangle
|
|
{
|
|
Edge Edge0;
|
|
Edge Edge1;
|
|
Edge Edge2;
|
|
|
|
public:
|
|
Triangle(uint32 Index0, uint32 Index1, uint32 Index2, const Vertex& Vertex0, const Vertex& Vertex1, const Vertex& Vertex2)
|
|
: Edge0(Index0, Index1, Vertex0, Vertex1)
|
|
, Edge1(Index1, Index2, Vertex1, Vertex2)
|
|
, Edge2(Index2, Index0, Vertex2, Vertex0)
|
|
{ }
|
|
|
|
FORCEINLINE bool operator<(const Triangle& Other) const
|
|
{
|
|
return Edge0 < Other.Edge0 || Edge1 < Other.Edge1 || Edge2 < Other.Edge2;
|
|
}
|
|
|
|
FORCEINLINE const Edge& GetEdge(uint32 I)
|
|
{
|
|
return ((Edge*)&Edge0)[I];
|
|
}
|
|
FORCEINLINE uint32 GetIndex(uint32 I)
|
|
{
|
|
return GetEdge(I).GetIndex(0);
|
|
}
|
|
|
|
};
|
|
using EdgeDictionary = TMap<Edge, Edge>;
|
|
using PositionDictionary = TMap<FVector, Corner>;
|
|
|
|
static void AddIfLeastUV(PositionDictionary& PosDict, const Vertex& Vert, uint32 Index);
|
|
|
|
static void ReplacePlaceholderIndices(const IRuntimeMeshVerticesBuilder* Vertices, const FRuntimeMeshIndicesBuilder* Indices,
|
|
EdgeDictionary& EdgeDict, PositionDictionary& PosDict, FRuntimeMeshIndicesBuilder* OutIndices);
|
|
|
|
static void ExpandIB(const IRuntimeMeshVerticesBuilder* Vertices, const FRuntimeMeshIndicesBuilder* Indices,
|
|
EdgeDictionary& OutEdgeDict, PositionDictionary& OutPosDict, FRuntimeMeshIndicesBuilder* OutIndices);
|
|
};
|