void URuntimeMeshLibrary::CopyStaticMeshToRuntimeMesh(UStaticMeshComponent* StaticMeshComponent, int32 LODIndex, URuntimeMesh* RuntimeMesh, bool bCreateCollision)
{
	SCOPE_CYCLE_COUNTER(STAT_RuntimeMeshLibrary_CopyStaticMeshToRuntimeMesh);
	if (StaticMeshComponent != nullptr &&
		StaticMeshComponent->GetStaticMesh() != nullptr &&
		RuntimeMesh != nullptr)
	{
		UStaticMesh* StaticMesh = StaticMeshComponent->GetStaticMesh();

		RuntimeMesh->ClearAllMeshSections();

		//// MESH DATA

		int32 NumSections = StaticMesh->GetNumSections(LODIndex);
		for (int32 SectionIndex = 0; SectionIndex < NumSections; SectionIndex++)
		{
			// Buffers for copying geom data
			TSharedPtr<FRuntimeMeshBuilder> MeshData = MakeRuntimeMeshBuilder<FRuntimeMeshTangents, FVector2DHalf, uint32>();
			TArray<uint8> AdjacencyTrianglesData;
			TSharedPtr<FRuntimeMeshIndicesAccessor> AdjacencyTrianglesAccessor = MakeShared<FRuntimeMeshIndicesAccessor>(true, &AdjacencyTrianglesData);
			TArray<uint32> AdjacencyTriangles;
			AdjacencyTriangles.SetNum(AdjacencyTrianglesData.Num() / 4);
			FMemory::Memcpy(AdjacencyTriangles.GetData(), AdjacencyTrianglesData.GetData(), AdjacencyTrianglesData.Num());


			// TODO: Make this smarter to setup a mesh section to match the static mesh vertex configuration
			// This will let it pick up the additional UVs or high pri normals/tangents/uvs

			// Get geom data from static mesh
			GetStaticMeshSection(StaticMesh, LODIndex, SectionIndex, MeshData, AdjacencyTrianglesAccessor);

			// Create RuntimeMesh
			RuntimeMesh->CreateMeshSection(SectionIndex, MeshData, bCreateCollision);
			RuntimeMesh->SetSectionTessellationTriangles(SectionIndex, AdjacencyTriangles);
		}

		//// SIMPLE COLLISION
		CopyCollisionFromStaticMesh(StaticMesh, RuntimeMesh);


		//// MATERIALS

		for (int32 MatIndex = 0; MatIndex < StaticMeshComponent->GetNumMaterials(); MatIndex++)
		{
			RuntimeMesh->SetSectionMaterial(MatIndex, StaticMeshComponent->GetMaterial(MatIndex));
		}
	}
}
EReimportResult::Type UReimportSpeedTreeFactory::Reimport(UObject* Obj)
{
#if WITH_SPEEDTREE
	UStaticMesh* Mesh = Cast<UStaticMesh>(Obj);
	if (!Mesh)
	{
		return EReimportResult::Failed;
	}

	const FString Filename = Mesh->AssetImportData->GetFirstFilename();
	const FString FileExtension = FPaths::GetExtension(Filename);
	const bool bIsSRT = FCString::Stricmp(*FileExtension, TEXT("SRT")) == 0;

	if (!bIsSRT)
	{
		return EReimportResult::Failed;
	}

	if (!(Filename.Len()))
	{
		// Since this is a new system most static meshes don't have paths, so logging has been commented out
		//UE_LOG(LogEditorFactories, Warning, TEXT("-- cannot reimport: static mesh resource does not have path stored."));
		return EReimportResult::Failed;
	}

	UE_LOG(LogEditorFactories, Log, TEXT("Performing atomic reimport of [%s]"), *Filename);

	if (UFactory::StaticImportObject(Mesh->GetClass(), Mesh->GetOuter(), *Mesh->GetName(), RF_Public | RF_Standalone, *Filename, NULL, this))
	{
		UE_LOG(LogEditorFactories, Log, TEXT("-- imported successfully"));

		Mesh->AssetImportData->Update(Filename);

		// Mark the package dirty after the successful import
		Mesh->MarkPackageDirty();

		return EReimportResult::Succeeded;
	}
	else
	{
		UE_LOG(LogEditorFactories, Warning, TEXT("-- import failed"));
	}
#endif // #if WITH_SPEEDTREE
	return EReimportResult::Failed;
}
FReply FProceduralMeshComponentDetails::ClickedOnConvertToStaticMesh()
{
    // Find first selected ProcMeshComp
    UProceduralMeshComponent* ProcMeshComp = GetFirstSelectedProcMeshComp();
    if (ProcMeshComp != nullptr)
    {
        FString NewNameSuggestion = FString(TEXT("ProcMesh"));
        FString PackageName = FString(TEXT("/Game/Meshes/")) + NewNameSuggestion;
        FString Name;
        FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
        AssetToolsModule.Get().CreateUniqueAssetName(PackageName, TEXT(""), PackageName, Name);

        TSharedPtr<SDlgPickAssetPath> PickAssetPathWidget =
            SNew(SDlgPickAssetPath)
            .Title(LOCTEXT("ConvertToStaticMeshPickName", "Choose New StaticMesh Location"))
            .DefaultAssetPath(FText::FromString(PackageName));

        if (PickAssetPathWidget->ShowModal() == EAppReturnType::Ok)
        {
            // Get the full name of where we want to create the physics asset.
            FString UserPackageName = PickAssetPathWidget->GetFullAssetPath().ToString();
            FName MeshName(*FPackageName::GetLongPackageAssetName(UserPackageName));

            // Check if the user inputed a valid asset name, if they did not, give it the generated default name
            if (MeshName == NAME_None)
            {
                // Use the defaults that were already generated.
                UserPackageName = PackageName;
                MeshName = *Name;
            }

            // Raw mesh data we are filling in
            FRawMesh RawMesh;
            // Materials to apply to new mesh
            TArray<UMaterialInterface*> MeshMaterials;

            const int32 NumSections = ProcMeshComp->GetNumSections();
            int32 VertexBase = 0;
            for (int32 SectionIdx = 0; SectionIdx < NumSections; SectionIdx++)
            {
                FProcMeshSection* ProcSection = ProcMeshComp->GetProcMeshSection(SectionIdx);

                // Copy verts
                for (FProcMeshVertex& Vert : ProcSection->ProcVertexBuffer)
                {
                    RawMesh.VertexPositions.Add(Vert.Position);
                }

                // Copy 'wedge' info
                int32 NumIndices = ProcSection->ProcIndexBuffer.Num();
                for (int32 IndexIdx=0; IndexIdx < NumIndices; IndexIdx++)
                {
                    int32 Index = ProcSection->ProcIndexBuffer[IndexIdx];

                    RawMesh.WedgeIndices.Add(Index + VertexBase);

                    FProcMeshVertex& ProcVertex = ProcSection->ProcVertexBuffer[Index];

                    FVector TangentX = ProcVertex.Tangent.TangentX;
                    FVector TangentZ = ProcVertex.Normal;
                    FVector TangentY = (TangentX ^ TangentZ).GetSafeNormal() * (ProcVertex.Tangent.bFlipTangentY ? -1.f : 1.f);

                    RawMesh.WedgeTangentX.Add(TangentX);
                    RawMesh.WedgeTangentY.Add(TangentY);
                    RawMesh.WedgeTangentZ.Add(TangentZ);

                    RawMesh.WedgeTexCoords[0].Add(ProcVertex.UV0);
                    RawMesh.WedgeColors.Add(ProcVertex.Color);
                }

                // copy face info
                int32 NumTris = NumIndices / 3;
                for (int32 TriIdx=0; TriIdx < NumTris; TriIdx++)
                {
                    RawMesh.FaceMaterialIndices.Add(SectionIdx);
                    RawMesh.FaceSmoothingMasks.Add(0); // Assume this is ignored as bRecomputeNormals is false
                }

                // Remember material
                MeshMaterials.Add(ProcMeshComp->GetMaterial(SectionIdx));

                // Update offset for creating one big index/vertex buffer
                VertexBase += ProcSection->ProcVertexBuffer.Num();
            }

            // If we got some valid data.
            if (RawMesh.VertexPositions.Num() > 3 && RawMesh.WedgeIndices.Num() > 3)
            {
                // Then find/create it.
                UPackage* Package = CreatePackage(NULL, *UserPackageName);
                check(Package);

                // Create StaticMesh object
                UStaticMesh* StaticMesh = NewObject<UStaticMesh>(Package, MeshName, RF_Public | RF_Standalone);
                StaticMesh->InitResources();

                StaticMesh->LightingGuid = FGuid::NewGuid();

                // Add source to new StaticMesh
                FStaticMeshSourceModel* SrcModel = new (StaticMesh->SourceModels) FStaticMeshSourceModel();
                SrcModel->BuildSettings.bRecomputeNormals = false;
                SrcModel->BuildSettings.bRecomputeTangents = false;
                SrcModel->BuildSettings.bRemoveDegenerates = false;
                SrcModel->BuildSettings.bUseHighPrecisionTangentBasis = false;
                SrcModel->BuildSettings.bUseFullPrecisionUVs = false;
                SrcModel->BuildSettings.bGenerateLightmapUVs = true;
                SrcModel->BuildSettings.SrcLightmapIndex = 0;
                SrcModel->BuildSettings.DstLightmapIndex = 1;
                SrcModel->RawMeshBulkData->SaveRawMesh(RawMesh);

                // Copy materials to new mesh
                for (UMaterialInterface* Material : MeshMaterials)
                {
                    StaticMesh->StaticMaterials.Add(FStaticMaterial(Material));
                }

                // Build mesh from source
                StaticMesh->Build(false);
                StaticMesh->PostEditChange();

                // Notify asset registry of new asset
                FAssetRegistryModule::AssetCreated(StaticMesh);
            }
        }
    }

    return FReply::Handled();
}
EReimportResult::Type UReimportFbxSceneFactory::ReimportStaticMesh(void* VoidFbxImporter, TSharedPtr<FFbxMeshInfo> MeshInfo)
{
	UnFbx::FFbxImporter* FbxImporter = (UnFbx::FFbxImporter*)VoidFbxImporter;
	//Find the UObject associate with this MeshInfo
	UPackage* PkgExist = LoadPackage(nullptr, *(MeshInfo->GetImportPath()), LOAD_Verify | LOAD_NoWarn);
	if (PkgExist != nullptr)
	{
		PkgExist->FullyLoad();
	}

	FString AssetName = MeshInfo->GetFullImportName();
	UStaticMesh* Mesh = FindObjectSafe<UStaticMesh>(ANY_PACKAGE, *AssetName);
	if (Mesh == nullptr)
	{
		//We reimport only static mesh here
		FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(FText::FromString("Reimport Mesh {0} fail, the original staicmesh in the content browser cannot be load."), FText::FromString(MeshInfo->GetImportPath()))), FName(TEXT("Reimport Fbx Scene")));
		return EReimportResult::Failed;
	}
	
	//Copy default options to StaticMeshImportData
	SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(GlobalImportSettingsReference, SceneImportOptionsStaticMesh);
	SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions);

	UnFbx::FBXImportOptions* OverrideImportSettings = GetOptionsFromName(MeshInfo->OptionName);
	if (OverrideImportSettings != nullptr)
	{
		SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(OverrideImportSettings, GlobalImportSettings);
		SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(OverrideImportSettings, SceneImportOptionsStaticMesh);
	}
	else
	{
		SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(GlobalImportSettingsReference, GlobalImportSettings);
		SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(GlobalImportSettingsReference, SceneImportOptionsStaticMesh);
	}
	SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions);

	FbxImporter->ApplyTransformSettingsToFbxNode(FbxImporter->Scene->GetRootNode(), StaticMeshImportData);
	const TArray<UAssetUserData*>* UserData = Mesh->GetAssetUserDataArray();
	TArray<UAssetUserData*> UserDataCopy;
	if (UserData)
	{
		for (int32 Idx = 0; Idx < UserData->Num(); Idx++)
		{
			UserDataCopy.Add((UAssetUserData*)StaticDuplicateObject((*UserData)[Idx], GetTransientPackage()));
		}
	}

	// preserve settings in navcollision subobject
	UNavCollision* NavCollision = Mesh->NavCollision ?
		(UNavCollision*)StaticDuplicateObject(Mesh->NavCollision, GetTransientPackage()) :
		nullptr;

	// preserve extended bound settings
	const FVector PositiveBoundsExtension = Mesh->PositiveBoundsExtension;
	const FVector NegativeBoundsExtension = Mesh->NegativeBoundsExtension;
	Mesh = FbxImporter->ReimportSceneStaticMesh(MeshInfo->UniqueId, Mesh, StaticMeshImportData);
	if (Mesh != nullptr)
	{
		//Put back the new mesh data since the reimport is putting back the original import data
		SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions);
		Mesh->AssetImportData = StaticMeshImportData;

		// Copy user data to newly created mesh
		for (int32 Idx = 0; Idx < UserDataCopy.Num(); Idx++)
		{
			UserDataCopy[Idx]->Rename(nullptr, Mesh, REN_DontCreateRedirectors | REN_DoNotDirty);
			Mesh->AddAssetUserData(UserDataCopy[Idx]);
		}

		if (NavCollision)
		{
			Mesh->NavCollision = NavCollision;
			NavCollision->Rename(nullptr, Mesh, REN_DontCreateRedirectors | REN_DoNotDirty);
		}

		// Restore bounds extension settings
		Mesh->PositiveBoundsExtension = PositiveBoundsExtension;
		Mesh->NegativeBoundsExtension = NegativeBoundsExtension;

		Mesh->AssetImportData->Update(FbxImportFileName);

		// Try to find the outer package so we can dirty it up
		if (Mesh->GetOutermost())
		{
			Mesh->GetOutermost()->MarkPackageDirty();
		}
		else
		{
			Mesh->MarkPackageDirty();
		}
		AllNewAssets.Add(MeshInfo, Mesh);
		AssetToSyncContentBrowser.Add(Mesh);
	}
	else
	{
		return EReimportResult::Failed;
	}
	return EReimportResult::Succeeded;
}
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);
}
static void StaticMeshToSlateRenderData(const UStaticMesh& DataSource, TArray<FSlateMeshVertex>& OutSlateVerts, TArray<uint32>& OutIndexes, FVector2D& OutExtentMin, FVector2D& OutExtentMax )
{
	OutExtentMin = FVector2D(FLT_MAX, FLT_MAX);
	OutExtentMax = FVector2D(-FLT_MAX, -FLT_MAX);

	const FStaticMeshLODResources& LOD = DataSource.RenderData->LODResources[0];
	const int32 NumSections = LOD.Sections.Num();
	if (NumSections > 1)
	{
		UE_LOG(LogUMG, Warning, TEXT("StaticMesh %s has %d sections. SMeshWidget expects a static mesh with 1 section."), *DataSource.GetName(), NumSections);
	}
	else
	{
		// Populate Vertex Data
		{
			const uint32 NumVerts = LOD.PositionVertexBuffer.GetNumVertices();
			OutSlateVerts.Empty();
			OutSlateVerts.Reserve(NumVerts);

			static const int32 MAX_SUPPORTED_UV_SETS = 6;
			const int32 TexCoordsPerVertex = LOD.GetNumTexCoords();
			if (TexCoordsPerVertex > MAX_SUPPORTED_UV_SETS)
			{
				UE_LOG(LogStaticMesh, Warning, TEXT("[%s] has %d UV sets; slate vertex data supports at most %d"), *DataSource.GetName(), TexCoordsPerVertex, MAX_SUPPORTED_UV_SETS);
			}

			for (uint32 i = 0; i < NumVerts; ++i)
			{
				// Copy Position
				const FVector& Position = LOD.PositionVertexBuffer.VertexPosition(i);
				OutExtentMin.X = FMath::Min(Position.X, OutExtentMin.X);
				OutExtentMin.Y = FMath::Min(Position.Y, OutExtentMin.Y);
				OutExtentMax.X = FMath::Max(Position.X, OutExtentMax.X);
				OutExtentMax.Y = FMath::Max(Position.Y, OutExtentMax.Y);
				
				// Copy Color
				FColor Color = (LOD.ColorVertexBuffer.GetNumVertices() > 0) ? LOD.ColorVertexBuffer.VertexColor(i) : FColor::White;
				
				// Copy all the UVs that we have, and as many as we can fit.
				const FVector2D& UV0 = (TexCoordsPerVertex > 0) ? LOD.VertexBuffer.GetVertexUV(i, 0) : FVector2D(1, 1);

				const FVector2D& UV1 = (TexCoordsPerVertex > 1) ? LOD.VertexBuffer.GetVertexUV(i, 1) : FVector2D(1, 1);

				const FVector2D& UV2 = (TexCoordsPerVertex > 2) ? LOD.VertexBuffer.GetVertexUV(i, 2) : FVector2D(1, 1);

				const FVector2D& UV3 = (TexCoordsPerVertex > 3) ? LOD.VertexBuffer.GetVertexUV(i, 3) : FVector2D(1, 1);

				const FVector2D& UV4 = (TexCoordsPerVertex > 4) ? LOD.VertexBuffer.GetVertexUV(i, 4) : FVector2D(1, 1);

				const FVector2D& UV5 = (TexCoordsPerVertex > 5) ? LOD.VertexBuffer.GetVertexUV(i, 5) : FVector2D(1, 1);

				OutSlateVerts.Add(FSlateMeshVertex(
					FVector2D(Position.X, Position.Y),
					Color,
					UV0,
					UV1,
					UV2,
					UV3,
					UV4,
					UV5
				));
			}
		}

		// Populate Index data
		{
			FIndexArrayView SourceIndexes = LOD.IndexBuffer.GetArrayView();
			const int32 NumIndexes = SourceIndexes.Num();
			OutIndexes.Empty();
			OutIndexes.Reserve(NumIndexes);
			for (int32 i = 0; i < NumIndexes; ++i)
			{
				OutIndexes.Add(SourceIndexes[i]);
			}


			// Sort the index buffer such that verts are drawn in Z-order.
			// Assume that all triangles are coplanar with Z == SomeValue.
			ensure(NumIndexes % 3 == 0);
			for (int32 a = 0; a < NumIndexes; a += 3)
			{
				for (int32 b = 0; b < NumIndexes; b += 3)
				{
					const float VertADepth = LOD.PositionVertexBuffer.VertexPosition(OutIndexes[a]).Z;
					const float VertBDepth = LOD.PositionVertexBuffer.VertexPosition(OutIndexes[b]).Z;
					if ( VertADepth < VertBDepth )
					{
						// Swap the order in which triangles will be drawn
						Swap(OutIndexes[a + 0], OutIndexes[b + 0]);
						Swap(OutIndexes[a + 1], OutIndexes[b + 1]);
						Swap(OutIndexes[a + 2], OutIndexes[b + 2]);
					}
				}
			}
		}
	}
}
FReply FRuntimeMeshComponentDetails::ClickedOnConvertToStaticMesh()
{
 	// Find first selected RuntimeMeshComp
 	URuntimeMeshComponent* RuntimeMeshComp = GetFirstSelectedRuntimeMeshComp();
 	if (RuntimeMeshComp != nullptr)
 	{
 		FString NewNameSuggestion = FString(TEXT("RuntimeMeshComp"));
 		FString PackageName = FString(TEXT("/Game/Meshes/")) + NewNameSuggestion;
 		FString Name;
 		FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
 		AssetToolsModule.Get().CreateUniqueAssetName(PackageName, TEXT(""), PackageName, Name);
 
 		TSharedPtr<SDlgPickAssetPath> PickAssetPathWidget =
 			SNew(SDlgPickAssetPath)
 			.Title(LOCTEXT("ConvertToStaticMeshPickName", "Choose New StaticMesh Location"))
 			.DefaultAssetPath(FText::FromString(PackageName));
 
 		if (PickAssetPathWidget->ShowModal() == EAppReturnType::Ok)
 		{
 			// Get the full name of where we want to create the physics asset.
 			FString UserPackageName = PickAssetPathWidget->GetFullAssetPath().ToString();
 			FName MeshName(*FPackageName::GetLongPackageAssetName(UserPackageName));
 
 			// Check if the user inputed a valid asset name, if they did not, give it the generated default name
 			if (MeshName == NAME_None)
 			{
 				// Use the defaults that were already generated.
 				UserPackageName = PackageName;
 				MeshName = *Name;
 			}
 
 			// Raw mesh data we are filling in
 			FRawMesh RawMesh;
 					
			// Unique Materials to apply to new mesh
#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 14
			TArray<FStaticMaterial> Materials;
#else
			TArray<UMaterialInterface*> Materials;
#endif
 
			bool bUseHighPrecisionTangents = false;
			bool bUseFullPrecisionUVs = false;

 			const int32 NumSections = RuntimeMeshComp->GetNumSections();
 			int32 VertexBase = 0;
 			for (int32 SectionIdx = 0; SectionIdx < NumSections; SectionIdx++)
 			{
				const IRuntimeMeshVerticesBuilder* Vertices;
				const FRuntimeMeshIndicesBuilder* Indices;
				RuntimeMeshComp->GetSectionMesh(SectionIdx, Vertices, Indices);

				if (Vertices->HasHighPrecisionNormals())
				{
					bUseHighPrecisionTangents = true;
				}
				if (Vertices->HasHighPrecisionUVs())
				{
					bUseFullPrecisionUVs = true;
				}
 
 				// Copy verts
				Vertices->Seek(-1);
				while (Vertices->MoveNext() < Vertices->Length())
				{
					RawMesh.VertexPositions.Add(Vertices->GetPosition());
				}
 
 				// Copy 'wedge' info
				Indices->Seek(0);
				while (Indices->HasRemaining())
 				{
					int32 Index = Indices->ReadOne();
 
 					RawMesh.WedgeIndices.Add(Index + VertexBase);
 

					Vertices->Seek(Index);
 
					FVector TangentX = Vertices->GetTangent();
					FVector TangentZ = Vertices->GetNormal();
 					FVector TangentY = (TangentX ^ TangentZ).GetSafeNormal() * Vertices->GetNormal().W;
 
 					RawMesh.WedgeTangentX.Add(TangentX);
 					RawMesh.WedgeTangentY.Add(TangentY);
 					RawMesh.WedgeTangentZ.Add(TangentZ);
 
					for (int UVIndex = 0; UVIndex < 8; UVIndex++)
					{
						if (!Vertices->HasUVComponent(UVIndex))
						{
							break;
						}
						RawMesh.WedgeTexCoords[UVIndex].Add(Vertices->GetUV(UVIndex));
					}

 					RawMesh.WedgeColors.Add(Vertices->GetColor());
 				}
 
				// Find a material index for this section.
				UMaterialInterface* Material = RuntimeMeshComp->GetMaterial(SectionIdx);

#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 14
				int32 MaterialIndex = Materials.AddUnique(FStaticMaterial(Material));
#else
				int32 MaterialIndex = Materials.AddUnique(Material);
#endif
				

 				// copy face info
 				int32 NumTris = Indices->Length() / 3;
 				for (int32 TriIdx=0; TriIdx < NumTris; TriIdx++)
 				{
					// Set the face material
					RawMesh.FaceMaterialIndices.Add(MaterialIndex);

 					RawMesh.FaceSmoothingMasks.Add(0); // Assume this is ignored as bRecomputeNormals is false
 				}
 
 				// Update offset for creating one big index/vertex buffer
				VertexBase += Vertices->Length();
 			}
 
 			// If we got some valid data.
 			if (RawMesh.VertexPositions.Num() >= 3 && RawMesh.WedgeIndices.Num() >= 3)
 			{
 				// Then find/create it.
 				UPackage* Package = CreatePackage(NULL, *UserPackageName);
 				check(Package);
 
 				// Create StaticMesh object
 				UStaticMesh* StaticMesh = NewObject<UStaticMesh>(Package, MeshName, RF_Public | RF_Standalone);
 				StaticMesh->InitResources();
 
 				StaticMesh->LightingGuid = FGuid::NewGuid();
 
 				// Add source to new StaticMesh
 				FStaticMeshSourceModel* SrcModel = new (StaticMesh->SourceModels) FStaticMeshSourceModel();
 				SrcModel->BuildSettings.bRecomputeNormals = false;
 				SrcModel->BuildSettings.bRecomputeTangents = false;
 				SrcModel->BuildSettings.bRemoveDegenerates = false;
 				SrcModel->BuildSettings.bUseHighPrecisionTangentBasis = bUseHighPrecisionTangents;
				SrcModel->BuildSettings.bUseFullPrecisionUVs = bUseFullPrecisionUVs;
 				SrcModel->BuildSettings.bGenerateLightmapUVs = true;
 				SrcModel->BuildSettings.SrcLightmapIndex = 0;
 				SrcModel->BuildSettings.DstLightmapIndex = 1;
 				SrcModel->RawMeshBulkData->SaveRawMesh(RawMesh);
 
				// Set the materials used for this static mesh
#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 14
				StaticMesh->StaticMaterials = Materials;
				int32 NumMaterials = StaticMesh->StaticMaterials.Num();
#else
				StaticMesh->Materials = Materials;
				int32 NumMaterials = StaticMesh->Materials.Num();
#endif

				// Set up the SectionInfoMap to enable collision
				for (int32 SectionIdx = 0; SectionIdx < NumMaterials; SectionIdx++)
				{
					FMeshSectionInfo Info = StaticMesh->SectionInfoMap.Get(0, SectionIdx);
					Info.MaterialIndex = SectionIdx;
					Info.bEnableCollision = true;
					StaticMesh->SectionInfoMap.Set(0, SectionIdx, Info);
				}

				// Configure body setup for working collision.
				StaticMesh->CreateBodySetup();
				StaticMesh->BodySetup->CollisionTraceFlag = CTF_UseComplexAsSimple;

 				// Build mesh from source
 				StaticMesh->Build(false);

				// Make package dirty.
				StaticMesh->MarkPackageDirty();

 				StaticMesh->PostEditChange();
 
 				// Notify asset registry of new asset
 				FAssetRegistryModule::AssetCreated(StaticMesh);
 			}
 		}
 	}

	return FReply::Handled();
}