Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
358210b
fix(editor): resolve packaged assets and refresh imports
JeanPhilippeKernel Sep 25, 2026
7c27ee2
Merge branch 'develop' into fix/833-packaged-asset-paths
JeanPhilippeKernel Sep 27, 2026
e9f4cf8
Merge branch 'develop' into fix/833-packaged-asset-paths
JeanPhilippeKernel Sep 28, 2026
3b936e9
feat(linux): support Wayland file dialogs
JeanPhilippeKernel Sep 28, 2026
1aaed13
fix(import): publish generated textures through VFS
JeanPhilippeKernel Sep 28, 2026
8c5e7a4
fix(linux): fall back when desktop portal picker fails
JeanPhilippeKernel Sep 28, 2026
6128a7b
fix(macos): launch editor with linked Vulkan loader
JeanPhilippeKernel Sep 28, 2026
db6866c
refactor(linux): model portal response codes
JeanPhilippeKernel Sep 28, 2026
aa2321a
fix(linux): avoid X11 status macro collision
JeanPhilippeKernel Sep 28, 2026
ed769b1
fix(rendering): serialize streamed geometry uploads
JeanPhilippeKernel Sep 28, 2026
d61b5cb
fix(rendering): synchronize geometry uploads with graph work
JeanPhilippeKernel Sep 28, 2026
a2fdafd
fix(linux): skip unsupported Wayland window icon
JeanPhilippeKernel Sep 28, 2026
0b715fe
fix(vulkan): serialize universal queue families
JeanPhilippeKernel Sep 28, 2026
f7b73a7
chore(vulkan): remove obsolete queue state
JeanPhilippeKernel Sep 28, 2026
37e973d
fix(vfs): retain FSEvents run loop until shutdown
JeanPhilippeKernel Sep 28, 2026
ef53662
chore(vulkan): trace atmosphere submissions
JeanPhilippeKernel Sep 30, 2026
8730544
fix(render-graph): preserve queue batching API
JeanPhilippeKernel Sep 30, 2026
1181d77
fix(vulkan): keep submission tracing non-blocking
JeanPhilippeKernel Sep 30, 2026
7e89938
chore(vulkan): trace submission boundaries
JeanPhilippeKernel Sep 30, 2026
435eb1b
fix(logging): preserve configured flush interval
JeanPhilippeKernel Sep 30, 2026
078740e
fix(swapchain): prevent reset fence self-wait
JeanPhilippeKernel Sep 30, 2026
db7666f
fix(ui): honor Linux content scale
JeanPhilippeKernel Sep 30, 2026
8e8d2b8
fix(ui): align framebuffer scaling and camera input
JeanPhilippeKernel Oct 3, 2026
fcb499e
fix(tests): avoid Windows swapchain test stack overflow
JeanPhilippeKernel Oct 3, 2026
e1d45a2
fix(rendering): submit upload batches before frame-slot changes
JeanPhilippeKernel Oct 3, 2026
ba4113b
fix(tests): explicitly initialize upload batch frame state
JeanPhilippeKernel Oct 4, 2026
e7812bc
fix(importers): harden asset cooking and scratch ownership
JeanPhilippeKernel Oct 5, 2026
359bc14
fix(vfs): bound material metadata completion
JeanPhilippeKernel Oct 5, 2026
2806d60
fix(vfs): defer watcher processing for import publications
JeanPhilippeKernel Oct 7, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/job-cmakebuild-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
run: sudo apt-get update

- name: Install Dependencies
run: sudo apt-get install libasound2-dev libgl1-mesa-dev libpulse-dev libdbus-1-dev libx11-dev libxcursor-dev libxext-dev libxi-dev libxinerama-dev libxrandr-dev libxss-dev libxt-dev libxxf86vm-dev cmake apt-transport-https software-properties-common gcc g++ powershell clang-format-22 glslang-tools libwayland-dev libxkbcommon-dev
run: sudo apt-get install libasound2-dev libgl1-mesa-dev libpulse-dev libdbus-1-dev libglib2.0-dev libx11-dev libxcursor-dev libxext-dev libxi-dev libxinerama-dev libxrandr-dev libxss-dev libxt-dev libxxf86vm-dev cmake apt-transport-https software-properties-common gcc g++ powershell clang-format-22 glslang-tools libwayland-dev libxkbcommon-dev pkg-config

- name: CMake Build
run: .\Scripts\BuildEngine.ps1 -Configurations ${{inputs.configuration}}
Expand Down
3 changes: 0 additions & 3 deletions Obelisk/EntryPoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ int applicationEntryPoint(int argc, char* argv[])
app->Run();
app->Shutdown();

// Step 15 — join worker threads before logger/memory teardown
Helpers::ThreadPoolHelper::Shutdown();

