git: fea222604fc0 - main - graphics/f3d: upgrade to 2.3.0
Date: Thu, 21 Mar 2024 18:02:14 UTC
The branch main has been updated by thierry:
URL: https://cgit.FreeBSD.org/ports/commit/?id=fea222604fc0b3ed6bcdd48324d1a7a462128dd7
commit fea222604fc0b3ed6bcdd48324d1a7a462128dd7
Author: Thierry Thomas <thierry@FreeBSD.org>
AuthorDate: 2024-03-08 10:07:26 +0000
Commit: Thierry Thomas <thierry@FreeBSD.org>
CommitDate: 2024-03-21 18:01:17 +0000
graphics/f3d: upgrade to 2.3.0
Release notes at <https://github.com/f3d-app/f3d/releases/tag/v2.3.0>.
Also fix with OpenCascade 7.8.0:
See <https://github.com/f3d-app/f3d/issues/1304>.
PR: 277308
Approved by: yuri (maintainer)
---
graphics/f3d/Makefile | 11 +-
graphics/f3d/distinfo | 6 +-
.../f3d/files/patch-plugins_occt_CMakeLists.txt | 35 ++
.../patch-plugins_occt_module_vtkF3DOCCTReader.cxx | 381 +++++++++++++++++++++
graphics/f3d/pkg-plist | 5 +-
5 files changed, 432 insertions(+), 6 deletions(-)
diff --git a/graphics/f3d/Makefile b/graphics/f3d/Makefile
index 981ed2bb3181..482fcc314e1f 100644
--- a/graphics/f3d/Makefile
+++ b/graphics/f3d/Makefile
@@ -1,6 +1,6 @@
PORTNAME= f3d
DISTVERSIONPREFIX= v
-DISTVERSION= 2.2.1
+DISTVERSION= 2.3.0
CATEGORIES= graphics
MAINTAINER= yuri@FreeBSD.org
@@ -11,17 +11,24 @@ LICENSE= BSD3CLAUSE
LICENSE_FILE= ${WRKSRC}/LICENSE.md
LIB_DEPENDS= libavcodec.so:multimedia/ffmpeg4 \
+ libexpat.so:textproc/expat2 \
libfontconfig.so:x11-fonts/fontconfig \
libfreeimage.so:graphics/freeimage \
libfreetype.so:print/freetype2 \
libhdf5.so:science/hdf5 \
libImath-3_1.so:math/Imath \
+ libjpeg.so:graphics/jpeg-turbo \
libnetcdf.so:science/netcdf \
+ libpng.so:graphics/png \
+ libtbbmalloc.so:devel/onetbb \
+ libtiff.so:graphics/tiff \
libvtkCommonMisc-${VTK_VER}.so:math/vtk${VTK_VER:R}
-USES= cmake:testing compiler:c++17-lang desktop-file-utils gl shared-mime-info tcl tk xorg
+USES= cmake:testing compiler:c++17-lang desktop-file-utils gl mpi \
+ shared-mime-info tcl tk xorg
USE_GL= gl glu
USE_XORG= ice sm x11 xt
+USE_LDCONFIG= yes
USE_GITHUB= yes
GH_ACCOUNT= f3d-app
diff --git a/graphics/f3d/distinfo b/graphics/f3d/distinfo
index c29c4501f9a2..3560f0ee0555 100644
--- a/graphics/f3d/distinfo
+++ b/graphics/f3d/distinfo
@@ -1,3 +1,3 @@
-TIMESTAMP = 1704769349
-SHA256 (f3d-app-f3d-v2.2.1_GH0.tar.gz) = 4d3a73b0107c8db7f0556107c74087d3748232a73981f65f7c5186ac1003ec8d
-SIZE (f3d-app-f3d-v2.2.1_GH0.tar.gz) = 29785716
+TIMESTAMP = 1709891821
+SHA256 (f3d-app-f3d-v2.3.0_GH0.tar.gz) = 9c2906b62f3066f075effbabd6501964391e8a8ffad6ed773c33db12580cc466
+SIZE (f3d-app-f3d-v2.3.0_GH0.tar.gz) = 40606315
diff --git a/graphics/f3d/files/patch-plugins_occt_CMakeLists.txt b/graphics/f3d/files/patch-plugins_occt_CMakeLists.txt
new file mode 100644
index 000000000000..922c86cde9d6
--- /dev/null
+++ b/graphics/f3d/files/patch-plugins_occt_CMakeLists.txt
@@ -0,0 +1,35 @@
+--- plugins/occt/CMakeLists.txt.orig 2024-01-21 15:29:01 UTC
++++ plugins/occt/CMakeLists.txt
+@@ -17,18 +17,30 @@ endif()
+ message(FATAL_ERROR "Plugin: OpenCASCADE: ${OpenCASCADE_VERSION} is not supported by F3D, please update your OpenCASCADE installation.")
+ endif()
+
+-if((NOT TARGET "TKSTEP") AND (NOT TARGET "TKIGES") AND (NOT TARGET "TKMesh"))
++if("${OpenCASCADE_VERSION}" VERSION_LESS "7.8.0")
++ if((NOT TARGET "TKSTEP") AND (NOT TARGET "TKIGES") AND (NOT TARGET "TKMesh"))
+ message(FATAL_ERROR "Plugin: OpenCASCADE does not contain required modules")
++ endif()
+ endif()
+
++if((NOT TARGET "TKDESTEP") AND (NOT TARGET "TKDEIGES") AND (NOT TARGET "TKMesh"))
++ message(FATAL_ERROR "Plugin: OpenCASCADE does not contain required modules")
++endif()
++
+ message(STATUS "Plugin: OpenCASCADE ${OpenCASCADE_VERSION} found")
+
+ option(F3D_PLUGIN_OCCT_COLORING_SUPPORT "Enable coloring support in occt plugin" ON)
+ mark_as_advanced(F3D_PLUGIN_OCCT_COLORING_SUPPORT)
+
+ if(F3D_PLUGIN_OCCT_COLORING_SUPPORT)
+- if (NOT (TARGET "TKXDESTEP") OR NOT (TARGET "TKXDEIGES"))
++ if("${OpenCASCADE_VERSION}" VERSION_LESS "7.8.0")
++ if (NOT (TARGET "TKXDESTEP") OR NOT (TARGET "TKXDEIGES"))
+ message(FATAL_ERROR "occt plugin: TKXDESTEP and TKXDEIGES OCCT modules are not found. Turn off F3D_PLUGIN_OCCT_COLORING_SUPPORT or enable them in your OpenCascade build.")
++ endif()
++ else()
++ if (NOT (TARGET "TKXSDRAWSTEP") OR NOT (TARGET "TKXSDRAWIGES"))
++ message(FATAL_ERROR "occt plugin: TKXSDRAWSTEP and TKXSDRAWIGES OCCT modules are not found. Turn off F3D_PLUGIN_OCCT_COLORING_SUPPORT or enable them in your OpenCascade build.")
++ endif()
+ endif()
+ endif()
+
diff --git a/graphics/f3d/files/patch-plugins_occt_module_vtkF3DOCCTReader.cxx b/graphics/f3d/files/patch-plugins_occt_module_vtkF3DOCCTReader.cxx
new file mode 100644
index 000000000000..270c6e9fd49b
--- /dev/null
+++ b/graphics/f3d/files/patch-plugins_occt_module_vtkF3DOCCTReader.cxx
@@ -0,0 +1,381 @@
+--- plugins/occt/module/vtkF3DOCCTReader.cxx.orig 2024-01-21 15:29:01 UTC
++++ plugins/occt/module/vtkF3DOCCTReader.cxx
+@@ -31,14 +31,17 @@
+ #if F3D_PLUGIN_OCCT_XCAF
+ #include <IGESCAFControl_Reader.hxx>
+ #include <STEPCAFControl_Reader.hxx>
++#include <Standard_Version.hxx>
+ #include <TDF_ChildIterator.hxx>
+ #include <TDataStd_Name.hxx>
+ #include <TDocStd_Document.hxx>
+ #include <XCAFApp_Application.hxx>
+-#include <XCAFDoc_ColorTool.hxx>
+ #include <XCAFDoc_DocumentTool.hxx>
+ #include <XCAFDoc_Location.hxx>
+ #include <XCAFDoc_ShapeTool.hxx>
++#include <XCAFPrs.hxx>
++#include <XCAFPrs_IndexedDataMapOfShapeStyle.hxx>
++#include <XCAFPrs_Style.hxx>
+ #endif
+
+ #if defined(__GNUC__)
+@@ -71,6 +74,10 @@ class vtkF3DOCCTReader::vtkInternals
+
+ class vtkF3DOCCTReader::vtkInternals
+ {
++#if F3D_PLUGIN_OCCT_XCAF
++ using StyleMap = XCAFPrs_IndexedDataMapOfShapeStyle;
++#endif
++
+ public:
+ //----------------------------------------------------------------------------
+ explicit vtkInternals(vtkF3DOCCTReader* parent)
+@@ -79,7 +86,11 @@ class vtkF3DOCCTReader::vtkInternals
+ }
+
+ //----------------------------------------------------------------------------
++#if F3D_PLUGIN_OCCT_XCAF
++ vtkSmartPointer<vtkPolyData> CreateShape(const TopoDS_Shape& shape, const TDF_Label& label)
++#else
+ vtkSmartPointer<vtkPolyData> CreateShape(const TopoDS_Shape& shape)
++#endif
+ {
+ vtkNew<vtkPoints> points;
+ vtkNew<vtkFloatArray> normals;
+@@ -88,32 +99,49 @@ class vtkF3DOCCTReader::vtkInternals
+ vtkNew<vtkFloatArray> uvs;
+ uvs->SetNumberOfComponents(2);
+ uvs->SetName("UV");
++#if F3D_PLUGIN_OCCT_XCAF
+ vtkNew<vtkUnsignedCharArray> colors;
+ colors->SetNumberOfComponents(3);
+ colors->SetName("Colors");
++#endif
+ vtkNew<vtkCellArray> trianglesCells;
+ vtkNew<vtkCellArray> linesCells;
+
+ Standard_Integer shift = 0;
+
++#if F3D_PLUGIN_OCCT_XCAF
++ const StyleMap inheritedStyles = this->CollectInheritedStyles(label, shape);
++#endif
++
++ /* Mesh the whole shape. This only affect faces, edges have to be handled separately. */
++ BRepMesh_IncrementalMesh(shape, this->Parent->GetLinearDeflection(),
++ this->Parent->GetRelativeDeflection(), this->Parent->GetAngularDeflection(), Standard_True);
++
+ if (this->Parent->GetReadWire())
+ {
+- // Add all edges to polydata
+- for (TopExp_Explorer exEdge(shape, TopAbs_EDGE); exEdge.More(); exEdge.Next())
++ std::vector<TopoDS_Edge> edges;
+ {
+- TopoDS_Edge edge = TopoDS::Edge(exEdge.Current());
++ /* add all edges to a compound to remesh them all at once */
++ TopoDS_Builder builder;
++ TopoDS_Compound compound;
++ builder.MakeCompound(compound);
++ for (TopExp_Explorer exEdge(shape, TopAbs_EDGE); exEdge.More(); exEdge.Next())
++ {
++ const TopoDS_Edge edge = TopoDS::Edge(exEdge.Current());
++ builder.Add(compound, edge);
++ edges.push_back(edge);
++ }
++ BRepMesh_IncrementalMesh(compound, this->Parent->GetLinearDeflection(),
++ this->Parent->GetRelativeDeflection(), this->Parent->GetAngularDeflection(),
++ Standard_True);
++ }
+
++ // Add all edges to polydata
++ for (const TopoDS_Edge& edge : edges)
++ {
+ TopLoc_Location location;
+ const auto& poly = BRep_Tool::Polygon3D(edge, location);
+
+- if (poly.IsNull() || poly->Nodes().Length() <= 0)
+- {
+- // meshing
+- BRepMesh_IncrementalMesh(edge, this->Parent->GetLinearDeflection(),
+- this->Parent->GetRelativeDeflection(), this->Parent->GetAngularDeflection(),
+- Standard_True);
+- }
+-
+ if (poly.IsNull())
+ {
+ continue;
+@@ -134,23 +162,29 @@ class vtkF3DOCCTReader::vtkInternals
+ uvs->InsertNextTypedTuple(fn);
+ }
+
+- std::vector<vtkIdType> polyline(nbV - 1);
++ std::vector<vtkIdType> polyline(nbV);
+ std::iota(polyline.begin(), polyline.end(), shift);
+ linesCells->InsertNextCell(polyline.size(), polyline.data());
+
+ #if F3D_PLUGIN_OCCT_XCAF
+- if (this->ColorTool)
++ std::array<unsigned char, 3> rgb = { 0, 0, 0 };
++ try
+ {
+- std::array<unsigned char, 3> rgb = { 0, 0, 0 };
+- Quantity_Color aColor;
+- if (this->ColorTool->GetColor(edge, XCAFDoc_ColorCurv, aColor))
++ const auto& style = inheritedStyles.FindFromKey(edge);
++ if (style.IsSetColorCurv())
+ {
+- rgb[0] = static_cast<unsigned char>(255.0 * aColor.Red());
+- rgb[1] = static_cast<unsigned char>(255.0 * aColor.Green());
+- rgb[2] = static_cast<unsigned char>(255.0 * aColor.Blue());
++ Quantity_Color color = style.GetColorCurv();
++ rgb[0] = static_cast<unsigned char>(255.0 * color.Red());
++ rgb[1] = static_cast<unsigned char>(255.0 * color.Green());
++ rgb[2] = static_cast<unsigned char>(255.0 * color.Blue());
+ }
+- colors->InsertNextTypedTuple(rgb.data());
+ }
++ catch (Standard_NoSuchObject&)
++ {
++ /* edge has no style, safe to ignore */
++ }
++
++ colors->InsertNextTypedTuple(rgb.data());
+ #endif
+
+ shift += nbV;
+@@ -165,14 +199,6 @@ class vtkF3DOCCTReader::vtkInternals
+ TopLoc_Location location;
+ const auto& poly = BRep_Tool::Triangulation(face, location);
+
+- if (poly.IsNull() || poly->NbTriangles() <= 0)
+- {
+- // meshing
+- BRepMesh_IncrementalMesh(face, this->Parent->GetLinearDeflection(),
+- this->Parent->GetRelativeDeflection(), this->Parent->GetAngularDeflection(),
+- Standard_True);
+- }
+-
+ if (poly.IsNull())
+ {
+ continue;
+@@ -243,23 +269,32 @@ class vtkF3DOCCTReader::vtkInternals
+ std::swap(cell[0], cell[2]);
+ }
+ trianglesCells->InsertNextCell(3, cell);
++ }
+
+ #if F3D_PLUGIN_OCCT_XCAF
+- if (this->ColorTool)
++ std::array<unsigned char, 3> rgb = { 255, 255, 255 };
++ try
++ {
++ const auto& style = inheritedStyles.FindFromKey(face);
++ if (style.IsSetColorSurf())
+ {
+- std::array<unsigned char, 3> rgb = { 255, 255, 255 };
+- Quantity_Color aColor;
+- if (this->ColorTool->GetColor(face, XCAFDoc_ColorSurf, aColor))
+- {
+- rgb[0] = static_cast<unsigned char>(255.0 * aColor.Red());
+- rgb[1] = static_cast<unsigned char>(255.0 * aColor.Green());
+- rgb[2] = static_cast<unsigned char>(255.0 * aColor.Blue());
+- }
+- colors->InsertNextTypedTuple(rgb.data());
++ Quantity_Color color = style.GetColorSurf();
++ rgb[0] = static_cast<unsigned char>(255.0 * color.Red());
++ rgb[1] = static_cast<unsigned char>(255.0 * color.Green());
++ rgb[2] = static_cast<unsigned char>(255.0 * color.Blue());
+ }
+-#endif
+ }
++ catch (Standard_NoSuchObject&)
++ {
++ /* face has no style, safe to ignore */
++ }
+
++ for (int i = 1; i <= nbT; i++)
++ {
++ colors->InsertNextTypedTuple(rgb.data());
++ }
++#endif
++
+ shift += nbV;
+ }
+
+@@ -271,11 +306,7 @@ class vtkF3DOCCTReader::vtkInternals
+ polydata->SetLines(linesCells);
+
+ #if F3D_PLUGIN_OCCT_XCAF
+- /* colors may be left empty if this->ColorTool has not been initialized */
+- if (colors->GetSize() > 0)
+- {
+- polydata->GetCellData()->SetScalars(colors);
+- }
++ polydata->GetCellData()->SetScalars(colors);
+ #endif
+
+ polydata->Squeeze();
+@@ -283,7 +314,99 @@ class vtkF3DOCCTReader::vtkInternals
+ }
+
+ #if F3D_PLUGIN_OCCT_XCAF
++ StyleMap CollectInheritedStyles(const TDF_Label& rootLabel, const TopoDS_Shape& rootShape)
++ {
++ StyleMap inheritedStyles;
++
++ if (rootLabel.IsNull())
++ {
++ return inheritedStyles;
++ }
++
++ /* collect styled shapes from the document */
++ StyleMap collectedStyles;
++ XCAFPrs::CollectStyleSettings(rootLabel, TopLoc_Location(), collectedStyles);
++
++ /* iterate styled shapes and collect sorted by ascending shape type depth */
++ const auto cmp = [](const TopoDS_Shape& a, const TopoDS_Shape& b)
++ { return a.ShapeType() > b.ShapeType(); };
++ std::multimap<TopoDS_Shape, XCAFPrs_Style, decltype(cmp)> styledShapes(cmp);
++
++ const TopAbs_ShapeEnum leafType = this->Parent->GetReadWire() ? TopAbs_EDGE : TopAbs_FACE;
++ for (StyleMap::Iterator iter(collectedStyles); iter.More(); iter.Next())
++ {
++ const TopoDS_Shape& shape = iter.Key();
++ if (shape.ShapeType() <= leafType)
++ {
++ styledShapes.insert({ shape, iter.Value() });
++ }
++ }
++
++ /* pass down each parent style props to descendent edge/face leaves */
++ const auto passDownToLeaves = [&](TopAbs_ShapeEnum type)
++ {
++ for (const auto& styledShape : styledShapes)
++ {
++ for (TopExp_Explorer iter(styledShape.first, type); iter.More(); iter.Next())
++ {
++ try
++ {
++ this->PassDownStyleProps(
++ styledShape.second, inheritedStyles.ChangeFromKey(iter.Current()));
++ }
++ catch (Standard_NoSuchObject&)
++ {
++ inheritedStyles.Add(iter.Current(), styledShape.second);
++ }
++ }
++ }
++ };
++
++ passDownToLeaves(TopAbs_FACE);
++
++ if (this->Parent->GetReadWire())
++ {
++ passDownToLeaves(TopAbs_EDGE);
++ }
++
++ /* pass down default style (if any) to all leaves */
++ try
++ {
++ const XCAFPrs_Style& defaultStyle = collectedStyles.FindFromKey(rootShape);
++ for (StyleMap::Iterator iter(inheritedStyles); iter.More(); iter.Next())
++ {
++ XCAFPrs_Style style = iter.Value();
++ this->PassDownStyleProps(defaultStyle, style);
++ }
++ }
++ catch (Standard_NoSuchObject&)
++ {
++ /* root shape has no style, safe to ignore */
++ }
++
++ return inheritedStyles;
++ }
++
+ //----------------------------------------------------------------------------
++ void PassDownStyleProps(const XCAFPrs_Style& parent, XCAFPrs_Style& child)
++ {
++ if (!child.IsSetColorCurv() && parent.IsSetColorCurv())
++ {
++ child.SetColorCurv(parent.GetColorCurv());
++ }
++
++ if (!child.IsSetColorSurf() && parent.IsSetColorSurf())
++ {
++ child.SetColorSurf(parent.GetColorSurfRGBA());
++ }
++
++ if (child.Material().IsNull() && !parent.Material().IsNull())
++ {
++ child.SetMaterial(parent.Material());
++ }
++ };
++
++ //----------------------------------------------------------------------------
+ void AddLabel(const TDF_Label& label, vtkMatrix4x4* position, vtkMultiBlockDataSet* mb)
+ {
+ if (this->ShapeTool->IsSimpleShape(label) && this->ShapeTool->IsTopLevel(label))
+@@ -365,7 +488,11 @@ class vtkF3DOCCTReader::vtkInternals
+ int GetHash(const TDF_Label& label)
+ {
+ TopoDS_Shape aShape;
++#if OCC_VERSION_HEX < 0x070800
+ return this->ShapeTool->GetShape(label, aShape) ? aShape.HashCode(INT_MAX) : 0;
++#else
++ return this->ShapeTool->GetShape(label, aShape) ? std::hash<TopoDS_Shape>{}(aShape) : 0;
++#endif
+ }
+
+ //----------------------------------------------------------------------------
+@@ -401,7 +528,6 @@ class vtkF3DOCCTReader::vtkInternals
+
+ std::unordered_map<int, vtkSmartPointer<vtkPolyData> > ShapeMap;
+ Handle(XCAFDoc_ShapeTool) ShapeTool;
+- Handle(XCAFDoc_ColorTool) ColorTool;
+ #endif
+
+ vtkF3DOCCTReader* Parent;
+@@ -424,7 +550,10 @@ class ProgressIndicator : public Message_ProgressIndic
+ class ProgressIndicator : public Message_ProgressIndicator
+ {
+ public:
+- explicit ProgressIndicator(vtkF3DOCCTReader* reader) { this->Reader = reader; }
++ explicit ProgressIndicator(vtkF3DOCCTReader* reader)
++ {
++ this->Reader = reader;
++ }
+
+ protected:
+ void Show(const Message_ProgressScope&, const Standard_Boolean) override
+@@ -493,7 +622,12 @@ int vtkF3DOCCTReader::RequestData(
+ if (success)
+ {
+ output->SetNumberOfBlocks(1);
++#if F3D_PLUGIN_OCCT_XCAF
++ const vtkSmartPointer<vtkPolyData> polydata =
++ this->Internals->CreateShape(shape, TDF_Label());
++#else
+ const vtkSmartPointer<vtkPolyData> polydata = this->Internals->CreateShape(shape);
++#endif
+ if (polydata && polydata->GetNumberOfCells() > 0)
+ {
+ output->SetBlock(1, polydata);
+@@ -522,7 +656,6 @@ int vtkF3DOCCTReader::RequestData(
+ }
+
+ this->Internals->ShapeTool = XCAFDoc_DocumentTool::ShapeTool(doc->Main());
+- this->Internals->ColorTool = XCAFDoc_DocumentTool::ColorTool(doc->Main());
+
+ TDF_LabelSequence topLevelShapes;
+
+@@ -537,9 +670,9 @@ int vtkF3DOCCTReader::RequestData(
+ this->Internals->ShapeTool->GetShape(label, shape);
+
+ this->Internals->ShapeMap[this->Internals->GetHash(label)] =
+- this->Internals->CreateShape(shape);
++ this->Internals->CreateShape(shape, label);
+
+- double progress = 0.5 + static_cast<double>(iLabel) / topLevelShapes.Length();
++ double progress = 0.5 + (static_cast<double>(iLabel) / topLevelShapes.Length()) / 2;
+ this->InvokeEvent(vtkCommand::ProgressEvent, &progress);
+ }
+
diff --git a/graphics/f3d/pkg-plist b/graphics/f3d/pkg-plist
index fed49a57c97b..adc827863ddd 100644
--- a/graphics/f3d/pkg-plist
+++ b/graphics/f3d/pkg-plist
@@ -47,10 +47,11 @@ lib/libVTKExtensionsReaders.a
lib/libVTKExtensionsRendering.a
lib/libf3d.so
lib/libf3d.so.2
-lib/libf3d.so.2.2
+lib/libf3d.so.2.3
%%ALEMBIC%%share/applications/f3d-plugin-alembic.desktop
%%ASSIMP%%share/applications/f3d-plugin-assimp.desktop
%%DRACO%%share/applications/f3d-plugin-draco.desktop
+%%EXODUS%%share/applications/f3d-plugin-exodus.desktop
share/applications/f3d-plugin-native.desktop
%%OCCT%%share/applications/f3d-plugin-occt.desktop
share/applications/f3d.desktop
@@ -69,6 +70,7 @@ share/icons/hicolor/48x48/apps/f3d.png
share/icons/hicolor/64x64/apps/f3d.png
share/icons/hicolor/scalable/apps/f3d.svg
share/metainfo/app.f3d.F3D.metainfo.xml
+%%EXODUS%%share/mime/packages/f3d-exodus-formats.xml
share/mime/packages/f3d-3d-formats.xml
share/mime/packages/f3d-3d-image-formats.xml
%%ALEMBIC%%share/mime/packages/f3d-alembic-formats.xml
@@ -79,6 +81,7 @@ share/mime/packages/f3d-vtk-formats.xml
%%ALEMBIC%%share/thumbnailers/f3d-plugin-alembic.thumbnailer
%%ASSIMP%%share/thumbnailers/f3d-plugin-assimp.thumbnailer
%%DRACO%%share/thumbnailers/f3d-plugin-draco.thumbnailer
+%%EXODUS%%share/thumbnailers/f3d-plugin-exodus.thumbnailer
share/thumbnailers/f3d-plugin-native.thumbnailer
%%OCCT%%share/thumbnailers/f3d-plugin-occt.thumbnailer
share/zsh/site-functions/_f3d