# See docs/imagevis3d-tuvok-plan.md for the survey behind this spec: the # bundled-library inventory, the licence audit and the upstream asks. # # Upstream has no release after 3.1.0 (2014). The tag v4.0.0rc (2021-03-01) # is the newest state of ImageVis3D that matches a Tuvok commit, but its # submodule pointer is WRONG: it still points at Tuvok 2c91b69 (2016), which # lacks the API the 4.0 GUI calls (SysTools::toNarrow, RemoveFile, string # instead of wstring) and does not compile against it. Its .gitmodules names # the branch IV3D-4.0.0-import, whose only commit, 8cefa8c "Jens changes for # IMV3D 4.0.0", was pushed four minutes before the tag. That pair is what # builds. The later mac_build branches (2022-23) pin a Tuvok descended from # 2016 master, not from the 4.0 import, and fail the same way. %global commit 17c460cb85f78ef3710b79dcb560f0dd10ef43a4 %global shortcommit %(c=%{commit}; echo ${c:0:7}) %global tuvok_commit 8cefa8c8d2f08b574b0a7e8ac43687d444f1922a %global tuvok_short %(c=%{tuvok_commit}; echo ${c:0:7}) %global snapdate 20210301 # Tuvok vendors Lua 5.2.0 compiled as C++ (see the bundling note below); it is # swapped for the last 5.2 release, which only fixes bugs (CVE-2014-5461 among them). %global lua_version 5.2.4 Name: imagevis3d # IV3D_VERSION and TUVOK_VERSION in the sources are both "4.0.0"; the tag # says rc, and the Tuvok half is a commit the tag does not record, so this # is a snapshot of a pre-release. Version: 4.0.0~rc^%{snapdate}git%{shortcommit} # Explicit, not %%autorelease (ci/PROCEDURES.md golden rule 3). Release: 4%{?dist} Summary: Interactive volume rendering of large 3D datasets # ImageVis3D and Tuvok: MIT (LICENSE; per-file headers, 2008-2020 SCI and # University of Duisburg-Essen). Tuvok has no LICENSE file of its own. # Bundled Lua 5.2.4: MIT. # Tuvok/IO/expressions parser: regenerated at build time by bison 3.8, whose # skeleton is GPL-3.0-or-later WITH Bison-exception-2.2. Confirm with # fedora-license-data whether the exception lets this be left out. # Deleted in %%prep, so not in the binary RPMs: the QFtp copy (LGPL-2.1 WITH # Qt-LGPL-exception-1.1 OR GPL-3.0-only), the Windows-only DirectX # VideoMemory sample files (VidMemViaD{Draw,XGI}.cpp; their headers say "All # rights reserved", but Microsoft has since published the same files under # MIT in github.com/microsoft/DirectX-SDK-Samples, C++/Misc/VideoMemory, so # the source tarball is redistributable), the cxxtest copy (LGPL-2.1), and the # copies of zlib, bzip2, IJG libjpeg 6b, libtiff 3.9.2, lz4, the LZMA SDK, # GLEW, Boost and TCLAP. # OPEN: Tuvok/IO/UVF/ExtendedOctree/Hilbert.h says it is derived from Doug # Moore's 1998 Rice University Hilbert code but carries no notice; # Basics/Checksums/MD5.{h,cpp} carry no header at all ("RSA MD5 # Implementation"). Both are compiled in. License: MIT AND GPL-3.0-or-later WITH Bison-exception-2.2 URL: https://github.com/SCIInstitute/ImageVis3D Source0: %{url}/archive/%{commit}/ImageVis3D-%{commit}.tar.gz Source1: https://github.com/SCIInstitute/Tuvok/archive/%{tuvok_commit}/Tuvok-%{tuvok_commit}.tar.gz Source2: https://www.lua.org/ftp/lua-%{lua_version}.tar.gz Source3: imagevis3d.desktop Source4: imagevis3d-wrapper.sh Source5: imagevis3d.metainfo.xml # All patches apply after %%prep has stripped the CRLF line endings that the # 4.0 import introduced across most of both trees. # # Use the system GLEW, libjpeg-turbo, libtiff, bzip2, lz4, LZMA SDK, zlib, # minizip-ng (compat API), Boost and TCLAP instead of the bundled copies: # include paths, .pro source lists, a shared system-libs.pri (Tuvok is a static # library, so every program needs its link line), LZ4_compress[HC2] -> # LZ4_compress_default/LZ4_compress_HC, ISzAlloc callbacks typed for LZMA SDK # 25, BITS_IN_JSAMPLE from , a const JOCTET* cast, drop -std=c++0x, # a no-op link flag ("-bullshit-link-flag") and the missing -fopenmp on genlua. Patch0: imagevis3d-system-libraries.patch # GCC 16 defaults to C++20: operator<<(ostream&, const wchar_t*) is deleted # (it printed the pointer before). Console::printf(wchar_t*) also passed a # byte count as a wchar_t count to vswprintf. LuaStrictStack # returned a pointer into a destroyed temporary. Patch1: imagevis3d-cxx20.patch # Every LZMA conversion aborted on an assert: the tree's LZMA props are made at # level L, the bricks are encoded at L-1. Decoding is unaffected (the # dictionary in the tree props is the larger one), so drop the assert. Patch2: imagevis3d-lzma-props-assert.patch # Qt 6: QGLWidget/QGLContext/QGLFormat -> QOpenGLWidget/QOpenGLContext/ # QSurfaceFormat (compatibility profile, contexts shared via # Qt::AA_ShareOpenGLContexts); Tuvok returns to the widget's FBO instead of 0; # screen capture reads that FBO; QImage::byteCount, QDesktopWidget, # QWheelEvent::delta, Qt::MidButton, "Qt::WindowFlags = 0" defaults; uic # --connections string. Also takes QFtp out of the build. Still builds with Qt 5.15. Patch3: imagevis3d-qt6.patch # "Report an issue" uploaded logs by anonymous FTP to ftp.sci.utah.edu through # QFtp. Keep the file and point at the GitHub tracker instead. Patch4: imagevis3d-no-ftp-upload.patch # Interactive start cd'd into the executable's directory (for tarball # installs), so every file dialog opened in /usr/libexec/imagevis3d and # relative paths broke. Shaders are found by absolute path; drop the cd. Patch5: imagevis3d-no-cwd-hack.patch # GridLeaper never started on Mesa: GLGridLeaper-frontfaces-FS.glsl writes # gl_FragColor under "#version 420 core", which strict compilers reject; and # the 4.0 import added a layout check that compares the finest level's brick # count with the all-levels metadata size, so it threw for every dataset with # more than one brick. The check now compares the pool's layout with the # dataset's at every level. The generated hash-table shader used the # EXT_shader_image_load_store qualifier "size1x32"; core GLSL 4.2 spells it r32ui. Patch6: imagevis3d-gridleaper.patch # Importer/exporter fixes found by a format-by-format round trip: # VTK: any type but float threw an uncaught std::logic_error (uvfconvert # aborted); header keys were read in a fixed order (SPACING before ORIGIN # gave aspect 0); POINT_DATA was treated as cell data (each axis one short); # it dumped rawdata-from-vtk.data into the working directory. # MHD: HeaderSize was taken from DimSize[0], so Tuvok's own .mhd export (which # writes "HeaderSize = 0") re-imported shifted by DimSize[0] bytes. # DICOM: PixelSpacing is row\column (y\x); x and y were swapped. # NIfTI-1: accept DT_INT8, DT_UINT16 and DT_UINT32 (uint16 was "Unknown data type"). # BOV export: write USHORT for unsigned 16-bit data. # Direct (non-UVF) conversion ignored the reader's endianness flag, so big-endian # sources (legacy VTK, VFF) were written byte-swapped under a little-endian header. Patch7: imagevis3d-io-fixes.patch # Link-time "tmpnam is dangerous" warnings: SysTools::GetTempDirectory used # tmpnam() only for its directory (now TMPDIR or /tmp); Lua gets LUA_USE_POSIX # (mkstemp for os.tmpname). Patch8: imagevis3d-tmpnam.patch # Shaders were looked up in the current directory before the search path (a # stray GLSBVR-1D-FS.glsl in $PWD replaced the installed one), and Tuvok added # ./Shaders, ./Tuvok/Shaders and ../Tuvok/Shaders. Linux uses only the installed # directory and absolute paths. Patch9: imagevis3d-shader-path.patch BuildRequires: gcc-c++ BuildRequires: make BuildRequires: qt6-qtbase-devel BuildRequires: glew-devel BuildRequires: mesa-libGLU-devel BuildRequires: libjpeg-turbo-devel BuildRequires: libtiff-devel BuildRequires: bzip2-devel BuildRequires: lz4-devel BuildRequires: lzma-sdk-devel BuildRequires: zlib-devel BuildRequires: minizip-ng-compat-devel BuildRequires: boost-devel # tclap-devel is in mhough/neurofedora, not in Fedora. BuildRequires: tclap-devel BuildRequires: bison BuildRequires: flex BuildRequires: desktop-file-utils BuildRequires: /usr/bin/appstream-util # Tuvok, the renderer, is SCI's own library but a separate repository with no # release, no install rules, no soname and no consumer other than ImageVis3D. # It is built in-tree as a static convenience library and not shipped. Provides: bundled(tuvok) = 4.0.0~rc^%{snapdate}git%{tuvok_short} # Lua stays bundled: Tuvok compiles it as C++ so that lua_error() throws and # lua_pcall() catches C++ exceptions, which its binding layer relies on (it # throws tuvok::LuaError from bound functions and keeps RAII guards on the Lua # stack). Fedora's Lua is C (longjmp) and 5.4, not 5.2. Provides: bundled(lua) = %{lua_version} # Image stacks are read through QImage; TIFF needs the plugin in # qt6-qtimageformats (without it a TIFF directory gives "found 0 image stacks"). Recommends: qt6-qtimageformats %description ImageVis3D is a volume rendering application from the SCI Institute (University of Utah) and the HPC group at the University of Duisburg-Essen, built on the Tuvok rendering library. It renders large 3D datasets interactively with 1D and 2D transfer functions, isosurfaces, clipping and stereo, and converts many volume formats (DICOM, NRRD, Analyze/NIfTI-1, TIFF stacks, VTK, raw and others) to its bricked multi-resolution UVF format. This package also contains uvfconvert, the command-line converter, which runs without a display. %prep %setup -q -n ImageVis3D-%{commit} rmdir Tuvok tar -xzf %{SOURCE1} mv Tuvok-%{tuvok_commit} Tuvok # Most text files are CRLF since the 4.0 import; the patches are LF. grep -rIlZ $'\r' . | xargs -0 -r sed -i 's/\r$//' %autopatch -p1 # Bundled code with a system replacement, Windows-only code, and code the # patches took out of the build. rm -r StandaloneTuvok rm -r Tuvok/3rdParty/GLEW rm -r Tuvok/IO/3rdParty/{boost,bzip2,cxxtest,jpeglib,lz4,lzma,tiff,zlib} rm -r Tuvok/Basics/3rdParty rm ImageVis3D/IO/3rdParty/{crypt.h,ioapi.c,ioapi.h,zip.c,zip.h} rm -r ImageVis3D/IO/3rdParty/QFtp rm ImageVis3D/UI/FTPDialog.{h,cpp} ImageVis3D/UI/UI/FTPDialog.ui rm Tuvok/Basics/Systeminfo/VidMemViaDDraw.cpp Tuvok/Basics/Systeminfo/VidMemViaDXGI.cpp # Pre-generated bison 2.3 / flex output: regenerated by expressions.pro. rm Tuvok/IO/expressions/tvk-parse.parser.{cpp,hpp} Tuvok/IO/expressions/tvk-scan.lexer.cpp # Lua 5.2.0 -> 5.2.4. Upstream's copy is pristine 5.2.0 (checked with diff -w) # with .c renamed to .cpp and an extern-"C"-free lua.hpp, which is kept. tar -xzf %{SOURCE2} for f in lua-%{lua_version}/src/*.c; do t=Tuvok/3rdParty/LUA/$(basename "$f" .c).cpp if [ -f "$t" ]; then cp -p "$f" "$t"; fi done for f in lua-%{lua_version}/src/*.h; do t=Tuvok/3rdParty/LUA/$(basename "$f") if [ -f "$t" ]; then cp -p "$f" "$t"; fi done # The Lua licence lives at the end of lua.h. sed -n '/Copyright (C) 1994/,/\*\*\*\*\*/p' lua-%{lua_version}/src/lua.h > LICENSE-lua rm -r lua-%{lua_version} %build # qmake subdirs with CONFIG += ordered; each program links the static Tuvok. %{qmake_qt6} -r ImageVis3D.pro %make_build %install install -Dpm 0755 Build/ImageVis3D %{buildroot}%{_libexecdir}/%{name}/ImageVis3D install -Dpm 0755 %{SOURCE4} %{buildroot}%{_bindir}/%{name} sed -i 's|/usr/libexec|%{_libexecdir}|' %{buildroot}%{_bindir}/%{name} install -Dpm 0755 CmdLineConverter/Build/uvfconvert %{buildroot}%{_bindir}/uvfconvert # UVF inspector and checksum verifier, renamed: "uvf" is too generic for /usr/bin. install -Dpm 0755 UVFReader/Build/uvf %{buildroot}%{_bindir}/imagevis3d-uvf # RenderWindowGL.cpp adds /usr/share/imagevis3d/shaders on Linux. install -d %{buildroot}%{_datadir}/%{name}/shaders install -pm 0644 Tuvok/Shaders/*.glsl %{buildroot}%{_datadir}/%{name}/shaders/ install -Dpm 0644 doc/imagevis3d.1 %{buildroot}%{_mandir}/man1/imagevis3d.1 install -Dpm 0644 doc/uvfconvert.1 %{buildroot}%{_mandir}/man1/uvfconvert.1 install -Dpm 0644 ImageVis3D/Resources/icon_256.png \ %{buildroot}%{_datadir}/icons/hicolor/256x256/apps/%{name}.png desktop-file-install --dir=%{buildroot}%{_datadir}/applications %{SOURCE3} install -Dpm 0644 %{SOURCE5} %{buildroot}%{_metainfodir}/%{name}.metainfo.xml %check # Headless: uvfconvert needs no display or GL. c60.uvf is upstream's # zlib-compressed demo volume and c60_old.uvf the same volume in the old # uncompressed format, so decoding the first with system zlib must give the # second byte for byte. Then the volume goes through every codec (zlib, LZMA # SDK, lz4, bzip2) and back. export QT_QPA_PLATFORM=offscreen mkdir -p check && cd check U=../CmdLineConverter/Build/uvfconvert N=$((128*128*128)) $U -i ../DemoData/c60_old.uvf -o ref.nrrd $U -i ../DemoData/c60.uvf -o zlib-demo.nrrd tail -c $N ref.nrrd > ref.raw tail -c $N zlib-demo.nrrd | cmp - ref.raw for p in 1 2 3 4; do $U -i ref.nrrd -o rt$p.uvf -p $p -v 5 $U -i rt$p.uvf -o rt$p.nrrd tail -c $N rt$p.nrrd | cmp - ref.raw done # MHD export must re-import unchanged (it wrote HeaderSize = 0 and the # reader used DimSize[0] as the header size). $U -i ref.nrrd -o exp.mhd $U -i exp.mhd -o mhd.nrrd tail -c $N mhd.nrrd | cmp - ref.raw # legacy VTK, unsigned_char point data, SPACING before ORIGIN { printf '# vtk DataFile Version 3.0\nc60\nBINARY\nDATASET STRUCTURED_POINTS\n' printf 'DIMENSIONS 128 128 128\nSPACING 1 1 1\nORIGIN 0 0 0\nPOINT_DATA %%d\n' $N printf 'SCALARS c60 unsigned_char 1\nLOOKUP_TABLE default\n'; cat ref.raw; } > c60.vtk $U -i c60.vtk -o vtk.nrrd tail -c $N vtk.nrrd | cmp - ref.raw test ! -e rawdata-from-vtk.data ../UVFReader/Build/uvf -f ../DemoData/c60.uvf | grep -q 'Checksum is valid' cd .. desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop appstream-util validate-relax --nonet %{buildroot}%{_metainfodir}/%{name}.metainfo.xml %files %license LICENSE LICENSE-lua %doc README.md %{_bindir}/%{name} %{_bindir}/uvfconvert %{_bindir}/imagevis3d-uvf %{_libexecdir}/%{name}/ %{_datadir}/%{name}/ %{_datadir}/applications/%{name}.desktop %{_datadir}/icons/hicolor/256x256/apps/%{name}.png %{_metainfodir}/%{name}.metainfo.xml %{_mandir}/man1/imagevis3d.1* %{_mandir}/man1/uvfconvert.1* %changelog * Sun Oct 11 2026 Morgan Hough - 4.0.0~rc^20210301git17c460c-4 - Error reports are kept: the no-FTP stub returned false, so the caller deleted report.apx right after saying it was kept. It now returns true and shows the absolute path. * Sun Oct 11 2026 Morgan Hough - 4.0.0~rc^20210301git17c460c-3 - GridLeaper renderer works (shader and brick-layout check fixes). - Importer fixes: VTK (no abort, all scalar types, point data, header order), MHD HeaderSize, DICOM pixel spacing order, NIfTI unsigned types, BOV export, byte order of big-endian sources in direct conversions. - No tmpnam: TMPDIR-aware temp directory, Lua built with LUA_USE_POSIX. - Shaders are no longer picked up from the current directory. - Recommends qt6-qtimageformats for TIFF image stacks. - Ship the UVF inspector as imagevis3d-uvf. * Sun Oct 11 2026 Morgan Hough - 4.0.0~rc^20210301git17c460c-2 - Stop changing the working directory to /usr/libexec/imagevis3d at startup: file dialogs now open in the launch directory, not libexec * Sat Oct 10 2026 Morgan Hough - 4.0.0~rc^20210301git17c460c-1 - Initial package: v4.0.0rc with Tuvok from its IV3D-4.0.0-import branch (8cefa8c; the tag's submodule pointer names a 2016 Tuvok that does not compile with the 4.0 GUI), ported to Qt 6 (QOpenGLWidget), built against system GLEW, zlib, minizip, bzip2, libjpeg, libtiff, lz4, LZMA SDK, Boost and TCLAP. Lua stays bundled (compiled as C++, updated 5.2.0 -> 5.2.4) and Tuvok is built in-tree. Fixes for C++20, a vswprintf length, a dangling Lua string pointer and an LZMA props assert; the anonymous FTP log upload is replaced by a pointer to the issue tracker. AppStream metadata.