Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 200 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
name: Release

# Fires when a version tag (e.g. v1.2.3) is pushed — typically right after
# merging the PR that should ship, via `git tag vX.Y.Z && git push origin
# vX.Y.Z` on main. Produces a Windows and a Linux binary archive and
# attaches both to a GitHub Release named after the tag.
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+*'

permissions:
contents: write

jobs:
# ──────────────────────────────────────────────
# Windows (primary platform)
# ──────────────────────────────────────────────
build-windows:
name: Windows / MSVC 2026
# Kept in lockstep with ci.yml's build-windows job — see the comment
# there for why this is pinned rather than "windows-latest".
runs-on: windows-2025-vs2026

steps:
- uses: actions/checkout@v5

- name: Cache Vulkan SDK
id: vulkan-cache
uses: actions/cache@v5
with:
path: C:\VulkanSDK
key: vulkan-sdk-windows-1.3.290.0

- name: Install Vulkan SDK
if: steps.vulkan-cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
$version = "1.3.290.0"
Write-Host "Downloading Vulkan SDK $version..."
Invoke-WebRequest `
-Uri "https://sdk.lunarg.com/sdk/download/$version/windows/VulkanSDK-$version-Installer.exe" `
-OutFile "$env:TEMP\VulkanSDK-Installer.exe"
Write-Host "Installing (silent)..."
$p = Start-Process "$env:TEMP\VulkanSDK-Installer.exe" `
-ArgumentList "--accept-licenses","--accept-messages","--confirm-command","install" `
-Wait -PassThru
Write-Host "Installer exit code: $($p.ExitCode)"

- name: Set Vulkan SDK environment
shell: pwsh
run: |
$version = "1.3.290.0"
echo "VULKAN_SDK=C:\VulkanSDK\$version" | Out-File -FilePath $env:GITHUB_ENV -Append
echo "C:\VulkanSDK\$version\Bin" | Out-File -FilePath $env:GITHUB_PATH -Append

- name: Setup vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: 57987637aac17d62bac535bc839baca3754490e6

- name: Cache vcpkg installed packages
uses: actions/cache@v5
with:
path: build/vcpkg_installed
# Same key ci.yml uses for this runner image, so a release build
# reuses whatever main's last CI run already populated instead of
# rebuilding every dependency from scratch.
key: vcpkg-windows-2025-vs2026-x64-${{ hashFiles('vcpkg.json') }}-57987637

- name: Configure CMake
run: >
cmake -B build
-G "Visual Studio 18 2026" -A x64
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"

- name: Build
run: cmake --build build --config Release --parallel

- name: Test
run: ctest --test-dir build -C Release --output-on-failure

- name: Install
run: cmake --install build --config Release --prefix install

- name: Bundle runtime DLLs
# vcpkg's default Windows triplet (x64-windows) links dependencies
# dynamically. VCPKG_APPLOCAL_DEPS (on by default with the vcpkg
# toolchain file) already copies the required DLLs next to
# build/Release/chiselcad.exe as a post-build step — `cmake
# --install` only installs the chiselcad target itself, so those
# DLLs have to be copied into the package by hand.
shell: pwsh
run: Copy-Item build\Release\*.dll install\bin\ -ErrorAction SilentlyContinue

- name: Package
shell: pwsh
run: |
$version = "${{ github.ref_name }}"
Compress-Archive -Path install\* -DestinationPath "chiselcad-$version-windows-x64.zip"

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: chiselcad-windows-x64
path: chiselcad-*-windows-x64.zip
if-no-files-found: error

# ──────────────────────────────────────────────
# Linux
# ──────────────────────────────────────────────
build-linux:
name: Linux / GCC
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5

- name: Install Vulkan SDK and build tools
run: |
wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc \
| sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-noble.list \
https://packages.lunarg.com/vulkan/lunarg-vulkan-noble.list
sudo apt-get update
sudo apt-get install -y \
vulkan-sdk \
ninja-build \
libxinerama-dev \
libxcursor-dev \
xorg-dev \
libglu1-mesa-dev \
pkg-config

- name: Setup vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: 57987637aac17d62bac535bc839baca3754490e6

- name: Cache vcpkg installed packages
uses: actions/cache@v5
with:
path: build/vcpkg_installed
key: vcpkg-linux-x64-${{ hashFiles('vcpkg.json') }}-57987637

- name: Configure CMake
run: >
cmake -B build -G Ninja
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"

- name: Build
run: cmake --build build --parallel

