mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
ROADMAP.md
This commit is contained in:
@@ -302,6 +302,7 @@ set(WORKFLOW_SOURCES
|
||||
|
||||
set(FRAME_WORKFLOW_SOURCES
|
||||
src/services/impl/workflow_frame_begin_step.cpp
|
||||
src/services/impl/workflow_frame_camera_step.cpp
|
||||
src/services/impl/workflow_frame_bullet_physics_step.cpp
|
||||
src/services/impl/workflow_frame_physics_step.cpp
|
||||
src/services/impl/workflow_frame_scene_step.cpp
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
"position": [260, 0],
|
||||
"inputs": {
|
||||
"delta": "frame.delta"
|
||||
},
|
||||
"outputs": {
|
||||
"view_state": "frame.view_state"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -39,7 +42,8 @@
|
||||
"plugin": "frame.render",
|
||||
"position": [1040, 0],
|
||||
"inputs": {
|
||||
"elapsed": "frame.elapsed"
|
||||
"elapsed": "frame.elapsed",
|
||||
"view_state": "frame.view_state"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -307,6 +307,7 @@ void ServiceBasedApp::RegisterServices() {
|
||||
|
||||
registry_.RegisterService<services::IFrameWorkflowService, services::impl::FrameWorkflowService>(
|
||||
registry_.GetService<services::ILogger>(),
|
||||
registry_.GetService<services::IConfigService>(),
|
||||
registry_.GetService<services::IAudioService>(),
|
||||
registry_.GetService<services::IInputService>(),
|
||||
registry_.GetService<services::IPhysicsService>(),
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
FrameWorkflowService::FrameWorkflowService(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IConfigService> configService,
|
||||
std::shared_ptr<IAudioService> audioService,
|
||||
std::shared_ptr<IInputService> inputService,
|
||||
std::shared_ptr<IPhysicsService> physicsService,
|
||||
@@ -27,6 +28,7 @@ FrameWorkflowService::FrameWorkflowService(std::shared_ptr<ILogger> logger,
|
||||
workflow_ = parser.ParseFile(path);
|
||||
|
||||
FrameWorkflowStepRegistrar registrar(logger_,
|
||||
std::move(configService),
|
||||
std::move(audioService),
|
||||
std::move(inputService),
|
||||
std::move(physicsService),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../interfaces/i_frame_workflow_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../interfaces/i_audio_service.hpp"
|
||||
#include "../interfaces/i_config_service.hpp"
|
||||
#include "../interfaces/i_input_service.hpp"
|
||||
#include "../interfaces/i_physics_service.hpp"
|
||||
#include "../interfaces/i_render_coordinator_service.hpp"
|
||||
@@ -21,6 +22,7 @@ namespace sdl3cpp::services::impl {
|
||||
class FrameWorkflowService final : public IFrameWorkflowService {
|
||||
public:
|
||||
FrameWorkflowService(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IConfigService> configService,
|
||||
std::shared_ptr<IAudioService> audioService,
|
||||
std::shared_ptr<IInputService> inputService,
|
||||
std::shared_ptr<IPhysicsService> physicsService,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "workflow_frame_audio_step.hpp"
|
||||
#include "workflow_frame_begin_step.hpp"
|
||||
#include "workflow_frame_camera_step.hpp"
|
||||
#include "workflow_frame_bullet_physics_step.hpp"
|
||||
#include "workflow_frame_gui_step.hpp"
|
||||
#include "workflow_frame_physics_step.hpp"
|
||||
@@ -16,6 +17,7 @@
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
FrameWorkflowStepRegistrar::FrameWorkflowStepRegistrar(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IConfigService> configService,
|
||||
std::shared_ptr<IAudioService> audioService,
|
||||
std::shared_ptr<IInputService> inputService,
|
||||
std::shared_ptr<IPhysicsService> physicsService,
|
||||
@@ -23,6 +25,7 @@ FrameWorkflowStepRegistrar::FrameWorkflowStepRegistrar(std::shared_ptr<ILogger>
|
||||
std::shared_ptr<IRenderCoordinatorService> renderService,
|
||||
std::shared_ptr<IValidationTourService> validationTourService)
|
||||
: logger_(std::move(logger)),
|
||||
configService_(std::move(configService)),
|
||||
audioService_(std::move(audioService)),
|
||||
inputService_(std::move(inputService)),
|
||||
physicsService_(std::move(physicsService)),
|
||||
@@ -50,6 +53,9 @@ void FrameWorkflowStepRegistrar::RegisterUsedSteps(
|
||||
if (plugins.contains("frame.bullet_physics")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowFrameBulletPhysicsStep>(physicsService_, logger_));
|
||||
}
|
||||
if (plugins.contains("frame.camera")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowFrameCameraStep>(configService_, logger_));
|
||||
}
|
||||
if (plugins.contains("frame.scene")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowFrameSceneStep>(sceneService_, logger_));
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
namespace sdl3cpp::services {
|
||||
class IAudioService;
|
||||
class IConfigService;
|
||||
class IInputService;
|
||||
class IPhysicsService;
|
||||
class IRenderCoordinatorService;
|
||||
@@ -20,6 +21,7 @@ namespace sdl3cpp::services::impl {
|
||||
class FrameWorkflowStepRegistrar {
|
||||
public:
|
||||
FrameWorkflowStepRegistrar(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IConfigService> configService,
|
||||
std::shared_ptr<IAudioService> audioService,
|
||||
std::shared_ptr<IInputService> inputService,
|
||||
std::shared_ptr<IPhysicsService> physicsService,
|
||||
@@ -32,6 +34,7 @@ public:
|
||||
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
std::shared_ptr<IConfigService> configService_;
|
||||
std::shared_ptr<IAudioService> audioService_;
|
||||
std::shared_ptr<IInputService> inputService_;
|
||||
std::shared_ptr<IPhysicsService> physicsService_;
|
||||
|
||||
@@ -132,6 +132,14 @@ void RenderCoordinatorService::ConfigureRenderGraphPasses() {
|
||||
}
|
||||
|
||||
void RenderCoordinatorService::RenderFrame(float time) {
|
||||
RenderFrameInternal(time, nullptr);
|
||||
}
|
||||
|
||||
void RenderCoordinatorService::RenderFrameWithViewState(float time, const ViewState& viewState) {
|
||||
RenderFrameInternal(time, &viewState);
|
||||
}
|
||||
|
||||
void RenderCoordinatorService::RenderFrameInternal(float time, const ViewState* overrideView) {
|
||||
if (logger_) {
|
||||
logger_->Trace("RenderCoordinatorService", "RenderFrame", "time=" + std::to_string(time), "Entering");
|
||||
}
|
||||
@@ -244,7 +252,7 @@ void RenderCoordinatorService::RenderFrame(float time) {
|
||||
validationPlan = validationTourService_->BeginFrame(aspect);
|
||||
}
|
||||
|
||||
ViewState viewState = sceneScriptService_->GetViewState(aspect);
|
||||
ViewState viewState = overrideView ? *overrideView : sceneScriptService_->GetViewState(aspect);
|
||||
if (validationPlan.active && validationPlan.overrideView) {
|
||||
viewState = validationPlan.viewState;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ public:
|
||||
~RenderCoordinatorService() override = default;
|
||||
|
||||
void RenderFrame(float time) override;
|
||||
void RenderFrameWithViewState(float time, const ViewState& viewState) override;
|
||||
|
||||
private:
|
||||
void ConfigureRenderGraphPasses();
|
||||
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
std::shared_ptr<IConfigService> configService_;
|
||||
@@ -49,6 +49,9 @@ private:
|
||||
bool shadersLoaded_ = false;
|
||||
bool geometryUploaded_ = false;
|
||||
bool configFirstLogged_ = false;
|
||||
|
||||
void ConfigureRenderGraphPasses();
|
||||
void RenderFrameInternal(float time, const ViewState* overrideView);
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
|
||||
160
src/services/impl/workflow_frame_camera_step.cpp
Normal file
160
src/services/impl/workflow_frame_camera_step.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#include "workflow_frame_camera_step.hpp"
|
||||
#include "workflow_step_io_resolver.hpp"
|
||||
|
||||
#include "../interfaces/graphics_types.hpp"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
namespace {
|
||||
|
||||
struct CameraConfig {
|
||||
std::array<float, 3> position{0.0f, 0.0f, 5.0f};
|
||||
std::array<float, 3> lookAt{0.0f, 0.0f, 0.0f};
|
||||
std::array<float, 3> up{0.0f, 1.0f, 0.0f};
|
||||
float fov = 0.78f;
|
||||
float nearPlane = 0.1f;
|
||||
float farPlane = 1000.0f;
|
||||
};
|
||||
|
||||
std::array<float, 16> ToArray(const glm::mat4& matrix) {
|
||||
std::array<float, 16> result{};
|
||||
std::memcpy(result.data(), glm::value_ptr(matrix), sizeof(float) * result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ReadVec3(const rapidjson::Value& object, const char* name, std::array<float, 3>& out) {
|
||||
if (!object.HasMember(name)) {
|
||||
return false;
|
||||
}
|
||||
const auto& value = object[name];
|
||||
if (!value.IsArray() || value.Size() != 3) {
|
||||
throw std::runtime_error(std::string("frame.camera: '") + name + "' must be a 3-element array");
|
||||
}
|
||||
for (rapidjson::SizeType i = 0; i < 3; ++i) {
|
||||
if (!value[i].IsNumber()) {
|
||||
throw std::runtime_error(std::string("frame.camera: '") + name + "' must contain numbers");
|
||||
}
|
||||
out[i] = static_cast<float>(value[i].GetDouble());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadNumber(const rapidjson::Value& object, const char* name, float& out) {
|
||||
if (!object.HasMember(name)) {
|
||||
return false;
|
||||
}
|
||||
const auto& value = object[name];
|
||||
if (!value.IsNumber()) {
|
||||
throw std::runtime_error(std::string("frame.camera: '") + name + "' must be a number");
|
||||
}
|
||||
out = static_cast<float>(value.GetDouble());
|
||||
return true;
|
||||
}
|
||||
|
||||
CameraConfig ReadCameraConfig(const std::string& json) {
|
||||
rapidjson::Document document;
|
||||
document.Parse(json.c_str());
|
||||
if (document.HasParseError()) {
|
||||
throw std::runtime_error("frame.camera: failed to parse config JSON");
|
||||
}
|
||||
CameraConfig config{};
|
||||
if (!document.HasMember("scene") || !document["scene"].IsObject()) {
|
||||
return config;
|
||||
}
|
||||
const auto& scene = document["scene"];
|
||||
if (!scene.HasMember("camera") || !scene["camera"].IsObject()) {
|
||||
return config;
|
||||
}
|
||||
const auto& camera = scene["camera"];
|
||||
ReadVec3(camera, "position", config.position);
|
||||
bool hasLookAt = ReadVec3(camera, "look_at", config.lookAt);
|
||||
if (!hasLookAt && camera.HasMember("lookAt")) {
|
||||
ReadVec3(camera, "lookAt", config.lookAt);
|
||||
hasLookAt = true;
|
||||
}
|
||||
if (!hasLookAt) {
|
||||
config.lookAt = {config.position[0], config.position[1], config.position[2] - 1.0f};
|
||||
}
|
||||
ReadVec3(camera, "up", config.up);
|
||||
if (ReadNumber(camera, "fov_degrees", config.fov)) {
|
||||
config.fov = glm::radians(config.fov);
|
||||
} else if (ReadNumber(camera, "fov", config.fov) && config.fov > 3.2f) {
|
||||
config.fov = glm::radians(config.fov);
|
||||
}
|
||||
ReadNumber(camera, "near", config.nearPlane);
|
||||
ReadNumber(camera, "far", config.farPlane);
|
||||
return config;
|
||||
}
|
||||
|
||||
ViewState BuildViewState(const CameraConfig& config, float aspect) {
|
||||
glm::vec3 position(config.position[0], config.position[1], config.position[2]);
|
||||
glm::vec3 lookAt(config.lookAt[0], config.lookAt[1], config.lookAt[2]);
|
||||
glm::vec3 up(config.up[0], config.up[1], config.up[2]);
|
||||
glm::mat4 view = glm::lookAt(position, lookAt, up);
|
||||
float safeAspect = aspect <= 0.0f ? 1.0f : aspect;
|
||||
glm::mat4 proj = glm::perspective(config.fov, safeAspect, config.nearPlane, config.farPlane);
|
||||
|
||||
ViewState state{};
|
||||
state.view = ToArray(view);
|
||||
state.proj = ToArray(proj);
|
||||
state.viewProj = ToArray(proj * view);
|
||||
state.cameraPosition = config.position;
|
||||
return state;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WorkflowFrameCameraStep::WorkflowFrameCameraStep(std::shared_ptr<IConfigService> configService,
|
||||
std::shared_ptr<ILogger> logger)
|
||||
: configService_(std::move(configService)),
|
||||
logger_(std::move(logger)) {}
|
||||
|
||||
std::string WorkflowFrameCameraStep::GetPluginId() const {
|
||||
return "frame.camera";
|
||||
}
|
||||
|
||||
void WorkflowFrameCameraStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) {
|
||||
if (!configService_) {
|
||||
throw std::runtime_error("frame.camera requires an IConfigService");
|
||||
}
|
||||
const std::string& configJson = configService_->GetConfigJson();
|
||||
if (configJson.empty()) {
|
||||
throw std::runtime_error("frame.camera requires config JSON to be available");
|
||||
}
|
||||
WorkflowStepIoResolver resolver;
|
||||
const std::string deltaKey = resolver.GetRequiredInputKey(step, "delta");
|
||||
const std::string outputKey = resolver.GetRequiredOutputKey(step, "view_state");
|
||||
const auto* delta = context.TryGet<double>(deltaKey);
|
||||
if (!delta) {
|
||||
throw std::runtime_error("frame.camera missing delta input");
|
||||
}
|
||||
|
||||
CameraConfig cameraConfig = ReadCameraConfig(configJson);
|
||||
float aspect = 1.0f;
|
||||
uint32_t width = configService_->GetWindowWidth();
|
||||
uint32_t height = configService_->GetWindowHeight();
|
||||
if (width > 0 && height > 0) {
|
||||
aspect = static_cast<float>(width) / static_cast<float>(height);
|
||||
}
|
||||
ViewState viewState = BuildViewState(cameraConfig, aspect);
|
||||
context.Set(outputKey, viewState);
|
||||
|
||||
if (logger_) {
|
||||
logger_->Trace("WorkflowFrameCameraStep", "Execute",
|
||||
"delta=" + std::to_string(*delta) +
|
||||
", output=" + outputKey +
|
||||
", aspect=" + std::to_string(aspect),
|
||||
"Camera view state updated");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
25
src/services/impl/workflow_frame_camera_step.hpp
Normal file
25
src/services/impl/workflow_frame_camera_step.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_config_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../interfaces/i_workflow_step.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class WorkflowFrameCameraStep final : public IWorkflowStep {
|
||||
public:
|
||||
WorkflowFrameCameraStep(std::shared_ptr<IConfigService> configService,
|
||||
std::shared_ptr<ILogger> logger);
|
||||
|
||||
std::string GetPluginId() const override;
|
||||
void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<IConfigService> configService_;
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
@@ -24,7 +24,19 @@ void WorkflowFrameRenderStep::Execute(const WorkflowStepDefinition& step, Workfl
|
||||
if (!elapsed) {
|
||||
throw std::runtime_error("frame.render missing elapsed input");
|
||||
}
|
||||
renderService_->RenderFrame(static_cast<float>(*elapsed));
|
||||
const ViewState* viewState = nullptr;
|
||||
auto it = step.inputs.find("view_state");
|
||||
if (it != step.inputs.end()) {
|
||||
viewState = context.TryGet<ViewState>(it->second);
|
||||
if (!viewState) {
|
||||
throw std::runtime_error("frame.render missing view_state input");
|
||||
}
|
||||
}
|
||||
if (viewState) {
|
||||
renderService_->RenderFrameWithViewState(static_cast<float>(*elapsed), *viewState);
|
||||
} else {
|
||||
renderService_->RenderFrame(static_cast<float>(*elapsed));
|
||||
}
|
||||
if (logger_) {
|
||||
logger_->Trace("WorkflowFrameRenderStep", "Execute",
|
||||
"elapsed=" + std::to_string(*elapsed),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics_types.hpp"
|
||||
|
||||
namespace sdl3cpp::services {
|
||||
|
||||
class IRenderCoordinatorService {
|
||||
@@ -7,6 +9,7 @@ public:
|
||||
virtual ~IRenderCoordinatorService() = default;
|
||||
|
||||
virtual void RenderFrame(float time) = 0;
|
||||
virtual void RenderFrameWithViewState(float time, const ViewState& viewState) = 0;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services
|
||||
|
||||
Reference in New Issue
Block a user