// Step 16 — flush and dispose logger
Logger::Flush();
Logger::Dispose();
Expand Down
Binary file added Resources/Editor/Settings/FallbackTexture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 9 additions & 9 deletions Resources/Shaders/zui_draw.vert
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ layout(location = 2) in vec4 aColor; // RGBA8 UNORM — hardware unpacks packed

layout(push_constant) uniform PC
{
vec2 uScale;
vec2 uTranslate;
uint uTexIdx;
float uFbScale; // UIScale = fb/win; snaps vertices to nearest physical pixel
vec2 uScale;
vec2 uTranslate;
vec2 uFbScale; // Actual render-target pixels per logical UI unit, per axis.
uint uTexIdx;
}
pc;

Expand All @@ -21,12 +21,12 @@ layout(location = 0) out struct

void main()
{
Out.Color = aColor;
Out.TexData = vec4(aUV, float(pc.uTexIdx), 0.0);
Out.Color = aColor;
Out.TexData = vec4(aUV, float(pc.uTexIdx), 0.0);

// Snap to the nearest physical pixel before projecting.
// Prevents sub-pixel drift that blurs glyph quads on non-Retina displays.
float fs = max(pc.uFbScale, 1.0);
vec2 snapped = round(aPos * fs) / fs;
gl_Position = vec4(snapped * pc.uScale + pc.uTranslate, 0.0, 1.0);
vec2 fs = max(pc.uFbScale, vec2(0.0001));
vec2 snapped = round(aPos * fs) / fs;
gl_Position = vec4(snapped * pc.uScale + pc.uTranslate, 0.0, 1.0);
}
8 changes: 4 additions & 4 deletions Tetragrama/Layers/ZUILayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,10 @@ namespace Tetragrama::Layers
{
return false;
}
// GLFW cursor callback reports in logical screen coords (same space as
// glfwGetWindowSize / ScreenW). No division needed on any platform.
m_ctx->MousePos[0] = (float) e.GetPosX();
m_ctx->MousePos[1] = (float) e.GetPosY();
// GLFW cursor positions are in window coordinates. Convert them into
// the DPI-independent coordinate space used by ZUI layout and rendering.
m_ctx->MousePos[0] = (float) e.GetPosX() * m_ctx->InputScale[0];
m_ctx->MousePos[1] = (float) e.GetPosY() * m_ctx->InputScale[1];
return false;
}

Expand Down
253 changes: 199 additions & 54 deletions Tetragrama/Panels/AssetImporterPanel.cpp

Large diffs are not rendered by default.

75 changes: 49 additions & 26 deletions Tetragrama/Panels/AssetImporterPanel.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
#pragma once
#include <Tetragrama/Layers/ZUILayer.h>
#include <Tetragrama/Panels/PanelHelpers.h>
#include <ZEngine/Core/Containers/Array.h>
#include <ZEngine/Core/Containers/Strings.h>
#include <ZEngine/Core/Memory/Allocator.h>
#include <ZEngine/Core/Memory/TLSFSlab.h>
#include <ZEngine/Core/VFS/VFSPath.h>
#include <ZEngine/Importers/AssimpImporter.h>
#include <ZEngine/Importers/FbxImporter.h>
#include <ZEngine/Importers/GltfImporter.h>
#include <ZEngine/UI/ZUIPanel.h>
#include <uuid.h>
#include <future>
#include <mutex>
#include <string>
#include <vector>

