%global commit 69f80b6e676ce56d1d99825c3579e59fc1e7e419 %global shortcommit %(c=%{commit}; echo ${c:0:7}) # FPC writes no DWARF that debugedit can use (Debian: "Lazarus code does not # export debug symbols"), and lazbuild strips the binary itself. %define debug_package %{nil} Name: surfice # Upstream's own version string (vers.inc: kVers='1.0.20260427'). The last # tag, v1.0.20211006, predates the Python bridge rework and TRX support. Version: 1.0.20260427 Release: 1%{?dist} Summary: Surface viewer for brain meshes, tractography and connectomes # Code: BSD-2-Clause (Chris Rorden; PythonBridge, Ryan Joseph); # MIT: meshify_simplify_quadric.pas (Fast-Quadric-Mesh-Simplification); # MPL-1.1: track_simplify.pas (Nils Haeck's Douglas-Peucker); # Zlib: ctm_loader.pas (OpenCTM MG2, Marcus Geelnard). # lzma/ is a Pascal port of the public-domain LZMA SDK decoder with no notice. # SynZip.pas (MPL-1.1 OR GPL OR LGPL) is only used with FASTGZ, which is off, # and is deleted in %%prep with the prebuilt CloudFlare zlib objects it links. License: BSD-2-Clause AND MIT AND MPL-1.1 AND Zlib URL: https://github.com/neurolabusc/surf-ice Source0: %{url}/archive/%{commit}/surf-ice-%{shortcommit}.tar.gz Source1: surfice.metainfo.xml # Debian's -dPYTHON_DYNAMIC build, made to work here: no static # libpython3.7m.a on Linux, and find /usr/lib64/libpython3.X.so.1.0. Patch0: surfice-python-dynamic-linux.patch # The dynamic import table names seven functions removed since Python 3.10; # the first failed Assert stopped Python from loading at all on 3.14. Patch1: surfice-python-removed-api.patch BuildRequires: lazarus >= 4.0 BuildRequires: fpc BuildRequires: fpc-src BuildRequires: lazarus-lcl-qt5 BuildRequires: qt5pas-devel BuildRequires: desktop-file-utils BuildRequires: /usr/bin/appstream-util # %%check: render a mesh through the embedded Python under Xvfb, llvmpipe BuildRequires: python3-libs BuildRequires: python3-pillow BuildRequires: xorg-x11-server-Xvfb BuildRequires: /usr/bin/xvfb-run BuildRequires: mesa-dri-drivers Requires: %{name}-data = %{version}-%{release} Requires: qt5pas%{?_isa} # Python scripting dlopen()s libpython3.X.so.1.0; nothing records that. Requires: python3-libs%{?_isa} Requires: hicolor-icon-theme Recommends: pigz %description Surf Ice renders neuroimaging surface meshes with statistical overlays, fibre tractography and connectome node and edge graphs, with ambient occlusion, matcap shading, clipping planes and transparency. It reads GIfTI, FreeSurfer, MZ3, OBJ, PLY, STL, VTK, CIFTI and OpenCTM meshes, TrackVis, TRX and VTK streamlines and BrainNet node/edge files, and can turn a NIfTI volume into a mesh. Rendering can be scripted in Python (import gl) for batch figure production. It is the surface companion to MRIcroGL. %package data Summary: Shaders, colour tables, matcaps and sample meshes for Surf Ice BuildArch: noarch # BSD-2-Clause: shaders, colour tables, scripts, sample fMRI meshes; # GPL-2.0-or-later: the Blender matcaps (Resources/matcap/license.txt); # MIT: the three.js Porcelain matcap; # HPND: meshes from the MNI ICBM 2009 template (sample/mni152_2009*); # GPL-1.0-or-later: BrainNet/ meshes, from BrainNet Viewer ("GNU GPL", no # version stated); # OFL-1.1, Apache-2.0: signed-distance atlases rendered from Montserrat, # Open Sans, Oswald, Oxygen (OFL) and Roboto (Apache, the default). # Removed in %%prep, not shipped: atlas/AICHAhr.lh.mz3 (AICHA: "freely use # it for non profit research purposes", any other use by permission) and # Resources/matcap/Fubax.jpg (from fubax-shaders, commercial use by # negotiation); the Ubuntu font atlas (Ubuntu Font Licence, not allowed in # Fedora). License: BSD-2-Clause AND GPL-2.0-or-later AND MIT AND HPND AND GPL-1.0-or-later AND OFL-1.1 AND Apache-2.0 %description data Architecture-independent files for Surf Ice: GLSL shaders, colour lookup tables, matcap textures, font atlases, example Python scripts, and sample meshes (MNI152 2009 cortex, BrainNet Viewer meshes and node/edge files, and an fMRI motor activation). %prep %autosetup -n surf-ice-%{commit} -p1 # Prebuilt binaries: static libpython 3.7, CloudFlare zlib objects for three # platforms, a Windows Python and runtime, and the macOS app bundle. rm -rf PythonBridge/x86_64-linux PythonBridge/x86_64-darwin PythonBridge/aarch64-darwin \ x86_64-linux x86_64-darwin x86_64-win64 surfice.app rm -f Resources/python36.dll Resources/python36.zip Resources/vcruntime140.dll rm -f SynZip.pas SynFPCLinux.pas Synopse.inc # Non-free data (see the -data License comment). rm -f atlas/AICHAhr.lh.mz3 Resources/matcap/Fubax.jpg Resources/lut/Ubuntu.json Resources/lut/Ubuntu.png rmdir atlas # Upstream commits most files 0755. find . -type f \( -name '*.txt' -o -name '*.md' -o -name '*.py' -o -name '*.mz3' -o -name LICENSE \) -exec chmod 0644 {} + find . \( -name '*.bat' -o -name '*.command' -o -name '*.dll' -o -name '*.so' \ -o -name '*.a' -o -name '*.o' -o -name '*.ppu' \) -print -delete # surfice.lpi targets macOS on Apple Silicon: TargetCPU aarch64 would # cross-compile on x86_64, and -k-ld_classic is an Apple linker flag. # Build for the host, link libpython at run time, PIC code as in mricrogl. sed -i -e '//d' \ -e '/|-dPYTHON_DYNAMIC -Cg -k-no-pie"/>|' \ surfice.lpi grep -q -- '-dPYTHON_DYNAMIC' surfice.lpi ! grep -q 'TargetCPU Value="aarch64"' surfice.lpi %build lazbuild --lazarusdir=%{_libdir}/lazarus --ws=qt5 --build-all surfice.lpi test -x surfice %install # The binary finds its data next to itself: Resources/ (ResourceDir) and # sample/, BrainNet/ (default meshes, from the executable's directory), so it # lives in libexec beside links into /usr/share, as mricrogl does. install -Dpm 0755 surfice %{buildroot}%{_libexecdir}/%{name}/%{name} mkdir -p %{buildroot}%{_datadir}/%{name} cp -pr Resources/lut Resources/matcap Resources/script Resources/shaders \ Resources/shadersOld %{buildroot}%{_datadir}/%{name}/ # Each folder keeps its Reference.txt (the provenance of its meshes). cp -pr sample BrainNet %{buildroot}%{_datadir}/%{name}/ find %{buildroot}%{_datadir}/%{name} -type f -exec chmod 0644 {} + ln -s ../../share/%{name} %{buildroot}%{_libexecdir}/%{name}/Resources ln -s ../../share/%{name}/sample %{buildroot}%{_libexecdir}/%{name}/sample ln -s ../../share/%{name}/BrainNet %{buildroot}%{_libexecdir}/%{name}/BrainNet mkdir -p %{buildroot}%{_bindir} cat > %{buildroot}%{_bindir}/%{name} <<'EOF' #!/bin/sh exec %{_libexecdir}/%{name}/%{name} "$@" EOF chmod 0755 %{buildroot}%{_bindir}/%{name} install -Dpm 0644 deb/surfice.1 %{buildroot}%{_mandir}/man1/surfice.1 install -Dpm 0644 surfice.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/%{name}.svg install -Dpm 0644 icon.png %{buildroot}%{_datadir}/icons/hicolor/256x256/apps/%{name}.png # Upstream's (Debian's) entry, with an icon name instead of an absolute path, # no GTK category (this is a Qt build), and one main category. desktop-file-install --dir=%{buildroot}%{_datadir}/applications \ --set-icon=%{name} \ --set-key=Categories --set-value="Science;MedicalSoftware;DataVisualization;" \ --set-key=Keywords --set-value="MRI;mesh;GIfTI;tractography;connectome;brain;neuroimaging;" \ deb/surfice.desktop install -Dpm 0644 %{SOURCE1} %{buildroot}%{_metainfodir}/%{name}.metainfo.xml appstream-util validate-relax --nonet %{buildroot}%{_metainfodir}/%{name}.metainfo.xml %check desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop # Render the shipped MNI152 cortex, then the same view with the shipped # motor activation, through the embedded Python from the installed tree. A # PNG exists only if libpython was found and loaded and the gl module ran; # the comparisons fail if the mesh did not load or the overlay was not drawn. # Preferences for a headless run: Xvfb's llvmpipe offers no multisampled GLX # configs, so the default MultiSample=1 makes Lazarus raise "Could not find # FB config" in a modal dialog. On Mesa, Surf Ice drops to "Poor" quality, # where savebmpxy reads back whatever the window last painted (stale under # a script); "Better" (MesaWarned=1, RenderQuality=1) renders each capture # into a framebuffer object. The -S script also starts before the GL control # is realised, hence the first wait. for d in Resources/shaders Resources/matcap sample BrainNet; do test -d %{buildroot}%{_libexecdir}/%{name}/$d done export HOME=$PWD/check-home LIBGL_ALWAYS_SOFTWARE=1 GALLIUM_DRIVER=llvmpipe mkdir -p "$HOME/.surfice" printf '[BOOL]\nMultiSample=0\nMesaWarned=1\n[INT]\nRenderQuality=1\n' > "$HOME/.surfice/surfice.ini" S=%{buildroot}%{_libexecdir}/%{name}/sample cat > check.py < 90 over_px = sum(diff(a, b) for a, b in zip(mesh, over)) print(f'background={bg} mesh={fg} overlay={over_px}') assert sum(p != bg for p in empty) < 0.02 * len(empty), 'empty scene not empty' assert fg > 0.20 * len(mesh), 'mesh not rendered' assert 200 < over_px < 0.10 * len(mesh), 'overlay not rendered' EOF %files %license LICENSE %doc README.md COMMANDS.md PYTHON.md %{_bindir}/%{name} %{_libexecdir}/%{name}/ %{_mandir}/man1/surfice.1* %{_datadir}/applications/%{name}.desktop %{_datadir}/icons/hicolor/scalable/apps/%{name}.svg %{_datadir}/icons/hicolor/256x256/apps/%{name}.png %{_metainfodir}/%{name}.metainfo.xml %files data %license LICENSE %{_datadir}/%{name}/ %changelog * Fri Oct 16 2026 Morgan Hough - 1.0.20260427-1 - Initial package: master 69f80b6, Qt 6 widgetset, Python scripting through the system libpython loaded at run time. - Prebuilt libpython, zlib objects and Windows runtimes removed; the AICHA atlas (non-commercial), the Fubax matcap and the Ubuntu font atlas removed. - %%check renders a shipped mesh and overlay through a Python script under Xvfb with llvmpipe and checks the PNG.