Skip to content

Commit

Permalink
cross-compatibility via wrapper module
Browse files Browse the repository at this point in the history
  • Loading branch information
jfmilke committed Nov 10, 2023
1 parent 6f76c1a commit e369042
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 36 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#ignore mac fs files
.DS_Store
.vscode

# ignore ue binaries
Binaries/*
Expand Down
22 changes: 4 additions & 18 deletions Source/VtkPlugin/Private/VtkFunctionLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,7 @@


#include "VtkFunctionLibrary.h"

THIRD_PARTY_INCLUDES_START
// DistanceBetweenTwoPoins example
#include "vtkMath.h"

#if PLATFORM_WINDOWS
// StructuredGridReader example
#include "vtkNamedColors.h"
#include "vtkNew.h"
#include "vtkPolyDataMapper.h"
#include "vtkStructuredGridGeometryFilter.h"
#include "vtkXMLStructuredGridReader.h"
#include "vtkStructuredGrid.h"
#endif
THIRD_PARTY_INCLUDES_END
#include "VtkWrapper.h"

float UVtkFunctionLibrary::DistanceBetweenTwoPoints(const FVector3f& P0, const FVector3f& P1)
{
Expand All @@ -29,7 +15,7 @@ float UVtkFunctionLibrary::DistanceBetweenTwoPoints(const FVector3f& P0, const F
const double vtk_p1[3] = {P1.X, P1.Y, P1.Z};

// Find the squared distance between the points using vtk.
const double squaredDistance = vtkMath::Distance2BetweenPoints(vtk_p0, vtk_p1);
const double squaredDistance = FvtkMath::Distance2BetweenPoints(vtk_p0, vtk_p1);

// Take the square root to get the Euclidean distance between the points.
const double distance = std::sqrt(squaredDistance);
Expand All @@ -44,7 +30,7 @@ float UVtkFunctionLibrary::DistanceBetweenTwoPoints(const FVector3f& P0, const F

bool UVtkFunctionLibrary::ReadStructuredGridTest(const FString& Filepath)
{
#if PLATFORM_WINDOWS
#if 1
const FString CleanFilepath = Filepath.TrimQuotes();
UE_LOG(LogTemp, Warning, TEXT("[VtkPlugin] VTK Example: Read Structured Grid"));
UE_LOG(LogTemp, Warning, TEXT("[VtkPlugin] Reading structured grid: %s"), *CleanFilepath);
Expand All @@ -56,7 +42,7 @@ bool UVtkFunctionLibrary::ReadStructuredGridTest(const FString& Filepath)
}

// Read the file.
vtkNew<vtkXMLStructuredGridReader> reader;
FvtkXMLStructuredGridReader* reader = new FvtkXMLStructuredGridReader();
reader->SetFileName(TCHAR_TO_ANSI(*CleanFilepath));
reader->Update();

Expand Down
2 changes: 1 addition & 1 deletion Source/VtkPlugin/VtkPlugin.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public VtkPlugin(ReadOnlyTargetRules Target) : base(Target)
new string[]
{
"Core",
"VtkLibrary",
"VtkWrapper",
"Projects",
// ... add other public dependencies that you statically link with here ...

Expand Down
101 changes: 101 additions & 0 deletions Source/VtkWrapper/Private/VtkWrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "VtkWrapper.h"

#include "Modules/ModuleManager.h"

PRAGMA_DEFAULT_VISIBILITY_START
THIRD_PARTY_INCLUDES_START
// DistanceBetweenTwoPoins example
#include "vtkMath.h"

// StructuredGridReader example
#include "vtkNamedColors.h"
#include "vtkNew.h"
#include "vtkPolyDataMapper.h"
#include "vtkStructuredGridGeometryFilter.h"
#include "vtkXMLStructuredGridReader.h"
#include "vtkStructuredGrid.h"
THIRD_PARTY_INCLUDES_END
PRAGMA_DEFAULT_VISIBILITY_END

// NOTE
// This is just am exemplary implementation, a "proof of concept" for cross-compatibility.
// I expect that better ways exist to do the stuff below.

// FvtkMath

double FvtkMath::Distance2BetweenPoints(const double p1[3], const double p2[3])
{
return vtkMath::Distance2BetweenPoints(p1, p2);
}

// FvtkStructuredGrid

FvtkStructuredGrid::FvtkStructuredGrid()
{
mStructuredGrid = vtkStructuredGrid::New();
}

FvtkStructuredGrid::FvtkStructuredGrid(vtkStructuredGrid* arg)
{
mStructuredGrid = arg;
}

FvtkStructuredGrid::~FvtkStructuredGrid()
{
mStructuredGrid->Delete();
}

int FvtkStructuredGrid::GetDataDimension()
{
return ((vtkStructuredGrid*)mStructuredGrid)->GetDataDimension();
}
int FvtkStructuredGrid::GetNumberOfPoints()
{
return ((vtkStructuredGrid*)mStructuredGrid)->GetNumberOfPoints();
}
int FvtkStructuredGrid::GetNumberOfCells()
{
return ((vtkStructuredGrid*)mStructuredGrid)->GetNumberOfCells();
}
void FvtkStructuredGrid::GetDimensions(int dims[3])
{
((vtkStructuredGrid*)mStructuredGrid)->GetDimensions(dims);
}
void FvtkStructuredGrid::GetCellDims(int cellDims[3])
{
((vtkStructuredGrid*)mStructuredGrid)->GetCellDims(cellDims);
}

// FvtkXMLStructuredGridReader

FvtkXMLStructuredGridReader::FvtkXMLStructuredGridReader()
{
mXMLStructuredGridReader = vtkXMLStructuredGridReader::New();
}

FvtkXMLStructuredGridReader::~FvtkXMLStructuredGridReader()
{
mXMLStructuredGridReader->Delete();
}

void FvtkXMLStructuredGridReader::SetFileName(const char* arg)
{
((vtkXMLStructuredGridReader*)mXMLStructuredGridReader)->SetFileName(arg);
}
void FvtkXMLStructuredGridReader::Update()
{
((vtkXMLStructuredGridReader*)mXMLStructuredGridReader)->Update();
}
bool FvtkXMLStructuredGridReader::CheckAbort()
{
return ((vtkXMLStructuredGridReader*)mXMLStructuredGridReader)->CheckAbort();
}

FvtkStructuredGrid* FvtkXMLStructuredGridReader::GetOutput()
{
auto out = ((vtkXMLStructuredGridReader*)mXMLStructuredGridReader)->GetOutput();
return new FvtkStructuredGrid(out);
}

IMPLEMENT_MODULE(FDefaultModuleImpl, VtkWrapper);
//IMPLEMENT_MODULE(FVtkWrapperModule, VtkWrapper);
48 changes: 48 additions & 0 deletions Source/VtkWrapper/Public/VtkWrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include "CoreTypes.h"

// NOTE
// This is just am exemplary implementation, a "proof of concept" for cross-compatibility.
// I expect that better ways exist to do the stuff below.

class vtkStructuredGrid;
class vtkXMLStructuredGridReader;

class VTKWRAPPER_API FvtkMath
{
public:
static double Distance2BetweenPoints(const double p1[3], const double p2[3]);
};

class VTKWRAPPER_API FvtkStructuredGrid
{
public:
FvtkStructuredGrid();
FvtkStructuredGrid(vtkStructuredGrid* arg);
~FvtkStructuredGrid();

int GetDataDimension();
int GetNumberOfPoints();
int GetNumberOfCells();
void GetDimensions(int dims[3]);
void GetCellDims(int cellDims[3]);

private:
vtkStructuredGrid* mStructuredGrid;
};

class VTKWRAPPER_API FvtkXMLStructuredGridReader
{
public:
FvtkXMLStructuredGridReader();
~FvtkXMLStructuredGridReader();

void SetFileName(const char* arg);
void Update();
bool CheckAbort();
FvtkStructuredGrid* GetOutput();

private:
vtkXMLStructuredGridReader* mXMLStructuredGridReader;
};
28 changes: 28 additions & 0 deletions Source/VtkWrapper/VtkWrapper.Build.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class VtkWrapper : ModuleRules
{
public VtkWrapper(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;

bUseRTTI = true;

PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
}
);


PrivateDependencyModuleNames.AddRange(
new string[]
{
"VtkLibrary",
}
);
}
}
26 changes: 9 additions & 17 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
## VTK Plugin for Unreal Engine 5+

**This branch is fully cross-compatible between Windows and Unix (Linux/Mac).** See "How" in the [Remarks on Linux/Mac](#remarks-on-linuxmac) section.

A plugin that links the [VTK Library](https://github.com/Kitware/VTK) to [Unreal Engine 5.3](https://docs.unrealengine.com/5.3/en-US/).

Currently, this plugin does the following:
- Download & build VTK (infer/change the version in the install script file)
- Expose VTK to your complete Unreal project (public, but you may want this private)
- Provide a blueprint function "DistanceBetweenTwoPoints" for testing `vtkMath.h` (based on an [official VTK example](https://examples.vtk.org/site/Cxx/SimpleOperations/DistanceBetweenPoints/), cross-compatible)
- Provide a blueprint function "ReadStructuredGridTest" for more complex vtk includes (loosely based on an [official VTK example](https://examples.vtk.org/site/Cxx/IO/ReadStructuredGrid/#download-and-build-readstructuredgrid), only Windows due to RTTI)
- Conditional cross-compatibility for Windows/Linux/Mac (tested)
- Windows: VTK should work as-is without further adjustments
- Linux/Mac: Certain VTK includes won't compile as they use [RTTI mechanics](https://en.wikipedia.org/wiki/Run-time_type_information)
- Provide a blueprint function "ReadStructuredGridTest" for more complex vtk includes (loosely based on an [official VTK example](https://examples.vtk.org/site/Cxx/IO/ReadStructuredGrid/#download-and-build-readstructuredgrid)
- Complete cross-compatibility for Windows/Linux/Mac (tested)

This plugin is quite verbose as it aims to be a foundation for implementing & testing VTK functionality in UE.
Check the Unreal Log for `[VtkPlugin]` to see what's happening (also valid for the blueprint functions).
Expand All @@ -22,21 +22,13 @@ This prevents module reloading.
### Remarks on Linux/Mac

Delay-loading is enabled on Unix-based systems and thus also module reloading (theoretically).
While this plugin compiles on Linux and Mac, not all features are currently supported compared to the Windows implementation because of missing RTTI support.

**TL;DR:** See the `VtkWrapper` branch for an example implementation with full cross-compatability.

Contrary to Windows, Unreal Engine on Unix is by default compiled without [RTTI](https://en.wikipedia.org/wiki/Run-time_type_information) support (thoroughly discussed [here](https://forums.unrealengine.com/t/rtti-failed-compiling-when-enabled-for-4-23-linux/455083/22)).

~~**Solution A:** Recompile Unreal Engine with RTTI support~~
This drastically limitates portability as any other Unix-based system needs a custom UE installation to develop using this plugin.
Also, according to some posts ([1](https://forums.unrealengine.com/t/rtti-failed-compiling-when-enabled-for-4-23-linux/455083), [2](https://forums.unrealengine.com/t/busertti-true-makes-an-unreal-project-fail-to-load/407837)) the XMPP Plugin currently prevents this approach.
To achieve cross-compatibility of all VTK methods, the `VtkWrapper` module with [RTTI](https://en.wikipedia.org/wiki/Run-time_type_information) enabled was implemented to wrap all VTK-native code.
Each VTK functionality needs to be wrapped explicitly before it is exposed (e.g., to `VtkPlugin` which implements the blueprints).
This is needed, as contrary to Windows Unreal Engine on Unix is by default compiled without RTTI support (thoroughly discussed [here](https://forums.unrealengine.com/t/rtti-failed-compiling-when-enabled-for-4-23-linux/455083/22)).
Globally enabling RTTI on Unix is not (easily) done, so this approach orients the way the `OpenExrWrapper` is implemented as suggested [here](https://forums.unrealengine.com/t/rtti-failed-compiling-when-enabled-for-4-23-linux/455083/13).

**Solution B:** Enable RTTI per Module
It is possible to enable RTTI just in a single module (Setting `bUseRTTI=true` in the `*.Build.cs` file) and compile only that with RTTI support.
But this needs extra care as RTTI-enabled modules will clash with many Unreal constructs (e.g., `UBlueprintFunctionLibrary`).
To circumvent that, constructing a seperate RTTI-enabled [Wrapper module is suggested](https://forums.unrealengine.com/t/rtti-failed-compiling-when-enabled-for-4-23-linux/455083/13) like the `OpenExrWrapper` module in `Engine/Plugins/Media/ImgMedia`.
The `VtkWrapper` branch shows such an example.
⚠️ The provided `VtkWrapper` implementation is just an example and better solutions exist.

## Installation

Expand Down

0 comments on commit e369042

Please sign in to comment.