From 7790472dabfa0ecd06f3408d847860ec6072866e Mon Sep 17 00:00:00 2001 From: skal Date: Mon, 9 Feb 2026 18:51:54 +0100 Subject: feat: Implement workspace system (Task #77) Self-contained workspaces for parallel demo development. Structure: - workspaces/main,test - Demo-specific resources - assets/common - Shared resources - workspace.cfg - Configuration per workspace CMake integration: - DEMO_WORKSPACE option (defaults to main) - cmake/ParseWorkspace.cmake - Config parser - Workspace-relative asset/timeline/music paths Migration: - Main demo: demo.seq to workspaces/main/timeline.seq - Test demo: test_demo.seq to workspaces/test/timeline.seq - Common shaders: assets/common/shaders - Workspace shaders: workspaces/*/shaders Build: cmake -B build -DDEMO_WORKSPACE=main cmake -B build_test -DDEMO_WORKSPACE=test All tests passing (36/36). handoff(Claude): Task #77 workspace system complete. Both main and test workspaces build and pass all tests. Co-Authored-By: Claude Sonnet 4.5 --- cmake/ParseWorkspace.cmake | 104 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 cmake/ParseWorkspace.cmake (limited to 'cmake/ParseWorkspace.cmake') diff --git a/cmake/ParseWorkspace.cmake b/cmake/ParseWorkspace.cmake new file mode 100644 index 0000000..da5e416 --- /dev/null +++ b/cmake/ParseWorkspace.cmake @@ -0,0 +1,104 @@ +# cmake/ParseWorkspace.cmake - Workspace configuration parser + +function(parse_workspace_config WORKSPACE_DIR) + set(WORKSPACE_CFG "${WORKSPACE_DIR}/workspace.cfg") + + if(NOT EXISTS ${WORKSPACE_CFG}) + message(FATAL_ERROR "Workspace config not found: ${WORKSPACE_CFG}") + endif() + + # Default values + set(WS_NAME "Unknown") + set(WS_TARGET "demo64k") + set(WS_TIMELINE "timeline.seq") + set(WS_MUSIC "music.track") + set(WS_ASSETS "assets.txt") + set(WS_ASSET_DIRS "") + set(WS_SHADER_DIRS "") + + # Read and parse config file + file(STRINGS ${WORKSPACE_CFG} CONFIG_LINES) + foreach(LINE ${CONFIG_LINES}) + # Skip comments and empty lines + string(STRIP "${LINE}" LINE) + if(LINE MATCHES "^#" OR LINE STREQUAL "" OR LINE MATCHES "^\\[") + continue() + endif() + + # Parse key = value + if(LINE MATCHES "^([^=]+)=(.*)$") + string(STRIP "${CMAKE_MATCH_1}" KEY) + string(STRIP "${CMAKE_MATCH_2}" VALUE) + + # Remove quotes + string(REGEX REPLACE "^\"(.*)\"$" "\\1" VALUE "${VALUE}") + + # Set variables + if(KEY STREQUAL "name") + set(WS_NAME "${VALUE}") + elseif(KEY STREQUAL "target") + set(WS_TARGET "${VALUE}") + elseif(KEY STREQUAL "timeline") + set(WS_TIMELINE "${VALUE}") + elseif(KEY STREQUAL "music") + set(WS_MUSIC "${VALUE}") + elseif(KEY STREQUAL "assets") + set(WS_ASSETS "${VALUE}") + elseif(KEY STREQUAL "asset_dirs") + # Parse array: ["assets/", "../common/"] + string(REGEX REPLACE "\\[|\\]" "" VALUE "${VALUE}") + string(REPLACE "," ";" VALUE "${VALUE}") + set(WS_ASSET_DIRS "") + foreach(DIR ${VALUE}) + string(STRIP "${DIR}" DIR) + string(REGEX REPLACE "^\"(.*)\"$" "\\1" DIR "${DIR}") + list(APPEND WS_ASSET_DIRS "${DIR}") + endforeach() + elseif(KEY STREQUAL "shader_dirs") + # Parse array: ["shaders/", "../common/shaders/"] + string(REGEX REPLACE "\\[|\\]" "" VALUE "${VALUE}") + string(REPLACE "," ";" VALUE "${VALUE}") + set(WS_SHADER_DIRS "") + foreach(DIR ${VALUE}) + string(STRIP "${DIR}" DIR) + string(REGEX REPLACE "^\"(.*)\"$" "\\1" DIR "${DIR}") + list(APPEND WS_SHADER_DIRS "${DIR}") + endforeach() + endif() + endif() + endforeach() + + # Export to parent scope + set(WORKSPACE_NAME "${WS_NAME}" PARENT_SCOPE) + set(WORKSPACE_TARGET "${WS_TARGET}" PARENT_SCOPE) + set(WORKSPACE_TIMELINE "${WORKSPACE_DIR}/${WS_TIMELINE}" PARENT_SCOPE) + set(WORKSPACE_MUSIC "${WORKSPACE_DIR}/${WS_MUSIC}" PARENT_SCOPE) + set(WORKSPACE_ASSETS "${WORKSPACE_DIR}/${WS_ASSETS}" PARENT_SCOPE) + + # Convert relative asset dirs to absolute + set(ABS_ASSET_DIRS "") + foreach(DIR ${WS_ASSET_DIRS}) + if(IS_ABSOLUTE "${DIR}") + list(APPEND ABS_ASSET_DIRS "${DIR}") + else() + list(APPEND ABS_ASSET_DIRS "${WORKSPACE_DIR}/${DIR}") + endif() + endforeach() + set(WORKSPACE_ASSET_DIRS "${ABS_ASSET_DIRS}" PARENT_SCOPE) + + # Convert relative shader dirs to absolute + set(ABS_SHADER_DIRS "") + foreach(DIR ${WS_SHADER_DIRS}) + if(IS_ABSOLUTE "${DIR}") + list(APPEND ABS_SHADER_DIRS "${DIR}") + else() + list(APPEND ABS_SHADER_DIRS "${WORKSPACE_DIR}/${DIR}") + endif() + endforeach() + set(WORKSPACE_SHADER_DIRS "${ABS_SHADER_DIRS}" PARENT_SCOPE) + + message(STATUS "Loaded workspace: ${WS_NAME}") + message(STATUS " Timeline: ${WS_TIMELINE}") + message(STATUS " Music: ${WS_MUSIC}") + message(STATUS " Assets: ${WS_ASSETS}") +endfunction() -- cgit v1.2.3