Example #1
0
//------------------------------------------------------------------------------
int32 FDeferredScriptTracker::ResolveDeferredScripts(ULinkerLoad* Linker)
{
	FArchive& Ar = *Linker;
	if (FStructScriptLoader::ShouldDeferScriptSerialization(Ar))
	{
		return 0;
	}

#if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
	TGuardValue<ULinkerLoad*> ScopedResolvingLinker(ResolvingLinker, Linker);
#endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS

	TArray<FDeferredScriptLoader> DefferedLinkerScripts;
	DeferredScriptLoads.MultiFind(Linker, DefferedLinkerScripts);
	// remove before we resolve, because a failed call to 
	// FDeferredScriptLoader::Resolve() could insert back into this list 
	DeferredScriptLoads.Remove(Linker);

	int32 const SerializationPosToRestore = Ar.Tell();

	int32 ResolveCount = 0;
	for (FDeferredScriptLoader& DeferredScript : DefferedLinkerScripts)
	{
		if (DeferredScript.Resolve(Ar))
		{
			++ResolveCount;
		}
	}

	Ar.Seek(SerializationPosToRestore);
	return ResolveCount;
}
void USceneCaptureComponentCube::UpdateDeferredCaptures( FSceneInterface* Scene )
{
	UWorld* World = Scene->GetWorld();
	
	if( World && CubedSceneCapturesToUpdateMap.Num() > 0 )
	{
		World->SendAllEndOfFrameUpdates();
		// Only update the scene captures associated with the current scene.
		// Updating others not associated with the scene would cause invalid data to be rendered into the target
		TArray< TWeakObjectPtr<USceneCaptureComponentCube> > SceneCapturesToUpdate;
		CubedSceneCapturesToUpdateMap.MultiFind( World, SceneCapturesToUpdate );
		
		for( TWeakObjectPtr<USceneCaptureComponentCube> Component : SceneCapturesToUpdate )
		{
			if( Component.IsValid() )
			{
				Scene->UpdateSceneCaptureContents( Component.Get() );
			}
		}
		
		// All scene captures for this world have been updated
		CubedSceneCapturesToUpdateMap.Remove( World );
	}

}
void USceneCaptureComponent2D::UpdateDeferredCaptures( FSceneInterface* Scene )
{
	UWorld* World = Scene->GetWorld();
	if( World && SceneCapturesToUpdateMap.Num() > 0 )
	{
		// Only update the scene captures assoicated with the current scene.
		// Updating others not associated with the scene would cause invalid data to be rendered into the target
		TArray<USceneCaptureComponent2D*> SceneCapturesToUpdate;
		SceneCapturesToUpdateMap.MultiFind( World, SceneCapturesToUpdate );
		
		for( USceneCaptureComponent2D* Component : SceneCapturesToUpdate )
		{
			Scene->UpdateSceneCaptureContents( Component );
		}
		
		// All scene captures for this world have been updated
		SceneCapturesToUpdateMap.Remove( World) ;
	}
}
/**
 * Loads all of the UClass-es used by code so we can search for commandlets
 */
