UMaterialInterface* FParticleBeam2EmitterInstance::GetCurrentMaterial()
{
	UMaterialInterface* RenderMaterial = CurrentMaterial;
	if ((RenderMaterial == NULL) || (RenderMaterial->CheckMaterialUsage_Concurrent(MATUSAGE_BeamTrails) == false))
	{
		RenderMaterial = UMaterial::GetDefaultMaterial(MD_Surface);
	}
	return RenderMaterial;
}
void SLandscapeAssetThumbnail::OnMaterialCompilationFinished(UMaterialInterface* MaterialInterface)
{
	UMaterialInterface* MaterialAsset = Cast<UMaterialInterface>(AssetThumbnail->GetAsset());
	if (MaterialAsset)
	{
		if (MaterialAsset->IsDependent(MaterialInterface))
		{
			// Refresh thumbnail
			AssetThumbnail->SetAsset(AssetThumbnail->GetAsset());
		}
	}
}
void SMaterialEditorViewport::OnSetPreviewMeshFromSelection()
{
	bool bFoundPreviewMesh = false;
	FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast();

	UMaterialInterface* MaterialInterface = MaterialEditorPtr.Pin()->GetMaterialInterface();

	// Look for a selected asset that can be converted to a mesh component
	for (FSelectionIterator SelectionIt(*GEditor->GetSelectedObjects()); SelectionIt && !bFoundPreviewMesh; ++SelectionIt)
	{
		UObject* TestAsset = *SelectionIt;
		if (TestAsset->IsAsset())
		{
			if (TSubclassOf<UActorComponent> ComponentClass = FComponentAssetBrokerage::GetPrimaryComponentForAsset(TestAsset->GetClass()))
			{
				if (ComponentClass->IsChildOf(UMeshComponent::StaticClass()))
				{
					if (USkeletalMesh* SkeletalMesh = Cast<USkeletalMesh>(TestAsset))
					{
						// Special case handling for skeletal meshes, sets the material to be usable with them
						if (MaterialInterface->GetMaterial())
						{
							bool bNeedsRecompile = false;
							MaterialInterface->GetMaterial()->SetMaterialUsage(bNeedsRecompile, MATUSAGE_SkeletalMesh);
						}
					}

					SetPreviewAsset(TestAsset);
					MaterialInterface->PreviewMesh = TestAsset->GetPathName();
					bFoundPreviewMesh = true;
				}
			}
		}
	}

	if (bFoundPreviewMesh)
	{
		FMaterialEditor::UpdateThumbnailInfoPreviewMesh(MaterialInterface);

		MaterialInterface->MarkPackageDirty();
		RefreshViewport();
	}
	else
	{
		FSuppressableWarningDialog::FSetupInfo Info(NSLOCTEXT("UnrealEd", "Warning_NoPreviewMeshFound_Message", "You need to select a mesh-based asset in the content browser to preview it."),
			NSLOCTEXT("UnrealEd", "Warning_NoPreviewMeshFound", "Warning: No Preview Mesh Found"), "Warning_NoPreviewMeshFound");
		Info.ConfirmText = NSLOCTEXT("UnrealEd", "Warning_NoPreviewMeshFound_Confirm", "Continue");
		
		FSuppressableWarningDialog NoPreviewMeshWarning( Info );
		NoPreviewMeshWarning.ShowModal();
	}
}
bool UParticleModuleCollisionGPU::IsValidForLODLevel(UParticleLODLevel* LODLevel, FString& OutErrorString)
{
	UMaterialInterface* Material = NULL;
	if (LODLevel && LODLevel->RequiredModule)
	{
		Material = LODLevel->RequiredModule->Material;
	}
	if (Material == NULL)
	{
		Material = UMaterial::GetDefaultMaterial(MD_Surface);
	}
	check(Material);

	EBlendMode BlendMode = BLEND_Opaque;
	const FMaterialResource* MaterialResource = Material->GetMaterialResource(GetWorld() ? GetWorld()->FeatureLevel : GMaxRHIFeatureLevel);
	if(MaterialResource)
	{
		BlendMode = MaterialResource->GetBlendMode();
	}

	if (CollisionMode == EParticleCollisionMode::SceneDepth && (BlendMode == BLEND_Opaque || BlendMode == BLEND_Masked))
	{
		OutErrorString = NSLOCTEXT("UnrealEd", "CollisionOnOpaqueEmitter", "Scene depth collision cannot be used on emitters with an opaque material.").ToString();
		return false;
	}

	if (CollisionMode == EParticleCollisionMode::DistanceField)
	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.GenerateMeshDistanceFields"));

		if (CVar->GetValueOnGameThread() == 0)
		{
			OutErrorString = NSLOCTEXT("UnrealEd", "CollisionWithoutDistanceField", "Distance Field collision requires the 'Generate Mesh Distance Fields' Renderer project setting to be enabled.").ToString();
			return false;
		}
	}

	if (LODLevel->TypeDataModule && LODLevel->TypeDataModule->IsA(UParticleModuleTypeDataGpu::StaticClass()))
	{
		if(!IsDistributionAllowedOnGPU(ResilienceScaleOverLife.Distribution))
		{
			OutErrorString = GetDistributionNotAllowedOnGPUText(StaticClass()->GetName(), "ResilienceScaleOverLife" ).ToString();
			return false;
		}
	}

	return true;
}
FLinearColor FMaterialEditorViewportClient::GetBackgroundColor() const
{
	FLinearColor BackgroundColor = FLinearColor::Black;
	UMaterialInterface* MaterialInterface = MaterialEditorPtr.Pin()->GetMaterialInterface();
	if (MaterialInterface)
	{
		const EBlendMode PreviewBlendMode = (EBlendMode)MaterialInterface->GetBlendMode();
		if (PreviewBlendMode == BLEND_Modulate)
		{
			BackgroundColor = FLinearColor::White;
		}
		else if (PreviewBlendMode == BLEND_Translucent)
		{
			BackgroundColor = FColor(64, 64, 64);
		}
	}
	return BackgroundColor;
}
bool ADebugCameraHUD::DisplayMaterials( float X, float& Y, float DY, UMeshComponent* MeshComp )
{
	bool bDisplayedMaterial = false;
	if ( MeshComp != NULL )
	{
		FFontRenderInfo FontRenderInfo = Canvas->CreateFontRenderInfo(false, true);

		UFont* Font = GEngine->GetSmallFont();
		for ( int32 MaterialIndex = 0; MaterialIndex < MeshComp->GetNumMaterials(); ++MaterialIndex )
		{
			UMaterialInterface* Material = MeshComp->GetMaterial(MaterialIndex);
			if ( Material != NULL )
			{
				Y += DY;
				Canvas->DrawText(Font, FString::Printf(TEXT("Material: '%s'"), *Material->GetFName().ToString()), X + DY, Y, 1.f, 1.f, FontRenderInfo );
				bDisplayedMaterial = true;
			}
		}
	}
	return bDisplayedMaterial;
}
bool UParticleModuleCollisionGPU::IsValidForLODLevel(UParticleLODLevel* LODLevel, FString& OutErrorString)
{
	UMaterialInterface* Material = NULL;
	if (LODLevel && LODLevel->RequiredModule)
	{
		Material = LODLevel->RequiredModule->Material;
	}
	if (Material == NULL)
	{
		Material = UMaterial::GetDefaultMaterial(MD_Surface);
	}
	check(Material);

	EBlendMode BlendMode = BLEND_Opaque;
	const FMaterialResource* MaterialResource = Material->GetMaterialResource(GetWorld() ? GetWorld()->FeatureLevel : GMaxRHIFeatureLevel);
	if(MaterialResource)
	{
		BlendMode = MaterialResource->GetBlendMode();
	}

	if (BlendMode == BLEND_Opaque || BlendMode == BLEND_Masked)
	{
		OutErrorString = NSLOCTEXT("UnrealEd", "CollisionOnOpaqueEmitter", "Scene depth collision cannot be used on emitters with an opaque material.").ToString();
		return false;
	}

	if (LODLevel->TypeDataModule && LODLevel->TypeDataModule->IsA(UParticleModuleTypeDataGpu::StaticClass()))
	{
		if(!IsDistributionAllowedOnGPU(ResilienceScaleOverLife.Distribution))
		{
			OutErrorString = GetDistributionNotAllowedOnGPUText(StaticClass()->GetName(), "ResilienceScaleOverLife" ).ToString();
			return false;
		}
	}

	return true;
}
void FTextRenderSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const 
{
	QUICK_SCOPE_CYCLE_COUNTER( STAT_TextRenderSceneProxy_GetDynamicMeshElements );

	// Vertex factory will not been initialized when the text string is empty or font is invalid.
	if(VertexFactory.IsInitialized())
	{
		for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
		{
			if (VisibilityMap & (1 << ViewIndex))
			{
				const FSceneView* View = Views[ViewIndex];
				// Draw the mesh.
				FMeshBatch& Mesh = Collector.AllocateMesh();
				FMeshBatchElement& BatchElement = Mesh.Elements[0];
				BatchElement.IndexBuffer = &IndexBuffer;
				Mesh.VertexFactory = &VertexFactory;
				BatchElement.PrimitiveUniformBufferResource = &GetUniformBuffer();
				BatchElement.FirstIndex = 0;
				BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3;
				BatchElement.MinVertexIndex = 0;
				BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1;
				Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
				Mesh.bDisableBackfaceCulling = false;
				Mesh.Type = PT_TriangleList;
				Mesh.DepthPriorityGroup = SDPG_World;
				const bool bUseSelectedMaterial = GIsEditor && (View->Family->EngineShowFlags.Selection) ? IsSelected() : false;
				Mesh.MaterialRenderProxy = TextMaterial->GetRenderProxy(bUseSelectedMaterial);
				Mesh.bCanApplyViewModeOverrides = !bAlwaysRenderAsText;

				Collector.AddMesh(ViewIndex, Mesh);

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
				RenderBounds(Collector.GetPDI(ViewIndex), View->Family->EngineShowFlags, GetBounds(), IsSelected());
#endif
			}
		}
	}
}
void FTextRenderSceneProxy::DrawStaticElements(FStaticPrimitiveDrawInterface* PDI)
{
	// Vertex factory will not been initialized when the font is invalid or the text string is empty.
	if(VertexFactory.IsInitialized())
	{
		// Draw the mesh.
		FMeshBatch Mesh;
		FMeshBatchElement& BatchElement = Mesh.Elements[0];
		BatchElement.IndexBuffer = &IndexBuffer;
		Mesh.VertexFactory = &VertexFactory;
		Mesh.MaterialRenderProxy = TextMaterial->GetRenderProxy(false);
		BatchElement.PrimitiveUniformBufferResource = &GetUniformBuffer();
		BatchElement.FirstIndex = 0;
		BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3;
		BatchElement.MinVertexIndex = 0;
		BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1;
		Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
		Mesh.bDisableBackfaceCulling = false;
		Mesh.Type = PT_TriangleList;
		Mesh.DepthPriorityGroup = SDPG_World;
		PDI->DrawMesh(Mesh, 1.0f);
	}
}
void USkeletalMeshComponent::TickAnimation(float DeltaTime)
{
	SCOPE_CYCLE_COUNTER(STAT_AnimTickTime);
	if (SkeletalMesh != NULL)
	{
		if (AnimScriptInstance != NULL)
		{
			// Tick the animation
			AnimScriptInstance->UpdateAnimation(DeltaTime * GlobalAnimRateScale);

			// TODO @LinaH - I've hit access violations due to AnimScriptInstance being NULL after this, probably due to
			// AnimNotifies?  Please take a look and fix as we discussed.  Temporary fix:
			if (AnimScriptInstance != NULL)
			{
				// now all tick/trigger/kismet is done
				// add MorphTarget Curves from Kismet driven or any other source
				// and overwrite if it exists
				// Tick always should maintain this list, not Evaluate
				for( auto Iter = MorphTargetCurves.CreateConstIterator(); Iter; ++Iter )
				{
					float *CurveValPtr = AnimScriptInstance->MorphTargetCurves.Find(Iter.Key());
					if ( CurveValPtr )
					{
						// override the value if Kismet request was made
						*CurveValPtr = Iter.Value();
					}
					else
					{
						AnimScriptInstance->MorphTargetCurves.Add(Iter.Key(), Iter.Value());
					}				
				}

				//Update material parameters
				if(AnimScriptInstance->MaterialParameterCurves.Num() > 0)
				{
					for( auto Iter = AnimScriptInstance->MaterialParameterCurves.CreateConstIterator(); Iter; ++Iter )
					{
						FName ParameterName = Iter.Key();
						float ParameterValue = Iter.Value();

						for(int32 MaterialIndex = 0; MaterialIndex < GetNumMaterials(); ++MaterialIndex)
						{
							UMaterialInterface* MaterialInterface = GetMaterial(MaterialIndex);
							if (MaterialInterface)
							{
								float TestValue; //not used but needed for GetScalarParameterValue call
								if(MaterialInterface->GetScalarParameterValue(ParameterName,TestValue))
								{
									UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(MaterialInterface);
									if(!DynamicMaterial) //Is it already a UMaterialInstanceDynamic (ie we used it last tick)
									{
										DynamicMaterial = CreateAndSetMaterialInstanceDynamic(MaterialIndex);
									}
									DynamicMaterial->SetScalarParameterValue(ParameterName, ParameterValue);
								
									//Assume that we only set the parameter on one of the materials, remove this break
									//if that is no longer desired
									break;
								}
							}
						}
					}
				}
			}
		}
	}
}
void UJanusExporterTool::Export()
{
	TArray<UObject*> ObjectsToExport;

	FString Root = FString(ExportPath); // copy so we dont mess with the original reference
	FString Index = "<html>\n\t<head>\n\t\t<title>Unreal Export</title>\n\t</head>\n\t<body>\n\t\t<FireBoxRoom>\n\t\t\t<Assets>";

	TArray<AActor*> ActorsExported;
	TArray<UStaticMesh*> StaticMeshesExp;
	TArray<FString> TexturesExp;
	TArray<FString> MaterialsExported;

	for (TObjectIterator<AActor> Itr; Itr; ++Itr)
	{
		AActor *Actor = *Itr;

		FString Name = Actor->GetName();
		/*if (!Name.StartsWith("SM_Floor_R"))
		{
			continue;
		}*/

		if (Actor->IsHiddenEd())
		{
			continue;
		}

		ActorsExported.Add(Actor);

		TArray<UStaticMeshComponent*> StaticMeshes;
		Actor->GetComponents<UStaticMeshComponent>(StaticMeshes);
		for (int32 i = 0; i < StaticMeshes.Num(); i++)
		{
			UStaticMeshComponent* Component = StaticMeshes[i];
			UStaticMesh *Mesh = Component->StaticMesh;
			if (!Mesh)
			{
				continue;
			}

			if (Component->LODData.Num() > 0)
				//if (false)
			{
				FStaticMeshComponentLODInfo* LODInfo = &Component->LODData[0];
				FLightMap* LightMap = LODInfo->LightMap;
				FShadowMap* ShadowMap = LODInfo->ShadowMap;
				if (LightMap != NULL)
				{
					FLightMap2D* LightMap2D = LightMap->GetLightMap2D();
					UTexture2D* Texture = LightMap2D->GetTexture(0); // 0 = HQ LightMap
					FString TexName = Texture->GetName();
					if (TexturesExp.Contains(TexName))
					{
						continue;
					}

					TexturesExp.Add(TexName);
					ExportPNG(Texture, Root);
				}
				if (ShadowMap != NULL)
				{
					FShadowMap2D* ShadowMap2D = ShadowMap->GetShadowMap2D();
					UShadowMapTexture2D* ShadowTex = ShadowMap2D->GetTexture();
					FString TexName = ShadowTex->GetName();
					if (TexturesExp.Contains(TexName))
					{
						continue;
					}

					TexturesExp.Add(TexName);
					ExportPNG(ShadowTex, Root);
				}
			}

			if (!StaticMeshesExp.Contains(Mesh))
			{
				StaticMeshesExp.Add(Mesh);
				ExportFBX(Mesh, Root);
			}

			TArray<UMaterialInterface*> Materials = Component->GetMaterials();
			for (int32 j = 0; j < Materials.Num(); j++)
			{
				UMaterialInterface* Material = Materials[j];
				if (!Material)
				{
					continue;
				}

				FString MatName = Material->GetName();

				if (MaterialsExported.Contains(MatName))
				{
					continue;
				}

				MaterialsExported.Add(MatName);
				ExportMaterial(Root, Material, &TexturesExp);
			}
		}
	}

	// Models before textures so we can start showing the scene faster (textures take too long to load)
	for (int32 i = 0; i < StaticMeshesExp.Num(); i++)
	{
		UStaticMesh *mesh = StaticMeshesExp[i];

		Index.Append("\n\t\t\t\t<AssetObject id=\"" + mesh->GetName() + "\" src=\"" + mesh->GetName() + ".fbx\" />");
	}

	for (int32 i = 0; i < TexturesExp.Num(); i++)
	{
		FString Path = TexturesExp[i];

		Index.Append("\n\t\t\t\t<AssetImage id=\"" + Path + "\" src=\"" + Path + ".png\" />");
	}

	Index.Append("\n\t\t\t</Assets>\n\t\t\t<Room>");

	for (int32 i = 0; i < ActorsExported.Num(); i++)
	{
		AActor *Actor = ActorsExported[i];

		TArray<UStaticMeshComponent*> StaticMeshes;
		Actor->GetComponents<UStaticMeshComponent>(StaticMeshes);
		for (int32 i = 0; i < StaticMeshes.Num(); i++)
		{
			UStaticMeshComponent* Component = StaticMeshes[i];
			UStaticMesh *Mesh = Component->StaticMesh;
			if (!Mesh)
			{
				continue;
			}

			FString ImageID = "";

			TArray<UMaterialInterface*> Materials = Component->GetMaterials();
			for (int32 j = 0; j < Materials.Num(); j++)
			{
				UMaterialInterface* Material = Materials[j];
				if (!Material)
				{
					continue;
				}
				ImageID = Material->GetName() + "_BaseColor";
				break;
			}

			if (ImageID == "")
			{
				Index.Append("\n\t\t\t\t<Object collision_id=\"" + Mesh->GetName() + "\" id=\"" + Mesh->GetName() + "\" lighting=\"true\" pos=\"");
			}
			else
			{
				Index.Append("\n\t\t\t\t<Object collision_id=\"" + Mesh->GetName() + "\" id=\"" + Mesh->GetName() + "\" image_id=\"" + ImageID + "\" lighting=\"true\" pos=\"");
			}

			FRotator Rot = Actor->GetActorRotation();
			FVector XDir = Rot.RotateVector(FVector::RightVector);
			FVector YDir = Rot.RotateVector(FVector::UpVector);
			FVector ZDir = Rot.RotateVector(FVector::ForwardVector);

			FVector Pos = Actor->GetActorLocation() * UniformScale;
			FVector Sca = Actor->GetActorScale();

			Pos = ChangeSpace(Pos);
			Sca = ChangeSpaceScalar(Sca) * UniformScale;

			XDir = ChangeSpace(XDir);
			YDir = ChangeSpace(YDir);
			ZDir = ChangeSpace(ZDir);
			FVector Sign = GetSignVector(Sca);

			Index.Append(FString::SanitizeFloat(Pos.X) + " " + FString::SanitizeFloat(Pos.Y) + " " + FString::SanitizeFloat(Pos.Z));
			if (Sca.X < 0 || Sca.Y < 0 || Sca.Z < 0)
			{
				Index.Append("\" cull_face=\"front");
			}

			Index.Append("\" scale=\"");
			Index.Append(FString::SanitizeFloat(Sca.X) + " " + FString::SanitizeFloat(Sca.Y) + " " + FString::SanitizeFloat(Sca.Z));

			Index.Append("\" xdir=\"");
			Index.Append(FString::SanitizeFloat(XDir.X) + " " + FString::SanitizeFloat(XDir.Y) + " " + FString::SanitizeFloat(XDir.Z));

			Index.Append("\" ydir=\"");
			Index.Append(FString::SanitizeFloat(YDir.X) + " " + FString::SanitizeFloat(YDir.Y) + " " + FString::SanitizeFloat(YDir.Z));

			Index.Append("\" zdir=\"");
			Index.Append(FString::SanitizeFloat(ZDir.X) + " " + FString::SanitizeFloat(ZDir.Y) + " " + FString::SanitizeFloat(ZDir.Z));

			Index.Append("\" />");
		}
	}

	Index.Append("\n\t\t\t</Room>\n\t\t</FireBoxRoom>\n\t</body>\n</html>");

	FString IndexPath = FString(ExportPath).Append("index.html");
	FFileHelper::SaveStringToFile(Index, *IndexPath);
}
bool SetApexDestructibleAsset(UDestructibleMesh& DestructibleMesh, NxDestructibleAsset& ApexDestructibleAsset, FSkeletalMeshImportData* OutData, EImportOptions::Type Options)
{
	DestructibleMesh.PreEditChange(NULL);

#if WITH_EDITORONLY_DATA
	// Handle the StaticMesh import case, where we have the materials only stored in the fracture settings
	if (DestructibleMesh.Materials.Num() == 0 && DestructibleMesh.FractureSettings != NULL && 
		DestructibleMesh.FractureSettings->Materials.Num() > 0)
	{
		for (int32 i=0; i < DestructibleMesh.FractureSettings->Materials.Num(); ++i)
		{
			FSkeletalMaterial Mat;
			Mat.MaterialInterface = DestructibleMesh.FractureSettings->Materials[i];
			Mat.bEnableShadowCasting = true;

			DestructibleMesh.Materials.Add(Mat);
		}
	}
#endif

	ExistingDestMeshData* ExistDestMeshDataPtr = NULL;
	ExistDestMeshDataPtr = SaveExistingDestMeshData(&DestructibleMesh);
	
	// The asset is going away, which will destroy any actors created from it.  We must destroy the physics state of any destructible mesh components before we release the asset.
	for(TObjectIterator<UDestructibleComponent> It; It; ++It)
	{
		UDestructibleComponent* DestructibleComponent = *It;
		if(DestructibleComponent->SkeletalMesh == &DestructibleMesh && DestructibleComponent->GetScene())
		{
			DestructibleComponent->DestroyPhysicsState();
		}
	}

	// Release old NxDestructibleAsset if it exists
	if (DestructibleMesh.ApexDestructibleAsset != NULL && DestructibleMesh.ApexDestructibleAsset != &ApexDestructibleAsset)
	{
		GPhysCommandHandler->DeferredRelease(DestructibleMesh.ApexDestructibleAsset);
	}

	// BRGTODO - need to remove the render data from the ApexDestructibleAsset, no longer need it
	// Removing const cast ... we'll have to make it non-const anyway when we modify it
	DestructibleMesh.ApexDestructibleAsset = &ApexDestructibleAsset;

	if ( !(Options&EImportOptions::PreserveSettings) )
	{
		// Resize the depth parameters array to the appropriate size
		DestructibleMesh.DefaultDestructibleParameters.DepthParameters.Init(FDestructibleDepthParameters(), ApexDestructibleAsset.getDepthCount());

		// Resize the fracture effects array to the appropriate size
		DestructibleMesh.FractureEffects.AddZeroed(ApexDestructibleAsset.getDepthCount());

		// Load the UnrealEd-editable parameters from the destructible asset
		DestructibleMesh.LoadDefaultDestructibleParametersFromApexAsset();
	}
		
	// Create body setup for the destructible mesh
	DestructibleMesh.CreateBodySetup();

#if 0	// BRGTODO
	// warning for missing smoothing group info
	CheckSmoothingInfo(FbxMesh);
#endif
	
	FSkeletalMeshImportData TempData;
	// Fill with data from buffer
	FSkeletalMeshImportData* SkelMeshImportDataPtr = &TempData;
	if( OutData )
	{
		SkelMeshImportDataPtr = OutData;
	}

	// Import animation hierarchy, although this is trivial for an Apex Destructible Asset
	CreateBones(*SkelMeshImportDataPtr, ApexDestructibleAsset);

	if (!(Options & EImportOptions::PreserveSettings))
	{
		// Get all material names here
		ImportMaterialsForSkelMesh(*SkelMeshImportDataPtr, ApexDestructibleAsset);
	}
	else
	{
		SkelMeshImportDataPtr->Materials.Empty(DestructibleMesh.Materials.Num());
		for (int32 i=0; i < DestructibleMesh.Materials.Num(); ++i)
		{
			UMaterialInterface* MI = DestructibleMesh.Materials[i].MaterialInterface;
			VMaterial NewMat;
			
			NewMat.MaterialName = MI != NULL ? MI->GetName() : TEXT("");
			SkelMeshImportDataPtr->Materials.Add(NewMat);
		}
	}

	// Import graphics data
	bool bHaveNormals, bHaveTangents;
	if (!FillSkelMeshImporterFromApexDestructibleAsset(*SkelMeshImportDataPtr, ApexDestructibleAsset, bHaveNormals, bHaveTangents))
	{
		return false;
	}

#if 0	// BRGTODO - what is this?
	if( SkelMeshImportDataPtr->Materials.Num() == FbxMatList.Num() )
	{
		// reorder material according to "SKinXX" in material name
		SetMaterialSkinXXOrder(*SkelMeshImportDataPtr, FbxMatList );
	}
#endif

#if 0	// BRGTODO - what is this?
	if( ImportOptions->bSplitNonMatchingTriangles )
	{
		DoUnSmoothVerts(*SkelMeshImportDataPtr);
	}
#endif

	if ( !(Options&EImportOptions::PreserveSettings) )
	{
		// process materials from import data
		ProcessImportMeshMaterials( DestructibleMesh.Materials,*SkelMeshImportDataPtr );
	}
	
	// process reference skeleton from import data
	int32 SkeletalDepth=0;
	if(!ProcessImportMeshSkeleton(DestructibleMesh.RefSkeleton, SkeletalDepth, *SkelMeshImportDataPtr))
	{
		return false;
	}
	UE_LOG(LogApexDestructibleAssetImport, Warning, TEXT("Bones digested - %i  Depth of hierarchy - %i"), DestructibleMesh.RefSkeleton.GetNum(), SkeletalDepth);

	// process bone influences from import data
	ProcessImportMeshInfluences(*SkelMeshImportDataPtr);

	FSkeletalMeshResource& DestructibleMeshResource = *DestructibleMesh.GetImportedResource();
	check(DestructibleMeshResource.LODModels.Num() == 0);
	DestructibleMeshResource.LODModels.Empty();
	new(DestructibleMeshResource.LODModels)FStaticLODModel();

	DestructibleMesh.LODInfo.Empty();
	DestructibleMesh.LODInfo.AddZeroed();
	DestructibleMesh.LODInfo[0].LODHysteresis = 0.02f;

	// Create initial bounding box based on expanded version of reference pose for meshes without physics assets. Can be overridden by artist.
	FBox BoundingBox( SkelMeshImportDataPtr->Points.GetTypedData(), SkelMeshImportDataPtr->Points.Num() );
	FBox Temp = BoundingBox;
	FVector MidMesh		= 0.5f*(Temp.Min + Temp.Max);
	BoundingBox.Min		= Temp.Min + 1.0f*(Temp.Min - MidMesh);
	BoundingBox.Max		= Temp.Max + 1.0f*(Temp.Max - MidMesh);
	// BRGTODO : what is this?
	// Tuck up the bottom as this rarely extends lower than a reference pose's (e.g. having its feet on the floor).
	// Maya has Y in the vertical, other packages have Z.
	//BEN const int32 CoordToTuck = bAssumeMayaCoordinates ? 1 : 2;
	//BEN BoundingBox.Min[CoordToTuck]	= Temp.Min[CoordToTuck] + 0.1f*(Temp.Min[CoordToTuck] - MidMesh[CoordToTuck]);
	BoundingBox.Min[2]	= Temp.Min[2] + 0.1f*(Temp.Min[2] - MidMesh[2]);
	DestructibleMesh.Bounds= FBoxSphereBounds(BoundingBox);

	// Store whether or not this mesh has vertex colors
	DestructibleMesh.bHasVertexColors = SkelMeshImportDataPtr->bHasVertexColors;

	FStaticLODModel& LODModel = DestructibleMeshResource.LODModels[0];
	
	// Pass the number of texture coordinate sets to the LODModel.  Ensure there is at least one UV coord
	LODModel.NumTexCoords = FMath::Max<uint32>(1,SkelMeshImportDataPtr->NumTexCoords);
//	if( bCreateRenderData )	// We always create render data
	{
		// copy vertex data needed to generate skinning streams for LOD
		TArray<FVector> LODPoints;
		TArray<FMeshWedge> LODWedges;
		TArray<FMeshFace> LODFaces;
		TArray<FVertInfluence> LODInfluences;
		TArray<int32> LODPointToRawMap;
		SkelMeshImportDataPtr->CopyLODImportData(LODPoints,LODWedges,LODFaces,LODInfluences,LODPointToRawMap);

		#include "Developer/MeshUtilities/Public/MeshUtilities.h"

		IMeshUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshUtilities>("MeshUtilities");

		// Create actual rendering data.
		if (!MeshUtilities.BuildSkeletalMesh(DestructibleMeshResource.LODModels[0], DestructibleMesh.RefSkeleton, LODInfluences,LODWedges,LODFaces,LODPoints,LODPointToRawMap,false,!bHaveNormals,!bHaveTangents))
		{
			DestructibleMesh.MarkPendingKill();
			return false;
		}

		// Presize the per-section shadow casting array with the number of sections in the imported LOD.
		const int32 NumSections = LODModel.Sections.Num();

		for ( int32 SectionIndex = 0 ; SectionIndex < NumSections ; ++SectionIndex )
		{
			DestructibleMesh.LODInfo[0].TriangleSortSettings.AddZeroed();
		}

		if (ExistDestMeshDataPtr)
		{
			RestoreExistingDestMeshData(ExistDestMeshDataPtr, &DestructibleMesh);
			delete ExistDestMeshDataPtr;
			ExistDestMeshDataPtr = NULL;
		}

		DestructibleMesh.CalculateInvRefMatrices();
		DestructibleMesh.PostEditChange();
		DestructibleMesh.MarkPackageDirty();

#if 0 // BRGTODO : Check, we don't need this, do we?
		// We have to go and fix any AnimSetMeshLinkup objects that refer to this skeletal mesh, as the reference skeleton has changed.
		for(TObjectIterator<UAnimSet> It;It;++It)
		{
			UAnimSet* AnimSet = *It;

			// Get DestructibleMesh path name
			FName SkelMeshName = FName( *DestructibleMesh.GetPathName() );

			// See if we have already cached this Skeletal Mesh.
			const int32* IndexPtr = AnimSet->SkelMesh2LinkupCache.Find( SkelMeshName );

			if( IndexPtr )
			{
				AnimSet->LinkupCache( *IndexPtr ).BuildLinkup( &DestructibleMesh, AnimSet );
			}
		}
#endif

		// Now iterate over all skeletal mesh components re-initialising them.
		for(TObjectIterator<UDestructibleComponent> It; It; ++It)
		{
			UDestructibleComponent* DestructibleComponent = *It;
			if(DestructibleComponent->SkeletalMesh == &DestructibleMesh && DestructibleComponent->GetScene())
			{
				FComponentReregisterContext ReregisterContext(DestructibleComponent);
			}
		}
	}

#if INVERT_Y_AND_V
	// Apply transformation for Y inversion
	const physx::PxMat44 MirrorY = physx::PxMat44(physx::PxVec4(1.0f, -1.0f, 1.0f, 1.0f));
#if !USE_TEMPORARY_TRANSFORMATION_FUNCTION
	ApexDestructibleAsset.applyTransformation(MirrorY, 1.0f);
#else
	ApplyTransformationToApexDestructibleAsset( ApexDestructibleAsset, MirrorY );
#endif
#endif

	return true;
}
void UTexture::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	SetLightingGuid();

	// Determine whether any property that requires recompression of the texture, or notification to Materials has changed.
	bool RequiresNotifyMaterials = false;
	bool DeferCompressionWasEnabled = false;

	UProperty* PropertyThatChanged = PropertyChangedEvent.Property;
	if( PropertyThatChanged )
	{
		static const FName CompressionSettingsName("CompressionSettings");
		static const FName LODGroupName("LODGroup");
		static const FName DeferCompressionName("DeferCompression");
#if WITH_EDITORONLY_DATA
		static const FName MaxTextureSizeName("MaxTextureSize");
#endif // #if WITH_EDITORONLY_DATA

		const FName PropertyName = PropertyThatChanged->GetFName();
		if (PropertyName == CompressionSettingsName || PropertyName == LODGroupName)
		{
			RequiresNotifyMaterials = true;
		}
		else if (PropertyName == DeferCompressionName)
		{
			DeferCompressionWasEnabled = DeferCompression;
		}
#if WITH_EDITORONLY_DATA
		else if (PropertyName == MaxTextureSizeName)
		{
			if (MaxTextureSize <= 0)
			{
				MaxTextureSize = 0;
			}
			else
			{
				MaxTextureSize = FMath::Min<int32>(FMath::RoundUpToPowerOfTwo(MaxTextureSize), GetMaximumDimension());
			}
		}
#endif // #if WITH_EDITORONLY_DATA

		bool bPreventSRGB = (CompressionSettings == TC_Alpha || CompressionSettings == TC_Normalmap || CompressionSettings == TC_Masks || CompressionSettings == TC_HDR || CompressionSettings == TC_HDR_Compressed);
		if(bPreventSRGB && SRGB == true)
		{
			SRGB = false;
		}
	}
	else
	{
		FMaterialUpdateContext UpdateContext;
		// Update any material that uses this texture
		TSet<UMaterial*> BaseMaterialsThatUseThisTexture;
		for (TObjectIterator<UMaterialInterface> It; It; ++It)
		{
			UMaterialInterface* MaterialInterface = *It;
			if (DoesMaterialUseTexture(MaterialInterface, this))
			{
				UMaterial *Material = MaterialInterface->GetMaterial();
				bool MaterialAlreadyCompute = false;
				BaseMaterialsThatUseThisTexture.Add(Material, &MaterialAlreadyCompute);
				if (!MaterialAlreadyCompute)
				{
					UpdateContext.AddMaterial(Material);
					if (Material->IsTextureForceRecompileCacheRessource(this))
					{
						Material->UpdateMaterialShaderCacheAndTextureReferences();
					}
				}
			}
		}
		//If the DDC key was different the material is already recompile here
		RequiresNotifyMaterials = false;
	}

	NumCinematicMipLevels = FMath::Max<int32>( NumCinematicMipLevels, 0 );

	// Don't update the texture resource if we've turned "DeferCompression" on, as this 
	// would cause it to immediately update as an uncompressed texture
	if( !DeferCompressionWasEnabled && (PropertyChangedEvent.ChangeType & EPropertyChangeType::Interactive) == 0 )
	{
		// Update the texture resource. This will recache derived data if necessary
		// which may involve recompressing the texture.
		UpdateResource();
	}

	// Notify any loaded material instances if changed our compression format
	if (RequiresNotifyMaterials)
	{
		TArray<UMaterialInterface*> MaterialsThatUseThisTexture;

		// Create a material update context to safely update materials.
		{
			FMaterialUpdateContext UpdateContext;

			// Notify any material that uses this texture
			TSet<UMaterial*> BaseMaterialsThatUseThisTexture;
			for (TObjectIterator<UMaterialInterface> It; It; ++It)
			{
				UMaterialInterface* MaterialInterface = *It;
				if (DoesMaterialUseTexture(MaterialInterface,this))
				{
					MaterialsThatUseThisTexture.Add(MaterialInterface);

					// This is a bit tricky. We want to make sure all materials using this texture are
					// updated. Materials are always updated. Material instances may also have to be
					// updated and if they have static permutations their children must be updated
					// whether they use the texture or not! The safe thing to do is to add the instance's
					// base material to the update context causing all materials in the tree to update.
					BaseMaterialsThatUseThisTexture.Add(MaterialInterface->GetMaterial());
				}
			}

			// Go ahead and update any base materials that need to be.
			for (TSet<UMaterial*>::TConstIterator It(BaseMaterialsThatUseThisTexture); It; ++It)
			{
				UpdateContext.AddMaterial(*It);
				(*It)->PostEditChange();
			}
		}

		// Now that all materials and instances have updated send necessary callbacks.
		for (int32 i = 0; i < MaterialsThatUseThisTexture.Num(); ++i)
		{
			FEditorSupportDelegates::MaterialTextureSettingsChanged.Broadcast(MaterialsThatUseThisTexture[i]);
		}
	}
		