namespace Tetragrama::Panels
{
struct ProjectViewPanel;

/// @brief Three-state asset importer panel (Idle → Options → Importing).
/// Supports glTF/GLB, FBX, and Assimp-backed formats. Import runs
/// on a background thread; ECS actor creation is posted back to the
/// main thread via TriggerScan().
/// on a background thread; completion is finalized on the main thread.
struct AssetImporterPanel : ZEngine::UI::ZUIPanelView
{
AssetImporterPanel()
Expand All @@ -25,7 +32,8 @@ namespace Tetragrama::Panels

/// @brief Allocates importers and arenas; must be called once before first use.
/// @param layer Owning ZUI layer (provides arena and app pointers).
void Initialize(Tetragrama::Layers::ZUILayer* layer);
/// @param project_view Content browser refreshed after a successful import.
void Initialize(Tetragrama::Layers::ZUILayer* layer, ProjectViewPanel* project_view);

/// @brief Dispatches to BuildIdle/BuildOptions/BuildImporting based on current state.
/// @param ctx ZUI context for the current frame.
Expand All @@ -34,9 +42,14 @@ namespace Tetragrama::Panels

private:
Tetragrama::Layers::ZUILayer* m_layer = nullptr;
ProjectViewPanel* m_project_view = nullptr;

// Scratch arena for ImportConfiguration strings (cleared before each import)
ZEngine::Core::Memory::ArenaAllocator m_local_arena = {};
// Task results must outlive the worker callback, but must not consume the
// 64 KiB configuration scratch arena. TLSF reuses and reclaims Array growth
// between imports without a per-import arena leak.
ZEngine::Core::Memory::TLSFSlab m_import_result_slab = {};
// Importer-dedicated arenas carved from the engine ImportPipeline budget
ZEngine::Core::Memory::ArenaAllocator m_gltf_importer_arena = {};
ZEngine::Core::Memory::ArenaAllocator m_assimp_importer_arena = {};
Expand All @@ -53,12 +66,26 @@ namespace Tetragrama::Panels
Assimp,
};

enum class ImportTaskOutcome : uint8_t
{
Pending,
Completed,
Failed,
};

struct ImportTask
{
AssetImporterPanel* Panel = nullptr;
ZEngine::Importers::AssetCodec::ImportConfiguration Configuration = {};
ImporterKind Kind = ImporterKind::Gltf;
char SourcePath[MAX_FILE_PATH_COUNT] = {};
AssetImporterPanel* Panel = nullptr;
ZEngine::Importers::AssetCodec::ImportConfiguration Configuration = {};
ImporterKind Kind = ImporterKind::Gltf;
char SourcePath[MAX_FILE_PATH_COUNT] = {};
// The importer releases its scratch arena after it calls its callback.
// Retain the small output list until the main thread consumes it.
std::vector<ZEngine::Importers::AssetImporterOutput> Outputs = {};
ZEngine::Core::Containers::Array<ZEngine::Core::VFS::VFSPath> PublishedPaths = {};
ZEngine::Core::VFS::VFSImportPublication Publication = {};
std::string Error = {};
ImportTaskOutcome Outcome = ImportTaskOutcome::Pending;
};
ImportTask m_import_task = {};

Expand Down Expand Up @@ -87,17 +114,8 @@ namespace Tetragrama::Panels
bool m_same_settings = false;
int m_options_filter = 5; // 0=General 1=Mesh 2=Material 3=Anim 4=LOD 5=All

// Pending ECS actor creation — written on bg thread, consumed on main thread
struct PendingActor
{
uuids::uuid uuid = {};
uint32_t render_id = UINT32_MAX;
char name[128] = {};
bool valid = false;
} m_pending_actor = {};

// Import history ring buffer (Idle state, newest first)
static constexpr int kHistMax = 16;
static constexpr int kHistMax = 16;
struct HistEntry
{
char name[256] = {};
Expand All @@ -117,7 +135,6 @@ namespace Tetragrama::Panels
LogEntry m_log[kLogMax] = {};
int m_log_head = 0;
int m_log_count = 0;
bool m_scroll_log = false;
std::mutex m_log_mutex;

// Build helpers
Expand All @@ -134,25 +151,31 @@ namespace Tetragrama::Panels
std::future<void> BrowseFileAsync();
/// @brief Begin the import process with the current settings.
void StartImport();
/// @brief Trigger a directory scan for importable assets.
void TriggerScan(); // main-thread only
/// @brief Add an imported mesh instance to the ECS scene on the main thread.
void CreateMeshActor(uuids::uuid mesh_uuid, uint32_t render_instance_id, const char* name);
/// @brief Append a log message to the import log.
void PushLog(const char* text, float r, float g, float b);
/// @brief Record the completed import in the history list.
void PushHistory(const char* name, bool ok, const char* msg);

/// @brief Runs one import on a worker through the allocation-free task API.
/// @brief Runs one import on a worker through the C-style task API.
static void RunImportTask(void* context);
/// @brief Consumes a completed worker task on the main thread.
static void FinalizeImportTask(void* context);

// Static callbacks for ImportFile (called from background thread)
/// @brief Callback invoked when the import file step finishes.
// Static callbacks for ImportFile. They execute on a worker, so they only
// copy the result into ImportTask; FinalizeImportTask performs editor work.
static void OnImportFileComplete(void* ctx, ZEngine::Core::Containers::ArrayView<ZEngine::Importers::AssetImporterOutput> outputs);
/// @brief Callback invoked with progress updates during import.
static void OnImportArtifactPublished(void* ctx, ZEngine::Importers::AssetFileType type, const char* path);
static void OnImportProgress(void* ctx, float pct);
/// @brief Callback invoked when an import error occurs.
static void OnImportError(void* ctx, std::string_view err);
/// @brief Callback invoked for each import log message.
static void OnImportLog(void* ctx, std::string_view msg);

// Main-thread-only completion handlers.
static void CompleteImportOnMainThread(void* ctx, ZEngine::Core::Containers::ArrayView<ZEngine::Importers::AssetImporterOutput> outputs);
static void CompleteImportErrorOnMainThread(void* ctx, std::string_view err);
static void RecordPublishedPath(ImportTask& task, const char* path);
static void EndImportPublication(ImportTask& task);
};

} // namespace Tetragrama::Panels
6 changes: 6 additions & 0 deletions Tetragrama/Panels/ProjectViewPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ namespace Tetragrama::Panels
Title = "Project";
}

