Skip to content

Commit 817d69b

Browse files
committed
[1.3.46] 2025-08-25
* Added cpplocate library integration for dynamic asset path resolution, enabling executables to run from any directory without path dependencies * Enhanced GitHub Actions workflows with new Windows GPU self-tests and improved CI configuration * Added comprehensive asset resolution functions including `resolveAssetPath()`, `resolvePluginAsset()`, `resolveShaderPath()`, and texture path resolution * Upgraded documentation build system with improved cross-referencing and layout enhancements ## Context - Implemented filesystem-based asset path resolution with fallback mechanisms for different installation types - Added extensive new utility functions in `global.h` for asset management and path validation - Enhanced `Context_fileIO.cpp` with robust file path handling and validation - Added comprehensive test coverage for new asset resolution functionality in `Test_functions.h` ## Visualizer - Fixed some potential segfaults that could occur when calling `Visualizer::plotInteractive()` or `Visualizer::plotUpdate()` in headless mode.
1 parent c09d5d0 commit 817d69b

607 files changed

Lines changed: 24341 additions & 17275 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/linux_GPU_selftests.yaml

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,42 @@ jobs:
2222
role-to-assume: ${{ secrets.OIDC_ROLE_ARN }}
2323
aws-region: us-west-2
2424
- run: |
25-
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID }}
26-
aws ec2 wait instance-running --instance-ids ${{ secrets.EC2_INSTANCE_ID }}
25+
# Wait for instance to be in a state where it can be started (max 5 minutes)
26+
echo "Waiting for instance to be in a startable state..."
27+
timeout 300 bash -c '
28+
while true; do
29+
STATE=$(aws ec2 describe-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID }} --query "Reservations[0].Instances[0].State.Name" --output text)
30+
echo "Current instance state: $STATE"
31+
if [[ "$STATE" == "stopped" || "$STATE" == "running" ]]; then
32+
echo "Instance is in a startable state: $STATE"
33+
break
34+
fi
35+
echo "Instance is in transitional state: $STATE. Waiting 10 seconds..."
36+
sleep 10
37+
done
38+
' || {
39+
echo "Timeout waiting for instance to reach startable state"
40+
exit 1
41+
}
42+
43+
# Only start if not already running
44+
CURRENT_STATE=$(aws ec2 describe-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID }} --query "Reservations[0].Instances[0].State.Name" --output text)
45+
if [[ "$CURRENT_STATE" == "stopped" ]]; then
46+
echo "Starting instance..."
47+
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID }}
48+
aws ec2 wait instance-running --instance-ids ${{ secrets.EC2_INSTANCE_ID }}
49+
elif [[ "$CURRENT_STATE" == "running" ]]; then
50+
echo "Instance is already running"
51+
else
52+
echo "Unexpected instance state: $CURRENT_STATE"
53+
exit 1
54+
fi
2755
2856
run_samples_linux:
2957
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
3058
# You can convert this to a matrix build if you need cross-platform coverage.
3159
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
32-
runs-on: [self-hosted]
60+
runs-on: [self-hosted, Linux]
3361
needs: start-gpu
3462
steps:
3563
- uses: actions/checkout@v3

.github/workflows/windows_GPU_selftests.yaml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,36 @@ jobs:
2222
role-to-assume: ${{ secrets.OIDC_ROLE_ARN }}
2323
aws-region: us-west-2
2424
- run: |
25-
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_WIN }}
26-
aws ec2 wait instance-running --instance-ids ${{ secrets.EC2_INSTANCE_ID_WIN }}
25+
# Wait for instance to be in a state where it can be started (max 5 minutes)
26+
echo "Waiting for instance to be in a startable state..."
27+
timeout 300 bash -c '
28+
while true; do
29+
STATE=$(aws ec2 describe-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_WIN }} --query "Reservations[0].Instances[0].State.Name" --output text)
30+
echo "Current instance state: $STATE"
31+
if [[ "$STATE" == "stopped" || "$STATE" == "running" ]]; then
32+
echo "Instance is in a startable state: $STATE"
33+
break
34+
fi
35+
echo "Instance is in transitional state: $STATE. Waiting 10 seconds..."
36+
sleep 10
37+
done
38+
' || {
39+
echo "Timeout waiting for instance to reach startable state"
40+
exit 1
41+
}
42+
43+
# Only start if not already running
44+
CURRENT_STATE=$(aws ec2 describe-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_WIN }} --query "Reservations[0].Instances[0].State.Name" --output text)
45+
if [[ "$CURRENT_STATE" == "stopped" ]]; then
46+
echo "Starting instance..."
47+
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_WIN }}
48+
aws ec2 wait instance-running --instance-ids ${{ secrets.EC2_INSTANCE_ID_WIN }}
49+
elif [[ "$CURRENT_STATE" == "running" ]]; then
50+
echo "Instance is already running"
51+
else
52+
echo "Unexpected instance state: $CURRENT_STATE"
53+
exit 1
54+
fi
2755
2856
run_samples_windows:
2957
runs-on: [self-hosted, Windows]

