//----------------------------------------------------------------------//
// rendering
//----------------------------------------------------------------------//
FPrimitiveSceneProxy* UGameplayDebuggingComponent::CreateSceneProxy()
{
    FDebugRenderSceneCompositeProxy* CompositeProxy = NULL;
    AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner());
    if (!World || World->GetNetMode() == NM_DedicatedServer)
    {
        return NULL;
    }

    if (!Replicator || !Replicator->IsDrawEnabled())
    {
        return NULL;
    }

#if WITH_RECAST
    if (ShouldReplicateData(EAIDebugDrawDataView::NavMesh))
    {
        FNavMeshSceneProxyData NewNavmeshRenderData;
        NewNavmeshRenderData.Reset();
        NewNavmeshRenderData.bNeedsNewData = false;
        NewNavmeshRenderData.bEnableDrawing = false;
        PrepareNavMeshData(&NewNavmeshRenderData);

        NavMeshBounds = NewNavmeshRenderData.Bounds;
        CompositeProxy = CompositeProxy ? CompositeProxy : (new FDebugRenderSceneCompositeProxy(this));
        CompositeProxy->AddChild(new FRecastRenderingSceneProxy(this, &NewNavmeshRenderData, true));
    }
#endif

#if USE_EQS_DEBUGGER
    if (ShouldReplicateData(EAIDebugDrawDataView::EQS) && IsClientEQSSceneProxyEnabled())
    {
        const int32 EQSIndex = EQSLocalData.Num() > 0 ? FMath::Clamp(CurrentEQSIndex, 0, EQSLocalData.Num() - 1) : INDEX_NONE;
        if (EQSLocalData.IsValidIndex(EQSIndex))
        {
            CompositeProxy = CompositeProxy ? CompositeProxy : (new FDebugRenderSceneCompositeProxy(this));
            auto& CurrentLocalData = EQSLocalData[EQSIndex];

            FString ViewFlagName = TEXT("Game");
#if WITH_EDITOR
            UEditorEngine* EEngine = Cast<UEditorEngine>(GEngine);
            if (EEngine && EEngine->bIsSimulatingInEditor)
            {
                ViewFlagName = TEXT("DebugAI");
            }
#endif
            CompositeProxy->AddChild(new FEQSSceneProxy(this, ViewFlagName, false, CurrentLocalData.SolidSpheres, CurrentLocalData.Texts));
        }
    }