static void LoadAllClasses(void)
{
	TArray<FString> ScriptPackageNames;
	TMultiMap<FString,FString>* Sec = GConfig->GetSectionPrivate( TEXT("UnrealEd.EditorEngine"), 0, 1, GEngineIni );
	if (Sec != NULL)
	{
		// Get the list of all code packages
		Sec->MultiFind( FString(TEXT("EditPackages")), ScriptPackageNames );
		// Iterate through loading each package
		for (INT Index = 0; Index < ScriptPackageNames.Num(); Index++)
		{
			// Loading without LOAD_Verify should load all objects
			UPackage* Package = UObject::LoadPackage(NULL,*ScriptPackageNames(Index),LOAD_NoWarn | LOAD_Quiet);
			if (Package == NULL)
			{
				warnf(TEXT("Error loading package %s"),*ScriptPackageNames(Index));
			}
		}
	}
	else
	{
		warnf(TEXT("Error finding the code packages"));
	}
}
void URuntimeMeshLibrary::CalculateTangentsForMesh(TFunction<int32(int32 Index)> IndexAccessor, TFunction<FVector(int32 Index)> VertexAccessor, TFunction<FVector2D(int32 Index)> UVAccessor,
	TFunction<void(int32 Index, FVector TangentX, FVector TangentY, FVector TangentZ)> TangentSetter, int32 NumVertices, int32 NumUVs, int32 NumIndices, bool bCreateSmoothNormals)
{
	SCOPE_CYCLE_COUNTER(STAT_RuntimeMeshLibrary_CalculateTangentsForMesh);

	if (NumVertices == 0 || NumIndices == 0)
	{
		return;
	}

	// Calculate the duplicate vertices map if we're wanting smooth normals.  Don't find duplicates if we don't want smooth normals
	// that will cause it to only smooth across faces sharing a common vertex, not across faces with vertices of common position
	const TMultiMap<uint32, uint32> DuplicateVertexMap = bCreateSmoothNormals ? FRuntimeMeshInternalUtilities::FindDuplicateVerticesMap(VertexAccessor, NumVertices) : TMultiMap<uint32, uint32>();


	// Number of triangles
	const int32 NumTris = NumIndices / 3;

	// Map of vertex to triangles in Triangles array
	TMultiMap<uint32, uint32> VertToTriMap;
	// Map of vertex to triangles to consider for normal calculation
	TMultiMap<uint32, uint32> VertToTriSmoothMap;

	// Normal/tangents for each face
	TArray<FVector> FaceTangentX, FaceTangentY, FaceTangentZ;
	FaceTangentX.AddUninitialized(NumTris);
	FaceTangentY.AddUninitialized(NumTris);
	FaceTangentZ.AddUninitialized(NumTris);

	// Iterate over triangles
	for (int TriIdx = 0; TriIdx < NumTris; TriIdx++)
	{
		uint32 CornerIndex[3];
		FVector P[3];

		for (int32 CornerIdx = 0; CornerIdx < 3; CornerIdx++)
		{
			// Find vert index (clamped within range)
			uint32 VertIndex = FMath::Min(IndexAccessor((TriIdx * 3) + CornerIdx), NumVertices - 1);

			CornerIndex[CornerIdx] = VertIndex;
			P[CornerIdx] = VertexAccessor(VertIndex);

			// Find/add this vert to index buffer
			TArray<uint32> VertOverlaps;
			DuplicateVertexMap.MultiFind(VertIndex, VertOverlaps);

			// Remember which triangles map to this vert
			VertToTriMap.AddUnique(VertIndex, TriIdx);
			VertToTriSmoothMap.AddUnique(VertIndex, TriIdx);

			// Also update map of triangles that 'overlap' this vert (ie don't match UV, but do match smoothing) and should be considered when calculating normal
			for (int32 OverlapIdx = 0; OverlapIdx < VertOverlaps.Num(); OverlapIdx++)
			{
				// For each vert we overlap..
				int32 OverlapVertIdx = VertOverlaps[OverlapIdx];

				// Add this triangle to that vert
				VertToTriSmoothMap.AddUnique(OverlapVertIdx, TriIdx);

				// And add all of its triangles to us
				TArray<uint32> OverlapTris;
				VertToTriMap.MultiFind(OverlapVertIdx, OverlapTris);
				for (int32 OverlapTriIdx = 0; OverlapTriIdx < OverlapTris.Num(); OverlapTriIdx++)
				{
					VertToTriSmoothMap.AddUnique(VertIndex, OverlapTris[OverlapTriIdx]);
				}
			}
		}

		// Calculate triangle edge vectors and normal
		const FVector Edge21 = P[1] - P[2];
		const FVector Edge20 = P[0] - P[2];
		const FVector TriNormal = (Edge21 ^ Edge20).GetSafeNormal();

		// If we have UVs, use those to calculate
		if (NumUVs == NumVertices)
		{
			const FVector2D T1 = UVAccessor(CornerIndex[0]);
			const FVector2D T2 = UVAccessor(CornerIndex[1]);
			const FVector2D T3 = UVAccessor(CornerIndex[2]);

// 			float X1 = P[1].X - P[0].X;
// 			float X2 = P[2].X - P[0].X;
// 			float Y1 = P[1].Y - P[0].Y;
// 			float Y2 = P[2].Y - P[0].Y;
// 			float Z1 = P[1].Z - P[0].Z;
// 			float Z2 = P[2].Z - P[0].Z;
// 
// 			float S1 = U1.X - U0.X;
// 			float S2 = U2.X - U0.X;
// 			float T1 = U1.Y - U0.Y;
// 			float T2 = U2.Y - U0.Y;
// 
// 			float R = 1.0f / (S1 * T2 - S2 * T1);
// 			FaceTangentX[TriIdx] = FVector((T2 * X1 - T1 * X2) * R, (T2 * Y1 - T1 * Y2) * R,
// 				(T2 * Z1 - T1 * Z2) * R);
// 			FaceTangentY[TriIdx] = FVector((S1 * X2 - S2 * X1) * R, (S1 * Y2 - S2 * Y1) * R,
// 				(S1 * Z2 - S2 * Z1) * R);




			FMatrix	ParameterToLocal(
				FPlane(P[1].X - P[0].X, P[1].Y - P[0].Y, P[1].Z - P[0].Z, 0),
				FPlane(P[2].X - P[0].X, P[2].Y - P[0].Y, P[2].Z - P[0].Z, 0),
				FPlane(P[0].X, P[0].Y, P[0].Z, 0),
				FPlane(0, 0, 0, 1)
			);

			FMatrix ParameterToTexture(
				FPlane(T2.X - T1.X, T2.Y - T1.Y, 0, 0),
				FPlane(T3.X - T1.X, T3.Y - T1.Y, 0, 0),
				FPlane(T1.X, T1.Y, 1, 0),
				FPlane(0, 0, 0, 1)
			);

			// Use InverseSlow to catch singular matrices.  Inverse can miss this sometimes.
			const FMatrix TextureToLocal = ParameterToTexture.Inverse() * ParameterToLocal;

			FaceTangentX[TriIdx] = TextureToLocal.TransformVector(FVector(1, 0, 0)).GetSafeNormal();
			FaceTangentY[TriIdx] = TextureToLocal.TransformVector(FVector(0, 1, 0)).GetSafeNormal();
		}
		else
		{
			FaceTangentX[TriIdx] = Edge20.GetSafeNormal();
			FaceTangentY[TriIdx] = (FaceTangentX[TriIdx] ^ TriNormal).GetSafeNormal();
		}

		FaceTangentZ[TriIdx] = TriNormal;
	}


	// Arrays to accumulate tangents into
	TArray<FVector> VertexTangentXSum, VertexTangentYSum, VertexTangentZSum;
	VertexTangentXSum.AddZeroed(NumVertices);
	VertexTangentYSum.AddZeroed(NumVertices);
	VertexTangentZSum.AddZeroed(NumVertices);

	// For each vertex..
	for (int VertxIdx = 0; VertxIdx < NumVertices; VertxIdx++)
	{
		// Find relevant triangles for normal
		TArray<uint32> SmoothTris;
		VertToTriSmoothMap.MultiFind(VertxIdx, SmoothTris);

		for (int i = 0; i < SmoothTris.Num(); i++)
		{
			uint32 TriIdx = SmoothTris[i];
			VertexTangentZSum[VertxIdx] += FaceTangentZ[TriIdx];
		}

		// Find relevant triangles for tangents
		TArray<uint32> TangentTris;
		VertToTriMap.MultiFind(VertxIdx, TangentTris);

		for (int i = 0; i < TangentTris.Num(); i++)
		{
			uint32 TriIdx = TangentTris[i];
			VertexTangentXSum[VertxIdx] += FaceTangentX[TriIdx];
			VertexTangentYSum[VertxIdx] += FaceTangentY[TriIdx];
		}
	}

	// Finally, normalize tangents and build output arrays	
	for (int VertxIdx = 0; VertxIdx < NumVertices; VertxIdx++)
	{
		FVector& TangentX = VertexTangentXSum[VertxIdx];
		FVector& TangentY = VertexTangentYSum[VertxIdx];
		FVector& TangentZ = VertexTangentZSum[VertxIdx];

		TangentX.Normalize();
		//TangentY.Normalize();
		TangentZ.Normalize();

		// Use Gram-Schmidt orthogonalization to make sure X is orthonormal with Z
		TangentX -= TangentZ * (TangentZ | TangentX);
		TangentX.Normalize();
		TangentY.Normalize();


		TangentSetter(VertxIdx, TangentX, TangentY, TangentZ);
	}
}
// Internal helper function to find all graph nodes that reference the specified object
static int32 FindReferencedGraphNodes(TMultiMap<UObject*, FRefGraphItem*>& InputGraphNodeList, UObject* ReferencedObj, TArray<FRefGraphItem*>& FoundNodes)
{
	InputGraphNodeList.MultiFind(ReferencedObj, FoundNodes);
	return FoundNodes.Num();
}
void FPropertyTable::UpdateColumns()
{
	if( Orientation == EPropertyTableOrientation::AlignPropertiesInColumns)
	{
		TMultiMap< UProperty*, TSharedRef< IPropertyTableColumn > > ColumnsMap;
		for (int ColumnIdx = 0; ColumnIdx < Columns.Num(); ++ColumnIdx)
		{
			TSharedRef< IDataSource > DataSource = Columns[ColumnIdx]->GetDataSource();
			TSharedPtr< FPropertyPath > PropertyPath = DataSource->AsPropertyPath();
			if( PropertyPath.IsValid() && PropertyPath->GetNumProperties() > 0 )
			{
				ColumnsMap.Add(PropertyPath->GetRootProperty().Property.Get(), Columns[ColumnIdx]);
			}
		}

		Columns.Empty();

		if ( ShowRowHeader )
		{
			TSharedRef< IPropertyTableColumn > NewColumn = MakeShareable( new FPropertyTableRowHeaderColumn( SharedThis( this ) ) );
			Columns.Add( NewColumn );
		}

		if ( ShowObjectName )
		{
			TSharedRef< IPropertyTableColumn > NewColumn = MakeShareable( new FPropertyTableObjectNameColumn( SharedThis( this ) ) );
			NewColumn->SetFrozen( true );
			Columns.Add( NewColumn );
		}

		TArray< TWeakObjectPtr< UStruct > > UniqueTypes;
		TArray< int > TypeCounter;

		for( auto ObjectIter = SourceObjects.CreateConstIterator(); ObjectIter; ++ObjectIter )
		{
			auto Object = *ObjectIter;

			if( !Object.IsValid() )
			{
				continue;
			}

			const TSharedRef< FObjectPropertyNode > RootObjectNode = GetObjectPropertyNode( Object );

			TWeakObjectPtr< UStruct > Type;
			if ( RootPath->GetNumProperties() == 0 )
			{
				Type = RootObjectNode->GetObjectBaseClass();
			}
			else
			{
				const TSharedPtr< FPropertyNode > PropertyNode = FPropertyNode::FindPropertyNodeByPath( RootPath, RootObjectNode );

				if ( !PropertyNode.IsValid() )
				{
					continue;
				}

				const TWeakObjectPtr< UProperty > Property = PropertyNode->GetProperty();

				if ( !Property.IsValid() || !Property->IsA( UStructProperty::StaticClass() ) )
				{
					continue;
				}

				UStructProperty* StructProperty = Cast< UStructProperty >( Property.Get() );
				Type = StructProperty->Struct;
			}

			if ( !Type.IsValid() )
			{
				continue;
			}

			int FoundIndex = -1;
			if ( UniqueTypes.Find( Type, /*OUT*/FoundIndex ) )
			{
				TypeCounter[ FoundIndex ] = TypeCounter[ FoundIndex ] + 1;
				continue;
			}

			UniqueTypes.Add( Type );
			TypeCounter.Add( 1 );
		}

		if ( UniqueTypes.Num() > 0 )
		{
			int HighestCountIndex = 0;
			int HighestCount = 0;
			for (int Index = 0; Index < TypeCounter.Num(); Index++)
			{
				if ( TypeCounter[Index] > HighestCount )
				{
					HighestCountIndex = Index;
					HighestCount = TypeCounter[Index];
				}
			}

			TWeakObjectPtr< UStruct > PrimaryType = UniqueTypes[ HighestCountIndex ];

			for (TFieldIterator<UProperty> PropertyIter( PrimaryType.Get(), EFieldIteratorFlags::IncludeSuper); PropertyIter; ++PropertyIter)
			{
				TWeakObjectPtr< UProperty > Property = *PropertyIter;

				if ( PropertyIter->HasAnyPropertyFlags(CPF_AssetRegistrySearchable) )
				{
					TArray< TSharedRef< IPropertyTableColumn > > MapResults;

					ColumnsMap.MultiFind(Property.Get(), MapResults);
					if(MapResults.Num() > 0)
					{
						for (int MapIdx = 0; MapIdx < MapResults.Num(); ++MapIdx)
						{
							Columns.Add(MapResults[MapIdx]);
						}
					}
					else
					{
						TSharedRef< IPropertyTableColumn > NewColumn = CreateColumn( Property );
						Columns.Add( NewColumn );
					}
				}
			}
		}
	}
	else
	{
		Columns.Empty();

		if( SourceObjects.Num() > 0 )
		{
			UClass* ObjectClass = SourceObjects[0]->GetClass();
			TSharedRef< IPropertyTableColumn > HeadingColumn = MakeShareable( new FPropertyTablePropertyNameColumn( SharedThis( this ) ) );

			Columns.Add( HeadingColumn );

			for( auto ObjectIter = SourceObjects.CreateConstIterator(); ObjectIter; ++ObjectIter )
			{
				auto Object = *ObjectIter;

				if( Object.IsValid() )
				{
					const TSharedRef< FObjectPropertyNode > ObjectNode = GetObjectPropertyNode( Object );
					const TSharedPtr< FPropertyNode > PropertyNode = FPropertyNode::FindPropertyNodeByPath( RootPath, ObjectNode );

					UProperty* Property = PropertyNode->GetProperty();
					if ( Property != NULL && Property->IsA( UArrayProperty::StaticClass() ) )
					{
						for (int ChildIdx = 0; ChildIdx < PropertyNode->GetNumChildNodes(); ChildIdx++)
						{
							TSharedPtr< FPropertyNode > ChildNode = PropertyNode->GetChildNode( ChildIdx );
							FPropertyInfo Extension;
							Extension.Property = ChildNode->GetProperty();
							Extension.ArrayIndex = ChildNode->GetArrayIndex();
							TSharedRef< FPropertyPath > Path = FPropertyPath::CreateEmpty()->ExtendPath( Extension );
							TSharedRef< IPropertyTableColumn > NewColumn = MakeShareable( new FPropertyTableColumn( SharedThis( this ), Object, Path ) );
							Columns.Add( NewColumn );
						}
					}
					else if (  Property != NULL )
					{
						TSharedRef< IPropertyTableColumn > NewColumn = MakeShareable( new FPropertyTableColumn( SharedThis( this ), Object ) );
						Columns.Add( NewColumn );
					}
				}

			}
		}
	}

	ColumnsChanged.Broadcast();
}
void FPropertyTable::UpdateRows()
{
	if( Orientation == EPropertyTableOrientation::AlignPropertiesInColumns )
	{
		TMultiMap< UObject*, TSharedRef< IPropertyTableRow > > RowsMap;

		for (int RowIdx = 0; RowIdx < Rows.Num(); ++RowIdx)
		{
			RowsMap.Add(Rows[RowIdx]->GetDataSource()->AsUObject().Get(), Rows[RowIdx]);
		}

		Rows.Empty();
		for( auto ObjectIter = SourceObjects.CreateConstIterator(); ObjectIter; ++ObjectIter )
		{
			const TWeakObjectPtr< UObject >& Object = *ObjectIter;

			if( Object.IsValid() )
			{
				const TSharedRef< FObjectPropertyNode > ObjectNode = GetObjectPropertyNode( Object );
				const TSharedPtr< FPropertyNode > PropertyNode = FPropertyNode::FindPropertyNodeByPath( RootPath, ObjectNode );

				//@todo This system will need to change in order to properly support arrays [11/30/2012 Justin.Sargent]
				if ( PropertyNode.IsValid() )
				{
					UProperty* Property = PropertyNode->GetProperty();

					if ( Property != NULL && Property->IsA( UArrayProperty::StaticClass() ) )
					{
						for (int ChildIdx = 0; ChildIdx < PropertyNode->GetNumChildNodes(); ChildIdx++)
						{
							TSharedPtr< FPropertyNode > ChildNode = PropertyNode->GetChildNode( ChildIdx );

							FPropertyInfo Extension;
							Extension.Property = ChildNode->GetProperty();
							Extension.ArrayIndex = ChildNode->GetArrayIndex();
							TSharedRef< FPropertyPath > Path = FPropertyPath::CreateEmpty()->ExtendPath( Extension );
							TArray< TSharedRef< IPropertyTableRow > > MapResults;
							bool Found = false;

							RowsMap.MultiFind(Object.Get(), MapResults);

							for (int MapIdx = 0; MapIdx < MapResults.Num(); ++MapIdx)
							{
								if (FPropertyPath::AreEqual(Path, MapResults[MapIdx]->GetPartialPath()))
								{
									Found = true;
									Rows.Add(MapResults[MapIdx]);
									break;
								}
							}

							if (!Found)
							{
								Rows.Add( MakeShareable( new FPropertyTableRow( SharedThis( this ), Object, Path ) ) );
							}
						}
					}
					else
					{
						TArray< TSharedRef< IPropertyTableRow > > MapResults;
						bool Found = false;

						RowsMap.MultiFind(Object.Get(), MapResults);

						for (int MapIdx = 0; MapIdx < MapResults.Num(); ++MapIdx)
						{
							if (MapResults[MapIdx]->GetPartialPath()->GetNumProperties() == 0)
							{
								Found = true;
								Rows.Add(MapResults[MapIdx]);
								break;
							}
						}

						if (!Found)
						{
							Rows.Add( MakeShareable( new FPropertyTableRow( SharedThis( this ), Object ) ) );
						}
					}
				}
			}
		}
	}

	const TSharedPtr< IPropertyTableColumn > Column = SortedByColumn.Pin();
	if ( Column.IsValid() && SortedColumnMode != EColumnSortMode::None )
	{
		Column->Sort( Rows, SortedColumnMode );
	}

	RowsChanged.Broadcast();
}
void FRCPassPostProcessSelectionOutlineColor::Process(FRenderingCompositePassContext& Context)
{
	SCOPED_DRAW_EVENT(Context.RHICmdList, PostProcessSelectionOutlineBuffer, DEC_SCENE_ITEMS);

	const FPooledRenderTargetDesc* SceneColorInputDesc = GetInputDesc(ePId_Input0);

	if(!SceneColorInputDesc)
	{
		// input is not hooked up correctly
		return;
	}

	const FViewInfo& View = Context.View;
	FIntRect ViewRect = View.ViewRect;
	FIntPoint SrcSize = SceneColorInputDesc->Extent;

	// Get the output render target
	const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context);
	
	// Set the render target/viewport.
	SetRenderTarget(Context.RHICmdList, FTextureRHIParamRef(), DestRenderTarget.TargetableTexture);
	// This is a reversed Z depth surface, so 0.0f is the far plane.
	Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect());
	Context.SetViewportAndCallRHI(ViewRect);

	if (View.Family->EngineShowFlags.Selection)
	{
		const bool bUseGetMeshElements = ShouldUseGetDynamicMeshElements();

		if (bUseGetMeshElements)
		{
			FHitProxyDrawingPolicyFactory::ContextType FactoryContext;

			//@todo - use memstack
			TMap<FName, int32> ActorNameToStencilIndex;
			ActorNameToStencilIndex.Add(NAME_BSP, 1);

			Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI());
			Context.RHICmdList.SetBlendState(TStaticBlendStateWriteMask<CW_NONE, CW_NONE, CW_NONE, CW_NONE>::GetRHI());

			for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++)
			{
				const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex];
				const FPrimitiveSceneProxy* PrimitiveSceneProxy = MeshBatchAndRelevance.PrimitiveSceneProxy;

				if (PrimitiveSceneProxy->IsSelected() && MeshBatchAndRelevance.Mesh->bUseSelectionOutline)
				{
					const int32* AssignedStencilIndexPtr = ActorNameToStencilIndex.Find(PrimitiveSceneProxy->GetOwnerName());

					if (!AssignedStencilIndexPtr)
					{
						AssignedStencilIndexPtr = &ActorNameToStencilIndex.Add(PrimitiveSceneProxy->GetOwnerName(), ActorNameToStencilIndex.Num() + 1);
					}

					// This is a reversed Z depth surface, using CF_GreaterEqual.
					// Note that the stencil value will overflow with enough selected objects
					Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_GreaterEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(), *AssignedStencilIndexPtr);

					const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh;
					FHitProxyDrawingPolicyFactory::DrawDynamicMesh(Context.RHICmdList, View, FactoryContext, MeshBatch, false, true, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId);
				}
			}
		}
		else if (View.VisibleDynamicPrimitives.Num() > 0)
		{
			TDynamicPrimitiveDrawer<FHitProxyDrawingPolicyFactory> Drawer(Context.RHICmdList, &View, FHitProxyDrawingPolicyFactory::ContextType(), true, false, false, true);
			TMultiMap<FName, const FPrimitiveSceneInfo*> PrimitivesByActor;

			for (int32 PrimitiveIndex = 0; PrimitiveIndex < View.VisibleDynamicPrimitives.Num();PrimitiveIndex++)
			{
				const FPrimitiveSceneInfo* PrimitiveSceneInfo = View.VisibleDynamicPrimitives[PrimitiveIndex];

				// Only draw the primitive if relevant
				if(PrimitiveSceneInfo->Proxy->IsSelected())
				{
					PrimitivesByActor.Add(PrimitiveSceneInfo->Proxy->GetOwnerName(), PrimitiveSceneInfo);
				}
			}

			if (PrimitivesByActor.Num())
			{
				// 0 means no object, 1 means BSP so we start with 2
				uint32 StencilValue = 2;

				Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI());
				Context.RHICmdList.SetBlendState(TStaticBlendStateWriteMask<CW_NONE, CW_NONE, CW_NONE, CW_NONE>::GetRHI());

				// Sort by actor
				TArray<FName> Actors;
				PrimitivesByActor.GetKeys(Actors);
				for( TArray<FName>::TConstIterator ActorIt(Actors); ActorIt; ++ActorIt )
				{
					bool bBSP = *ActorIt == NAME_BSP;
					if (bBSP)
					{
						// This is a reversed Z depth surface, using CF_GreaterEqual.
						Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_GreaterEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(), 1);
					}
					else
					{
						// This is a reversed Z depth surface, using CF_GreaterEqual.
						Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_GreaterEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(), StencilValue);

						// we want to use 1..255 for all objects, not correct silhouettes after that is acceptable
						StencilValue = (StencilValue == 255) ? 2 : (StencilValue + 1);
					}

					TArray<const FPrimitiveSceneInfo*> Primitives;
					PrimitivesByActor.MultiFind(*ActorIt, Primitives);

					for( TArray<const FPrimitiveSceneInfo*>::TConstIterator PrimIt(Primitives); PrimIt; ++PrimIt )
					{
						const FPrimitiveSceneInfo* PrimitiveSceneInfo = *PrimIt;
						// Render the object to the stencil/depth buffer
						Drawer.SetPrimitive(PrimitiveSceneInfo->Proxy);
						PrimitiveSceneInfo->Proxy->DrawDynamicElements(&Drawer, &View);
					}
				}
			}
		}

		// to get an outline around the objects if it's partly outside of the screen
		{
			FIntRect InnerRect = ViewRect;

			// 1 as we have an outline that is that thick
			InnerRect.InflateRect(-1);

			// We could use Clear with InnerRect but this is just an optimization - on some hardware it might do a full clear (and we cannot disable yet)
			//			RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, InnerRect);
			// so we to 4 clears - one for each border.

			// top
			Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Max.X, InnerRect.Min.Y);
			Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect());
			// bottom
			Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, InnerRect.Max.Y, ViewRect.Max.X, ViewRect.Max.Y);
			Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect());
			// left
			Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, InnerRect.Min.X, ViewRect.Max.Y);
			Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect());
			// right
			Context.RHICmdList.SetScissorRect(true, InnerRect.Max.X, ViewRect.Min.Y, ViewRect.Max.X, ViewRect.Max.Y);
			Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect());

			Context.RHICmdList.SetScissorRect(false, 0, 0, 0, 0);
		}
	}
	
	// Resolve to the output
	Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams());
}