- name: Test
run: ctest --test-dir build --output-on-failure

- name: Install
# vcpkg's default Linux triplet (x64-linux) links dependencies
# statically, so unlike Windows there are no extra shared libraries
# to bundle here — only system/driver libraries (libc, libstdc++,
# the Vulkan loader) are needed, and those are expected to already
# be present on any machine with a working Vulkan driver.
run: cmake --install build --prefix install

- name: Package
run: |
version="${{ github.ref_name }}"
tar czf "chiselcad-${version}-linux-x64.tar.gz" -C install .

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: chiselcad-linux-x64
path: chiselcad-*-linux-x64.tar.gz
if-no-files-found: error

# ──────────────────────────────────────────────
# Publish
# ──────────────────────────────────────────────
publish-release:
name: Publish GitHub Release
needs: [build-windows, build-linux]
runs-on: ubuntu-latest

steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true

- name: Create release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "${{ github.ref_name }}" dist/* \
--repo "${{ github.repository }}" \
--title "${{ github.ref_name }}" \
--generate-notes
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,16 @@ if(WIN32)
set(PLATFORM_SOURCES
src/editor/FileWatcherWin32.cpp
)
set(PLATFORM_UTIL_SOURCES
src/util/ResourcePathsWin32.cpp
)
elseif(UNIX)
set(PLATFORM_SOURCES
src/editor/FileWatcherInotify.cpp
)
set(PLATFORM_UTIL_SOURCES
src/util/ResourcePathsPosix.cpp
)
endif()

# ============================================================
Expand All @@ -92,6 +98,10 @@ set(CHISELCAD_SOURCES
src/app/Config.cpp
src/app/MeshBuilder.cpp

# Util
src/util/ResourcePaths.cpp
${PLATFORM_UTIL_SOURCES}

# Editor (external editor + file watcher only; no embedded editor in v1)
src/editor/ExternalEditor.cpp
src/editor/DiagnosticsPanel.cpp
Expand Down Expand Up @@ -218,6 +228,8 @@ set(CHISELCAD_TEST_SOURCES
src/lang/Interpreter.cpp
src/lang/SourceLoader.cpp
src/csg/CsgEvaluator.cpp
src/util/ResourcePaths.cpp
${PLATFORM_UTIL_SOURCES}
src/import/StlLoader.cpp
src/import/OffLoader.cpp
src/import/DxfLoader.cpp
Expand Down
4 changes: 3 additions & 1 deletion src/app/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#endif

#include "editor/ExternalEditor.h"
#include "util/ResourcePaths.h"

namespace chisel::app {
using namespace chisel::io;
Expand Down Expand Up @@ -249,7 +250,8 @@ void Application::initVulkan() {
glfwGetFramebufferSize(m_window, &w, &h);
m_vma.init(m_ctx.instance(), m_ctx.physDevice(), m_ctx.device());
m_swapchain.init(m_ctx, static_cast<uint32_t>(w), static_cast<uint32_t>(h));
m_pipeline.init(m_ctx.device(), m_swapchain.renderPass(), CHISELCAD_SHADER_DIR,
m_pipeline.init(m_ctx.device(), m_swapchain.renderPass(),
chisel::util::resolveShaderDir().string(),
m_ctx.fillModeNonSolidSupported());
m_renderer.init(m_ctx, m_swapchain);
}
Expand Down
7 changes: 2 additions & 5 deletions src/csg/CsgEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@
#include "import/ThreeMfLoader.h"
#include "util/PathSuffix.h"
#include "util/PathUtf8.h"
#include "util/ResourcePaths.h"

#include <cctype>
#include <cmath>
#include <cstdio>
#include <filesystem>
#include <glm/gtc/matrix_transform.hpp>

#ifndef CHISELCAD_RESOURCE_DIR
#error "CHISELCAD_RESOURCE_DIR must be defined by the build (see CMakeLists.txt)"
#endif

namespace chisel::csg {

using namespace chisel::lang;
Expand All @@ -31,7 +28,7 @@ static constexpr double kDeg2Rad = 3.14159265358979323846 / 180.0;
// Not baseDir-relative — this is a build-time resource path, not a
// .scad-file-relative user path (see resolveFilePathArg()).
static std::filesystem::path defaultFontPath() {
return std::filesystem::path(CHISELCAD_RESOURCE_DIR) / "fonts" / "Roboto-Regular.ttf";
return chisel::util::resolveResourceDir() / "fonts" / "Roboto-Regular.ttf";
}

// ---------------------------------------------------------------------------
Expand Down
15 changes: 11 additions & 4 deletions src/render/Pipeline.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "Pipeline.h"
#include "GpuMesh.h"
#include <array>
#include <filesystem>
#include <fstream>
#include <stdexcept>
#include <vector>
Expand Down Expand Up @@ -229,6 +230,12 @@ VkPipeline Pipeline::buildBackgroundPipeline(VkDevice device, VkRenderPass rende
// ---------------------------------------------------------------------------
// init
// ---------------------------------------------------------------------------
namespace {
std::string shaderPath(const std::string& shaderDir, const char* name) {
return (std::filesystem::path(shaderDir) / name).string();
}
} // namespace

void Pipeline::init(VkDevice device, VkRenderPass renderPass,
const std::string& shaderDir, bool wireSupported)
{
Expand All @@ -247,8 +254,8 @@ void Pipeline::init(VkDevice device, VkRenderPass renderPass,
layoutCI.pPushConstantRanges = pcRanges.data();
VK_CHECK(vkCreatePipelineLayout(device, &layoutCI, nullptr, &m_layout));

auto vertMod = loadShader(device, shaderDir + "mesh.vert.spv");
auto fragMod = loadShader(device, shaderDir + "mesh.frag.spv");
auto vertMod = loadShader(device, shaderPath(shaderDir, "mesh.vert.spv"));
auto fragMod = loadShader(device, shaderPath(shaderDir, "mesh.frag.spv"));

// Solid pipeline: filled triangles, back-face culling, no depth bias
m_solidPipeline = buildPipeline(device, renderPass, vertMod, fragMod,
Expand All @@ -270,8 +277,8 @@ void Pipeline::init(VkDevice device, VkRenderPass renderPass,
bgLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
VK_CHECK(vkCreatePipelineLayout(device, &bgLayoutCI, nullptr, &m_bgLayout));

auto bgVert = loadShader(device, shaderDir + "background.vert.spv");
auto bgFrag = loadShader(device, shaderDir + "background.frag.spv");
auto bgVert = loadShader(device, shaderPath(shaderDir, "background.vert.spv"));
auto bgFrag = loadShader(device, shaderPath(shaderDir, "background.frag.spv"));
m_bgPipeline = buildBackgroundPipeline(device, renderPass, bgVert, bgFrag);
vkDestroyShaderModule(device, bgVert, nullptr);
vkDestroyShaderModule(device, bgFrag, nullptr);
Expand Down
41 changes: 41 additions & 0 deletions src/util/ResourcePaths.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "util/ResourcePaths.h"

#include <system_error>

namespace chisel::util {

namespace {

std::filesystem::path installedCandidate(const char* leaf) {
return executableDir() / ".." / "share" / "chiselcad" / leaf;
}

} // namespace

std::filesystem::path resolveShaderDir() {
std::filesystem::path installed = installedCandidate("shaders");
std::error_code ec;
if (std::filesystem::exists(installed, ec)) {
return installed;
}
#ifdef CHISELCAD_SHADER_DIR
return CHISELCAD_SHADER_DIR;
#else
return installed;
#endif
}

std::filesystem::path resolveResourceDir() {
std::filesystem::path installed = installedCandidate("resources");
std::error_code ec;
if (std::filesystem::exists(installed, ec)) {
return installed;
}
#ifdef CHISELCAD_RESOURCE_DIR
return CHISELCAD_RESOURCE_DIR;
#else
return installed;
#endif
}

} // namespace chisel::util
23 changes: 23 additions & 0 deletions src/util/ResourcePaths.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once
#include <filesystem>

namespace chisel::util {

// Directory containing the currently running executable, resolved via a
// platform API (never argv[0] or the current working directory, both of
// which are caller-controlled and unreliable).
std::filesystem::path executableDir();

// Resolves the directory holding compiled SPIR-V shaders. Prefers the
// relocatable installed layout (<exeDir>/../share/chiselcad/shaders, as
// produced by `cmake --install`) so a packaged release binary keeps working
// after being copied to another machine; falls back to the compile-time
// build-tree path (CHISELCAD_SHADER_DIR) for dev builds run in place from
// the build directory.
std::filesystem::path resolveShaderDir();

// Same idea as resolveShaderDir(), for the bundled resources/ directory
// (fonts, etc).
std::filesystem::path resolveResourceDir();

} // namespace chisel::util
Loading
Loading