diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f3fc59..d456b89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,25 +285,27 @@ set(JSON_CONFIG_SOURCES src/services/impl/config/json_config_migration_service.cpp ) +file(GLOB WORKFLOW_GENERIC_STEP_SOURCES CONFIGURE_DEPENDS + src/services/impl/workflow/workflow_generic_steps/*.cpp +) + set(WORKFLOW_SOURCES src/services/impl/workflow/workflow_step_io_resolver.cpp + src/services/impl/workflow/workflow_step_parameter_resolver.cpp src/services/impl/workflow/workflow_step_registry.cpp src/services/impl/workflow/workflow_executor.cpp src/services/impl/workflow/workflow_definition_parser.cpp src/services/impl/workflow/workflow_template_resolver.cpp + src/services/impl/workflow/workflow_camera_view_state_builder.cpp src/services/impl/workflow/workflow_config_pipeline.cpp src/services/impl/workflow/workflow_config_load_step.cpp src/services/impl/workflow/workflow_config_version_step.cpp src/services/impl/workflow/workflow_config_migration_step.cpp src/services/impl/workflow/workflow_config_schema_step.cpp src/services/impl/workflow/workflow_default_step_registrar.cpp - src/services/impl/workflow/workflow_generic_steps/workflow_list_filter_equals_step.cpp - src/services/impl/workflow/workflow_generic_steps/workflow_list_map_add_step.cpp - src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_sum_step.cpp - src/services/impl/workflow/workflow_generic_steps/workflow_number_add_step.cpp + src/services/impl/workflow/workflow_mesh_payload_converter.cpp src/services/impl/workflow/workflow_runtime_config_step.cpp - src/services/impl/workflow/workflow_generic_steps/workflow_value_copy_step.cpp - src/services/impl/workflow/workflow_generic_steps/workflow_value_default_step.cpp + ${WORKFLOW_GENERIC_STEP_SOURCES} ) set(FRAME_WORKFLOW_SOURCES @@ -321,16 +323,16 @@ set(FRAME_WORKFLOW_SOURCES src/services/impl/workflow/workflow_validation_checkpoint_step.cpp src/services/impl/workflow/frame/frame_workflow_step_registrar.cpp src/services/impl/workflow/frame/frame_workflow_service.cpp - src/services/impl/soundboard_state_service.cpp - src/services/impl/soundboard_path_resolver.cpp + src/services/impl/soundboard/soundboard_state_service.cpp + src/services/impl/soundboard/soundboard_path_resolver.cpp ) set(MATERIALX_SCRIPT_SOURCES - src/services/impl/materialx_path_resolver.cpp - src/services/impl/materialx_search_path_builder.cpp - src/services/impl/materialx_document_loader.cpp - src/services/impl/materialx_surface_node_resolver.cpp - src/services/impl/materialx_surface_parameter_reader.cpp + src/services/impl/materialx/materialx_path_resolver.cpp + src/services/impl/materialx/materialx_search_path_builder.cpp + src/services/impl/materialx/materialx_document_loader.cpp + src/services/impl/materialx/materialx_surface_node_resolver.cpp + src/services/impl/materialx/materialx_surface_parameter_reader.cpp ) if(BUILD_SDL3_APP) @@ -344,45 +346,45 @@ if(BUILD_SDL3_APP) ${FRAME_WORKFLOW_SOURCES} ${MATERIALX_SCRIPT_SOURCES} src/services/impl/config/config_compiler_service.cpp - src/services/impl/command_line_service.cpp + src/services/impl/app/command_line_service.cpp src/services/impl/config/json_config_writer_service.cpp - src/services/impl/logger_service.cpp - src/services/impl/ecs_service.cpp - src/services/impl/platform_service.cpp - src/services/impl/probe_service.cpp - src/services/impl/script_engine_service.cpp - src/services/impl/lua_helpers.cpp - src/services/impl/scene_script_service.cpp - src/services/impl/shader_script_service.cpp - src/services/impl/shader_system_registry.cpp - src/services/impl/materialx_shader_system.cpp - src/services/impl/glsl_shader_system.cpp - src/services/impl/materialx_shader_generator.cpp - src/services/impl/shader_pipeline_validator.cpp - src/services/impl/gui_script_service.cpp - $<$>:src/services/impl/bgfx_gui_service.cpp> - $<$>:src/services/impl/bgfx_shader_compiler.cpp> - src/services/impl/audio_command_service.cpp - src/services/impl/physics_bridge_service.cpp - src/services/impl/mesh_service.cpp - src/services/impl/sdl_window_service.cpp - src/services/impl/sdl_input_service.cpp - src/services/impl/sdl_audio_service.cpp - src/services/impl/crash_recovery_service.cpp - src/services/impl/lifecycle_service.cpp - src/services/impl/application_loop_service.cpp - src/services/impl/render_coordinator_service.cpp - src/services/impl/validation_tour_service.cpp - src/services/impl/render_graph_service.cpp - src/services/impl/null_gui_service.cpp - src/services/impl/bgfx_gui_service.cpp - src/services/impl/bgfx_shader_compiler.cpp - src/services/impl/pipeline_compiler_service.cpp - src/services/impl/bullet_physics_service.cpp - src/services/impl/scene_service.cpp - src/services/impl/graphics_service.cpp - $<$>:src/services/impl/bgfx_graphics_backend.cpp> - $<$:src/services/impl/gxm_graphics_backend.cpp> + src/services/impl/diagnostics/logger_service.cpp + src/services/impl/scene/ecs_service.cpp + src/services/impl/platform/platform_service.cpp + src/services/impl/diagnostics/probe_service.cpp + src/services/impl/script/script_engine_service.cpp + src/services/impl/script/lua_helpers.cpp + src/services/impl/script/scene_script_service.cpp + src/services/impl/script/shader_script_service.cpp + src/services/impl/shader/shader_system_registry.cpp + src/services/impl/shader/materialx_shader_system.cpp + src/services/impl/shader/glsl_shader_system.cpp + src/services/impl/materialx/materialx_shader_generator.cpp + src/services/impl/shader/shader_pipeline_validator.cpp + src/services/impl/script/gui_script_service.cpp + $<$>:src/services/impl/gui/bgfx_gui_service.cpp> + $<$>:src/services/impl/graphics/bgfx_shader_compiler.cpp> + src/services/impl/audio/audio_command_service.cpp + src/services/impl/scene/physics_bridge_service.cpp + src/services/impl/scene/mesh_service.cpp + src/services/impl/platform/sdl_window_service.cpp + src/services/impl/input/sdl_input_service.cpp + src/services/impl/audio/sdl_audio_service.cpp + src/services/impl/diagnostics/crash_recovery_service.cpp + src/services/impl/app/lifecycle_service.cpp + src/services/impl/app/application_loop_service.cpp + src/services/impl/render/render_coordinator_service.cpp + src/services/impl/diagnostics/validation_tour_service.cpp + src/services/impl/render/render_graph_service.cpp + src/services/impl/gui/null_gui_service.cpp + src/services/impl/gui/bgfx_gui_service.cpp + src/services/impl/graphics/bgfx_shader_compiler.cpp + src/services/impl/shader/pipeline_compiler_service.cpp + src/services/impl/scene/bullet_physics_service.cpp + src/services/impl/scene/scene_service.cpp + src/services/impl/graphics/graphics_service.cpp + $<$>:src/services/impl/graphics/bgfx_graphics_backend.cpp> + $<$:src/services/impl/graphics/gxm_graphics_backend.cpp> src/app/service_based_app.cpp ) target_include_directories(sdl3_app PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") @@ -461,28 +463,28 @@ enable_testing() if(NOT ENABLE_VITA) add_executable(script_engine_tests tests/test_cube_script.cpp - src/services/impl/bgfx_graphics_backend.cpp - src/services/impl/bgfx_shader_compiler.cpp - src/services/impl/logger_service.cpp - src/services/impl/mesh_service.cpp - src/services/impl/physics_bridge_service.cpp - src/services/impl/platform_service.cpp - src/services/impl/script_engine_service.cpp + src/services/impl/graphics/bgfx_graphics_backend.cpp + src/services/impl/graphics/bgfx_shader_compiler.cpp + src/services/impl/diagnostics/logger_service.cpp + src/services/impl/scene/mesh_service.cpp + src/services/impl/scene/physics_bridge_service.cpp + src/services/impl/platform/platform_service.cpp + src/services/impl/script/script_engine_service.cpp ${MATERIALX_SCRIPT_SOURCES} - src/services/impl/lua_helpers.cpp - src/services/impl/scene_script_service.cpp - src/services/impl/shader_script_service.cpp - src/services/impl/shader_system_registry.cpp - src/services/impl/materialx_shader_system.cpp - src/services/impl/glsl_shader_system.cpp - src/services/impl/materialx_shader_generator.cpp - src/services/impl/shader_pipeline_validator.cpp - src/services/impl/sdl_window_service.cpp - src/services/impl/ecs_service.cpp - src/services/impl/scene_service.cpp + src/services/impl/script/lua_helpers.cpp + src/services/impl/script/scene_script_service.cpp + src/services/impl/script/shader_script_service.cpp + src/services/impl/shader/shader_system_registry.cpp + src/services/impl/shader/materialx_shader_system.cpp + src/services/impl/shader/glsl_shader_system.cpp + src/services/impl/materialx/materialx_shader_generator.cpp + src/services/impl/shader/shader_pipeline_validator.cpp + src/services/impl/platform/sdl_window_service.cpp + src/services/impl/scene/ecs_service.cpp + src/services/impl/scene/scene_service.cpp src/events/event_bus.cpp src/stb_image.cpp - src/services/impl/pipeline_compiler_service.cpp + src/services/impl/shader/pipeline_compiler_service.cpp ) target_include_directories(script_engine_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_include_directories(script_engine_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") @@ -515,11 +517,11 @@ add_test(NAME script_engine_tests COMMAND script_engine_tests) add_executable(bgfx_gui_service_tests tests/test_bgfx_gui_service.cpp - src/services/impl/bgfx_gui_service.cpp - src/services/impl/bgfx_shader_compiler.cpp - src/services/impl/materialx_shader_generator.cpp - src/services/impl/shader_pipeline_validator.cpp - src/services/impl/pipeline_compiler_service.cpp + src/services/impl/gui/bgfx_gui_service.cpp + src/services/impl/graphics/bgfx_shader_compiler.cpp + src/services/impl/materialx/materialx_shader_generator.cpp + src/services/impl/shader/shader_pipeline_validator.cpp + src/services/impl/shader/pipeline_compiler_service.cpp ) target_include_directories(bgfx_gui_service_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_include_directories(bgfx_gui_service_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") @@ -546,11 +548,11 @@ add_test(NAME bgfx_gui_service_tests COMMAND bgfx_gui_service_tests) # Test: GUI budget enforcement (cache pruning) add_executable(bgfx_gui_budget_enforcement_test tests/bgfx_gui_budget_enforcement_test.cpp - src/services/impl/bgfx_gui_service.cpp - src/services/impl/bgfx_shader_compiler.cpp - src/services/impl/materialx_shader_generator.cpp - src/services/impl/shader_pipeline_validator.cpp - src/services/impl/pipeline_compiler_service.cpp + src/services/impl/gui/bgfx_gui_service.cpp + src/services/impl/graphics/bgfx_shader_compiler.cpp + src/services/impl/materialx/materialx_shader_generator.cpp + src/services/impl/shader/shader_pipeline_validator.cpp + src/services/impl/shader/pipeline_compiler_service.cpp ) target_include_directories(bgfx_gui_budget_enforcement_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_include_directories(bgfx_gui_budget_enforcement_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") @@ -578,8 +580,8 @@ add_test(NAME bgfx_gui_budget_enforcement_test COMMAND bgfx_gui_budget_enforceme # Test: Texture budget tracker (allocation + free) add_executable(bgfx_texture_budget_tracker_test tests/bgfx_texture_budget_tracker_test.cpp - src/services/impl/bgfx_graphics_backend.cpp - src/services/impl/bgfx_shader_compiler.cpp + src/services/impl/graphics/bgfx_graphics_backend.cpp + src/services/impl/graphics/bgfx_shader_compiler.cpp src/stb_image.cpp ) target_include_directories(bgfx_texture_budget_tracker_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") @@ -606,18 +608,18 @@ add_test(NAME bgfx_texture_budget_tracker_test COMMAND bgfx_texture_budget_track # Test: Vulkan shader linking (TDD test for walls/ceiling/floor rendering) add_executable(vulkan_shader_linking_test tests/test_vulkan_shader_linking.cpp - src/services/impl/bgfx_graphics_backend.cpp - src/services/impl/bgfx_gui_service.cpp - src/services/impl/bgfx_shader_compiler.cpp + src/services/impl/graphics/bgfx_graphics_backend.cpp + src/services/impl/gui/bgfx_gui_service.cpp + src/services/impl/graphics/bgfx_shader_compiler.cpp ${JSON_CONFIG_SOURCES} ${WORKFLOW_SOURCES} - src/services/impl/materialx_shader_generator.cpp - src/services/impl/shader_pipeline_validator.cpp - src/services/impl/platform_service.cpp - src/services/impl/sdl_window_service.cpp + src/services/impl/materialx/materialx_shader_generator.cpp + src/services/impl/shader/shader_pipeline_validator.cpp + src/services/impl/platform/platform_service.cpp + src/services/impl/platform/sdl_window_service.cpp src/events/event_bus.cpp src/stb_image.cpp - src/services/impl/pipeline_compiler_service.cpp + src/services/impl/shader/pipeline_compiler_service.cpp ) target_include_directories(vulkan_shader_linking_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_include_directories(vulkan_shader_linking_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") @@ -644,7 +646,7 @@ add_test(NAME vulkan_shader_linking_test COMMAND vulkan_shader_linking_test) # Test: Shader Pipeline Validator (mega-strict validation system) add_executable(shader_pipeline_validator_test tests/shader_pipeline_validator_test.cpp - src/services/impl/shader_pipeline_validator.cpp + src/services/impl/shader/shader_pipeline_validator.cpp ) target_include_directories(shader_pipeline_validator_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_link_libraries(shader_pipeline_validator_test PRIVATE @@ -670,8 +672,8 @@ add_test(NAME shaderc_uniform_mapping_test COMMAND shaderc_uniform_mapping_test) # Test: MaterialX Shader Generator Integration (validates shader generation + validation together) add_executable(materialx_shader_generator_integration_test tests/materialx_shader_generator_integration_test.cpp - src/services/impl/materialx_shader_generator.cpp - src/services/impl/shader_pipeline_validator.cpp + src/services/impl/materialx/materialx_shader_generator.cpp + src/services/impl/shader/shader_pipeline_validator.cpp ) target_include_directories(materialx_shader_generator_integration_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_link_libraries(materialx_shader_generator_integration_test PRIVATE @@ -719,7 +721,7 @@ add_test(NAME bgfx_frame_requirement_test COMMAND bgfx_frame_requirement_test) # Test: Render coordinator initialization order (TDD guard for shader load timing) add_executable(render_coordinator_init_order_test tests/render_coordinator_init_order_test.cpp - src/services/impl/render_coordinator_service.cpp + src/services/impl/render/render_coordinator_service.cpp ) target_include_directories(render_coordinator_init_order_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_link_libraries(render_coordinator_init_order_test PRIVATE @@ -731,8 +733,8 @@ add_test(NAME render_coordinator_init_order_test COMMAND render_coordinator_init # Test: Bgfx backend frame guard (ensures texture loads are blocked before first frame) add_executable(bgfx_backend_frame_guard_test tests/bgfx_backend_frame_guard_test.cpp - src/services/impl/bgfx_graphics_backend.cpp - src/services/impl/bgfx_shader_compiler.cpp + src/services/impl/graphics/bgfx_graphics_backend.cpp + src/services/impl/graphics/bgfx_shader_compiler.cpp src/stb_image.cpp ) target_include_directories(bgfx_backend_frame_guard_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") @@ -759,8 +761,8 @@ add_test(NAME bgfx_backend_frame_guard_test COMMAND bgfx_backend_frame_guard_tes # Test: Gui script service missing fields (logs trace and uses defaults) add_executable(gui_script_service_missing_fields_test tests/gui_script_service_missing_fields_test.cpp - src/services/impl/gui_script_service.cpp - src/services/impl/lua_helpers.cpp + src/services/impl/script/gui_script_service.cpp + src/services/impl/script/lua_helpers.cpp ) target_include_directories(gui_script_service_missing_fields_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_link_libraries(gui_script_service_missing_fields_test PRIVATE @@ -774,7 +776,7 @@ add_test(NAME gui_script_service_missing_fields_test COMMAND gui_script_service_ # Test: Graphics service buffer lifecycle (TDD guard for VRAM leaks on reupload) add_executable(graphics_service_buffer_lifecycle_test tests/graphics_service_buffer_lifecycle_test.cpp - src/services/impl/graphics_service.cpp + src/services/impl/graphics/graphics_service.cpp ) target_include_directories(graphics_service_buffer_lifecycle_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_link_libraries(graphics_service_buffer_lifecycle_test PRIVATE @@ -786,7 +788,7 @@ add_test(NAME graphics_service_buffer_lifecycle_test COMMAND graphics_service_bu # Test: Render graph validation (cycles + unknown dependencies) add_executable(render_graph_service_test tests/render_graph_service_test.cpp - src/services/impl/render_graph_service.cpp + src/services/impl/render/render_graph_service.cpp ) target_include_directories(render_graph_service_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_link_libraries(render_graph_service_test PRIVATE @@ -854,11 +856,11 @@ add_test(NAME config_compiler_reference_validation_test COMMAND config_compiler_ add_executable(shader_system_registry_test tests/shader_system_registry_test.cpp src/services/impl/config/config_compiler_service.cpp - src/services/impl/shader_system_registry.cpp - src/services/impl/glsl_shader_system.cpp - src/services/impl/materialx_shader_system.cpp - src/services/impl/materialx_shader_generator.cpp - src/services/impl/shader_pipeline_validator.cpp + src/services/impl/shader/shader_system_registry.cpp + src/services/impl/shader/glsl_shader_system.cpp + src/services/impl/shader/materialx_shader_system.cpp + src/services/impl/materialx/materialx_shader_generator.cpp + src/services/impl/shader/shader_pipeline_validator.cpp ) target_include_directories(shader_system_registry_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_include_directories(shader_system_registry_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") @@ -895,7 +897,7 @@ add_test(NAME gui_shader_linking_failure_test COMMAND gui_shader_linking_failure # Test: Crash recovery timeout (TDD test for main loop hang after timeout) add_executable(crash_recovery_timeout_test tests/crash_recovery_timeout_test.cpp - src/services/impl/crash_recovery_service.cpp + src/services/impl/diagnostics/crash_recovery_service.cpp ) target_include_directories(crash_recovery_timeout_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_link_libraries(crash_recovery_timeout_test PRIVATE @@ -972,7 +974,7 @@ endif() if(ENABLE_VITA) add_executable(gxm_backend_tests tests/test_gxm_backend.cpp - src/services/impl/gxm_graphics_backend.cpp + src/services/impl/graphics/gxm_graphics_backend.cpp ) target_include_directories(gxm_backend_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") target_link_libraries(gxm_backend_tests PRIVATE diff --git a/ROADMAP.md b/ROADMAP.md index f1af068..227364b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -24,6 +24,7 @@ Treat JSON config as a declarative control plane that compiles into scene, resou - Schema now covers assets/materials/shaders, `shader_systems`, and render-pass `view_id` + `clear` metadata. - Runtime rendering is still Lua-driven, with MaterialX shader generation, pipeline validation, sampler caps, and texture/GUI cache budget enforcement. - Diagnostics include ProbeService reports plus CrashRecoveryService heartbeats/GPU hang detection; runtime probe hooks (draw/present/frame) are still missing. +- Package workflows still include stub placeholders in `packages/*/workflows/stubs`, so `scripts/package_lint.py` currently fails. ## Launch Packages (Cheesy Edition) @@ -65,6 +66,7 @@ Treat JSON config as a declarative control plane that compiles into scene, resou - Enforce shader uniform compatibility using reflection + material metadata. - Validate soundboard workflow steps (catalog/GUI/audio) in runtime and retire the Lua soundboard UI path. - Port Lua demos (seed/gui/soundboard/quake3) into JSON-first packages and workflows. +- Replace all workflow stubs in `packages/*/workflows/stubs` with fully implemented n8n JSON graphs derived from the existing Lua scripts + JSON configs (no placeholders). - Add tests for schema/merge rules, render graph validation, and budget enforcement. - Start service refactor program for large modules (approaching 2K LOC). - Remove the Lua-first execution path once config-first workflows (boot, frame, gameplay) can fully describe the engine; workflows should be able to teleport the camera to key spots, render expected visuals, and fail fast when actual output deviates from the JSON-specified state (no Lua required unless explicitly chosen). @@ -171,9 +173,10 @@ Treat JSON config as a declarative control plane that compiles into scene, resou - MaterialXShaderGenerator (~1100 LOC): split MaterialX graph prep, shader emit, validation. ### Phase A: Mechanical Extraction (1-3 days) -- [~] JsonConfigService: extracted config document load/merge helpers into `src/services/impl/json_config_document_loader.cpp` plus small parser/extend/merge services to keep files <100 LOC. +- [~] JsonConfigService: extracted config document load/merge helpers into `src/services/impl/config/json_config_document_loader.cpp` plus small parser/extend/merge services to keep files <100 LOC. - [~] JsonConfigService: split schema validation/versioning/migration into `json_config_*` services (`schema_validator`, `version_validator`, `migration_service`). - [~] ScriptEngineService: extracted MaterialX helpers into micro services (`materialx_path_resolver`, `materialx_search_path_builder`, `materialx_document_loader`, `materialx_surface_node_resolver`, `materialx_surface_parameter_reader`). +- [x] Reorganized `src/services/impl` into domain subfolders (app/audio/config/diagnostics/graphics/gui/input/materialx/platform/render/scene/script/shader/soundboard/workflow) to align with workflow boundaries and DI. - Move self-contained helpers into `*_helpers.cpp` with clear headers. - Extract pure data transforms into free functions with unit tests. - Preserve public interfaces; no behavior change in this phase. @@ -258,18 +261,27 @@ Option B: per-shader only - [x] Boot config workflow execution (load/version/migrate/schema + runtime config build). - [x] Workflow schema: `config/schema/workflow_v1.schema.json` supports n8n nodes + connections. - [x] Templates: `config/workflows/templates/boot_default.json`, `config/workflows/templates/frame_default.json`. -- [x] Package workflows converted to n8n nodes (`seed`, `gui`, `soundboard`, `quake3`, `engine_tester`). +- [~] Package workflows converted to n8n nodes (`seed`, `gui`, `soundboard`, `quake3`, `engine_tester`); stub placeholders still present and must be replaced. - [x] Workflow steps implemented: `frame.bullet_physics`, `frame.camera`, `validation.tour.checkpoint`, `soundboard.catalog.scan`, `soundboard.gui`, `soundboard.audio`. - [x] Render coordinator supports workflow-supplied GUI command overrides (bypass Lua GUI path). -- [~] Generic step library started (`value.copy`, `value.default`, `number.add`, `list.filter.equals`, `list.map.add`, `list.reduce.sum`). +- [x] Generic step library implemented (core data ops + camera/audio/scene/model coverage). + +### Generic Step Catalog (Implemented) +- Value: `value.copy`, `value.default`, `value.literal`, `value.clear`, `value.assert.exists`, `value.assert.type`. +- Number: `number.add`, `number.sub`, `number.mul`, `number.div`, `number.min`, `number.max`, `number.clamp`, `number.abs`, `number.round`. +- Compare: `compare.eq`, `compare.ne`, `compare.gt`, `compare.gte`, `compare.lt`, `compare.lte`. +- Bool: `bool.and`, `bool.or`, `bool.not`. +- String: `string.concat`, `string.trim`, `string.lower`, `string.upper`, `string.replace`, `string.contains`, `string.equals`, `string.split`, `string.join`. +- List: `list.literal`, `list.append`, `list.concat`, `list.filter.equals`, `list.filter.gt`, `list.map.add`, `list.map.mul`, `list.reduce.sum`, `list.reduce.min`, `list.reduce.max`, `list.count`. +- Camera: `camera.set_pose`, `camera.look_at`, `camera.teleport`, `camera.set_fov`, `camera.build_view_state`. +- Audio: `audio.play`, `audio.stop`, `audio.set_volume`. +- Mesh/Model/Scene: `mesh.load`, `model.spawn`, `model.despawn`, `model.set_transform`, `scene.load`, `scene.clear`, `scene.set_active`. ### Next Steps - [ ] Publish gameplay workflow templates (FPS/passive camera variants, bullet physics, validation/teleport checks). - [ ] Expand JSON-driven GUI steps beyond soundboard (replace Lua GUI scripts in demo packages). -- [ ] Build out generic "software building blocks" step coverage (strings, math, comparisons, branching, fan-out, list transforms). -- [ ] Add generic game workflow steps (camera controls, teleport/waypoints, audio cues, model spawn/despawn, animation toggles). - [ ] Publish a workflow step catalog with example JSON snippets for each generic step. -- [ ] Add workflow step analytics (probe events with JSON path + node id). +- [ ] Add workflow step analytics (probe events with JSON path + node id + per-step timing/counters). ## Feature Matrix (What You Get, When You Get It) @@ -295,15 +307,15 @@ Option B: per-shader only ## Deliverables Checklist - [x] `config/schema/` with versioned JSON Schema and migration notes - [x] n8n workflow schema + parser support (nodes + connections) -- [x] n8n templates + package workflow conversion +- [~] n8n templates + package workflow conversion (templates shipped; package workflows still contain stubs) - [x] Workflow step plugins for camera + validation checkpoints + bullet physics + soundboard catalog/GUI/audio -- [x] `src/services/impl/config_compiler_service.*` for JSON -> IR compilation -- [x] `src/services/impl/render_graph_service.*` for graph build and scheduling +- [x] `src/services/impl/config/config_compiler_service.*` for JSON -> IR compilation +- [x] `src/services/impl/render/render_graph_service.*` for graph build and scheduling - [x] `src/services/interfaces/i_probe_service.hpp` plus report/event types -- [x] `src/services/impl/probe_service.*` for logging/queueing probe reports +- [x] `src/services/impl/diagnostics/probe_service.*` for logging/queueing probe reports - [x] `src/services/interfaces/config_ir_types.hpp` for typed IR payloads -- [x] `src/services/impl/shader_pipeline_validator.*` for mesh/shader compatibility checks -- [x] `src/services/impl/crash_recovery_service.*` for heartbeat + hang detection +- [x] `src/services/impl/shader/shader_pipeline_validator.*` for mesh/shader compatibility checks +- [x] `src/services/impl/diagnostics/crash_recovery_service.*` for heartbeat + hang detection - [~] Budget enforcement with clear failure modes and fallback resources (textures + GUI caches today) - [ ] Cube demo config-only boot path @@ -367,11 +379,11 @@ Option B: per-shader only - Ensure bgfx is initialized and has seen a frame before loading textures/shaders. ### Known Hotspots To Inspect -- Shader pipeline validation: `src/services/impl/shader_pipeline_validator.cpp` -- Texture load guards + budgets: `src/services/impl/bgfx_graphics_backend.cpp` -- Render graph scheduling: `src/services/impl/render_graph_service.cpp` -- Config compiler diagnostics: `src/services/impl/config_compiler_service.cpp` -- Crash recovery timeouts: `src/services/impl/crash_recovery_service.cpp` +- Shader pipeline validation: `src/services/impl/shader/shader_pipeline_validator.cpp` +- Texture load guards + budgets: `src/services/impl/graphics/bgfx_graphics_backend.cpp` +- Render graph scheduling: `src/services/impl/render/render_graph_service.cpp` +- Config compiler diagnostics: `src/services/impl/config/config_compiler_service.cpp` +- Crash recovery timeouts: `src/services/impl/diagnostics/crash_recovery_service.cpp` ### Ordering Checklist (When Things Crash) - `InitializeDevice` → `InitializeSwapchain` → `BeginFrame` → `EndFrame` before loading shaders/textures. diff --git a/docs/N8N_WORKFLOWS.md b/docs/N8N_WORKFLOWS.md index eebcd82..04f101d 100644 --- a/docs/N8N_WORKFLOWS.md +++ b/docs/N8N_WORKFLOWS.md @@ -31,11 +31,5 @@ Templates - `config/workflows/templates/n8n_skeleton.json` is a minimal starting point. Generic Steps -- Implementations live in `src/services/impl/workflow_generic_steps/`. -- Current generic plugins: - - `value.copy` (inputs: `value`, outputs: `value`) - - `value.default` (inputs: `primary`, `fallback`, outputs: `value`) - - `number.add` (inputs: `left`, `right`, outputs: `value`) - - `list.filter.equals` (inputs: `list`, `value`, outputs: `list`) - - `list.map.add` (inputs: `list`, `value`, outputs: `list`) - - `list.reduce.sum` (inputs: `list`, outputs: `value`) +- Implementations live in `src/services/impl/workflow/workflow_generic_steps/`. +- Full catalog lives in `ROADMAP.md` under "Generic Step Catalog (Implemented)". diff --git a/src/app/service_based_app.cpp b/src/app/service_based_app.cpp index 91137aa..933d656 100644 --- a/src/app/service_based_app.cpp +++ b/src/app/service_based_app.cpp @@ -7,37 +7,37 @@ #include "services/interfaces/i_lifecycle_service.hpp" #include "services/impl/config/json_config_service.hpp" #include "services/impl/config/config_compiler_service.hpp" -#include "services/impl/lifecycle_service.hpp" -#include "services/impl/application_loop_service.hpp" -#include "services/impl/render_coordinator_service.hpp" -#include "services/impl/render_graph_service.hpp" -#include "services/impl/platform_service.hpp" -#include "services/impl/probe_service.hpp" -#include "services/impl/sdl_window_service.hpp" -#include "services/impl/sdl_input_service.hpp" -#include "services/impl/ecs_service.hpp" -#include "services/impl/graphics_service.hpp" -#include "services/impl/bgfx_graphics_backend.hpp" -#include "services/impl/script_engine_service.hpp" -#include "services/impl/scene_script_service.hpp" -#include "services/impl/shader_script_service.hpp" -#include "services/impl/shader_system_registry.hpp" -#include "services/impl/gui_script_service.hpp" -#include "services/impl/audio_command_service.hpp" -#include "services/impl/physics_bridge_service.hpp" -#include "services/impl/mesh_service.hpp" -#include "services/impl/scene_service.hpp" -#include "services/impl/sdl_audio_service.hpp" -#include "services/impl/null_gui_service.hpp" +#include "services/impl/app/lifecycle_service.hpp" +#include "services/impl/app/application_loop_service.hpp" +#include "services/impl/render/render_coordinator_service.hpp" +#include "services/impl/render/render_graph_service.hpp" +#include "services/impl/platform/platform_service.hpp" +#include "services/impl/diagnostics/probe_service.hpp" +#include "services/impl/platform/sdl_window_service.hpp" +#include "services/impl/input/sdl_input_service.hpp" +#include "services/impl/scene/ecs_service.hpp" +#include "services/impl/graphics/graphics_service.hpp" +#include "services/impl/graphics/bgfx_graphics_backend.hpp" +#include "services/impl/script/script_engine_service.hpp" +#include "services/impl/script/scene_script_service.hpp" +#include "services/impl/script/shader_script_service.hpp" +#include "services/impl/shader/shader_system_registry.hpp" +#include "services/impl/script/gui_script_service.hpp" +#include "services/impl/audio/audio_command_service.hpp" +#include "services/impl/scene/physics_bridge_service.hpp" +#include "services/impl/scene/mesh_service.hpp" +#include "services/impl/scene/scene_service.hpp" +#include "services/impl/audio/sdl_audio_service.hpp" +#include "services/impl/gui/null_gui_service.hpp" #if !defined(SDL3CPP_ENABLE_VITA) -#include "services/impl/bgfx_gui_service.hpp" +#include "services/impl/gui/bgfx_gui_service.hpp" #endif -#include "services/impl/bullet_physics_service.hpp" -#include "services/impl/crash_recovery_service.hpp" -#include "services/impl/logger_service.hpp" -#include "services/impl/pipeline_compiler_service.hpp" -#include "services/impl/validation_tour_service.hpp" -#include "services/impl/soundboard_state_service.hpp" +#include "services/impl/scene/bullet_physics_service.hpp" +#include "services/impl/diagnostics/crash_recovery_service.hpp" +#include "services/impl/diagnostics/logger_service.hpp" +#include "services/impl/shader/pipeline_compiler_service.hpp" +#include "services/impl/diagnostics/validation_tour_service.hpp" +#include "services/impl/soundboard/soundboard_state_service.hpp" #include "services/impl/workflow/workflow_default_step_registrar.hpp" #include "services/impl/workflow/workflow_definition_parser.hpp" #include "services/impl/workflow/workflow_executor.hpp" @@ -309,11 +309,16 @@ void ServiceBasedApp::RegisterServices() { registry_.RegisterService( registry_.GetService()); + registry_.RegisterService( + registry_.GetService(), + registry_.GetService()); + registry_.RegisterService( registry_.GetService(), registry_.GetService(), registry_.GetService(), registry_.GetService(), + registry_.GetService(), registry_.GetService(), registry_.GetService(), registry_.GetService(), @@ -321,9 +326,6 @@ void ServiceBasedApp::RegisterServices() { registry_.GetService()); // Script bridge services - registry_.RegisterService( - registry_.GetService(), - registry_.GetService()); registry_.RegisterService( registry_.GetService()); registry_.RegisterService( diff --git a/src/main.cpp b/src/main.cpp index 240f8ae..150b2f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,10 +12,10 @@ #include #include "app/service_based_app.hpp" -#include "services/impl/command_line_service.hpp" -#include "services/impl/json_config_writer_service.hpp" -#include "services/impl/logger_service.hpp" -#include "services/impl/platform_service.hpp" +#include "services/impl/app/command_line_service.hpp" +#include "services/impl/config/json_config_writer_service.hpp" +#include "services/impl/diagnostics/logger_service.hpp" +#include "services/impl/platform/platform_service.hpp" #include "services/interfaces/i_logger.hpp" namespace sdl3cpp::app { diff --git a/src/services/impl/application_loop_service.cpp b/src/services/impl/app/application_loop_service.cpp similarity index 100% rename from src/services/impl/application_loop_service.cpp rename to src/services/impl/app/application_loop_service.cpp diff --git a/src/services/impl/application_loop_service.hpp b/src/services/impl/app/application_loop_service.hpp similarity index 75% rename from src/services/impl/application_loop_service.hpp rename to src/services/impl/app/application_loop_service.hpp index 85cd6d8..0a8913d 100644 --- a/src/services/impl/application_loop_service.hpp +++ b/src/services/impl/app/application_loop_service.hpp @@ -1,16 +1,16 @@ #pragma once -#include "../interfaces/i_application_loop_service.hpp" -#include "../interfaces/i_frame_workflow_service.hpp" -#include "../interfaces/i_audio_service.hpp" -#include "../interfaces/i_crash_recovery_service.hpp" -#include "../interfaces/i_input_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_physics_service.hpp" -#include "../interfaces/i_render_coordinator_service.hpp" -#include "../interfaces/i_scene_service.hpp" -#include "../interfaces/i_window_service.hpp" -#include "../../events/i_event_bus.hpp" +#include "services/interfaces/i_application_loop_service.hpp" +#include "services/interfaces/i_frame_workflow_service.hpp" +#include "services/interfaces/i_audio_service.hpp" +#include "services/interfaces/i_crash_recovery_service.hpp" +#include "services/interfaces/i_input_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_physics_service.hpp" +#include "services/interfaces/i_render_coordinator_service.hpp" +#include "services/interfaces/i_scene_service.hpp" +#include "services/interfaces/i_window_service.hpp" +#include "../../../events/i_event_bus.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/command_line_service.cpp b/src/services/impl/app/command_line_service.cpp similarity index 99% rename from src/services/impl/command_line_service.cpp rename to src/services/impl/app/command_line_service.cpp index 3146b97..b503532 100644 --- a/src/services/impl/command_line_service.cpp +++ b/src/services/impl/app/command_line_service.cpp @@ -1,6 +1,6 @@ #include "command_line_service.hpp" -#include "config/json_config_service.hpp" +#include "../config/json_config_service.hpp" #include #include diff --git a/src/services/impl/command_line_service.hpp b/src/services/impl/app/command_line_service.hpp similarity index 83% rename from src/services/impl/command_line_service.hpp rename to src/services/impl/app/command_line_service.hpp index 4b21cc7..20701f4 100644 --- a/src/services/impl/command_line_service.hpp +++ b/src/services/impl/app/command_line_service.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/i_command_line_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_platform_service.hpp" +#include "services/interfaces/i_command_line_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_platform_service.hpp" #include #include #include diff --git a/src/services/impl/lifecycle_service.cpp b/src/services/impl/app/lifecycle_service.cpp similarity index 100% rename from src/services/impl/lifecycle_service.cpp rename to src/services/impl/app/lifecycle_service.cpp diff --git a/src/services/impl/lifecycle_service.hpp b/src/services/impl/app/lifecycle_service.hpp similarity index 76% rename from src/services/impl/lifecycle_service.hpp rename to src/services/impl/app/lifecycle_service.hpp index 977cbf0..02db9ec 100644 --- a/src/services/impl/lifecycle_service.hpp +++ b/src/services/impl/app/lifecycle_service.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/i_lifecycle_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../../di/service_registry.hpp" +#include "services/interfaces/i_lifecycle_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "../../../di/service_registry.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/audio_command_service.cpp b/src/services/impl/audio/audio_command_service.cpp similarity index 100% rename from src/services/impl/audio_command_service.cpp rename to src/services/impl/audio/audio_command_service.cpp diff --git a/src/services/impl/audio_command_service.hpp b/src/services/impl/audio/audio_command_service.hpp similarity index 80% rename from src/services/impl/audio_command_service.hpp rename to src/services/impl/audio/audio_command_service.hpp index 61cb0d4..32b5d20 100644 --- a/src/services/impl/audio_command_service.hpp +++ b/src/services/impl/audio/audio_command_service.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../interfaces/i_audio_command_service.hpp" -#include "../interfaces/i_audio_service.hpp" -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_audio_command_service.hpp" +#include "services/interfaces/i_audio_service.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_logger.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/sdl_audio_service.cpp b/src/services/impl/audio/sdl_audio_service.cpp similarity index 100% rename from src/services/impl/sdl_audio_service.cpp rename to src/services/impl/audio/sdl_audio_service.cpp diff --git a/src/services/impl/sdl_audio_service.hpp b/src/services/impl/audio/sdl_audio_service.hpp similarity index 94% rename from src/services/impl/sdl_audio_service.hpp rename to src/services/impl/audio/sdl_audio_service.hpp index 736d28a..3b17e9c 100644 --- a/src/services/impl/sdl_audio_service.hpp +++ b/src/services/impl/audio/sdl_audio_service.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/i_audio_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../../di/lifecycle.hpp" +#include "services/interfaces/i_audio_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "../../../di/lifecycle.hpp" #include #include #include diff --git a/src/services/impl/config/config_compiler_service.hpp b/src/services/impl/config/config_compiler_service.hpp index 27b37d0..4a20605 100644 --- a/src/services/impl/config/config_compiler_service.hpp +++ b/src/services/impl/config/config_compiler_service.hpp @@ -5,7 +5,7 @@ #include "services/interfaces/i_logger.hpp" #include "services/interfaces/i_probe_service.hpp" #include "services/interfaces/i_render_graph_service.hpp" -#include "../../di/lifecycle.hpp" +#include "../../../di/lifecycle.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/crash_recovery_service.cpp b/src/services/impl/diagnostics/crash_recovery_service.cpp similarity index 100% rename from src/services/impl/crash_recovery_service.cpp rename to src/services/impl/diagnostics/crash_recovery_service.cpp diff --git a/src/services/impl/crash_recovery_service.hpp b/src/services/impl/diagnostics/crash_recovery_service.hpp similarity index 95% rename from src/services/impl/crash_recovery_service.hpp rename to src/services/impl/diagnostics/crash_recovery_service.hpp index 077af23..4f83fd6 100644 --- a/src/services/impl/crash_recovery_service.hpp +++ b/src/services/impl/diagnostics/crash_recovery_service.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/config_types.hpp" -#include "../interfaces/i_crash_recovery_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/config_types.hpp" +#include "services/interfaces/i_crash_recovery_service.hpp" +#include "services/interfaces/i_logger.hpp" #include #include #include diff --git a/src/services/impl/logger_service.cpp b/src/services/impl/diagnostics/logger_service.cpp similarity index 100% rename from src/services/impl/logger_service.cpp rename to src/services/impl/diagnostics/logger_service.cpp diff --git a/src/services/impl/logger_service.hpp b/src/services/impl/diagnostics/logger_service.hpp similarity index 99% rename from src/services/impl/logger_service.hpp rename to src/services/impl/diagnostics/logger_service.hpp index c305c52..8a31df8 100644 --- a/src/services/impl/logger_service.hpp +++ b/src/services/impl/diagnostics/logger_service.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_logger.hpp" #include #include #include diff --git a/src/services/impl/probe_service.cpp b/src/services/impl/diagnostics/probe_service.cpp similarity index 100% rename from src/services/impl/probe_service.cpp rename to src/services/impl/diagnostics/probe_service.cpp diff --git a/src/services/impl/probe_service.hpp b/src/services/impl/diagnostics/probe_service.hpp similarity index 86% rename from src/services/impl/probe_service.hpp rename to src/services/impl/diagnostics/probe_service.hpp index 589958c..47819f1 100644 --- a/src/services/impl/probe_service.hpp +++ b/src/services/impl/diagnostics/probe_service.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../interfaces/i_probe_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_probe_service.hpp" +#include "services/interfaces/i_logger.hpp" #include #include diff --git a/src/services/impl/validation_tour_service.cpp b/src/services/impl/diagnostics/validation_tour_service.cpp similarity index 99% rename from src/services/impl/validation_tour_service.cpp rename to src/services/impl/diagnostics/validation_tour_service.cpp index 46cb206..160b01b 100644 --- a/src/services/impl/validation_tour_service.cpp +++ b/src/services/impl/diagnostics/validation_tour_service.cpp @@ -1,6 +1,6 @@ #include "validation_tour_service.hpp" -#include "../interfaces/probe_types.hpp" +#include "services/interfaces/probe_types.hpp" #include #include #include diff --git a/src/services/impl/validation_tour_service.hpp b/src/services/impl/diagnostics/validation_tour_service.hpp similarity index 91% rename from src/services/impl/validation_tour_service.hpp rename to src/services/impl/diagnostics/validation_tour_service.hpp index 8763685..4a36c76 100644 --- a/src/services/impl/validation_tour_service.hpp +++ b/src/services/impl/diagnostics/validation_tour_service.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_probe_service.hpp" -#include "../interfaces/i_validation_tour_service.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_probe_service.hpp" +#include "services/interfaces/i_validation_tour_service.hpp" #include #include #include diff --git a/src/services/impl/bgfx_graphics_backend.cpp b/src/services/impl/graphics/bgfx_graphics_backend.cpp similarity index 99% rename from src/services/impl/bgfx_graphics_backend.cpp rename to src/services/impl/graphics/bgfx_graphics_backend.cpp index e09649c..004132d 100644 --- a/src/services/impl/bgfx_graphics_backend.cpp +++ b/src/services/impl/graphics/bgfx_graphics_backend.cpp @@ -1,6 +1,6 @@ #include "bgfx_graphics_backend.hpp" #include "bgfx_shader_compiler.hpp" -#include "../interfaces/i_pipeline_compiler_service.hpp" +#include "services/interfaces/i_pipeline_compiler_service.hpp" #include #include diff --git a/src/services/impl/bgfx_graphics_backend.hpp b/src/services/impl/graphics/bgfx_graphics_backend.hpp similarity index 96% rename from src/services/impl/bgfx_graphics_backend.hpp rename to src/services/impl/graphics/bgfx_graphics_backend.hpp index 5f84017..5d64269 100644 --- a/src/services/impl/bgfx_graphics_backend.hpp +++ b/src/services/impl/graphics/bgfx_graphics_backend.hpp @@ -1,12 +1,12 @@ #pragma once -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_graphics_backend.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_platform_service.hpp" -#include "../interfaces/i_pipeline_compiler_service.hpp" -#include "../interfaces/i_probe_service.hpp" -#include "../../core/vertex.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_graphics_backend.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_platform_service.hpp" +#include "services/interfaces/i_pipeline_compiler_service.hpp" +#include "services/interfaces/i_probe_service.hpp" +#include "../../../core/vertex.hpp" #include #include #include diff --git a/src/services/impl/bgfx_shader_compiler.cpp b/src/services/impl/graphics/bgfx_shader_compiler.cpp similarity index 100% rename from src/services/impl/bgfx_shader_compiler.cpp rename to src/services/impl/graphics/bgfx_shader_compiler.cpp diff --git a/src/services/impl/bgfx_shader_compiler.hpp b/src/services/impl/graphics/bgfx_shader_compiler.hpp similarity index 95% rename from src/services/impl/bgfx_shader_compiler.hpp rename to src/services/impl/graphics/bgfx_shader_compiler.hpp index 944f7b4..f24326f 100644 --- a/src/services/impl/bgfx_shader_compiler.hpp +++ b/src/services/impl/graphics/bgfx_shader_compiler.hpp @@ -1,11 +1,11 @@ #pragma once -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_logger.hpp" #include #include #include #include -#include "../interfaces/i_pipeline_compiler_service.hpp" +#include "services/interfaces/i_pipeline_compiler_service.hpp" namespace sdl3cpp::services::impl { diff --git a/src/services/impl/graphics_service.cpp b/src/services/impl/graphics/graphics_service.cpp similarity index 99% rename from src/services/impl/graphics_service.cpp rename to src/services/impl/graphics/graphics_service.cpp index bd27d22..d90cf0e 100644 --- a/src/services/impl/graphics_service.cpp +++ b/src/services/impl/graphics/graphics_service.cpp @@ -1,6 +1,6 @@ #include "graphics_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/graphics_types.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/graphics_types.hpp" #include #include diff --git a/src/services/impl/graphics_service.hpp b/src/services/impl/graphics/graphics_service.hpp similarity index 92% rename from src/services/impl/graphics_service.hpp rename to src/services/impl/graphics/graphics_service.hpp index 6acebfb..d10785c 100644 --- a/src/services/impl/graphics_service.hpp +++ b/src/services/impl/graphics/graphics_service.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../interfaces/i_graphics_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_window_service.hpp" -#include "../../di/lifecycle.hpp" +#include "services/interfaces/i_graphics_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_window_service.hpp" +#include "../../../di/lifecycle.hpp" #include #include diff --git a/src/services/impl/gxm_graphics_backend.cpp b/src/services/impl/graphics/gxm_graphics_backend.cpp similarity index 99% rename from src/services/impl/gxm_graphics_backend.cpp rename to src/services/impl/graphics/gxm_graphics_backend.cpp index b5bab63..c7a8c34 100644 --- a/src/services/impl/gxm_graphics_backend.cpp +++ b/src/services/impl/graphics/gxm_graphics_backend.cpp @@ -1,5 +1,5 @@ #include "gxm_graphics_backend.hpp" -#include "../../core/vertex.hpp" +#include "../../../core/vertex.hpp" #include #include #include diff --git a/src/services/impl/gxm_graphics_backend.hpp b/src/services/impl/graphics/gxm_graphics_backend.hpp similarity index 98% rename from src/services/impl/gxm_graphics_backend.hpp rename to src/services/impl/graphics/gxm_graphics_backend.hpp index da2a4d8..17dbddf 100644 --- a/src/services/impl/gxm_graphics_backend.hpp +++ b/src/services/impl/graphics/gxm_graphics_backend.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../interfaces/i_graphics_backend.hpp" +#include "services/interfaces/i_graphics_backend.hpp" #include #include #include diff --git a/src/services/impl/bgfx_gui_service.cpp b/src/services/impl/gui/bgfx_gui_service.cpp similarity index 99% rename from src/services/impl/bgfx_gui_service.cpp rename to src/services/impl/gui/bgfx_gui_service.cpp index f260e04..fe2acf5 100644 --- a/src/services/impl/bgfx_gui_service.cpp +++ b/src/services/impl/gui/bgfx_gui_service.cpp @@ -1,8 +1,8 @@ #include "bgfx_gui_service.hpp" -#include "bgfx_shader_compiler.hpp" +#include "services/impl/graphics/bgfx_shader_compiler.hpp" -#include "../interfaces/config_types.hpp" -#include "../interfaces/gui_types.hpp" +#include "services/interfaces/config_types.hpp" +#include "services/interfaces/gui_types.hpp" #include #include diff --git a/src/services/impl/bgfx_gui_service.hpp b/src/services/impl/gui/bgfx_gui_service.hpp similarity index 95% rename from src/services/impl/bgfx_gui_service.hpp rename to src/services/impl/gui/bgfx_gui_service.hpp index 98ba15f..6d890ac 100644 --- a/src/services/impl/bgfx_gui_service.hpp +++ b/src/services/impl/gui/bgfx_gui_service.hpp @@ -1,14 +1,14 @@ #pragma once -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_gui_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_pipeline_compiler_service.hpp" -#include "../../di/lifecycle.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_gui_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_pipeline_compiler_service.hpp" +#include "../../../di/lifecycle.hpp" #include -#include "materialx_shader_generator.hpp" +#include "services/impl/materialx/materialx_shader_generator.hpp" #include #include diff --git a/src/services/impl/null_gui_service.cpp b/src/services/impl/gui/null_gui_service.cpp similarity index 94% rename from src/services/impl/null_gui_service.cpp rename to src/services/impl/gui/null_gui_service.cpp index 4fc4950..0e4efac 100644 --- a/src/services/impl/null_gui_service.cpp +++ b/src/services/impl/gui/null_gui_service.cpp @@ -1,6 +1,6 @@ #include "null_gui_service.hpp" -#include "../interfaces/gui_types.hpp" +#include "services/interfaces/gui_types.hpp" #include diff --git a/src/services/impl/null_gui_service.hpp b/src/services/impl/gui/null_gui_service.hpp similarity index 82% rename from src/services/impl/null_gui_service.hpp rename to src/services/impl/gui/null_gui_service.hpp index f407ed2..448a6c6 100644 --- a/src/services/impl/null_gui_service.hpp +++ b/src/services/impl/gui/null_gui_service.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../interfaces/i_gui_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_gui_service.hpp" +#include "services/interfaces/i_logger.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/sdl_input_service.cpp b/src/services/impl/input/sdl_input_service.cpp similarity index 100% rename from src/services/impl/sdl_input_service.cpp rename to src/services/impl/input/sdl_input_service.cpp diff --git a/src/services/impl/sdl_input_service.hpp b/src/services/impl/input/sdl_input_service.hpp similarity index 94% rename from src/services/impl/sdl_input_service.hpp rename to src/services/impl/input/sdl_input_service.hpp index e61f34d..58a945b 100644 --- a/src/services/impl/sdl_input_service.hpp +++ b/src/services/impl/input/sdl_input_service.hpp @@ -1,10 +1,10 @@ #pragma once -#include "../interfaces/i_input_service.hpp" -#include "../interfaces/i_gui_script_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_config_service.hpp" -#include "../../events/i_event_bus.hpp" +#include "services/interfaces/i_input_service.hpp" +#include "services/interfaces/i_gui_script_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "../../../events/i_event_bus.hpp" #include #include diff --git a/src/services/impl/materialx_document_loader.cpp b/src/services/impl/materialx/materialx_document_loader.cpp similarity index 100% rename from src/services/impl/materialx_document_loader.cpp rename to src/services/impl/materialx/materialx_document_loader.cpp diff --git a/src/services/impl/materialx_document_loader.hpp b/src/services/impl/materialx/materialx_document_loader.hpp similarity index 89% rename from src/services/impl/materialx_document_loader.hpp rename to src/services/impl/materialx/materialx_document_loader.hpp index 60bd299..37d0aa0 100644 --- a/src/services/impl/materialx_document_loader.hpp +++ b/src/services/impl/materialx/materialx_document_loader.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../interfaces/config_types.hpp" +#include "services/interfaces/config_types.hpp" #include diff --git a/src/services/impl/materialx_path_resolver.cpp b/src/services/impl/materialx/materialx_path_resolver.cpp similarity index 100% rename from src/services/impl/materialx_path_resolver.cpp rename to src/services/impl/materialx/materialx_path_resolver.cpp diff --git a/src/services/impl/materialx_path_resolver.hpp b/src/services/impl/materialx/materialx_path_resolver.hpp similarity index 100% rename from src/services/impl/materialx_path_resolver.hpp rename to src/services/impl/materialx/materialx_path_resolver.hpp diff --git a/src/services/impl/materialx_search_path_builder.cpp b/src/services/impl/materialx/materialx_search_path_builder.cpp similarity index 100% rename from src/services/impl/materialx_search_path_builder.cpp rename to src/services/impl/materialx/materialx_search_path_builder.cpp diff --git a/src/services/impl/materialx_search_path_builder.hpp b/src/services/impl/materialx/materialx_search_path_builder.hpp similarity index 88% rename from src/services/impl/materialx_search_path_builder.hpp rename to src/services/impl/materialx/materialx_search_path_builder.hpp index 8174a67..28ae4ff 100644 --- a/src/services/impl/materialx_search_path_builder.hpp +++ b/src/services/impl/materialx/materialx_search_path_builder.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../interfaces/config_types.hpp" +#include "services/interfaces/config_types.hpp" #include diff --git a/src/services/impl/materialx_shader_generator.cpp b/src/services/impl/materialx/materialx_shader_generator.cpp similarity index 99% rename from src/services/impl/materialx_shader_generator.cpp rename to src/services/impl/materialx/materialx_shader_generator.cpp index 3cd20f6..cc588e9 100644 --- a/src/services/impl/materialx_shader_generator.cpp +++ b/src/services/impl/materialx/materialx_shader_generator.cpp @@ -1,6 +1,6 @@ #include "materialx_shader_generator.hpp" -#include "shader_pipeline_validator.hpp" -#include "../../core/vertex.hpp" +#include "services/impl/shader/shader_pipeline_validator.hpp" +#include "../../../core/vertex.hpp" #include #include diff --git a/src/services/impl/materialx_shader_generator.hpp b/src/services/impl/materialx/materialx_shader_generator.hpp similarity index 80% rename from src/services/impl/materialx_shader_generator.hpp rename to src/services/impl/materialx/materialx_shader_generator.hpp index 85e4f20..1f87dc5 100644 --- a/src/services/impl/materialx_shader_generator.hpp +++ b/src/services/impl/materialx/materialx_shader_generator.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/config_types.hpp" -#include "../interfaces/graphics_types.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/config_types.hpp" +#include "services/interfaces/graphics_types.hpp" +#include "services/interfaces/i_logger.hpp" #include #include diff --git a/src/services/impl/materialx_surface_node_resolver.cpp b/src/services/impl/materialx/materialx_surface_node_resolver.cpp similarity index 100% rename from src/services/impl/materialx_surface_node_resolver.cpp rename to src/services/impl/materialx/materialx_surface_node_resolver.cpp diff --git a/src/services/impl/materialx_surface_node_resolver.hpp b/src/services/impl/materialx/materialx_surface_node_resolver.hpp similarity index 100% rename from src/services/impl/materialx_surface_node_resolver.hpp rename to src/services/impl/materialx/materialx_surface_node_resolver.hpp diff --git a/src/services/impl/materialx_surface_parameter_reader.cpp b/src/services/impl/materialx/materialx_surface_parameter_reader.cpp similarity index 100% rename from src/services/impl/materialx_surface_parameter_reader.cpp rename to src/services/impl/materialx/materialx_surface_parameter_reader.cpp diff --git a/src/services/impl/materialx_surface_parameter_reader.hpp b/src/services/impl/materialx/materialx_surface_parameter_reader.hpp similarity index 100% rename from src/services/impl/materialx_surface_parameter_reader.hpp rename to src/services/impl/materialx/materialx_surface_parameter_reader.hpp diff --git a/src/services/impl/materialx_surface_parameters.hpp b/src/services/impl/materialx/materialx_surface_parameters.hpp similarity index 100% rename from src/services/impl/materialx_surface_parameters.hpp rename to src/services/impl/materialx/materialx_surface_parameters.hpp diff --git a/src/services/impl/platform_service.cpp b/src/services/impl/platform/platform_service.cpp similarity index 100% rename from src/services/impl/platform_service.cpp rename to src/services/impl/platform/platform_service.cpp diff --git a/src/services/impl/platform_service.hpp b/src/services/impl/platform/platform_service.hpp similarity index 89% rename from src/services/impl/platform_service.hpp rename to src/services/impl/platform/platform_service.hpp index 729e115..2e34d7a 100644 --- a/src/services/impl/platform_service.hpp +++ b/src/services/impl/platform/platform_service.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../interfaces/i_platform_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_platform_service.hpp" +#include "services/interfaces/i_logger.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/sdl_window_service.cpp b/src/services/impl/platform/sdl_window_service.cpp similarity index 99% rename from src/services/impl/sdl_window_service.cpp rename to src/services/impl/platform/sdl_window_service.cpp index 68c87d3..e17663b 100644 --- a/src/services/impl/sdl_window_service.cpp +++ b/src/services/impl/platform/sdl_window_service.cpp @@ -1,5 +1,5 @@ #include "sdl_window_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_logger.hpp" #include #include #include diff --git a/src/services/impl/sdl_window_service.hpp b/src/services/impl/platform/sdl_window_service.hpp similarity index 91% rename from src/services/impl/sdl_window_service.hpp rename to src/services/impl/platform/sdl_window_service.hpp index 3bfa8c3..46bfff0 100644 --- a/src/services/impl/sdl_window_service.hpp +++ b/src/services/impl/platform/sdl_window_service.hpp @@ -1,10 +1,10 @@ #pragma once -#include "../interfaces/i_window_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_platform_service.hpp" -#include "../../di/lifecycle.hpp" -#include "../../events/i_event_bus.hpp" +#include "services/interfaces/i_window_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_platform_service.hpp" +#include "../../../di/lifecycle.hpp" +#include "../../../events/i_event_bus.hpp" #include #include diff --git a/src/services/impl/render_coordinator_service.cpp b/src/services/impl/render/render_coordinator_service.cpp similarity index 100% rename from src/services/impl/render_coordinator_service.cpp rename to src/services/impl/render/render_coordinator_service.cpp diff --git a/src/services/impl/render_coordinator_service.hpp b/src/services/impl/render/render_coordinator_service.hpp similarity index 79% rename from src/services/impl/render_coordinator_service.hpp rename to src/services/impl/render/render_coordinator_service.hpp index c2a3b24..0bcf083 100644 --- a/src/services/impl/render_coordinator_service.hpp +++ b/src/services/impl/render/render_coordinator_service.hpp @@ -1,16 +1,16 @@ #pragma once -#include "../interfaces/i_render_coordinator_service.hpp" -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_config_compiler_service.hpp" -#include "../interfaces/i_graphics_service.hpp" -#include "../interfaces/i_gui_script_service.hpp" -#include "../interfaces/i_gui_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_scene_script_service.hpp" -#include "../interfaces/i_scene_service.hpp" -#include "../interfaces/i_shader_script_service.hpp" -#include "../interfaces/i_validation_tour_service.hpp" +#include "services/interfaces/i_render_coordinator_service.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_config_compiler_service.hpp" +#include "services/interfaces/i_graphics_service.hpp" +#include "services/interfaces/i_gui_script_service.hpp" +#include "services/interfaces/i_gui_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_scene_script_service.hpp" +#include "services/interfaces/i_scene_service.hpp" +#include "services/interfaces/i_shader_script_service.hpp" +#include "services/interfaces/i_validation_tour_service.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/render_graph_service.cpp b/src/services/impl/render/render_graph_service.cpp similarity index 100% rename from src/services/impl/render_graph_service.cpp rename to src/services/impl/render/render_graph_service.cpp diff --git a/src/services/impl/render_graph_service.hpp b/src/services/impl/render/render_graph_service.hpp similarity index 84% rename from src/services/impl/render_graph_service.hpp rename to src/services/impl/render/render_graph_service.hpp index c2d860a..9a8961a 100644 --- a/src/services/impl/render_graph_service.hpp +++ b/src/services/impl/render/render_graph_service.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/i_render_graph_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_probe_service.hpp" +#include "services/interfaces/i_render_graph_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_probe_service.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/bullet_physics_service.cpp b/src/services/impl/scene/bullet_physics_service.cpp similarity index 99% rename from src/services/impl/bullet_physics_service.cpp rename to src/services/impl/scene/bullet_physics_service.cpp index fd83bbc..5ee200d 100644 --- a/src/services/impl/bullet_physics_service.cpp +++ b/src/services/impl/scene/bullet_physics_service.cpp @@ -1,5 +1,5 @@ #include "bullet_physics_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_logger.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/bullet_physics_service.hpp b/src/services/impl/scene/bullet_physics_service.hpp similarity index 94% rename from src/services/impl/bullet_physics_service.hpp rename to src/services/impl/scene/bullet_physics_service.hpp index 7844cdd..6b01112 100644 --- a/src/services/impl/bullet_physics_service.hpp +++ b/src/services/impl/scene/bullet_physics_service.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../interfaces/i_physics_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_physics_service.hpp" +#include "services/interfaces/i_logger.hpp" #include "physics_bridge_service.hpp" -#include "../../di/lifecycle.hpp" +#include "../../../di/lifecycle.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/ecs_service.cpp b/src/services/impl/scene/ecs_service.cpp similarity index 100% rename from src/services/impl/ecs_service.cpp rename to src/services/impl/scene/ecs_service.cpp diff --git a/src/services/impl/ecs_service.hpp b/src/services/impl/scene/ecs_service.hpp similarity index 81% rename from src/services/impl/ecs_service.hpp rename to src/services/impl/scene/ecs_service.hpp index 93dc8e1..6343644 100644 --- a/src/services/impl/ecs_service.hpp +++ b/src/services/impl/scene/ecs_service.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/i_ecs_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../../di/lifecycle.hpp" +#include "services/interfaces/i_ecs_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "../../../di/lifecycle.hpp" #include namespace sdl3cpp::services::impl { diff --git a/src/services/impl/mesh_service.cpp b/src/services/impl/scene/mesh_service.cpp similarity index 100% rename from src/services/impl/mesh_service.cpp rename to src/services/impl/scene/mesh_service.cpp diff --git a/src/services/impl/mesh_service.hpp b/src/services/impl/scene/mesh_service.hpp similarity index 88% rename from src/services/impl/mesh_service.hpp rename to src/services/impl/scene/mesh_service.hpp index 87c9acb..12a1fde 100644 --- a/src/services/impl/mesh_service.hpp +++ b/src/services/impl/scene/mesh_service.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/i_mesh_service.hpp" -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_mesh_service.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_logger.hpp" #include #include diff --git a/src/services/impl/physics_bridge_service.cpp b/src/services/impl/scene/physics_bridge_service.cpp similarity index 100% rename from src/services/impl/physics_bridge_service.cpp rename to src/services/impl/scene/physics_bridge_service.cpp diff --git a/src/services/impl/physics_bridge_service.hpp b/src/services/impl/scene/physics_bridge_service.hpp similarity index 97% rename from src/services/impl/physics_bridge_service.hpp rename to src/services/impl/scene/physics_bridge_service.hpp index f4d679f..01250b1 100644 --- a/src/services/impl/physics_bridge_service.hpp +++ b/src/services/impl/scene/physics_bridge_service.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../interfaces/i_physics_bridge_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_physics_bridge_service.hpp" +#include "services/interfaces/i_logger.hpp" #include #include #include diff --git a/src/services/impl/scene_service.cpp b/src/services/impl/scene/scene_service.cpp similarity index 92% rename from src/services/impl/scene_service.cpp rename to src/services/impl/scene/scene_service.cpp index 43f32e0..af5ef03 100644 --- a/src/services/impl/scene_service.cpp +++ b/src/services/impl/scene/scene_service.cpp @@ -94,7 +94,12 @@ void SceneService::LoadScene(const std::vector& objects) { sceneEntities_.push_back(entity); registry_->emplace(entity); registry_->emplace(entity, obj.vertices, obj.indices); - registry_->emplace(entity, obj.computeModelMatrixRef, obj.shaderKeys); + RenderComponent renderComponent; + renderComponent.computeModelMatrixRef = obj.computeModelMatrixRef; + renderComponent.hasCustomModelMatrix = obj.hasCustomModelMatrix; + renderComponent.modelMatrix = obj.modelMatrix; + renderComponent.shaderKeys = obj.shaderKeys; + registry_->emplace(entity, std::move(renderComponent)); } for (const auto entity : sceneEntities_) { @@ -134,6 +139,8 @@ void SceneService::LoadScene(const std::vector& objects) { drawInfo.indexCount = static_cast(mesh.indices.size()); drawInfo.vertexOffset = static_cast(vertexOffset); drawInfo.computeModelMatrixRef = render.computeModelMatrixRef; + drawInfo.hasCustomModelMatrix = render.hasCustomModelMatrix; + drawInfo.modelMatrix = render.modelMatrix; drawInfo.shaderKeys = render.shaderKeys; drawInfos_.push_back(std::move(drawInfo)); } @@ -184,7 +191,11 @@ std::vector SceneService::GetRenderCommands(float time) const { cmd.indexCount = drawInfo.indexCount; cmd.vertexOffset = drawInfo.vertexOffset; cmd.shaderKeys = drawInfo.shaderKeys; - cmd.modelMatrix = scriptService_->ComputeModelMatrix(drawInfo.computeModelMatrixRef, time); + if (drawInfo.hasCustomModelMatrix) { + cmd.modelMatrix = drawInfo.modelMatrix; + } else { + cmd.modelMatrix = scriptService_->ComputeModelMatrix(drawInfo.computeModelMatrixRef, time); + } commands.push_back(cmd); } diff --git a/src/services/impl/scene_service.hpp b/src/services/impl/scene/scene_service.hpp similarity index 84% rename from src/services/impl/scene_service.hpp rename to src/services/impl/scene/scene_service.hpp index e70ce95..0d77575 100644 --- a/src/services/impl/scene_service.hpp +++ b/src/services/impl/scene/scene_service.hpp @@ -1,11 +1,12 @@ #pragma once -#include "../interfaces/i_scene_service.hpp" -#include "../interfaces/i_scene_script_service.hpp" -#include "../interfaces/i_ecs_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_probe_service.hpp" -#include "../../di/lifecycle.hpp" +#include "services/interfaces/i_scene_service.hpp" +#include "services/interfaces/i_scene_script_service.hpp" +#include "services/interfaces/i_ecs_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_probe_service.hpp" +#include "../../../di/lifecycle.hpp" +#include #include #include #include @@ -50,6 +51,8 @@ private: struct RenderComponent { int computeModelMatrixRef = -1; + bool hasCustomModelMatrix = false; + std::array modelMatrix{}; std::vector shaderKeys; }; @@ -58,6 +61,8 @@ private: uint32_t indexCount = 0; int32_t vertexOffset = 0; int computeModelMatrixRef = -1; + bool hasCustomModelMatrix = false; + std::array modelMatrix{}; std::vector shaderKeys; }; diff --git a/src/services/impl/gui_script_service.cpp b/src/services/impl/script/gui_script_service.cpp similarity index 100% rename from src/services/impl/gui_script_service.cpp rename to src/services/impl/script/gui_script_service.cpp diff --git a/src/services/impl/gui_script_service.hpp b/src/services/impl/script/gui_script_service.hpp similarity index 87% rename from src/services/impl/gui_script_service.hpp rename to src/services/impl/script/gui_script_service.hpp index b77c03f..48e690b 100644 --- a/src/services/impl/gui_script_service.hpp +++ b/src/services/impl/script/gui_script_service.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../interfaces/i_gui_script_service.hpp" -#include "../interfaces/i_script_engine_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../../di/lifecycle.hpp" +#include "services/interfaces/i_gui_script_service.hpp" +#include "services/interfaces/i_script_engine_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "../../../di/lifecycle.hpp" #include #include diff --git a/src/services/impl/lua_helpers.cpp b/src/services/impl/script/lua_helpers.cpp similarity index 100% rename from src/services/impl/lua_helpers.cpp rename to src/services/impl/script/lua_helpers.cpp diff --git a/src/services/impl/lua_helpers.hpp b/src/services/impl/script/lua_helpers.hpp similarity index 100% rename from src/services/impl/lua_helpers.hpp rename to src/services/impl/script/lua_helpers.hpp diff --git a/src/services/impl/scene_script_service.cpp b/src/services/impl/script/scene_script_service.cpp similarity index 100% rename from src/services/impl/scene_script_service.cpp rename to src/services/impl/script/scene_script_service.cpp diff --git a/src/services/impl/scene_script_service.hpp b/src/services/impl/script/scene_script_service.hpp similarity index 81% rename from src/services/impl/scene_script_service.hpp rename to src/services/impl/script/scene_script_service.hpp index b964f44..8a27ae4 100644 --- a/src/services/impl/scene_script_service.hpp +++ b/src/services/impl/script/scene_script_service.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../interfaces/i_scene_script_service.hpp" -#include "../interfaces/i_script_engine_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_scene_script_service.hpp" +#include "services/interfaces/i_script_engine_service.hpp" +#include "services/interfaces/i_logger.hpp" #include struct lua_State; diff --git a/src/services/impl/script_engine_service.cpp b/src/services/impl/script/script_engine_service.cpp similarity index 99% rename from src/services/impl/script_engine_service.cpp rename to src/services/impl/script/script_engine_service.cpp index d51aba9..042c75f 100644 --- a/src/services/impl/script_engine_service.cpp +++ b/src/services/impl/script/script_engine_service.cpp @@ -1,10 +1,10 @@ #include "script_engine_service.hpp" #include "lua_helpers.hpp" -#include "materialx_document_loader.hpp" -#include "materialx_path_resolver.hpp" -#include "materialx_surface_node_resolver.hpp" -#include "materialx_surface_parameter_reader.hpp" +#include "services/impl/materialx/materialx_document_loader.hpp" +#include "services/impl/materialx/materialx_path_resolver.hpp" +#include "services/impl/materialx/materialx_surface_node_resolver.hpp" +#include "services/impl/materialx/materialx_surface_parameter_reader.hpp" #include "services/interfaces/i_logger.hpp" #include diff --git a/src/services/impl/script_engine_service.hpp b/src/services/impl/script/script_engine_service.hpp similarity index 91% rename from src/services/impl/script_engine_service.hpp rename to src/services/impl/script/script_engine_service.hpp index 5aec40d..94abe81 100644 --- a/src/services/impl/script_engine_service.hpp +++ b/src/services/impl/script/script_engine_service.hpp @@ -1,14 +1,14 @@ #pragma once -#include "../interfaces/i_script_engine_service.hpp" -#include "../interfaces/i_audio_command_service.hpp" -#include "../interfaces/i_mesh_service.hpp" -#include "../interfaces/i_physics_bridge_service.hpp" -#include "../interfaces/i_input_service.hpp" -#include "../interfaces/i_window_service.hpp" -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../../di/lifecycle.hpp" +#include "services/interfaces/i_script_engine_service.hpp" +#include "services/interfaces/i_audio_command_service.hpp" +#include "services/interfaces/i_mesh_service.hpp" +#include "services/interfaces/i_physics_bridge_service.hpp" +#include "services/interfaces/i_input_service.hpp" +#include "services/interfaces/i_window_service.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "../../../di/lifecycle.hpp" #include #include diff --git a/src/services/impl/shader_script_service.cpp b/src/services/impl/script/shader_script_service.cpp similarity index 100% rename from src/services/impl/shader_script_service.cpp rename to src/services/impl/script/shader_script_service.cpp diff --git a/src/services/impl/shader_script_service.hpp b/src/services/impl/script/shader_script_service.hpp similarity index 80% rename from src/services/impl/shader_script_service.hpp rename to src/services/impl/script/shader_script_service.hpp index 776b252..08ebae4 100644 --- a/src/services/impl/shader_script_service.hpp +++ b/src/services/impl/script/shader_script_service.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../interfaces/i_shader_script_service.hpp" -#include "../interfaces/i_script_engine_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_shader_system_registry.hpp" +#include "services/interfaces/i_shader_script_service.hpp" +#include "services/interfaces/i_script_engine_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_shader_system_registry.hpp" #include struct lua_State; diff --git a/src/services/impl/glsl_shader_system.cpp b/src/services/impl/shader/glsl_shader_system.cpp similarity index 100% rename from src/services/impl/glsl_shader_system.cpp rename to src/services/impl/shader/glsl_shader_system.cpp diff --git a/src/services/impl/glsl_shader_system.hpp b/src/services/impl/shader/glsl_shader_system.hpp similarity index 83% rename from src/services/impl/glsl_shader_system.hpp rename to src/services/impl/shader/glsl_shader_system.hpp index f7e7a67..1d3bf25 100644 --- a/src/services/impl/glsl_shader_system.hpp +++ b/src/services/impl/shader/glsl_shader_system.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../interfaces/i_config_compiler_service.hpp" -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_shader_system.hpp" +#include "services/interfaces/i_config_compiler_service.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_shader_system.hpp" #include #include diff --git a/src/services/impl/materialx_shader_system.cpp b/src/services/impl/shader/materialx_shader_system.cpp similarity index 100% rename from src/services/impl/materialx_shader_system.cpp rename to src/services/impl/shader/materialx_shader_system.cpp diff --git a/src/services/impl/materialx_shader_system.hpp b/src/services/impl/shader/materialx_shader_system.hpp similarity index 80% rename from src/services/impl/materialx_shader_system.hpp rename to src/services/impl/shader/materialx_shader_system.hpp index 947d8be..0f1b3b0 100644 --- a/src/services/impl/materialx_shader_system.hpp +++ b/src/services/impl/shader/materialx_shader_system.hpp @@ -1,10 +1,10 @@ #pragma once -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_script_engine_service.hpp" -#include "../interfaces/i_shader_system.hpp" -#include "materialx_shader_generator.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_script_engine_service.hpp" +#include "services/interfaces/i_shader_system.hpp" +#include "services/impl/materialx/materialx_shader_generator.hpp" #include #include diff --git a/src/services/impl/pipeline_compiler_service.cpp b/src/services/impl/shader/pipeline_compiler_service.cpp similarity index 100% rename from src/services/impl/pipeline_compiler_service.cpp rename to src/services/impl/shader/pipeline_compiler_service.cpp diff --git a/src/services/impl/pipeline_compiler_service.hpp b/src/services/impl/shader/pipeline_compiler_service.hpp similarity index 86% rename from src/services/impl/pipeline_compiler_service.hpp rename to src/services/impl/shader/pipeline_compiler_service.hpp index 699ecff..9db51b0 100644 --- a/src/services/impl/pipeline_compiler_service.hpp +++ b/src/services/impl/shader/pipeline_compiler_service.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../interfaces/i_pipeline_compiler_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_pipeline_compiler_service.hpp" +#include "services/interfaces/i_logger.hpp" #include #include #include diff --git a/src/services/impl/shader_pipeline_validator.cpp b/src/services/impl/shader/shader_pipeline_validator.cpp similarity index 99% rename from src/services/impl/shader_pipeline_validator.cpp rename to src/services/impl/shader/shader_pipeline_validator.cpp index cd131af..034720a 100644 --- a/src/services/impl/shader_pipeline_validator.cpp +++ b/src/services/impl/shader/shader_pipeline_validator.cpp @@ -1,5 +1,5 @@ #include "shader_pipeline_validator.hpp" -#include "../interfaces/i_logger.hpp" +#include "services/interfaces/i_logger.hpp" #include namespace sdl3cpp::services { diff --git a/src/services/impl/shader_pipeline_validator.hpp b/src/services/impl/shader/shader_pipeline_validator.hpp similarity index 100% rename from src/services/impl/shader_pipeline_validator.hpp rename to src/services/impl/shader/shader_pipeline_validator.hpp diff --git a/src/services/impl/shader_system_registry.cpp b/src/services/impl/shader/shader_system_registry.cpp similarity index 100% rename from src/services/impl/shader_system_registry.cpp rename to src/services/impl/shader/shader_system_registry.cpp diff --git a/src/services/impl/shader_system_registry.hpp b/src/services/impl/shader/shader_system_registry.hpp similarity index 83% rename from src/services/impl/shader_system_registry.hpp rename to src/services/impl/shader/shader_system_registry.hpp index f7ed90e..54642ef 100644 --- a/src/services/impl/shader_system_registry.hpp +++ b/src/services/impl/shader/shader_system_registry.hpp @@ -1,10 +1,10 @@ #pragma once -#include "../interfaces/i_config_compiler_service.hpp" -#include "../interfaces/i_config_service.hpp" -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_script_engine_service.hpp" -#include "../interfaces/i_shader_system_registry.hpp" +#include "services/interfaces/i_config_compiler_service.hpp" +#include "services/interfaces/i_config_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_script_engine_service.hpp" +#include "services/interfaces/i_shader_system_registry.hpp" #include "glsl_shader_system.hpp" #include "materialx_shader_system.hpp" diff --git a/src/services/impl/soundboard_path_resolver.cpp b/src/services/impl/soundboard/soundboard_path_resolver.cpp similarity index 100% rename from src/services/impl/soundboard_path_resolver.cpp rename to src/services/impl/soundboard/soundboard_path_resolver.cpp diff --git a/src/services/impl/soundboard_path_resolver.hpp b/src/services/impl/soundboard/soundboard_path_resolver.hpp similarity index 82% rename from src/services/impl/soundboard_path_resolver.hpp rename to src/services/impl/soundboard/soundboard_path_resolver.hpp index 73daa20..4d077a1 100644 --- a/src/services/impl/soundboard_path_resolver.hpp +++ b/src/services/impl/soundboard/soundboard_path_resolver.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../interfaces/i_config_service.hpp" +#include "services/interfaces/i_config_service.hpp" #include #include diff --git a/src/services/impl/soundboard_state_service.cpp b/src/services/impl/soundboard/soundboard_state_service.cpp similarity index 100% rename from src/services/impl/soundboard_state_service.cpp rename to src/services/impl/soundboard/soundboard_state_service.cpp diff --git a/src/services/impl/soundboard_state_service.hpp b/src/services/impl/soundboard/soundboard_state_service.hpp similarity index 81% rename from src/services/impl/soundboard_state_service.hpp rename to src/services/impl/soundboard/soundboard_state_service.hpp index 0e059d8..e45b051 100644 --- a/src/services/impl/soundboard_state_service.hpp +++ b/src/services/impl/soundboard/soundboard_state_service.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../interfaces/i_logger.hpp" -#include "../interfaces/i_soundboard_state_service.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_soundboard_state_service.hpp" #include #include diff --git a/src/services/impl/workflow/frame/frame_workflow_service.cpp b/src/services/impl/workflow/frame/frame_workflow_service.cpp index 7904703..4c4f61c 100644 --- a/src/services/impl/workflow/frame/frame_workflow_service.cpp +++ b/src/services/impl/workflow/frame/frame_workflow_service.cpp @@ -12,6 +12,7 @@ FrameWorkflowService::FrameWorkflowService(std::shared_ptr logger, std::shared_ptr configService, std::shared_ptr audioService, std::shared_ptr inputService, + std::shared_ptr meshService, std::shared_ptr physicsService, std::shared_ptr sceneService, std::shared_ptr renderService, @@ -32,6 +33,7 @@ FrameWorkflowService::FrameWorkflowService(std::shared_ptr logger, std::move(configService), std::move(audioService), std::move(inputService), + std::move(meshService), std::move(physicsService), std::move(sceneService), std::move(renderService), diff --git a/src/services/impl/workflow/frame/frame_workflow_service.hpp b/src/services/impl/workflow/frame/frame_workflow_service.hpp index 3100b6a..3e08053 100644 --- a/src/services/impl/workflow/frame/frame_workflow_service.hpp +++ b/src/services/impl/workflow/frame/frame_workflow_service.hpp @@ -5,6 +5,7 @@ #include "services/interfaces/i_audio_service.hpp" #include "services/interfaces/i_config_service.hpp" #include "services/interfaces/i_input_service.hpp" +#include "services/interfaces/i_mesh_service.hpp" #include "services/interfaces/i_physics_service.hpp" #include "services/interfaces/i_render_coordinator_service.hpp" #include "services/interfaces/i_scene_service.hpp" @@ -26,6 +27,7 @@ public: std::shared_ptr configService, std::shared_ptr audioService, std::shared_ptr inputService, + std::shared_ptr meshService, std::shared_ptr physicsService, std::shared_ptr sceneService, std::shared_ptr renderService, diff --git a/src/services/impl/workflow/frame/frame_workflow_step_registrar.cpp b/src/services/impl/workflow/frame/frame_workflow_step_registrar.cpp index 0daa8fa..447ba9f 100644 --- a/src/services/impl/workflow/frame/frame_workflow_step_registrar.cpp +++ b/src/services/impl/workflow/frame/frame_workflow_step_registrar.cpp @@ -8,16 +8,69 @@ #include "workflow_frame_physics_step.hpp" #include "workflow_frame_render_step.hpp" #include "workflow_frame_scene_step.hpp" +#include "../workflow_generic_steps/workflow_audio_play_step.hpp" +#include "../workflow_generic_steps/workflow_audio_set_volume_step.hpp" +#include "../workflow_generic_steps/workflow_audio_stop_step.hpp" +#include "../workflow_generic_steps/workflow_bool_and_step.hpp" +#include "../workflow_generic_steps/workflow_bool_not_step.hpp" +#include "../workflow_generic_steps/workflow_bool_or_step.hpp" +#include "../workflow_generic_steps/workflow_camera_build_view_state_step.hpp" +#include "../workflow_generic_steps/workflow_camera_look_at_step.hpp" +#include "../workflow_generic_steps/workflow_camera_set_fov_step.hpp" +#include "../workflow_generic_steps/workflow_camera_set_pose_step.hpp" +#include "../workflow_generic_steps/workflow_camera_teleport_step.hpp" +#include "../workflow_generic_steps/workflow_compare_eq_step.hpp" +#include "../workflow_generic_steps/workflow_compare_gte_step.hpp" +#include "../workflow_generic_steps/workflow_compare_gt_step.hpp" +#include "../workflow_generic_steps/workflow_compare_lte_step.hpp" +#include "../workflow_generic_steps/workflow_compare_lt_step.hpp" +#include "../workflow_generic_steps/workflow_compare_ne_step.hpp" +#include "../workflow_generic_steps/workflow_list_append_step.hpp" +#include "../workflow_generic_steps/workflow_list_concat_step.hpp" +#include "../workflow_generic_steps/workflow_list_count_step.hpp" #include "../workflow_generic_steps/workflow_list_filter_equals_step.hpp" +#include "../workflow_generic_steps/workflow_list_filter_gt_step.hpp" +#include "../workflow_generic_steps/workflow_list_literal_step.hpp" #include "../workflow_generic_steps/workflow_list_map_add_step.hpp" +#include "../workflow_generic_steps/workflow_list_map_mul_step.hpp" +#include "../workflow_generic_steps/workflow_list_reduce_max_step.hpp" +#include "../workflow_generic_steps/workflow_list_reduce_min_step.hpp" #include "../workflow_generic_steps/workflow_list_reduce_sum_step.hpp" +#include "../workflow_generic_steps/workflow_mesh_load_step.hpp" +#include "../workflow_generic_steps/workflow_model_despawn_step.hpp" +#include "../workflow_generic_steps/workflow_model_set_transform_step.hpp" +#include "../workflow_generic_steps/workflow_model_spawn_step.hpp" +#include "../workflow_generic_steps/workflow_number_abs_step.hpp" #include "../workflow_generic_steps/workflow_number_add_step.hpp" +#include "../workflow_generic_steps/workflow_number_clamp_step.hpp" +#include "../workflow_generic_steps/workflow_number_div_step.hpp" +#include "../workflow_generic_steps/workflow_number_max_step.hpp" +#include "../workflow_generic_steps/workflow_number_min_step.hpp" +#include "../workflow_generic_steps/workflow_number_mul_step.hpp" +#include "../workflow_generic_steps/workflow_number_round_step.hpp" +#include "../workflow_generic_steps/workflow_number_sub_step.hpp" +#include "../workflow_generic_steps/workflow_scene_clear_step.hpp" +#include "../workflow_generic_steps/workflow_scene_load_step.hpp" +#include "../workflow_generic_steps/workflow_scene_set_active_step.hpp" +#include "../workflow_generic_steps/workflow_string_concat_step.hpp" +#include "../workflow_generic_steps/workflow_string_contains_step.hpp" +#include "../workflow_generic_steps/workflow_string_equals_step.hpp" +#include "../workflow_generic_steps/workflow_string_join_step.hpp" +#include "../workflow_generic_steps/workflow_string_lower_step.hpp" +#include "../workflow_generic_steps/workflow_string_replace_step.hpp" +#include "../workflow_generic_steps/workflow_string_split_step.hpp" +#include "../workflow_generic_steps/workflow_string_trim_step.hpp" +#include "../workflow_generic_steps/workflow_string_upper_step.hpp" +#include "../workflow_generic_steps/workflow_value_assert_exists_step.hpp" +#include "../workflow_generic_steps/workflow_value_assert_type_step.hpp" +#include "../workflow_generic_steps/workflow_value_clear_step.hpp" #include "../workflow_soundboard_audio_step.hpp" #include "../workflow_soundboard_catalog_scan_step.hpp" #include "../workflow_soundboard_gui_step.hpp" #include "../workflow_step_registry.hpp" #include "../workflow_generic_steps/workflow_value_copy_step.hpp" #include "../workflow_generic_steps/workflow_value_default_step.hpp" +#include "../workflow_generic_steps/workflow_value_literal_step.hpp" #include "../workflow_validation_checkpoint_step.hpp" #include @@ -29,6 +82,7 @@ FrameWorkflowStepRegistrar::FrameWorkflowStepRegistrar(std::shared_ptr std::shared_ptr configService, std::shared_ptr audioService, std::shared_ptr inputService, + std::shared_ptr meshService, std::shared_ptr physicsService, std::shared_ptr sceneService, std::shared_ptr renderService, @@ -38,6 +92,7 @@ FrameWorkflowStepRegistrar::FrameWorkflowStepRegistrar(std::shared_ptr configService_(std::move(configService)), audioService_(std::move(audioService)), inputService_(std::move(inputService)), + meshService_(std::move(meshService)), physicsService_(std::move(physicsService)), sceneService_(std::move(sceneService)), renderService_(std::move(renderService)), @@ -97,24 +152,183 @@ void FrameWorkflowStepRegistrar::RegisterUsedSteps( soundboardStateService_, logger_)); } + if (plugins.contains("camera.set_pose")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("camera.look_at")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("camera.teleport")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("camera.set_fov")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("camera.build_view_state")) { + registry->RegisterStep(std::make_shared(configService_, logger_)); + } + if (plugins.contains("audio.play")) { + registry->RegisterStep(std::make_shared(audioService_, logger_)); + } + if (plugins.contains("audio.stop")) { + registry->RegisterStep(std::make_shared(audioService_, logger_)); + } + if (plugins.contains("audio.set_volume")) { + registry->RegisterStep(std::make_shared(audioService_, logger_)); + } + if (plugins.contains("mesh.load")) { + registry->RegisterStep(std::make_shared(meshService_, logger_)); + } + if (plugins.contains("model.spawn")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("model.despawn")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("model.set_transform")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("scene.load")) { + registry->RegisterStep(std::make_shared(sceneService_, logger_)); + } + if (plugins.contains("scene.clear")) { + registry->RegisterStep(std::make_shared(sceneService_, logger_)); + } + if (plugins.contains("scene.set_active")) { + registry->RegisterStep(std::make_shared(sceneService_, logger_)); + } if (plugins.contains("value.copy")) { registry->RegisterStep(std::make_shared(logger_)); } if (plugins.contains("value.default")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("value.literal")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("value.clear")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("value.assert.exists")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("value.assert.type")) { + registry->RegisterStep(std::make_shared(logger_)); + } if (plugins.contains("number.add")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("number.sub")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.mul")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.div")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.min")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.max")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.clamp")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.abs")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.round")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.eq")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.ne")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.gt")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.gte")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.lt")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.lte")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("bool.and")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("bool.or")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("bool.not")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.concat")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.trim")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.lower")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.upper")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.replace")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.contains")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.equals")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.split")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.join")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.literal")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.append")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.concat")) { + registry->RegisterStep(std::make_shared(logger_)); + } if (plugins.contains("list.filter.equals")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("list.filter.gt")) { + registry->RegisterStep(std::make_shared(logger_)); + } if (plugins.contains("list.map.add")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("list.map.mul")) { + registry->RegisterStep(std::make_shared(logger_)); + } if (plugins.contains("list.reduce.sum")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("list.reduce.min")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.reduce.max")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.count")) { + registry->RegisterStep(std::make_shared(logger_)); + } } } // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/frame/frame_workflow_step_registrar.hpp b/src/services/impl/workflow/frame/frame_workflow_step_registrar.hpp index 9d92caa..663e782 100644 --- a/src/services/impl/workflow/frame/frame_workflow_step_registrar.hpp +++ b/src/services/impl/workflow/frame/frame_workflow_step_registrar.hpp @@ -10,6 +10,7 @@ namespace sdl3cpp::services { class IAudioService; class IConfigService; class IInputService; +class IMeshService; class IPhysicsService; class IRenderCoordinatorService; class ISceneService; @@ -25,6 +26,7 @@ public: std::shared_ptr configService, std::shared_ptr audioService, std::shared_ptr inputService, + std::shared_ptr meshService, std::shared_ptr physicsService, std::shared_ptr sceneService, std::shared_ptr renderService, @@ -39,6 +41,7 @@ private: std::shared_ptr configService_; std::shared_ptr audioService_; std::shared_ptr inputService_; + std::shared_ptr meshService_; std::shared_ptr physicsService_; std::shared_ptr sceneService_; std::shared_ptr renderService_; diff --git a/src/services/impl/workflow/workflow_camera_view_state_builder.cpp b/src/services/impl/workflow/workflow_camera_view_state_builder.cpp new file mode 100644 index 0000000..a1b560b --- /dev/null +++ b/src/services/impl/workflow/workflow_camera_view_state_builder.cpp @@ -0,0 +1,37 @@ +#include "workflow_camera_view_state_builder.hpp" + +#include +#include +#include + +#include + +namespace sdl3cpp::services::impl { +namespace { +std::array ToArray(const glm::mat4& matrix) { + std::array result{}; + std::memcpy(result.data(), glm::value_ptr(matrix), sizeof(float) * result.size()); + return result; +} +} // namespace + +ViewState BuildViewState(const CameraPose& pose, float aspect) { + glm::vec3 position(pose.position[0], pose.position[1], pose.position[2]); + glm::vec3 lookAt(pose.lookAt[0], pose.lookAt[1], pose.lookAt[2]); + glm::vec3 up(pose.up[0], pose.up[1], pose.up[2]); + glm::mat4 view = glm::lookAt(position, lookAt, up); + float safeAspect = aspect <= 0.0f ? 1.0f : aspect; + glm::mat4 proj = glm::perspective(glm::radians(pose.fovDegrees), + safeAspect, + pose.nearPlane, + pose.farPlane); + + ViewState state{}; + state.view = ToArray(view); + state.proj = ToArray(proj); + state.viewProj = ToArray(proj * view); + state.cameraPosition = pose.position; + return state; +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_camera_view_state_builder.hpp b/src/services/impl/workflow/workflow_camera_view_state_builder.hpp new file mode 100644 index 0000000..4ea5838 --- /dev/null +++ b/src/services/impl/workflow/workflow_camera_view_state_builder.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "services/interfaces/camera_types.hpp" +#include "services/interfaces/graphics_types.hpp" + +namespace sdl3cpp::services::impl { + +ViewState BuildViewState(const CameraPose& pose, float aspect); + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_default_step_registrar.cpp b/src/services/impl/workflow/workflow_default_step_registrar.cpp index ace6e9c..ee7f3c5 100644 --- a/src/services/impl/workflow/workflow_default_step_registrar.cpp +++ b/src/services/impl/workflow/workflow_default_step_registrar.cpp @@ -4,12 +4,50 @@ #include "workflow_config_schema_step.hpp" #include "workflow_config_version_step.hpp" #include "workflow_runtime_config_step.hpp" +#include "workflow_generic_steps/workflow_bool_and_step.hpp" +#include "workflow_generic_steps/workflow_bool_not_step.hpp" +#include "workflow_generic_steps/workflow_bool_or_step.hpp" +#include "workflow_generic_steps/workflow_compare_eq_step.hpp" +#include "workflow_generic_steps/workflow_compare_gte_step.hpp" +#include "workflow_generic_steps/workflow_compare_gt_step.hpp" +#include "workflow_generic_steps/workflow_compare_lte_step.hpp" +#include "workflow_generic_steps/workflow_compare_lt_step.hpp" +#include "workflow_generic_steps/workflow_compare_ne_step.hpp" +#include "workflow_generic_steps/workflow_list_append_step.hpp" +#include "workflow_generic_steps/workflow_list_concat_step.hpp" +#include "workflow_generic_steps/workflow_list_count_step.hpp" #include "workflow_generic_steps/workflow_list_filter_equals_step.hpp" +#include "workflow_generic_steps/workflow_list_filter_gt_step.hpp" +#include "workflow_generic_steps/workflow_list_literal_step.hpp" #include "workflow_generic_steps/workflow_list_map_add_step.hpp" +#include "workflow_generic_steps/workflow_list_map_mul_step.hpp" +#include "workflow_generic_steps/workflow_list_reduce_max_step.hpp" +#include "workflow_generic_steps/workflow_list_reduce_min_step.hpp" #include "workflow_generic_steps/workflow_list_reduce_sum_step.hpp" +#include "workflow_generic_steps/workflow_number_abs_step.hpp" #include "workflow_generic_steps/workflow_number_add_step.hpp" +#include "workflow_generic_steps/workflow_number_clamp_step.hpp" +#include "workflow_generic_steps/workflow_number_div_step.hpp" +#include "workflow_generic_steps/workflow_number_max_step.hpp" +#include "workflow_generic_steps/workflow_number_min_step.hpp" +#include "workflow_generic_steps/workflow_number_mul_step.hpp" +#include "workflow_generic_steps/workflow_number_round_step.hpp" +#include "workflow_generic_steps/workflow_number_sub_step.hpp" +#include "workflow_generic_steps/workflow_string_concat_step.hpp" +#include "workflow_generic_steps/workflow_string_contains_step.hpp" +#include "workflow_generic_steps/workflow_string_equals_step.hpp" +#include "workflow_generic_steps/workflow_string_join_step.hpp" +#include "workflow_generic_steps/workflow_string_lower_step.hpp" +#include "workflow_generic_steps/workflow_string_replace_step.hpp" +#include "workflow_generic_steps/workflow_string_split_step.hpp" +#include "workflow_generic_steps/workflow_string_trim_step.hpp" +#include "workflow_generic_steps/workflow_string_upper_step.hpp" +#include "workflow_generic_steps/workflow_value_assert_exists_step.hpp" +#include "workflow_generic_steps/workflow_value_assert_type_step.hpp" +#include "workflow_generic_steps/workflow_value_clear_step.hpp" #include "workflow_generic_steps/workflow_value_copy_step.hpp" #include "workflow_generic_steps/workflow_value_default_step.hpp" +#include "workflow_generic_steps/workflow_value_literal_step.hpp" #include #include @@ -55,18 +93,132 @@ void WorkflowDefaultStepRegistrar::RegisterUsedSteps( if (plugins.contains("value.default")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("value.literal")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("value.clear")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("value.assert.exists")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("value.assert.type")) { + registry->RegisterStep(std::make_shared(logger_)); + } if (plugins.contains("number.add")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("number.sub")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.mul")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.div")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.min")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.max")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.clamp")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.abs")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("number.round")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.eq")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.ne")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.gt")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.gte")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.lt")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("compare.lte")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("bool.and")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("bool.or")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("bool.not")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.concat")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.trim")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.lower")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.upper")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.replace")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.contains")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.equals")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.split")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("string.join")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.literal")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.append")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.concat")) { + registry->RegisterStep(std::make_shared(logger_)); + } if (plugins.contains("list.filter.equals")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("list.filter.gt")) { + registry->RegisterStep(std::make_shared(logger_)); + } if (plugins.contains("list.map.add")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("list.map.mul")) { + registry->RegisterStep(std::make_shared(logger_)); + } if (plugins.contains("list.reduce.sum")) { registry->RegisterStep(std::make_shared(logger_)); } + if (plugins.contains("list.reduce.min")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.reduce.max")) { + registry->RegisterStep(std::make_shared(logger_)); + } + if (plugins.contains("list.count")) { + registry->RegisterStep(std::make_shared(logger_)); + } } } // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_definition_parser.cpp b/src/services/impl/workflow/workflow_definition_parser.cpp index c20c967..6f8c30a 100644 --- a/src/services/impl/workflow/workflow_definition_parser.cpp +++ b/src/services/impl/workflow/workflow_definition_parser.cpp @@ -38,6 +38,59 @@ std::unordered_map ReadStringMap(const rapidjson::Valu return result; } +std::unordered_map ReadParameterMap(const rapidjson::Value& object, + const char* name) { + std::unordered_map result; + if (!object.HasMember(name)) { + return result; + } + const auto& mapValue = object[name]; + if (!mapValue.IsObject()) { + throw std::runtime_error("Workflow member '" + std::string(name) + "' must be an object"); + } + for (auto it = mapValue.MemberBegin(); it != mapValue.MemberEnd(); ++it) { + const std::string key = it->name.GetString(); + const auto& value = it->value; + if (value.IsString()) { + result.emplace(key, WorkflowParameterValue::FromString(value.GetString())); + continue; + } + if (value.IsBool()) { + result.emplace(key, WorkflowParameterValue::FromBool(value.GetBool())); + continue; + } + if (value.IsNumber()) { + result.emplace(key, WorkflowParameterValue::FromNumber(value.GetDouble())); + continue; + } + if (value.IsArray()) { + std::vector stringItems; + std::vector numberItems; + for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { + const auto& entry = value[i]; + if (entry.IsString()) { + stringItems.emplace_back(entry.GetString()); + } else if (entry.IsNumber()) { + numberItems.emplace_back(entry.GetDouble()); + } else { + throw std::runtime_error("Workflow parameter '" + key + "' must contain strings or numbers"); + } + } + if (!stringItems.empty() && !numberItems.empty()) { + throw std::runtime_error("Workflow parameter '" + key + "' cannot mix string and number values"); + } + if (!stringItems.empty() || value.Empty()) { + result.emplace(key, WorkflowParameterValue::FromStringList(std::move(stringItems))); + } else { + result.emplace(key, WorkflowParameterValue::FromNumberList(std::move(numberItems))); + } + continue; + } + throw std::runtime_error("Workflow parameter '" + key + "' must be a string, number, bool, or array"); + } + return result; +} + std::string ReadNodeId(const rapidjson::Value& node, size_t index) { if (node.HasMember("id") && node["id"].IsString()) { return node["id"].GetString(); @@ -186,6 +239,7 @@ WorkflowDefinition WorkflowDefinitionParser::ParseFile(const std::filesystem::pa step.plugin = ReadRequiredString(entry, "plugin"); step.inputs = ReadStringMap(entry, "inputs"); step.outputs = ReadStringMap(entry, "outputs"); + step.parameters = ReadParameterMap(entry, "parameters"); workflow.steps.push_back(std::move(step)); } return workflow; @@ -207,6 +261,7 @@ WorkflowDefinition WorkflowDefinitionParser::ParseFile(const std::filesystem::pa step.plugin = ReadNodePlugin(entry, step.id); step.inputs = ReadStringMap(entry, "inputs"); step.outputs = ReadStringMap(entry, "outputs"); + step.parameters = ReadParameterMap(entry, "parameters"); nodes.push_back(step); nodeOrder.push_back(step.id); } diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_audio_play_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_play_step.cpp new file mode 100644 index 0000000..52bd030 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_play_step.cpp @@ -0,0 +1,110 @@ +#include "workflow_audio_play_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../workflow_step_parameter_resolver.hpp" + +#include +#include +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { +namespace { +std::string ResolveMode(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver) { + auto it = step.inputs.find("mode"); + if (it != step.inputs.end()) { + const auto* mode = context.TryGet(it->second); + if (!mode) { + throw std::runtime_error("audio.play requires string mode input"); + } + return *mode; + } + if (const auto* param = parameterResolver.FindParameter(step, "mode")) { + if (param->type != WorkflowParameterValue::Type::String) { + throw std::runtime_error("audio.play parameter 'mode' must be a string"); + } + return param->stringValue; + } + return "effect"; +} + +bool ResolveLoop(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver, + bool fallback) { + auto it = step.inputs.find("loop"); + if (it != step.inputs.end()) { + const auto* loop = context.TryGet(it->second); + if (!loop) { + throw std::runtime_error("audio.play requires bool loop input"); + } + return *loop; + } + if (const auto* param = parameterResolver.FindParameter(step, "loop")) { + if (param->type != WorkflowParameterValue::Type::Bool) { + throw std::runtime_error("audio.play parameter 'loop' must be a bool"); + } + return param->boolValue; + } + return fallback; +} + +std::string NormalizeMode(std::string mode) { + std::transform(mode.begin(), mode.end(), mode.begin(), + [](unsigned char ch) { return static_cast(std::tolower(ch)); }); + return mode; +} +} // namespace + +WorkflowAudioPlayStep::WorkflowAudioPlayStep(std::shared_ptr audioService, + std::shared_ptr logger) + : audioService_(std::move(audioService)), + logger_(std::move(logger)) {} + +std::string WorkflowAudioPlayStep::GetPluginId() const { + return "audio.play"; +} + +void WorkflowAudioPlayStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + if (!audioService_) { + throw std::runtime_error("audio.play requires an IAudioService"); + } + + WorkflowStepIoResolver resolver; + WorkflowStepParameterResolver parameterResolver; + const std::string pathKey = resolver.GetRequiredInputKey(step, "path"); + + std::filesystem::path pathValue; + if (const auto* path = context.TryGet(pathKey)) { + pathValue = *path; + } else if (const auto* pathString = context.TryGet(pathKey)) { + pathValue = *pathString; + } else { + throw std::runtime_error("audio.play missing path input '" + pathKey + "'"); + } + + std::string mode = NormalizeMode(ResolveMode(step, context, parameterResolver)); + bool loop = ResolveLoop(step, context, parameterResolver, false); + + if (mode == "background" || mode == "music") { + audioService_->PlayBackground(pathValue, loop); + } else if (mode == "effect" || mode == "sfx") { + audioService_->PlayEffect(pathValue, loop); + } else { + throw std::runtime_error("audio.play mode must be 'background' or 'effect'"); + } + + if (logger_) { + logger_->Trace("WorkflowAudioPlayStep", "Execute", + "path=" + pathValue.string() + + ", mode=" + mode + + ", loop=" + std::string(loop ? "true" : "false"), + "Dispatched audio playback"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_audio_play_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_play_step.hpp new file mode 100644 index 0000000..c347906 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_play_step.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../../interfaces/i_audio_service.hpp" +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowAudioPlayStep final : public IWorkflowStep { +public: + WorkflowAudioPlayStep(std::shared_ptr audioService, + std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr audioService_; + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_audio_set_volume_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_set_volume_step.cpp new file mode 100644 index 0000000..6d451d2 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_set_volume_step.cpp @@ -0,0 +1,43 @@ +#include "workflow_audio_set_volume_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowAudioSetVolumeStep::WorkflowAudioSetVolumeStep(std::shared_ptr audioService, + std::shared_ptr logger) + : audioService_(std::move(audioService)), + logger_(std::move(logger)) {} + +std::string WorkflowAudioSetVolumeStep::GetPluginId() const { + return "audio.set_volume"; +} + +void WorkflowAudioSetVolumeStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + if (!audioService_) { + throw std::runtime_error("audio.set_volume requires an IAudioService"); + } + + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("audio.set_volume requires numeric value input"); + } + + const float clamped = static_cast(std::clamp(*value, 0.0, 1.0)); + audioService_->SetVolume(clamped); + + if (logger_) { + logger_->Trace("WorkflowAudioSetVolumeStep", "Execute", + "value=" + std::to_string(clamped), + "Updated audio volume"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_audio_set_volume_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_set_volume_step.hpp new file mode 100644 index 0000000..3c90fe7 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_set_volume_step.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../../interfaces/i_audio_service.hpp" +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowAudioSetVolumeStep final : public IWorkflowStep { +public: + WorkflowAudioSetVolumeStep(std::shared_ptr audioService, + std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr audioService_; + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_audio_stop_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_stop_step.cpp new file mode 100644 index 0000000..e26c048 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_stop_step.cpp @@ -0,0 +1,66 @@ +#include "workflow_audio_stop_step.hpp" + +#include "../workflow_step_parameter_resolver.hpp" + +#include +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { +namespace { +std::string NormalizeMode(std::string mode) { + std::transform(mode.begin(), mode.end(), mode.begin(), + [](unsigned char ch) { return static_cast(std::tolower(ch)); }); + return mode; +} +} // namespace + +WorkflowAudioStopStep::WorkflowAudioStopStep(std::shared_ptr audioService, + std::shared_ptr logger) + : audioService_(std::move(audioService)), + logger_(std::move(logger)) {} + +std::string WorkflowAudioStopStep::GetPluginId() const { + return "audio.stop"; +} + +void WorkflowAudioStopStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + if (!audioService_) { + throw std::runtime_error("audio.stop requires an IAudioService"); + } + + WorkflowStepParameterResolver parameterResolver; + std::string mode = "all"; + auto it = step.inputs.find("mode"); + if (it != step.inputs.end()) { + const auto* inputMode = context.TryGet(it->second); + if (!inputMode) { + throw std::runtime_error("audio.stop requires string mode input"); + } + mode = *inputMode; + } else if (const auto* param = parameterResolver.FindParameter(step, "mode")) { + if (param->type != WorkflowParameterValue::Type::String) { + throw std::runtime_error("audio.stop parameter 'mode' must be a string"); + } + mode = param->stringValue; + } + mode = NormalizeMode(mode); + + if (mode == "background" || mode == "music") { + audioService_->StopBackground(); + } else if (mode == "all") { + audioService_->StopAll(); + } else { + throw std::runtime_error("audio.stop mode must be 'background' or 'all'"); + } + + if (logger_) { + logger_->Trace("WorkflowAudioStopStep", "Execute", + "mode=" + mode, + "Stopped audio playback"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_audio_stop_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_stop_step.hpp new file mode 100644 index 0000000..ac181e7 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_audio_stop_step.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../../interfaces/i_audio_service.hpp" +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowAudioStopStep final : public IWorkflowStep { +public: + WorkflowAudioStopStep(std::shared_ptr audioService, + std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr audioService_; + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_bool_and_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_and_step.cpp new file mode 100644 index 0000000..da3074e --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_and_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_bool_and_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowBoolAndStep::WorkflowBoolAndStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowBoolAndStep::GetPluginId() const { + return "bool.and"; +} + +void WorkflowBoolAndStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("bool.and requires bool inputs"); + } + + const bool result = *left && *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowBoolAndStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Computed workflow AND"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_bool_and_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_and_step.hpp new file mode 100644 index 0000000..7245871 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_and_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowBoolAndStep final : public IWorkflowStep { +public: + explicit WorkflowBoolAndStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_bool_not_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_not_step.cpp new file mode 100644 index 0000000..c106ebc --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_not_step.cpp @@ -0,0 +1,38 @@ +#include "workflow_bool_not_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowBoolNotStep::WorkflowBoolNotStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowBoolNotStep::GetPluginId() const { + return "bool.not"; +} + +void WorkflowBoolNotStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("bool.not requires bool input"); + } + + const bool result = !(*value); + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowBoolNotStep", "Execute", + "value=" + valueKey + + ", output=" + outputKey, + "Computed workflow NOT"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_bool_not_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_not_step.hpp new file mode 100644 index 0000000..0003dad --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_not_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowBoolNotStep final : public IWorkflowStep { +public: + explicit WorkflowBoolNotStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_bool_or_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_or_step.cpp new file mode 100644 index 0000000..1dda6cd --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_or_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_bool_or_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowBoolOrStep::WorkflowBoolOrStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowBoolOrStep::GetPluginId() const { + return "bool.or"; +} + +void WorkflowBoolOrStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("bool.or requires bool inputs"); + } + + const bool result = *left || *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowBoolOrStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Computed workflow OR"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_bool_or_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_or_step.hpp new file mode 100644 index 0000000..ec5e462 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_bool_or_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowBoolOrStep final : public IWorkflowStep { +public: + explicit WorkflowBoolOrStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_build_view_state_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_build_view_state_step.cpp new file mode 100644 index 0000000..215a54c --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_build_view_state_step.cpp @@ -0,0 +1,59 @@ +#include "workflow_camera_build_view_state_step.hpp" + +#include "../workflow_camera_view_state_builder.hpp" +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCameraBuildViewStateStep::WorkflowCameraBuildViewStateStep(std::shared_ptr configService, + std::shared_ptr logger) + : configService_(std::move(configService)), + logger_(std::move(logger)) {} + +std::string WorkflowCameraBuildViewStateStep::GetPluginId() const { + return "camera.build_view_state"; +} + +void WorkflowCameraBuildViewStateStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string poseKey = resolver.GetRequiredInputKey(step, "pose"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "view_state"); + + const auto* pose = context.TryGet(poseKey); + if (!pose) { + throw std::runtime_error("camera.build_view_state requires pose input"); + } + + float aspect = 1.0f; + auto aspectIt = step.inputs.find("aspect"); + if (aspectIt != step.inputs.end()) { + const auto* aspectValue = context.TryGet(aspectIt->second); + if (!aspectValue) { + throw std::runtime_error("camera.build_view_state missing aspect input"); + } + aspect = static_cast(*aspectValue); + } else if (configService_) { + uint32_t width = configService_->GetWindowWidth(); + uint32_t height = configService_->GetWindowHeight(); + if (width > 0 && height > 0) { + aspect = static_cast(width) / static_cast(height); + } + } + + ViewState viewState = BuildViewState(*pose, aspect); + context.Set(outputKey, viewState); + + if (logger_) { + logger_->Trace("WorkflowCameraBuildViewStateStep", "Execute", + "input=" + poseKey + + ", output=" + outputKey + + ", aspect=" + std::to_string(aspect), + "Built camera view state"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_build_view_state_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_build_view_state_step.hpp new file mode 100644 index 0000000..ca24a32 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_build_view_state_step.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "../../interfaces/camera_types.hpp" +#include "../../interfaces/i_config_service.hpp" +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCameraBuildViewStateStep final : public IWorkflowStep { +public: + WorkflowCameraBuildViewStateStep(std::shared_ptr configService, + std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr configService_; + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_look_at_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_look_at_step.cpp new file mode 100644 index 0000000..9057862 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_look_at_step.cpp @@ -0,0 +1,44 @@ +#include "workflow_camera_look_at_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCameraLookAtStep::WorkflowCameraLookAtStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCameraLookAtStep::GetPluginId() const { + return "camera.look_at"; +} + +void WorkflowCameraLookAtStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string poseKey = resolver.GetRequiredInputKey(step, "pose"); + const std::string targetKey = resolver.GetRequiredInputKey(step, "target"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "pose"); + + const auto* pose = context.TryGet(poseKey); + const auto* target = context.TryGet>(targetKey); + if (!pose || !target || target->size() != 3u) { + throw std::runtime_error("camera.look_at requires pose and target[3] inputs"); + } + + CameraPose updated = *pose; + updated.lookAt = {static_cast((*target)[0]), + static_cast((*target)[1]), + static_cast((*target)[2])}; + context.Set(outputKey, updated); + + if (logger_) { + logger_->Trace("WorkflowCameraLookAtStep", "Execute", + "input=" + poseKey + + ", output=" + outputKey, + "Updated camera look-at"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_look_at_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_look_at_step.hpp new file mode 100644 index 0000000..897ea8c --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_look_at_step.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "services/interfaces/camera_types.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCameraLookAtStep final : public IWorkflowStep { +public: + explicit WorkflowCameraLookAtStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_fov_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_fov_step.cpp new file mode 100644 index 0000000..0fcbcd7 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_fov_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_camera_set_fov_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCameraSetFovStep::WorkflowCameraSetFovStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCameraSetFovStep::GetPluginId() const { + return "camera.set_fov"; +} + +void WorkflowCameraSetFovStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string poseKey = resolver.GetRequiredInputKey(step, "pose"); + const std::string fovKey = resolver.GetRequiredInputKey(step, "fov_degrees"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "pose"); + + const auto* pose = context.TryGet(poseKey); + const auto* fov = context.TryGet(fovKey); + if (!pose || !fov) { + throw std::runtime_error("camera.set_fov requires pose and fov_degrees inputs"); + } + + CameraPose updated = *pose; + updated.fovDegrees = static_cast(*fov); + context.Set(outputKey, updated); + + if (logger_) { + logger_->Trace("WorkflowCameraSetFovStep", "Execute", + "input=" + poseKey + + ", output=" + outputKey, + "Updated camera FOV"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_fov_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_fov_step.hpp new file mode 100644 index 0000000..32b4079 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_fov_step.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "../../interfaces/camera_types.hpp" +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCameraSetFovStep final : public IWorkflowStep { +public: + explicit WorkflowCameraSetFovStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_pose_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_pose_step.cpp new file mode 100644 index 0000000..0090064 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_pose_step.cpp @@ -0,0 +1,90 @@ +#include "workflow_camera_set_pose_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../workflow_step_parameter_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { +namespace { +std::array ReadVec3(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver, + const std::string& name, + const std::array& fallback) { + auto it = step.inputs.find(name); + if (it != step.inputs.end()) { + const auto* list = context.TryGet>(it->second); + if (!list || list->size() != 3u) { + throw std::runtime_error("camera.set_pose requires '" + name + "' list of 3 numbers"); + } + return {static_cast((*list)[0]), + static_cast((*list)[1]), + static_cast((*list)[2])}; + } + if (const auto* param = parameterResolver.FindParameter(step, name)) { + if (param->type != WorkflowParameterValue::Type::NumberList || param->numberList.size() != 3u) { + throw std::runtime_error("camera.set_pose parameter '" + name + "' must be number list of 3"); + } + return {static_cast(param->numberList[0]), + static_cast(param->numberList[1]), + static_cast(param->numberList[2])}; + } + return fallback; +} + +float ReadNumber(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver, + const std::string& name, + float fallback) { + auto it = step.inputs.find(name); + if (it != step.inputs.end()) { + const auto* value = context.TryGet(it->second); + if (!value) { + throw std::runtime_error("camera.set_pose requires number input '" + name + "'"); + } + return static_cast(*value); + } + if (const auto* param = parameterResolver.FindParameter(step, name)) { + if (param->type != WorkflowParameterValue::Type::Number) { + throw std::runtime_error("camera.set_pose parameter '" + name + "' must be a number"); + } + return static_cast(param->numberValue); + } + return fallback; +} +} // namespace + +WorkflowCameraSetPoseStep::WorkflowCameraSetPoseStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCameraSetPoseStep::GetPluginId() const { + return "camera.set_pose"; +} + +void WorkflowCameraSetPoseStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver ioResolver; + WorkflowStepParameterResolver parameterResolver; + const std::string outputKey = ioResolver.GetRequiredOutputKey(step, "pose"); + + CameraPose pose; + pose.position = ReadVec3(step, context, parameterResolver, "position", pose.position); + pose.lookAt = ReadVec3(step, context, parameterResolver, "look_at", pose.lookAt); + pose.up = ReadVec3(step, context, parameterResolver, "up", pose.up); + pose.fovDegrees = ReadNumber(step, context, parameterResolver, "fov_degrees", pose.fovDegrees); + pose.nearPlane = ReadNumber(step, context, parameterResolver, "near", pose.nearPlane); + pose.farPlane = ReadNumber(step, context, parameterResolver, "far", pose.farPlane); + + context.Set(outputKey, pose); + + if (logger_) { + logger_->Trace("WorkflowCameraSetPoseStep", "Execute", + "output=" + outputKey, + "Set camera pose"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_pose_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_pose_step.hpp new file mode 100644 index 0000000..18510c8 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_set_pose_step.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "services/interfaces/camera_types.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCameraSetPoseStep final : public IWorkflowStep { +public: + explicit WorkflowCameraSetPoseStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_teleport_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_teleport_step.cpp new file mode 100644 index 0000000..968fb59 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_teleport_step.cpp @@ -0,0 +1,44 @@ +#include "workflow_camera_teleport_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCameraTeleportStep::WorkflowCameraTeleportStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCameraTeleportStep::GetPluginId() const { + return "camera.teleport"; +} + +void WorkflowCameraTeleportStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string poseKey = resolver.GetRequiredInputKey(step, "pose"); + const std::string positionKey = resolver.GetRequiredInputKey(step, "position"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "pose"); + + const auto* pose = context.TryGet(poseKey); + const auto* position = context.TryGet>(positionKey); + if (!pose || !position || position->size() != 3u) { + throw std::runtime_error("camera.teleport requires pose and position[3] inputs"); + } + + CameraPose updated = *pose; + updated.position = {static_cast((*position)[0]), + static_cast((*position)[1]), + static_cast((*position)[2])}; + context.Set(outputKey, updated); + + if (logger_) { + logger_->Trace("WorkflowCameraTeleportStep", "Execute", + "input=" + poseKey + + ", output=" + outputKey, + "Teleported camera"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_camera_teleport_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_teleport_step.hpp new file mode 100644 index 0000000..7e27cea --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_camera_teleport_step.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "services/interfaces/camera_types.hpp" +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCameraTeleportStep final : public IWorkflowStep { +public: + explicit WorkflowCameraTeleportStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_eq_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_eq_step.cpp new file mode 100644 index 0000000..4773e10 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_eq_step.cpp @@ -0,0 +1,59 @@ +#include "workflow_compare_eq_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCompareEqStep::WorkflowCompareEqStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCompareEqStep::GetPluginId() const { + return "compare.eq"; +} + +void WorkflowCompareEqStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + bool result = false; + if (const auto* left = context.TryGet(leftKey)) { + const auto* right = context.TryGet(rightKey); + if (!right) { + throw std::runtime_error("compare.eq requires both inputs to be numbers"); + } + result = (*left == *right); + } else if (const auto* left = context.TryGet(leftKey)) { + const auto* right = context.TryGet(rightKey); + if (!right) { + throw std::runtime_error("compare.eq requires both inputs to be strings"); + } + result = (*left == *right); + } else if (const auto* left = context.TryGet(leftKey)) { + const auto* right = context.TryGet(rightKey); + if (!right) { + throw std::runtime_error("compare.eq requires both inputs to be bools"); + } + result = (*left == *right); + } else { + throw std::runtime_error("compare.eq requires number, string, or bool inputs"); + } + + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowCompareEqStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Compared workflow values for equality"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_eq_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_eq_step.hpp new file mode 100644 index 0000000..03b1557 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_eq_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCompareEqStep final : public IWorkflowStep { +public: + explicit WorkflowCompareEqStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gt_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gt_step.cpp new file mode 100644 index 0000000..b45a7da --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gt_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_compare_gt_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCompareGtStep::WorkflowCompareGtStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCompareGtStep::GetPluginId() const { + return "compare.gt"; +} + +void WorkflowCompareGtStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("compare.gt requires number inputs"); + } + + const bool result = *left > *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowCompareGtStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Compared workflow values (>)"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gt_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gt_step.hpp new file mode 100644 index 0000000..3f1e552 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gt_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCompareGtStep final : public IWorkflowStep { +public: + explicit WorkflowCompareGtStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gte_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gte_step.cpp new file mode 100644 index 0000000..69789af --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gte_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_compare_gte_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCompareGteStep::WorkflowCompareGteStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCompareGteStep::GetPluginId() const { + return "compare.gte"; +} + +void WorkflowCompareGteStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("compare.gte requires number inputs"); + } + + const bool result = *left >= *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowCompareGteStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Compared workflow values (>=)"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gte_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gte_step.hpp new file mode 100644 index 0000000..9e0336d --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_gte_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCompareGteStep final : public IWorkflowStep { +public: + explicit WorkflowCompareGteStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lt_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lt_step.cpp new file mode 100644 index 0000000..ff2b323 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lt_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_compare_lt_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCompareLtStep::WorkflowCompareLtStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCompareLtStep::GetPluginId() const { + return "compare.lt"; +} + +void WorkflowCompareLtStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("compare.lt requires number inputs"); + } + + const bool result = *left < *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowCompareLtStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Compared workflow values (<)"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lt_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lt_step.hpp new file mode 100644 index 0000000..9c9d371 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lt_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCompareLtStep final : public IWorkflowStep { +public: + explicit WorkflowCompareLtStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lte_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lte_step.cpp new file mode 100644 index 0000000..dd42f5a --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lte_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_compare_lte_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCompareLteStep::WorkflowCompareLteStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCompareLteStep::GetPluginId() const { + return "compare.lte"; +} + +void WorkflowCompareLteStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("compare.lte requires number inputs"); + } + + const bool result = *left <= *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowCompareLteStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Compared workflow values (<=)"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lte_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lte_step.hpp new file mode 100644 index 0000000..0225a15 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_lte_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCompareLteStep final : public IWorkflowStep { +public: + explicit WorkflowCompareLteStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_ne_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_ne_step.cpp new file mode 100644 index 0000000..965bd1d --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_ne_step.cpp @@ -0,0 +1,58 @@ +#include "workflow_compare_ne_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowCompareNeStep::WorkflowCompareNeStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowCompareNeStep::GetPluginId() const { + return "compare.ne"; +} + +void WorkflowCompareNeStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + bool result = false; + if (const auto* left = context.TryGet(leftKey)) { + const auto* right = context.TryGet(rightKey); + if (!right) { + throw std::runtime_error("compare.ne requires both inputs to be numbers"); + } + result = (*left != *right); + } else if (const auto* left = context.TryGet(leftKey)) { + const auto* right = context.TryGet(rightKey); + if (!right) { + throw std::runtime_error("compare.ne requires both inputs to be strings"); + } + result = (*left != *right); + } else if (const auto* left = context.TryGet(leftKey)) { + const auto* right = context.TryGet(rightKey); + if (!right) { + throw std::runtime_error("compare.ne requires both inputs to be bools"); + } + result = (*left != *right); + } else { + throw std::runtime_error("compare.ne requires number, string, or bool inputs"); + } + + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowCompareNeStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Compared workflow values for inequality"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_compare_ne_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_ne_step.hpp new file mode 100644 index 0000000..5e41d4e --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_compare_ne_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowCompareNeStep final : public IWorkflowStep { +public: + explicit WorkflowCompareNeStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_append_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_append_step.cpp new file mode 100644 index 0000000..0ea282f --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_append_step.cpp @@ -0,0 +1,53 @@ +#include "workflow_list_append_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowListAppendStep::WorkflowListAppendStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowListAppendStep::GetPluginId() const { + return "list.append"; +} + +void WorkflowListAppendStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string listKey = resolver.GetRequiredInputKey(step, "list"); + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "list"); + + if (const auto* list = context.TryGet>(listKey)) { + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("list.append requires numeric value input"); + } + std::vector result = *list; + result.push_back(*value); + context.Set(outputKey, std::move(result)); + } else if (const auto* list = context.TryGet>(listKey)) { + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("list.append requires string value input"); + } + std::vector result = *list; + result.push_back(*value); + context.Set(outputKey, std::move(result)); + } else { + throw std::runtime_error("list.append requires list input of strings or numbers"); + } + + if (logger_) { + logger_->Trace("WorkflowListAppendStep", "Execute", + "input=" + listKey + + ", output=" + outputKey, + "Appended workflow list"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_append_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_append_step.hpp new file mode 100644 index 0000000..ebb3043 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_append_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowListAppendStep final : public IWorkflowStep { +public: + explicit WorkflowListAppendStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_concat_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_concat_step.cpp new file mode 100644 index 0000000..290a933 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_concat_step.cpp @@ -0,0 +1,54 @@ +#include "workflow_list_concat_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowListConcatStep::WorkflowListConcatStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowListConcatStep::GetPluginId() const { + return "list.concat"; +} + +void WorkflowListConcatStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "list"); + + if (const auto* left = context.TryGet>(leftKey)) { + const auto* right = context.TryGet>(rightKey); + if (!right) { + throw std::runtime_error("list.concat requires both inputs to be numeric lists"); + } + std::vector result = *left; + result.insert(result.end(), right->begin(), right->end()); + context.Set(outputKey, std::move(result)); + } else if (const auto* left = context.TryGet>(leftKey)) { + const auto* right = context.TryGet>(rightKey); + if (!right) { + throw std::runtime_error("list.concat requires both inputs to be string lists"); + } + std::vector result = *left; + result.insert(result.end(), right->begin(), right->end()); + context.Set(outputKey, std::move(result)); + } else { + throw std::runtime_error("list.concat requires list inputs of strings or numbers"); + } + + if (logger_) { + logger_->Trace("WorkflowListConcatStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Concatenated workflow lists"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_concat_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_concat_step.hpp new file mode 100644 index 0000000..705412a --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_concat_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowListConcatStep final : public IWorkflowStep { +public: + explicit WorkflowListConcatStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_count_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_count_step.cpp new file mode 100644 index 0000000..c17570b --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_count_step.cpp @@ -0,0 +1,40 @@ +#include "workflow_list_count_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowListCountStep::WorkflowListCountStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowListCountStep::GetPluginId() const { + return "list.count"; +} + +void WorkflowListCountStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string listKey = resolver.GetRequiredInputKey(step, "list"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + if (const auto* list = context.TryGet>(listKey)) { + context.Set(outputKey, static_cast(list->size())); + } else if (const auto* list = context.TryGet>(listKey)) { + context.Set(outputKey, static_cast(list->size())); + } else { + throw std::runtime_error("list.count requires list input of strings or numbers"); + } + + if (logger_) { + logger_->Trace("WorkflowListCountStep", "Execute", + "input=" + listKey + + ", output=" + outputKey, + "Counted workflow list"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_count_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_count_step.hpp new file mode 100644 index 0000000..d8ef69a --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_count_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowListCountStep final : public IWorkflowStep { +public: + explicit WorkflowListCountStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_filter_gt_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_filter_gt_step.cpp new file mode 100644 index 0000000..6b154b2 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_filter_gt_step.cpp @@ -0,0 +1,47 @@ +#include "workflow_list_filter_gt_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowListFilterGtStep::WorkflowListFilterGtStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowListFilterGtStep::GetPluginId() const { + return "list.filter.gt"; +} + +void WorkflowListFilterGtStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string listKey = resolver.GetRequiredInputKey(step, "list"); + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "list"); + + const auto* list = context.TryGet>(listKey); + const auto* value = context.TryGet(valueKey); + if (!list || !value) { + throw std::runtime_error("list.filter.gt requires numeric list and value inputs"); + } + + std::vector filtered; + filtered.reserve(list->size()); + for (double entry : *list) { + if (entry > *value) { + filtered.push_back(entry); + } + } + context.Set(outputKey, std::move(filtered)); + + if (logger_) { + logger_->Trace("WorkflowListFilterGtStep", "Execute", + "input=" + listKey + + ", output=" + outputKey, + "Filtered numeric list by greater-than"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_filter_gt_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_filter_gt_step.hpp new file mode 100644 index 0000000..2203a60 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_filter_gt_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowListFilterGtStep final : public IWorkflowStep { +public: + explicit WorkflowListFilterGtStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_literal_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_literal_step.cpp new file mode 100644 index 0000000..a882a05 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_literal_step.cpp @@ -0,0 +1,68 @@ +#include "workflow_list_literal_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../workflow_step_parameter_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowListLiteralStep::WorkflowListLiteralStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowListLiteralStep::GetPluginId() const { + return "list.literal"; +} + +void WorkflowListLiteralStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver ioResolver; + WorkflowStepParameterResolver parameterResolver; + const std::string outputKey = ioResolver.GetRequiredOutputKey(step, "list"); + const auto& items = parameterResolver.GetRequiredParameter(step, "items"); + + std::string typeHint; + if (const auto* typeParam = parameterResolver.FindParameter(step, "type")) { + if (typeParam->type != WorkflowParameterValue::Type::String) { + throw std::runtime_error("list.literal parameter 'type' must be a string"); + } + typeHint = typeParam->stringValue; + std::transform(typeHint.begin(), typeHint.end(), typeHint.begin(), + [](unsigned char ch) { return static_cast(std::tolower(ch)); }); + } + + switch (items.type) { + case WorkflowParameterValue::Type::String: + context.Set(outputKey, std::vector{items.stringValue}); + break; + case WorkflowParameterValue::Type::Number: + context.Set(outputKey, std::vector{items.numberValue}); + break; + case WorkflowParameterValue::Type::StringList: + if (items.stringList.empty() && typeHint == "number") { + context.Set(outputKey, std::vector{}); + } else { + context.Set(outputKey, items.stringList); + } + break; + case WorkflowParameterValue::Type::NumberList: + if (items.numberList.empty() && typeHint == "string") { + context.Set(outputKey, std::vector{}); + } else { + context.Set(outputKey, items.numberList); + } + break; + default: + throw std::runtime_error("list.literal parameter 'items' must be string or number list"); + } + + if (logger_) { + logger_->Trace("WorkflowListLiteralStep", "Execute", + "output=" + outputKey, + "Set literal workflow list"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_literal_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_literal_step.hpp new file mode 100644 index 0000000..795c2d9 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_literal_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowListLiteralStep final : public IWorkflowStep { +public: + explicit WorkflowListLiteralStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_map_mul_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_map_mul_step.cpp new file mode 100644 index 0000000..b39e057 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_map_mul_step.cpp @@ -0,0 +1,45 @@ +#include "workflow_list_map_mul_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowListMapMulStep::WorkflowListMapMulStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowListMapMulStep::GetPluginId() const { + return "list.map.mul"; +} + +void WorkflowListMapMulStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string listKey = resolver.GetRequiredInputKey(step, "list"); + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "list"); + + const auto* list = context.TryGet>(listKey); + const auto* value = context.TryGet(valueKey); + if (!list || !value) { + throw std::runtime_error("list.map.mul requires numeric list and value inputs"); + } + + std::vector mapped; + mapped.reserve(list->size()); + for (double entry : *list) { + mapped.push_back(entry * (*value)); + } + context.Set(outputKey, std::move(mapped)); + + if (logger_) { + logger_->Trace("WorkflowListMapMulStep", "Execute", + "input=" + listKey + + ", output=" + outputKey, + "Scaled numeric list"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_map_mul_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_map_mul_step.hpp new file mode 100644 index 0000000..8cc12d3 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_map_mul_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowListMapMulStep final : public IWorkflowStep { +public: + explicit WorkflowListMapMulStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_max_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_max_step.cpp new file mode 100644 index 0000000..7c9e952 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_max_step.cpp @@ -0,0 +1,40 @@ +#include "workflow_list_reduce_max_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowListReduceMaxStep::WorkflowListReduceMaxStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowListReduceMaxStep::GetPluginId() const { + return "list.reduce.max"; +} + +void WorkflowListReduceMaxStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string listKey = resolver.GetRequiredInputKey(step, "list"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* list = context.TryGet>(listKey); + if (!list || list->empty()) { + throw std::runtime_error("list.reduce.max requires a non-empty numeric list"); + } + + const double result = *std::max_element(list->begin(), list->end()); + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowListReduceMaxStep", "Execute", + "input=" + listKey + + ", output=" + outputKey, + "Reduced numeric list to max"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_max_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_max_step.hpp new file mode 100644 index 0000000..c6f0fdb --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_max_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowListReduceMaxStep final : public IWorkflowStep { +public: + explicit WorkflowListReduceMaxStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_min_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_min_step.cpp new file mode 100644 index 0000000..2a11806 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_min_step.cpp @@ -0,0 +1,40 @@ +#include "workflow_list_reduce_min_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowListReduceMinStep::WorkflowListReduceMinStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowListReduceMinStep::GetPluginId() const { + return "list.reduce.min"; +} + +void WorkflowListReduceMinStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string listKey = resolver.GetRequiredInputKey(step, "list"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* list = context.TryGet>(listKey); + if (!list || list->empty()) { + throw std::runtime_error("list.reduce.min requires a non-empty numeric list"); + } + + const double result = *std::min_element(list->begin(), list->end()); + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowListReduceMinStep", "Execute", + "input=" + listKey + + ", output=" + outputKey, + "Reduced numeric list to min"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_min_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_min_step.hpp new file mode 100644 index 0000000..1fd274e --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_list_reduce_min_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowListReduceMinStep final : public IWorkflowStep { +public: + explicit WorkflowListReduceMinStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_mesh_load_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_mesh_load_step.cpp new file mode 100644 index 0000000..0eaf784 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_mesh_load_step.cpp @@ -0,0 +1,54 @@ +#include "workflow_mesh_load_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowMeshLoadStep::WorkflowMeshLoadStep(std::shared_ptr meshService, + std::shared_ptr logger) + : meshService_(std::move(meshService)), + logger_(std::move(logger)) {} + +std::string WorkflowMeshLoadStep::GetPluginId() const { + return "mesh.load"; +} + +void WorkflowMeshLoadStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + if (!meshService_) { + throw std::runtime_error("mesh.load requires an IMeshService"); + } + + WorkflowStepIoResolver resolver; + const std::string pathKey = resolver.GetRequiredInputKey(step, "path"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "mesh"); + + std::filesystem::path pathValue; + if (const auto* path = context.TryGet(pathKey)) { + pathValue = *path; + } else if (const auto* pathString = context.TryGet(pathKey)) { + pathValue = *pathString; + } else { + throw std::runtime_error("mesh.load missing path input '" + pathKey + "'"); + } + + MeshPayload payload; + std::string error; + if (!meshService_->LoadFromFile(pathValue.string(), payload, error)) { + throw std::runtime_error("mesh.load failed: " + error); + } + + context.Set(outputKey, std::move(payload)); + + if (logger_) { + logger_->Trace("WorkflowMeshLoadStep", "Execute", + "path=" + pathValue.string() + + ", output=" + outputKey, + "Loaded mesh payload"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_mesh_load_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_mesh_load_step.hpp new file mode 100644 index 0000000..5279e96 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_mesh_load_step.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_mesh_service.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowMeshLoadStep final : public IWorkflowStep { +public: + WorkflowMeshLoadStep(std::shared_ptr meshService, + std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr meshService_; + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_model_despawn_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_model_despawn_step.cpp new file mode 100644 index 0000000..fcc06dc --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_model_despawn_step.cpp @@ -0,0 +1,72 @@ +#include "workflow_model_despawn_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../workflow_step_parameter_resolver.hpp" +#include "../../interfaces/scene_types.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { +namespace { +std::string ReadObjectType(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver) { + auto it = step.inputs.find("object_type"); + if (it != step.inputs.end()) { + const auto* value = context.TryGet(it->second); + if (!value) { + throw std::runtime_error("model.despawn requires object_type string input"); + } + return *value; + } + if (const auto* param = parameterResolver.FindParameter(step, "object_type")) { + if (param->type != WorkflowParameterValue::Type::String) { + throw std::runtime_error("model.despawn parameter 'object_type' must be string"); + } + return param->stringValue; + } + throw std::runtime_error("model.despawn requires object_type"); +} +} // namespace + +WorkflowModelDespawnStep::WorkflowModelDespawnStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowModelDespawnStep::GetPluginId() const { + return "model.despawn"; +} + +void WorkflowModelDespawnStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + WorkflowStepParameterResolver parameterResolver; + const std::string objectsKey = resolver.GetRequiredInputKey(step, "objects"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "objects"); + + const auto* objects = context.TryGet>(objectsKey); + if (!objects) { + throw std::runtime_error("model.despawn requires objects list input"); + } + + const std::string objectType = ReadObjectType(step, context, parameterResolver); + + std::vector remaining; + remaining.reserve(objects->size()); + for (const auto& object : *objects) { + if (object.objectType != objectType) { + remaining.push_back(object); + } + } + + context.Set(outputKey, std::move(remaining)); + + if (logger_) { + logger_->Trace("WorkflowModelDespawnStep", "Execute", + "object_type=" + objectType + + ", output=" + outputKey, + "Removed model(s) from workflow list"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_model_despawn_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_model_despawn_step.hpp new file mode 100644 index 0000000..e446e76 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_model_despawn_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowModelDespawnStep final : public IWorkflowStep { +public: + explicit WorkflowModelDespawnStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_model_set_transform_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_model_set_transform_step.cpp new file mode 100644 index 0000000..9aad1e0 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_model_set_transform_step.cpp @@ -0,0 +1,102 @@ +#include "workflow_model_set_transform_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../workflow_step_parameter_resolver.hpp" +#include "../../interfaces/scene_types.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { +namespace { +std::array ReadMatrix(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver) { + auto it = step.inputs.find("matrix"); + if (it != step.inputs.end()) { + const auto* list = context.TryGet>(it->second); + if (!list || list->size() != 16u) { + throw std::runtime_error("model.set_transform requires matrix list of 16 numbers"); + } + std::array matrix{}; + for (size_t i = 0; i < 16; ++i) { + matrix[i] = static_cast((*list)[i]); + } + return matrix; + } + if (const auto* param = parameterResolver.FindParameter(step, "matrix")) { + if (param->type != WorkflowParameterValue::Type::NumberList || param->numberList.size() != 16u) { + throw std::runtime_error("model.set_transform parameter 'matrix' must be number list of 16"); + } + std::array matrix{}; + for (size_t i = 0; i < 16; ++i) { + matrix[i] = static_cast(param->numberList[i]); + } + return matrix; + } + throw std::runtime_error("model.set_transform requires matrix input"); +} + +std::string ReadObjectType(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver) { + auto it = step.inputs.find("object_type"); + if (it != step.inputs.end()) { + const auto* value = context.TryGet(it->second); + if (!value) { + throw std::runtime_error("model.set_transform requires object_type string input"); + } + return *value; + } + if (const auto* param = parameterResolver.FindParameter(step, "object_type")) { + if (param->type != WorkflowParameterValue::Type::String) { + throw std::runtime_error("model.set_transform parameter 'object_type' must be string"); + } + return param->stringValue; + } + throw std::runtime_error("model.set_transform requires object_type"); +} +} // namespace + +WorkflowModelSetTransformStep::WorkflowModelSetTransformStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowModelSetTransformStep::GetPluginId() const { + return "model.set_transform"; +} + +void WorkflowModelSetTransformStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + WorkflowStepParameterResolver parameterResolver; + const std::string objectsKey = resolver.GetRequiredInputKey(step, "objects"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "objects"); + + const auto* objects = context.TryGet>(objectsKey); + if (!objects) { + throw std::runtime_error("model.set_transform requires objects list input"); + } + + const std::string objectType = ReadObjectType(step, context, parameterResolver); + const std::array matrix = ReadMatrix(step, context, parameterResolver); + + std::vector updated = *objects; + for (auto& object : updated) { + if (object.objectType == objectType) { + object.modelMatrix = matrix; + object.hasCustomModelMatrix = true; + object.computeModelMatrixRef = -1; + } + } + + context.Set(outputKey, std::move(updated)); + + if (logger_) { + logger_->Trace("WorkflowModelSetTransformStep", "Execute", + "object_type=" + objectType + + ", output=" + outputKey, + "Updated model transform"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_model_set_transform_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_model_set_transform_step.hpp new file mode 100644 index 0000000..8f17a92 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_model_set_transform_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowModelSetTransformStep final : public IWorkflowStep { +public: + explicit WorkflowModelSetTransformStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_model_spawn_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_model_spawn_step.cpp new file mode 100644 index 0000000..18d510c --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_model_spawn_step.cpp @@ -0,0 +1,151 @@ +#include "workflow_model_spawn_step.hpp" + +#include "../workflow_mesh_payload_converter.hpp" +#include "../workflow_step_io_resolver.hpp" +#include "../workflow_step_parameter_resolver.hpp" +#include "../../interfaces/scene_types.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { +namespace { +std::array ReadMatrix(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver) { + auto it = step.inputs.find("matrix"); + if (it != step.inputs.end()) { + const auto* list = context.TryGet>(it->second); + if (!list || list->size() != 16u) { + throw std::runtime_error("model.spawn requires matrix list of 16 numbers"); + } + std::array matrix{}; + for (size_t i = 0; i < 16; ++i) { + matrix[i] = static_cast((*list)[i]); + } + return matrix; + } + if (const auto* param = parameterResolver.FindParameter(step, "matrix")) { + if (param->type != WorkflowParameterValue::Type::NumberList || param->numberList.size() != 16u) { + throw std::runtime_error("model.spawn parameter 'matrix' must be number list of 16"); + } + std::array matrix{}; + for (size_t i = 0; i < 16; ++i) { + matrix[i] = static_cast(param->numberList[i]); + } + return matrix; + } + return { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; +} + +std::vector ReadShaderKeys(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver) { + auto it = step.inputs.find("shader_keys"); + if (it != step.inputs.end()) { + const auto* list = context.TryGet>(it->second); + if (!list) { + throw std::runtime_error("model.spawn requires shader_keys list input"); + } + return *list; + } + auto singleIt = step.inputs.find("shader_key"); + if (singleIt != step.inputs.end()) { + const auto* value = context.TryGet(singleIt->second); + if (!value) { + throw std::runtime_error("model.spawn requires shader_key string input"); + } + return { *value }; + } + if (const auto* param = parameterResolver.FindParameter(step, "shader_keys")) { + if (param->type != WorkflowParameterValue::Type::StringList) { + throw std::runtime_error("model.spawn parameter 'shader_keys' must be string list"); + } + return param->stringList; + } + if (const auto* param = parameterResolver.FindParameter(step, "shader_key")) { + if (param->type != WorkflowParameterValue::Type::String) { + throw std::runtime_error("model.spawn parameter 'shader_key' must be string"); + } + return { param->stringValue }; + } + throw std::runtime_error("model.spawn requires shader_key(s)"); +} + +std::string ReadObjectType(const WorkflowStepDefinition& step, + const WorkflowContext& context, + const WorkflowStepParameterResolver& parameterResolver) { + auto it = step.inputs.find("object_type"); + if (it != step.inputs.end()) { + const auto* value = context.TryGet(it->second); + if (!value) { + throw std::runtime_error("model.spawn requires object_type string input"); + } + return *value; + } + if (const auto* param = parameterResolver.FindParameter(step, "object_type")) { + if (param->type != WorkflowParameterValue::Type::String) { + throw std::runtime_error("model.spawn parameter 'object_type' must be string"); + } + return param->stringValue; + } + return {}; +} +} // namespace + +WorkflowModelSpawnStep::WorkflowModelSpawnStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowModelSpawnStep::GetPluginId() const { + return "model.spawn"; +} + +void WorkflowModelSpawnStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + WorkflowStepParameterResolver parameterResolver; + const std::string meshKey = resolver.GetRequiredInputKey(step, "mesh"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "objects"); + + const auto* mesh = context.TryGet(meshKey); + if (!mesh) { + throw std::runtime_error("model.spawn requires mesh input"); + } + + std::vector objects; + auto objectsIt = step.inputs.find("objects"); + if (objectsIt != step.inputs.end()) { + const auto* existing = context.TryGet>(objectsIt->second); + if (!existing) { + throw std::runtime_error("model.spawn requires objects list input"); + } + objects = *existing; + } + + MeshPayloadConversionResult conversion = ConvertMeshPayload(*mesh); + SceneObject object; + object.vertices = std::move(conversion.vertices); + object.indices = std::move(conversion.indices); + object.shaderKeys = ReadShaderKeys(step, context, parameterResolver); + object.objectType = ReadObjectType(step, context, parameterResolver); + object.computeModelMatrixRef = -1; + object.modelMatrix = ReadMatrix(step, context, parameterResolver); + object.hasCustomModelMatrix = true; + objects.push_back(std::move(object)); + + context.Set(outputKey, std::move(objects)); + + if (logger_) { + logger_->Trace("WorkflowModelSpawnStep", "Execute", + "mesh=" + meshKey + + ", output=" + outputKey, + "Spawned model into workflow list"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_model_spawn_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_model_spawn_step.hpp new file mode 100644 index 0000000..b84a402 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_model_spawn_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowModelSpawnStep final : public IWorkflowStep { +public: + explicit WorkflowModelSpawnStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_abs_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_abs_step.cpp new file mode 100644 index 0000000..7a3cbb5 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_abs_step.cpp @@ -0,0 +1,39 @@ +#include "workflow_number_abs_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowNumberAbsStep::WorkflowNumberAbsStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowNumberAbsStep::GetPluginId() const { + return "number.abs"; +} + +void WorkflowNumberAbsStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("number.abs missing input '" + valueKey + "'"); + } + + const double result = std::abs(*value); + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowNumberAbsStep", "Execute", + "value=" + std::to_string(*value) + + ", output=" + outputKey, + "Computed workflow absolute value"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_abs_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_abs_step.hpp new file mode 100644 index 0000000..f4c1640 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_abs_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowNumberAbsStep final : public IWorkflowStep { +public: + explicit WorkflowNumberAbsStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_clamp_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_clamp_step.cpp new file mode 100644 index 0000000..76f6eb8 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_clamp_step.cpp @@ -0,0 +1,46 @@ +#include "workflow_number_clamp_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowNumberClampStep::WorkflowNumberClampStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowNumberClampStep::GetPluginId() const { + return "number.clamp"; +} + +void WorkflowNumberClampStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string minKey = resolver.GetRequiredInputKey(step, "min"); + const std::string maxKey = resolver.GetRequiredInputKey(step, "max"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + const auto* minValue = context.TryGet(minKey); + const auto* maxValue = context.TryGet(maxKey); + if (!value || !minValue || !maxValue) { + throw std::runtime_error("number.clamp missing inputs '" + valueKey + "', '" + + minKey + "', or '" + maxKey + "'"); + } + + const double clamped = std::clamp(*value, *minValue, *maxValue); + context.Set(outputKey, clamped); + + if (logger_) { + logger_->Trace("WorkflowNumberClampStep", "Execute", + "value=" + std::to_string(*value) + + ", min=" + std::to_string(*minValue) + + ", max=" + std::to_string(*maxValue) + + ", output=" + outputKey, + "Clamped workflow number"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_clamp_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_clamp_step.hpp new file mode 100644 index 0000000..4125518 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_clamp_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowNumberClampStep final : public IWorkflowStep { +public: + explicit WorkflowNumberClampStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_div_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_div_step.cpp new file mode 100644 index 0000000..7f513e7 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_div_step.cpp @@ -0,0 +1,44 @@ +#include "workflow_number_div_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowNumberDivStep::WorkflowNumberDivStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowNumberDivStep::GetPluginId() const { + return "number.div"; +} + +void WorkflowNumberDivStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("number.div missing inputs '" + leftKey + "' or '" + rightKey + "'"); + } + if (*right == 0.0) { + throw std::runtime_error("number.div divide by zero"); + } + + const double result = *left / *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowNumberDivStep", "Execute", + "left=" + std::to_string(*left) + + ", right=" + std::to_string(*right) + + ", output=" + outputKey, + "Divided workflow numbers"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_div_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_div_step.hpp new file mode 100644 index 0000000..46874bb --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_div_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowNumberDivStep final : public IWorkflowStep { +public: + explicit WorkflowNumberDivStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_max_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_max_step.cpp new file mode 100644 index 0000000..1e9b9f7 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_max_step.cpp @@ -0,0 +1,42 @@ +#include "workflow_number_max_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowNumberMaxStep::WorkflowNumberMaxStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowNumberMaxStep::GetPluginId() const { + return "number.max"; +} + +void WorkflowNumberMaxStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("number.max missing inputs '" + leftKey + "' or '" + rightKey + "'"); + } + + const double result = std::max(*left, *right); + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowNumberMaxStep", "Execute", + "left=" + std::to_string(*left) + + ", right=" + std::to_string(*right) + + ", output=" + outputKey, + "Computed workflow max"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_max_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_max_step.hpp new file mode 100644 index 0000000..c99a8e3 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_max_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowNumberMaxStep final : public IWorkflowStep { +public: + explicit WorkflowNumberMaxStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_min_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_min_step.cpp new file mode 100644 index 0000000..033bfb9 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_min_step.cpp @@ -0,0 +1,42 @@ +#include "workflow_number_min_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowNumberMinStep::WorkflowNumberMinStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowNumberMinStep::GetPluginId() const { + return "number.min"; +} + +void WorkflowNumberMinStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("number.min missing inputs '" + leftKey + "' or '" + rightKey + "'"); + } + + const double result = std::min(*left, *right); + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowNumberMinStep", "Execute", + "left=" + std::to_string(*left) + + ", right=" + std::to_string(*right) + + ", output=" + outputKey, + "Computed workflow min"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_min_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_min_step.hpp new file mode 100644 index 0000000..f57442e --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_min_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowNumberMinStep final : public IWorkflowStep { +public: + explicit WorkflowNumberMinStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_mul_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_mul_step.cpp new file mode 100644 index 0000000..94e488b --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_mul_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_number_mul_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowNumberMulStep::WorkflowNumberMulStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowNumberMulStep::GetPluginId() const { + return "number.mul"; +} + +void WorkflowNumberMulStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("number.mul missing inputs '" + leftKey + "' or '" + rightKey + "'"); + } + + const double result = *left * *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowNumberMulStep", "Execute", + "left=" + std::to_string(*left) + + ", right=" + std::to_string(*right) + + ", output=" + outputKey, + "Multiplied workflow numbers"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_mul_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_mul_step.hpp new file mode 100644 index 0000000..854346f --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_mul_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowNumberMulStep final : public IWorkflowStep { +public: + explicit WorkflowNumberMulStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_round_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_round_step.cpp new file mode 100644 index 0000000..6653c5e --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_round_step.cpp @@ -0,0 +1,39 @@ +#include "workflow_number_round_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowNumberRoundStep::WorkflowNumberRoundStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowNumberRoundStep::GetPluginId() const { + return "number.round"; +} + +void WorkflowNumberRoundStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("number.round missing input '" + valueKey + "'"); + } + + const double result = std::round(*value); + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowNumberRoundStep", "Execute", + "value=" + std::to_string(*value) + + ", output=" + outputKey, + "Rounded workflow number"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_round_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_round_step.hpp new file mode 100644 index 0000000..222628e --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_round_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowNumberRoundStep final : public IWorkflowStep { +public: + explicit WorkflowNumberRoundStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_sub_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_sub_step.cpp new file mode 100644 index 0000000..20226be --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_sub_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_number_sub_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowNumberSubStep::WorkflowNumberSubStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowNumberSubStep::GetPluginId() const { + return "number.sub"; +} + +void WorkflowNumberSubStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("number.sub missing inputs '" + leftKey + "' or '" + rightKey + "'"); + } + + const double result = *left - *right; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowNumberSubStep", "Execute", + "left=" + std::to_string(*left) + + ", right=" + std::to_string(*right) + + ", output=" + outputKey, + "Subtracted workflow numbers"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_number_sub_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_number_sub_step.hpp new file mode 100644 index 0000000..f81e91a --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_number_sub_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowNumberSubStep final : public IWorkflowStep { +public: + explicit WorkflowNumberSubStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_scene_clear_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_clear_step.cpp new file mode 100644 index 0000000..08f18ea --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_clear_step.cpp @@ -0,0 +1,30 @@ +#include "workflow_scene_clear_step.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowSceneClearStep::WorkflowSceneClearStep(std::shared_ptr sceneService, + std::shared_ptr logger) + : sceneService_(std::move(sceneService)), + logger_(std::move(logger)) {} + +std::string WorkflowSceneClearStep::GetPluginId() const { + return "scene.clear"; +} + +void WorkflowSceneClearStep::Execute(const WorkflowStepDefinition&, WorkflowContext&) { + if (!sceneService_) { + throw std::runtime_error("scene.clear requires an ISceneService"); + } + + sceneService_->Clear(); + + if (logger_) { + logger_->Trace("WorkflowSceneClearStep", "Execute", + "Cleared scene"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_scene_clear_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_clear_step.hpp new file mode 100644 index 0000000..9610590 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_clear_step.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_scene_service.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowSceneClearStep final : public IWorkflowStep { +public: + WorkflowSceneClearStep(std::shared_ptr sceneService, + std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr sceneService_; + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_scene_load_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_load_step.cpp new file mode 100644 index 0000000..e507b8f --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_load_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_scene_load_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../../interfaces/scene_types.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowSceneLoadStep::WorkflowSceneLoadStep(std::shared_ptr sceneService, + std::shared_ptr logger) + : sceneService_(std::move(sceneService)), + logger_(std::move(logger)) {} + +std::string WorkflowSceneLoadStep::GetPluginId() const { + return "scene.load"; +} + +void WorkflowSceneLoadStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + if (!sceneService_) { + throw std::runtime_error("scene.load requires an ISceneService"); + } + + WorkflowStepIoResolver resolver; + const std::string objectsKey = resolver.GetRequiredInputKey(step, "objects"); + const auto* objects = context.TryGet>(objectsKey); + if (!objects) { + throw std::runtime_error("scene.load requires objects list input"); + } + + sceneService_->LoadScene(*objects); + + if (logger_) { + logger_->Trace("WorkflowSceneLoadStep", "Execute", + "objects=" + std::to_string(objects->size()), + "Loaded scene objects"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_scene_load_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_load_step.hpp new file mode 100644 index 0000000..bd7b0bc --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_load_step.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_scene_service.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowSceneLoadStep final : public IWorkflowStep { +public: + WorkflowSceneLoadStep(std::shared_ptr sceneService, + std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr sceneService_; + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_scene_set_active_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_set_active_step.cpp new file mode 100644 index 0000000..871217d --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_set_active_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_scene_set_active_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../../interfaces/scene_types.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowSceneSetActiveStep::WorkflowSceneSetActiveStep(std::shared_ptr sceneService, + std::shared_ptr logger) + : sceneService_(std::move(sceneService)), + logger_(std::move(logger)) {} + +std::string WorkflowSceneSetActiveStep::GetPluginId() const { + return "scene.set_active"; +} + +void WorkflowSceneSetActiveStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + if (!sceneService_) { + throw std::runtime_error("scene.set_active requires an ISceneService"); + } + + WorkflowStepIoResolver resolver; + const std::string objectsKey = resolver.GetRequiredInputKey(step, "objects"); + const auto* objects = context.TryGet>(objectsKey); + if (!objects) { + throw std::runtime_error("scene.set_active requires objects list input"); + } + + sceneService_->LoadScene(*objects); + + if (logger_) { + logger_->Trace("WorkflowSceneSetActiveStep", "Execute", + "objects=" + std::to_string(objects->size()), + "Set active scene"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_scene_set_active_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_set_active_step.hpp new file mode 100644 index 0000000..05d83dd --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_scene_set_active_step.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../../interfaces/i_logger.hpp" +#include "../../interfaces/i_scene_service.hpp" +#include "../../interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowSceneSetActiveStep final : public IWorkflowStep { +public: + WorkflowSceneSetActiveStep(std::shared_ptr sceneService, + std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr sceneService_; + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_concat_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_concat_step.cpp new file mode 100644 index 0000000..50a681b --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_concat_step.cpp @@ -0,0 +1,41 @@ +#include "workflow_string_concat_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringConcatStep::WorkflowStringConcatStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringConcatStep::GetPluginId() const { + return "string.concat"; +} + +void WorkflowStringConcatStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("string.concat requires string inputs"); + } + + context.Set(outputKey, *left + *right); + + if (logger_) { + logger_->Trace("WorkflowStringConcatStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Concatenated workflow strings"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_concat_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_concat_step.hpp new file mode 100644 index 0000000..bc28219 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_concat_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringConcatStep final : public IWorkflowStep { +public: + explicit WorkflowStringConcatStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_contains_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_contains_step.cpp new file mode 100644 index 0000000..bb0a8a4 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_contains_step.cpp @@ -0,0 +1,42 @@ +#include "workflow_string_contains_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringContainsStep::WorkflowStringContainsStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringContainsStep::GetPluginId() const { + return "string.contains"; +} + +void WorkflowStringContainsStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string needleKey = resolver.GetRequiredInputKey(step, "needle"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + const auto* needle = context.TryGet(needleKey); + if (!value || !needle) { + throw std::runtime_error("string.contains requires string inputs"); + } + + const bool result = value->find(*needle) != std::string::npos; + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowStringContainsStep", "Execute", + "input=" + valueKey + + ", needle=" + needleKey + + ", output=" + outputKey, + "Checked workflow string containment"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_contains_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_contains_step.hpp new file mode 100644 index 0000000..79cc1f9 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_contains_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringContainsStep final : public IWorkflowStep { +public: + explicit WorkflowStringContainsStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_equals_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_equals_step.cpp new file mode 100644 index 0000000..fcb7d3e --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_equals_step.cpp @@ -0,0 +1,42 @@ +#include "workflow_string_equals_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringEqualsStep::WorkflowStringEqualsStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringEqualsStep::GetPluginId() const { + return "string.equals"; +} + +void WorkflowStringEqualsStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string leftKey = resolver.GetRequiredInputKey(step, "left"); + const std::string rightKey = resolver.GetRequiredInputKey(step, "right"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* left = context.TryGet(leftKey); + const auto* right = context.TryGet(rightKey); + if (!left || !right) { + throw std::runtime_error("string.equals requires string inputs"); + } + + const bool result = (*left == *right); + context.Set(outputKey, result); + + if (logger_) { + logger_->Trace("WorkflowStringEqualsStep", "Execute", + "left=" + leftKey + + ", right=" + rightKey + + ", output=" + outputKey, + "Compared workflow strings for equality"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_equals_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_equals_step.hpp new file mode 100644 index 0000000..95fe62d --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_equals_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringEqualsStep final : public IWorkflowStep { +public: + explicit WorkflowStringEqualsStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_join_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_join_step.cpp new file mode 100644 index 0000000..514c8d4 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_join_step.cpp @@ -0,0 +1,48 @@ +#include "workflow_string_join_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringJoinStep::WorkflowStringJoinStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringJoinStep::GetPluginId() const { + return "string.join"; +} + +void WorkflowStringJoinStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string listKey = resolver.GetRequiredInputKey(step, "list"); + const std::string delimiterKey = resolver.GetRequiredInputKey(step, "delimiter"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* list = context.TryGet>(listKey); + const auto* delimiter = context.TryGet(delimiterKey); + if (!list || !delimiter) { + throw std::runtime_error("string.join requires list and delimiter inputs"); + } + + std::string result; + for (size_t i = 0; i < list->size(); ++i) { + if (i > 0) { + result += *delimiter; + } + result += (*list)[i]; + } + context.Set(outputKey, std::move(result)); + + if (logger_) { + logger_->Trace("WorkflowStringJoinStep", "Execute", + "input=" + listKey + + ", output=" + outputKey, + "Joined workflow strings"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_join_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_join_step.hpp new file mode 100644 index 0000000..b801c6f --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_join_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringJoinStep final : public IWorkflowStep { +public: + explicit WorkflowStringJoinStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_lower_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_lower_step.cpp new file mode 100644 index 0000000..faeaefd --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_lower_step.cpp @@ -0,0 +1,43 @@ +#include "workflow_string_lower_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringLowerStep::WorkflowStringLowerStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringLowerStep::GetPluginId() const { + return "string.lower"; +} + +void WorkflowStringLowerStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("string.lower requires string input"); + } + + std::string result = *value; + std::transform(result.begin(), result.end(), result.begin(), + [](unsigned char ch) { return static_cast(std::tolower(ch)); }); + context.Set(outputKey, std::move(result)); + + if (logger_) { + logger_->Trace("WorkflowStringLowerStep", "Execute", + "input=" + valueKey + + ", output=" + outputKey, + "Lowercased workflow string"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_lower_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_lower_step.hpp new file mode 100644 index 0000000..edb2abb --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_lower_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringLowerStep final : public IWorkflowStep { +public: + explicit WorkflowStringLowerStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_replace_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_replace_step.cpp new file mode 100644 index 0000000..8c79ce2 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_replace_step.cpp @@ -0,0 +1,53 @@ +#include "workflow_string_replace_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringReplaceStep::WorkflowStringReplaceStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringReplaceStep::GetPluginId() const { + return "string.replace"; +} + +void WorkflowStringReplaceStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string searchKey = resolver.GetRequiredInputKey(step, "search"); + const std::string replaceKey = resolver.GetRequiredInputKey(step, "replace"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + const auto* search = context.TryGet(searchKey); + const auto* replace = context.TryGet(replaceKey); + if (!value || !search || !replace) { + throw std::runtime_error("string.replace requires string inputs"); + } + + if (search->empty()) { + throw std::runtime_error("string.replace search string cannot be empty"); + } + + std::string result = *value; + size_t pos = 0; + while ((pos = result.find(*search, pos)) != std::string::npos) { + result.replace(pos, search->size(), *replace); + pos += replace->size(); + } + + context.Set(outputKey, std::move(result)); + + if (logger_) { + logger_->Trace("WorkflowStringReplaceStep", "Execute", + "input=" + valueKey + + ", output=" + outputKey, + "Replaced workflow string content"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_replace_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_replace_step.hpp new file mode 100644 index 0000000..c10385d --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_replace_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringReplaceStep final : public IWorkflowStep { +public: + explicit WorkflowStringReplaceStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_split_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_split_step.cpp new file mode 100644 index 0000000..2b69a38 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_split_step.cpp @@ -0,0 +1,52 @@ +#include "workflow_string_split_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringSplitStep::WorkflowStringSplitStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringSplitStep::GetPluginId() const { + return "string.split"; +} + +void WorkflowStringSplitStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string delimiterKey = resolver.GetRequiredInputKey(step, "delimiter"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "list"); + + const auto* value = context.TryGet(valueKey); + const auto* delimiter = context.TryGet(delimiterKey); + if (!value || !delimiter) { + throw std::runtime_error("string.split requires string inputs"); + } + if (delimiter->empty()) { + throw std::runtime_error("string.split delimiter cannot be empty"); + } + + std::vector parts; + size_t start = 0; + size_t pos = 0; + while ((pos = value->find(*delimiter, start)) != std::string::npos) { + parts.emplace_back(value->substr(start, pos - start)); + start = pos + delimiter->size(); + } + parts.emplace_back(value->substr(start)); + context.Set(outputKey, std::move(parts)); + + if (logger_) { + logger_->Trace("WorkflowStringSplitStep", "Execute", + "input=" + valueKey + + ", output=" + outputKey, + "Split workflow string"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_split_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_split_step.hpp new file mode 100644 index 0000000..b6ad05d --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_split_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringSplitStep final : public IWorkflowStep { +public: + explicit WorkflowStringSplitStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_trim_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_trim_step.cpp new file mode 100644 index 0000000..0aaf138 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_trim_step.cpp @@ -0,0 +1,47 @@ +#include "workflow_string_trim_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringTrimStep::WorkflowStringTrimStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringTrimStep::GetPluginId() const { + return "string.trim"; +} + +void WorkflowStringTrimStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("string.trim requires string input"); + } + + size_t start = 0; + size_t end = value->size(); + while (start < end && std::isspace(static_cast((*value)[start]))) { + ++start; + } + while (end > start && std::isspace(static_cast((*value)[end - 1]))) { + --end; + } + context.Set(outputKey, value->substr(start, end - start)); + + if (logger_) { + logger_->Trace("WorkflowStringTrimStep", "Execute", + "input=" + valueKey + + ", output=" + outputKey, + "Trimmed workflow string"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_trim_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_trim_step.hpp new file mode 100644 index 0000000..f7692b7 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_trim_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringTrimStep final : public IWorkflowStep { +public: + explicit WorkflowStringTrimStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_upper_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_upper_step.cpp new file mode 100644 index 0000000..766b62d --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_upper_step.cpp @@ -0,0 +1,43 @@ +#include "workflow_string_upper_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowStringUpperStep::WorkflowStringUpperStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowStringUpperStep::GetPluginId() const { + return "string.upper"; +} + +void WorkflowStringUpperStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string valueKey = resolver.GetRequiredInputKey(step, "value"); + const std::string outputKey = resolver.GetRequiredOutputKey(step, "value"); + + const auto* value = context.TryGet(valueKey); + if (!value) { + throw std::runtime_error("string.upper requires string input"); + } + + std::string result = *value; + std::transform(result.begin(), result.end(), result.begin(), + [](unsigned char ch) { return static_cast(std::toupper(ch)); }); + context.Set(outputKey, std::move(result)); + + if (logger_) { + logger_->Trace("WorkflowStringUpperStep", "Execute", + "input=" + valueKey + + ", output=" + outputKey, + "Uppercased workflow string"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_string_upper_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_string_upper_step.hpp new file mode 100644 index 0000000..591ec93 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_string_upper_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStringUpperStep final : public IWorkflowStep { +public: + explicit WorkflowStringUpperStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_exists_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_exists_step.cpp new file mode 100644 index 0000000..f39262a --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_exists_step.cpp @@ -0,0 +1,31 @@ +#include "workflow_value_assert_exists_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowValueAssertExistsStep::WorkflowValueAssertExistsStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowValueAssertExistsStep::GetPluginId() const { + return "value.assert.exists"; +} + +void WorkflowValueAssertExistsStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string inputKey = resolver.GetRequiredInputKey(step, "value"); + if (!context.Contains(inputKey)) { + throw std::runtime_error("value.assert.exists missing value '" + inputKey + "'"); + } + + if (logger_) { + logger_->Trace("WorkflowValueAssertExistsStep", "Execute", + "key=" + inputKey, + "Workflow value exists"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_exists_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_exists_step.hpp new file mode 100644 index 0000000..6603148 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_exists_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowValueAssertExistsStep final : public IWorkflowStep { +public: + explicit WorkflowValueAssertExistsStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_type_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_type_step.cpp new file mode 100644 index 0000000..c29b353 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_type_step.cpp @@ -0,0 +1,56 @@ +#include "workflow_value_assert_type_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../workflow_step_parameter_resolver.hpp" + +#include +#include +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowValueAssertTypeStep::WorkflowValueAssertTypeStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowValueAssertTypeStep::GetPluginId() const { + return "value.assert.type"; +} + +void WorkflowValueAssertTypeStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver ioResolver; + WorkflowStepParameterResolver parameterResolver; + const std::string inputKey = ioResolver.GetRequiredInputKey(step, "value"); + std::string type = parameterResolver.GetRequiredString(step, "type"); + std::transform(type.begin(), type.end(), type.begin(), + [](unsigned char ch) { return static_cast(std::tolower(ch)); }); + + if (!context.Contains(inputKey)) { + throw std::runtime_error("value.assert.type missing value '" + inputKey + "'"); + } + + if (type == "any") { + return; + } + + const bool matches = (type == "string" && context.TryGet(inputKey)) || + (type == "number" && context.TryGet(inputKey)) || + (type == "bool" && context.TryGet(inputKey)) || + (type == "string_list" && context.TryGet>(inputKey)) || + (type == "number_list" && context.TryGet>(inputKey)) || + (type == "path" && context.TryGet(inputKey)); + + if (!matches) { + throw std::runtime_error("value.assert.type mismatch for '" + inputKey + "', expected " + type); + } + + if (logger_) { + logger_->Trace("WorkflowValueAssertTypeStep", "Execute", + "key=" + inputKey + ", type=" + type, + "Workflow value type confirmed"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_type_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_type_step.hpp new file mode 100644 index 0000000..91ee7bd --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_value_assert_type_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowValueAssertTypeStep final : public IWorkflowStep { +public: + explicit WorkflowValueAssertTypeStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_value_clear_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_value_clear_step.cpp new file mode 100644 index 0000000..f0e189a --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_value_clear_step.cpp @@ -0,0 +1,29 @@ +#include "workflow_value_clear_step.hpp" + +#include "../workflow_step_io_resolver.hpp" + +#include + +namespace sdl3cpp::services::impl { + +WorkflowValueClearStep::WorkflowValueClearStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowValueClearStep::GetPluginId() const { + return "value.clear"; +} + +void WorkflowValueClearStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver resolver; + const std::string inputKey = resolver.GetRequiredInputKey(step, "value"); + const bool removed = context.Remove(inputKey); + + if (logger_) { + logger_->Trace("WorkflowValueClearStep", "Execute", + "key=" + inputKey + + ", removed=" + std::string(removed ? "true" : "false"), + "Cleared workflow value"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_value_clear_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_value_clear_step.hpp new file mode 100644 index 0000000..b22122a --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_value_clear_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowValueClearStep final : public IWorkflowStep { +public: + explicit WorkflowValueClearStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_value_literal_step.cpp b/src/services/impl/workflow/workflow_generic_steps/workflow_value_literal_step.cpp new file mode 100644 index 0000000..6bfb4af --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_value_literal_step.cpp @@ -0,0 +1,51 @@ +#include "workflow_value_literal_step.hpp" + +#include "../workflow_step_io_resolver.hpp" +#include "../workflow_step_parameter_resolver.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +WorkflowValueLiteralStep::WorkflowValueLiteralStep(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +std::string WorkflowValueLiteralStep::GetPluginId() const { + return "value.literal"; +} + +void WorkflowValueLiteralStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) { + WorkflowStepIoResolver ioResolver; + WorkflowStepParameterResolver parameterResolver; + const std::string outputKey = ioResolver.GetRequiredOutputKey(step, "value"); + const auto& parameter = parameterResolver.GetRequiredParameter(step, "value"); + + switch (parameter.type) { + case WorkflowParameterValue::Type::String: + context.Set(outputKey, parameter.stringValue); + break; + case WorkflowParameterValue::Type::Number: + context.Set(outputKey, parameter.numberValue); + break; + case WorkflowParameterValue::Type::Bool: + context.Set(outputKey, parameter.boolValue); + break; + case WorkflowParameterValue::Type::StringList: + context.Set(outputKey, parameter.stringList); + break; + case WorkflowParameterValue::Type::NumberList: + context.Set(outputKey, parameter.numberList); + break; + default: + throw std::runtime_error("value.literal parameter type unsupported"); + } + + if (logger_) { + logger_->Trace("WorkflowValueLiteralStep", "Execute", + "output=" + outputKey, + "Set literal workflow value"); + } +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_generic_steps/workflow_value_literal_step.hpp b/src/services/impl/workflow/workflow_generic_steps/workflow_value_literal_step.hpp new file mode 100644 index 0000000..0e3df41 --- /dev/null +++ b/src/services/impl/workflow/workflow_generic_steps/workflow_value_literal_step.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "services/interfaces/i_logger.hpp" +#include "services/interfaces/i_workflow_step.hpp" + +#include + +namespace sdl3cpp::services::impl { + +class WorkflowValueLiteralStep final : public IWorkflowStep { +public: + explicit WorkflowValueLiteralStep(std::shared_ptr logger); + + std::string GetPluginId() const override; + void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override; + +private: + std::shared_ptr logger_; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_mesh_payload_converter.cpp b/src/services/impl/workflow/workflow_mesh_payload_converter.cpp new file mode 100644 index 0000000..91fa55f --- /dev/null +++ b/src/services/impl/workflow/workflow_mesh_payload_converter.cpp @@ -0,0 +1,45 @@ +#include "workflow_mesh_payload_converter.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +MeshPayloadConversionResult ConvertMeshPayload(const MeshPayload& payload) { + MeshPayloadConversionResult result; + const size_t vertexCount = payload.positions.size(); + result.vertices.reserve(vertexCount); + + for (size_t i = 0; i < vertexCount; ++i) { + core::Vertex vertex{}; + vertex.position = payload.positions[i]; + if (i < payload.normals.size()) { + vertex.normal = payload.normals[i]; + } + if (i < payload.tangents.size()) { + vertex.tangent = payload.tangents[i]; + } + if (i < payload.texcoords.size()) { + vertex.texcoord = payload.texcoords[i]; + } + if (i < payload.colors.size()) { + vertex.color = payload.colors[i]; + } else { + vertex.color = {1.0f, 1.0f, 1.0f}; + } + result.vertices.push_back(vertex); + } + + constexpr uint32_t kMaxIndex = std::numeric_limits::max(); + result.indices.reserve(payload.indices.size()); + for (uint32_t index : payload.indices) { + if (index > kMaxIndex) { + throw std::runtime_error("Mesh indices exceed uint16_t range"); + } + result.indices.push_back(static_cast(index)); + } + + return result; +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_mesh_payload_converter.hpp b/src/services/impl/workflow/workflow_mesh_payload_converter.hpp new file mode 100644 index 0000000..70feff0 --- /dev/null +++ b/src/services/impl/workflow/workflow_mesh_payload_converter.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "../interfaces/mesh_types.hpp" +#include "../../core/vertex.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +struct MeshPayloadConversionResult { + std::vector vertices; + std::vector indices; +}; + +MeshPayloadConversionResult ConvertMeshPayload(const MeshPayload& payload); + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_soundboard_catalog_scan_step.cpp b/src/services/impl/workflow/workflow_soundboard_catalog_scan_step.cpp index 287fc75..a2481f0 100644 --- a/src/services/impl/workflow/workflow_soundboard_catalog_scan_step.cpp +++ b/src/services/impl/workflow/workflow_soundboard_catalog_scan_step.cpp @@ -1,7 +1,7 @@ #include "workflow_soundboard_catalog_scan_step.hpp" #include "../config/json_config_document_parser.hpp" -#include "../soundboard_path_resolver.hpp" +#include "../soundboard/soundboard_path_resolver.hpp" #include "workflow_step_io_resolver.hpp" #include diff --git a/src/services/impl/workflow/workflow_soundboard_gui_step.cpp b/src/services/impl/workflow/workflow_soundboard_gui_step.cpp index 280b8e3..a54145b 100644 --- a/src/services/impl/workflow/workflow_soundboard_gui_step.cpp +++ b/src/services/impl/workflow/workflow_soundboard_gui_step.cpp @@ -1,7 +1,7 @@ #include "workflow_soundboard_gui_step.hpp" #include "../config/json_config_document_parser.hpp" -#include "../soundboard_path_resolver.hpp" +#include "../soundboard/soundboard_path_resolver.hpp" #include "workflow_step_io_resolver.hpp" #include diff --git a/src/services/impl/workflow/workflow_step_parameter_resolver.cpp b/src/services/impl/workflow/workflow_step_parameter_resolver.cpp new file mode 100644 index 0000000..f9f8e6d --- /dev/null +++ b/src/services/impl/workflow/workflow_step_parameter_resolver.cpp @@ -0,0 +1,74 @@ +#include "workflow_step_parameter_resolver.hpp" + +#include + +namespace sdl3cpp::services::impl { + +const WorkflowParameterValue* WorkflowStepParameterResolver::FindParameter( + const WorkflowStepDefinition& step, + const std::string& name) const { + auto it = step.parameters.find(name); + if (it == step.parameters.end()) { + return nullptr; + } + return &it->second; +} + +const WorkflowParameterValue& WorkflowStepParameterResolver::GetRequiredParameter( + const WorkflowStepDefinition& step, + const std::string& name) const { + const auto* param = FindParameter(step, name); + if (!param) { + throw std::runtime_error("Workflow step '" + step.id + "' missing parameter '" + name + "'"); + } + return *param; +} + +std::string WorkflowStepParameterResolver::GetRequiredString(const WorkflowStepDefinition& step, + const std::string& name) const { + const auto& param = GetRequiredParameter(step, name); + if (param.type != WorkflowParameterValue::Type::String) { + throw std::runtime_error("Workflow step '" + step.id + "' parameter '" + name + "' must be a string"); + } + return param.stringValue; +} + +double WorkflowStepParameterResolver::GetRequiredNumber(const WorkflowStepDefinition& step, + const std::string& name) const { + const auto& param = GetRequiredParameter(step, name); + if (param.type != WorkflowParameterValue::Type::Number) { + throw std::runtime_error("Workflow step '" + step.id + "' parameter '" + name + "' must be a number"); + } + return param.numberValue; +} + +bool WorkflowStepParameterResolver::GetRequiredBool(const WorkflowStepDefinition& step, + const std::string& name) const { + const auto& param = GetRequiredParameter(step, name); + if (param.type != WorkflowParameterValue::Type::Bool) { + throw std::runtime_error("Workflow step '" + step.id + "' parameter '" + name + "' must be a bool"); + } + return param.boolValue; +} + +std::vector WorkflowStepParameterResolver::GetRequiredStringList( + const WorkflowStepDefinition& step, + const std::string& name) const { + const auto& param = GetRequiredParameter(step, name); + if (param.type != WorkflowParameterValue::Type::StringList) { + throw std::runtime_error("Workflow step '" + step.id + "' parameter '" + name + "' must be string list"); + } + return param.stringList; +} + +std::vector WorkflowStepParameterResolver::GetRequiredNumberList( + const WorkflowStepDefinition& step, + const std::string& name) const { + const auto& param = GetRequiredParameter(step, name); + if (param.type != WorkflowParameterValue::Type::NumberList) { + throw std::runtime_error("Workflow step '" + step.id + "' parameter '" + name + "' must be number list"); + } + return param.numberList; +} + +} // namespace sdl3cpp::services::impl diff --git a/src/services/impl/workflow/workflow_step_parameter_resolver.hpp b/src/services/impl/workflow/workflow_step_parameter_resolver.hpp new file mode 100644 index 0000000..c651c78 --- /dev/null +++ b/src/services/impl/workflow/workflow_step_parameter_resolver.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "services/interfaces/workflow_step_definition.hpp" + +#include +#include + +namespace sdl3cpp::services::impl { + +class WorkflowStepParameterResolver { +public: + const WorkflowParameterValue* FindParameter(const WorkflowStepDefinition& step, + const std::string& name) const; + const WorkflowParameterValue& GetRequiredParameter(const WorkflowStepDefinition& step, + const std::string& name) const; + std::string GetRequiredString(const WorkflowStepDefinition& step, const std::string& name) const; + double GetRequiredNumber(const WorkflowStepDefinition& step, const std::string& name) const; + bool GetRequiredBool(const WorkflowStepDefinition& step, const std::string& name) const; + std::vector GetRequiredStringList(const WorkflowStepDefinition& step, + const std::string& name) const; + std::vector GetRequiredNumberList(const WorkflowStepDefinition& step, + const std::string& name) const; +}; + +} // namespace sdl3cpp::services::impl diff --git a/src/services/interfaces/camera_types.hpp b/src/services/interfaces/camera_types.hpp new file mode 100644 index 0000000..c420123 --- /dev/null +++ b/src/services/interfaces/camera_types.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace sdl3cpp::services { + +struct CameraPose { + std::array position{0.0f, 0.0f, 5.0f}; + std::array lookAt{0.0f, 0.0f, 0.0f}; + std::array up{0.0f, 1.0f, 0.0f}; + float fovDegrees = 60.0f; + float nearPlane = 0.1f; + float farPlane = 1000.0f; +}; + +} // namespace sdl3cpp::services diff --git a/src/services/interfaces/scene_types.hpp b/src/services/interfaces/scene_types.hpp index b24b3de..8806093 100644 --- a/src/services/interfaces/scene_types.hpp +++ b/src/services/interfaces/scene_types.hpp @@ -1,6 +1,7 @@ #pragma once #include "../../core/vertex.hpp" +#include #include #include #include @@ -11,6 +12,13 @@ struct SceneObject { std::vector vertices; std::vector indices; int computeModelMatrixRef = -1; + std::array modelMatrix = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + bool hasCustomModelMatrix = false; std::vector shaderKeys; std::string objectType; // Semantic object type (e.g., "lantern", "physics_cube", "floor") }; diff --git a/src/services/interfaces/workflow_context.hpp b/src/services/interfaces/workflow_context.hpp index d2e035b..191b3e3 100644 --- a/src/services/interfaces/workflow_context.hpp +++ b/src/services/interfaces/workflow_context.hpp @@ -18,6 +18,10 @@ public: return values_.find(key) != values_.end(); } + bool Remove(const std::string& key) { + return values_.erase(key) > 0u; + } + template const T* TryGet(const std::string& key) const { auto it = values_.find(key); diff --git a/src/services/interfaces/workflow_parameter_value.hpp b/src/services/interfaces/workflow_parameter_value.hpp new file mode 100644 index 0000000..c3d1d45 --- /dev/null +++ b/src/services/interfaces/workflow_parameter_value.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +namespace sdl3cpp::services { + +struct WorkflowParameterValue { + enum class Type { + String, + Number, + Bool, + StringList, + NumberList + }; + + Type type = Type::String; + std::string stringValue; + double numberValue = 0.0; + bool boolValue = false; + std::vector stringList; + std::vector numberList; + + static WorkflowParameterValue FromString(std::string value) { + WorkflowParameterValue param; + param.type = Type::String; + param.stringValue = std::move(value); + return param; + } + + static WorkflowParameterValue FromNumber(double value) { + WorkflowParameterValue param; + param.type = Type::Number; + param.numberValue = value; + return param; + } + + static WorkflowParameterValue FromBool(bool value) { + WorkflowParameterValue param; + param.type = Type::Bool; + param.boolValue = value; + return param; + } + + static WorkflowParameterValue FromStringList(std::vector value) { + WorkflowParameterValue param; + param.type = Type::StringList; + param.stringList = std::move(value); + return param; + } + + static WorkflowParameterValue FromNumberList(std::vector value) { + WorkflowParameterValue param; + param.type = Type::NumberList; + param.numberList = std::move(value); + return param; + } +}; + +} // namespace sdl3cpp::services diff --git a/src/services/interfaces/workflow_step_definition.hpp b/src/services/interfaces/workflow_step_definition.hpp index e9c253a..77fabcc 100644 --- a/src/services/interfaces/workflow_step_definition.hpp +++ b/src/services/interfaces/workflow_step_definition.hpp @@ -1,5 +1,7 @@ #pragma once +#include "workflow_parameter_value.hpp" + #include #include @@ -10,6 +12,7 @@ struct WorkflowStepDefinition { std::string plugin; std::unordered_map inputs; std::unordered_map outputs; + std::unordered_map parameters; }; } // namespace sdl3cpp::services diff --git a/tests/bgfx_backend_frame_guard_test.cpp b/tests/bgfx_backend_frame_guard_test.cpp index ef2a0c2..3776565 100644 --- a/tests/bgfx_backend_frame_guard_test.cpp +++ b/tests/bgfx_backend_frame_guard_test.cpp @@ -1,6 +1,6 @@ #include -#include "services/impl/bgfx_graphics_backend.hpp" +#include "services/impl/graphics/bgfx_graphics_backend.hpp" #include "services/interfaces/i_logger.hpp" #include diff --git a/tests/bgfx_draw_bounds_crash_test.cpp b/tests/bgfx_draw_bounds_crash_test.cpp index cff6e1f..65de493 100644 --- a/tests/bgfx_draw_bounds_crash_test.cpp +++ b/tests/bgfx_draw_bounds_crash_test.cpp @@ -161,7 +161,7 @@ TEST(BgfxDrawBoundsCrashTest, ValidDrawParameters_ShouldPass) { // TEST 6: Document what needs to be added to BgfxGraphicsBackend::Draw() TEST(BgfxDrawBoundsCrashTest, RequiredImplementation) { - // File: src/services/impl/bgfx_graphics_backend.cpp + // File: src/services/impl/graphics/bgfx_graphics_backend.cpp // Function: BgfxGraphicsBackend::Draw (lines ~1093-1145) // // REQUIRED CHANGES: diff --git a/tests/bgfx_draw_bounds_validation_test.cpp b/tests/bgfx_draw_bounds_validation_test.cpp index 30f808c..902ccdb 100644 --- a/tests/bgfx_draw_bounds_validation_test.cpp +++ b/tests/bgfx_draw_bounds_validation_test.cpp @@ -163,7 +163,7 @@ TEST(BgfxDrawBoundsValidationTest, NegativeVertexOffset) { // Test 7: Document the fix needed in BgfxGraphicsBackend::Draw TEST(BgfxDrawBoundsValidationTest, RequiredValidations) { - // File: src/services/impl/bgfx_graphics_backend.cpp + // File: src/services/impl/graphics/bgfx_graphics_backend.cpp // Function: BgfxGraphicsBackend::Draw (lines ~1093-1145) // // Missing validations: diff --git a/tests/bgfx_gui_budget_enforcement_test.cpp b/tests/bgfx_gui_budget_enforcement_test.cpp index 255bff1..5508ca2 100644 --- a/tests/bgfx_gui_budget_enforcement_test.cpp +++ b/tests/bgfx_gui_budget_enforcement_test.cpp @@ -1,6 +1,6 @@ #include -#include "services/impl/bgfx_gui_service.hpp" +#include "services/impl/gui/bgfx_gui_service.hpp" #include "services/interfaces/i_logger.hpp" namespace sdl3cpp::services::impl { diff --git a/tests/bgfx_texture_budget_tracker_test.cpp b/tests/bgfx_texture_budget_tracker_test.cpp index c9005b8..8f8a0e3 100644 --- a/tests/bgfx_texture_budget_tracker_test.cpp +++ b/tests/bgfx_texture_budget_tracker_test.cpp @@ -1,6 +1,6 @@ #include -#include "services/impl/bgfx_graphics_backend.hpp" +#include "services/impl/graphics/bgfx_graphics_backend.hpp" #include "services/interfaces/i_logger.hpp" namespace sdl3cpp::services::impl { diff --git a/tests/crash_recovery_timeout_test.cpp b/tests/crash_recovery_timeout_test.cpp index 91e41cc..7b5cacb 100644 --- a/tests/crash_recovery_timeout_test.cpp +++ b/tests/crash_recovery_timeout_test.cpp @@ -1,6 +1,6 @@ #include -#include "services/impl/crash_recovery_service.hpp" +#include "services/impl/diagnostics/crash_recovery_service.hpp" #include #include diff --git a/tests/graphics_service_buffer_lifecycle_test.cpp b/tests/graphics_service_buffer_lifecycle_test.cpp index 5a1cb94..61ef653 100644 --- a/tests/graphics_service_buffer_lifecycle_test.cpp +++ b/tests/graphics_service_buffer_lifecycle_test.cpp @@ -1,6 +1,6 @@ #include -#include "services/impl/graphics_service.hpp" +#include "services/impl/graphics/graphics_service.hpp" #include "services/interfaces/i_graphics_backend.hpp" #include "services/interfaces/i_logger.hpp" #include "services/interfaces/i_window_service.hpp" diff --git a/tests/gui_script_service_missing_fields_test.cpp b/tests/gui_script_service_missing_fields_test.cpp index 8864dad..cfb79f8 100644 --- a/tests/gui_script_service_missing_fields_test.cpp +++ b/tests/gui_script_service_missing_fields_test.cpp @@ -1,6 +1,6 @@ #include -#include "services/impl/gui_script_service.hpp" +#include "services/impl/script/gui_script_service.hpp" #include "services/interfaces/i_logger.hpp" #include "services/interfaces/i_script_engine_service.hpp" diff --git a/tests/materialx_shader_generator_integration_test.cpp b/tests/materialx_shader_generator_integration_test.cpp index d075dcf..aa2bd15 100644 --- a/tests/materialx_shader_generator_integration_test.cpp +++ b/tests/materialx_shader_generator_integration_test.cpp @@ -1,5 +1,5 @@ -#include "services/impl/materialx_shader_generator.hpp" -#include "services/impl/shader_pipeline_validator.hpp" +#include "services/impl/materialx/materialx_shader_generator.hpp" +#include "services/impl/shader/shader_pipeline_validator.hpp" #include "services/interfaces/i_logger.hpp" #include "core/vertex.hpp" #include diff --git a/tests/render_coordinator_init_order_test.cpp b/tests/render_coordinator_init_order_test.cpp index 58f5edd..7bf050b 100644 --- a/tests/render_coordinator_init_order_test.cpp +++ b/tests/render_coordinator_init_order_test.cpp @@ -1,6 +1,6 @@ #include -#include "services/impl/render_coordinator_service.hpp" +#include "services/impl/render/render_coordinator_service.hpp" #include "services/interfaces/i_config_compiler_service.hpp" #include "services/interfaces/i_config_service.hpp" #include "services/interfaces/i_graphics_service.hpp" diff --git a/tests/render_graph_service_test.cpp b/tests/render_graph_service_test.cpp index df01d89..e51b196 100644 --- a/tests/render_graph_service_test.cpp +++ b/tests/render_graph_service_test.cpp @@ -1,6 +1,6 @@ #include -#include "services/impl/render_graph_service.hpp" +#include "services/impl/render/render_graph_service.hpp" namespace { diff --git a/tests/shader_pipeline_validator_test.cpp b/tests/shader_pipeline_validator_test.cpp index 8b6a1f9..d5dcada 100644 --- a/tests/shader_pipeline_validator_test.cpp +++ b/tests/shader_pipeline_validator_test.cpp @@ -1,4 +1,4 @@ -#include "services/impl/shader_pipeline_validator.hpp" +#include "services/impl/shader/shader_pipeline_validator.hpp" #include "services/interfaces/i_logger.hpp" #include "core/vertex.hpp" #include diff --git a/tests/shader_system_registry_test.cpp b/tests/shader_system_registry_test.cpp index ac48392..8326922 100644 --- a/tests/shader_system_registry_test.cpp +++ b/tests/shader_system_registry_test.cpp @@ -1,7 +1,7 @@ #include #include "services/impl/config/config_compiler_service.hpp" -#include "services/impl/shader_system_registry.hpp" +#include "services/impl/shader/shader_system_registry.hpp" #include diff --git a/tests/test_bgfx_gui_service.cpp b/tests/test_bgfx_gui_service.cpp index bcedda2..a26e530 100644 --- a/tests/test_bgfx_gui_service.cpp +++ b/tests/test_bgfx_gui_service.cpp @@ -1,4 +1,4 @@ -#include "services/impl/bgfx_gui_service.hpp" +#include "services/impl/gui/bgfx_gui_service.hpp" #include "services/interfaces/gui_types.hpp" #include "services/interfaces/i_config_service.hpp" diff --git a/tests/test_cube_script.cpp b/tests/test_cube_script.cpp index c89fe43..630d97d 100644 --- a/tests/test_cube_script.cpp +++ b/tests/test_cube_script.cpp @@ -1,16 +1,16 @@ -#include "services/impl/bgfx_graphics_backend.hpp" -#include "services/impl/logger_service.hpp" -#include "services/impl/mesh_service.hpp" -#include "services/impl/pipeline_compiler_service.hpp" -#include "services/impl/physics_bridge_service.hpp" -#include "services/impl/platform_service.hpp" -#include "services/impl/script_engine_service.hpp" -#include "services/impl/scene_script_service.hpp" -#include "services/impl/shader_script_service.hpp" -#include "services/impl/shader_system_registry.hpp" -#include "services/impl/ecs_service.hpp" -#include "services/impl/scene_service.hpp" -#include "services/impl/sdl_window_service.hpp" +#include "services/impl/graphics/bgfx_graphics_backend.hpp" +#include "services/impl/diagnostics/logger_service.hpp" +#include "services/impl/scene/mesh_service.hpp" +#include "services/impl/shader/pipeline_compiler_service.hpp" +#include "services/impl/scene/physics_bridge_service.hpp" +#include "services/impl/platform/platform_service.hpp" +#include "services/impl/script/script_engine_service.hpp" +#include "services/impl/script/scene_script_service.hpp" +#include "services/impl/script/shader_script_service.hpp" +#include "services/impl/shader/shader_system_registry.hpp" +#include "services/impl/scene/ecs_service.hpp" +#include "services/impl/scene/scene_service.hpp" +#include "services/impl/platform/sdl_window_service.hpp" #include "services/interfaces/i_audio_command_service.hpp" #include "services/interfaces/i_config_service.hpp" #include "events/event_bus.hpp" diff --git a/tests/test_gxm_backend.cpp b/tests/test_gxm_backend.cpp index 316679e..ec69968 100644 --- a/tests/test_gxm_backend.cpp +++ b/tests/test_gxm_backend.cpp @@ -1,4 +1,4 @@ -#include "services/impl/gxm_graphics_backend.hpp" +#include "services/impl/graphics/gxm_graphics_backend.hpp" #include #include #include diff --git a/tests/test_vulkan_shader_linking.cpp b/tests/test_vulkan_shader_linking.cpp index 00d210c..c7c8328 100644 --- a/tests/test_vulkan_shader_linking.cpp +++ b/tests/test_vulkan_shader_linking.cpp @@ -1,9 +1,9 @@ -#include "services/impl/bgfx_graphics_backend.hpp" -#include "services/impl/bgfx_gui_service.hpp" +#include "services/impl/graphics/bgfx_graphics_backend.hpp" +#include "services/impl/gui/bgfx_gui_service.hpp" #include "services/impl/config/json_config_service.hpp" -#include "services/impl/platform_service.hpp" -#include "services/impl/sdl_window_service.hpp" -#include "services/impl/pipeline_compiler_service.hpp" +#include "services/impl/platform/platform_service.hpp" +#include "services/impl/platform/sdl_window_service.hpp" +#include "services/impl/shader/pipeline_compiler_service.hpp" #include "services/interfaces/i_logger.hpp" #include "services/interfaces/gui_types.hpp" #include "events/event_bus.hpp"