mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
feat(render-graph): Implement Lua-based render graph system
- Added render graph configuration to JSON files and runtime settings. - Introduced RenderGraphScriptService to load and manage render graph definitions from Lua. - Updated GraphicsService to handle render graph definitions. - Enhanced cube_logic.lua with a sample render graph function. - Modified various services and interfaces to support render graph functionality. - Improved logging for render graph operations and configurations.
This commit is contained in:
@@ -65,6 +65,7 @@
|
||||
"fog_density": 0.003,
|
||||
"fog_color": [0.05, 0.05, 0.08],
|
||||
"gamma": 2.2,
|
||||
"exposure": 1.0,
|
||||
"enable_tone_mapping": true,
|
||||
"enable_shadows": true,
|
||||
"enable_ssgi": true,
|
||||
@@ -72,6 +73,10 @@
|
||||
"pbr_roughness": 0.3,
|
||||
"pbr_metallic": 0.1
|
||||
},
|
||||
"render_graph": {
|
||||
"enabled": true,
|
||||
"function": "get_render_graph"
|
||||
},
|
||||
"gui_opacity": 1.0,
|
||||
"config_file": "config/seed_runtime.json"
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
"scripts_directory": "scripts",
|
||||
"project_root": "../",
|
||||
"shaders_directory": "shaders",
|
||||
"render_graph": {
|
||||
"enabled": false,
|
||||
"function": "get_render_graph"
|
||||
},
|
||||
"vita_specific": {
|
||||
"analog_stick_sensitivity": 1.2,
|
||||
"gyroscope_enabled": true,
|
||||
@@ -72,4 +76,4 @@
|
||||
"shadows_enabled": true,
|
||||
"particle_effects": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ local cube_mesh_info = {
|
||||
local cube_vertices = {}
|
||||
local cube_indices = {}
|
||||
local cube_indices_double_sided = {}
|
||||
local cube_indices_active = {}
|
||||
local use_double_sided_indices = false
|
||||
|
||||
local function build_double_sided_indices(indices)
|
||||
local doubled = {}
|
||||
@@ -51,8 +49,6 @@ local function load_cube_mesh()
|
||||
cube_vertices = mesh.vertices
|
||||
cube_indices = mesh.indices
|
||||
cube_indices_double_sided = build_double_sided_indices(cube_indices)
|
||||
use_double_sided_indices = #cube_indices_double_sided > 0
|
||||
cube_indices_active = use_double_sided_indices and cube_indices_double_sided or cube_indices
|
||||
cube_mesh_info.loaded = true
|
||||
cube_mesh_info.vertex_count = #mesh.vertices
|
||||
cube_mesh_info.index_count = #mesh.indices
|
||||
@@ -222,8 +218,8 @@ end
|
||||
if cube_mesh_info.loaded then
|
||||
log_debug("Loaded cube mesh from %s (%d vertices, %d indices)",
|
||||
cube_mesh_info.path, cube_mesh_info.vertex_count, cube_mesh_info.index_count)
|
||||
if use_double_sided_indices then
|
||||
log_debug("Using double-sided cube indices (%d -> %d)",
|
||||
if #cube_indices_double_sided > 0 then
|
||||
log_debug("Built double-sided cube indices (%d -> %d)",
|
||||
cube_mesh_info.index_count, #cube_indices_double_sided)
|
||||
end
|
||||
end
|
||||
@@ -339,7 +335,7 @@ local camera = {
|
||||
}
|
||||
|
||||
local controls = {
|
||||
move_speed = 4.0,
|
||||
move_speed = 16.0,
|
||||
fly_speed = 3.0,
|
||||
jump_speed = 5.5,
|
||||
gravity = -12.0,
|
||||
@@ -640,7 +636,7 @@ local function create_static_cube(position, scale, color, shader_key)
|
||||
|
||||
return {
|
||||
vertices = vertices,
|
||||
indices = cube_indices_active,
|
||||
indices = cube_indices,
|
||||
compute_model_matrix = compute_model_matrix,
|
||||
shader_key = resolved_shader,
|
||||
}
|
||||
@@ -657,7 +653,7 @@ local function create_spinning_cube()
|
||||
|
||||
return {
|
||||
vertices = cube_vertices,
|
||||
indices = cube_indices_active,
|
||||
indices = (#cube_indices_double_sided > 0) and cube_indices_double_sided or cube_indices,
|
||||
compute_model_matrix = compute_model_matrix,
|
||||
shader_key = "default",
|
||||
}
|
||||
@@ -845,6 +841,114 @@ function get_shader_paths()
|
||||
return shader_variants
|
||||
end
|
||||
|
||||
|
||||
local function resolve_number(value, fallback)
|
||||
if type(value) == "number" then
|
||||
return value
|
||||
end
|
||||
return fallback
|
||||
end
|
||||
|
||||
function get_render_graph()
|
||||
local atmospherics = {}
|
||||
if type(config) == "table" and type(config.atmospherics) == "table" then
|
||||
atmospherics = config.atmospherics
|
||||
end
|
||||
|
||||
local exposure = resolve_number(atmospherics.exposure, 1.0)
|
||||
local gamma = resolve_number(atmospherics.gamma, 2.2)
|
||||
local fog_density = resolve_number(atmospherics.fog_density, 0.003)
|
||||
|
||||
return {
|
||||
resources = {
|
||||
scene_hdr = {type = "color", format = "rgba16f", size = "swapchain"},
|
||||
depth = {type = "depth", format = "d32", size = "swapchain"},
|
||||
normal_rough = {type = "color", format = "a2b10g10r10", size = "swapchain"},
|
||||
motion = {type = "color", format = "rg16f", size = "swapchain"},
|
||||
shadow_csm = {type = "depth_array", format = "d32", size = {2048, 2048}, layers = 4},
|
||||
ao = {type = "color", format = "r8", size = "half"},
|
||||
ssr = {type = "color", format = "rgba16f", size = "swapchain"},
|
||||
volumetric = {type = "color", format = "rgba16f", size = "half"},
|
||||
taa_history = {type = "color", format = "rgba16f", size = "swapchain"},
|
||||
bloom = {type = "color", format = "rgba16f", size = "half", mips = 5},
|
||||
},
|
||||
passes = {
|
||||
{
|
||||
name = "shadow",
|
||||
kind = "shadow_csm",
|
||||
output = "shadow_csm",
|
||||
settings = {cascades = 4, bias = 0.002, normal_bias = 0.02, pcf = 5},
|
||||
},
|
||||
{
|
||||
name = "gbuffer",
|
||||
kind = "gbuffer",
|
||||
shader = "pbr",
|
||||
outputs = {
|
||||
color = "scene_hdr",
|
||||
depth = "depth",
|
||||
normal = "normal_rough",
|
||||
motion = "motion",
|
||||
},
|
||||
},
|
||||
{
|
||||
name = "ssao",
|
||||
kind = "fullscreen",
|
||||
shader = "ssao",
|
||||
inputs = {depth = "depth", normal = "normal_rough"},
|
||||
output = "ao",
|
||||
settings = {radius = 0.5, power = 1.3},
|
||||
},
|
||||
{
|
||||
name = "ssr",
|
||||
kind = "fullscreen",
|
||||
shader = "ssr",
|
||||
inputs = {scene = "scene_hdr", depth = "depth", normal = "normal_rough"},
|
||||
output = "ssr",
|
||||
settings = {max_steps = 64, thickness = 0.1, roughness_fallback = 0.7},
|
||||
},
|
||||
{
|
||||
name = "volumetric",
|
||||
kind = "fullscreen",
|
||||
shader = "volumetric",
|
||||
inputs = {scene = "scene_hdr", depth = "depth"},
|
||||
output = "volumetric",
|
||||
settings = {density = 0.02},
|
||||
},
|
||||
{
|
||||
name = "height_fog",
|
||||
kind = "fullscreen",
|
||||
shader = "height_fog",
|
||||
inputs = {scene = "scene_hdr", depth = "depth"},
|
||||
output = "scene_hdr",
|
||||
settings = {height = 2.5, falloff = fog_density * 80.0},
|
||||
},
|
||||
{
|
||||
name = "taa",
|
||||
kind = "taa",
|
||||
inputs = {scene = "scene_hdr", history = "taa_history", motion = "motion"},
|
||||
output = "scene_hdr",
|
||||
settings = {feedback = 0.9, sharpen = 0.2},
|
||||
},
|
||||
{
|
||||
name = "bloom",
|
||||
kind = "bloom",
|
||||
input = "scene_hdr",
|
||||
output = "scene_hdr",
|
||||
settings = {threshold = 1.0, intensity = 0.7},
|
||||
},
|
||||
{
|
||||
name = "tonemap",
|
||||
kind = "fullscreen",
|
||||
shader = "tonemap",
|
||||
input = "scene_hdr",
|
||||
output = "swapchain",
|
||||
settings = {exposure = exposure, gamma = gamma, curve = "aces", grade = "warm"},
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
function get_view_projection(aspect)
|
||||
local now = os.clock()
|
||||
local dt = 0.0
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "services/impl/script_engine_service.hpp"
|
||||
#include "services/impl/scene_script_service.hpp"
|
||||
#include "services/impl/shader_script_service.hpp"
|
||||
#include "services/impl/render_graph_script_service.hpp"
|
||||
#include "services/impl/gui_script_service.hpp"
|
||||
#include "services/impl/audio_command_service.hpp"
|
||||
#include "services/impl/physics_bridge_service.hpp"
|
||||
@@ -276,6 +277,10 @@ void ServiceBasedApp::RegisterServices() {
|
||||
registry_.RegisterService<services::IShaderScriptService, services::impl::ShaderScriptService>(
|
||||
registry_.GetService<services::IScriptEngineService>(),
|
||||
registry_.GetService<services::ILogger>());
|
||||
registry_.RegisterService<services::IRenderGraphScriptService, services::impl::RenderGraphScriptService>(
|
||||
registry_.GetService<services::IScriptEngineService>(),
|
||||
registry_.GetService<services::IConfigService>(),
|
||||
registry_.GetService<services::ILogger>());
|
||||
registry_.RegisterService<services::IGuiScriptService, services::impl::GuiScriptService>(
|
||||
registry_.GetService<services::IScriptEngineService>(),
|
||||
registry_.GetService<services::ILogger>());
|
||||
@@ -356,6 +361,7 @@ void ServiceBasedApp::RegisterServices() {
|
||||
registry_.GetService<services::IGraphicsService>(),
|
||||
registry_.GetService<services::ISceneScriptService>(),
|
||||
registry_.GetService<services::IShaderScriptService>(),
|
||||
registry_.GetService<services::IRenderGraphScriptService>(),
|
||||
registry_.GetService<services::IGuiScriptService>(),
|
||||
registry_.GetService<services::IGuiService>(),
|
||||
registry_.GetService<services::ISceneService>());
|
||||
|
||||
@@ -106,6 +106,19 @@ void GraphicsService::LoadShaders(const std::unordered_map<std::string, ShaderPa
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsService::SetRenderGraphDefinition(const RenderGraphDefinition& definition) {
|
||||
logger_->Trace("GraphicsService", "SetRenderGraphDefinition",
|
||||
"resources=" + std::to_string(definition.resources.size()) +
|
||||
", passes=" + std::to_string(definition.passes.size()));
|
||||
|
||||
renderGraphDefinition_ = definition;
|
||||
}
|
||||
|
||||
const RenderGraphDefinition& GraphicsService::GetRenderGraphDefinition() const {
|
||||
logger_->Trace("GraphicsService", "GetRenderGraphDefinition");
|
||||
return renderGraphDefinition_;
|
||||
}
|
||||
|
||||
void GraphicsService::UploadVertexData(const std::vector<core::Vertex>& vertices) {
|
||||
logger_->Trace("GraphicsService", "UploadVertexData",
|
||||
"vertices.size=" + std::to_string(vertices.size()));
|
||||
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
void InitializeSwapchain() override;
|
||||
void RecreateSwapchain() override;
|
||||
void LoadShaders(const std::unordered_map<std::string, ShaderPaths>& shaders) override;
|
||||
void SetRenderGraphDefinition(const RenderGraphDefinition& definition) override;
|
||||
const RenderGraphDefinition& GetRenderGraphDefinition() const override;
|
||||
void UploadVertexData(const std::vector<core::Vertex>& vertices) override;
|
||||
void UploadIndexData(const std::vector<uint16_t>& indices) override;
|
||||
bool BeginFrame() override;
|
||||
@@ -56,8 +58,9 @@ private:
|
||||
std::unordered_map<std::string, GraphicsPipelineHandle> pipelines_;
|
||||
GraphicsBufferHandle vertexBuffer_;
|
||||
GraphicsBufferHandle indexBuffer_;
|
||||
RenderGraphDefinition renderGraphDefinition_{};
|
||||
// Other state
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
} // namespace sdl3cpp::services::impl
|
||||
|
||||
@@ -353,6 +353,7 @@ RuntimeConfig JsonConfigService::LoadFromJson(std::shared_ptr<ILogger> logger,
|
||||
readFloat("fog_density", config.atmospherics.fogDensity);
|
||||
readFloatArray3("fog_color", config.atmospherics.fogColor);
|
||||
readFloat("gamma", config.atmospherics.gamma);
|
||||
readFloat("exposure", config.atmospherics.exposure);
|
||||
readBool("enable_tone_mapping", config.atmospherics.enableToneMapping);
|
||||
readBool("enable_shadows", config.atmospherics.enableShadows);
|
||||
readBool("enable_ssgi", config.atmospherics.enableSSGI);
|
||||
@@ -361,6 +362,29 @@ RuntimeConfig JsonConfigService::LoadFromJson(std::shared_ptr<ILogger> logger,
|
||||
readFloat("pbr_metallic", config.atmospherics.pbrMetallic);
|
||||
}
|
||||
|
||||
if (document.HasMember("render_graph")) {
|
||||
const auto& renderGraphValue = document["render_graph"];
|
||||
if (!renderGraphValue.IsObject()) {
|
||||
throw std::runtime_error("JSON member 'render_graph' must be an object");
|
||||
}
|
||||
|
||||
if (renderGraphValue.HasMember("enabled")) {
|
||||
const auto& value = renderGraphValue["enabled"];
|
||||
if (!value.IsBool()) {
|
||||
throw std::runtime_error("JSON member 'render_graph.enabled' must be a boolean");
|
||||
}
|
||||
config.renderGraph.enabled = value.GetBool();
|
||||
}
|
||||
|
||||
if (renderGraphValue.HasMember("function")) {
|
||||
const auto& value = renderGraphValue["function"];
|
||||
if (!value.IsString()) {
|
||||
throw std::runtime_error("JSON member 'render_graph.function' must be a string");
|
||||
}
|
||||
config.renderGraph.functionName = value.GetString();
|
||||
}
|
||||
}
|
||||
|
||||
if (document.HasMember("gui_opacity")) {
|
||||
const auto& value = document["gui_opacity"];
|
||||
if (!value.IsNumber()) {
|
||||
@@ -410,6 +434,13 @@ std::string JsonConfigService::BuildConfigJson(const RuntimeConfig& config,
|
||||
allocator);
|
||||
document.AddMember("mouse_grab", mouseGrabObject, allocator);
|
||||
|
||||
rapidjson::Value renderGraphObject(rapidjson::kObjectType);
|
||||
renderGraphObject.AddMember("enabled", config.renderGraph.enabled, allocator);
|
||||
renderGraphObject.AddMember("function",
|
||||
rapidjson::Value(config.renderGraph.functionName.c_str(), allocator),
|
||||
allocator);
|
||||
document.AddMember("render_graph", renderGraphObject, allocator);
|
||||
|
||||
rapidjson::Value bindingsObject(rapidjson::kObjectType);
|
||||
auto addBindingMember = [&](const char* name, const std::string& value) {
|
||||
rapidjson::Value nameValue(name, allocator);
|
||||
|
||||
@@ -88,6 +88,12 @@ public:
|
||||
}
|
||||
return config_.mouseGrab;
|
||||
}
|
||||
const RenderGraphConfig& GetRenderGraphConfig() const override {
|
||||
if (logger_) {
|
||||
logger_->Trace("JsonConfigService", "GetRenderGraphConfig");
|
||||
}
|
||||
return config_.renderGraph;
|
||||
}
|
||||
const std::string& GetConfigJson() const override {
|
||||
if (logger_) {
|
||||
logger_->Trace("JsonConfigService", "GetConfigJson");
|
||||
|
||||
@@ -204,7 +204,7 @@ void RenderCommandService::RecordCommands(uint32_t imageIndex,
|
||||
pushConstants.fogEnd = 100.0f;
|
||||
pushConstants.fogColor = config.atmospherics.fogColor;
|
||||
pushConstants.gamma = config.atmospherics.gamma;
|
||||
pushConstants.exposure = 1.0f;
|
||||
pushConstants.exposure = config.atmospherics.exposure;
|
||||
pushConstants.enableShadows = config.atmospherics.enableShadows ? 1 : 0;
|
||||
pushConstants.enableFog = 1; // Enable fog for PBR
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ RenderCoordinatorService::RenderCoordinatorService(std::shared_ptr<ILogger> logg
|
||||
std::shared_ptr<IGraphicsService> graphicsService,
|
||||
std::shared_ptr<ISceneScriptService> sceneScriptService,
|
||||
std::shared_ptr<IShaderScriptService> shaderScriptService,
|
||||
std::shared_ptr<IRenderGraphScriptService> renderGraphScriptService,
|
||||
std::shared_ptr<IGuiScriptService> guiScriptService,
|
||||
std::shared_ptr<IGuiService> guiService,
|
||||
std::shared_ptr<ISceneService> sceneService)
|
||||
@@ -13,6 +14,7 @@ RenderCoordinatorService::RenderCoordinatorService(std::shared_ptr<ILogger> logg
|
||||
graphicsService_(std::move(graphicsService)),
|
||||
sceneScriptService_(std::move(sceneScriptService)),
|
||||
shaderScriptService_(std::move(shaderScriptService)),
|
||||
renderGraphScriptService_(std::move(renderGraphScriptService)),
|
||||
guiScriptService_(std::move(guiScriptService)),
|
||||
guiService_(std::move(guiService)),
|
||||
sceneService_(std::move(sceneService)) {
|
||||
@@ -21,6 +23,7 @@ RenderCoordinatorService::RenderCoordinatorService(std::shared_ptr<ILogger> logg
|
||||
"graphicsService=" + std::string(graphicsService_ ? "set" : "null") +
|
||||
", sceneScriptService=" + std::string(sceneScriptService_ ? "set" : "null") +
|
||||
", shaderScriptService=" + std::string(shaderScriptService_ ? "set" : "null") +
|
||||
", renderGraphScriptService=" + std::string(renderGraphScriptService_ ? "set" : "null") +
|
||||
", guiScriptService=" + std::string(guiScriptService_ ? "set" : "null") +
|
||||
", guiService=" + std::string(guiService_ ? "set" : "null") +
|
||||
", sceneService=" + std::string(sceneService_ ? "set" : "null"),
|
||||
@@ -41,6 +44,21 @@ void RenderCoordinatorService::RenderFrame(float time) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!renderGraphInitialized_) {
|
||||
renderGraphInitialized_ = true;
|
||||
if (renderGraphScriptService_ && renderGraphScriptService_->IsEnabled()) {
|
||||
if (logger_) {
|
||||
logger_->Trace("RenderCoordinatorService", "RenderFrame",
|
||||
"Loading render graph from Lua");
|
||||
}
|
||||
auto graph = renderGraphScriptService_->LoadRenderGraph();
|
||||
graphicsService_->SetRenderGraphDefinition(graph);
|
||||
} else if (logger_) {
|
||||
logger_->Trace("RenderCoordinatorService", "RenderFrame",
|
||||
"Render graph disabled or unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
if (!shadersLoaded_) {
|
||||
if (!shaderScriptService_) {
|
||||
if (logger_) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../interfaces/i_gui_script_service.hpp"
|
||||
#include "../interfaces/i_gui_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../interfaces/i_render_graph_script_service.hpp"
|
||||
#include "../interfaces/i_scene_script_service.hpp"
|
||||
#include "../interfaces/i_scene_service.hpp"
|
||||
#include "../interfaces/i_shader_script_service.hpp"
|
||||
@@ -18,6 +19,7 @@ public:
|
||||
std::shared_ptr<IGraphicsService> graphicsService,
|
||||
std::shared_ptr<ISceneScriptService> sceneScriptService,
|
||||
std::shared_ptr<IShaderScriptService> shaderScriptService,
|
||||
std::shared_ptr<IRenderGraphScriptService> renderGraphScriptService,
|
||||
std::shared_ptr<IGuiScriptService> guiScriptService,
|
||||
std::shared_ptr<IGuiService> guiService,
|
||||
std::shared_ptr<ISceneService> sceneService);
|
||||
@@ -30,6 +32,7 @@ private:
|
||||
std::shared_ptr<IGraphicsService> graphicsService_;
|
||||
std::shared_ptr<ISceneScriptService> sceneScriptService_;
|
||||
std::shared_ptr<IShaderScriptService> shaderScriptService_;
|
||||
std::shared_ptr<IRenderGraphScriptService> renderGraphScriptService_;
|
||||
std::shared_ptr<IGuiScriptService> guiScriptService_;
|
||||
std::shared_ptr<IGuiService> guiService_;
|
||||
std::shared_ptr<ISceneService> sceneService_;
|
||||
@@ -37,6 +40,7 @@ private:
|
||||
size_t lastIndexCount_ = 0;
|
||||
bool shadersLoaded_ = false;
|
||||
bool geometryUploaded_ = false;
|
||||
bool renderGraphInitialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
|
||||
417
src/services/impl/render_graph_script_service.cpp
Normal file
417
src/services/impl/render_graph_script_service.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
#include "render_graph_script_service.hpp"
|
||||
|
||||
#include "lua_helpers.hpp"
|
||||
#include "services/interfaces/i_logger.hpp"
|
||||
|
||||
#include <lua.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
RenderGraphScriptService::RenderGraphScriptService(std::shared_ptr<IScriptEngineService> engineService,
|
||||
std::shared_ptr<IConfigService> configService,
|
||||
std::shared_ptr<ILogger> logger)
|
||||
: engineService_(std::move(engineService)),
|
||||
configService_(std::move(configService)),
|
||||
logger_(std::move(logger)) {
|
||||
if (logger_) {
|
||||
logger_->Trace("RenderGraphScriptService", "RenderGraphScriptService",
|
||||
"engineService=" + std::string(engineService_ ? "set" : "null") +
|
||||
", configService=" + std::string(configService_ ? "set" : "null"));
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderGraphScriptService::IsEnabled() const {
|
||||
if (!configService_) {
|
||||
return false;
|
||||
}
|
||||
return configService_->GetRenderGraphConfig().enabled;
|
||||
}
|
||||
|
||||
bool RenderGraphScriptService::HasRenderGraphFunction() const {
|
||||
if (!IsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
lua_State* L = GetLuaState();
|
||||
const auto& config = GetRenderGraphConfig();
|
||||
lua_getglobal(L, config.functionName.c_str());
|
||||
bool isFunction = lua_isfunction(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return isFunction;
|
||||
}
|
||||
|
||||
RenderGraphDefinition RenderGraphScriptService::LoadRenderGraph() {
|
||||
if (logger_) {
|
||||
logger_->Trace("RenderGraphScriptService", "LoadRenderGraph");
|
||||
}
|
||||
|
||||
if (!IsEnabled()) {
|
||||
if (logger_) {
|
||||
logger_->Trace("RenderGraphScriptService", "LoadRenderGraph",
|
||||
"renderGraphEnabled=false");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
if (graphLoaded_) {
|
||||
return cachedGraph_;
|
||||
}
|
||||
|
||||
lua_State* L = GetLuaState();
|
||||
const auto& config = GetRenderGraphConfig();
|
||||
lua_getglobal(L, config.functionName.c_str());
|
||||
if (!lua_isfunction(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
if (logger_) {
|
||||
logger_->Error("Lua render graph function '" + config.functionName + "' is missing");
|
||||
}
|
||||
throw std::runtime_error("Lua render graph function '" + config.functionName + "' is missing");
|
||||
}
|
||||
|
||||
if (lua_pcall(L, 0, 1, 0) != LUA_OK) {
|
||||
std::string message = lua::GetLuaError(L);
|
||||
lua_pop(L, 1);
|
||||
if (logger_) {
|
||||
logger_->Error("Lua render graph failed: " + message);
|
||||
}
|
||||
throw std::runtime_error("Lua render graph failed: " + message);
|
||||
}
|
||||
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
if (logger_) {
|
||||
logger_->Error("Render graph function did not return a table");
|
||||
}
|
||||
throw std::runtime_error("Render graph function did not return a table");
|
||||
}
|
||||
|
||||
cachedGraph_ = ParseRenderGraph(L, lua_gettop(L));
|
||||
graphLoaded_ = true;
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (logger_) {
|
||||
logger_->Info("Loaded render graph with resources=" +
|
||||
std::to_string(cachedGraph_.resources.size()) +
|
||||
", passes=" + std::to_string(cachedGraph_.passes.size()));
|
||||
}
|
||||
|
||||
return cachedGraph_;
|
||||
}
|
||||
|
||||
lua_State* RenderGraphScriptService::GetLuaState() const {
|
||||
if (logger_) {
|
||||
logger_->Trace("RenderGraphScriptService", "GetLuaState");
|
||||
}
|
||||
if (!engineService_) {
|
||||
throw std::runtime_error("Render graph script service is missing script engine service");
|
||||
}
|
||||
lua_State* state = engineService_->GetLuaState();
|
||||
if (!state) {
|
||||
throw std::runtime_error("Lua state is not initialized");
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
const RenderGraphConfig& RenderGraphScriptService::GetRenderGraphConfig() const {
|
||||
if (!configService_) {
|
||||
throw std::runtime_error("Render graph script service is missing config service");
|
||||
}
|
||||
return configService_->GetRenderGraphConfig();
|
||||
}
|
||||
|
||||
RenderGraphDefinition RenderGraphScriptService::ParseRenderGraph(lua_State* L, int index) const {
|
||||
RenderGraphDefinition graph;
|
||||
int graphIndex = lua_absindex(L, index);
|
||||
|
||||
lua_getfield(L, graphIndex, "resources");
|
||||
if (lua_istable(L, -1)) {
|
||||
int resourcesIndex = lua_absindex(L, -1);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, resourcesIndex) != 0) {
|
||||
if (lua_isstring(L, -2) && lua_istable(L, -1)) {
|
||||
std::string name = lua_tostring(L, -2);
|
||||
graph.resources.push_back(ParseResource(L, lua_gettop(L), name));
|
||||
} else if (logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: Skipping invalid resource entry");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else if (!lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Render graph 'resources' must be a table when provided");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, graphIndex, "passes");
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Render graph 'passes' must be a table");
|
||||
}
|
||||
|
||||
int passesIndex = lua_absindex(L, -1);
|
||||
size_t count = lua_rawlen(L, passesIndex);
|
||||
graph.passes.reserve(count);
|
||||
for (size_t i = 1; i <= count; ++i) {
|
||||
lua_rawgeti(L, passesIndex, static_cast<int>(i));
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Render graph pass at index " +
|
||||
std::to_string(i) + " must be a table");
|
||||
}
|
||||
graph.passes.push_back(ParsePass(L, lua_gettop(L), i));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (graph.passes.empty()) {
|
||||
throw std::runtime_error("Render graph must define at least one pass");
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
RenderGraphResource RenderGraphScriptService::ParseResource(lua_State* L, int index,
|
||||
const std::string& name) const {
|
||||
RenderGraphResource resource;
|
||||
resource.name = name;
|
||||
int resourceIndex = lua_absindex(L, index);
|
||||
|
||||
auto readRequiredString = [&](const char* field, std::string& target) {
|
||||
lua_getfield(L, resourceIndex, field);
|
||||
if (!lua_isstring(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Render graph resource '" + name +
|
||||
"' field '" + field + "' must be a string");
|
||||
}
|
||||
target = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
};
|
||||
|
||||
auto readOptionalNumber = [&](const char* field, uint32_t& target) {
|
||||
lua_getfield(L, resourceIndex, field);
|
||||
if (lua_isnumber(L, -1)) {
|
||||
double value = lua_tonumber(L, -1);
|
||||
target = value < 0.0 ? 0u : static_cast<uint32_t>(value);
|
||||
} else if (!lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Render graph resource '" + name +
|
||||
"' field '" + field + "' must be a number");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
};
|
||||
|
||||
readRequiredString("type", resource.type);
|
||||
readRequiredString("format", resource.format);
|
||||
|
||||
resource.size = "swapchain";
|
||||
lua_getfield(L, resourceIndex, "size");
|
||||
if (lua_isstring(L, -1)) {
|
||||
resource.size = lua_tostring(L, -1);
|
||||
} else if (lua_istable(L, -1)) {
|
||||
int sizeIndex = lua_absindex(L, -1);
|
||||
bool parsed = false;
|
||||
size_t sizeLen = lua_rawlen(L, sizeIndex);
|
||||
if (sizeLen >= 2) {
|
||||
lua_rawgeti(L, sizeIndex, 1);
|
||||
lua_rawgeti(L, sizeIndex, 2);
|
||||
if (lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
|
||||
resource.explicitSize[0] = static_cast<uint32_t>(lua_tonumber(L, -2));
|
||||
resource.explicitSize[1] = static_cast<uint32_t>(lua_tonumber(L, -1));
|
||||
resource.hasExplicitSize = true;
|
||||
parsed = true;
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
if (!parsed) {
|
||||
lua_getfield(L, sizeIndex, "width");
|
||||
lua_getfield(L, sizeIndex, "height");
|
||||
if (lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
|
||||
resource.explicitSize[0] = static_cast<uint32_t>(lua_tonumber(L, -2));
|
||||
resource.explicitSize[1] = static_cast<uint32_t>(lua_tonumber(L, -1));
|
||||
resource.hasExplicitSize = true;
|
||||
parsed = true;
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
if (!parsed) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Render graph resource '" + name +
|
||||
"' size must be a string or {width,height}");
|
||||
}
|
||||
} else if (!lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Render graph resource '" + name +
|
||||
"' size must be a string or table");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
readOptionalNumber("layers", resource.layers);
|
||||
readOptionalNumber("mips", resource.mips);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
RenderGraphPass RenderGraphScriptService::ParsePass(lua_State* L, int index, size_t passIndex) const {
|
||||
RenderGraphPass pass;
|
||||
int passTableIndex = lua_absindex(L, index);
|
||||
|
||||
lua_getfield(L, passTableIndex, "name");
|
||||
if (lua_isstring(L, -1)) {
|
||||
pass.name = lua_tostring(L, -1);
|
||||
} else {
|
||||
pass.name = "pass_" + std::to_string(passIndex);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, passTableIndex, "kind");
|
||||
if (!lua_isstring(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Render graph pass '" + pass.name + "' missing 'kind' string");
|
||||
}
|
||||
pass.kind = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, passTableIndex, "shader");
|
||||
if (lua_isstring(L, -1)) {
|
||||
pass.shader = lua_tostring(L, -1);
|
||||
} else if (!lua_isnil(L, -1) && logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: pass '" + pass.name + "' shader must be a string");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, passTableIndex, "output");
|
||||
if (lua_isstring(L, -1)) {
|
||||
pass.output = lua_tostring(L, -1);
|
||||
} else if (!lua_isnil(L, -1) && logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: pass '" + pass.name + "' output must be a string");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
std::string inputValue;
|
||||
lua_getfield(L, passTableIndex, "input");
|
||||
if (lua_isstring(L, -1)) {
|
||||
inputValue = lua_tostring(L, -1);
|
||||
} else if (!lua_isnil(L, -1) && logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: pass '" + pass.name + "' input must be a string");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, passTableIndex, "inputs");
|
||||
if (lua_istable(L, -1)) {
|
||||
pass.inputs = ParseStringMap(L, lua_gettop(L));
|
||||
} else if (!lua_isnil(L, -1) && logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: pass '" + pass.name + "' inputs must be a table");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
if (!inputValue.empty() && pass.inputs.find("input") == pass.inputs.end()) {
|
||||
pass.inputs.emplace("input", std::move(inputValue));
|
||||
}
|
||||
|
||||
lua_getfield(L, passTableIndex, "outputs");
|
||||
if (lua_istable(L, -1)) {
|
||||
pass.outputs = ParseStringMap(L, lua_gettop(L));
|
||||
} else if (!lua_isnil(L, -1) && logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: pass '" + pass.name + "' outputs must be a table");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, passTableIndex, "settings");
|
||||
if (lua_istable(L, -1)) {
|
||||
pass.settings = ParseSettingsMap(L, lua_gettop(L));
|
||||
} else if (!lua_isnil(L, -1) && logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: pass '" + pass.name + "' settings must be a table");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> RenderGraphScriptService::ParseStringMap(lua_State* L,
|
||||
int index) const {
|
||||
std::unordered_map<std::string, std::string> result;
|
||||
int mapIndex = lua_absindex(L, index);
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, mapIndex) != 0) {
|
||||
if (lua_isstring(L, -2) && lua_isstring(L, -1)) {
|
||||
std::string key = lua_tostring(L, -2);
|
||||
std::string value = lua_tostring(L, -1);
|
||||
result.emplace(std::move(key), std::move(value));
|
||||
} else if (logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: String map entry must be string->string");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, RenderGraphValue> RenderGraphScriptService::ParseSettingsMap(lua_State* L,
|
||||
int index) const {
|
||||
std::unordered_map<std::string, RenderGraphValue> result;
|
||||
int mapIndex = lua_absindex(L, index);
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, mapIndex) != 0) {
|
||||
if (!lua_isstring(L, -2)) {
|
||||
lua_pop(L, 1);
|
||||
continue;
|
||||
}
|
||||
std::string key = lua_tostring(L, -2);
|
||||
RenderGraphValue value;
|
||||
if (TryParseValue(L, lua_gettop(L), value)) {
|
||||
result.emplace(std::move(key), std::move(value));
|
||||
} else if (logger_) {
|
||||
logger_->Warn("RenderGraphScriptService: Unsupported settings value for key '" + key + "'");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RenderGraphScriptService::TryParseValue(lua_State* L, int index, RenderGraphValue& outValue) const {
|
||||
int absIndex = lua_absindex(L, index);
|
||||
if (lua_isnumber(L, absIndex)) {
|
||||
outValue.type = RenderGraphValue::Type::Number;
|
||||
outValue.number = lua_tonumber(L, absIndex);
|
||||
return true;
|
||||
}
|
||||
if (lua_isboolean(L, absIndex)) {
|
||||
outValue.type = RenderGraphValue::Type::Boolean;
|
||||
outValue.boolean = lua_toboolean(L, absIndex) != 0;
|
||||
return true;
|
||||
}
|
||||
if (lua_isstring(L, absIndex)) {
|
||||
outValue.type = RenderGraphValue::Type::String;
|
||||
outValue.string = lua_tostring(L, absIndex);
|
||||
return true;
|
||||
}
|
||||
if (lua_istable(L, absIndex)) {
|
||||
size_t len = lua_rawlen(L, absIndex);
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
outValue.type = RenderGraphValue::Type::Array;
|
||||
outValue.array.clear();
|
||||
outValue.array.reserve(len);
|
||||
for (size_t i = 1; i <= len; ++i) {
|
||||
lua_rawgeti(L, absIndex, static_cast<int>(i));
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
outValue.array.clear();
|
||||
return false;
|
||||
}
|
||||
outValue.array.push_back(lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
43
src/services/impl/render_graph_script_service.hpp
Normal file
43
src/services/impl/render_graph_script_service.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_render_graph_script_service.hpp"
|
||||
#include "../interfaces/i_config_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../interfaces/i_script_engine_service.hpp"
|
||||
#include <memory>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
/**
|
||||
* @brief Loads render graph definitions from the shared Lua runtime.
|
||||
*/
|
||||
class RenderGraphScriptService : public IRenderGraphScriptService {
|
||||
public:
|
||||
RenderGraphScriptService(std::shared_ptr<IScriptEngineService> engineService,
|
||||
std::shared_ptr<IConfigService> configService,
|
||||
std::shared_ptr<ILogger> logger);
|
||||
|
||||
bool IsEnabled() const override;
|
||||
bool HasRenderGraphFunction() const override;
|
||||
RenderGraphDefinition LoadRenderGraph() override;
|
||||
|
||||
private:
|
||||
lua_State* GetLuaState() const;
|
||||
const RenderGraphConfig& GetRenderGraphConfig() const;
|
||||
RenderGraphDefinition ParseRenderGraph(lua_State* L, int index) const;
|
||||
RenderGraphResource ParseResource(lua_State* L, int index, const std::string& name) const;
|
||||
RenderGraphPass ParsePass(lua_State* L, int index, size_t passIndex) const;
|
||||
bool TryParseValue(lua_State* L, int index, RenderGraphValue& outValue) const;
|
||||
std::unordered_map<std::string, std::string> ParseStringMap(lua_State* L, int index) const;
|
||||
std::unordered_map<std::string, RenderGraphValue> ParseSettingsMap(lua_State* L, int index) const;
|
||||
|
||||
std::shared_ptr<IScriptEngineService> engineService_;
|
||||
std::shared_ptr<IConfigService> configService_;
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
bool graphLoaded_ = false;
|
||||
RenderGraphDefinition cachedGraph_{};
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
@@ -71,6 +71,7 @@ struct AtmosphericsConfig {
|
||||
float fogDensity = 0.003f;
|
||||
std::array<float, 3> fogColor = {0.05f, 0.05f, 0.08f};
|
||||
float gamma = 2.2f;
|
||||
float exposure = 1.0f;
|
||||
bool enableToneMapping = true;
|
||||
bool enableShadows = true;
|
||||
bool enableSSGI = true;
|
||||
@@ -79,6 +80,14 @@ struct AtmosphericsConfig {
|
||||
float pbrMetallic = 0.1f;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Lua-defined render graph configuration.
|
||||
*/
|
||||
struct RenderGraphConfig {
|
||||
bool enabled = false;
|
||||
std::string functionName = "get_render_graph";
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Runtime configuration values used across services.
|
||||
*/
|
||||
@@ -91,6 +100,7 @@ struct RuntimeConfig {
|
||||
MouseGrabConfig mouseGrab{};
|
||||
InputBindings inputBindings{};
|
||||
AtmosphericsConfig atmospherics{};
|
||||
RenderGraphConfig renderGraph{};
|
||||
float guiOpacity = 1.0f;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace sdl3cpp::services {
|
||||
|
||||
@@ -45,4 +46,57 @@ struct RenderCommand {
|
||||
std::array<float, 16> modelMatrix;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Render graph value used for Lua-defined settings.
|
||||
*/
|
||||
struct RenderGraphValue {
|
||||
enum class Type {
|
||||
Number,
|
||||
Boolean,
|
||||
String,
|
||||
Array
|
||||
};
|
||||
|
||||
Type type = Type::Number;
|
||||
double number = 0.0;
|
||||
bool boolean = false;
|
||||
std::string string;
|
||||
std::vector<double> array;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Render graph resource definition loaded from Lua.
|
||||
*/
|
||||
struct RenderGraphResource {
|
||||
std::string name;
|
||||
std::string type;
|
||||
std::string format;
|
||||
std::string size;
|
||||
std::array<uint32_t, 2> explicitSize{};
|
||||
bool hasExplicitSize = false;
|
||||
uint32_t layers = 1;
|
||||
uint32_t mips = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Render graph pass definition loaded from Lua.
|
||||
*/
|
||||
struct RenderGraphPass {
|
||||
std::string name;
|
||||
std::string kind;
|
||||
std::string shader;
|
||||
std::string output;
|
||||
std::unordered_map<std::string, std::string> inputs;
|
||||
std::unordered_map<std::string, std::string> outputs;
|
||||
std::unordered_map<std::string, RenderGraphValue> settings;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Render graph definition loaded from Lua.
|
||||
*/
|
||||
struct RenderGraphDefinition {
|
||||
std::vector<RenderGraphResource> resources;
|
||||
std::vector<RenderGraphPass> passes;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services
|
||||
|
||||
@@ -66,6 +66,12 @@ public:
|
||||
*/
|
||||
virtual const MouseGrabConfig& GetMouseGrabConfig() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get render graph settings.
|
||||
* @return Render graph configuration
|
||||
*/
|
||||
virtual const RenderGraphConfig& GetRenderGraphConfig() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the full JSON configuration as a string.
|
||||
*
|
||||
|
||||
@@ -61,6 +61,18 @@ public:
|
||||
*/
|
||||
virtual void LoadShaders(const std::unordered_map<std::string, ShaderPaths>& shaders) = 0;
|
||||
|
||||
/**
|
||||
* @brief Store the Lua-defined render graph definition.
|
||||
*
|
||||
* @param definition Render graph definition
|
||||
*/
|
||||
virtual void SetRenderGraphDefinition(const RenderGraphDefinition& definition) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the current render graph definition.
|
||||
*/
|
||||
virtual const RenderGraphDefinition& GetRenderGraphDefinition() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Upload vertex data to GPU buffer.
|
||||
*
|
||||
|
||||
30
src/services/interfaces/i_render_graph_script_service.hpp
Normal file
30
src/services/interfaces/i_render_graph_script_service.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics_types.hpp"
|
||||
|
||||
namespace sdl3cpp::services {
|
||||
|
||||
/**
|
||||
* @brief Loads render graph definitions from Lua.
|
||||
*/
|
||||
class IRenderGraphScriptService {
|
||||
public:
|
||||
virtual ~IRenderGraphScriptService() = default;
|
||||
|
||||
/**
|
||||
* @brief Check if render graph execution is enabled.
|
||||
*/
|
||||
virtual bool IsEnabled() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Check whether the configured Lua function exists.
|
||||
*/
|
||||
virtual bool HasRenderGraphFunction() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Load the render graph definition from Lua.
|
||||
*/
|
||||
virtual RenderGraphDefinition LoadRenderGraph() = 0;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services
|
||||
@@ -40,3 +40,19 @@ end
|
||||
function compute_model_matrix(time)
|
||||
return identity_matrix()
|
||||
end
|
||||
|
||||
function get_render_graph()
|
||||
return {
|
||||
resources = {
|
||||
scene_hdr = {type = "color", format = "rgba16f", size = "swapchain"},
|
||||
depth = {type = "depth", format = "d32", size = "swapchain"},
|
||||
},
|
||||
passes = {
|
||||
{
|
||||
name = "gbuffer",
|
||||
kind = "gbuffer",
|
||||
outputs = {color = "scene_hdr", depth = "depth"},
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user