void DecomposeUCXMesh( const TArray<FVector>& CollisionVertices, const TArray<int32>& CollisionFaceIdx, UBodySetup* BodySetup )
{
    // We keep no ref to this Model, so it will be GC'd at some point after the import.
    auto TempModel = NewObject<UModel>();
    TempModel->Initialize(nullptr, 1);

    FMeshConnectivityBuilder ConnectivityBuilder;

    // Send triangles to connectivity builder
    for(int32 x = 0; x < CollisionFaceIdx.Num(); x += 3)
    {
        const FVector &VertexA = CollisionVertices[ CollisionFaceIdx[x + 2] ];
        const FVector &VertexB = CollisionVertices[ CollisionFaceIdx[x + 1] ];
        const FVector &VertexC = CollisionVertices[ CollisionFaceIdx[x + 0] ];
        ConnectivityBuilder.AddTriangle( VertexA, VertexB, VertexC );
    }

    ConnectivityBuilder.CreateConnectivityGroups();

    // For each valid group build BSP and extract convex hulls
    for ( int32 i=0; i<ConnectivityBuilder.Groups.Num(); i++ )
    {
        const FMeshConnectivityGroup &Group = ConnectivityBuilder.Groups[ i ];

        // TODO: add some BSP friendly checks here
        // e.g. if group triangles form a closed mesh

        // Generate polygons from group triangles
        TempModel->Polys->Element.Empty();

        for ( int32 j=0; j<Group.Triangles.Num(); j++ )
        {
            const FMeshConnectivityTriangle &Triangle = ConnectivityBuilder.Triangles[ Group.Triangles[j] ];

            FPoly*	Poly = new( TempModel->Polys->Element ) FPoly();
            Poly->Init();
            Poly->iLink = j / 3;

            // Add vertices
            new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[0] ].Position );
            new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[1] ].Position );
            new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[2] ].Position );

            // Update polygon normal
            Poly->CalcNormal(1);
        }

        // Build bounding box.
        TempModel->BuildBound();

        // Build BSP for the brush.
        FBSPOps::bspBuild( TempModel,FBSPOps::BSP_Good,15,70,1,0 );
        FBSPOps::bspRefresh( TempModel, 1 );
        FBSPOps::bspBuildBounds( TempModel );

        // Convert collision model into a collection of convex hulls.
        // Generated convex hulls will be added to existing ones
        BodySetup->CreateFromModel( TempModel, false );
    }
}
Mesh2::Mesh2(const char * filename)
{ // read the mesh  

  int nt,nv,nbe;
  int ok=load(filename);
  if(ok)
    {
      ifstream f(filename);
      if(!f) {cerr << "Mesh2::Mesh2 Erreur openning " << filename<<endl;exit(1);}
      if(verbosity)
      cout << " Read On file \"" <<filename<<"\""<<  endl;
      f >> nv >> nt >> nbe ;
      this->set(nv,nt,nbe);
      if(verbosity)
      cout << "  -- Nb of Vertex " << nv << " " << " Nb of Triangles " << nt 
	   << " , Nb of border edges " << nbe <<  endl;
      assert(f.good() && nt && nv) ;
      for (int i=0;i<nv;i++)    
	{
	  f >> this->vertices[i];
	  assert(f.good());
	}
      mes=0;
      for (int i=0;i<nt;i++) 
	{ 
	  this->t(i).Read1(f,this->vertices,nv);
	  mes += t(i).mesure();
	}
      mesb=0.;
      for (int i=0;i<nbe;i++) 
	{ 
	  this->be(i).Read1(f,this->vertices,nv);
	  mesb += be(i).mesure();
	}
    }
  BuildBound();
  BuildAdj();
  Buildbnormalv();  
  BuildjElementConteningVertex();  

  if(verbosity)  
  cout << "   - mesh mesure = " << mes << " border mesure: " << mesb << endl;  
}
    Mesh2::Mesh2(FILE *f)
    {
	
	GRead(f);
	assert( (nt >= 0 || nbe>=0)  && nv>0) ;
	BuildBound();
	if(verbosity>1)
	    cout << "  -- End of read: mesure = " << mes << " border mesure " << mesb << endl;  
	
	if(nt > 0){ 
	    BuildAdj();
	    Buildbnormalv();  
	    BuildjElementConteningVertex();  
	}
	
	if(verbosity>1)
	    cout << "  -- Mesh2  (File *), d "<< 2  << ", n Tet " << nt << ", n Vtx "
	    << nv << " n Bord " << nbe << endl;
	
    }
