Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

958 lines
33 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CADData.h"
#include "CADSceneGraph.h"
#include "TUniqueTechSoftObj.h"
#include "TechSoftInterface.h"
#ifdef USE_TECHSOFT_SDK
namespace TechSoftInterfaceUtils
{
class FTechSoftTessellationExtractor
{
public:
FTechSoftTessellationExtractor(const A3DRiRepresentationItem* RepresentationItemPtr, const double InBodyUnit)
: BodyUnit(InBodyUnit)
, TextureUnit(InBodyUnit)
{
CADLibrary::TUniqueTSObj<A3DRiRepresentationItemData> RepresentationItemData(RepresentationItemPtr);
if (!RepresentationItemData.IsValid())
{
return;
}
A3DEEntityType Type;
A3DEntityGetType(RepresentationItemData->m_pTessBase, &Type);
if (Type != kA3DTypeTess3D)
{
return;
}
TessellationPtr = RepresentationItemData->m_pTessBase;
A3DEntityGetType(RepresentationItemPtr, &Type);
if (Type == kA3DTypeRiBrepModel)
{
CADLibrary::TUniqueTSObj<A3DRiBrepModelData> BRepModelData(RepresentationItemPtr);
if (BRepModelData.IsValid())
{
A3DBrepData = BRepModelData->m_pBrepData;
}
}
}
bool FillBodyMesh(CADLibrary::FBodyMesh& BodyMesh)
{
if (TessellationPtr == nullptr)
{
return false;
}
int32 VertexOffset = BodyMesh.VertexArray.Num();
FillVertexArray(BodyMesh.VertexArray);
if (BodyMesh.VertexArray.Num() == VertexOffset)
{
return false;
}
BodyFaces.Empty();
GetBRepFaces();
FillFaceArray(BodyMesh, VertexOffset);
return BodyMesh.Faces.Num() > 0 ? true : false;
}
private:
void FillVertexArray(TArray<FVector3f>& VertexArray)
{
using namespace CADLibrary;
CADLibrary::TUniqueTSObj<A3DTessBaseData> TessellationBaseData(TessellationPtr);
if (!TessellationBaseData.IsValid() || TessellationBaseData->m_uiCoordSize == 0)
{
return;
}
int32 VertexCount = TessellationBaseData->m_uiCoordSize / 3;
VertexArray.Reserve(VertexArray.Num() + VertexCount);
const double ScaleFactor = BodyUnit * FImportParameters::GUnitScale;
double* Coordinates = TessellationBaseData->m_pdCoords;
for (unsigned int Index = 0; Index < TessellationBaseData->m_uiCoordSize; ++Index)
{
Coordinates[Index] *= ScaleFactor;
}
for (unsigned int Index = 0; Index < TessellationBaseData->m_uiCoordSize; Index += 3)
{
VertexArray.Emplace(Coordinates[Index], Coordinates[Index + 1], Coordinates[Index + 2]);
}
}
// #ueent_techsoft: TODO: Make it more in line with the actual implementation of FillFaceArray
uint32 CountTriangles(const A3DTessFaceData& FaceTessData)
{
const int32 TessellationFaceDataWithTriangle = 0x2222;
const int32 TessellationFaceDataWithFan = 0x4444;
const int32 TessellationFaceDataWithStripe = 0x8888;
const int32 TessellationFaceDataWithOneNormal = 0xE0E0;
uint32 UsedEntitiesFlags = FaceTessData.m_usUsedEntitiesFlags;
uint32 TriangleCount = 0;
uint32 FaceSetIndex = 0;
if (UsedEntitiesFlags & TessellationFaceDataWithTriangle)
{
TriangleCount += FaceTessData.m_puiSizesTriangulated[FaceSetIndex];
FaceSetIndex++;
}
if (FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex)
{
if (UsedEntitiesFlags & TessellationFaceDataWithFan)
{
uint32 LastFanIndex = 1 + FaceSetIndex + FaceTessData.m_puiSizesTriangulated[FaceSetIndex];
FaceSetIndex++;
for (; FaceSetIndex < LastFanIndex; FaceSetIndex++)
{
uint32 FanSize = (FaceTessData.m_puiSizesTriangulated[FaceSetIndex] & kA3DTessFaceDataNormalMask);
TriangleCount += (FanSize - 2);
}
}
}
if (FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex)
{
FaceSetIndex++;
for (; FaceSetIndex < FaceTessData.m_uiSizesTriangulatedSize; FaceSetIndex++)
{
uint32 StripeSize = (FaceTessData.m_puiSizesTriangulated[FaceSetIndex] & kA3DTessFaceDataNormalMask);
TriangleCount += (StripeSize - 2);
}
}
return TriangleCount;
}
void FillFaceArray(CADLibrary::FBodyMesh& BodyMesh, int32 VertexOffset = 0)
{
using namespace CADLibrary;
TArray<FTessellationData>& Faces = BodyMesh.Faces;
CADLibrary::TUniqueTSObj<A3DTess3DData> A3DTessellationData(TessellationPtr);
if (!A3DTessellationData.IsValid() || A3DTessellationData->m_uiFaceTessSize == 0)
{
return;
}
TessellationNormals = A3DTessellationData->m_pdNormals;
TessellationTexCoords = A3DTessellationData->m_pdTextureCoords;
TriangulatedIndexes = A3DTessellationData->m_puiTriangulatedIndexes;
if (A3DTessellationData->m_uiFaceTessSize != BodyFaces.Num())
{
BodyFaces.Empty();
A3DBrepData = nullptr;
}
for (unsigned int Index = 0; Index < A3DTessellationData->m_uiFaceTessSize; ++Index)
{
const A3DTessFaceData& FaceTessData = A3DTessellationData->m_psFaceTessData[Index];
uint32 FaceSetIndex = 0;
bool bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
// don't create empty TessellationData
if (!bMustProcess)
{
continue;
}
FTessellationData& Tessellation = Faces.Emplace_GetRef();
// there is a bijection between A3DTess3DData->m_psFaceTessData and A3DTopoShellData->m_ppFaces
Tessellation.PatchId = Index;
Tessellation.MaterialUId = 0;
if (FaceTessData.m_uiStyleIndexesSize != 0)
{
// Store the StyleIndex on the MaterialName. It will be processed after tessellation
Tessellation.MaterialUId = FaceTessData.m_puiStyleIndexes[0];
}
// Pre-allocate memory for triangles' data
uint32 TriangleCount = CountTriangles(FaceTessData);
Tessellation.PositionIndices.Reserve(3 * TriangleCount);
Tessellation.VertexIndices.Reserve(3 * TriangleCount);
Tessellation.NormalArray.Reserve(3 * TriangleCount);
if (FaceTessData.m_uiTextureCoordIndexesSize > 0)
{
Tessellation.TexCoordArray.Reserve(3 * TriangleCount);
}
uint32 UsedEntitiesFlags = FaceTessData.m_usUsedEntitiesFlags;
uint32 LastTrianguleIndex = FaceTessData.m_uiStartTriangulated;
LastVertexIndex = 0;
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangle)
{
AddFaceTriangle(Tessellation, FaceTessData.m_puiSizesTriangulated[FaceSetIndex++], LastTrianguleIndex, LastVertexIndex);
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleOneNormal)
{
AddFaceTriangleWithUniqueNormal(Tessellation, FaceTessData.m_puiSizesTriangulated[FaceSetIndex++], LastTrianguleIndex, LastVertexIndex);
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleTextured)
{
AddFaceTriangleWithTexture(Tessellation, FaceTessData.m_puiSizesTriangulated[FaceSetIndex++], FaceTessData.m_uiTextureCoordIndexesSize, LastTrianguleIndex, LastVertexIndex);
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleOneNormalTextured)
{
AddFaceTriangleWithUniqueNormalAndTexture(Tessellation, FaceTessData.m_puiSizesTriangulated[FaceSetIndex++], FaceTessData.m_uiTextureCoordIndexesSize, LastTrianguleIndex, LastVertexIndex);
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleFan)
{
uint32 FanCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++];
for (uint32 FanIndex = 0; FanIndex < FanCount; ++FanIndex)
{
uint32 VertexCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++];
AddFaceTriangleFan(Tessellation, VertexCount, LastTrianguleIndex, LastVertexIndex);
}
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleFanOneNormal)
{
uint32 FanCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++] & kA3DTessFaceDataNormalMask;
for (uint32 FanIndex = 0; FanIndex < FanCount; ++FanIndex)
{
ensure((FaceTessData.m_puiSizesTriangulated[FaceSetIndex] & kA3DTessFaceDataNormalSingle) != 0);
uint32 VertexCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++] & kA3DTessFaceDataNormalMask;
AddFaceTriangleFanWithUniqueNormal(Tessellation, VertexCount, LastTrianguleIndex, LastVertexIndex);
}
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleFanTextured)
{
uint32 FanCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++];
for (uint32 FanIndex = 0; FanIndex < FanCount; ++FanIndex)
{
uint32 VertexCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++];
AddFaceTriangleFanWithTexture(Tessellation, VertexCount, FaceTessData.m_uiTextureCoordIndexesSize, LastTrianguleIndex, LastVertexIndex);
}
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleFanOneNormalTextured)
{
uint32 FanCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++] & kA3DTessFaceDataNormalMask;
for (uint32 FanIndex = 0; FanIndex < FanCount; ++FanIndex)
{
ensure((FaceTessData.m_puiSizesTriangulated[FaceSetIndex] & kA3DTessFaceDataNormalSingle) != 0);
uint32 VertexCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++] & kA3DTessFaceDataNormalMask;
AddFaceTriangleFanWithUniqueNormalAndTexture(Tessellation, VertexCount, FaceTessData.m_uiTextureCoordIndexesSize, LastTrianguleIndex, LastVertexIndex);
}
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleStripe)
{
A3DUns32 StripeSize = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++];
for (A3DUns32 StripeIndex = 0; StripeIndex < StripeSize; ++StripeIndex)
{
A3DUns32 PointCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++];
AddFaceTriangleStripe(Tessellation, PointCount, LastTrianguleIndex, LastVertexIndex);
}
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleStripeOneNormal)
{
A3DUns32 StripeSize = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++] & kA3DTessFaceDataNormalMask;
for (A3DUns32 StripeIndex = 0; StripeIndex < StripeSize; ++StripeIndex)
{
bool bIsOneNormal = (FaceTessData.m_puiSizesTriangulated[FaceSetIndex] & kA3DTessFaceDataNormalSingle) != 0;
A3DUns32 PointCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++] & kA3DTessFaceDataNormalMask;
// Is there only one normal for the entire stripe?
if (bIsOneNormal == false)
{
AddFaceTriangleStripe(Tessellation, PointCount, LastTrianguleIndex, LastVertexIndex);
continue;
}
AddFaceTriangleStripeWithUniqueNormal(Tessellation, PointCount, LastTrianguleIndex, LastVertexIndex);
}
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleStripeTextured)
{
A3DUns32 StripeSize = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++];
for (A3DUns32 StripeIndex = 0; StripeIndex < StripeSize; ++StripeIndex)
{
A3DUns32 PointCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++];
AddFaceTriangleStripeWithTexture(Tessellation, PointCount, FaceTessData.m_uiTextureCoordIndexesSize, LastTrianguleIndex, LastVertexIndex);
}
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (bMustProcess && UsedEntitiesFlags & kA3DTessFaceDataTriangleStripeOneNormalTextured)
{
A3DUns32 StripeSize = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++] & kA3DTessFaceDataNormalMask;
for (A3DUns32 StripeIndex = 0; StripeIndex < StripeSize; ++StripeIndex)
{
A3DUns32 PointCount = FaceTessData.m_puiSizesTriangulated[FaceSetIndex++] & kA3DTessFaceDataNormalMask;
AddFaceTriangleStripeWithUniqueNormalAndTexture(Tessellation, PointCount, FaceTessData.m_uiTextureCoordIndexesSize, LastTrianguleIndex, LastVertexIndex);
}
bMustProcess = FaceTessData.m_uiSizesTriangulatedSize > FaceSetIndex;
}
if (VertexOffset > 0)
{
for (int32& PositionIndex : Tessellation.PositionIndices)
{
PositionIndex += VertexOffset;
}
}
ensure(!bMustProcess);
if (!BodyFaces.IsEmpty())
{
const A3DTopoFace* TopoFace = BodyFaces[Index];
ScaleUV(TopoFace, Tessellation.TexCoordArray);
}
BodyMesh.TriangleCount += (Tessellation.VertexIndices.Num() / 3.);
}
}
typedef double A3DDouble;
bool AddFace(int32 FaceIndex[3], CADLibrary::FTessellationData& Tessellation, int32& InOutVertexIndex)
{
if (FaceIndex[0] == FaceIndex[1] || FaceIndex[0] == FaceIndex[2] || FaceIndex[1] == FaceIndex[2])
{
return false;
}
for (int32 Index = 0; Index < 3; ++Index)
{
Tessellation.VertexIndices.Add(InOutVertexIndex++);
}
Tessellation.PositionIndices.Append(FaceIndex, 3);
return true;
};
void AddNormals(const A3DDouble* Normals, const int32 Indices[3], TArray<FVector3f>& NormalsArray)
{
for (int32 Index = 0; Index < 3; ++Index)
{
int32 NormalIndex = Indices[Index];
NormalsArray.Emplace(Normals[NormalIndex], Normals[NormalIndex + 1], Normals[NormalIndex + 2]);
}
};
void AddTextureCoordinates(const A3DDouble* TextureCoords, const int32 Indices[3], TArray<FVector2f>& TessellationTextures)
{
for (int32 Index = 0; Index < 3; ++Index)
{
int32 TextureIndex = Indices[Index];
TessellationTextures.Emplace(TextureCoords[TextureIndex], TextureCoords[TextureIndex + 1]);
}
};
void AddFaceTriangle(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, uint32& InOutStartIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
// Get Triangles
for (uint32 TriangleIndex = 0; TriangleIndex < InTriangleCount; TriangleIndex++)
{
NormalIndex[0] = TriangulatedIndexes[InOutStartIndex++];
FaceIndex[0] = TriangulatedIndexes[InOutStartIndex++] / 3;
NormalIndex[1] = TriangulatedIndexes[InOutStartIndex++];
FaceIndex[1] = TriangulatedIndexes[InOutStartIndex++] / 3;
NormalIndex[2] = TriangulatedIndexes[InOutStartIndex++];
FaceIndex[2] = TriangulatedIndexes[InOutStartIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
}
}
void AddFaceTriangleWithUniqueNormal(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, uint32& InOutLastTriangleIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
// Get Triangles
for (uint32 TriangleIndex = 0; TriangleIndex < InTriangleCount; TriangleIndex++)
{
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
NormalIndex[1] = NormalIndex[0];
NormalIndex[2] = NormalIndex[0];
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (!AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
continue;
}
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
}
void AddFaceTriangleWithUniqueNormalAndTexture(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, const uint32 TextureCount, uint32& InOutStartIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
int32 TextureIndex[3] = { 0, 0, 0 };
// Get Triangles
for (uint32 TriangleIndex = 0; TriangleIndex < InTriangleCount; TriangleIndex++)
{
NormalIndex[0] = TriangulatedIndexes[InOutStartIndex++];
NormalIndex[1] = NormalIndex[0];
NormalIndex[2] = NormalIndex[0];
TextureIndex[0] = TriangulatedIndexes[InOutStartIndex];
InOutStartIndex += TextureCount;
FaceIndex[0] = TriangulatedIndexes[InOutStartIndex++] / 3;
TextureIndex[1] = TriangulatedIndexes[InOutStartIndex];
InOutStartIndex += TextureCount;
FaceIndex[1] = TriangulatedIndexes[InOutStartIndex++] / 3;
TextureIndex[2] = TriangulatedIndexes[InOutStartIndex];
InOutStartIndex += TextureCount;
FaceIndex[2] = TriangulatedIndexes[InOutStartIndex++] / 3;
if (!AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
continue;
}
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
AddTextureCoordinates(TessellationTexCoords, TextureIndex, Tessellation.TexCoordArray);
}
}
void AddFaceTriangleWithTexture(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, const uint32 InTextureCount, uint32& InOutStartIndex, int32& inOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
int32 TextureIndex[3] = { 0, 0, 0 };
// Get Triangles
for (uint64 TriangleIndex = 0; TriangleIndex < InTriangleCount; TriangleIndex++)
{
NormalIndex[0] = TriangulatedIndexes[InOutStartIndex++];
TextureIndex[0] = TriangulatedIndexes[InOutStartIndex];
InOutStartIndex += InTextureCount;
FaceIndex[0] = TriangulatedIndexes[InOutStartIndex++] / 3;
NormalIndex[1] = TriangulatedIndexes[InOutStartIndex++];
TextureIndex[1] = TriangulatedIndexes[InOutStartIndex];
InOutStartIndex += InTextureCount;
FaceIndex[1] = TriangulatedIndexes[InOutStartIndex++] / 3;
NormalIndex[2] = TriangulatedIndexes[InOutStartIndex++];
TextureIndex[2] = TriangulatedIndexes[InOutStartIndex];
InOutStartIndex += InTextureCount;
FaceIndex[2] = TriangulatedIndexes[InOutStartIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, inOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
AddTextureCoordinates(TessellationTexCoords, TextureIndex, Tessellation.TexCoordArray);
}
}
}
void AddFaceTriangleFan(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, uint32& InOutLastTriangleIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
NormalIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++];
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
for (unsigned long TriangleIndex = 2; TriangleIndex < InTriangleCount; TriangleIndex++)
{
NormalIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++];
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
NormalIndex[1] = NormalIndex[2];
FaceIndex[1] = FaceIndex[2];
}
}
void AddFaceTriangleFanWithUniqueNormal(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, uint32& InOutLastTriangleIndex, int32& /*LastVertexIndex*/)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
NormalIndex[1] = NormalIndex[0];
NormalIndex[2] = NormalIndex[0];
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
// Get Triangles
for (uint32 TriangleIndex = 2; TriangleIndex < InTriangleCount; TriangleIndex++)
{
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, LastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
FaceIndex[1] = FaceIndex[2];
}
}
void AddFaceTriangleFanWithUniqueNormalAndTexture(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, const uint32 TextureCount, uint32& InOutLastTriangleIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
int32 TextureIndex[3] = { 0, 0, 0 };
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
NormalIndex[1] = NormalIndex[0];
NormalIndex[2] = NormalIndex[0];
TextureIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
TextureIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
for (uint32 TriangleIndex = 2; TriangleIndex < InTriangleCount; TriangleIndex++)
{
TextureIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
AddTextureCoordinates(TessellationTexCoords, TextureIndex, Tessellation.TexCoordArray);
}
FaceIndex[1] = FaceIndex[2];
TextureIndex[1] = TextureIndex[2];
}
}
void AddFaceTriangleFanWithTexture(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, const uint32 TextureCount, uint32& InOutLastTriangleIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
int32 TextureIndex[3] = { 0, 0, 0 };
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
TextureIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
NormalIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++];
TextureIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
for (uint32 TriangleIndex = 2; TriangleIndex < InTriangleCount; TriangleIndex++)
{
NormalIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++];
TextureIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
AddTextureCoordinates(TessellationTexCoords, TextureIndex, Tessellation.TexCoordArray);
}
NormalIndex[1] = NormalIndex[2];
TextureIndex[1] = TextureIndex[2];
FaceIndex[1] = FaceIndex[2];
}
}
void AddFaceTriangleStripe(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, uint32& InOutLastTriangleIndex, int32& /*LastVertexIndex*/)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
NormalIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++];
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
for (unsigned long TriangleIndex = 2; TriangleIndex < InTriangleCount; TriangleIndex++)
{
NormalIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++];
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, LastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
TriangleIndex++;
if (TriangleIndex == InTriangleCount)
{
break;
}
Swap(FaceIndex[1], FaceIndex[2]);
Swap(NormalIndex[1], NormalIndex[2]);
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, LastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
Swap(FaceIndex[0], FaceIndex[1]);
Swap(NormalIndex[0], NormalIndex[1]);
}
}
void AddFaceTriangleStripeWithTexture(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, const uint32 TextureCount, uint32& InOutLastTriangleIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
int32 TextureIndex[3] = { 0, 0, 0 };
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
TextureIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
NormalIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++];
TextureIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
for (unsigned long TriangleIndex = 2; TriangleIndex < InTriangleCount; TriangleIndex++)
{
NormalIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++];
TextureIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
AddTextureCoordinates(TessellationTexCoords, TextureIndex, Tessellation.TexCoordArray);
}
TriangleIndex++;
if (TriangleIndex == InTriangleCount)
{
break;
}
Swap(FaceIndex[1], FaceIndex[2]);
Swap(NormalIndex[1], NormalIndex[2]);
Swap(TextureIndex[1], TextureIndex[2]);
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
Swap(FaceIndex[0], FaceIndex[1]);
Swap(NormalIndex[0], NormalIndex[1]);
Swap(TextureIndex[0], TextureIndex[1]);
}
}
void AddFaceTriangleStripeWithUniqueNormal(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, uint32& InOutLastTriangleIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
NormalIndex[1] = NormalIndex[0];
NormalIndex[2] = NormalIndex[0];
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
for (unsigned long TriangleIndex = 2; TriangleIndex < InTriangleCount; TriangleIndex++)
{
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
TriangleIndex++;
if (TriangleIndex == InTriangleCount)
{
break;
}
Swap(FaceIndex[1], FaceIndex[2]);
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
Swap(FaceIndex[0], FaceIndex[1]);
}
}
void AddFaceTriangleStripeWithUniqueNormalAndTexture(CADLibrary::FTessellationData& Tessellation, const uint32 InTriangleCount, const uint32 TextureCount, uint32& InOutLastTriangleIndex, int32& InOutLastVertexIndex)
{
int32 FaceIndex[3] = { 0, 0, 0 };
int32 NormalIndex[3] = { 0, 0, 0 };
int32 TextureIndex[3] = { 0, 0, 0 };
NormalIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++];
NormalIndex[1] = NormalIndex[0];
NormalIndex[2] = NormalIndex[0];
TextureIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
TextureIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[1] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
for (unsigned long TriangleIndex = 2; TriangleIndex < InTriangleCount; TriangleIndex++)
{
TextureIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[2] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
AddTextureCoordinates(TessellationTexCoords, TextureIndex, Tessellation.TexCoordArray);
}
TriangleIndex++;
if (TriangleIndex == InTriangleCount)
{
break;
}
Swap(FaceIndex[1], FaceIndex[2]);
Swap(TextureIndex[1], TextureIndex[2]);
TextureIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex];
InOutLastTriangleIndex += TextureCount;
FaceIndex[0] = TriangulatedIndexes[InOutLastTriangleIndex++] / 3;
if (AddFace(FaceIndex, Tessellation, InOutLastVertexIndex))
{
AddNormals(TessellationNormals, NormalIndex, Tessellation.NormalArray);
}
Swap(FaceIndex[0], FaceIndex[1]);
Swap(TextureIndex[0], TextureIndex[1]);
}
}
void ScaleUV(const A3DTopoFace* TopoFace, TArray<FVector2f>& TexCoordArray)
{
CADLibrary::TUniqueTSObj<A3DTopoFaceData> TopoFaceData(TopoFace);
if (!TopoFaceData.IsValid())
{
return;
}
CADLibrary::TUniqueTSObj<A3DDomainData> Domain;
if (TopoFaceData->m_bHasTrimDomain)
{
*Domain = TopoFaceData->m_sSurfaceDomain;
}
else
{
CADLibrary::TechSoftInterface::GetSurfaceDomain(TopoFaceData->m_pSurface, *Domain);
}
const int32 IsoCurveCount = 7;
const double DeltaU = (Domain->m_sMax.m_dX - Domain->m_sMin.m_dX) / (IsoCurveCount - 1.);
const double DeltaV = (Domain->m_sMax.m_dY - Domain->m_sMin.m_dY) / (IsoCurveCount - 1.);
const A3DSurfBase* A3DSurface = TopoFaceData->m_pSurface;
FVector NodeMatrix[IsoCurveCount * IsoCurveCount];
CADLibrary::TUniqueTSObj<A3DVector3dData> Point3D;
CADLibrary::TUniqueTSObj<A3DVector2dData> CoordinateObj;
A3DVector2dData& Coordinate = *CoordinateObj;
Coordinate.m_dX = Domain->m_sMin.m_dX;
Coordinate.m_dY = Domain->m_sMin.m_dY;
for (int32 IndexI = 0; IndexI < IsoCurveCount; IndexI++)
{
for (int32 IndexJ = 0; IndexJ < IsoCurveCount; IndexJ++)
{
CADLibrary::TechSoftInterface::Evaluate(A3DSurface, Coordinate, 0, Point3D.GetPtr());
NodeMatrix[IndexI * IsoCurveCount + IndexJ].X = Point3D->m_dX;
NodeMatrix[IndexI * IsoCurveCount + IndexJ].Y = Point3D->m_dY;
NodeMatrix[IndexI * IsoCurveCount + IndexJ].Z = Point3D->m_dZ;
Coordinate.m_dY += DeltaV;
}
Coordinate.m_dX += DeltaU;
Coordinate.m_dY = Domain->m_sMin.m_dY;
}
// Compute length of 7 iso V line
double LengthU[IsoCurveCount];
double LengthUMax = 0;
double LengthUMed = 0;
for (int32 IndexJ = 0; IndexJ < IsoCurveCount; IndexJ++)
{
LengthU[IndexJ] = 0;
for (int32 IndexI = 0; IndexI < (IsoCurveCount - 1); IndexI++)
{
LengthU[IndexJ] += FVector::Distance(NodeMatrix[IndexI * IsoCurveCount + IndexJ], NodeMatrix[(IndexI + 1) * IsoCurveCount + IndexJ]);
}
LengthUMed += LengthU[IndexJ];
LengthUMax = FMath::Max(LengthU[IndexJ], LengthUMax);
}
LengthUMed /= IsoCurveCount;
LengthUMed = LengthUMed * 2 / 3 + LengthUMax / 3;
// Compute length of 7 iso U line
double LengthV[IsoCurveCount];
double LengthVMax = 0;
double LengthVMed = 0;
for (int32 IndexI = 0; IndexI < IsoCurveCount; IndexI++)
{
LengthV[IndexI] = 0;
for (int32 IndexJ = 0; IndexJ < (IsoCurveCount - 1); IndexJ++)
{
LengthV[IndexI] += FVector::Distance(NodeMatrix[IndexI * IsoCurveCount + IndexJ], NodeMatrix[IndexI * IsoCurveCount + IndexJ + 1]);
}
LengthVMed += LengthV[IndexI];
LengthVMax = FMath::Max(LengthV[IndexI], LengthVMax);
}
LengthVMed /= IsoCurveCount;
LengthVMed = LengthVMed * 2 / 3 + LengthVMax / 3;
// Texture unit is meter, Coord unit from TechSoft is mm, so TextureScale = 0.001 to convert mm into m
const double TextureScale = 0.01;
const float UScale = TextureUnit * TextureScale * LengthUMed / (Domain->m_sMax.m_dX - Domain->m_sMin.m_dX);
const float VScale = TextureUnit * TextureScale * LengthVMed / (Domain->m_sMax.m_dY - Domain->m_sMin.m_dY);
for (FVector2f& TexCoord : TexCoordArray)
{
TexCoord[0] *= UScale;
TexCoord[1] *= VScale;
}
}
void GetBRepFaces()
{
if (A3DBrepData == nullptr)
{
return;
}
CADLibrary::TUniqueTSObj<A3DTopoBodyData> TopoBodyData(A3DBrepData);
if (TopoBodyData.IsValid())
{
if (TopoBodyData->m_pContext)
{
CADLibrary::TUniqueTSObj<A3DTopoContextData> TopoContextData(TopoBodyData->m_pContext);
if (TopoContextData.IsValid())
{
if (TopoContextData->m_bHaveScale)
{
TextureUnit *= TopoContextData->m_dScale;
}
}
}
}
CADLibrary::TUniqueTSObj<A3DTopoBrepDataData> TopoBrepData(A3DBrepData);
if (TopoBrepData.IsValid())
{
for (A3DUns32 Index = 0; Index < TopoBrepData->m_uiConnexSize; ++Index)
{
CADLibrary::TUniqueTSObj<A3DTopoConnexData> TopoConnexData(TopoBrepData->m_ppConnexes[Index]);
if (TopoConnexData.IsValid())
{
for (A3DUns32 Sndex = 0; Sndex < TopoConnexData->m_uiShellSize; ++Sndex)
{
CADLibrary::TUniqueTSObj<A3DTopoShellData> ShellData(TopoConnexData->m_ppShells[Sndex]);
if (ShellData.IsValid())
{
for (A3DUns32 Fndex = 0; Fndex < ShellData->m_uiFaceSize; ++Fndex)
{
const A3DTopoFace* A3DFace = ShellData->m_ppFaces[Fndex];
BodyFaces.Add(A3DFace);
}
}
}
}
}
}
}
private:
const A3DTess3D* TessellationPtr = nullptr;
const A3DTopoBrepData* A3DBrepData = nullptr;
const double BodyUnit = 1;
double TextureUnit = 1;
TArray<const A3DTopoFace*> BodyFaces;
int32 LastVertexIndex = 0;
A3DUns32* TriangulatedIndexes = nullptr;
A3DDouble* TessellationNormals;
A3DDouble* TessellationTexCoords; /*!< Array of \ref A3DDouble, as texture coordinates. */
};
} // ns TechSoftUtils
#endif