// Copyright 2016 Chris Conway (Koderz). All Rights Reserved. #pragma once #include "RuntimeMeshCore.h" #include "RuntimeMeshGenericVertex.h" ////////////////////////////////////////////////////////////////////////// // This is a work in progress, it's functional, but could use some improvement ////////////////////////////////////////////////////////////////////////// enum class ERuntimeMeshVerticesBuilderType : uint8 { Component, Packed }; class IRuntimeMeshVerticesBuilder { public: IRuntimeMeshVerticesBuilder() { } IRuntimeMeshVerticesBuilder(const IRuntimeMeshVerticesBuilder& Other) = delete; IRuntimeMeshVerticesBuilder& operator=(const IRuntimeMeshVerticesBuilder& Other) = delete; virtual ~IRuntimeMeshVerticesBuilder() { } virtual ERuntimeMeshVerticesBuilderType GetBuilderType() const = 0; virtual const FRuntimeMeshVertexTypeInfo* GetVertexType() const = 0; virtual bool HasPositionComponent() const = 0; virtual bool HasNormalComponent() const = 0; virtual bool HasTangentComponent() const = 0; virtual bool HasColorComponent() const = 0; virtual bool HasUVComponent(int32 Index) const = 0; virtual bool HasHighPrecisionNormals() const = 0; virtual bool HasHighPrecisionUVs() const = 0; virtual void SetPosition(const FVector& InPosition) = 0; virtual void SetNormal(const FVector4& InNormal) = 0; virtual void SetTangent(const FVector& InTangent) = 0; virtual void SetColor(const FColor& InColor) = 0; virtual void SetUV(int32 Index, const FVector2D& InUV) = 0; virtual void SetPosition(int32 VertexIndex, const FVector& InPosition) = 0; virtual void SetNormal(int32 VertexIndex, const FVector4& InNormal) = 0; virtual void SetTangent(int32 VertexIndex, const FVector& InTangent) = 0; virtual void SetColor(int32 VertexIndex, const FColor& InColor) = 0; virtual void SetUV(int32 VertexIndex, int32 Index, const FVector2D& InUV) = 0; void SetTangents(const FVector& InTangentX, const FVector& InTangentY, const FVector& InTangentZ) { SetNormal(FVector4(InTangentZ, GetBasisDeterminantSign(InTangentX, InTangentY, InTangentZ))); SetTangent(InTangentX); } void SetTangents(int32 VertexIndex, const FVector& InTangentX, const FVector& InTangentY, const FVector& InTangentZ) { Seek(VertexIndex); SetNormal(FVector4(InTangentZ, GetBasisDeterminantSign(InTangentX, InTangentY, InTangentZ))); SetTangent(InTangentX); } virtual FVector GetPosition() const = 0; virtual FVector4 GetNormal() const = 0; virtual FVector GetTangent() const = 0; virtual FColor GetColor() const = 0; virtual FVector2D GetUV(int32 Index) const = 0; virtual FVector GetPosition(int32 VertexIndex) const = 0; virtual FVector4 GetNormal(int32 VertexIndex) const = 0; virtual FVector GetTangent(int32 VertexIndex) const = 0; virtual FColor GetColor(int32 VertexIndex) const = 0; virtual FVector2D GetUV(int32 VertexIndex, int32 Index) const = 0; virtual int32 Length() const = 0; virtual void Seek(int32 Position) const = 0; void SeekEnd() const { Seek(Length() - 1); } virtual int32 MoveNext() const = 0; virtual int32 MoveNextOrAdd() = 0; virtual void Reset() = 0; virtual IRuntimeMeshVerticesBuilder* Clone(bool bIncludeData = true) const = 0; virtual bool WantsSeparatePositionBuffer() const { return false; } }; template class FRuntimeMeshPackedVerticesBuilder : public IRuntimeMeshVerticesBuilder { private: TArray* Vertices; TArray* Positions; int32 CurrentPosition; bool bOwnsVertexArray; public: FRuntimeMeshPackedVerticesBuilder(bool bWantsSeparatePositions = false) : Vertices(new TArray()) , Positions(bWantsSeparatePositions? new TArray() : nullptr) , CurrentPosition(-1) , bOwnsVertexArray(true) { } FRuntimeMeshPackedVerticesBuilder(TArray* InVertices, TArray* InPositions = nullptr) : Vertices(InVertices) , Positions(InPositions) , CurrentPosition(-1) , bOwnsVertexArray(false) { } FRuntimeMeshPackedVerticesBuilder(const FRuntimeMeshPackedVerticesBuilder& Other) = delete; FRuntimeMeshPackedVerticesBuilder& operator=(const FRuntimeMeshPackedVerticesBuilder& Other) = delete; virtual ~FRuntimeMeshPackedVerticesBuilder() override { if (bOwnsVertexArray) { delete Vertices; if (Positions) { delete Positions; } } } virtual ERuntimeMeshVerticesBuilderType GetBuilderType() const { return ERuntimeMeshVerticesBuilderType::Packed; } virtual const FRuntimeMeshVertexTypeInfo* GetVertexType() const { return &VertexType::TypeInfo; } virtual bool HasPositionComponent() const override { return Positions != nullptr || FRuntimeMeshVertexTraits::HasPosition; } virtual bool HasNormalComponent() const override { return FRuntimeMeshVertexTraits::HasNormal; } virtual bool HasTangentComponent() const override { return FRuntimeMeshVertexTraits::HasTangent; } virtual bool HasColorComponent() const override { return FRuntimeMeshVertexTraits::HasColor; } virtual bool HasUVComponent(int32 Index) const override { switch (Index) { case 0: return FRuntimeMeshVertexTraits::HasUV0; case 1: return FRuntimeMeshVertexTraits::HasUV1; case 2: return FRuntimeMeshVertexTraits::HasUV2; case 3: return FRuntimeMeshVertexTraits::HasUV3; case 4: return FRuntimeMeshVertexTraits::HasUV4; case 5: return FRuntimeMeshVertexTraits::HasUV5; case 6: return FRuntimeMeshVertexTraits::HasUV6; case 7: return FRuntimeMeshVertexTraits::HasUV7; } return false; } virtual bool HasHighPrecisionNormals() const override { return FRuntimeMeshVertexTraits::HasHighPrecisionNormals; } virtual bool HasHighPrecisionUVs() const override { return FRuntimeMeshVertexTraits::HasHighPrecisionUVs; } virtual void SetPosition(const FVector& InPosition) override { if (Positions) { (*Positions)[CurrentPosition] = InPosition; } else { SetPositionInternal((*Vertices)[CurrentPosition], InPosition); } } virtual void SetNormal(const FVector4& InNormal) override { SetNormalInternal((*Vertices)[CurrentPosition], InNormal); } virtual void SetTangent(const FVector& InTangent) override { SetTangentInternal((*Vertices)[CurrentPosition], InTangent); } virtual void SetColor(const FColor& InColor) override { SetColorInternal((*Vertices)[CurrentPosition], InColor); } virtual void SetUV(int32 Index, const FVector2D& InUV) { switch (Index) { case 0: SetUV0Internal((*Vertices)[CurrentPosition], InUV); return; case 1: SetUV1Internal((*Vertices)[CurrentPosition], InUV); return; case 2: SetUV2Internal((*Vertices)[CurrentPosition], InUV); return; case 3: SetUV3Internal((*Vertices)[CurrentPosition], InUV); return; case 4: SetUV4Internal((*Vertices)[CurrentPosition], InUV); return; case 5: SetUV5Internal((*Vertices)[CurrentPosition], InUV); return; case 6: SetUV6Internal((*Vertices)[CurrentPosition], InUV); return; case 7: SetUV7Internal((*Vertices)[CurrentPosition], InUV); return; } } virtual void SetPosition(int32 VertexIndex, const FVector& InPosition) override { Seek(VertexIndex); if (Positions) { (*Positions)[CurrentPosition] = InPosition; } else { SetPositionInternal((*Vertices)[CurrentPosition], InPosition); } } virtual void SetNormal(int32 VertexIndex, const FVector4& InNormal) override { Seek(VertexIndex); SetNormalInternal((*Vertices)[CurrentPosition], InNormal); } virtual void SetTangent(int32 VertexIndex, const FVector& InTangent) override { Seek(VertexIndex); SetTangentInternal((*Vertices)[CurrentPosition], InTangent); } virtual void SetColor(int32 VertexIndex, const FColor& InColor) override { Seek(VertexIndex); SetColorInternal((*Vertices)[CurrentPosition], InColor); } virtual void SetUV(int32 VertexIndex, int32 Index, const FVector2D& InUV) { Seek(VertexIndex); switch (Index) { case 0: SetUV0Internal((*Vertices)[CurrentPosition], InUV); return; case 1: SetUV1Internal((*Vertices)[CurrentPosition], InUV); return; case 2: SetUV2Internal((*Vertices)[CurrentPosition], InUV); return; case 3: SetUV3Internal((*Vertices)[CurrentPosition], InUV); return; case 4: SetUV4Internal((*Vertices)[CurrentPosition], InUV); return; case 5: SetUV5Internal((*Vertices)[CurrentPosition], InUV); return; case 6: SetUV6Internal((*Vertices)[CurrentPosition], InUV); return; case 7: SetUV7Internal((*Vertices)[CurrentPosition], InUV); return; } } virtual FVector GetPosition() const override { if (Positions) { return (*Positions)[CurrentPosition]; } else { return GetPositionInternal((*Vertices)[CurrentPosition]); } } virtual FVector4 GetNormal() const override { return GetNormalInternal((*Vertices)[CurrentPosition]); } virtual FVector GetTangent() const override { return GetTangentInternal((*Vertices)[CurrentPosition]); } virtual FColor GetColor() const override { return GetColorInternal((*Vertices)[CurrentPosition]); } virtual FVector2D GetUV(int32 Index) const override { switch (Index) { case 0: return GetUV0Internal((*Vertices)[CurrentPosition]); case 1: return GetUV1Internal((*Vertices)[CurrentPosition]); case 2: return GetUV2Internal((*Vertices)[CurrentPosition]); case 3: return GetUV3Internal((*Vertices)[CurrentPosition]); case 4: return GetUV4Internal((*Vertices)[CurrentPosition]); case 5: return GetUV5Internal((*Vertices)[CurrentPosition]); case 6: return GetUV6Internal((*Vertices)[CurrentPosition]); case 7: return GetUV7Internal((*Vertices)[CurrentPosition]); } return FVector2D::ZeroVector; } virtual FVector GetPosition(int32 VertexIndex) const override { Seek(VertexIndex); if (Positions) { return (*Positions)[CurrentPosition]; } else { return GetPositionInternal((*Vertices)[CurrentPosition]); } } virtual FVector4 GetNormal(int32 VertexIndex) const override { Seek(VertexIndex); return GetNormalInternal((*Vertices)[CurrentPosition]); } virtual FVector GetTangent(int32 VertexIndex) const override { Seek(VertexIndex); return GetTangentInternal((*Vertices)[CurrentPosition]); } virtual FColor GetColor(int32 VertexIndex) const override { Seek(VertexIndex); return GetColorInternal((*Vertices)[CurrentPosition]); } virtual FVector2D GetUV(int32 VertexIndex, int32 Index) const override { Seek(VertexIndex); switch (Index) { case 0: return GetUV0Internal((*Vertices)[CurrentPosition]); case 1: return GetUV1Internal((*Vertices)[CurrentPosition]); case 2: return GetUV2Internal((*Vertices)[CurrentPosition]); case 3: return GetUV3Internal((*Vertices)[CurrentPosition]); case 4: return GetUV4Internal((*Vertices)[CurrentPosition]); case 5: return GetUV5Internal((*Vertices)[CurrentPosition]); case 6: return GetUV6Internal((*Vertices)[CurrentPosition]); case 7: return GetUV7Internal((*Vertices)[CurrentPosition]); } return FVector2D::ZeroVector; } virtual int32 Length() const override { return Vertices->Num(); } virtual void Seek(int32 Position) const override { const_cast*>(this)->CurrentPosition = Position; } virtual int32 MoveNext() const override { return ++const_cast*>(this)->CurrentPosition; } virtual int32 MoveNextOrAdd() override { CurrentPosition++; if (CurrentPosition >= Vertices->Num()) { Vertices->SetNumZeroed(CurrentPosition + 1, false); if (Positions) { Positions->SetNumZeroed(CurrentPosition + 1, false); } } return CurrentPosition; } virtual void Reset() override { Vertices->Reset(); if (Positions) { Positions->Reset(); } CurrentPosition = -1; } virtual IRuntimeMeshVerticesBuilder* Clone(bool bIncludeData = true) const override { FRuntimeMeshPackedVerticesBuilder* NewBuilder = new FRuntimeMeshPackedVerticesBuilder(Positions != nullptr); if (bIncludeData) { *NewBuilder->Vertices = *Vertices; *NewBuilder->Positions = *Positions; NewBuilder->Seek(0); } return NewBuilder; } TArray* GetVertices() { return Vertices; } TArray* GetPositions() { return Positions; } virtual bool WantsSeparatePositionBuffer() const { return Positions != nullptr; } private: template FORCEINLINE static typename TEnableIf::HasPosition>::Type SetPositionInternal(Type& Vertex, const FVector& Position) { Vertex.Position = Position; } template FORCEINLINE static typename TEnableIf::HasPosition>::Type SetPositionInternal(Type& Vertex, const FVector& Position) { } template FORCEINLINE static typename TEnableIf::HasPosition, FVector>::Type GetPositionInternal(const Type& Vertex) { return Vertex.Position; } template FORCEINLINE static typename TEnableIf::HasPosition, FVector>::Type GetPositionInternal(const Type& Vertex) { return FVector::ZeroVector; } template FORCEINLINE static typename TEnableIf::HasNormal>::Type SetNormalInternal(Type& Vertex, const FVector4& Normal) { Vertex.Normal = Normal; } template FORCEINLINE static typename TEnableIf::HasNormal>::Type SetNormalInternal(Type& Vertex, const FVector4& Normal) { } template FORCEINLINE static typename TEnableIf::HasNormal, FVector4>::Type GetNormalInternal(const Type& Vertex) { return Vertex.Normal; } template FORCEINLINE static typename TEnableIf::HasNormal, FVector4>::Type GetNormalInternal(const Type& Vertex) { return FVector::ZeroVector; } template FORCEINLINE static typename TEnableIf::HasTangent>::Type SetTangentInternal(Type& Vertex, const FVector4& Tangent) { Vertex.Tangent = Tangent; } template FORCEINLINE static typename TEnableIf::HasTangent>::Type SetTangentInternal(Type& Vertex, const FVector4& Tangent) { } template FORCEINLINE static typename TEnableIf::HasTangent, FVector4>::Type GetTangentInternal(const Type& Vertex) { return Vertex.Tangent; } template FORCEINLINE static typename TEnableIf::HasTangent, FVector4>::Type GetTangentInternal(const Type& Vertex) { return FVector::ZeroVector; } template FORCEINLINE static typename TEnableIf::HasColor>::Type SetColorInternal(Type& Vertex, const FColor& Color) { Vertex.Color = Color; } template FORCEINLINE static typename TEnableIf::HasColor>::Type SetColorInternal(Type& Vertex, const FColor& Color) { } template FORCEINLINE static typename TEnableIf::HasColor, FColor>::Type GetColorInternal(const Type& Vertex) { return Vertex.Color; } template FORCEINLINE static typename TEnableIf::HasColor, FColor>::Type GetColorInternal(const Type& Vertex) { return FColor::Transparent; } #define CreateUVChannelGetSetPair(Index) \ template \ FORCEINLINE static typename TEnableIf::HasUV##Index>::Type SetUV##Index##Internal(Type& Vertex, const FVector2D& UV##Index) \ { \ Vertex.UV##Index = UV##Index; \ } \ template \ FORCEINLINE static typename TEnableIf::HasUV##Index>::Type SetUV##Index##Internal(Type& Vertex, const FVector2D& UV##Index) \ { \ } \ template \ FORCEINLINE static typename TEnableIf::HasUV##Index, FVector2D>::Type GetUV##Index##Internal(const Type& Vertex) \ { \ return Vertex.UV##Index; \ } \ template \ FORCEINLINE static typename TEnableIf::HasUV##Index, FVector2D>::Type GetUV##Index##Internal(const Type& Vertex) \ { \ return FVector2D::ZeroVector; \ } CreateUVChannelGetSetPair(0); CreateUVChannelGetSetPair(1); CreateUVChannelGetSetPair(2); CreateUVChannelGetSetPair(3); CreateUVChannelGetSetPair(4); CreateUVChannelGetSetPair(5); CreateUVChannelGetSetPair(6); CreateUVChannelGetSetPair(7); #undef CreateUVChannelGetSetPair }; class RUNTIMEMESHCOMPONENT_API FRuntimeMeshComponentVerticesBuilder : public IRuntimeMeshVerticesBuilder { private: TArray* Positions; TArray* Normals; TArray* Tangents; TArray* Colors; TArray* UV0s; TArray* UV1s; int32 CurrentPosition; bool bOwnsBuffers; public: FRuntimeMeshComponentVerticesBuilder(bool bInWantsNormal, bool bInWantsTangent, bool bInWantsColor, bool bInWantsUV0, bool bInWantsUV1) : Positions(new TArray()) , Normals(bInWantsNormal ? new TArray() : nullptr) , Tangents(bInWantsTangent ? new TArray() : nullptr) , Colors(bInWantsColor ? new TArray() : nullptr) , UV0s(bInWantsUV0 ? new TArray() : nullptr) , UV1s(bInWantsUV1 ? new TArray() : nullptr) , CurrentPosition(-1) , bOwnsBuffers(true) { } FRuntimeMeshComponentVerticesBuilder(TArray* InPositions, TArray* InNormals, TArray* InTangents, TArray* InColors, TArray* InUV0s, TArray* InUV1s = nullptr) : Positions(InPositions) , Normals(InNormals) , Tangents(InTangents) , Colors(InColors) , UV0s(InUV0s) , UV1s(InUV1s) , CurrentPosition(-1) , bOwnsBuffers(false) { } FRuntimeMeshComponentVerticesBuilder(const FRuntimeMeshComponentVerticesBuilder& Other) = delete; FRuntimeMeshComponentVerticesBuilder& operator=(const FRuntimeMeshComponentVerticesBuilder& Other) = delete; virtual ~FRuntimeMeshComponentVerticesBuilder() override { if (bOwnsBuffers) { if (Positions) delete Positions; if (Normals) delete Normals; if (Tangents) delete Tangents; if (Colors) delete Colors; if (UV0s) delete UV0s; if (UV1s) delete UV1s; } } virtual ERuntimeMeshVerticesBuilderType GetBuilderType() const { return ERuntimeMeshVerticesBuilderType::Packed; } virtual const FRuntimeMeshVertexTypeInfo* GetVertexType() const; virtual bool HasPositionComponent() const override { return Positions != nullptr; } virtual bool HasNormalComponent() const override { return Normals != nullptr; } virtual bool HasTangentComponent() const override { return Tangents != nullptr; } virtual bool HasColorComponent() const override { return Colors != nullptr; } virtual bool HasUVComponent(int32 Index) const override { switch (Index) { case 0: return UV0s != nullptr; case 1: return UV1s != nullptr; default: return false; } } virtual bool HasHighPrecisionNormals() const override { return false; } virtual bool HasHighPrecisionUVs() const override { return true; } virtual void SetPosition(const FVector& InPosition) override { if (CurrentPosition >= Positions->Num()) { Positions->SetNumZeroed(CurrentPosition + 1, false); } (*Positions)[CurrentPosition] = InPosition; } virtual void SetNormal(const FVector4& InNormal) override { if (Normals) { if (CurrentPosition >= Normals->Num()) { Normals->SetNumZeroed(CurrentPosition + 1, false); } (*Normals)[CurrentPosition] = InNormal; (*Tangents)[CurrentPosition].bFlipTangentY = InNormal.W < 0.0f; } } virtual void SetTangent(const FVector& InTangent) override { if (Tangents) { if (CurrentPosition >= Tangents->Num()) { Tangents->SetNumZeroed(CurrentPosition + 1, false); } (*Tangents)[CurrentPosition].TangentX = InTangent; } } virtual void SetColor(const FColor& InColor) override { if (Colors) { if (CurrentPosition >= Colors->Num()) { Colors->SetNumZeroed(CurrentPosition + 1, false); } (*Colors)[CurrentPosition] = InColor; } } virtual void SetUV(int32 Index, const FVector2D& InUV) { switch (Index) { case 0: { if (UV0s) { if (CurrentPosition >= UV0s->Num()) { UV0s->SetNumZeroed(CurrentPosition + 1, false); } (*UV0s)[CurrentPosition] = InUV; } } case 1: { if (UV1s) { if (CurrentPosition >= UV1s->Num()) { UV1s->SetNumZeroed(CurrentPosition + 1, false); } (*UV1s)[CurrentPosition] = InUV; } } default: return; } } virtual void SetPosition(int32 VertexIndex, const FVector& InPosition) override { Seek(VertexIndex); if (CurrentPosition >= Positions->Num()) { Positions->SetNumZeroed(CurrentPosition + 1, false); } (*Positions)[CurrentPosition] = InPosition; } virtual void SetNormal(int32 VertexIndex, const FVector4& InNormal) override { Seek(VertexIndex); if (Normals) { if (CurrentPosition >= Normals->Num()) { Normals->SetNumZeroed(CurrentPosition + 1, false); } (*Normals)[CurrentPosition] = InNormal; (*Tangents)[CurrentPosition].bFlipTangentY = InNormal.W < 0.0f; } } virtual void SetTangent(int32 VertexIndex, const FVector& InTangent) override { Seek(VertexIndex); if (Tangents) { if (CurrentPosition >= Tangents->Num()) { Tangents->SetNumZeroed(CurrentPosition + 1, false); } (*Tangents)[CurrentPosition].TangentX = InTangent; } } virtual void SetColor(int32 VertexIndex, const FColor& InColor) override { Seek(VertexIndex); if (Colors) { if (CurrentPosition >= Colors->Num()) { Colors->SetNumZeroed(CurrentPosition + 1, false); } (*Colors)[CurrentPosition] = InColor; } } virtual void SetUV(int32 VertexIndex, int32 Index, const FVector2D& InUV) { Seek(VertexIndex); switch (Index) { case 0: { if (UV0s) { if (CurrentPosition >= UV0s->Num()) { UV0s->SetNumZeroed(CurrentPosition + 1, false); } (*UV0s)[CurrentPosition] = InUV; } } case 1: { if (UV1s) { if (CurrentPosition >= UV1s->Num()) { UV1s->SetNumZeroed(CurrentPosition + 1, false); } (*UV1s)[CurrentPosition] = InUV; } } default: return; } } virtual FVector GetPosition() const override { check(Positions && Positions->Num() > CurrentPosition); return (*Positions)[CurrentPosition]; } virtual FVector4 GetNormal() const override { check(Normals && Normals->Num() > CurrentPosition); float W = (Tangents && Tangents->Num() > CurrentPosition) ? ((*Tangents)[CurrentPosition].bFlipTangentY ? -1.0f : 1.0f) : 1.0f; return FVector4((*Normals)[CurrentPosition], W); } virtual FVector GetTangent() const override { check(Tangents && Tangents->Num() > CurrentPosition); return (*Tangents)[CurrentPosition].TangentX; } virtual FColor GetColor() const override { check(Colors && Colors->Num() > CurrentPosition); return (*Colors)[CurrentPosition]; } virtual FVector2D GetUV(int32 Index) const override { switch (Index) { case 0: check(UV0s && UV0s->Num() > CurrentPosition); return (*UV0s)[CurrentPosition]; case 1: check(UV1s && UV1s->Num() > CurrentPosition); return (*UV1s)[CurrentPosition]; } return FVector2D::ZeroVector; } virtual FVector GetPosition(int32 VertexIndex) const override { Seek(VertexIndex); check(Positions && Positions->Num() > CurrentPosition); return (*Positions)[CurrentPosition]; } virtual FVector4 GetNormal(int32 VertexIndex) const override { Seek(VertexIndex); check(Normals && Normals->Num() > CurrentPosition); float W = (Tangents && Tangents->Num() > CurrentPosition) ? ((*Tangents)[CurrentPosition].bFlipTangentY ? -1.0f : 1.0f) : 1.0f; return FVector4((*Normals)[CurrentPosition], W); } virtual FVector GetTangent(int32 VertexIndex) const override { Seek(VertexIndex); check(Tangents && Tangents->Num() > CurrentPosition); return (*Tangents)[CurrentPosition].TangentX; } virtual FColor GetColor(int32 VertexIndex) const override { Seek(VertexIndex); check(Colors && Colors->Num() > CurrentPosition); return (*Colors)[CurrentPosition]; } virtual FVector2D GetUV(int32 VertexIndex, int32 Index) const override { Seek(VertexIndex); switch (Index) { case 0: check(UV0s && UV0s->Num() > CurrentPosition); return (*UV0s)[CurrentPosition]; case 1: check(UV1s && UV1s->Num() > CurrentPosition); return (*UV1s)[CurrentPosition]; } return FVector2D::ZeroVector; } virtual int32 Length() const override { return Positions->Num(); } virtual void Seek(int32 Position) const override { const_cast(this)->CurrentPosition = Position; } virtual int32 MoveNext() const override { return ++const_cast(this)->CurrentPosition; } virtual int32 MoveNextOrAdd() override { return ++CurrentPosition; } TArray* GetPositions() const { return Positions; } TArray* GetNormals() const { return Normals; } TArray* GetTangents() const { return Tangents; } TArray* GetColors() const { return Colors; } TArray* GetUV0s() const { return UV0s; } TArray* GetUV1s() const { return UV1s; } virtual void Reset() override { Positions->Reset(); Normals->Reset(); Tangents->Reset(); Colors->Reset(); UV0s->Reset(); UV1s->Reset(); CurrentPosition = -1; } virtual IRuntimeMeshVerticesBuilder* Clone(bool bIncludeData = true) const override { FRuntimeMeshComponentVerticesBuilder* NewBuilder = new FRuntimeMeshComponentVerticesBuilder(Normals != nullptr, Tangents != nullptr, Colors != nullptr, UV0s != nullptr, UV1s != nullptr); if (bIncludeData) { *NewBuilder->Positions = *Positions; *NewBuilder->Normals = *Normals; *NewBuilder->Tangents = *Tangents; *NewBuilder->Colors = *Colors; *NewBuilder->UV0s = *UV0s; *NewBuilder->UV1s = *UV1s; NewBuilder->Seek(0); } return NewBuilder; } }; class FRuntimeMeshIndicesBuilder { bool bOwnsIndexArray; TArray* Indices; int32 CurrentPosition; public: FRuntimeMeshIndicesBuilder() : bOwnsIndexArray(true), Indices(new TArray()), CurrentPosition(0) { } FRuntimeMeshIndicesBuilder(TArray* InVertices) : bOwnsIndexArray(false), Indices(InVertices), CurrentPosition(0) { } FRuntimeMeshIndicesBuilder(const FRuntimeMeshIndicesBuilder& Other) = delete; FRuntimeMeshIndicesBuilder& operator=(const FRuntimeMeshIndicesBuilder& Other) = delete; virtual ~FRuntimeMeshIndicesBuilder() { if (bOwnsIndexArray) { delete Indices; } } virtual ERuntimeMeshVerticesBuilderType GetBuilderType() const { return ERuntimeMeshVerticesBuilderType::Component; } void AddTriangle(int32 Index0, int32 Index1, int32 Index2) { if ((CurrentPosition + 3) >= Indices->Num()) { Indices->SetNum(CurrentPosition + 3); } (*Indices)[CurrentPosition++] = Index0; (*Indices)[CurrentPosition++] = Index1; (*Indices)[CurrentPosition++] = Index2; } void AddIndex(int32 Index) { if ((CurrentPosition + 1) >= Indices->Num()) { Indices->SetNum(CurrentPosition + 1); } (*Indices)[CurrentPosition++] = Index; } int32 ReadOne() const { return (*Indices)[const_cast(this)->CurrentPosition++]; } int32 GetIndex(int32 Position) const { const_cast(this)->CurrentPosition = Position; return (*Indices)[CurrentPosition]; } int32 TriangleLength() const { return Length() / 3; } int32 Length() const { return Indices->Num(); } bool HasRemaining() const { return CurrentPosition < Indices->Num(); } void Seek(int32 Position) const { const_cast(this)->CurrentPosition = Position; } void SeekEnd() const { Seek(Length()); } void Reset(int32 NewSize = 0) { Indices->Reset(NewSize); CurrentPosition = 0; } void SetNum(int32 NewSize) { Indices->SetNum(NewSize); } FRuntimeMeshIndicesBuilder* Clone(bool bIncludeData = true) const { FRuntimeMeshIndicesBuilder* NewBuilder = new FRuntimeMeshIndicesBuilder(); if (bIncludeData) { *NewBuilder->Indices = *Indices; } return NewBuilder; } TArray* GetIndices() { return Indices; } };