core/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ target_include_directories(helios
2626
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
2727
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/pugixml>
2828
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/doctest>
29+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/cpplocate/cpplocate/include>
2930
$<INSTALL_INTERFACE:include>
3031
$<INSTALL_INTERFACE:lib/pugixml>
3132
$<INSTALL_INTERFACE:lib/doctest>
33+
$<INSTALL_INTERFACE:lib/cpplocate/cpplocate/include>
3234
)
3335

3436
# External libraries
@@ -45,7 +47,10 @@ add_dependencies( png_static zlibstatic )
4547
include_directories("${CMAKE_BINARY_DIR}/lib/libjpeg-9a" "${CMAKE_CURRENT_SOURCE_DIR}/lib/libjpeg-9a")
4648
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/lib/libjpeg-9a" "${CMAKE_BINARY_DIR}/lib/libjpeg-9a")
4749

48-
target_link_libraries( helios PRIVATE png_static jpeg ) #note that zlib is already linked by libpng
50+
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/lib/cpplocate/cpplocate/include")
51+
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/lib/cpplocate" "${CMAKE_BINARY_DIR}/lib/cpplocate")
52+
53+
target_link_libraries( helios PRIVATE png_static jpeg cpplocate ) #note that zlib is already linked by libpng
4954

5055
# Suppress warnings for third-party libraries
5156
if(TARGET zlibstatic)

