mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-25 06:04:57 +00:00
386 lines
12 KiB
Lua
386 lines
12 KiB
Lua
local M = {}
|
|
|
|
local string_format = string.format
|
|
|
|
local function get_logger(log_debug)
|
|
if type(log_debug) == "function" then
|
|
return log_debug
|
|
end
|
|
return function()
|
|
end
|
|
end
|
|
|
|
local function resolve_color3(value, fallback)
|
|
if type(value) == "table" then
|
|
local r = tonumber(value[1])
|
|
local g = tonumber(value[2])
|
|
local b = tonumber(value[3])
|
|
if r and g and b then
|
|
return {r, g, b}
|
|
end
|
|
end
|
|
return {fallback[1], fallback[2], fallback[3]}
|
|
end
|
|
|
|
local function resolve_number_optional(value)
|
|
if type(value) == "number" then
|
|
return value
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function resolve_color3_optional(value)
|
|
if type(value) == "table" then
|
|
local r = tonumber(value[1])
|
|
local g = tonumber(value[2])
|
|
local b = tonumber(value[3])
|
|
if r and g and b then
|
|
return {r, g, b}
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function format_optional_number(value)
|
|
if type(value) == "number" then
|
|
return string_format("%.3f", value)
|
|
end
|
|
return "default"
|
|
end
|
|
|
|
local function format_optional_color(value)
|
|
if type(value) == "table"
|
|
and type(value[1]) == "number"
|
|
and type(value[2]) == "number"
|
|
and type(value[3]) == "number" then
|
|
return string_format("{%.2f, %.2f, %.2f}", value[1], value[2], value[3])
|
|
end
|
|
return "default"
|
|
end
|
|
|
|
local function build_shader_parameter_overrides(config, log_debug)
|
|
if type(config) ~= "table" or type(config.atmospherics) ~= "table" then
|
|
return {}
|
|
end
|
|
|
|
local atmospherics = config.atmospherics
|
|
local ambient_strength = resolve_number_optional(atmospherics.ambient_strength)
|
|
local light_intensity = resolve_number_optional(atmospherics.light_intensity)
|
|
local key_intensity = resolve_number_optional(atmospherics.key_light_intensity)
|
|
local fill_intensity = resolve_number_optional(atmospherics.fill_light_intensity)
|
|
local light_color = resolve_color3_optional(atmospherics.light_color)
|
|
local pbr_roughness = resolve_number_optional(atmospherics.pbr_roughness)
|
|
local pbr_metallic = resolve_number_optional(atmospherics.pbr_metallic)
|
|
|
|
local parameters = {}
|
|
|
|
local function apply_common(key)
|
|
if ambient_strength == nil and light_intensity == nil and light_color == nil then
|
|
return
|
|
end
|
|
local entry = {}
|
|
if ambient_strength ~= nil then
|
|
entry.ambient_strength = ambient_strength
|
|
end
|
|
if light_intensity ~= nil then
|
|
entry.light_intensity = light_intensity
|
|
end
|
|
if light_color ~= nil then
|
|
entry.light_color = light_color
|
|
end
|
|
parameters[key] = entry
|
|
end
|
|
|
|
apply_common("solid")
|
|
apply_common("floor")
|
|
apply_common("wall")
|
|
apply_common("ceiling")
|
|
|
|
if ambient_strength ~= nil or key_intensity ~= nil or fill_intensity ~= nil or light_intensity ~= nil then
|
|
local entry = {}
|
|
if ambient_strength ~= nil then
|
|
entry.ambient_strength = ambient_strength
|
|
end
|
|
if key_intensity ~= nil then
|
|
entry.key_intensity = key_intensity
|
|
elseif light_intensity ~= nil then
|
|
entry.key_intensity = light_intensity
|
|
end
|
|
if fill_intensity ~= nil then
|
|
entry.fill_intensity = fill_intensity
|
|
elseif light_intensity ~= nil then
|
|
entry.fill_intensity = light_intensity * 0.45
|
|
end
|
|
parameters.default = entry
|
|
end
|
|
|
|
if light_intensity ~= nil or light_color ~= nil or pbr_roughness ~= nil or pbr_metallic ~= nil then
|
|
local entry = {}
|
|
if light_intensity ~= nil then
|
|
entry.light_intensity = light_intensity
|
|
end
|
|
if light_color ~= nil then
|
|
entry.light_color = light_color
|
|
end
|
|
if pbr_roughness ~= nil then
|
|
entry.material_roughness = pbr_roughness
|
|
end
|
|
if pbr_metallic ~= nil then
|
|
entry.material_metallic = pbr_metallic
|
|
end
|
|
parameters.pbr = entry
|
|
end
|
|
|
|
if next(parameters) ~= nil then
|
|
log_debug("Shader lighting overrides: ambient=%s light_intensity=%s light_color=%s",
|
|
format_optional_number(ambient_strength),
|
|
format_optional_number(light_intensity),
|
|
format_optional_color(light_color))
|
|
end
|
|
|
|
return parameters
|
|
end
|
|
|
|
local function load_materialx_parameters(config, log_debug)
|
|
if type(config) ~= "table" then
|
|
return nil
|
|
end
|
|
local materialx = config.materialx
|
|
if type(materialx) ~= "table" then
|
|
return nil
|
|
end
|
|
local enabled = materialx.enabled
|
|
if type(materialx.parameters_enabled) == "boolean" then
|
|
enabled = materialx.parameters_enabled
|
|
end
|
|
if not enabled then
|
|
return nil
|
|
end
|
|
if type(materialx.document) ~= "string" or materialx.document == "" then
|
|
log_debug("MaterialX enabled but document path is missing")
|
|
return nil
|
|
end
|
|
if type(materialx_get_surface_parameters) ~= "function" then
|
|
log_debug("MaterialX loader unavailable (materialx_get_surface_parameters missing)")
|
|
return nil
|
|
end
|
|
|
|
local material_name = nil
|
|
if type(materialx.material) == "string" and materialx.material ~= "" then
|
|
material_name = materialx.material
|
|
end
|
|
|
|
local ok, result, err = pcall(materialx_get_surface_parameters, materialx.document, material_name)
|
|
if not ok then
|
|
log_debug("MaterialX parameter load failed: %s", tostring(result))
|
|
return nil
|
|
end
|
|
if result == nil then
|
|
log_debug("MaterialX parameter load failed: %s", tostring(err))
|
|
return nil
|
|
end
|
|
if type(result) ~= "table" then
|
|
log_debug("MaterialX parameter load returned unexpected result")
|
|
return nil
|
|
end
|
|
return result
|
|
end
|
|
|
|
local function resolve_skybox_color(config, default_color)
|
|
if type(config) ~= "table" then
|
|
return default_color
|
|
end
|
|
local atmospherics = config.atmospherics
|
|
if type(atmospherics) ~= "table" then
|
|
return default_color
|
|
end
|
|
return resolve_color3(atmospherics.sky_color, default_color)
|
|
end
|
|
|
|
local function build_static_cube_variants()
|
|
local fallback_vertex_source = [[
|
|
#version 450
|
|
|
|
layout(location = 0) in vec3 inPos;
|
|
layout(location = 1) in vec3 inNormal;
|
|
layout(location = 2) in vec3 inColor;
|
|
|
|
layout(location = 0) out vec3 fragColor;
|
|
|
|
layout(push_constant) uniform PushConstants {
|
|
mat4 model;
|
|
mat4 viewProj;
|
|
mat4 view;
|
|
mat4 proj;
|
|
mat4 lightViewProj;
|
|
vec3 cameraPos;
|
|
float time;
|
|
float ambientStrength;
|
|
float fogDensity;
|
|
float fogStart;
|
|
float fogEnd;
|
|
vec3 fogColor;
|
|
float gamma;
|
|
float exposure;
|
|
int enableShadows;
|
|
int enableFog;
|
|
} pushConstants;
|
|
|
|
void main() {
|
|
fragColor = inColor;
|
|
gl_Position = pushConstants.viewProj * pushConstants.model * vec4(inPos, 1.0);
|
|
}
|
|
]]
|
|
|
|
local fallback_fragment_source = [[
|
|
#version 450
|
|
|
|
layout(location = 0) in vec3 fragColor;
|
|
layout(location = 0) out vec4 outColor;
|
|
|
|
void main() {
|
|
outColor = vec4(fragColor, 1.0);
|
|
}
|
|
]]
|
|
|
|
return {
|
|
default = {
|
|
vertex_source = fallback_vertex_source,
|
|
fragment_source = fallback_fragment_source,
|
|
},
|
|
solid = {
|
|
vertex_source = fallback_vertex_source,
|
|
fragment_source = fallback_fragment_source,
|
|
},
|
|
floor = {
|
|
vertex_source = fallback_vertex_source,
|
|
fragment_source = fallback_fragment_source,
|
|
},
|
|
wall = {
|
|
vertex_source = fallback_vertex_source,
|
|
fragment_source = fallback_fragment_source,
|
|
},
|
|
ceiling = {
|
|
vertex_source = fallback_vertex_source,
|
|
fragment_source = fallback_fragment_source,
|
|
},
|
|
pbr = {
|
|
vertex_source = fallback_vertex_source,
|
|
fragment_source = fallback_fragment_source,
|
|
},
|
|
skybox = {
|
|
vertex_source = fallback_vertex_source,
|
|
fragment_source = fallback_fragment_source,
|
|
},
|
|
}
|
|
end
|
|
|
|
local function count_shader_variants(variants)
|
|
local count = 0
|
|
for _ in pairs(variants) do
|
|
count = count + 1
|
|
end
|
|
return count
|
|
end
|
|
|
|
function M.build_cube_variants(config, log_debug, base_skybox_color)
|
|
local logger = get_logger(log_debug)
|
|
local skybox_color = resolve_skybox_color(config, base_skybox_color or {0.04, 0.05, 0.08})
|
|
local shader_parameters = build_shader_parameter_overrides(config, logger)
|
|
local materialx_parameters = load_materialx_parameters(config, logger)
|
|
if materialx_parameters then
|
|
local entry = shader_parameters.pbr or {}
|
|
local albedo = resolve_color3_optional(materialx_parameters.material_albedo)
|
|
local roughness = resolve_number_optional(materialx_parameters.material_roughness)
|
|
local metallic = resolve_number_optional(materialx_parameters.material_metallic)
|
|
if albedo ~= nil then
|
|
entry.material_albedo = albedo
|
|
end
|
|
if roughness ~= nil then
|
|
entry.material_roughness = roughness
|
|
end
|
|
if metallic ~= nil then
|
|
entry.material_metallic = metallic
|
|
end
|
|
if next(entry) ~= nil then
|
|
shader_parameters.pbr = entry
|
|
logger("MaterialX PBR overrides: albedo=%s roughness=%s metallic=%s",
|
|
format_optional_color(albedo),
|
|
format_optional_number(roughness),
|
|
format_optional_number(metallic))
|
|
end
|
|
end
|
|
|
|
local ok, toolkit = pcall(require, "shader_toolkit")
|
|
if not ok then
|
|
logger("Shader toolkit unavailable: %s", tostring(toolkit))
|
|
return build_static_cube_variants(), skybox_color
|
|
end
|
|
|
|
local output_mode = "source"
|
|
local compile = false
|
|
local ok_generate, generated = pcall(toolkit.generate_cube_demo_variants,
|
|
{compile = compile, output_mode = output_mode, parameters = shader_parameters})
|
|
if not ok_generate then
|
|
logger("Shader generation failed: %s", tostring(generated))
|
|
return build_static_cube_variants(), skybox_color
|
|
end
|
|
|
|
local ok_skybox, skybox_variant = pcall(toolkit.generate_variant, {
|
|
key = "skybox",
|
|
template = "solid_color",
|
|
output_mode = output_mode,
|
|
compile = compile,
|
|
parameters = {color = skybox_color},
|
|
})
|
|
if ok_skybox then
|
|
generated.skybox = skybox_variant
|
|
else
|
|
logger("Skybox shader generation failed: %s", tostring(skybox_variant))
|
|
end
|
|
|
|
logger("Generated %d shader variants", count_shader_variants(generated))
|
|
return generated, skybox_color
|
|
end
|
|
|
|
function M.build_gui_variants()
|
|
local ok, toolkit = pcall(require, "shader_toolkit")
|
|
if not ok then
|
|
error("Shader toolkit unavailable: " .. tostring(toolkit))
|
|
end
|
|
|
|
local ok_generate, variant = pcall(toolkit.generate_variant, {
|
|
key = "default",
|
|
template = "gui_2d",
|
|
output_mode = "source",
|
|
compile = false,
|
|
})
|
|
if not ok_generate then
|
|
error("Shader generation failed: " .. tostring(variant))
|
|
end
|
|
|
|
return {default = variant}
|
|
end
|
|
|
|
function M.build_soundboard_variants()
|
|
local ok, toolkit = pcall(require, "shader_toolkit")
|
|
if not ok then
|
|
error("Shader toolkit unavailable: " .. tostring(toolkit))
|
|
end
|
|
|
|
local ok_generate, variant = pcall(toolkit.generate_variant, {
|
|
key = "default",
|
|
template = "cube_rainbow",
|
|
output_name = "cube",
|
|
output_mode = "source",
|
|
compile = false,
|
|
})
|
|
if not ok_generate then
|
|
error("Shader generation failed: " .. tostring(variant))
|
|
end
|
|
|
|
return {default = variant}
|
|
end
|
|
|
|
return M
|