void FSpriteGeometryEditingHelper::DrawGeometry(const FSceneView& View, FPrimitiveDrawInterface& PDI, const FLinearColor& GeometryVertexColor, const FLinearColor& NegativeGeometryVertexColor) { if (GeometryBeingEdited == nullptr) { return; } FSpriteGeometryCollection& Geometry = GetGeometryChecked(); const bool bIsHitTesting = PDI.IsHitTesting(); const float UnitsPerPixel = EditorContext->SelectedItemGetUnitsPerPixel(); // Run thru the geometry shapes and draw hit proxies for them for (int32 ShapeIndex = 0; ShapeIndex < Geometry.Shapes.Num(); ++ShapeIndex) { const FSpriteGeometryShape& Shape = Geometry.Shapes[ShapeIndex]; const bool bIsShapeSelected = IsGeometrySelected(FShapeVertexPair(ShapeIndex, INDEX_NONE)); const FLinearColor LineColorRaw = Shape.bNegativeWinding ? NegativeGeometryVertexColor : GeometryVertexColor; const FLinearColor VertexColor = Shape.bNegativeWinding ? NegativeGeometryVertexColor : GeometryVertexColor; const FLinearColor LineColor = Shape.IsShapeValid() ? LineColorRaw : FMath::Lerp(LineColorRaw, FLinearColor::Red, 0.8f); // Draw the interior (allowing selection of the whole shape) if (bIsHitTesting) { TSharedPtr<FSpriteSelectedShape> Data = MakeShareable(new FSpriteSelectedShape(EditorContext, Geometry, ShapeIndex, /*bIsBackground=*/ true)); PDI.SetHitProxy(new HSpriteSelectableObjectHitProxy(Data)); } FColor BackgroundColor(bIsShapeSelected ? SpriteEditingConstantsEX::GeometrySelectedColor : LineColor); BackgroundColor.A = 4; FMaterialRenderProxy* ShapeMaterialProxy = WidgetVertexColorMaterial->GetRenderProxy(bIsShapeSelected); if (Shape.ShapeType == ESpriteShapeType::Circle) { //@TODO: This is going to have issues if we ever support ellipses const FVector2D PixelSpaceRadius = Shape.BoxSize * 0.5f; const float WorldSpaceRadius = PixelSpaceRadius.X * UnitsPerPixel; const FVector CircleCenterWorldPos = EditorContext->TextureSpaceToWorldSpace(Shape.BoxPosition); DrawDisc(&PDI, CircleCenterWorldPos, PaperAxisX, PaperAxisY, BackgroundColor, WorldSpaceRadius, SpriteEditingConstantsEX::CircleShapeNumSides, ShapeMaterialProxy, SDPG_Foreground); } else { TArray<FVector2D> SourceTextureSpaceVertices; Shape.GetTextureSpaceVertices(/*out*/ SourceTextureSpaceVertices); TArray<FVector2D> TriangulatedPolygonVertices; PaperGeomTools::TriangulatePoly(/*out*/ TriangulatedPolygonVertices, SourceTextureSpaceVertices, /*bKeepColinearVertices=*/ true); if (((TriangulatedPolygonVertices.Num() % 3) == 0) && (TriangulatedPolygonVertices.Num() > 0)) { FDynamicMeshBuilder MeshBuilder; FDynamicMeshVertex MeshVertex; MeshVertex.Color = BackgroundColor; MeshVertex.TextureCoordinate = FVector2D::ZeroVector; MeshVertex.SetTangents(PaperAxisX, PaperAxisY, PaperAxisZ); for (const FVector2D& SrcTriangleVertex : TriangulatedPolygonVertices) { MeshVertex.Position = EditorContext->TextureSpaceToWorldSpace(SrcTriangleVertex); MeshBuilder.AddVertex(MeshVertex); } for (int32 TriangleIndex = 0; TriangleIndex < TriangulatedPolygonVertices.Num(); TriangleIndex += 3) { MeshBuilder.AddTriangle(TriangleIndex, TriangleIndex + 1, TriangleIndex + 2); } MeshBuilder.Draw(&PDI, FMatrix::Identity, ShapeMaterialProxy, SDPG_Foreground); } } if (bIsHitTesting) { PDI.SetHitProxy(nullptr); } } }
void FKSphylElem::DrawElemSolid(FPrimitiveDrawInterface* PDI, const FTransform& ElemTM, float Scale, const FMaterialRenderProxy* MaterialRenderProxy) { const int32 NumSides = DrawCollisionSides; const int32 NumRings = (DrawCollisionSides/2) + 1; // The first/last arc are on top of each other. const int32 NumVerts = (NumSides+1) * (NumRings+1); FDynamicMeshVertex* Verts = (FDynamicMeshVertex*)FMemory::Malloc( NumVerts * sizeof(FDynamicMeshVertex) ); // Calculate verts for one arc FDynamicMeshVertex* ArcVerts = (FDynamicMeshVertex*)FMemory::Malloc( (NumRings+1) * sizeof(FDynamicMeshVertex) ); for(int32 RingIdx=0; RingIdx<NumRings+1; RingIdx++) { FDynamicMeshVertex* ArcVert = &ArcVerts[RingIdx]; float Angle; float ZOffset; if( RingIdx <= DrawCollisionSides/4 ) { Angle = ((float)RingIdx/(NumRings-1)) * PI; ZOffset = 0.5 * Scale * Length; } else { Angle = ((float)(RingIdx-1)/(NumRings-1)) * PI; ZOffset = -0.5 * Scale * Length; } // Note- unit sphere, so position always has mag of one. We can just use it for normal! FVector SpherePos; SpherePos.X = 0.0f; SpherePos.Y = Scale * Radius * FMath::Sin(Angle); SpherePos.Z = Scale * Radius * FMath::Cos(Angle); ArcVert->Position = SpherePos + FVector(0,0,ZOffset); ArcVert->SetTangents( FVector(1,0,0), FVector(0.0f, -SpherePos.Z, SpherePos.Y), SpherePos ); ArcVert->TextureCoordinate.X = 0.0f; ArcVert->TextureCoordinate.Y = ((float)RingIdx/NumRings); } // Then rotate this arc NumSides+1 times. for(int32 SideIdx=0; SideIdx<NumSides+1; SideIdx++) { const FRotator ArcRotator(0, 360.f * ((float)SideIdx/NumSides), 0); const FRotationMatrix ArcRot( ArcRotator ); const float XTexCoord = ((float)SideIdx/NumSides); for(int32 VertIdx=0; VertIdx<NumRings+1; VertIdx++) { int32 VIx = (NumRings+1)*SideIdx + VertIdx; Verts[VIx].Position = ArcRot.TransformPosition( ArcVerts[VertIdx].Position ); Verts[VIx].SetTangents( ArcRot.TransformVector( ArcVerts[VertIdx].TangentX ), ArcRot.TransformVector( ArcVerts[VertIdx].GetTangentY() ), ArcRot.TransformVector( ArcVerts[VertIdx].TangentZ ) ); Verts[VIx].TextureCoordinate.X = XTexCoord; Verts[VIx].TextureCoordinate.Y = ArcVerts[VertIdx].TextureCoordinate.Y; } } FDynamicMeshBuilder MeshBuilder; { // Add all of the vertices to the mesh. for(int32 VertIdx=0; VertIdx<NumVerts; VertIdx++) { MeshBuilder.AddVertex(Verts[VertIdx]); } // Add all of the triangles to the mesh. for(int32 SideIdx=0; SideIdx<NumSides; SideIdx++) { const int32 a0start = (SideIdx+0) * (NumRings+1); const int32 a1start = (SideIdx+1) * (NumRings+1); for(int32 RingIdx=0; RingIdx<NumRings; RingIdx++) { MeshBuilder.AddTriangle(a0start + RingIdx + 0, a1start + RingIdx + 0, a0start + RingIdx + 1); MeshBuilder.AddTriangle(a1start + RingIdx + 0, a1start + RingIdx + 1, a0start + RingIdx + 1); } } } MeshBuilder.Draw(PDI, ElemTM.ToMatrixWithScale(), MaterialRenderProxy, SDPG_World,0.f); FMemory::Free(Verts); FMemory::Free(ArcVerts); }
void FEdModeGeometry::RenderPoly( const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI ) { for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx ) { const FGeomObject* GeomObject = GeomObjects[ObjectIdx]; FLinearColor UnselectedColor = GeomObject->GetActualBrush()->GetWireColor(); UnselectedColor.A = .1f; FLinearColor SelectedColor = GetDefault<UEditorStyleSettings>()->SelectionColor; SelectedColor.A = .5f; // Allocate the material proxy and register it so it can be deleted properly once the rendering is done with it. FDynamicColoredMaterialRenderProxy* SelectedColorInstance = new FDynamicColoredMaterialRenderProxy(GEngine->GeomMaterial->GetRenderProxy(false),SelectedColor ); PDI->RegisterDynamicResource( SelectedColorInstance ); FDynamicColoredMaterialRenderProxy* UnselectedColorInstance = new FDynamicColoredMaterialRenderProxy(GEngine->GeomMaterial->GetRenderProxy(false),UnselectedColor); PDI->RegisterDynamicResource( UnselectedColorInstance ); // Render selected filled polygons. for( int32 PolyIdx = 0 ; PolyIdx < GeomObject->PolyPool.Num() ; ++PolyIdx ) { const FGeomPoly* GeomPoly = &GeomObject->PolyPool[PolyIdx]; PDI->SetHitProxy( new HGeomPolyProxy(const_cast<FGeomObject*>(GeomPoly->GetParentObject()),PolyIdx) ); { FDynamicMeshBuilder MeshBuilder; TArray<FVector> Verts; // Look at the edge list and create a list of vertices to render from. FVector LastPos(0); for( int32 EdgeIdx = 0 ; EdgeIdx < GeomPoly->EdgeIndices.Num() ; ++EdgeIdx ) { const FGeomEdge* GeomEdge = &GeomPoly->GetParentObject()->EdgePool[ GeomPoly->EdgeIndices[EdgeIdx] ]; if( EdgeIdx == 0 ) { Verts.Add( GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ] ); LastPos = GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ]; } else if( GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ].Equals( LastPos ) ) { Verts.Add( GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[1] ] ); LastPos = GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[1] ]; } else { Verts.Add( GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ] ); LastPos = GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ]; } } // Draw Polygon Triangles const int32 VertexOffset = MeshBuilder.AddVertex(Verts[0], FVector2D::ZeroVector, FVector(1,0,0), FVector(0,1,0), FVector(0,0,1), FColor(255,255,255)); MeshBuilder.AddVertex(Verts[1], FVector2D::ZeroVector, FVector(1,0,0), FVector(0,1,0), FVector(0,0,1), FColor(255,255,255)); for( int32 VertIdx = 2 ; VertIdx < Verts.Num() ; ++VertIdx ) { MeshBuilder.AddVertex(Verts[VertIdx], FVector2D::ZeroVector, FVector(1,0,0), FVector(0,1,0), FVector(0,0,1), FColor(255,255,255)); MeshBuilder.AddTriangle( VertexOffset + VertIdx - 1, VertexOffset, VertexOffset + VertIdx); } if( GeomPoly->IsSelected() ) { MeshBuilder.Draw(PDI, GeomObject->GetActualBrush()->ActorToWorld().ToMatrixWithScale(), SelectedColorInstance, SDPG_World, false ); } else { // We only draw unselected polygons in the perspective viewport if( !Viewport->GetClient()->IsOrtho() ) { // Unselected polygons are drawn at the world level but are bumped slightly forward to avoid z-fighting MeshBuilder.Draw(PDI, GeomObject->GetActualBrush()->ActorToWorld().ToMatrixWithScale(), UnselectedColorInstance, SDPG_World, false ); } } } PDI->SetHitProxy( NULL ); } } }