#if WITH_EDITORONLY_DATA
	// any texture that is referencing this texture as AssociatedNormalMap needs to be informed
	{
		TArray<UTexture*> TexturesThatUseThisTexture;

		for (TObjectIterator<UTexture> It; It; ++It)
		{
			UTexture* Tex = *It;

			if(Tex != this && Tex->CompositeTexture == this && Tex->CompositeTextureMode != CTM_Disabled)
			{
				TexturesThatUseThisTexture.Add(Tex);
			}
		}
		for (int32 i = 0; i < TexturesThatUseThisTexture.Num(); ++i)
		{
			TexturesThatUseThisTexture[i]->PostEditChange();
		}
	}
#endif
}
void Assignment::ApplyToMeshes()
{
	UClass *refMeshClass= AStaticMeshActor::StaticClass();
	UClass *refSkeletaMeshClass = ASkeletalMeshActor::StaticClass();

	for (TObjectIterator<UObject> Itr; Itr; ++Itr)
	{
		if (Itr->GetClass()->IsChildOf(refMeshClass))
		{
			UE_LOG(ModoMaterialImporter, Log, TEXT("Scan materials in: %s %s"), *Itr->GetName(), *Itr->GetClass()->GetDesc());

			AStaticMeshActor *aMeshActor = dynamic_cast<AStaticMeshActor*> (*Itr);

			if (aMeshActor != NULL)
			{
				UMeshComponent* meshCompo = aMeshActor->GetStaticMeshComponent();

				if (meshCompo != NULL)
				{
					for (int i = 0; i < meshCompo->GetNumMaterials(); i++)
					{
						UMaterialInterface* material = meshCompo->GetMaterial(i);

						// It seems a UE4 bug, GetNumMaterials contains NULL materials!
						if (material == NULL)
							continue;

						std::string strName = (TCHAR_TO_UTF8(*material->GetName()));

						std::map<std::string, UMaterial*>::iterator mat_itr = Materials.find(strName);
						if (mat_itr != Materials.end())
						{
							UE_LOG(ModoMaterialImporter, Log, TEXT("Set Material: %s"), *material->GetName());
							meshCompo->SetMaterial(i, mat_itr->second);
						}
					}
				}
			}
		}
		else if (Itr->GetClass()->IsChildOf(refSkeletaMeshClass))
		{
			UE_LOG(ModoMaterialImporter, Log, TEXT("Scan materials in: %s %s"), *Itr->GetName(), *Itr->GetClass()->GetDesc());

			ASkeletalMeshActor *aMeshActor = dynamic_cast<ASkeletalMeshActor*> (*Itr);

			if (aMeshActor != NULL)
			{
				UMeshComponent * meshCompo = aMeshActor->GetSkeletalMeshComponent();
				for (int i = 0; i < meshCompo->GetNumMaterials(); i++)
				{
					UMaterialInterface* material = meshCompo->GetMaterial(i);

					// It seems a UE4 bug, GetNumMaterials contains NULL materials!
					if (material == NULL)
						continue;

					std::string strName = (TCHAR_TO_UTF8(*material->GetName()));

					std::map<std::string, UMaterial*>::iterator mat_itr = Materials.find(strName);
					if (mat_itr != Materials.end())
					{
						UE_LOG(ModoMaterialImporter, Log, TEXT("Set Material: %s"), *material->GetName());
						meshCompo->SetMaterial(i, mat_itr->second);
					}
				}
			}
		}
	}
}
void FStaticMeshEditorViewportClient::ProcessClick(class FSceneView& InView, class HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY)
{
	const bool bCtrlDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl);

	bool ClearSelectedSockets = true;
	bool ClearSelectedPrims = true;
	bool ClearSelectedEdges = true;

	if( HitProxy )
	{
		if(HitProxy->IsA( HSMESocketProxy::StaticGetType() ) )
		{
			HSMESocketProxy* SocketProxy = (HSMESocketProxy*)HitProxy;

			UStaticMeshSocket* Socket = NULL;

			if(SocketProxy->SocketIndex < StaticMesh->Sockets.Num())
			{
				Socket = StaticMesh->Sockets[SocketProxy->SocketIndex];
			}

			if(Socket)
			{
				StaticMeshEditorPtr.Pin()->SetSelectedSocket(Socket);
			}

			ClearSelectedSockets = false;
		}
		else if (HitProxy->IsA(HSMECollisionProxy::StaticGetType()) && StaticMesh->BodySetup)
		{
			HSMECollisionProxy* CollisionProxy = (HSMECollisionProxy*)HitProxy;			

			if (StaticMeshEditorPtr.Pin()->IsSelectedPrim(CollisionProxy->PrimData))
			{
				if (!bCtrlDown)
				{
					StaticMeshEditorPtr.Pin()->AddSelectedPrim(CollisionProxy->PrimData, true);
				}
				else
				{
					StaticMeshEditorPtr.Pin()->RemoveSelectedPrim(CollisionProxy->PrimData);
				}
			}
			else
			{
				StaticMeshEditorPtr.Pin()->AddSelectedPrim(CollisionProxy->PrimData, !bCtrlDown);
			}

			// Force the widget to translate, if not already set
			if (WidgetMode == FWidget::WM_None)
			{
				WidgetMode = FWidget::WM_Translate;
			}

			ClearSelectedPrims = false;
		}
	}
	else
	{
		const bool bShiftDown = Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift);

		if(!bCtrlDown && !bShiftDown)
		{
			SelectedEdgeIndices.Empty();
		}

		// Check to see if we clicked on a mesh edge
		if( StaticMeshComponent != NULL && Viewport->GetSizeXY().X > 0 && Viewport->GetSizeXY().Y > 0 )
		{
			FSceneViewFamilyContext ViewFamily( FSceneViewFamily::ConstructionValues( Viewport, GetScene(), EngineShowFlags ));
			FSceneView* View = CalcSceneView(&ViewFamily);
			FViewportClick ViewportClick(View, this, Key, Event, HitX, HitY);

			const FVector ClickLineStart( ViewportClick.GetOrigin() );
			const FVector ClickLineEnd( ViewportClick.GetOrigin() + ViewportClick.GetDirection() * HALF_WORLD_MAX );

			// Don't bother doing a line check as there is only one mesh in the SME and it makes fuzzy selection difficult
			// 	FHitResult CheckResult( 1.0f );
			// 	if( StaticMeshComponent->LineCheck(
			// 			CheckResult,	// In/Out: Result
			// 			ClickLineEnd,	// Target
			// 			ClickLineStart,	// Source
			// 			FVector::ZeroVector,	// Extend
			// 			TRACE_ComplexCollision ) )	// Trace flags
			{
				// @todo: Should be in screen space ideally
				const float WorldSpaceMinClickDistance = 100.0f;

				float ClosestEdgeDistance = FLT_MAX;
				TArray< int32 > ClosestEdgeIndices;
				FVector ClosestEdgeVertices[ 2 ];

				const uint32 LODLevel = FMath::Clamp( StaticMeshComponent->ForcedLodModel - 1, 0, StaticMeshComponent->StaticMesh->GetNumLODs() - 1 );
				FRawMesh RawMesh;
				StaticMeshComponent->StaticMesh->SourceModels[LODLevel].RawMeshBulkData->LoadRawMesh(RawMesh);

				const int32 RawEdgeCount = RawMesh.WedgeIndices.Num() - 1; 
				const int32 NumFaces = RawMesh.WedgeIndices.Num() / 3;
				int32 NumBackFacingTriangles = 0;
				for(int32 FaceIndex = 0; FaceIndex < NumFaces; ++FaceIndex)
				{
					// We disable edge selection where all adjoining triangles are back face culled and the 
					// material is not two-sided. This prevents edges that are back-face culled from being selected.
					bool bIsBackFacing = false;
					bool bIsTwoSided = false;
					UMaterialInterface* Material = StaticMeshComponent->GetMaterial(RawMesh.FaceMaterialIndices[FaceIndex]);
					if (Material && Material->GetMaterial())
					{
						bIsTwoSided = Material->IsTwoSided();
					}
					if(!bIsTwoSided)
					{
						// Check whether triangle if back facing 
						const FVector A = RawMesh.GetWedgePosition( FaceIndex * 3);
						const FVector B = RawMesh.GetWedgePosition( FaceIndex * 3 + 1);
						const FVector C = RawMesh.GetWedgePosition( FaceIndex * 3 + 2);
								
						// Compute the per-triangle normal
						const FVector BA = A - B;
						const FVector CA = A - C;
						const FVector TriangleNormal = (CA ^ BA).SafeNormal();

						// Transform the view position from world to component space
						const FVector ComponentSpaceViewOrigin = StaticMeshComponent->ComponentToWorld.InverseTransformPosition( View->ViewMatrices.ViewOrigin);
								
						// Determine which side of the triangle's plane that the view position lies on.
						bIsBackFacing = (FVector::PointPlaneDist( ComponentSpaceViewOrigin,  A, TriangleNormal)  < 0.0f);
					}
						
					for( int32 VertIndex = 0; VertIndex < 3; ++VertIndex )
					{
						const int32 EdgeIndex = FaceIndex * 3 + VertIndex;
						const int32 EdgeIndex2 = FaceIndex * 3 + ((VertIndex + 1) % 3);

						FVector EdgeVertices[ 2 ];
						EdgeVertices[0]	= RawMesh.GetWedgePosition(EdgeIndex);
						EdgeVertices[1] = RawMesh.GetWedgePosition(EdgeIndex2);

						// First check to see if this edge is already in our "closest to click" list.
						// Most edges are shared by two faces in our raw triangle data set, so we want
						// to select (or deselect) both of these edges that the user clicks on (what
						// appears to be) a single edge
						if( ClosestEdgeIndices.Num() > 0 &&
							( ( EdgeVertices[ 0 ].Equals( ClosestEdgeVertices[ 0 ] ) && EdgeVertices[ 1 ].Equals( ClosestEdgeVertices[ 1 ] ) ) ||
							( EdgeVertices[ 0 ].Equals( ClosestEdgeVertices[ 1 ] ) && EdgeVertices[ 1 ].Equals( ClosestEdgeVertices[ 0 ] ) ) ) )
						{
							// Edge overlaps the closest edge we have so far, so just add it to the list
							ClosestEdgeIndices.Add( EdgeIndex );
							// Increment the number of back facing triangles if the adjoining triangle 
							// is back facing and isn't two-sided
							if(bIsBackFacing && !bIsTwoSided)
							{
								++NumBackFacingTriangles;
							}
						}
						else
						{
							FVector WorldSpaceEdgeStart( StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 0 ] ) );
							FVector WorldSpaceEdgeEnd( StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 1 ] ) );

							// Determine the mesh edge that's closest to the ray cast through the eye towards the click location
							FVector ClosestPointToEdgeOnClickLine;
							FVector ClosestPointToClickLineOnEdge;
							FMath::SegmentDistToSegment(
								ClickLineStart,
								ClickLineEnd,
								WorldSpaceEdgeStart,
								WorldSpaceEdgeEnd,
								ClosestPointToEdgeOnClickLine,
								ClosestPointToClickLineOnEdge );

							// Compute the minimum distance (squared)
							const float MinDistanceToEdgeSquared = ( ClosestPointToClickLineOnEdge - ClosestPointToEdgeOnClickLine ).SizeSquared();

							if( MinDistanceToEdgeSquared <= WorldSpaceMinClickDistance )
							{
								if( MinDistanceToEdgeSquared <= ClosestEdgeDistance )
								{
									// This is the closest edge to the click line that we've found so far!
									ClosestEdgeDistance = MinDistanceToEdgeSquared;
									ClosestEdgeVertices[ 0 ] = EdgeVertices[ 0 ];
									ClosestEdgeVertices[ 1 ] = EdgeVertices[ 1 ];

									ClosestEdgeIndices.Reset();
									ClosestEdgeIndices.Add( EdgeIndex );

									// Reset the number of back facing triangles.
									NumBackFacingTriangles = (bIsBackFacing && !bIsTwoSided) ? 1 : 0;
								}
							}
						}
					}
				}

				// Did the user click on an edge? Edges must also have at least one adjoining triangle 
				// which isn't back face culled (for one-sided materials)
				if( ClosestEdgeIndices.Num() > 0 && ClosestEdgeIndices.Num() > NumBackFacingTriangles)
				{
					for( int32 CurIndex = 0; CurIndex < ClosestEdgeIndices.Num(); ++CurIndex )
					{
						const int32 CurEdgeIndex = ClosestEdgeIndices[ CurIndex ];

						if( bCtrlDown )
						{
							// Toggle selection
							if( SelectedEdgeIndices.Contains( CurEdgeIndex ) )
							{
								SelectedEdgeIndices.Remove( CurEdgeIndex );
							}
							else
							{
								SelectedEdgeIndices.Add( CurEdgeIndex );
							}
						}
						else
						{
							// Append to selection
							SelectedEdgeIndices.Add( CurEdgeIndex );
						}
					}

					// Reset cached vertices and uv coordinates.
					SelectedEdgeVertices.Reset();
					for(int32 TexCoordIndex = 0; TexCoordIndex < MAX_STATIC_TEXCOORDS; ++TexCoordIndex)
					{
						SelectedEdgeTexCoords[TexCoordIndex].Reset();
					}

					for(FSelectedEdgeSet::TIterator SelectionIt( SelectedEdgeIndices ); SelectionIt; ++SelectionIt)
					{
						const uint32 EdgeIndex = *SelectionIt;
						const uint32 FaceIndex = EdgeIndex / 3;

						const uint32 WedgeIndex = FaceIndex * 3 + (EdgeIndex % 3);
						const uint32 WedgeIndex2 = FaceIndex * 3 + ((EdgeIndex + 1) % 3);

						// Cache edge vertices in local space.
						FVector EdgeVertices[ 2 ];
						EdgeVertices[ 0 ] = RawMesh.GetWedgePosition(WedgeIndex);
						EdgeVertices[ 1 ] = RawMesh.GetWedgePosition(WedgeIndex2);

						SelectedEdgeVertices.Add(EdgeVertices[0]);
						SelectedEdgeVertices.Add(EdgeVertices[1]);

						// Cache UV
						for(int32 TexCoordIndex = 0; TexCoordIndex < MAX_STATIC_TEXCOORDS; ++TexCoordIndex)
						{
							if( RawMesh.WedgeTexCoords[TexCoordIndex].Num() > 0)
							{
								FVector2D UVIndex1, UVIndex2;
								UVIndex1 = RawMesh.WedgeTexCoords[TexCoordIndex][WedgeIndex];
								UVIndex2 = RawMesh.WedgeTexCoords[TexCoordIndex][WedgeIndex2];
								SelectedEdgeTexCoords[TexCoordIndex].Add(UVIndex1);
								SelectedEdgeTexCoords[TexCoordIndex].Add(UVIndex2);
							}
						}
					}

					ClearSelectedEdges = false;
				}
			}
		}
	}

	if (ClearSelectedSockets && StaticMeshEditorPtr.Pin()->GetSelectedSocket())
	{
		StaticMeshEditorPtr.Pin()->SetSelectedSocket(NULL);
	}
	if (ClearSelectedPrims)
	{
		StaticMeshEditorPtr.Pin()->ClearSelectedPrims();
	}
	if (ClearSelectedEdges)
	{
		SelectedEdgeIndices.Empty();
	}

	Invalidate();
}
Beispiel #16
0
void UPhATEdSkeletalMeshComponent::RenderAssetTools(const FSceneView* View, class FPrimitiveDrawInterface* PDI, bool bHitTest)
{
	check(SharedData);

	UPhysicsAsset* const PhysicsAsset = GetPhysicsAsset();
	check(PhysicsAsset);

	bool bHitTestAndBodyMode = bHitTest && SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit;
	bool bHitTestAndConstraintMode = bHitTest && SharedData->EditingMode == FPhATSharedData::PEM_ConstraintEdit;

	FPhATSharedData::EPhATRenderMode CollisionViewMode = SharedData->GetCurrentCollisionViewMode();

#if DEBUG_CLICK_VIEWPORT
	PDI->DrawLine(SharedData->LastClickOrigin, SharedData->LastClickOrigin + SharedData->LastClickDirection * 5000.0f, FLinearColor(1, 1, 0, 1), SDPG_Foreground);
	PDI->DrawPoint(SharedData->LastClickOrigin, FLinearColor(1, 0, 0), 5, SDPG_Foreground);
#endif
	// Draw bodies
	for (int32 i = 0; i <PhysicsAsset->BodySetup.Num(); ++i)
	{
		int32 BoneIndex = GetBoneIndex(PhysicsAsset->BodySetup[i]->BoneName);

		// If we found a bone for it, draw the collision.
		// The logic is as follows; always render in the ViewMode requested when not in hit mode - but if we are in hit mode and the right editing mode, render as solid
		if (BoneIndex != INDEX_NONE)
		{
			FTransform BoneTM = GetBoneTransform(BoneIndex);
			float Scale = BoneTM.GetScale3D().GetAbsMax();
			FVector VectorScale(Scale);
			BoneTM.RemoveScaling();

			FKAggregateGeom* AggGeom = &PhysicsAsset->BodySetup[i]->AggGeom;

			for (int32 j = 0; j <AggGeom->SphereElems.Num(); ++j)
			{
				if (bHitTest)
				{
					PDI->SetHitProxy(new HPhATEdBoneProxy(i, KPT_Sphere, j));
				}

				FTransform ElemTM = GetPrimitiveTransform(BoneTM, i, KPT_Sphere, j, Scale);

				//solids are drawn if it's the ViewMode and we're not doing a hit, or if it's hitAndBodyMode
				if( (CollisionViewMode == FPhATSharedData::PRM_Solid && !bHitTest) || bHitTestAndBodyMode)
				{
					UMaterialInterface*	PrimMaterial = GetPrimitiveMaterial(i, KPT_Sphere, j, bHitTestAndBodyMode);
					AggGeom->SphereElems[j].DrawElemSolid(PDI, ElemTM, VectorScale, PrimMaterial->GetRenderProxy(0));
				}

				//wires are never used during hit
				if(!bHitTest)
				{
					if (CollisionViewMode == FPhATSharedData::PRM_Solid || CollisionViewMode == FPhATSharedData::PRM_Wireframe)
					{
						AggGeom->SphereElems[j].DrawElemWire(PDI, ElemTM, VectorScale, GetPrimitiveColor(i, KPT_Sphere, j));
					}
				}

				if (bHitTest)
				{
					PDI->SetHitProxy(NULL);
				}
				
			}

			for (int32 j = 0; j <AggGeom->BoxElems.Num(); ++j)
			{
				if (bHitTest)
				{
					PDI->SetHitProxy(new HPhATEdBoneProxy(i, KPT_Box, j));
				}

				FTransform ElemTM = GetPrimitiveTransform(BoneTM, i, KPT_Box, j, Scale);

				if ( (CollisionViewMode == FPhATSharedData::PRM_Solid && !bHitTest) || bHitTestAndBodyMode)
				{
					UMaterialInterface*	PrimMaterial = GetPrimitiveMaterial(i, KPT_Box, j, bHitTestAndBodyMode);
					AggGeom->BoxElems[j].DrawElemSolid(PDI, ElemTM, VectorScale, PrimMaterial->GetRenderProxy(0));
				}

				if(!bHitTest)
				{
					if (CollisionViewMode == FPhATSharedData::PRM_Solid || CollisionViewMode == FPhATSharedData::PRM_Wireframe)
					{
						AggGeom->BoxElems[j].DrawElemWire(PDI, ElemTM, VectorScale, GetPrimitiveColor(i, KPT_Box, j));
					}
				}
				

				if (bHitTest) 
				{
					PDI->SetHitProxy(NULL);
				}
			}

			for (int32 j = 0; j <AggGeom->SphylElems.Num(); ++j)
			{
				if (bHitTest) 
				{
					PDI->SetHitProxy(new HPhATEdBoneProxy(i, KPT_Sphyl, j));
				}

				FTransform ElemTM = GetPrimitiveTransform(BoneTM, i, KPT_Sphyl, j, Scale);

				if ( (CollisionViewMode == FPhATSharedData::PRM_Solid && !bHitTest) || bHitTestAndBodyMode)
				{
					UMaterialInterface*	PrimMaterial = GetPrimitiveMaterial(i, KPT_Sphyl, j, bHitTestAndBodyMode);
					AggGeom->SphylElems[j].DrawElemSolid(PDI, ElemTM, VectorScale, PrimMaterial->GetRenderProxy(0));
				}

				if(!bHitTest)
				{
					if (CollisionViewMode == FPhATSharedData::PRM_Solid || CollisionViewMode == FPhATSharedData::PRM_Wireframe)
					{
						AggGeom->SphylElems[j].DrawElemWire(PDI, ElemTM, VectorScale, GetPrimitiveColor(i, KPT_Sphyl, j));
					}
				}

				if (bHitTest) 
				{
					PDI->SetHitProxy(NULL);
				}
			}

			for (int32 j = 0; j <AggGeom->ConvexElems.Num(); ++j)
			{
				if (bHitTest) 
				{
					PDI->SetHitProxy(new HPhATEdBoneProxy(i, KPT_Convex, j));
				}

				FTransform ElemTM = GetPrimitiveTransform(BoneTM, i, KPT_Convex, j, Scale);

				//convex doesn't have solid draw so render lines if we're in hitTestAndBodyMode
				if(!bHitTest || bHitTestAndBodyMode)
				{
					if (CollisionViewMode == FPhATSharedData::PRM_Solid || CollisionViewMode == FPhATSharedData::PRM_Wireframe)
					{
						AggGeom->ConvexElems[j].DrawElemWire(PDI, ElemTM, Scale, GetPrimitiveColor(i, KPT_Convex, j));
					}
				}
				

				if (bHitTest) 
				{
					PDI->SetHitProxy(NULL);
				}
			}

			if (!bHitTest && SharedData->bShowCOM && Bodies.IsValidIndex(i))
			{
				Bodies[i]->DrawCOMPosition(PDI, COMRenderSize, SharedData->COMRenderColor);
			}
		}
	}

	// Draw Constraints
	FPhATSharedData::EPhATConstraintViewMode ConstraintViewMode = SharedData->GetCurrentConstraintViewMode();
	if (ConstraintViewMode != FPhATSharedData::PCV_None)
	{
		for (int32 i = 0; i <PhysicsAsset->ConstraintSetup.Num(); ++i)
		{
			int32 BoneIndex1 = GetBoneIndex(PhysicsAsset->ConstraintSetup[i]->DefaultInstance.ConstraintBone1);
			int32 BoneIndex2 = GetBoneIndex(PhysicsAsset->ConstraintSetup[i]->DefaultInstance.ConstraintBone2);
			// if bone doesn't exist, do not draw it. It crashes in random points when we try to manipulate. 
			if (BoneIndex1 != INDEX_NONE && BoneIndex2 != INDEX_NONE)
			{
				if (bHitTest) 
				{
					PDI->SetHitProxy(new HPhATEdConstraintProxy(i));
				}

				if(bHitTestAndConstraintMode || !bHitTest)
				{
					DrawConstraint(i, View, PDI, SharedData->EditorSimOptions->bShowConstraintsAsPoints);
				}
					
				if (bHitTest) 
				{
					PDI->SetHitProxy(NULL);
				}
			}
		}
	}

	if (!bHitTest && SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit && SharedData->bShowInfluences)
	{
		DrawCurrentInfluences(PDI);
	}

	// If desired, draw bone hierarchy.
	if (!bHitTest && SharedData->bShowHierarchy)
	{
		DrawHierarchy(PDI, false);
	}

	// If desired, draw animation skeleton.
	if (!bHitTest && SharedData->bShowAnimSkel)
	{
		DrawHierarchy(PDI, SharedData->bRunningSimulation);
	}
}
Beispiel #17
0
void UTexture::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	SetLightingGuid();

	// Determine whether any property that requires recompression of the texture, or notification to Materials has changed.
	bool RequiresNotifyMaterials = false;

	UProperty* PropertyThatChanged = PropertyChangedEvent.Property;
	if( PropertyThatChanged )
	{
		FString PropertyName = *PropertyThatChanged->GetName();
		if (FCString::Stricmp(*PropertyName, TEXT("CompressionSettings")) == 0)
		{
			RequiresNotifyMaterials = true;
		}

		bool bPreventSRGB = (CompressionSettings == TC_Alpha || CompressionSettings == TC_Normalmap || CompressionSettings == TC_Masks || CompressionSettings == TC_HDR);		
		if(bPreventSRGB && SRGB == true)
		{
			SRGB = false;
		}
	}

	NumCinematicMipLevels = FMath::Max<int32>( NumCinematicMipLevels, 0 );

	if( (PropertyChangedEvent.ChangeType & EPropertyChangeType::Interactive) == 0 )
	{
		// Update the texture resource. This will recache derived data if necessary
		// which may involve recompressing the texture.
		UpdateResource();
	}

	// Notify any loaded material instances if changed our compression format
	if (RequiresNotifyMaterials)
	{
		TArray<UMaterialInterface*> MaterialsThatUseThisTexture;

		// Create a material update context to safely update materials.
		{
			FMaterialUpdateContext UpdateContext;

			// Notify any material that uses this texture
			TSet<UMaterial*> BaseMaterialsThatUseThisTexture;
			for (TObjectIterator<UMaterialInterface> It; It; ++It)
			{
				UMaterialInterface* MaterialInterface = *It;
				if (DoesMaterialUseTexture(MaterialInterface,this))
				{
					MaterialsThatUseThisTexture.Add(MaterialInterface);

					// This is a bit tricky. We want to make sure all materials using this texture are
					// updated. Materials are always updated. Material instances may also have to be
					// updated and if they have static permutations their children must be updated
					// whether they use the texture or not! The safe thing to do is to add the instance's
					// base material to the update context causing all materials in the tree to update.
					BaseMaterialsThatUseThisTexture.Add(MaterialInterface->GetMaterial());
				}
			}

			// Go ahead and update any base materials that need to be.
			for (TSet<UMaterial*>::TConstIterator It(BaseMaterialsThatUseThisTexture); It; ++It)
			{
				UpdateContext.AddMaterial(*It);
				(*It)->PostEditChange();
			}
		}

		// Now that all materials and instances have updated send necessary callbacks.
		for (int32 i = 0; i < MaterialsThatUseThisTexture.Num(); ++i)
		{
			FEditorSupportDelegates::MaterialTextureSettingsChanged.Broadcast(MaterialsThatUseThisTexture[i]);
		}
	}
		
#if WITH_EDITORONLY_DATA
	// any texture that is referencing this texture as AssociatedNormalMap needs to be informed
	{
		TArray<UTexture*> TexturesThatUseThisTexture;

		for (TObjectIterator<UTexture> It; It; ++It)
		{
			UTexture* Tex = *It;

			if(Tex != this && Tex->CompositeTexture == this && Tex->CompositeTextureMode != CTM_Disabled)
			{
				TexturesThatUseThisTexture.Add(Tex);
			}
		}
		for (int32 i = 0; i < TexturesThatUseThisTexture.Num(); ++i)
		{
			TexturesThatUseThisTexture[i]->PostEditChange();
		}
	}
#endif
}