From e3690422fcf420056c1e72b1d16302b94752aefe Mon Sep 17 00:00:00 2001 From: Jan Frieder Milke Date: Fri, 10 Nov 2023 13:31:25 +0100 Subject: [PATCH] cross-compatibility via wrapper module --- .gitignore | 1 + .../VtkPlugin/Private/VtkFunctionLibrary.cpp | 22 +--- Source/VtkPlugin/VtkPlugin.Build.cs | 2 +- Source/VtkWrapper/Private/VtkWrapper.cpp | 101 ++++++++++++++++++ Source/VtkWrapper/Public/VtkWrapper.h | 48 +++++++++ Source/VtkWrapper/VtkWrapper.Build.cs | 28 +++++ readme.md | 26 ++--- 7 files changed, 192 insertions(+), 36 deletions(-) create mode 100644 Source/VtkWrapper/Private/VtkWrapper.cpp create mode 100644 Source/VtkWrapper/Public/VtkWrapper.h create mode 100644 Source/VtkWrapper/VtkWrapper.Build.cs diff --git a/.gitignore b/.gitignore index f091ae6..eac572d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ #ignore mac fs files .DS_Store +.vscode # ignore ue binaries Binaries/* diff --git a/Source/VtkPlugin/Private/VtkFunctionLibrary.cpp b/Source/VtkPlugin/Private/VtkFunctionLibrary.cpp index 4a69a68..7895c9f 100644 --- a/Source/VtkPlugin/Private/VtkFunctionLibrary.cpp +++ b/Source/VtkPlugin/Private/VtkFunctionLibrary.cpp @@ -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) { @@ -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); @@ -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); @@ -56,7 +42,7 @@ bool UVtkFunctionLibrary::ReadStructuredGridTest(const FString& Filepath) } // Read the file. - vtkNew reader; + FvtkXMLStructuredGridReader* reader = new FvtkXMLStructuredGridReader(); reader->SetFileName(TCHAR_TO_ANSI(*CleanFilepath)); reader->Update(); diff --git a/Source/VtkPlugin/VtkPlugin.Build.cs b/Source/VtkPlugin/VtkPlugin.Build.cs index 54982fc..8023e89 100644 --- a/Source/VtkPlugin/VtkPlugin.Build.cs +++ b/Source/VtkPlugin/VtkPlugin.Build.cs @@ -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 ... diff --git a/Source/VtkWrapper/Private/VtkWrapper.cpp b/Source/VtkWrapper/Private/VtkWrapper.cpp new file mode 100644 index 0000000..ee0b6ef --- /dev/null +++ b/Source/VtkWrapper/Private/VtkWrapper.cpp @@ -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); \ No newline at end of file diff --git a/Source/VtkWrapper/Public/VtkWrapper.h b/Source/VtkWrapper/Public/VtkWrapper.h new file mode 100644 index 0000000..24ff3e1 --- /dev/null +++ b/Source/VtkWrapper/Public/VtkWrapper.h @@ -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; +}; diff --git a/Source/VtkWrapper/VtkWrapper.Build.cs b/Source/VtkWrapper/VtkWrapper.Build.cs new file mode 100644 index 0000000..d2978f4 --- /dev/null +++ b/Source/VtkWrapper/VtkWrapper.Build.cs @@ -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", + } + ); + } +} diff --git a/readme.md b/readme.md index e459804..02861bf 100644 --- a/readme.md +++ b/readme.md @@ -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). @@ -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