void ProjectViewPanel::RequestRefresh()
{
m_needs_refresh = true;
m_tree_cache_count = 0;
}

// VFS listing
void ProjectViewPanel::RefreshListing(IVFSContext* vfs)
{
Expand Down
3 changes: 3 additions & 0 deletions Tetragrama/Panels/ProjectViewPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ namespace Tetragrama::Panels
/// @param rect Panel bounding rect [x0, y0, x1, y1].
void BuildContent(ZEngine::UI::ZUIContext* ctx, float rect[4]) override;

/// @brief Invalidates cached listings after a main-thread file operation.
void RequestRefresh();

private:
// Navigation
ZEngine::Core::VFS::VFSPath m_current_dir = {};
Expand Down
8 changes: 3 additions & 5 deletions Tetragrama/Panels/ViewportPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,11 @@ namespace Tetragrama::Panels
ZUISignal img_sig = ZUISignalFromBox(ctx, img);
ZUIPopBox(ctx);

// Feed the viewport rect to the camera controller every frame so it can
// self-gate on cursor position without depending on the ZUI hit-test chain.
// The camera consumes raw GLFW cursor positions, not UI-space positions.
// Convert both the hover bounds and the extent used by camera rays/panning.
if (app->CameraController)
{
app->CameraController->SetViewportRect(rect[0], rect[1], rect[2], rect[3]);
if (sw > 0.0f && sh > 0.0f)
app->CameraController->SetViewport(sw, sh);
app->CameraController->SetViewportFromUI(rect, ctx->InputScale);
}

// Keep ViewportHovered for ZUI-level concerns (drag-drop, scroll routing).
Expand Down
8 changes: 5 additions & 3 deletions Tetragrama/Panels/ZUIPanelManagerComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ namespace Tetragrama::Panels
auto* p_proj = Manager.AddPanel(ZUIDockHashName("Project"));
Manager.AddView(p_proj, &project);

importer.Initialize(parent); // allocate importers from ImportPipeline budget
importer.Initialize(parent, &project); // allocate importers from ImportPipeline budget

// EngineAssetsBackend is rooted at <cwd>/ZodiacEngine (mounted at /ZodiacEngine).
// EngineAssetsBackend is rooted at the packaged ZodiacEngine directory
// beside the executable (mounted at /ZodiacEngine).
// Settings/ is created by the engine build. Verify it exists via the backend,
// then use VFSPath::ResolveNative to produce the correct native path — no
// manual string concatenation. Falls back to the working directory if absent.
// manual string concatenation. A missing settings directory uses the local
// layout filename so the editor can still start with its default layout.
char layout_path[512] = {};
bool settings_ok = false;
auto* eng = ZEngine::Engine::GetContext();
Expand Down
11 changes: 8 additions & 3 deletions Tetragrama/Serializers/EditorSceneSerializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <ZEngine/Helpers/ThreadPool.h>
#include <ZEngine/Importers/AssetCodec.h>
#include <ZEngine/Importers/IAssetImporter.h>
#include <ZEngine/Logging/LoggerDefinition.h>
#include <ZEngine/Managers/AssetManager.h>
#include <ZEngine/Rendering/Scenes/SkyConfigSerialization.h>
#include <fmt/format.h>
Expand Down Expand Up @@ -106,12 +107,16 @@ namespace Tetragrama::Serializers
cook_cfg.VFS = reinterpret_cast<ZEngine::Core::VFS::IVFSContext*>(ZEngine::Engine::GetContext()->VFS);

auto output = ZEngine::Importers::AssetCodec::SerializeMeshAssetFile(scratch.Arena, *mesh, *hierarchy, cook_cfg);
if (!output.Path.empty())
if (output.Succeeded())
{
// Register the artifact path so future saves don't re-cook
ZEngine::Helpers::secure_strncpy(const_cast<ZEngine::Core::VFS::AssetRecord*>(rec)->Meta.ArtifactPath, MAX_FILE_PATH_COUNT, output.Path.c_str(), output.Path.size());
ZEngine::Helpers::secure_strncpy(const_cast<ZEngine::Core::VFS::AssetRecord*>(rec)->Meta.ArtifactPath, MAX_FILE_PATH_COUNT, output.Value().Path.c_str(), output.Value().Path.size());

scene->PushAssetFile(output);
scene->PushAssetFile(output.Value());
}
else
{
ZENGINE_CORE_ERROR("Failed to cook '{}/{}' (VFS error {})", cook_cfg.OutputAssetsPath.c_str(), output_file, static_cast<uint32_t>(output.Error()))
}
}
ZReleaseScratch(scratch);
Expand Down
Loading
Loading