PyObject *py_ue_skeletal_mesh_set_skeleton(ue_PyUObject * self, PyObject * args)
{
	ue_py_check(self);

	PyObject *py_skeleton;
	if (!PyArg_ParseTuple(args, "O:skeletal_mesh_set_skeleton", &py_skeleton))
		return nullptr;

	USkeletalMesh *mesh = ue_py_check_type<USkeletalMesh>(self);
	if (!mesh)
		return PyErr_Format(PyExc_Exception, "UObject is not a USkeletalMesh.");

	USkeleton *skeleton = ue_py_check_type<USkeleton>(py_skeleton);
	if (!skeleton)
		return PyErr_Format(PyExc_Exception, "argument is not a USkeleton.");

	mesh->ReleaseResources();
	mesh->ReleaseResourcesFence.Wait();

	mesh->Skeleton = skeleton;

	mesh->RefSkeleton = skeleton->GetReferenceSkeleton();

	mesh->RefBasesInvMatrix.Empty();
	mesh->CalculateInvRefMatrices();

#if WITH_EDITOR
	mesh->PostEditChange();
#endif
	mesh->InitResources();
	mesh->MarkPackageDirty();

	Py_RETURN_NONE;
}
void FLODUtilities::RemoveLOD(FSkeletalMeshUpdateContext& UpdateContext, int32 DesiredLOD )
{
	USkeletalMesh* SkeletalMesh = UpdateContext.SkeletalMesh;
	FSkeletalMeshResource* SkelMeshResource = SkeletalMesh->GetImportedResource();

	if( SkelMeshResource->LODModels.Num() == 1 )
	{
		FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "NoLODToRemove", "No LODs to remove!") );
		return;
	}

	// Now display combo to choose which LOD to remove.
	TArray<FString> LODStrings;
	LODStrings.AddZeroed( SkelMeshResource->LODModels.Num()-1 );
	for(int32 i=0; i<SkelMeshResource->LODModels.Num()-1; i++)
	{
		LODStrings[i] = FString::Printf( TEXT("%d"), i+1 );
	}

	check( SkeletalMesh->LODInfo.Num() == SkelMeshResource->LODModels.Num() );

	// If its a valid LOD, kill it.
	if( DesiredLOD > 0 && DesiredLOD < SkelMeshResource->LODModels.Num() )
	{
		//We'll be modifying the skel mesh data so reregister

		//TODO - do we need to reregister something else instead?
		FMultiComponentReregisterContext ReregisterContext(UpdateContext.AssociatedComponents);

		// Release rendering resources before deleting LOD
		SkelMeshResource->ReleaseResources();

		// Block until this is done
		FlushRenderingCommands();

		SkelMeshResource->LODModels.RemoveAt(DesiredLOD);
		SkeletalMesh->LODInfo.RemoveAt(DesiredLOD);
		SkeletalMesh->InitResources();

		RefreshLODChange(SkeletalMesh);

		// Set the forced LOD to Auto.
		for(auto Iter = UpdateContext.AssociatedComponents.CreateIterator(); Iter; ++Iter)
		{
			USkinnedMeshComponent* SkinnedComponent = Cast<USkinnedMeshComponent>(*Iter);
			if(SkinnedComponent)
			{
				SkinnedComponent->ForcedLodModel = 0;
			}
		}
		
		//Notify calling system of change
		UpdateContext.OnLODChanged.ExecuteIfBound();

		// Mark things for saving.
		SkeletalMesh->MarkPackageDirty();
	}
}
PyObject *py_ue_skeletal_mesh_set_required_bones(ue_PyUObject *self, PyObject * args)
{
	ue_py_check(self);

	PyObject *py_map;
	int lod_index = 0;
	if (!PyArg_ParseTuple(args, "O|i:skeletal_mesh_set_required_bones", &py_map, &lod_index))
		return nullptr;

	USkeletalMesh *mesh = ue_py_check_type<USkeletalMesh>(self);
	if (!mesh)
		return PyErr_Format(PyExc_Exception, "uobject is not a USkeletalMesh");

#if ENGINE_MINOR_VERSION < 19
	FSkeletalMeshResource *resource = mesh->GetImportedResource();
#else
	FSkeletalMeshModel *resource = mesh->GetImportedModel();
#endif

	if (lod_index < 0 || lod_index >= resource->LODModels.Num())
		return PyErr_Format(PyExc_Exception, "invalid LOD index, must be between 0 and %d", resource->LODModels.Num() - 1);

#if ENGINE_MINOR_VERSION < 19
	FStaticLODModel &model = resource->LODModels[lod_index];
#else
	FSkeletalMeshLODModel &model = resource->LODModels[lod_index];
#endif

	PyObject *py_iter = PyObject_GetIter(py_map);
	if (!py_iter)
	{
		return PyErr_Format(PyExc_Exception, "argument is not an iterable of numbers");
	}

	TArray<FBoneIndexType> required_bones;

	while (PyObject *py_item = PyIter_Next(py_iter))
	{
		if (!PyNumber_Check(py_item))
		{
			Py_DECREF(py_iter);
			return PyErr_Format(PyExc_Exception, "argument is not an iterable of numbers");
		}
		PyObject *py_num = PyNumber_Long(py_item);
		uint16 index = PyLong_AsUnsignedLong(py_num);
		Py_DECREF(py_num);
		required_bones.Add(index);
	}
	Py_DECREF(py_iter);

	// temporarily disable all USkinnedMeshComponent's
	TComponentReregisterContext<USkinnedMeshComponent> ReregisterContext;

	mesh->ReleaseResources();
	mesh->ReleaseResourcesFence.Wait();

	model.RequiredBones = required_bones;
	model.RequiredBones.Sort();

	mesh->RefBasesInvMatrix.Empty();
	mesh->CalculateInvRefMatrices();

#if WITH_EDITOR
	mesh->PostEditChange();
#endif
	mesh->InitResources();
	mesh->MarkPackageDirty();

	Py_RETURN_NONE;
}
PyObject *py_ue_skeletal_mesh_set_soft_vertices(ue_PyUObject *self, PyObject * args)
{
	ue_py_check(self);

	PyObject *py_ss_vertex;
	int lod_index = 0;
	int section_index = 0;
	if (!PyArg_ParseTuple(args, "O|ii:skeletal_mesh_set_soft_vertices", &py_ss_vertex, &lod_index, &section_index))
		return nullptr;

	USkeletalMesh *mesh = ue_py_check_type<USkeletalMesh>(self);
	if (!mesh)
		return PyErr_Format(PyExc_Exception, "uobject is not a USkeletalMesh");

#if ENGINE_MINOR_VERSION < 19
	FSkeletalMeshResource *resource = mesh->GetImportedResource();
#else
	FSkeletalMeshModel *resource = mesh->GetImportedModel();
#endif

	if (lod_index < 0 || lod_index >= resource->LODModels.Num())
		return PyErr_Format(PyExc_Exception, "invalid LOD index, must be between 0 and %d", resource->LODModels.Num() - 1);

#if ENGINE_MINOR_VERSION < 19
	FStaticLODModel &model = resource->LODModels[lod_index];
#else
	FSkeletalMeshLODModel &model = resource->LODModels[lod_index];
#endif

	if (section_index < 0 || section_index >= model.Sections.Num())
		return PyErr_Format(PyExc_Exception, "invalid Section index, must be between 0 and %d", model.Sections.Num() - 1);

	PyObject *py_iter = PyObject_GetIter(py_ss_vertex);
	if (!py_iter)
	{
		return PyErr_Format(PyExc_Exception, "argument is not an iterable of FSoftSkinVertex");
	}

	TArray<FSoftSkinVertex> soft_vertices;

	while (PyObject *py_item = PyIter_Next(py_iter))
	{
		ue_PyFSoftSkinVertex *ss_vertex = py_ue_is_fsoft_skin_vertex(py_item);
		if (!ss_vertex)
		{
			Py_DECREF(py_iter);
			return PyErr_Format(PyExc_Exception, "argument is not an iterable of FSoftSkinVertex");
		}
		soft_vertices.Add(ss_vertex->ss_vertex);
	}
	Py_DECREF(py_iter);

	// temporarily disable all USkinnedMeshComponent's
	TComponentReregisterContext<USkinnedMeshComponent> ReregisterContext;

	mesh->ReleaseResources();
	mesh->ReleaseResourcesFence.Wait();

	model.Sections[section_index].SoftVertices = soft_vertices;

	model.Sections[section_index].NumVertices = soft_vertices.Num();
	model.Sections[section_index].CalcMaxBoneInfluences();

	mesh->RefBasesInvMatrix.Empty();
	mesh->CalculateInvRefMatrices();

#if WITH_EDITOR
	mesh->PostEditChange();
#endif

	mesh->InitResources();
	mesh->MarkPackageDirty();

	Py_RETURN_NONE;

}