core/include/global.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ constexpr To scast(From &&v) noexcept {
9999
// pugi XML parser
100100
#include "pugixml.hpp"
101101

102+
// cpplocate for asset path resolution
103+
#include <cpplocate/cpplocate.h>
104+
#include <filesystem>
105+
102106
// *** Groups *** //
103107

104108
//! Miscellaneous helper functions
@@ -1115,6 +1119,85 @@ namespace helios {
11151119
*/
11161120
[[nodiscard]] bool validateOutputPath(std::string &output_directory, const std::vector<std::string> &allowable_file_extensions = {});
11171121

1122+
//--------------------- ASSET PATH RESOLUTION -----------------------------------//
1123+
1124+
//! Resolve asset file path using cpplocate, allowing executables to run from any directory
1125+
/**
1126+
* \param[in] relativePath Relative path to the asset file (e.g., "plugins/visualizer/shaders/shader.vert")
1127+
* \return Absolute path to the asset file
1128+
* \note This function searches for assets in multiple locations: build directory, system install locations, and custom paths
1129+
* \ingroup functions
1130+
*/
1131+
[[nodiscard]] std::filesystem::path resolveAssetPath(const std::string& relativePath);
1132+
1133+
//! Resolve plugin-specific asset path
1134+
/**
1135+
* \param[in] pluginName Name of the plugin (e.g., "visualizer", "plantarchitecture", "radiation")
1136+
* \param[in] assetPath Relative path within the plugin's asset directory
1137+
* \return Absolute path to the plugin asset file
1138+
* \ingroup functions
1139+
*/
1140+
[[nodiscard]] std::filesystem::path resolvePluginAsset(const std::string& pluginName, const std::string& assetPath);
1141+
1142+
//! Resolve shader file path
1143+
/**
1144+
* \param[in] shaderFile Shader filename with or without path (e.g., "primaryShader.vert" or "shaders/primaryShader.vert")
1145+
* \return Absolute path to the shader file
1146+
* \ingroup functions
1147+
*/
1148+
[[nodiscard]] std::filesystem::path resolveShaderPath(const std::string& shaderFile);
1149+
1150+
//! Resolve texture file path
1151+
/**
1152+
* \param[in] textureFile Texture filename with or without path (e.g., "AlmondLeaf.png" or "textures/AlmondLeaf.png")
1153+
* \return Absolute path to the texture file
1154+
* \ingroup functions
1155+
*/
1156+
[[nodiscard]] std::filesystem::path resolveTexturePath(const std::string& textureFile);
1157+
1158+
//! Resolve 3D model file path
1159+
/**
1160+
* \param[in] modelFile Model filename with or without path (e.g., "AlmondHull.obj" or "assets/obj/AlmondHull.obj")
1161+
* \return Absolute path to the model file
1162+
* \ingroup functions
1163+
*/
1164+
[[nodiscard]] std::filesystem::path resolveModelPath(const std::string& modelFile);
1165+
1166+
//! Resolve spectral data file path
1167+
/**
1168+
* \param[in] spectraFile Spectral data filename with or without path (e.g., "camera_spectral_library.xml")
1169+
* \return Absolute path to the spectral data file
1170+
* \ingroup functions
1171+
*/
1172+
[[nodiscard]] std::filesystem::path resolveSpectraPath(const std::string& spectraFile);
1173+
1174+
//! Validate that an asset file exists and is readable
1175+
/**
1176+
* \param[in] assetPath Path to the asset file to validate
1177+
* \return True if the file exists and is readable, false otherwise
1178+
* \ingroup functions
1179+
*/
1180+
[[nodiscard]] bool validateAssetPath(const std::filesystem::path& assetPath);
1181+
1182+
//! Find the project root directory (directory containing top-level CMakeLists.txt)
1183+
/**
1184+
* \param[in] startPath Starting directory for search (defaults to current working directory)
1185+
* \return Absolute path to the project root directory, or empty path if not found
1186+
* \note Searches upward from startPath for a directory containing CMakeLists.txt
1187+
* \ingroup functions
1188+
*/
1189+
[[nodiscard]] std::filesystem::path findProjectRoot(const std::filesystem::path& startPath = std::filesystem::current_path());
1190+
1191+
//! Resolve file path using project-based resolution strategy
1192+
/**
1193+
* \param[in] relativePath Relative path to the file
1194+
* \return Absolute path to the file
1195+
* \note Resolution order: 1) Current working directory, 2) Project directory, 3) Error
1196+
* \throws std::runtime_error if file cannot be found
1197+
* \ingroup functions
1198+
*/
1199+
[[nodiscard]] std::filesystem::path resolveProjectFile(const std::string& relativePath);
1200+
11181201
//! Read values contained in a text file into a one-dimensional vector of floats
11191202
/**
11201203
* \param[in] filepath Path to text file

core/lib/cpplocate/AUTHORS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
Stefan Buschmann <buschmann@cginternals.com>
3+
Willy Scheibel <scheibel@cginternals.com>

core/lib/cpplocate/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Minimal CMakeLists.txt for cpplocate integration into Helios
2+
cmake_minimum_required(VERSION 3.15)
3+
4+
# Only build the main cpplocate library
5+
add_subdirectory(cpplocate)

core/lib/cpplocate/LICENSE

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
Copyright (c) 2015-2018 CG Internals GmbH, Potsdam, Germany
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5+
6+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7+
8+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
#ifndef ${target_id}_TEMPLATE_API_H
3+
#define ${target_id}_TEMPLATE_API_H
4+
5+
#include <${target}/${target}_export.h>
6+
7+
#ifdef ${target_id}_STATIC_DEFINE
8+
# define ${target_id}_TEMPLATE_API
9+
#else
10+
# ifndef ${target_id}_TEMPLATE_API
11+
# ifdef ${target_id}_EXPORTS
12+
/* We are building this library */
13+
# define ${target_id}_TEMPLATE_API __attribute__((visibility("default")))
14+
# else
15+
/* We are using this library */
16+
# define ${target_id}_TEMPLATE_API __attribute__((visibility("default")))
17+
# endif
18+
# endif
19+
20+
#endif
21+
22+
#endif
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
#ifndef ${target_id}_TEMPLATE_API_H
3+
#define ${target_id}_TEMPLATE_API_H
4+
5+
#include <${target}/${target}_export.h>
6+
7+
#ifdef ${target_id}_STATIC_DEFINE
8+
# define ${target_id}_TEMPLATE_API
9+
#else
10+
# ifndef ${target_id}_TEMPLATE_API
11+
# ifdef ${target_id}_EXPORTS
12+
/* We are building this library */
13+
# define ${target_id}_TEMPLATE_API
14+
# else
15+
/* We are using this library */
16+
# define ${target_id}_TEMPLATE_API
17+
# endif
18+
# endif
19+
20+
#endif
21+
22+
#endif
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Minimal CMakeLists.txt for cpplocate integration into Helios
2+
3+
# Target name
4+
set(target cpplocate)
5+
6+
# Source files
7+
set(headers
8+
include/cpplocate/cpplocate.h
9+
)
10+
11+
set(sources
12+
source/cpplocate.cpp
13+
../liblocate/source/liblocate.c
14+
../liblocate/source/utils.c
15+
)
16+
17+
# Build library
18+
add_library(${target} STATIC
19+
${sources}
20+
${headers}
21+
)
22+
23+
# Include directories
24+
target_include_directories(${target}
25+
PUBLIC
26+
${CMAKE_CURRENT_SOURCE_DIR}/include
27+
${CMAKE_CURRENT_SOURCE_DIR}/../liblocate/include
28+
)
29+
30+
# Platform-specific libraries
31+
if(WIN32)
32+
target_link_libraries(${target} PRIVATE shlwapi)
33+
elseif(APPLE)
34+
target_link_libraries(${target} PRIVATE "-framework CoreFoundation")
35+
endif()
36+
37+
# Platform-specific compile definitions
38+
if(WIN32)
39+
set(SYSTEM_DEFINE "SYSTEM_WINDOWS")
40+
elseif(APPLE)
41+
set(SYSTEM_DEFINE "SYSTEM_DARWIN")
42+
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
43+
set(SYSTEM_DEFINE "SYSTEM_LINUX")
44+
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
45+
set(SYSTEM_DEFINE "SYSTEM_FREEBSD")
46+
elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
47+
set(SYSTEM_DEFINE "SYSTEM_SOLARIS")
48+
endif()
49+
50+
# Compile definitions
51+
target_compile_definitions(${target}
52+
PUBLIC
53+
LIBLOCATE_EXPORTS
54+
liblocate_EXPORTS
55+
${SYSTEM_DEFINE}
56+
)
57+
58+
# Set properties
59+
set_target_properties(${target}
60+
PROPERTIES
61+
CXX_STANDARD 11
62+
CXX_STANDARD_REQUIRED ON
63+
)

0 commit comments

Comments
 (0)