void FNiagaraEditor::DeleteSelectedNodes() { TSharedPtr<SGraphEditor> CurrentGraphEditor = NodeGraphEditorPtr.Pin(); if (!CurrentGraphEditor.IsValid()) { return; } const FScopedTransaction Transaction(FGenericCommands::Get().Delete->GetDescription()); CurrentGraphEditor->GetCurrentGraph()->Modify(); const FGraphPanelSelectionSet SelectedNodes = CurrentGraphEditor->GetSelectedNodes(); CurrentGraphEditor->ClearSelectionSet(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { if (UEdGraphNode* Node = Cast<UEdGraphNode>(*NodeIt)) { if (Node->CanUserDeleteNode()) { Node->Modify(); Node->DestroyNode(); } } } }
void FSoundCueEditor::SyncInBrowser() { TArray<UObject*> ObjectsToSync; const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { USoundCueGraphNode* SelectedNode = Cast<USoundCueGraphNode>(*NodeIt); if (SelectedNode) { USoundNodeWavePlayer* SelectedWave = Cast<USoundNodeWavePlayer>(SelectedNode->SoundNode); if (SelectedWave && SelectedWave->GetSoundWave()) { ObjectsToSync.AddUnique(SelectedWave->GetSoundWave()); } //ObjectsToSync.AddUnique(SelectedNode->SoundNode); } } if (ObjectsToSync.Num() > 0) { GEditor->SyncBrowserToObjects(ObjectsToSync); } }
FBoxSphereBounds UNavMeshRenderingComponent::CalcBounds(const FTransform& LocalToWorld) const { FBox BoundingBox(0); #if WITH_RECAST ARecastNavMesh* NavMesh = Cast<ARecastNavMesh>(GetOwner()); if (NavMesh) { BoundingBox = NavMesh->GetNavMeshBounds(); 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 FOctreeNodeContext& CorrentContext = NodeIt.GetCurrentContext(); BoundingBox += CorrentContext.Bounds.GetBox(); } } } } #endif return FBoxSphereBounds(BoundingBox); }
void FSoundCueEditor::PlayNode() { // already checked that only one node is selected const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { PlaySingleNode(CastChecked<UEdGraphNode>(*NodeIt)); } }
void SGraphEditorImpl::ReconstructNodes() { const UEdGraphSchema* Schema = this->EdGraphObj->GetSchema(); for (FGraphPanelSelectionSet::TConstIterator NodeIt( GraphPanel->SelectionManager.GetSelectedNodes() ); NodeIt; ++NodeIt) { if (UEdGraphNode* Node = Cast<UEdGraphNode>(*NodeIt)) { Schema->ReconstructNode(*Node); } } NotifyGraphChanged(); }
void SGraphEditorImpl::BreakNodeLinks() { const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "GraphEd_BreakNodeLinks", "Break Node Links") ); for (FGraphPanelSelectionSet::TConstIterator NodeIt( GraphPanel->SelectionManager.GetSelectedNodes() ); NodeIt; ++NodeIt) { if (UEdGraphNode* Node = Cast<UEdGraphNode>(*NodeIt)) { const UEdGraphSchema* Schema = Node->GetSchema(); Schema->BreakNodeLinks(*Node); } } }
void SGraphPanel::UpdateSelectedNodesPositions (FVector2D PositionIncrement) { for (FGraphPanelSelectionSet::TIterator NodeIt(SelectionManager.SelectedNodes); NodeIt; ++NodeIt) { TSharedRef<SNode>* pWidget = NodeToWidgetLookup.Find(*NodeIt); if (pWidget != NULL) { SNode& Widget = pWidget->Get(); SNode::FNodeSet NodeFilter; Widget.MoveTo(Widget.GetPosition() + PositionIncrement, NodeFilter); } } }
void UK2Node_MacroInstance::AllocateDefaultPins() { UK2Node::AllocateDefaultPins(); PreloadObject(MacroGraphReference.GetBlueprint()); UEdGraph* MacroGraph = MacroGraphReference.GetGraph(); if (MacroGraph != NULL) { PreloadObject(MacroGraph); // Preload the macro graph, if needed, so that we can get the proper pins if (MacroGraph->HasAnyFlags(RF_NeedLoad)) { PreloadObject(MacroGraph); FBlueprintEditorUtils::PreloadMembers(MacroGraph); } for (TArray<UEdGraphNode*>::TIterator NodeIt(MacroGraph->Nodes); NodeIt; ++NodeIt) { if (UK2Node_Tunnel* TunnelNode = Cast<UK2Node_Tunnel>(*NodeIt)) { // Only want exact tunnel nodes, more specific nodes like composites or macro instances shouldn't be grabbed. if (TunnelNode->GetClass() == UK2Node_Tunnel::StaticClass()) { for (TArray<UEdGraphPin*>::TIterator PinIt(TunnelNode->Pins); PinIt; ++PinIt) { UEdGraphPin* PortPin = *PinIt; // We're not interested in any pins that have been expanded internally on the macro if (PortPin->ParentPin == NULL) { UEdGraphPin* NewLocalPin = CreatePin( UEdGraphPin::GetComplementaryDirection(PortPin->Direction), PortPin->PinType.PinCategory, PortPin->PinType.PinSubCategory, PortPin->PinType.PinSubCategoryObject.Get(), PortPin->PinType.bIsArray, PortPin->PinType.bIsReference, PortPin->PinName); NewLocalPin->DefaultValue = NewLocalPin->AutogeneratedDefaultValue = PortPin->DefaultValue; } } } } } } }
void FSoundCueEditor::AddInput() { const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); // Iterator used but should only contain one node for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { USoundCueGraphNode* SelectedNode = Cast<USoundCueGraphNode>(*NodeIt); if (SelectedNode) { SelectedNode->AddInputPin(); break; } } }
bool FSoundClassEditor::CanRemoveNodes() const { const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { USoundClassGraphNode* Node = Cast<USoundClassGraphNode>(*NodeIt); if (Node && Node->CanUserDeleteNode()) { return true; } } return false; }
void USoundClassGraph::RecursivelyRemoveNodes(const TSet<class UObject*> NodesToRemove) { Modify(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(NodesToRemove); NodeIt; ++NodeIt) { USoundClassGraphNode* Node = Cast<USoundClassGraphNode>(*NodeIt); if (Node && Node->CanUserDeleteNode()) { RecursivelyRemoveNode(Node); } } LinkSoundClasses(); }
bool FSoundCueEditor::CanDeleteNodes() const { const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); if (SelectedNodes.Num() == 1) { for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { if (Cast<USoundCueGraphNode_Root>(*NodeIt)) { // Return false if only root node is selected, as it can't be deleted return false; } } } return SelectedNodes.Num() > 0; }
bool FSoundCueEditor::CanSyncInBrowser() const { const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { USoundCueGraphNode* SelectedNode = Cast<USoundCueGraphNode>(*NodeIt); if (SelectedNode) { USoundNodeWavePlayer* WavePlayer = Cast<USoundNodeWavePlayer>(SelectedNode->SoundNode); if (WavePlayer && WavePlayer->GetSoundWave()) { return true; } } } return false; }
void FNiagaraEditor::DeleteSelectedNodes() { TSharedPtr<SGraphEditor> NodeGraphEditor = NodeGraphEditorPtr.Pin(); if (!NodeGraphEditor.IsValid()) { return; } const FGraphPanelSelectionSet SelectedNodes = NodeGraphEditor->GetSelectedNodes(); NodeGraphEditor->ClearSelectionSet(); for (FGraphPanelSelectionSet::TConstIterator NodeIt( SelectedNodes ); NodeIt; ++NodeIt) { if (UEdGraphNode* Node = Cast<UEdGraphNode>(*NodeIt)) { if (Node->CanUserDeleteNode()) { Node->DestroyNode(); } } } }
// Exports a set of nodes to text void FEdGraphUtilities::ExportNodesToText(TSet<UObject*> NodesToExport, /*out*/ FString& ExportedText) { // Clear the mark state for saving. UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp)); FStringOutputDevice Archive; const FExportObjectInnerContext Context; // Export each of the selected nodes UObject* LastOuter = NULL; for (TSet<UObject*>::TConstIterator NodeIt(NodesToExport); NodeIt; ++NodeIt) { UObject* Node = *NodeIt; // The nodes should all be from the same scope UObject* ThisOuter = Node->GetOuter(); check((LastOuter == ThisOuter) || (LastOuter == NULL)); LastOuter = ThisOuter; UExporter::ExportToOutputDevice(&Context, Node, NULL, Archive, TEXT("copy"), 0, PPF_ExportsNotFullyQualified|PPF_Copy|PPF_Delimited, false, ThisOuter); } ExportedText = Archive; }
void FSoundCueEditor::DeleteSelectedNodes() { const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "SoundCueEditorDeleteSelectedNode", "Delete Selected Sound Cue Node") ); SoundCueGraphEditor->GetCurrentGraph()->Modify(); const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); SoundCueGraphEditor->ClearSelectionSet(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { UEdGraphNode* Node = CastChecked<UEdGraphNode>(*NodeIt); if (Node->CanUserDeleteNode()) { if (USoundCueGraphNode* SoundGraphNode = Cast<USoundCueGraphNode>(Node)) { USoundNode* DelNode = SoundGraphNode->SoundNode; FBlueprintEditorUtils::RemoveNode(NULL, SoundGraphNode, true); // Make sure SoundCue is updated to match graph SoundCue->CompileSoundNodesFromGraphNodes(); // Remove this node from the SoundCue's list of all SoundNodes SoundCue->AllNodes.Remove(DelNode); SoundCue->MarkPackageDirty(); } else { FBlueprintEditorUtils::RemoveNode(NULL, Node, true); } } } }
void UNavMeshRenderingComponent::GatherData(struct FNavMeshSceneProxyData* CurrentData) const { #if WITH_RECAST const ARecastNavMesh* NavMesh = Cast<ARecastNavMesh>(GetOwner()); CurrentData->Reset(); CurrentData->bEnableDrawing = NavMesh->bEnableDrawing; CurrentData->bNeedsNewData = false; if (CurrentData && NavMesh && NavMesh->bEnableDrawing) { 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->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(); 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->NavDataConfig) && 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(); }
// Called every frame void ASpacePartioner::Tick( float DeltaTime ) { Super::Tick( DeltaTime ); //check(bInitialized); //check(bDrawDebugInfo); if (bInitialized && bDrawDebugInfo) { int level = 0; float max; float offsetMax; float offset; FVector maxExtent; FVector center; FVector tempForCoercion; FBoxCenterAndExtent OldBounds = FBoxCenterAndExtent(); int nodeCount = 0; int elementCount = 0; // Go through the nodes of the octree for (FSimpleOctree::TConstIterator<> NodeIt(*OctreeData); NodeIt.HasPendingNodes(); NodeIt.Advance()) { const FSimpleOctree::FNode& CurrentNode = NodeIt.GetCurrentNode(); const FOctreeNodeContext& CurrentContext = NodeIt.GetCurrentContext(); const FBoxCenterAndExtent& CurrentBounds = CurrentContext.Bounds; nodeCount++; FOREACH_OCTREE_CHILD_NODE(ChildRef) { if (CurrentNode.HasChild(ChildRef)) { NodeIt.PushChild(ChildRef); } } // If the extents have changed then we have moved a level. if (!OldBounds.Extent.Equals(CurrentBounds.Extent)) { level++; } OldBounds = CurrentBounds; // UE_LOG(LogTemp, Log, TEXT("Level: %d"), level); // Draw Node Bounds tempForCoercion = CurrentBounds.Extent; max = tempForCoercion.GetMax(); center = CurrentBounds.Center; // UE_LOG(LogTemp, Log, TEXT("center before: %s"), *center.ToString()); // To understand the math here check out the constructors in FOctreeNodeContext // Offset nodes that are not the root bounds if (!OctreeData->GetRootBounds().Extent.Equals(CurrentBounds.Extent)) { for (int i = 1; i < level; i++) { // Calculate offset offsetMax = max / (1.0f + (1.0f / FOctreeNodeContext::LoosenessDenominator)); offset = max - offsetMax; max = offsetMax; // Calculate Center Offset if (center.X > 0) { center.X = center.X + offset; } else { center.X = center.X - offset; } if (center.Y > 0) { center.Y = center.Y + offset; } else { center.Y = center.Y - offset; } if (center.Z > 0) { center.Z = center.Z + offset; } else { center.Z = center.Z - offset; } } } UE_LOG(LogTemp, Log, TEXT("max: %f"), max); // UE_LOG(LogTemp, Log, TEXT("center of nodes: %s"), *center.ToString()); maxExtent = FVector(max, max, max); // UE_LOG(LogTemp, Log, TEXT("Extent of nodes: %s"), *tempForCoercion.ToString()); DrawDebugBox(GetWorld(), center, maxExtent, FColor().Blue, false, 0.0f); DrawDebugSphere(GetWorld(), center + maxExtent, 4.0f, 12, FColor().Green, false, 0.0f); DrawDebugSphere(GetWorld(), center - maxExtent, 4.0f, 12, FColor().Red, false, 0.0f); for (FSimpleOctree::ElementConstIt ElementIt(CurrentNode.GetElementIt()); ElementIt; ++ElementIt) { const FOctreeElement& Sample = *ElementIt; // Draw debug boxes around elements max = Sample.BoxSphereBounds.BoxExtent.GetMax(); maxExtent = FVector(max, max, max); center = Sample.MyActor->GetActorLocation(); DrawDebugBox(GetWorld(), center, maxExtent, FColor().Blue, false, 0.0f); DrawDebugSphere(GetWorld(), center + maxExtent, 4.0f, 12, FColor().White, false, 0.0f); DrawDebugSphere(GetWorld(), center - maxExtent, 4.0f, 12, FColor().White, false, 0.0f); elementCount++; } } // UE_LOG(LogTemp, Log, TEXT("Node Count: %d, Element Count: %d"), nodeCount, elementCount); }
FArchive& operator<<(FArchive& Ar,FPrecomputedLightVolume& Volume) { if (Ar.IsCountingMemory()) { const int32 AllocatedBytes = Volume.GetAllocatedBytes(); Ar.CountBytes(AllocatedBytes, AllocatedBytes); } else if (Ar.IsLoading()) { Ar << Volume.bInitialized; if (Volume.bInitialized) { FBox Bounds; Ar << Bounds; float SampleSpacing = 0.0f; Ar << SampleSpacing; Volume.Initialize(Bounds); TArray<FVolumeLightingSample> HighQualitySamples; // Deserialize samples as an array, and add them to the octree Ar << HighQualitySamples; if (FPlatformProperties::SupportsHighQualityLightmaps() && (GIsEditor || AllowHighQualityLightmaps(GMaxRHIFeatureLevel))) { for(int32 SampleIndex = 0; SampleIndex < HighQualitySamples.Num(); SampleIndex++) { Volume.AddHighQualityLightingSample(HighQualitySamples[SampleIndex]); } } TArray<FVolumeLightingSample> LowQualitySamples; if (Ar.UE4Ver() >= VER_UE4_VOLUME_SAMPLE_LOW_QUALITY_SUPPORT) { Ar << LowQualitySamples; } if (FPlatformProperties::SupportsLowQualityLightmaps() && (GIsEditor || !AllowHighQualityLightmaps(GMaxRHIFeatureLevel))) { for(int32 SampleIndex = 0; SampleIndex < LowQualitySamples.Num(); SampleIndex++) { Volume.AddLowQualityLightingSample(LowQualitySamples[SampleIndex]); } } Volume.FinalizeSamples(); } } else if (Ar.IsSaving()) { Ar << Volume.bInitialized; if (Volume.bInitialized) { Ar << Volume.Bounds; float SampleSpacing = 0.0f; Ar << SampleSpacing; TArray<FVolumeLightingSample> HighQualitySamples; if (!Ar.IsCooking() || Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::HighQualityLightmaps)) { // Gather an array of samples from the octree for(FLightVolumeOctree::TConstIterator<> NodeIt(Volume.HighQualityLightmapOctree); NodeIt.HasPendingNodes(); NodeIt.Advance()) { const FLightVolumeOctree::FNode& CurrentNode = NodeIt.GetCurrentNode(); FOREACH_OCTREE_CHILD_NODE(ChildRef) { if(CurrentNode.HasChild(ChildRef)) { NodeIt.PushChild(ChildRef); } } for (FLightVolumeOctree::ElementConstIt ElementIt(CurrentNode.GetElementIt()); ElementIt; ++ElementIt) { const FVolumeLightingSample& Sample = *ElementIt; HighQualitySamples.Add(Sample); } } } Ar << HighQualitySamples; TArray<FVolumeLightingSample> LowQualitySamples; if (!Ar.IsCooking() || Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::LowQualityLightmaps)) { // Gather an array of samples from the octree for(FLightVolumeOctree::TConstIterator<> NodeIt(Volume.LowQualityLightmapOctree); NodeIt.HasPendingNodes(); NodeIt.Advance()) { const FLightVolumeOctree::FNode& CurrentNode = NodeIt.GetCurrentNode(); FOREACH_OCTREE_CHILD_NODE(ChildRef) { if(CurrentNode.HasChild(ChildRef)) { NodeIt.PushChild(ChildRef); } } for (FLightVolumeOctree::ElementConstIt ElementIt(CurrentNode.GetElementIt()); ElementIt; ++ElementIt) { const FVolumeLightingSample& Sample = *ElementIt; LowQualitySamples.Add(Sample); } } } Ar << LowQualitySamples; }