#endif // USE_EQS_DEBUGGER

    return CompositeProxy;
}
FPrimitiveSceneProxy* UNavMeshRenderingComponent::CreateSceneProxy()
{
#if WITH_RECAST && WITH_EDITOR
	FPrimitiveSceneProxy* SceneProxy = NULL;
	if (IsVisible())
	{
		FNavMeshSceneProxyData ProxyData;
		ProxyData.Reset();
		GatherData(&ProxyData);

		SceneProxy = new FRecastRenderingSceneProxy(this, &ProxyData);
		ProxyData.Reset();
	}
	return SceneProxy;
#else
	return NULL;
#endif
}
FPrimitiveSceneProxy* UNavMeshRenderingComponent::CreateSceneProxy()
{
#if WITH_RECAST && !UE_BUILD_SHIPPING && !UE_BUILD_TEST
	FPrimitiveSceneProxy* SceneProxy = NULL;

	const bool bShowNavigation = IsNavigationShowFlagSet(GetWorld());

	bCollectNavigationData = bShowNavigation;

	if (bCollectNavigationData && IsVisible())
	{
		FNavMeshSceneProxyData ProxyData;
		ProxyData.Reset();
		GatherData(ProxyData);

		SceneProxy = new FRecastRenderingSceneProxy(this, &ProxyData);
		ProxyData.Reset();
	}
	return SceneProxy;
#else
	return NULL;
#endif //WITH_RECAST && !UE_BUILD_SHIPPING && !UE_BUILD_TEST
}
void UNavMeshRenderingComponent::GatherData(FNavMeshSceneProxyData& CurrentData) const
{
	QUICK_SCOPE_CYCLE_COUNTER(STAT_NavMesh_GatherDebugDrawingGeometry);
#if WITH_RECAST
	const ARecastNavMesh* NavMesh = Cast<ARecastNavMesh>(GetOwner());

	CurrentData.Reset();
	
	if (NavMesh && NavMesh->IsDrawingEnabled())
	{
		CurrentData.bEnableDrawing = true;
		CurrentData.bNeedsNewData = false;

		FHitProxyId HitProxyId = FHitProxyId();
		CurrentData.bDrawPathCollidingGeometry = NavMesh->bDrawPathCollidingGeometry;

		CurrentData.NavMeshDrawOffset.Z = NavMesh->DrawOffset;
		CurrentData.NavMeshGeometry.bGatherPolyEdges = NavMesh->bDrawPolyEdges;
		CurrentData.NavMeshGeometry.bGatherNavMeshEdges = NavMesh->bDrawNavMeshEdges;

		const FNavDataConfig& NavConfig = NavMesh->GetConfig();
		CurrentData.NavMeshColors[RECAST_DEFAULT_AREA] = NavConfig.Color.DWColor() > 0 ? NavConfig.Color : NavMeshRenderColor_RecastMesh;
		for (uint8 i = 0; i < RECAST_DEFAULT_AREA; ++i)
		{
			CurrentData.NavMeshColors[i] = NavMesh->GetAreaIDColor(i);
		}

		// just a little trick to make sure navmeshes with different sized are not drawn with same offset
		CurrentData.NavMeshDrawOffset.Z += NavMesh->GetConfig().AgentRadius / 10.f;

		NavMesh->BeginBatchQuery();

		if (NavMesh->bDrawOctree)
		{
			const UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
			const FNavigationOctree* NavOctree = NavSys ? NavSys->GetNavOctree() : NULL;
			if (NavOctree)
			{
				for (FNavigationOctree::TConstIterator<> NodeIt(*NavOctree); NodeIt.HasPendingNodes(); NodeIt.Advance())
				{
					const FNavigationOctree::FNode& CurrentNode = NodeIt.GetCurrentNode();
					const FOctreeNodeContext& CorrentContext = NodeIt.GetCurrentContext();
					CurrentData.OctreeBounds.Add(CorrentContext.Bounds);

					FOREACH_OCTREE_CHILD_NODE(ChildRef)
					{
						if (CurrentNode.HasChild(ChildRef))
						{
							NodeIt.PushChild(ChildRef);
						}
					}
				}
			}
		}

		NavMesh->GetDebugGeometry(CurrentData.NavMeshGeometry);
		const TArray<FVector>& MeshVerts = CurrentData.NavMeshGeometry.MeshVerts;

		// @fixme, this is going to double up on lots of interior lines
		if (NavMesh->bDrawTriangleEdges)
		{
			for (int32 AreaIdx = 0; AreaIdx < RECAST_MAX_AREAS; ++AreaIdx)
			{
				const TArray<int32>& MeshIndices = CurrentData.NavMeshGeometry.AreaIndices[AreaIdx];
				for (int32 Idx=0; Idx<MeshIndices.Num(); Idx += 3)
				{
					CurrentData.ThickLineItems.Add(FNavMeshSceneProxyData::FDebugThickLine(MeshVerts[MeshIndices[Idx + 0]] + CurrentData.NavMeshDrawOffset, MeshVerts[MeshIndices[Idx + 1]] + CurrentData.NavMeshDrawOffset, NavMeshRenderColor_Recast_TriangleEdges, DefaultEdges_LineThickness));
					CurrentData.ThickLineItems.Add(FNavMeshSceneProxyData::FDebugThickLine(MeshVerts[MeshIndices[Idx + 1]] + CurrentData.NavMeshDrawOffset, MeshVerts[MeshIndices[Idx + 2]] + CurrentData.NavMeshDrawOffset, NavMeshRenderColor_Recast_TriangleEdges, DefaultEdges_LineThickness));
					CurrentData.ThickLineItems.Add(FNavMeshSceneProxyData::FDebugThickLine(MeshVerts[MeshIndices[Idx + 2]] + CurrentData.NavMeshDrawOffset, MeshVerts[MeshIndices[Idx + 0]] + CurrentData.NavMeshDrawOffset, NavMeshRenderColor_Recast_TriangleEdges, DefaultEdges_LineThickness));
				}
			}
		}

		// make lines for tile edges
		if (NavMesh->bDrawPolyEdges)
		{
			const TArray<FVector>& TileEdgeVerts = CurrentData.NavMeshGeometry.PolyEdges;
			for (int32 Idx=0; Idx < TileEdgeVerts.Num(); Idx += 2)
			{
				CurrentData.TileEdgeLines.Add(FDebugRenderSceneProxy::FDebugLine(TileEdgeVerts[Idx] + CurrentData.NavMeshDrawOffset, TileEdgeVerts[Idx + 1] + CurrentData.NavMeshDrawOffset, NavMeshRenderColor_Recast_TileEdges));
			}
		}

		// make lines for navmesh edges
		if (NavMesh->bDrawNavMeshEdges)
		{
			const FColor EdgesColor = DarkenColor(CurrentData.NavMeshColors[RECAST_DEFAULT_AREA]);
			const TArray<FVector>& NavMeshEdgeVerts = CurrentData.NavMeshGeometry.NavMeshEdges;
			for (int32 Idx=0; Idx < NavMeshEdgeVerts.Num(); Idx += 2)
			{
				CurrentData.NavMeshEdgeLines.Add( FDebugRenderSceneProxy::FDebugLine(NavMeshEdgeVerts[Idx] + CurrentData.NavMeshDrawOffset, NavMeshEdgeVerts[Idx+1] + CurrentData.NavMeshDrawOffset, EdgesColor));
			}
		}

		// offset all navigation-link positions
		if (!NavMesh->bDrawClusters)
		{
			for (int32 OffMeshLineIndex = 0; OffMeshLineIndex < CurrentData.NavMeshGeometry.OffMeshLinks.Num(); ++OffMeshLineIndex)
			{
				FRecastDebugGeometry::FOffMeshLink& Link = CurrentData.NavMeshGeometry.OffMeshLinks[OffMeshLineIndex];
				const bool bLinkValid = (Link.ValidEnds & FRecastDebugGeometry::OMLE_Left) && (Link.ValidEnds & FRecastDebugGeometry::OMLE_Right);

				if (NavMesh->bDrawFailedNavLinks || (NavMesh->bDrawNavLinks && bLinkValid))
				{
					const FVector V0 = Link.Left + CurrentData.NavMeshDrawOffset;
					const FVector V1 = Link.Right + CurrentData.NavMeshDrawOffset;
					const FColor LinkColor = ((Link.Direction && Link.ValidEnds) || (Link.ValidEnds & FRecastDebugGeometry::OMLE_Left)) ? DarkenColor(CurrentData.NavMeshColors[Link.AreaID]) : NavMeshRenderColor_OffMeshConnectionInvalid;

					CacheArc(CurrentData.NavLinkLines, V0, V1, 0.4f, 4, LinkColor, LinkLines_LineThickness);

					const FVector VOffset(0, 0, FVector::Dist(V0, V1) * 1.333f);
					CacheArrowHead(CurrentData.NavLinkLines, V1, V0+VOffset, 30.f, LinkColor, LinkLines_LineThickness);
					if (Link.Direction)
					{
						CacheArrowHead(CurrentData.NavLinkLines, V0, V1+VOffset, 30.f, LinkColor, LinkLines_LineThickness);
					}

					// if the connection as a whole is valid check if there are any of ends is invalid
					if (LinkColor != NavMeshRenderColor_OffMeshConnectionInvalid)
					{
						if (Link.Direction && (Link.ValidEnds & FRecastDebugGeometry::OMLE_Left) == 0)
						{
							// left end invalid - mark it
							DrawWireCylinder(CurrentData.NavLinkLines, V0, FVector(1,0,0), FVector(0,1,0), FVector(0,0,1), NavMeshRenderColor_OffMeshConnectionInvalid, Link.Radius, NavMesh->AgentMaxStepHeight, 16, 0, DefaultEdges_LineThickness);
						}
						if ((Link.ValidEnds & FRecastDebugGeometry::OMLE_Right) == 0)
						{
							DrawWireCylinder(CurrentData.NavLinkLines, V1, FVector(1,0,0), FVector(0,1,0), FVector(0,0,1), NavMeshRenderColor_OffMeshConnectionInvalid, Link.Radius, NavMesh->AgentMaxStepHeight, 16, 0, DefaultEdges_LineThickness);
						}
					}
				}					
			}
		}

		if (NavMesh->bDrawTileLabels || NavMesh->bDrawPolygonLabels || NavMesh->bDrawDefaultPolygonCost || NavMesh->bDrawTileBounds)
		{
			// calculate appropriate points for displaying debug labels
			const int32 TilesCount = NavMesh->GetNavMeshTilesCount();
			CurrentData.DebugLabels.Reserve(TilesCount);

			for (int32 TileIndex = 0; TileIndex < TilesCount; ++TileIndex)
			{
				int32 X, Y, Layer;
				if (NavMesh->GetNavMeshTileXY(TileIndex, X, Y, Layer))
				{
					const FBox TileBoundingBox = NavMesh->GetNavMeshTileBounds(TileIndex);
					FVector TileLabelLocation = TileBoundingBox.GetCenter();
					TileLabelLocation.Z = TileBoundingBox.Max.Z;

					FNavLocation NavLocation(TileLabelLocation);
					if (!NavMesh->ProjectPoint(TileLabelLocation, NavLocation, FVector(NavMesh->TileSizeUU/100, NavMesh->TileSizeUU/100, TileBoundingBox.Max.Z-TileBoundingBox.Min.Z)))
					{
						NavMesh->ProjectPoint(TileLabelLocation, NavLocation, FVector(NavMesh->TileSizeUU/2, NavMesh->TileSizeUU/2, TileBoundingBox.Max.Z-TileBoundingBox.Min.Z));
					}

					if (NavMesh->bDrawTileLabels)
					{
						CurrentData.DebugLabels.Add(FNavMeshSceneProxyData::FDebugText(
							/*Location*/NavLocation.Location + CurrentData.NavMeshDrawOffset
							, /*Text*/FString::Printf(TEXT("(%d,%d:%d)"), X, Y, Layer)
							));
					}

					if (NavMesh->bDrawPolygonLabels || NavMesh->bDrawDefaultPolygonCost)
					{
						TArray<FNavPoly> Polys;
						NavMesh->GetPolysInTile(TileIndex, Polys);

						if (NavMesh->bDrawDefaultPolygonCost)
						{
							float DefaultCosts[RECAST_MAX_AREAS];
							float FixedCosts[RECAST_MAX_AREAS];

							NavMesh->GetDefaultQueryFilter()->GetAllAreaCosts(DefaultCosts, FixedCosts, RECAST_MAX_AREAS);

							for(int k = 0; k < Polys.Num(); ++k)
							{
								uint32 AreaID = NavMesh->GetPolyAreaID(Polys[k].Ref);

								CurrentData.DebugLabels.Add(FNavMeshSceneProxyData::FDebugText(
									/*Location*/Polys[k].Center + CurrentData.NavMeshDrawOffset
									, /*Text*/FString::Printf(TEXT("\\%.3f; %.3f\\"), DefaultCosts[AreaID], FixedCosts[AreaID])
									));
							}
						}
						else
						{
							for(int k = 0; k < Polys.Num(); ++k)
							{
								uint32 NavPolyIndex = 0;
								uint32 NavTileIndex = 0;
								NavMesh->GetPolyTileIndex(Polys[k].Ref, NavPolyIndex, NavTileIndex);

								CurrentData.DebugLabels.Add(FNavMeshSceneProxyData::FDebugText(
									/*Location*/Polys[k].Center + CurrentData.NavMeshDrawOffset
									, /*Text*/FString::Printf(TEXT("[%X:%X]"), NavTileIndex, NavPolyIndex)
									));
							}
						}
					}							

					if (NavMesh->bDrawTileBounds)
					{
						FBox TileBox = NavMesh->GetNavMeshTileBounds(TileIndex);

						float DrawZ = (TileBox.Min.Z + TileBox.Max.Z) * 0.5f;		// @hack average
						FVector LL(TileBox.Min.X, TileBox.Min.Y, DrawZ);
						FVector UR(TileBox.Max.X, TileBox.Max.Y, DrawZ);
						FVector UL(LL.X, UR.Y, DrawZ);
						FVector LR(UR.X, LL.Y, DrawZ);
						CurrentData.ThickLineItems.Add(FNavMeshSceneProxyData::FDebugThickLine(LL, UL, NavMeshRenderColor_TileBounds, DefaultEdges_LineThickness));
						CurrentData.ThickLineItems.Add(FNavMeshSceneProxyData::FDebugThickLine(UL, UR, NavMeshRenderColor_TileBounds, DefaultEdges_LineThickness));
						CurrentData.ThickLineItems.Add(FNavMeshSceneProxyData::FDebugThickLine(UR, LR, NavMeshRenderColor_TileBounds, DefaultEdges_LineThickness));
						CurrentData.ThickLineItems.Add(FNavMeshSceneProxyData::FDebugThickLine(LR, LL, NavMeshRenderColor_TileBounds, DefaultEdges_LineThickness));
					}
				}
			}
		}

		CurrentData.bSkipDistanceCheck = GIsEditor && (GEngine->GetDebugLocalPlayer() == NULL);
		CurrentData.bDrawClusters = NavMesh->bDrawClusters;
		NavMesh->FinishBatchQuery();

		// Draw Mesh
		if (NavMesh->bDrawFilledPolys)
		{
			if (NavMesh->bDrawClusters)
			{
				for (int32 Idx = 0; Idx < CurrentData.NavMeshGeometry.Clusters.Num(); ++Idx)
				{
					const TArray<int32>& MeshIndices = CurrentData.NavMeshGeometry.Clusters[Idx].MeshIndices;

					if (MeshIndices.Num() == 0)
					{
						continue;
					}

					FNavMeshSceneProxyData::FDebugMeshData DebugMeshData;
					DebugMeshData.ClusterColor = GetClusterColor(Idx);
					for (int32 VertIdx = 0; VertIdx < MeshVerts.Num(); ++VertIdx)
					{
						AddVertexHelper(DebugMeshData, MeshVerts[VertIdx] + CurrentData.NavMeshDrawOffset, DebugMeshData.ClusterColor);
					}
					for (int32 TriIdx = 0; TriIdx < MeshIndices.Num(); TriIdx += 3)
					{
						AddTriangleHelper(DebugMeshData, MeshIndices[TriIdx], MeshIndices[TriIdx + 1], MeshIndices[TriIdx + 2]);
					}

					CurrentData.MeshBuilders.Add(DebugMeshData);
				}
			}
			else if (NavMesh->bDrawNavMesh)
			{
				for (int32 AreaType = 0; AreaType < RECAST_MAX_AREAS; ++AreaType)
				{
					const TArray<int32>& MeshIndices = CurrentData.NavMeshGeometry.AreaIndices[AreaType];

					if (MeshIndices.Num() == 0)
					{
						continue;
					}

					FNavMeshSceneProxyData::FDebugMeshData DebugMeshData;
					for (int32 VertIdx = 0; VertIdx < MeshVerts.Num(); ++VertIdx)
					{
						AddVertexHelper(DebugMeshData, MeshVerts[VertIdx] + CurrentData.NavMeshDrawOffset, CurrentData.NavMeshColors[AreaType]);
					}
					for (int32 TriIdx = 0; TriIdx < MeshIndices.Num(); TriIdx += 3)
					{
						AddTriangleHelper(DebugMeshData, MeshIndices[TriIdx], MeshIndices[TriIdx + 1], MeshIndices[TriIdx + 2]);
					}

					DebugMeshData.ClusterColor = CurrentData.NavMeshColors[AreaType];
					CurrentData.MeshBuilders.Add(DebugMeshData);
				}
			}
		}

		if (NavMesh->bDrawPathCollidingGeometry)
		{
			// draw all geometry gathered in navoctree
			const FNavigationOctree* NavOctree = NavMesh->GetWorld()->GetNavigationSystem()->GetNavOctree();

			if (NavOctree)
			{
				TArray<FVector> PathCollidingGeomVerts;
				TArray <int32> PathCollidingGeomIndices;
				for (FNavigationOctree::TConstIterator<> It(*NavOctree); It.HasPendingNodes(); It.Advance())
				{
					const FNavigationOctree::FNode& Node = It.GetCurrentNode();
					for (FNavigationOctree::ElementConstIt ElementIt(Node.GetElementIt()); ElementIt; ElementIt++)
					{
						const FNavigationOctreeElement& Element = *ElementIt;
						if (Element.ShouldUseGeometry(NavMesh->GetConfig()) && Element.Data->CollisionData.Num())
						{
							const FRecastGeometryCache CachedGeometry(Element.Data->CollisionData.GetData());
							AppendGeometry(PathCollidingGeomVerts, PathCollidingGeomIndices, CachedGeometry.Verts, CachedGeometry.Header.NumVerts, CachedGeometry.Indices, CachedGeometry.Header.NumFaces);
						}
					}
					FOREACH_OCTREE_CHILD_NODE(ChildRef)
					{
						if (Node.HasChild(ChildRef))
						{
							It.PushChild(ChildRef);
						}
					}
				}
				CurrentData.PathCollidingGeomIndices = PathCollidingGeomIndices;
				for (const auto& Vertex : PathCollidingGeomVerts)
				{
					CurrentData.PathCollidingGeomVerts.Add(FDynamicMeshVertex(Vertex));
				}
			}
		}

		if (CurrentData.NavMeshGeometry.BuiltMeshIndices.Num() > 0)
		{
			FNavMeshSceneProxyData::FDebugMeshData DebugMeshData;
			for (int32 VertIdx=0; VertIdx < MeshVerts.Num(); ++VertIdx)
			{
				AddVertexHelper(DebugMeshData, MeshVerts[VertIdx] + CurrentData.NavMeshDrawOffset, NavMeshRenderColor_RecastTileBeingRebuilt);
			}
			DebugMeshData.Indices.Append(CurrentData.NavMeshGeometry.BuiltMeshIndices);
			DebugMeshData.ClusterColor = NavMeshRenderColor_RecastTileBeingRebuilt;
			CurrentData.MeshBuilders.Add(DebugMeshData);

			// updates should be requested by FRecastNavMeshGenerator::TickAsyncBuild after tiles were refreshed
		}

		if (NavMesh->bDrawClusters)
		{
			for (int i = 0; i < CurrentData.NavMeshGeometry.ClusterLinks.Num(); i++)
			{
				const FRecastDebugGeometry::FClusterLink& CLink = CurrentData.NavMeshGeometry.ClusterLinks[i];
				const FVector V0 = CLink.FromCluster + CurrentData.NavMeshDrawOffset;
				const FVector V1 = CLink.ToCluster + CurrentData.NavMeshDrawOffset + FVector(0,0,20.0f);

				CacheArc(CurrentData.ClusterLinkLines, V0, V1, 0.4f, 4, FColor::Black, ClusterLinkLines_LineThickness);
				const FVector VOffset(0, 0, FVector::Dist(V0, V1) * 1.333f);
				CacheArrowHead(CurrentData.ClusterLinkLines, V1, V0+VOffset, 30.f, FColor::Black, ClusterLinkLines_LineThickness);
			}
		}

		// cache segment links
		if (NavMesh->bDrawNavLinks)
		{
			for (int32 iArea = 0; iArea < RECAST_MAX_AREAS; iArea++)
			{
				const TArray<int32>& Indices = CurrentData.NavMeshGeometry.OffMeshSegmentAreas[iArea];
				FNavMeshSceneProxyData::FDebugMeshData DebugMeshData;
				int32 VertBase = 0;

				for (int32 i = 0; i < Indices.Num(); i++)
				{
					FRecastDebugGeometry::FOffMeshSegment& SegInfo = CurrentData.NavMeshGeometry.OffMeshSegments[Indices[i]];
					const FVector A0 = SegInfo.LeftStart + CurrentData.NavMeshDrawOffset;
					const FVector A1 = SegInfo.LeftEnd + CurrentData.NavMeshDrawOffset;
					const FVector B0 = SegInfo.RightStart + CurrentData.NavMeshDrawOffset;
					const FVector B1 = SegInfo.RightEnd + CurrentData.NavMeshDrawOffset;
					const FVector Edge0 = B0 - A0;
					const FVector Edge1 = B1 - A1;
					const float Len0 = Edge0.Size();
					const float Len1 = Edge1.Size();
					const FColor SegColor = DarkenColor(CurrentData.NavMeshColors[SegInfo.AreaID]);
					const FColor ColA = (SegInfo.ValidEnds & FRecastDebugGeometry::OMLE_Left) ? FColor::White : FColor::Black;
					const FColor ColB = (SegInfo.ValidEnds & FRecastDebugGeometry::OMLE_Right) ? FColor::White : FColor::Black;

					const int32 NumArcPoints = 8;
					const float ArcPtsScale = 1.0f / NumArcPoints;

					FVector Prev0 = EvalArc(A0, Edge0, Len0*0.25f, 0);
					FVector Prev1 = EvalArc(A1, Edge1, Len1*0.25f, 0);
					AddVertexHelper(DebugMeshData, Prev0, ColA);
					AddVertexHelper(DebugMeshData, Prev1, ColA);
					for (int32 j = 1; j <= NumArcPoints; j++)
					{
						const float u = j * ArcPtsScale;
						FVector Pt0 = EvalArc(A0, Edge0, Len0*0.25f, u);
						FVector Pt1 = EvalArc(A1, Edge1, Len1*0.25f, u);

						AddVertexHelper(DebugMeshData, Pt0, (j == NumArcPoints) ? ColB : FColor::White);
						AddVertexHelper(DebugMeshData, Pt1, (j == NumArcPoints) ? ColB : FColor::White);

						AddTriangleHelper(DebugMeshData, VertBase+0, VertBase+2, VertBase+1);
						AddTriangleHelper(DebugMeshData, VertBase+2, VertBase+3, VertBase+1);
						AddTriangleHelper(DebugMeshData, VertBase+0, VertBase+1, VertBase+2);
						AddTriangleHelper(DebugMeshData, VertBase+2, VertBase+1, VertBase+3);

						VertBase += 2;
						Prev0 = Pt0;
						Prev1 = Pt1;
					}
					VertBase += 2;

					DebugMeshData.ClusterColor = SegColor;
				}

				if (DebugMeshData.Indices.Num())
				{
					CurrentData.MeshBuilders.Add(DebugMeshData);
				}
			}
		}

		CurrentData.NavMeshGeometry.PolyEdges.Empty();
		CurrentData.NavMeshGeometry.NavMeshEdges.Empty();
	}