int32 GenerateKDopAsSimpleCollision(UStaticMesh* StaticMesh, const TArray<FVector> &Dirs)
{
	// Make sure rendering is done - so we are not changing data being used by collision drawing.
	FlushRenderingCommands();

	if (!PromptToRemoveExistingCollision(StaticMesh))
	{
		return INDEX_NONE;
	}

	UBodySetup* bs = StaticMesh->BodySetup;

	// Do k- specific stuff.
	int32 kCount = Dirs.Num();
	TArray<float> maxDist;
	for(int32 i=0; i<kCount; i++)
		maxDist.Add(-MY_FLTMAX);

	// Construct temporary UModel for kdop creation. We keep no refs to it, so it can be GC'd.
	auto TempModel = NewObject<UModel>();
	TempModel->Initialize(nullptr, 1);

	// For each vertex, project along each kdop direction, to find the max in that direction.
	const FStaticMeshLODResources& RenderData = StaticMesh->RenderData->LODResources[0];
	for(int32 i=0; i<RenderData.GetNumVertices(); i++)
	{
		for(int32 j=0; j<kCount; j++)
		{
			float dist = RenderData.PositionVertexBuffer.VertexPosition(i) | Dirs[j];
			maxDist[j] = FMath::Max(dist, maxDist[j]);
		}
	}

	// Inflate kdop to ensure it is no degenerate
	const float MinSize = 0.1f;
	for(int32 i=0; i<kCount; i++)
	{
		maxDist[i] += MinSize;
	}

	// Now we have the planes of the kdop, we work out the face polygons.
	TArray<FPlane> planes;
	for(int32 i=0; i<kCount; i++)
		planes.Add( FPlane(Dirs[i], maxDist[i]) );

	for(int32 i=0; i<planes.Num(); i++)
	{
		FPoly*	Polygon = new(TempModel->Polys->Element) FPoly();
		FVector Base, AxisX, AxisY;

		Polygon->Init();
		Polygon->Normal = planes[i];
		Polygon->Normal.FindBestAxisVectors(AxisX,AxisY);

		Base = planes[i] * planes[i].W;

		new(Polygon->Vertices) FVector(Base + AxisX * HALF_WORLD_MAX + AxisY * HALF_WORLD_MAX);
		new(Polygon->Vertices) FVector(Base + AxisX * HALF_WORLD_MAX - AxisY * HALF_WORLD_MAX);
		new(Polygon->Vertices) FVector(Base - AxisX * HALF_WORLD_MAX - AxisY * HALF_WORLD_MAX);
		new(Polygon->Vertices) FVector(Base - AxisX * HALF_WORLD_MAX + AxisY * HALF_WORLD_MAX);

		for(int32 j=0; j<planes.Num(); j++)
		{
			if(i != j)
			{
				if(!Polygon->Split(-FVector(planes[j]), planes[j] * planes[j].W))
				{
					Polygon->Vertices.Empty();
					break;
				}
			}
		}

		if(Polygon->Vertices.Num() < 3)
		{
			// If poly resulted in no verts, remove from array
			TempModel->Polys->Element.RemoveAt(TempModel->Polys->Element.Num()-1);
		}
		else
		{
			// Other stuff...
			Polygon->iLink = i;
			Polygon->CalcNormal(1);
		}
	}

	if(TempModel->Polys->Element.Num() < 4)
	{
		TempModel = NULL;
		return INDEX_NONE;
	}

	// Build bounding box.
	TempModel->BuildBound();

	// Build BSP for the brush.
	FBSPOps::bspBuild(TempModel,FBSPOps::BSP_Good,15,70,1,0);
	FBSPOps::bspRefresh(TempModel,1);
	FBSPOps::bspBuildBounds(TempModel);

	bs->Modify();

	bs->CreateFromModel(TempModel, false);
	
	// create all body instances
	RefreshCollisionChange(StaticMesh);

	// Mark staticmesh as dirty, to help make sure it gets saved.
	StaticMesh->MarkPackageDirty();

	return bs->AggGeom.ConvexElems.Num() - 1;
}