Skip to content
Snippets Groups Projects
Commit a4c4222e authored by David Gilbert's avatar David Gilbert :bug:
Browse files

Started working on better serialization aspects

parent e440deb9
No related branches found
No related tags found
No related merge requests found
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "GPUInstancedLineComponent.h" #include "GPUInstancedLineComponent.h"
#include "InstancedMeshLineRendering.h" // Only needed for logging #include "InstancedMeshLineRendering.h" // Only needed for logging
//#pragma optimize("", off) #pragma optimize("", off)
UGPUInstancedLineComponent::UGPUInstancedLineComponent(const FObjectInitializer& ObjectInitializer) UGPUInstancedLineComponent::UGPUInstancedLineComponent(const FObjectInitializer& ObjectInitializer)
...@@ -25,12 +25,19 @@ UGPUInstancedLineComponent::UGPUInstancedLineComponent(const FObjectInitializer& ...@@ -25,12 +25,19 @@ UGPUInstancedLineComponent::UGPUInstancedLineComponent(const FObjectInitializer&
SetStaticMesh(LineAsset); SetStaticMesh(LineAsset);
SetMaterial(0, LineMaterial); SetMaterial(0, LineMaterial);
UMaterialInterface* LineMaterialInterface = LoadObject<UMaterialInterface>(NULL, TEXT("/InstancedMeshLineRendering/DynamicLineMaterial.DynamicLineMaterial"), NULL, LOAD_None, NULL);
DynamicLineMaterial = UMaterialInstanceDynamic::Create(LineMaterialInterface, GetTransientPackage());
check(DynamicLineMaterial);
// three color values + width + 1 texture index value // three color values + width + 1 texture index value
// r | g | b | w | i_T // r | g | b | w | i_T
NumCustomDataFloats = 5; NumCustomDataFloats = 5;
CurrentTextureMarker = FIntPoint(0, 0); CurrentTextureMarker = FIntPoint(0, 0);
CurrentTextureIndex = 0, CurrentTextureIndex = 0,
NextFreeId = 0;
TextureWidth = 2048; TextureWidth = 2048;
TextureHeight = 2048; TextureHeight = 2048;
...@@ -83,36 +90,37 @@ void UGPUInstancedLineComponent::UpdateWholeTexture() ...@@ -83,36 +90,37 @@ void UGPUInstancedLineComponent::UpdateWholeTexture()
void UGPUInstancedLineComponent::Init() void UGPUInstancedLineComponent::Init()
{ {
if(PositionTexture != nullptr)
{
UE_LOG(LogLineRendering, Error, TEXT("UGPUInstancedLineComponent::Init PositionTexture already exists!"));
}
UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Creating Texture")); UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Creating Texture"));
PositionTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_A32B32G32R32F); PositionTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_A32B32G32R32F);
// Allocate the texture RHI // Allocate the texture RHI
PositionTexture->UpdateResource(); PositionTexture->UpdateResource();
UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Creating MID"));
DynamicLineMaterial = CreateAndSetMaterialInstanceDynamic(0);// UMaterialInstanceDynamic::Create(LineMat, this, "DynamicLineMaterialMID");
if (DynamicLineMaterial == nullptr) // FOR WHATEVER REASON I HAVE NO IDEA if (DynamicLineMaterial == nullptr) // FOR WHATEVER REASON I HAVE NO IDEA
{ {
DynamicLineMaterial = UMaterialInstanceDynamic::Create(GetStaticMesh()->GetMaterial(0), this);// UMaterialInstanceDynamic::Create(LineMat, this, "DynamicLineMaterialMID"); UE_LOG(LogLineRendering, Fatal, TEXT("UGPUInstancedLineComponent::Init MID was nullptr!"));
SetMaterial(0, DynamicLineMaterial);
} }
if(DynamicLineMaterial) else
{ {
UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Setting MID"));
SetMaterial(0, DynamicLineMaterial);
DynamicLineMaterial->SetTextureParameterValue("PositionTexture", PositionTexture); DynamicLineMaterial->SetTextureParameterValue("PositionTexture", PositionTexture);
DynamicLineMaterial->SetScalarParameterValue("TextureWidth", TextureWidth); DynamicLineMaterial->SetScalarParameterValue("TextureWidth", TextureWidth);
} }
else
UE_LOG(LogLineRendering, Error, TEXT("UGPUInstancedLineComponent::Init DynamicLineMaterial was nullptr"));
UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Resetting Data")); //UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Resetting Data"));
LineMap.Empty(); //LineMap.Empty();
LinearLineData.Empty(); //LinearLineData.Empty();
NextFreeId = 0; //NextFreeId = 0;
CurrentTextureIndex = 0; //CurrentTextureIndex = 0;
CurrentTextureMarker = FIntPoint(0, 0); //CurrentTextureMarker = FIntPoint(0, 0);
ClearInstances(); //ClearInstances();
RegisterSerializedEditorLines(); //RegisterSerializedEditorLines();
bIsInitialized = true; bIsInitialized = true;
...@@ -122,22 +130,27 @@ void UGPUInstancedLineComponent::Init() ...@@ -122,22 +130,27 @@ void UGPUInstancedLineComponent::Init()
// AddLineFromEditorData(EditorLine); // AddLineFromEditorData(EditorLine);
//} //}
} // Update the texture
void UGPUInstancedLineComponent::RegisterSerializedEditorLines()
{
// Here's to hoping the respective id field doesn't get serialized... // Theoretically we could serialize the texture as well, but that seems like too much work
UpdateWholeTexture();
for (FEditorLineData& EditorLine : EditorLines)
{
if(EditorLine.RespectiveLineId == -1)
{
AddLineFromEditorData(EditorLine);
}
}
} }
//void UGPUInstancedLineComponent::RegisterSerializedEditorLines()
//{
//
// // Here's to hoping the respective id field doesn't get serialized...
//
// for (FEditorLineData& EditorLine : EditorLines)
// {
// if(EditorLine.RespectiveLineId == -1 || !LineMap.Contains(EditorLine.RespectiveLineId))
// {
// AddLineFromEditorData(EditorLine);
// }
// }
//}
void UGPUInstancedLineComponent::UpdateAllEditorLines() void UGPUInstancedLineComponent::UpdateAllEditorLines()
{ {
for (const FEditorLineData& EditorLine : EditorLines) for (const FEditorLineData& EditorLine : EditorLines)
...@@ -224,7 +237,7 @@ void UGPUInstancedLineComponent::BeginPlay() ...@@ -224,7 +237,7 @@ void UGPUInstancedLineComponent::BeginPlay()
Super::BeginPlay(); Super::BeginPlay();
// todo don't think this is needed here // todo don't think this is needed here
RegisterSerializedEditorLines(); //RegisterSerializedEditorLines();
//Init(); //Init();
if(!bIsInitialized) if(!bIsInitialized)
...@@ -245,7 +258,7 @@ void UGPUInstancedLineComponent::PostInitProperties() ...@@ -245,7 +258,7 @@ void UGPUInstancedLineComponent::PostInitProperties()
#if WITH_EDITOR #if WITH_EDITOR
void UGPUInstancedLineComponent::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) void UGPUInstancedLineComponent::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
{ {
if (PropertyChangedEvent.Property != NULL) if (PropertyChangedEvent.Property != NULL && bIsInitialized)
{ {
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UGPUInstancedLineComponent, EditorLines)) if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UGPUInstancedLineComponent, EditorLines))
{ {
...@@ -467,6 +480,14 @@ void UGPUInstancedLineComponent::BeginDestroy() ...@@ -467,6 +480,14 @@ void UGPUInstancedLineComponent::BeginDestroy()
ReleaseData(); ReleaseData();
} }
void UGPUInstancedLineComponent::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
}
void UGPUInstancedLineComponent::ReserveMemory(int32 NumberOfSegments, int32 NumberOfLines) void UGPUInstancedLineComponent::ReserveMemory(int32 NumberOfSegments, int32 NumberOfLines)
{ {
const int32 Total = NumberOfSegments * NumberOfLines; const int32 Total = NumberOfSegments * NumberOfLines;
...@@ -496,14 +517,14 @@ bool UGPUInstancedLineComponent::ResizeTexture(int32 Width, int32 Height) ...@@ -496,14 +517,14 @@ bool UGPUInstancedLineComponent::ResizeTexture(int32 Width, int32 Height)
// This might be a bit awkward as the line map is a *map*, and not just an array. // This might be a bit awkward as the line map is a *map*, and not just an array.
// Some lines might be re-ordered in the texture, but that should be fine. // Some lines might be re-ordered in the texture, but that should be fine.
for(TPair<int32, GPULineArray>& Line : LineMap) for(TPair<int32, FGPULineArray>& Line : LineMap)
{ {
for (GPULineIndices& LineIndices : Line.Value) for (FGPULineIndices& LineIndices : Line.Value.IndexArray)
{ {
// Key is instance id, value is texture index. // Key is instance id, value is texture index.
if(LineIndices.Key >= 0) if(LineIndices.InstanceIndex >= 0)
SetCustomDataValue(LineIndices.Key, 4, CurrentTextureIndex, false); SetCustomDataValue(LineIndices.InstanceIndex, 4, CurrentTextureIndex, false);
LineIndices.Value = CurrentTextureIndex; LineIndices.TextureIndex = CurrentTextureIndex;
CurrentTextureIndex++; CurrentTextureIndex++;
MoveTextureMarker(); MoveTextureMarker();
} }
...@@ -556,8 +577,8 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3 ...@@ -556,8 +577,8 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3
const FLinearColor Color = UniformColor ? Colors[0] : Colors[LineIndex]; const FLinearColor Color = UniformColor ? Colors[0] : Colors[LineIndex];
const float Width = UniformWidth ? Widths[0] : Widths[LineIndex]; const float Width = UniformWidth ? Widths[0] : Widths[LineIndex];
GPULineArray& NewLineArray = LineMap.Add(NextFreeId, GPULineArray()); FGPULineArray& NewLineArray = LineMap.Add(NextFreeId, FGPULineArray());
NewLineArray.Reserve(NumberOfSegmentsPerLine + 1); NewLineArray.IndexArray.Reserve(NumberOfSegmentsPerLine + 1);
for (int32 PointIndex = 0; PointIndex < NumberOfSegmentsPerLine; ++PointIndex) for (int32 PointIndex = 0; PointIndex < NumberOfSegmentsPerLine; ++PointIndex)
{ {
...@@ -568,12 +589,12 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3 ...@@ -568,12 +589,12 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3
SetCustomDataValue(InstanceId, 2, Color.B, false); SetCustomDataValue(InstanceId, 2, Color.B, false);
SetCustomDataValue(InstanceId, 3, Width, false); SetCustomDataValue(InstanceId, 3, Width, false);
SetCustomDataValue(InstanceId, 4, static_cast<float>(CurrentTextureIndex), false); // Segment Start SetCustomDataValue(InstanceId, 4, static_cast<float>(CurrentTextureIndex), false); // Segment Start
NewLineArray.Add(TPair<int32, int32>{InstanceId, LineIndex * (NumberOfSegmentsPerLine + 1) + PointIndex}); NewLineArray.IndexArray.Add({InstanceId, LineIndex * (NumberOfSegmentsPerLine + 1) + PointIndex});
CurrentTextureIndex++; CurrentTextureIndex++;
MoveTextureMarker(); MoveTextureMarker();
} }
NewLineArray.Add(TPair<int32, int32>{-1, LineIndex * (NumberOfSegmentsPerLine + 1) + NumberOfSegmentsPerLine}); NewLineArray.IndexArray.Add({-1, LineIndex * (NumberOfSegmentsPerLine + 1) + NumberOfSegmentsPerLine});
MoveTextureMarker(); MoveTextureMarker();
CurrentTextureIndex++; CurrentTextureIndex++;
NextFreeId++; NextFreeId++;
...@@ -592,8 +613,8 @@ int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearCo ...@@ -592,8 +613,8 @@ int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearCo
return -1; return -1;
} }
// 1. // 1.
GPULineArray& NewLineArray = LineMap.Add(NextFreeId, GPULineArray()); FGPULineArray& NewLineArray = LineMap.Add(NextFreeId, FGPULineArray());
NewLineArray.Reserve(Line.Num()); NewLineArray.IndexArray.Reserve(Line.Num());
const int32 LineId = NextFreeId; const int32 LineId = NextFreeId;
NextFreeId++; // TODO Fix Id system as this can possibly overflow. NextFreeId++; // TODO Fix Id system as this can possibly overflow.
...@@ -613,13 +634,13 @@ int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearCo ...@@ -613,13 +634,13 @@ int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearCo
SetCustomDataValue(InstanceId, 2, Color.B, false); SetCustomDataValue(InstanceId, 2, Color.B, false);
SetCustomDataValue(InstanceId, 3, Width, false); SetCustomDataValue(InstanceId, 3, Width, false);
SetCustomDataValue(InstanceId, 4, static_cast<float>(CurrentTextureIndex), false); // Segment Start SetCustomDataValue(InstanceId, 4, static_cast<float>(CurrentTextureIndex), false); // Segment Start
NewLineArray.Add(TPair<int32, int32>{InstanceId, LinearLineData.Num() + PointIndex}); NewLineArray.IndexArray.Add({InstanceId, LinearLineData.Num() + PointIndex});
CurrentTextureIndex++; CurrentTextureIndex++;
MoveTextureMarker(); MoveTextureMarker();
} }
// Add the last point which does not correspond to a transform/instance, but needs to be added to the texture still such that the second last instance can read it: // Add the last point which does not correspond to a transform/instance, but needs to be added to the texture still such that the second last instance can read it:
NewLineArray.Add(TPair<int32, int32>{-1, LinearLineData.Num() + NumberSegments}); NewLineArray.IndexArray.Add({-1, LinearLineData.Num() + NumberSegments});
MoveTextureMarker(); MoveTextureMarker();
CurrentTextureIndex++; CurrentTextureIndex++;
...@@ -670,18 +691,18 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point) ...@@ -670,18 +691,18 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point)
// Adding a point to the last line is easy. Adding it to a line the middle is awkward and requires an almost complete recalculation // Adding a point to the last line is easy. Adding it to a line the middle is awkward and requires an almost complete recalculation
// Get color and width of the line // Get color and width of the line
GPULineArray& Line = LineMap[LineId]; FGPULineArray& Line = LineMap[LineId];
const float R = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats]; const float R = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats];
const float G = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 1]; const float G = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 1];
const float B = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 2]; const float B = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 2];
const float Width = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 3]; const float Width = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 3];
const FIntPoint InitialTextureMarker = CurrentTextureMarker; const FIntPoint InitialTextureMarker = CurrentTextureMarker;
// Check if it's the last line: // Check if it's the last line:
GPULineIndices& Indices = Line.Last(); FGPULineIndices& Indices = Line.IndexArray.Last();
const int32 InstanceId = AddInstanceWorldSpace(FTransform::Identity); const int32 InstanceId = AddInstanceWorldSpace(FTransform::Identity);
SetCustomDataValue(InstanceId, 0, R, false); SetCustomDataValue(InstanceId, 0, R, false);
SetCustomDataValue(InstanceId, 1, G, false); SetCustomDataValue(InstanceId, 1, G, false);
...@@ -689,11 +710,11 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point) ...@@ -689,11 +710,11 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point)
SetCustomDataValue(InstanceId, 3, Width, false); SetCustomDataValue(InstanceId, 3, Width, false);
// Update the latest dummy entry to point to the actual segment. // Update the latest dummy entry to point to the actual segment.
Line.Last().Key = InstanceId; Line.IndexArray.Last().InstanceIndex = InstanceId;
// Set remaining custom data for the newly created segment: // Set remaining custom data for the newly created segment:
SetCustomDataValue(InstanceId, 4, static_cast<float>(Indices.Value), false); // Segment Start SetCustomDataValue(InstanceId, 4, static_cast<float>(Indices.TextureIndex), false); // Segment Start
FVector4& PreviousLastPoint = LinearLineData[Indices.Value]; FVector4& PreviousLastPoint = LinearLineData[Indices.TextureIndex];
PreviousLastPoint.W = 1.0; // This isn't the line end anymore. PreviousLastPoint.W = 1.0; // This isn't the line end anymore.
if(LineId == NextFreeId - 1) if(LineId == NextFreeId - 1)
...@@ -702,7 +723,7 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point) ...@@ -702,7 +723,7 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point)
LinearLineData.Add(FVector4(Point, -1)); // This is the last point now. LinearLineData.Add(FVector4(Point, -1)); // This is the last point now.
// Add a new dummy entry for the last point // Add a new dummy entry for the last point
Line.Add(GPULineIndices{ -1, LinearLineData.Num() - 1 }); Line.IndexArray.Add(FGPULineIndices{ -1, LinearLineData.Num() - 1 });
CurrentTextureIndex++; CurrentTextureIndex++;
MoveTextureMarker(); MoveTextureMarker();
...@@ -756,26 +777,26 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point) ...@@ -756,26 +777,26 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point)
// This is slightly more complicated as all the indices after the added point need to be adjusted. // This is slightly more complicated as all the indices after the added point need to be adjusted.
// Additionally, the point needs to be inserted into the texture, shifting the whole thing. // Additionally, the point needs to be inserted into the texture, shifting the whole thing.
const int32 NewPointTextureIndex = Indices.Value + 1; const int32 NewPointTextureIndex = Indices.TextureIndex + 1;
// Update all LineMap Indices that have a texture index larger than the newly inserted point. Todo: Make more efficient, maybe remove map and swap to array: // Update all LineMap Indices that have a texture index larger than the newly inserted point. Todo: Make more efficient, maybe remove map and swap to array:
for (TPair<int32, GPULineArray>& Pair : LineMap) for (TPair<int32, FGPULineArray>& Pair : LineMap)
{ {
GPULineArray& LineArray = Pair.Value; FGPULineArray& LineArray = Pair.Value;
if (LineArray[0].Value >= NewPointTextureIndex) if (LineArray.IndexArray[0].TextureIndex >= NewPointTextureIndex)
{ {
// Need to increase all indices by 1 and adjust the custom data // Need to increase all indices by 1 and adjust the custom data
for (int32 i = 0; i < LineArray.Num(); ++i) for (int32 i = 0; i < LineArray.IndexArray.Num(); ++i)
{ {
LineArray[i].Value++; LineArray.IndexArray[i].TextureIndex++;
SetCustomDataValue(LineArray[i].Key, 4, LineArray[i].Value, false); SetCustomDataValue(LineArray.IndexArray[i].InstanceIndex, 4, LineArray.IndexArray[i].TextureIndex, false);
} }
} }
} }
// Insert the point into the LinearData: // Insert the point into the LinearData:
LinearLineData.Insert(FVector4(Point, -1), NewPointTextureIndex); LinearLineData.Insert(FVector4(Point, -1), NewPointTextureIndex);
// Add it to the LineMap - this is the new dummy segment because we add it at the end of the line // Add it to the LineMap - this is the new dummy segment because we add it at the end of the line
Line.Add(GPULineIndices{ -1, NewPointTextureIndex }); Line.IndexArray.Add(FGPULineIndices{ -1, NewPointTextureIndex });
//SetCustomDataValue(InstanceId, 4, NewPointTextureIndex, true); //SetCustomDataValue(InstanceId, 4, NewPointTextureIndex, true);
CurrentTextureIndex++; CurrentTextureIndex++;
...@@ -792,15 +813,15 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons ...@@ -792,15 +813,15 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons
{ {
TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::InsertPoint")) TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::InsertPoint"))
GPULineArray& Line = LineMap[LineId]; FGPULineArray& Line = LineMap[LineId];
if (SegmentId == Line.Num()) if (SegmentId == Line.IndexArray.Num())
{ {
return AddPoint(LineId, Point); return AddPoint(LineId, Point);
} }
const float Width = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 3]; const float Width = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 3];
const int32 LinearDataIndex = Line[SegmentId].Value; const int32 LinearDataIndex = Line.IndexArray[SegmentId].TextureIndex;
// Add a new segment BEFORE the current one. // Add a new segment BEFORE the current one.
const int32 InstanceId = AddInstanceWorldSpace(FTransform::Identity); const int32 InstanceId = AddInstanceWorldSpace(FTransform::Identity);
...@@ -819,27 +840,27 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons ...@@ -819,27 +840,27 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons
// This was the old start point // This was the old start point
LinearLineData[LinearDataIndex + 1].W = 1; LinearLineData[LinearDataIndex + 1].W = 1;
} }
Line.Insert(GPULineIndices{ InstanceId, LinearDataIndex }, SegmentId); Line.IndexArray.Insert(FGPULineIndices{ InstanceId, LinearDataIndex }, SegmentId);
SetCustomDataValue(InstanceId, 4, LinearDataIndex, false); SetCustomDataValue(InstanceId, 4, LinearDataIndex, false);
// Update the rest of the line // Update the rest of the line
for(int32 i = SegmentId + 1; i < Line.Num(); ++i) for(int32 i = SegmentId + 1; i < Line.IndexArray.Num(); ++i)
{ {
Line[i].Value++; Line.IndexArray[i].TextureIndex++;
SetCustomDataValue(Line[i].Key, 4, Line[i].Value); SetCustomDataValue(Line.IndexArray[i].InstanceIndex, 4, Line.IndexArray[i].TextureIndex);
} }
// Update all following lines // Update all following lines
for (TPair<int32, GPULineArray>& Pair : LineMap) for (TPair<int32, FGPULineArray>& Pair : LineMap)
{ {
GPULineArray& LineArray = Pair.Value; FGPULineArray& LineArray = Pair.Value;
if (LineArray[0].Value > LinearDataIndex) if (LineArray.IndexArray[0].TextureIndex > LinearDataIndex)
{ {
// Need to increase all indices by 1 and adjust the custom data // Need to increase all indices by 1 and adjust the custom data
for (int32 i = 0; i < LineArray.Num(); ++i) for (int32 i = 0; i < LineArray.IndexArray.Num(); ++i)
{ {
LineArray[i].Value++; LineArray.IndexArray[i].TextureIndex++;
SetCustomDataValue(LineArray[i].Key, 4, LineArray[i].Value, false); SetCustomDataValue(LineArray.IndexArray[i].InstanceIndex, 4, LineArray.IndexArray[i].TextureIndex, false);
} }
} }
} }
...@@ -857,10 +878,10 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons ...@@ -857,10 +878,10 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons
bool UGPUInstancedLineComponent::InsertPointWithSameColor(int32 LineId, int32 SegmentId, const FVector& Point) bool UGPUInstancedLineComponent::InsertPointWithSameColor(int32 LineId, int32 SegmentId, const FVector& Point)
{ {
GPULineArray& Line = LineMap[LineId]; FGPULineArray& Line = LineMap[LineId];
const float R = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats]; const float R = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats];
const float G = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 1]; const float G = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 1];
const float B = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 2]; const float B = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 2];
return InsertPoint(LineId, SegmentId, Point, { R, G, B }); return InsertPoint(LineId, SegmentId, Point, { R, G, B });
} }
...@@ -878,18 +899,18 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& ...@@ -878,18 +899,18 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
// Adding a point to the last line is easy. Adding it to a line the middle is awkward and requires an almost complete recalculation // Adding a point to the last line is easy. Adding it to a line the middle is awkward and requires an almost complete recalculation
// Get color and width of the line // Get color and width of the line
GPULineArray& Line = LineMap[LineId]; FGPULineArray& Line = LineMap[LineId];
const float R = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats]; const float R = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats];
const float G = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 1]; const float G = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 1];
const float B = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 2]; const float B = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 2];
const float Width = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 3]; const float Width = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 3];
const FIntPoint InitialTextureMarker = CurrentTextureMarker; const FIntPoint InitialTextureMarker = CurrentTextureMarker;
// Check if it's the last line: // Check if it's the last line:
GPULineIndices& Indices = Line.Last(); FGPULineIndices& Indices = Line.IndexArray.Last();
const int32 PointTextureIndex = Indices.Value; const int32 PointTextureIndex = Indices.TextureIndex;
FVector4& PreviousLastPoint = LinearLineData[Indices.Value]; FVector4& PreviousLastPoint = LinearLineData[Indices.TextureIndex];
PreviousLastPoint.W = 1.0; // This isn't the line end anymore. PreviousLastPoint.W = 1.0; // This isn't the line end anymore.
if (LineId == NextFreeId - 1) if (LineId == NextFreeId - 1)
...@@ -906,9 +927,9 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& ...@@ -906,9 +927,9 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
// Update the latest dummy entry to point to the actual segment. // Update the latest dummy entry to point to the actual segment.
if (PointIndex == 0) if (PointIndex == 0)
Line.Last().Key = InstanceId; Line.IndexArray.Last().InstanceIndex = InstanceId;
else else
Line.Add(TPair<int32, int32>{InstanceId, LinearLineData.Num() - 1 + PointIndex}); Line.IndexArray.Add({InstanceId, LinearLineData.Num() - 1 + PointIndex});
CurrentTextureIndex++; CurrentTextureIndex++;
MoveTextureMarker(); MoveTextureMarker();
} }
...@@ -917,7 +938,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& ...@@ -917,7 +938,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
LinearLineData.Last().W = -1; LinearLineData.Last().W = -1;
// Add a new dummy entry for the last point // Add a new dummy entry for the last point
Line.Add(GPULineIndices{ -1, LinearLineData.Num() - 1 }); Line.IndexArray.Add({ -1, LinearLineData.Num() - 1 });
CurrentTextureIndex++; CurrentTextureIndex++;
MoveTextureMarker(); MoveTextureMarker();
...@@ -949,19 +970,19 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& ...@@ -949,19 +970,19 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
// This is slightly more complicated as all the indices after the added points need to be adjusted. // This is slightly more complicated as all the indices after the added points need to be adjusted.
// Additionally, the points needs to be inserted into the texture, shifting the whole thing. // Additionally, the points needs to be inserted into the texture, shifting the whole thing.
const int32 NewPointTextureIndex = Indices.Value + 1; const int32 NewPointTextureIndex = Indices.TextureIndex + 1;
// Update all LineMap Indices that have a texture index larger than the newly inserted point. Todo: Make more efficient, maybe remove map and swap to array: // Update all LineMap Indices that have a texture index larger than the newly inserted point. Todo: Make more efficient, maybe remove map and swap to array:
for (TPair<int32, GPULineArray>& Pair : LineMap) for (TPair<int32, FGPULineArray>& Pair : LineMap)
{ {
GPULineArray& LineArray = Pair.Value; FGPULineArray& LineArray = Pair.Value;
if (LineArray[0].Value >= NewPointTextureIndex) if (LineArray.IndexArray[0].TextureIndex >= NewPointTextureIndex)
{ {
// Need to increase all indices by 1 and adjust the custom data // Need to increase all indices by 1 and adjust the custom data
for (int32 i = 0; i < LineArray.Num(); ++i) for (int32 i = 0; i < LineArray.IndexArray.Num(); ++i)
{ {
LineArray[i].Value += Points.Num(); LineArray.IndexArray[i].TextureIndex += Points.Num();
SetCustomDataValue(LineArray[i].Key, 4, LineArray[i].Value, false); SetCustomDataValue(LineArray.IndexArray[i].InstanceIndex, 4, LineArray.IndexArray[i].TextureIndex, false);
} }
} }
} }
...@@ -978,10 +999,10 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& ...@@ -978,10 +999,10 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
// Update the latest dummy entry to point to the actual segment. // Update the latest dummy entry to point to the actual segment.
if (PointIndex == 0) if (PointIndex == 0)
Line.Last().Key = InstanceId; Line.IndexArray.Last().InstanceIndex = InstanceId;
else else
{ {
Line.Add(TPair<int32, int32>{InstanceId, NewPointTextureIndex + PointIndex - 1}); Line.IndexArray.Add({InstanceId, NewPointTextureIndex + PointIndex - 1});
CurrentTextureIndex++; CurrentTextureIndex++;
MoveTextureMarker(); MoveTextureMarker();
} }
...@@ -994,7 +1015,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& ...@@ -994,7 +1015,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
LinearLineData.Insert(TextureData, NewPointTextureIndex); LinearLineData.Insert(TextureData, NewPointTextureIndex);
// Add it to the LineMap - this is the new dummy segment because we add it at the end of the line // Add it to the LineMap - this is the new dummy segment because we add it at the end of the line
Line.Add(GPULineIndices{ -1, NewPointTextureIndex + Points.Num() - 1 }); Line.IndexArray.Add({ -1, NewPointTextureIndex + Points.Num() - 1 });
//SetCustomDataValue(InstanceId, 4, NewPointTextureIndex, true); //SetCustomDataValue(InstanceId, 4, NewPointTextureIndex, true);
CurrentTextureIndex++; CurrentTextureIndex++;
...@@ -1011,18 +1032,18 @@ bool UGPUInstancedLineComponent::InsertPoints(int32 LineId, int32 SegmentId, con ...@@ -1011,18 +1032,18 @@ bool UGPUInstancedLineComponent::InsertPoints(int32 LineId, int32 SegmentId, con
{ {
TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::InsertPoint")) TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::InsertPoint"))
GPULineArray& Line = LineMap[LineId]; FGPULineArray& Line = LineMap[LineId];
if (SegmentId == Line.Num()) if (SegmentId == Line.IndexArray.Num())
{ {
return AddPoints(LineId, Points); return AddPoints(LineId, Points);
} }
const float R = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats]; const float R = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats];
const float G = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 1]; const float G = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 1];
const float B = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 2]; const float B = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 2];
const float Width = PerInstanceSMCustomData[Line[0].Key * NumCustomDataFloats + 3]; const float Width = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 3];
const int32 LinearDataIndex = Line[SegmentId].Value; const int32 LinearDataIndex = Line.IndexArray[SegmentId].TextureIndex;
LinearLineData.Insert(TArray<FVector4>(Points), LinearDataIndex); LinearLineData.Insert(TArray<FVector4>(Points), LinearDataIndex);
if (SegmentId == 0) if (SegmentId == 0)
{ {
...@@ -1040,30 +1061,30 @@ bool UGPUInstancedLineComponent::InsertPoints(int32 LineId, int32 SegmentId, con ...@@ -1040,30 +1061,30 @@ bool UGPUInstancedLineComponent::InsertPoints(int32 LineId, int32 SegmentId, con
SetCustomDataValue(InstanceId, 2, B, false); SetCustomDataValue(InstanceId, 2, B, false);
SetCustomDataValue(InstanceId, 3, Width, false); SetCustomDataValue(InstanceId, 3, Width, false);
Line.Insert(GPULineIndices{ InstanceId, LinearDataIndex + PointIndex }, SegmentId + PointIndex); Line.IndexArray.Insert({ InstanceId, LinearDataIndex + PointIndex }, SegmentId + PointIndex);
SetCustomDataValue(InstanceId, 4, LinearDataIndex + PointIndex, false); SetCustomDataValue(InstanceId, 4, LinearDataIndex + PointIndex, false);
CurrentTextureIndex++; CurrentTextureIndex++;
MoveTextureMarker(); MoveTextureMarker();
} }
// Update the rest of the line // Update the rest of the line
for (int32 i = SegmentId + Points.Num(); i < Line.Num(); ++i) for (int32 i = SegmentId + Points.Num(); i < Line.IndexArray.Num(); ++i)
{ {
Line[i].Value += Points.Num(); Line.IndexArray[i].TextureIndex += Points.Num();
SetCustomDataValue(Line[i].Key, 4, Line[i].Value); SetCustomDataValue(Line.IndexArray[i].InstanceIndex, 4, Line.IndexArray[i].TextureIndex);
} }
// Update all following lines // Update all following lines
for (TPair<int32, GPULineArray>& Pair : LineMap) for (TPair<int32, FGPULineArray>& Pair : LineMap)
{ {
GPULineArray& LineArray = Pair.Value; FGPULineArray& LineArray = Pair.Value;
if (LineArray[0].Value > LinearDataIndex) if (LineArray.IndexArray[0].TextureIndex > LinearDataIndex)
{ {
// Need to increase all indices by 1 and adjust the custom data // Need to increase all indices by 1 and adjust the custom data
for (int32 i = 0; i < LineArray.Num(); ++i) for (int32 i = 0; i < LineArray.IndexArray.Num(); ++i)
{ {
LineArray[i].Value += Points.Num(); LineArray.IndexArray[i].TextureIndex += Points.Num();
SetCustomDataValue(LineArray[i].Key, 4, LineArray[i].Value, false); SetCustomDataValue(LineArray.IndexArray[i].InstanceIndex, 4, LineArray.IndexArray[i].TextureIndex, false);
} }
} }
} }
...@@ -1081,9 +1102,9 @@ bool UGPUInstancedLineComponent::UpdateLine(int32 LineId, TArray<FVector>& Point ...@@ -1081,9 +1102,9 @@ bool UGPUInstancedLineComponent::UpdateLine(int32 LineId, TArray<FVector>& Point
{ {
TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::UpdateLine")) TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::UpdateLine"))
const GPULineArray& Line = LineMap[LineId]; const FGPULineArray& Line = LineMap[LineId];
if(Line.Num() != Points.Num()) if(Line.IndexArray.Num() != Points.Num())
{ {
return false; return false;
} }
...@@ -1091,7 +1112,7 @@ bool UGPUInstancedLineComponent::UpdateLine(int32 LineId, TArray<FVector>& Point ...@@ -1091,7 +1112,7 @@ bool UGPUInstancedLineComponent::UpdateLine(int32 LineId, TArray<FVector>& Point
TArray<FVector4>* TextureData = new TArray<FVector4>(MoveTemp(Points)); TArray<FVector4>* TextureData = new TArray<FVector4>(MoveTemp(Points));
TextureData->Last().W = -1; TextureData->Last().W = -1;
(*TextureData)[0].W = 0; (*TextureData)[0].W = 0;
const int32 TextureIndex = Line[0].Value; const int32 TextureIndex = Line.IndexArray[0].TextureIndex;
const FIntPoint StartIndex(TextureIndex % TextureWidth, TextureIndex / TextureWidth); const FIntPoint StartIndex(TextureIndex % TextureWidth, TextureIndex / TextureWidth);
FMemory::Memcpy(LinearLineData.GetData() + TextureIndex, TextureData->GetData(), TextureData->Num() * sizeof(FVector4)); FMemory::Memcpy(LinearLineData.GetData() + TextureIndex, TextureData->GetData(), TextureData->Num() * sizeof(FVector4));
...@@ -1179,16 +1200,16 @@ bool UGPUInstancedLineComponent::DrawLinesDirectly(int32 LineIdStart, TArray<FVe ...@@ -1179,16 +1200,16 @@ bool UGPUInstancedLineComponent::DrawLinesDirectly(int32 LineIdStart, TArray<FVe
bool UGPUInstancedLineComponent::UpdatePoint(int32 LineId, int32 PointId, const FVector& Point) bool UGPUInstancedLineComponent::UpdatePoint(int32 LineId, int32 PointId, const FVector& Point)
{ {
// Should check for validity // Should check for validity
const GPULineIndices& PointIndices = LineMap[LineId][PointId]; const FGPULineIndices& PointIndices = LineMap[LineId].IndexArray[PointId];
// Only need to update the linear data - don't overwrite W as the line start/end doesn't change // Only need to update the linear data - don't overwrite W as the line start/end doesn't change
LinearLineData[PointIndices.Value].X = Point.X; LinearLineData[PointIndices.TextureIndex].X = Point.X;
LinearLineData[PointIndices.Value].Y = Point.Y; LinearLineData[PointIndices.TextureIndex].Y = Point.Y;
LinearLineData[PointIndices.Value].Z = Point.Z; LinearLineData[PointIndices.TextureIndex].Z = Point.Z;
const int32 InstanceId = (PointIndices.Key != -1) ? PointIndices.Key : LineMap[LineId][PointId - 1].Key; const int32 InstanceId = (PointIndices.InstanceIndex != -1) ? PointIndices.InstanceIndex : LineMap[LineId].IndexArray[PointId - 1].InstanceIndex;
const int32 TextureIndex = PointIndices.Value; const int32 TextureIndex = PointIndices.TextureIndex;
//const int32 Y = PerInstanceSMCustomData[InstanceId * NumCustomDataFloats + 5]; //const int32 Y = PerInstanceSMCustomData[InstanceId * NumCustomDataFloats + 5];
const int32 X = TextureIndex % TextureWidth; const int32 X = TextureIndex % TextureWidth;
const int32 Y = TextureIndex / TextureWidth; const int32 Y = TextureIndex / TextureWidth;
...@@ -1205,7 +1226,7 @@ bool UGPUInstancedLineComponent::UpdatePoint(int32 LineId, int32 PointId, const ...@@ -1205,7 +1226,7 @@ bool UGPUInstancedLineComponent::UpdatePoint(int32 LineId, int32 PointId, const
// Copy for now - no need to do that // Copy for now - no need to do that
TArray<FVector4>* TextureData = new TArray<FVector4>{ LinearLineData[PointIndices.Value] }; TArray<FVector4>* TextureData = new TArray<FVector4>{ LinearLineData[PointIndices.TextureIndex] };
PositionTexture->UpdateTextureRegions(0, 1, Region, TextureWidth * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(), PositionTexture->UpdateTextureRegions(0, 1, Region, TextureWidth * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(),
...@@ -1224,31 +1245,31 @@ bool UGPUInstancedLineComponent::UpdatePoints(int32 LineId, int32 StartingPointI ...@@ -1224,31 +1245,31 @@ bool UGPUInstancedLineComponent::UpdatePoints(int32 LineId, int32 StartingPointI
{ {
TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::UpdatePoints")) TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::UpdatePoints"))
const GPULineArray& Line = LineMap[LineId]; const FGPULineArray& Line = LineMap[LineId];
if (Line.Num() < Points.Num() || StartingPointId + Points.Num() > Line.Num()) if (Line.IndexArray.Num() < Points.Num() || StartingPointId + Points.Num() > Line.IndexArray.Num())
{ {
return false; return false;
} }
if(Line.Num() == Points.Num() && StartingPointId == 0) if(Line.IndexArray.Num() == Points.Num() && StartingPointId == 0)
{ {
return UpdateLine(LineId, Points); return UpdateLine(LineId, Points);
} }
// Should check for validity // Should check for validity
const GPULineIndices& FirstPointIndices = LineMap[LineId][StartingPointId]; const FGPULineIndices& FirstPointIndices = LineMap[LineId].IndexArray[StartingPointId];
TArray<FVector4>* TextureData = new TArray<FVector4>(MoveTemp(Points)); TArray<FVector4>* TextureData = new TArray<FVector4>(MoveTemp(Points));
if(StartingPointId == 0) if(StartingPointId == 0)
{ {
(*TextureData)[0].W = 0; (*TextureData)[0].W = 0;
} }
if (StartingPointId + Points.Num() == Line.Num()) if (StartingPointId + Points.Num() == Line.IndexArray.Num())
{ {
TextureData->Last().W = -1; TextureData->Last().W = -1;
} }
const int32 StartTextureIndex = Line[StartingPointId].Value; const int32 StartTextureIndex = Line.IndexArray[StartingPointId].TextureIndex;
const FIntPoint StartIndex(StartTextureIndex % TextureWidth, StartTextureIndex / TextureWidth); const FIntPoint StartIndex(StartTextureIndex % TextureWidth, StartTextureIndex / TextureWidth);
FMemory::Memcpy(LinearLineData.GetData() + StartTextureIndex, TextureData->GetData(), TextureData->Num() * sizeof(FVector4)); FMemory::Memcpy(LinearLineData.GetData() + StartTextureIndex, TextureData->GetData(), TextureData->Num() * sizeof(FVector4));
...@@ -1270,20 +1291,20 @@ bool UGPUInstancedLineComponent::RemoveLine(int32 LineId) ...@@ -1270,20 +1291,20 @@ bool UGPUInstancedLineComponent::RemoveLine(int32 LineId)
{ {
TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::RemoveLine")) TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::RemoveLine"))
const GPULineArray& Line = LineMap[LineId]; const FGPULineArray& Line = LineMap[LineId];
const int32 LineLength = Line.Num(); const int32 LineLength = Line.IndexArray.Num();
const int32 LineTextureIndex = Line[0].Value; const int32 LineTextureIndex = Line.IndexArray[0].TextureIndex;
// Because ISM are so great, they reshuffle id's on removal.... // Because ISM are so great, they reshuffle id's on removal....
// This means we can't just remove consecutive ids, but need to actually re-calculate them EVERY SINGLE TIME // This means we can't just remove consecutive ids, but need to actually re-calculate them EVERY SINGLE TIME
// As instances of a line aren't guaranteed to be in order, collect and sort the indices first, then start top down. // As instances of a line aren't guaranteed to be in order, collect and sort the indices first, then start top down.
// //
TArray<int32> InstancesToRemove; TArray<int32> InstancesToRemove;
InstancesToRemove.Reserve(Line.Num()); InstancesToRemove.Reserve(Line.IndexArray.Num());
for(int32 PointIndex = 0; PointIndex < Line.Num() - 1; PointIndex++) for(int32 PointIndex = 0; PointIndex < Line.IndexArray.Num() - 1; PointIndex++)
{ {
InstancesToRemove.Add(Line[PointIndex].Key); InstancesToRemove.Add(Line.IndexArray[PointIndex].InstanceIndex);
} }
InstancesToRemove.Sort(); InstancesToRemove.Sort();
...@@ -1298,12 +1319,12 @@ bool UGPUInstancedLineComponent::RemoveLine(int32 LineId) ...@@ -1298,12 +1319,12 @@ bool UGPUInstancedLineComponent::RemoveLine(int32 LineId)
LineMap.Remove(LineId); LineMap.Remove(LineId);
// Update all following lines // Update all following lines
for (TPair<int32, GPULineArray>& Pair : LineMap) for (TPair<int32, FGPULineArray>& Pair : LineMap)
{ {
GPULineArray& LineArray = Pair.Value; FGPULineArray& LineArray = Pair.Value;
for (int32 i = 0; i < LineArray.Num(); ++i) for (int32 i = 0; i < LineArray.IndexArray.Num(); ++i)
{ {
if (LineArray[i].Key >= InstancesToRemove[0]) if (LineArray.IndexArray[i].InstanceIndex >= InstancesToRemove[0])
{ {
// Apparently unreal also shuffles the instance indices, this might bite us later on // Apparently unreal also shuffles the instance indices, this might bite us later on
...@@ -1311,17 +1332,17 @@ bool UGPUInstancedLineComponent::RemoveLine(int32 LineId) ...@@ -1311,17 +1332,17 @@ bool UGPUInstancedLineComponent::RemoveLine(int32 LineId)
for(int32 Index = InstancesToRemove.Num(); Index > 0; --Index) for(int32 Index = InstancesToRemove.Num(); Index > 0; --Index)
{ {
if (LineArray[i].Key >= InstancesToRemove[Index - 1]) if (LineArray.IndexArray[i].InstanceIndex >= InstancesToRemove[Index - 1])
{ {
LineArray[i].Key -= Index; LineArray.IndexArray[i].InstanceIndex -= Index;
break; break;
} }
} }
} }
if (LineArray[0].Value >= LineTextureIndex) if (LineArray.IndexArray[0].TextureIndex >= LineTextureIndex)
{ {
LineArray[i].Value -= LineLength; LineArray.IndexArray[i].TextureIndex -= LineLength;
SetCustomDataValue(LineArray[i].Key, 4, LineArray[i].Value, false); SetCustomDataValue(LineArray.IndexArray[i].InstanceIndex, 4, LineArray.IndexArray[i].TextureIndex, false);
} }
} }
} }
...@@ -1364,10 +1385,10 @@ bool UGPUInstancedLineComponent::RemovePoint(int32 LineId, int32 PointId) ...@@ -1364,10 +1385,10 @@ bool UGPUInstancedLineComponent::RemovePoint(int32 LineId, int32 PointId)
{ {
TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::RemovePoint")) TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::RemovePoint"))
GPULineArray& Line = LineMap[LineId]; FGPULineArray& Line = LineMap[LineId];
const GPULineIndices& Indices = Line[PointId]; const FGPULineIndices& Indices = Line.IndexArray[PointId];
const int32 LineTextureIndex = Indices.Value; const int32 LineTextureIndex = Indices.TextureIndex;
int32 RemovedInstanceId = Indices.Key; int32 RemovedInstanceId = Indices.InstanceIndex;
if (PointId == 0) if (PointId == 0)
{ {
...@@ -1377,42 +1398,42 @@ bool UGPUInstancedLineComponent::RemovePoint(int32 LineId, int32 PointId) ...@@ -1377,42 +1398,42 @@ bool UGPUInstancedLineComponent::RemovePoint(int32 LineId, int32 PointId)
LinearLineData.RemoveAt(LineTextureIndex); LinearLineData.RemoveAt(LineTextureIndex);
// Last point is special // Last point is special
if(PointId == Line.Num() - 1) if(PointId == Line.IndexArray.Num() - 1)
{ {
LinearLineData[Line[PointId - 1].Value].W = -1; LinearLineData[Line.IndexArray[PointId - 1].TextureIndex].W = -1;
RemovedInstanceId = Line[PointId - 1].Key; RemovedInstanceId = Line.IndexArray[PointId - 1].InstanceIndex;
RemoveInstance(Line[PointId - 1].Key); RemoveInstance(Line.IndexArray[PointId - 1].InstanceIndex);
Line[PointId - 1].Key = -1; Line.IndexArray[PointId - 1].InstanceIndex = -1;
} }
else else
{ {
// Update the following segments in this line: // Update the following segments in this line:
for (int32 i = PointId + 1; i < Line.Num(); ++i) for (int32 i = PointId + 1; i < Line.IndexArray.Num(); ++i)
{ {
Line[i].Value -= 1; Line.IndexArray[i].TextureIndex -= 1;
SetCustomDataValue(Line[i].Key, 4, Line[i].Value, false); SetCustomDataValue(Line.IndexArray[i].InstanceIndex, 4, Line.IndexArray[i].TextureIndex, false);
} }
MarkRenderStateDirty(); MarkRenderStateDirty();
RemoveInstance(RemovedInstanceId); RemoveInstance(RemovedInstanceId);
} }
Line.RemoveAt(PointId); Line.IndexArray.RemoveAt(PointId);
// Update all following lines // Update all following lines
for (TPair<int32, GPULineArray>& Pair : LineMap) for (TPair<int32, FGPULineArray>& Pair : LineMap)
{ {
GPULineArray& LineArray = Pair.Value; FGPULineArray& LineArray = Pair.Value;
for (int32 i = 0; i < LineArray.Num(); ++i) for (int32 i = 0; i < LineArray.IndexArray.Num(); ++i)
{ {
if (LineArray[i].Key >= RemovedInstanceId) if (LineArray.IndexArray[i].InstanceIndex >= RemovedInstanceId)
{ {
// Apparently unreal also shuffles the instance indices, this might bite us later on // Apparently unreal also shuffles the instance indices, this might bite us later on
LineArray[i].Key -= 1; LineArray.IndexArray[i].InstanceIndex -= 1;
} }
if (LineArray[0].Value > LineTextureIndex) if (LineArray.IndexArray[0].TextureIndex > LineTextureIndex)
{ {
LineArray[i].Value -= 1; LineArray.IndexArray[i].TextureIndex -= 1;
SetCustomDataValue(LineArray[i].Key, 4, LineArray[i].Value, false); SetCustomDataValue(LineArray.IndexArray[i].InstanceIndex, 4, LineArray.IndexArray[i].TextureIndex, false);
} }
} }
} }
...@@ -1439,11 +1460,11 @@ bool UGPUInstancedLineComponent::RemovePoints(int32 LineId, int32 StartingPointI ...@@ -1439,11 +1460,11 @@ bool UGPUInstancedLineComponent::RemovePoints(int32 LineId, int32 StartingPointI
bool UGPUInstancedLineComponent::SetLineColor(int32 LineId, const FLinearColor& Color) bool UGPUInstancedLineComponent::SetLineColor(int32 LineId, const FLinearColor& Color)
{ {
const GPULineArray& Line = LineMap[LineId]; const FGPULineArray& Line = LineMap[LineId];
for (const GPULineIndices& LineIndices: Line) for (const FGPULineIndices& LineIndices: Line.IndexArray)
{ {
const int32 InstanceId = LineIndices.Key; const int32 InstanceId = LineIndices.InstanceIndex;
if (InstanceId >= 0) if (InstanceId >= 0)
{ {
SetCustomDataValue(InstanceId, 0, Color.R, false); SetCustomDataValue(InstanceId, 0, Color.R, false);
...@@ -1459,7 +1480,7 @@ bool UGPUInstancedLineComponent::SetSegmentColor(int32 LineId, int32 SegmentId, ...@@ -1459,7 +1480,7 @@ bool UGPUInstancedLineComponent::SetSegmentColor(int32 LineId, int32 SegmentId,
{ {
// Get Instance Id: // Get Instance Id:
const int32 InstanceId = LineMap[LineId][SegmentId].Key; const int32 InstanceId = LineMap[LineId].IndexArray[SegmentId].InstanceIndex;
SetCustomDataValue(InstanceId, 0, Color.R, false); SetCustomDataValue(InstanceId, 0, Color.R, false);
SetCustomDataValue(InstanceId, 1, Color.G, false); SetCustomDataValue(InstanceId, 1, Color.G, false);
...@@ -1470,11 +1491,11 @@ bool UGPUInstancedLineComponent::SetSegmentColor(int32 LineId, int32 SegmentId, ...@@ -1470,11 +1491,11 @@ bool UGPUInstancedLineComponent::SetSegmentColor(int32 LineId, int32 SegmentId,
bool UGPUInstancedLineComponent::SetLineWidth(int32 LineId, float Width) bool UGPUInstancedLineComponent::SetLineWidth(int32 LineId, float Width)
{ {
const GPULineArray& Line = LineMap[LineId]; const FGPULineArray& Line = LineMap[LineId];
for (const GPULineIndices& LineIndices : Line) for (const FGPULineIndices& LineIndices : Line.IndexArray)
{ {
const int32 InstanceId = LineIndices.Key; const int32 InstanceId = LineIndices.InstanceIndex;
if (InstanceId >= 0) if (InstanceId >= 0)
{ {
SetCustomDataValue(InstanceId, 3, Width, false); SetCustomDataValue(InstanceId, 3, Width, false);
...@@ -1486,9 +1507,9 @@ bool UGPUInstancedLineComponent::SetLineWidth(int32 LineId, float Width) ...@@ -1486,9 +1507,9 @@ bool UGPUInstancedLineComponent::SetLineWidth(int32 LineId, float Width)
bool UGPUInstancedLineComponent::SetSegmentWidth(int32 LineId, int32 SegmentId, float Width) bool UGPUInstancedLineComponent::SetSegmentWidth(int32 LineId, int32 SegmentId, float Width)
{ {
const int32 InstanceId = LineMap[LineId][SegmentId].Key; const int32 InstanceId = LineMap[LineId].IndexArray[SegmentId].InstanceIndex;
SetCustomDataValue(InstanceId, 3, Width, false); SetCustomDataValue(InstanceId, 3, Width, false);
return true; return true;
} }
//#pragma optimize("", on) #pragma optimize("", on)
...@@ -13,14 +13,21 @@ ...@@ -13,14 +13,21 @@
//typedef TPair<FVector, TTuple<int32, int32, int32>> GPULineSegment; //typedef TPair<FVector, TTuple<int32, int32, int32>> GPULineSegment;
// Pair of InstanceId and LinearData index. // Pair of InstanceId and LinearData index.
typedef TPair<int32, int32> GPULineIndices; //
// LineArray that contains indices into the instance list and the linear data. // LineArray that contains indices into the instance list and the linear data.
typedef TPair<int32, int32> GPULineIndices;
typedef TArray<GPULineIndices> GPULineArray; typedef TArray<GPULineIndices> GPULineArray;
// Maps a LineId to a LineArray. // Maps a LineId to a LineArray.
typedef TMap<int32, GPULineArray> GPULinesMap; typedef TMap<int32, GPULineArray> GPULinesMap;
USTRUCT(BlueprintType) USTRUCT(BlueprintType)
struct FEditorPoint struct FEditorPoint
{ {
...@@ -55,6 +62,7 @@ struct FEditorLineData ...@@ -55,6 +62,7 @@ struct FEditorLineData
UPROPERTY(EditAnywhere) UPROPERTY(EditAnywhere)
FColor Color; FColor Color;
UPROPERTY()
int32 RespectiveLineId = -1; int32 RespectiveLineId = -1;
FEditorLineData() FEditorLineData()
...@@ -74,51 +82,42 @@ struct FEditorLineData ...@@ -74,51 +82,42 @@ struct FEditorLineData
} }
}; };
USTRUCT()
UCLASS(Blueprintable, BlueprintType, meta = (BlueprintSpawnableComponent), HideCategories=("Instances", "Object", "LOD", "Physics", "Activation", "Materials", "Cooking", "Sockets", "Collision", "Mobile", "HLOD")) struct FGPULineIndices
class INSTANCEDMESHLINERENDERING_API UGPUInstancedLineComponent : public UInstancedStaticMeshComponent
{ {
GENERATED_BODY() GENERATED_USTRUCT_BODY()
private:
void MoveTextureMarker()
{
CurrentTextureMarker.X++;
if (CurrentTextureMarker.X == TextureWidth)
{
// move marker down one row:
CurrentTextureMarker.X = 0;
CurrentTextureMarker.Y = CurrentTextureMarker.Y + 1;
}
}
void UpdateWholeTexture();
void Init(); UPROPERTY()
int32 InstanceIndex;
void RegisterSerializedEditorLines(); UPROPERTY()
int32 TextureIndex;
void UpdateAllEditorLines(); FGPULineIndices() = default;
FUpdateTextureRegion2D* CalculateTextureRegions(const FIntPoint& StartIndex, int32 NumberOfPoints, int32& NumberOfRegionsOut); FGPULineIndices(int32 InstanceIndex, int32 TextureIndex)
: InstanceIndex(InstanceIndex), TextureIndex(TextureIndex) {}
};
GPULinesMap LineMap; USTRUCT()
struct FGPULineArray
{
GENERATED_USTRUCT_BODY()
TArray<FVector4> LinearLineData; UPROPERTY()
TArray<FGPULineIndices> IndexArray;
};
// Array that keeps track of editor lines. This is ONLY needed because the array can be cleared by a simple stupid button press in the UCLASS(Blueprintable, BlueprintType, meta = (BlueprintSpawnableComponent), HideCategories=(Object, LOD, Physics, Activation, Materials, "Cooking", "Sockets", "Collision", "Mobile", "HLOD"))
// details panel, circumventing the PostEditChangeChainProperty function by clearing the array first. The change callback gets called, but class INSTANCEDMESHLINERENDERING_API UGPUInstancedLineComponent : public UInstancedStaticMeshComponent
// as the EditorLines array has already been cleared, it's not possible to backtrack the removed lines. {
TArray<int32> EditorLineIds; GENERATED_BODY()
int32 NextFreeId = 0; public:
int32 CurrentTextureIndex;
FIntPoint CurrentTextureMarker;
bool bIsInitialized = false; UGPUInstancedLineComponent(const FObjectInitializer& ObjectInitializer);
~UGPUInstancedLineComponent();
protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
virtual void PostInitProperties() override; virtual void PostInitProperties() override;
...@@ -134,11 +133,32 @@ protected: ...@@ -134,11 +133,32 @@ protected:
virtual void OnComponentCreated() override; virtual void OnComponentCreated() override;
virtual void BeginDestroy() override; virtual void BeginDestroy() override;
public: virtual void Serialize(FArchive& Ar) override;
UGPUInstancedLineComponent(const FObjectInitializer& ObjectInitializer); private:
~UGPUInstancedLineComponent();
void MoveTextureMarker()
{
CurrentTextureMarker.X++;
if (CurrentTextureMarker.X == TextureWidth)
{
// move marker down one row:
CurrentTextureMarker.X = 0;
CurrentTextureMarker.Y = CurrentTextureMarker.Y + 1;
}
}
void UpdateWholeTexture();
void Init();
//void RegisterSerializedEditorLines();
void UpdateAllEditorLines();
FUpdateTextureRegion2D* CalculateTextureRegions(const FIntPoint& StartIndex, int32 NumberOfPoints, int32& NumberOfRegionsOut);
public:
// todo // todo
void ReleaseData(); void ReleaseData();
...@@ -423,7 +443,7 @@ public: ...@@ -423,7 +443,7 @@ public:
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Components|InstancedLineComponent") UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Components|InstancedLineComponent")
int32 GetNumberOfPointsInLine(int32 LineId) const int32 GetNumberOfPointsInLine(int32 LineId) const
{ {
return LineMap[LineId].Num(); return LineMap[LineId].IndexArray.Num();
} }
UPROPERTY(BlueprintReadWrite, EditAnywhere) UPROPERTY(BlueprintReadWrite, EditAnywhere)
...@@ -438,10 +458,34 @@ public: ...@@ -438,10 +458,34 @@ public:
UPROPERTY(BlueprintReadOnly, EditAnywhere) UPROPERTY(BlueprintReadOnly, EditAnywhere)
int32 TextureHeight; int32 TextureHeight;
UPROPERTY(BlueprintReadOnly, VisibleAnywhere) UPROPERTY(transient)
UMaterialInstanceDynamic* DynamicLineMaterial; UMaterialInstanceDynamic* DynamicLineMaterial;
UPROPERTY(EditAnywhere, DisplayName = "Lines", meta = (MakeEditWidget = true, EditFixedOrder)) UPROPERTY(EditAnywhere, DisplayName = "Lines", meta = (MakeEditWidget = true, EditFixedOrder))
TArray<FEditorLineData> EditorLines; TArray<FEditorLineData> EditorLines;
private:
UPROPERTY()
TMap<int32, FGPULineArray> LineMap;
UPROPERTY()
TArray<FVector4> LinearLineData;
// Array that keeps track of editor lines. This is ONLY needed because the array can be cleared by a simple stupid button press in the
// details panel, circumventing the PostEditChangeChainProperty function by clearing the array first. The change callback gets called, but
// as the EditorLines array has already been cleared, it's not possible to backtrack the removed lines.
UPROPERTY()
TArray<int32> EditorLineIds;
UPROPERTY()
int32 NextFreeId;
UPROPERTY()
int32 CurrentTextureIndex;
UPROPERTY()
FIntPoint CurrentTextureMarker;
bool bIsInitialized = false;
}; };
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment