Refactor shader widget classes and remove deprecated shader_spec_widget

- Replaced instances of shader_spec_widget with procedural_shader_widget in gradient_widget and wave_widget.
- Updated gradient_widget and wave_widget to use new effect handling methods.
- Removed the deprecated shader_spec_widget.h file and its associated functionality.
- Adjusted header template to reflect changes in push constant effect type naming.
This commit is contained in:
daiqingshuang
2025-12-24 17:33:45 +08:00
parent f9adcf5f5c
commit 8b0a14d12a
13 changed files with 360 additions and 1220 deletions

View File

@@ -86,8 +86,8 @@ namespace mirage {
*/
template <typename ShaderSpec>
constexpr bool validate_shader_spec_push_constants() {
if constexpr (requires { typename ShaderSpec::push_constant_effect_type; }) {
using EffectType = typename ShaderSpec::push_constant_effect_type;
if constexpr (requires { typename ShaderSpec::effect_type; }) {
using EffectType = typename ShaderSpec::effect_type;
// 验证效果类型的大小 (Layer 3 最大 16 字节)
constexpr bool size_valid = sizeof(EffectType) <= PUSH_CONSTANT_EFFECT_MAX_SIZE;
return size_valid;

View File

@@ -1,220 +0,0 @@
#pragma once
#include "ui/widgets/custom_shader/custom_shader_widget_base.h"
#include "render/vertex_types.h"
#include <type_traits>
namespace mirage {
/// @brief 自定义着色器控件模板基类
///
/// @tparam ParamsT 着色器参数结构体类型(由着色器工具自动生成)
/// @tparam VertexT 顶点类型(默认使用 ui_vertex
///
/// 用户通过继承此类创建自定义着色器控件。ParamsT 类型应由着色器工具
/// 从 GLSL UBO 定义自动生成,确保 C++ 和着色器之间的类型安全。
///
/// 支持三种渲染模式:
/// - **程序化渲染**:使用着色器生成内容(无子控件,无源纹理)
/// - **后处理模式**:对子控件渲染结果或指定纹理应用着色器效果
/// - **自定义几何模式**:使用自定义顶点着色器和顶点缓冲
///
/// @example
/// ```cpp
/// // 使用工具生成的类型
/// #include "gen/shaders/gradient.h"
///
/// class gradient_widget : public custom_shader_widget<shaders::GradientParams> {
/// public:
/// gradient_widget() {
/// params().start_color = {1, 0, 0, 1};
/// params().end_color = {0, 0, 1, 1};
/// }
///
/// auto& colors(const vec4f_t& start, const vec4f_t& end) {
/// params().start_color = start;
/// params().end_color = end;
/// mark_params_dirty();
/// return *this;
/// }
///
/// protected:
/// auto get_shader_id() const noexcept -> uint32_t override {
/// return hash_compile_time("gradient_widget");
/// }
///
/// auto get_fragment_shader_spirv() const -> std::span<const uint32_t> override {
/// return shaders::gradient_frag_spirv;
/// }
///
/// auto get_bindings() const -> std::span<const shader_binding_info> override {
/// return shaders::gradient_bindings;
/// }
///
/// auto get_render_mode() const noexcept -> custom_shader_render_mode override {
/// return custom_shader_render_mode::procedural;
/// }
/// };
/// ```
template <typename ParamsT, typename VertexT = ui_vertex>
class custom_shader_widget : public custom_shader_widget_base {
public:
using params_type = ParamsT;
using vertex_type = VertexT;
// 静态断言:确保 ParamsT 满足要求
static_assert(std::is_standard_layout_v<ParamsT>,
"ParamsT must be standard layout for GPU compatibility");
static_assert(alignof(ParamsT) <= 16,
"ParamsT alignment must not exceed 16 bytes");
custom_shader_widget() = default;
~custom_shader_widget() override = default;
// ========================================================================
// 参数访问
// ========================================================================
/// @brief 获取参数的可变引用
/// @note 修改后需要调用 mark_params_dirty()
[[nodiscard]] auto params() noexcept -> ParamsT& { return params_; }
/// @brief 获取参数的只读引用
[[nodiscard]] auto params() const noexcept -> const ParamsT& { return params_; }
/// @brief 标记参数已修改
void mark_params_dirty() {
params_dirty_ = true;
mark_render_dirty_internal();
}
protected:
// ========================================================================
// 实现基类纯虚函数
// ========================================================================
[[nodiscard]] auto get_params_data() const
-> std::pair<const void*, size_t> override {
return {&params_, sizeof(ParamsT)};
}
[[nodiscard]] auto is_params_dirty() const noexcept -> bool override {
return params_dirty_;
}
void clear_params_dirty() override {
params_dirty_ = false;
}
// ========================================================================
// 自定义顶点支持
// ========================================================================
/// @brief 标记顶点数据已修改
void mark_vertices_dirty() {
vertices_dirty_ = true;
mark_render_dirty_internal();
}
[[nodiscard]] auto is_vertices_dirty() const noexcept -> bool override {
return vertices_dirty_;
}
void clear_vertices_dirty() override {
vertices_dirty_ = false;
}
// ========================================================================
// 顶点数据管理(仅 custom_geometry 模式使用)
// ========================================================================
/// @brief 获取顶点数据
[[nodiscard]] auto get_vertices() const noexcept -> const std::vector<VertexT>& {
return vertices_;
}
/// @brief 获取顶点数据(可修改)
[[nodiscard]] auto get_vertices() noexcept -> std::vector<VertexT>& {
return vertices_;
}
/// @brief 设置顶点数据
void set_vertices(std::vector<VertexT> vertices) {
vertices_ = std::move(vertices);
mark_vertices_dirty();
}
/// @brief 获取索引数据
[[nodiscard]] auto get_indices() const noexcept -> const std::vector<uint32_t>& {
return indices_;
}
/// @brief 设置索引数据
void set_indices(std::vector<uint32_t> indices) {
indices_ = std::move(indices);
mark_vertices_dirty();
}
/// @brief 获取顶点缓冲配置
[[nodiscard]] auto get_vertex_buffer_config() const
-> std::optional<custom_vertex_buffer_config> override {
if (vertices_.empty()) {
return std::nullopt;
}
return custom_vertex_buffer_config{
.data = vertices_.data(),
.data_size = vertices_.size() * sizeof(VertexT),
.vertex_count = vertices_.size(),
.binding = get_vertex_binding_description(),
.attributes = get_vertex_attribute_descriptions()
};
}
/// @brief 获取索引缓冲配置
[[nodiscard]] auto get_index_buffer_config() const
-> std::optional<index_buffer_config> override {
if (indices_.empty()) {
return std::nullopt;
}
return index_buffer_config{
.data = indices_.data(),
.index_count = indices_.size()
};
}
/// @brief 获取顶点绑定描述(可重写)
[[nodiscard]] virtual auto get_vertex_binding_description() const
-> vk::VertexInputBindingDescription {
if constexpr (requires { VertexT::get_binding_description(); }) {
return VertexT::get_binding_description();
}
else {
return vk::VertexInputBindingDescription{
0, sizeof(VertexT), vk::VertexInputRate::eVertex
};
}
}
/// @brief 获取顶点属性描述(可重写)
[[nodiscard]] virtual auto get_vertex_attribute_descriptions() const
-> std::vector<vk::VertexInputAttributeDescription> {
if constexpr (requires { VertexT::get_attribute_descriptions(); }) {
auto attrs = VertexT::get_attribute_descriptions();
return std::vector<vk::VertexInputAttributeDescription>(
attrs.begin(), attrs.end());
}
else {
return {};
}
}
private:
ParamsT params_{};
bool params_dirty_ = true;
bool vertices_dirty_ = false;
std::vector<VertexT> vertices_;
std::vector<uint32_t> indices_;
};
} // namespace mirage

View File

@@ -1,6 +1,6 @@
#pragma once
#include "ui/widgets/custom_shader/shader_spec_widget.h"
#include "ui/widgets/custom_shader/post_process/post_process_shader_widget.h"
#include "blur_vert_frag.h"
namespace mirage {
@@ -25,7 +25,7 @@ namespace mirage {
/// blur->set_samples(32);
/// blur->set_direction(glm::vec2{1.0f, 0.0f}); // 水平模糊
/// @endcode
class blur_widget : public shader_spec_widget<shaders::blur_shader_spec<>> {
class blur_widget : public post_process_shader_widget<shaders::blur_shader_spec<>> {
public:
blur_widget() {
// Uniform Buffer 参数默认值
@@ -33,8 +33,8 @@ public:
params().samples = 16;
params().direction = vec2f_t{1.0f, 0.0f};
// Push Constants 效果参数默认值
push_constant_effect().intensity = 1.0f;
// 效果参数默认值
effect().intensity = 1.0f;
}
~blur_widget() override = default;
@@ -104,35 +104,25 @@ public:
}
// ========================================================================
// Push Constants 效果参数接口
// 效果参数接口
// ========================================================================
/// @brief 设置效果强度
/// @param intensity 强度值 [0.0, 1.0]
/// @return *this
auto& set_intensity(float intensity) {
push_constant_effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
mark_push_constant_effect_dirty();
effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
mark_effect_dirty();
return *this;
}
/// @brief 获取效果强度
/// @return 强度值 [0.0, 1.0]
[[nodiscard]] auto get_intensity() const noexcept -> float {
return push_constant_effect().intensity;
return effect().intensity;
}
// ========================================================================
// 基类虚函数实现
// ========================================================================
protected:
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::post_process;
}
/// @brief 更新描述符绑定 - 自定义采样器配置
///
/// 重写此方法以使用自定义采样器配置。

View File

@@ -1,6 +1,6 @@
#pragma once
#include "ui/widgets/custom_shader/shader_spec_widget.h"
#include "ui/widgets/custom_shader/post_process/post_process_shader_widget.h"
#include "chromatic_aberration_vert_frag.h"
namespace mirage {
@@ -20,14 +20,14 @@ namespace mirage {
/// chromatic_aberration->set_size({200, 100});
/// chromatic_aberration->set_offset(vec2f_t{0.02f, 0.0f});
/// @endcode
class chromatic_aberration_widget : public shader_spec_widget<shaders::chromatic_aberration_shader_spec<>> {
class chromatic_aberration_widget : public post_process_shader_widget<shaders::chromatic_aberration_shader_spec<>> {
public:
chromatic_aberration_widget() {
// Uniform Buffer 参数默认值
params().offset = vec2f_t{0.02f, 0.0f};
// Push Constants 效果参数默认值
push_constant_effect().intensity = 1.0f;
// 效果参数默认值
effect().intensity = 1.0f;
}
~chromatic_aberration_widget() override = default;
@@ -81,33 +81,22 @@ public:
}
// ========================================================================
// Push Constants 效果参数接口
// 效果参数接口
// ========================================================================
/// @brief 设置效果强度
/// @param intensity 强度值 [0.0, 1.0]
/// @return *this
auto& set_intensity(float intensity) {
push_constant_effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
mark_push_constant_effect_dirty();
effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
mark_effect_dirty();
return *this;
}
/// @brief 获取效果强度
/// @return 强度值 [0.0, 1.0]
[[nodiscard]] auto get_intensity() const noexcept -> float {
return push_constant_effect().intensity;
}
// ========================================================================
// 基类虚函数实现 - 只需重写渲染模式
// ========================================================================
protected:
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::post_process;
return effect().intensity;
}
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include "ui/widgets/custom_shader/shader_spec_widget.h"
#include "ui/widgets/custom_shader/post_process/post_process_shader_widget.h"
#include "color_adjust_vert_frag.h"
namespace mirage {
@@ -20,7 +20,7 @@ namespace mirage {
/// color_adjust->set_saturation(1.5f);
/// color_adjust->set_gamma(0.8f);
/// @endcode
class color_adjust_widget : public shader_spec_widget<shaders::color_adjust_shader_spec<>> {
class color_adjust_widget : public post_process_shader_widget<shaders::color_adjust_shader_spec<>> {
public:
color_adjust_widget() {
// Uniform Buffer 参数默认值
@@ -29,8 +29,8 @@ public:
params().saturation = 1.0f;
params().gamma = 1.0f;
// Push Constants 效果参数默认值
push_constant_effect().intensity = 1.0f;
// 效果参数默认值
effect().intensity = 1.0f;
}
~color_adjust_widget() override = default;
@@ -99,33 +99,22 @@ public:
}
// ========================================================================
// Push Constants 效果参数接口
// 效果参数接口
// ========================================================================
/// @brief 设置效果强度
/// @param intensity 强度值 [0.0, 1.0]
/// @return *this
auto& set_intensity(float intensity) {
push_constant_effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
mark_push_constant_effect_dirty();
effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
mark_effect_dirty();
return *this;
}
/// @brief 获取效果强度
/// @return 强度值 [0.0, 1.0]
[[nodiscard]] auto get_intensity() const noexcept -> float {
return push_constant_effect().intensity;
}
// ========================================================================
// 基类虚函数实现 - 只需重写渲染模式
// ========================================================================
protected:
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::post_process;
return effect().intensity;
}
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include "ui/widgets/custom_shader/shader_spec_widget.h"
#include "ui/widgets/custom_shader/post_process/post_process_shader_widget.h"
#include "color_tint_vert_frag.h"
namespace mirage {
@@ -26,7 +26,7 @@ namespace mirage {
/// color_tint->set_tint_color(glm::vec4{1.0f, 0.5f, 0.0f, 0.7f}); // 橙色强度0.7
/// color_tint->set_blend_mode(2); // Multiply 模式
/// @endcode
class color_tint_widget : public shader_spec_widget<shaders::color_tint_shader_spec<>> {
class color_tint_widget : public post_process_shader_widget<shaders::color_tint_shader_spec<>> {
public:
color_tint_widget() = default;
~color_tint_widget() override = default;
@@ -79,17 +79,6 @@ public:
[[nodiscard]] auto get_blend_mode() const noexcept -> int32_t {
return params().blend_mode;
}
// ========================================================================
// 基类虚函数实现 - 只需重写渲染模式
// ========================================================================
protected:
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::post_process;
}
};
} // namespace mirage

View File

@@ -1,6 +1,6 @@
#pragma once
#include "ui/widgets/custom_shader/shader_spec_widget.h"
#include "ui/widgets/custom_shader/post_process/post_process_shader_widget.h"
#include "noise_vert_frag.h"
namespace mirage {
@@ -32,7 +32,7 @@ namespace mirage {
/// animated_noise->set_grain_size(2.0f);
/// animated_noise->set_animated(true); // 启用动画
/// @endcode
class noise_widget : public shader_spec_widget<shaders::noise_shader_spec<>> {
class noise_widget : public post_process_shader_widget<shaders::noise_shader_spec<>> {
public:
noise_widget() = default;
~noise_widget() override = default;
@@ -80,17 +80,7 @@ public:
return *this;
}
// ========================================================================
// 基类虚函数实现 - 只需重写渲染模式
// ========================================================================
protected:
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::post_process;
}
/// @brief 检查是否需要动画更新
/// @return 当 animated 参数为 true 时返回 true
[[nodiscard]] auto is_animated() const noexcept -> bool override {

View File

@@ -1,6 +1,6 @@
#pragma once
#include "ui/widgets/custom_shader/shader_spec_widget.h"
#include "ui/widgets/custom_shader/post_process/post_process_shader_widget.h"
#include "vignette_vert_frag.h"
namespace mirage {
@@ -23,7 +23,7 @@ namespace mirage {
/// vignette->set_softness(0.3f);
/// vignette->set_tint_color(glm::vec4{0.0f, 0.0f, 0.0f, 1.0f}); // 黑色暗角
/// @endcode
class vignette_widget : public shader_spec_widget<shaders::vignette_shader_spec<>> {
class vignette_widget : public post_process_shader_widget<shaders::vignette_shader_spec<>> {
public:
vignette_widget() = default;
~vignette_widget() override = default;
@@ -76,16 +76,5 @@ namespace mirage {
[[nodiscard]] auto get_tint_color() const noexcept {
return params().tint_color;
}
// ========================================================================
// 基类虚函数实现 - 只需重写渲染模式
// ========================================================================
protected:
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::post_process;
}
};
} // namespace mirage

View File

@@ -1,170 +1,91 @@
#pragma once
#include "ui/widgets/custom_shader/custom_shader_widget.h"
#include <glm/vec4.hpp>
#include "ui/widgets/custom_shader/post_process/post_process_shader_widget.h"
#include "glitch_effect_vert_frag.h"
namespace mirage::ui {
namespace mirage {
/// @brief 故障效果控件
///
/// 使用后处理模式,对子控件或源纹理应用故障效果。
/// 支持 RGB 分离、扫描线和噪声效果,可用于动画.
///
/// @par 使用示例
/// @code
/// // 创建故障效果控件
/// auto glitch = create_widget<glitch_widget>();
/// glitch->set_size({200, 100});
/// glitch->set_intensity(0.5f);
/// glitch->set_scan_line_frequency(100.0f);
/// glitch->set_noise_amount(0.1f);
/// @endcode
class glitch_widget : public post_process_shader_widget<shaders::glitch_effect_shader_spec<>> {
public:
glitch_widget() {
// 设置默认效果参数Layer 3 Push Constants
// effect_params.x = intensity, y = scan_line_frequency, z = noise_amount
effect().effect_params.x() = 0.5f; // intensity
effect().effect_params.y() = 100.0f; // scan_line_frequency
effect().effect_params.z() = 0.1f; // noise_amount
}
/// @brief 故障效果控件
///
/// 使用后处理模式,对子控件或源纹理应用故障效果。
/// 支持 RGB 分离、扫描线和噪声效果,可用于动画.
///
/// @par 使用示例
/// @code
/// // 创建故障效果控件
/// auto glitch = create_widget<glitch_widget>();
/// glitch->set_size({200, 100});
/// glitch->set_intensity(0.5f);
/// glitch->set_scan_line_frequency(100.0f);
/// glitch->set_noise_amount(0.1f);
/// @endcode
class glitch_widget : public custom_shader_widget<glitch_widget::GlitchParams> {
public:
/// @brief 故障效果参数结构体
/// @note 对应 shader 中的 GlitchParams UBO
struct GlitchParams {
float time{0.0f}; ///< 时间(秒)
float intensity{0.5f}; ///< 故障强度 [0, 1]
float scan_line_freq{100.0f}; ///< 扫描线频率
float noise_amount{0.1f}; ///< 噪声量
};
~glitch_widget() override = default;
glitch_widget() = default;
~glitch_widget() override = default;
// ========================================================================
// 公共接口
// ========================================================================
// ========================================================================
// 公共接口
// ========================================================================
/// @brief 设置故障强度
/// @param intensity 强度 [0, 1]
/// @return *this
auto& set_intensity(float intensity) {
effect().effect_params.x() = std::clamp(intensity, 0.0f, 1.0f);
mark_effect_dirty();
return *this;
}
/// @brief 设置故障强度
/// @param intensity 强度 [0, 1]
/// @return *this
auto& set_intensity(float intensity) {
params().intensity = glm::clamp(intensity, 0.0f, 1.0f);
mark_params_dirty();
return *this;
}
/// @brief 获取故障强度
/// @return 强度 [0, 1]
[[nodiscard]] auto get_intensity() const noexcept -> float {
return effect().effect_params.x();
}
/// @brief 获取故障强度
/// @return 强度 [0, 1]
[[nodiscard]] auto get_intensity() const noexcept -> float {
return params().intensity;
}
/// @brief 设置扫描线频率
/// @param freq 频率
/// @return *this
auto& set_scan_line_frequency(float freq) {
effect().effect_params.y() = freq;
mark_effect_dirty();
return *this;
}
/// @brief 设置扫描线频率
/// @param freq 频率
/// @return *this
auto& set_scan_line_frequency(float freq) {
params().scan_line_freq = freq;
mark_params_dirty();
return *this;
}
/// @brief 获取扫描线频率
/// @return 频率
[[nodiscard]] auto get_scan_line_frequency() const noexcept -> float {
return effect().effect_params.y();
}
/// @brief 获取扫描线频率
/// @return 频率
[[nodiscard]] auto get_scan_line_frequency() const noexcept -> float {
return params().scan_line_freq;
}
/// @brief 设置噪声量
/// @param amount 噪声量
/// @return *this
auto& set_noise_amount(float amount) {
effect().effect_params.z() = amount;
mark_effect_dirty();
return *this;
}
/// @brief 设置噪声量
/// @param amount 噪声量
/// @return *this
auto& set_noise_amount(float amount) {
params().noise_amount = amount;
mark_params_dirty();
return *this;
}
/// @brief 获取噪声量
/// @return 噪声量
[[nodiscard]] auto get_noise_amount() const noexcept -> float {
return effect().effect_params.z();
}
/// @brief 获取噪声量
/// @return 噪声量
[[nodiscard]] auto get_noise_amount() const noexcept -> float {
return params().noise_amount;
}
// ========================================================================
// 动画控制
// ========================================================================
/// @brief 设置时间(用于手动控制动画
/// @param time 时间(秒)
/// @return *this
auto& set_time(float time) {
params().time = time;
mark_params_dirty();
return *this;
}
/// @brief 获取当前时间
/// @return 时间(秒)
[[nodiscard]] auto get_time() const noexcept -> float {
return params().time;
}
// ========================================================================
// 动画控制
// ========================================================================
/// @brief 标记为动画控件(启用自动时间更新)
[[nodiscard]] auto is_animated() const noexcept -> bool override {
return true;
}
/// @brief 更新时间(每帧调用)
void tick(float dt) override {
params().time += dt;
mark_params_dirty();
}
// ========================================================================
// 基类虚函数实现
// ========================================================================
protected:
/// @brief 获取着色器唯一标识符
[[nodiscard]] auto get_shader_id() const noexcept -> uint32_t override {
return hash_compile_time("glitch_widget");
}
/// @brief 获取片段着色器 SPIR-V
/// @note TODO: 使用着色器工具链预编译的 SPIR-V
[[nodiscard]] auto get_fragment_shader_spirv() const
-> std::span<const uint32_t> override {
// TODO: 返回预编译的 glitch_effect.frag.glsl SPIR-V
// 从生成的着色器头文件获取:
// return shaders::glitch_effect_frag_spirv;
return {};
}
/// @brief 获取描述符绑定信息
[[nodiscard]] auto get_bindings() const
-> std::span<const shader_binding_info> override {
static constexpr shader_binding_info bindings[] = {
{
.binding = 0,
.type = vk::DescriptorType::eUniformBuffer,
.count = 1,
.stage = vk::ShaderStageFlagBits::eFragment
},
{
.binding = 1,
.type = vk::DescriptorType::eCombinedImageSampler,
.count = 1,
.stage = vk::ShaderStageFlagBits::eFragment
}
};
return bindings;
}
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::post_process;
}
/// @brief 获取顶点着色器 SPIR-V
/// @note 使用默认的程序化四边形顶点着色器
[[nodiscard]] auto get_vertex_shader_spirv() const
-> std::span<const uint32_t> override {
// 返回 nullopt 使用默认顶点着色器
return {};
}
};
} // namespace mirage::ui
/// @brief 标记为动画控件(启用自动时间更新
[[nodiscard]] auto is_animated() const noexcept -> bool override {
return true;
}
};
} // namespace mirage

View File

@@ -1,166 +1,146 @@
#pragma once
#include "ui/widgets/custom_shader/shader_spec_widget.h"
#include "ui/widgets/custom_shader/procedural/procedural_shader_widget.h"
#include "gradient_vert_frag.h"
#include <cmath>
namespace mirage {
/// @brief 渐变类型枚举
enum class gradient_type : uint32_t {
horizontal = 0, ///< 水平渐变
vertical = 1, ///< 垂直渐变
diagonal = 2, ///< 对角线/角度渐变
radial = 3 ///< 径向渐变
};
/// @brief 渐变类型枚举
enum class gradient_type : uint32_t {
horizontal = 0, ///< 水平渐变
vertical = 1, ///< 垂直渐变
diagonal = 2, ///< 对角线/角度渐变
radial = 3 ///< 径向渐变
};
/// @brief 渐变背景控件
///
/// 使用程序化渲染模式,通过着色器生成线性渐变背景。
/// 支持自定义渐变颜色、方向和角度。
///
/// 渐变参数通过 Push Constants 传递:
/// - v_color (通过顶点着色器): 起始颜色
/// - base_color: 结束颜色
/// - effect_params.x: 渐变类型 (0=horizontal, 1=vertical, 2=diagonal, 3=radial)
/// - effect_params.y: 渐变角度(弧度),用于 diagonal 模式
///
/// @par 使用示例
/// @code
/// // 创建渐变控件
/// auto gradient = create_widget<gradient_widget>();
/// gradient->set_size({200, 100});
/// gradient->set_colors(
/// vec4f_t{1.0f, 0.0f, 0.0f, 1.0f}, // 红色起始
/// vec4f_t{0.0f, 0.0f, 1.0f, 1.0f} // 蓝色结束
/// );
/// gradient->set_gradient_type(gradient_type::diagonal);
/// gradient->set_angle(45.0f); // 45度角
/// @endcode
class gradient_widget : public procedural_shader_widget<shaders::gradient_shader_spec<>> {
public:
gradient_widget() {
// 设置默认颜色
set_start_color({1.0f, 0.0f, 0.0f, 1.0f}); // 红色
set_end_color({0.0f, 0.0f, 1.0f, 1.0f}); // 蓝色
set_gradient_type(gradient_type::horizontal);
set_angle(0.0f);
}
/// @brief 渐变背景控件
///
/// 使用程序化渲染模式,通过着色器生成线性渐变背景。
/// 支持自定义渐变颜色、方向和角度。
///
/// 渐变参数通过 Push Constants 传递:
/// - v_color (通过顶点着色器): 起始颜色
/// - base_color: 结束颜色
/// - effect_params.x: 渐变类型 (0=horizontal, 1=vertical, 2=diagonal, 3=radial)
/// - effect_params.y: 渐变角度(弧度),用于 diagonal 模式
///
/// @par 使用示例
/// @code
/// // 创建渐变控件
/// auto gradient = create_widget<gradient_widget>();
/// gradient->set_size({200, 100});
/// gradient->set_colors(
/// vec4f_t{1.0f, 0.0f, 0.0f, 1.0f}, // 红色起始
/// vec4f_t{0.0f, 0.0f, 1.0f, 1.0f} // 蓝色结束
/// );
/// gradient->set_gradient_type(gradient_type::diagonal);
/// gradient->set_angle(45.0f); // 45度角
/// @endcode
class gradient_widget : public shader_spec_widget<shaders::gradient_shader_spec<>> {
public:
gradient_widget() {
// 设置默认颜色
set_start_color({1.0f, 0.0f, 0.0f, 1.0f}); // 红色
set_end_color({0.0f, 0.0f, 1.0f, 1.0f}); // 蓝色
set_gradient_type(gradient_type::horizontal);
set_angle(0.0f);
}
~gradient_widget() override = default;
~gradient_widget() override = default;
// ========================================================================
// 公共接口
// ========================================================================
// ========================================================================
// 公共接口
// ========================================================================
/// @brief 设置渐变颜色
/// @param start 起始颜色
/// @param end 结束颜色
/// @return *this
auto& set_colors(const vec4f_t& start, const vec4f_t& end) {
set_start_color(start);
set_end_color(end);
return *this;
}
/// @brief 设置渐变颜色
/// @param start 起始颜色
/// @param end 结束颜色
/// @return *this
auto& set_colors(const vec4f_t& start, const vec4f_t& end) {
set_start_color(start);
set_end_color(end);
return *this;
}
/// @brief 设置渐变颜色(使用线性 RGB
/// @param start 起始颜色 [0-255]
/// @param end 结束颜色 [0-255]
/// @return *this
auto& set_colors_linear(const vec4f_t& start, const vec4f_t& end) {
return set_colors(start / 255.0f, end / 255.0f);
}
/// @brief 设置渐变颜色(使用线性 RGB
/// @param start 起始颜色 [0-255]
/// @param end 结束颜色 [0-255]
/// @return *this
auto& set_colors_linear(const vec4f_t& start, const vec4f_t& end) {
return set_colors(start / 255.0f, end / 255.0f);
}
/// @brief 设置起始颜色
/// @param color 起始颜色
/// @return *this
auto& set_start_color(const vec4f_t& color) {
start_color_ = color;
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 设置起始颜色
/// @param color 起始颜色
/// @return *this
auto& set_start_color(const vec4f_t& color) {
start_color_ = color;
mark_effect_dirty();
return *this;
}
/// @brief 获取起始颜色
[[nodiscard]] auto get_start_color() const noexcept -> vec4f_t {
return start_color_;
}
/// @brief 获取起始颜色
[[nodiscard]] auto get_start_color() const noexcept -> vec4f_t {
return start_color_;
}
/// @brief 设置结束颜色
/// @param color 结束颜色
/// @return *this
auto& set_end_color(const vec4f_t& color) {
push_constant_effect().base_color = color;
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 设置结束颜色
/// @param color 结束颜色
/// @return *this
auto& set_end_color(const vec4f_t& color) {
effect().base_color = color;
mark_effect_dirty();
return *this;
}
/// @brief 获取结束颜色
[[nodiscard]] auto get_end_color() const noexcept -> vec4f_t {
return push_constant_effect().base_color;
}
/// @brief 获取结束颜色
[[nodiscard]] auto get_end_color() const noexcept -> vec4f_t {
return effect().base_color;
}
/// @brief 设置渐变类型
/// @param type 渐变类型
/// @return *this
auto& set_gradient_type(gradient_type type) {
push_constant_effect().effect_params.x() = static_cast<float>(type);
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 设置渐变类型
/// @param type 渐变类型
/// @return *this
auto& set_gradient_type(gradient_type type) {
effect().effect_params.x() = static_cast<float>(type);
mark_effect_dirty();
return *this;
}
/// @brief 获取渐变类型
[[nodiscard]] auto get_gradient_type() const noexcept -> gradient_type {
return static_cast<gradient_type>(
static_cast<uint32_t>(push_constant_effect().effect_params.x()));
}
/// @brief 获取渐变类型
[[nodiscard]] auto get_gradient_type() const noexcept -> gradient_type {
return static_cast<gradient_type>(
static_cast<uint32_t>(effect().effect_params.x()));
}
/// @brief 设置渐变角度
/// @param degrees 角度(度)
/// @return *this
auto& set_angle(float degrees) {
float radians = degrees * 3.14159265358979323846f / 180.0f;
push_constant_effect().effect_params.y() = radians;
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 设置渐变角度
/// @param degrees 角度(度)
/// @return *this
auto& set_angle(float degrees) {
float radians = degrees * 3.14159265358979323846f / 180.0f;
effect().effect_params.y() = radians;
mark_effect_dirty();
return *this;
}
/// @brief 获取渐变角度
/// @return 角度(度)
[[nodiscard]] auto get_angle() const noexcept -> float {
return push_constant_effect().effect_params.y() * 180.0f / 3.14159265358979323846f;
}
/// @brief 获取渐变角度
/// @return 角度(度)
[[nodiscard]] auto get_angle() const noexcept -> float {
return effect().effect_params.y() * 180.0f / 3.14159265358979323846f;
}
/// @brief 设置渐变方向(归一化向量,自动计算角度)
/// @param direction 方向向量
/// @return *this
auto& set_direction(const vec2f_t& direction) {
float angle = std::atan2(direction.y(), direction.x());
push_constant_effect().effect_params.y() = angle;
set_gradient_type(gradient_type::diagonal);
mark_push_constant_effect_dirty();
return *this;
}
// ========================================================================
// 基类虚函数实现
// ========================================================================
protected:
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::procedural;
}
/// @brief 获取 Push Constants 效果参数数据
/// @note 只返回 effect_params 部分16字节对应 Layer 3
/// Layer 2 的 widget_rect 和 base_color 由渲染器自动填充
[[nodiscard]] auto get_push_constant_effect_data() const
-> std::pair<const void*, size_t> override {
return {&(push_constant_effect().effect_params), sizeof(vec4f_t)};
}
private:
vec4f_t start_color_{1.0f, 0.0f, 0.0f, 1.0f}; ///< 起始颜色(暂存,需要通过颜色传递机制使用)
};
/// @brief 设置渐变方向(归一化向量,自动计算角度)
/// @param direction 方向向量
/// @return *this
auto& set_direction(const vec2f_t& direction) {
float angle = std::atan2(direction.y(), direction.x());
effect().effect_params.y() = angle;
set_gradient_type(gradient_type::diagonal);
mark_effect_dirty();
return *this;
}
private:
vec4f_t start_color_{1.0f, 0.0f, 0.0f, 1.0f}; ///< 起始颜色(暂存,需要通过颜色传递机制使用)
};
} // namespace mirage

View File

@@ -1,167 +1,147 @@
#pragma once
#include "ui/widgets/custom_shader/shader_spec_widget.h"
#include "ui/widgets/custom_shader/procedural/procedural_shader_widget.h"
#include "wave_vert_frag.h"
namespace mirage {
/// @brief 波浪效果控件
///
/// 使用程序化渲染模式,通过正弦波生成动态颜色渐变效果。
/// 支持动画,可用于创建流动的波浪背景。
///
/// 波浪参数通过 Push Constants 传递:
/// - v_color (通过顶点着色器): 主色
/// - base_color: 次色
/// - effect_params.x: frequency 波浪频率(推荐值: 5.0 - 20.0
/// - effect_params.y: amplitude 波浪振幅(推荐值: 0.1 - 0.5
/// - effect_params.z: speed 波浪速度(推荐值: 1.0 - 5.0
/// - time: 由渲染器自动更新
///
/// @par 使用示例
/// @code
/// // 创建波浪效果控件
/// auto wave = create_widget<wave_widget>();
/// wave->set_size({200, 100});
/// wave->set_colors(
/// vec4f_t{0.0f, 0.5f, 1.0f, 1.0f}, // 蓝色主色
/// vec4f_t{0.0f, 1.0f, 0.8f, 1.0f} // 青色次色
/// );
/// wave->set_frequency(10.0f);
/// wave->set_amplitude(0.2f);
/// wave->set_speed(2.0f);
/// @endcode
class wave_widget : public procedural_shader_widget<shaders::wave_shader_spec<>> {
public:
wave_widget() {
// 设置默认颜色
set_color1({0.0f, 0.5f, 1.0f, 1.0f}); // 蓝色主色
set_color2({0.0f, 1.0f, 0.8f, 1.0f}); // 青色次色
/// @brief 波浪效果控件
///
/// 使用程序化渲染模式,通过正弦波生成动态颜色渐变效果。
/// 支持动画,可用于创建流动的波浪背景。
///
/// 波浪参数通过 Push Constants 传递:
/// - v_color (通过顶点着色器): 主色
/// - base_color: 次色
/// - effect_params.x: frequency 波浪频率(推荐值: 5.0 - 20.0
/// - effect_params.y: amplitude 波浪振幅(推荐值: 0.1 - 0.5
/// - effect_params.z: speed 波浪速度(推荐值: 1.0 - 5.0
/// - time: 由渲染器自动更新
///
/// @par 使用示例
/// @code
/// // 创建波浪效果控件
/// auto wave = create_widget<wave_widget>();
/// wave->set_size({200, 100});
/// wave->set_colors(
/// vec4f_t{0.0f, 0.5f, 1.0f, 1.0f}, // 蓝色主色
/// vec4f_t{0.0f, 1.0f, 0.8f, 1.0f} // 青色次色
/// );
/// wave->set_frequency(10.0f);
/// wave->set_amplitude(0.2f);
/// wave->set_speed(2.0f);
/// @endcode
class wave_widget : public shader_spec_widget<shaders::wave_shader_spec<>> {
public:
wave_widget() {
// 设置默认颜色
set_color1({0.0f, 0.5f, 1.0f, 1.0f}); // 蓝色主色
set_color2({0.0f, 1.0f, 0.8f, 1.0f}); // 青色次色
// 设置默认波浪参数
set_frequency(10.0f);
set_amplitude(0.2f);
set_speed(2.0f);
}
~wave_widget() override = default;
// 设置默认波浪参数
set_frequency(10.0f);
set_amplitude(0.2f);
set_speed(2.0f);
}
// ========================================================================
// 公共接口
// ========================================================================
~wave_widget() override = default;
/// @brief 设置颜色
/// @param c1 主色
/// @param c2 次色
/// @return *this
auto& set_colors(const vec4f_t& c1, const vec4f_t& c2) {
set_color1(c1);
set_color2(c2);
return *this;
}
// ========================================================================
// 公共接口
// ========================================================================
/// @brief 设置
/// @param color 主色
/// @return *this
auto& set_color1(const vec4f_t& color) {
color1_ = color;
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 设置
/// @param c1 主色
/// @param c2 次色
/// @return *this
auto& set_colors(const vec4f_t& c1, const vec4f_t& c2) {
set_color1(c1);
set_color2(c2);
return *this;
}
/// @brief 获取主色
[[nodiscard]] auto get_color1() const noexcept -> vec4f_t {
return color1_;
}
/// @brief 设置主色
/// @param color 主色
/// @return *this
auto& set_color1(const vec4f_t& color) {
color1_ = color;
mark_effect_dirty();
return *this;
}
/// @brief 设置次
/// @param color 次色
/// @return *this
auto& set_color2(const vec4f_t& color) {
push_constant_effect().base_color = color;
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 获取主
[[nodiscard]] auto get_color1() const noexcept -> vec4f_t {
return color1_;
}
/// @brief 获取次色
[[nodiscard]] auto get_color2() const noexcept -> vec4f_t {
return push_constant_effect().base_color;
}
/// @brief 设置次色
/// @param color 次色
/// @return *this
auto& set_color2(const vec4f_t& color) {
effect().base_color = color;
mark_effect_dirty();
return *this;
}
/// @brief 设置波浪频率
/// @param freq 频率(每个单位的波浪数)
/// @return *this
auto& set_frequency(float freq) {
push_constant_effect().effect_params.x() = freq;
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 获取次色
[[nodiscard]] auto get_color2() const noexcept -> vec4f_t {
return effect().base_color;
}
/// @brief 获取波浪频率
/// @return 频率
[[nodiscard]] auto get_frequency() const noexcept -> float {
return push_constant_effect().effect_params.x();
}
/// @brief 设置波浪频率
/// @param freq 频率(每个单位的波浪数)
/// @return *this
auto& set_frequency(float freq) {
effect().effect_params.x() = freq;
mark_effect_dirty();
return *this;
}
/// @brief 设置波浪振幅
/// @param amp 振幅UV 偏移量)
/// @return *this
auto& set_amplitude(float amp) {
push_constant_effect().effect_params.y() = amp;
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 获取波浪频率
/// @return 频率
[[nodiscard]] auto get_frequency() const noexcept -> float {
return effect().effect_params.x();
}
/// @brief 获取波浪振幅
/// @return 振幅
[[nodiscard]] auto get_amplitude() const noexcept -> float {
return push_constant_effect().effect_params.y();
}
/// @brief 设置波浪振幅
/// @param amp 振幅UV 偏移量)
/// @return *this
auto& set_amplitude(float amp) {
effect().effect_params.y() = amp;
mark_effect_dirty();
return *this;
}
/// @brief 设置波浪速度
/// @param speed 速度(单位/秒)
/// @return *this
auto& set_speed(float speed) {
push_constant_effect().effect_params.z() = speed;
mark_push_constant_effect_dirty();
return *this;
}
/// @brief 获取波浪振幅
/// @return 振幅
[[nodiscard]] auto get_amplitude() const noexcept -> float {
return effect().effect_params.y();
}
/// @brief 获取波浪速度
/// @return 速度
[[nodiscard]] auto get_speed() const noexcept -> float {
return push_constant_effect().effect_params.z();
}
/// @brief 设置波浪速度
/// @param speed 速度(单位/秒)
/// @return *this
auto& set_speed(float speed) {
effect().effect_params.z() = speed;
mark_effect_dirty();
return *this;
}
// ========================================================================
// 动画控制
// ========================================================================
/// @brief 获取波浪速度
/// @return 速度
[[nodiscard]] auto get_speed() const noexcept -> float {
return effect().effect_params.z();
}
/// @brief 标记为动画控件(启用自动时间更新)
[[nodiscard]] auto is_animated() const noexcept -> bool override {
return true;
}
// ========================================================================
// 动画控制
// ========================================================================
// ========================================================================
// 基类虚函数实现
// ========================================================================
/// @brief 标记为动画控件(启用自动时间更新)
[[nodiscard]] auto is_animated() const noexcept -> bool override {
return true;
}
protected:
/// @brief 获取渲染模式
[[nodiscard]] auto get_render_mode() const noexcept
-> custom_shader_render_mode override {
return custom_shader_render_mode::procedural;
}
/// @brief 获取 Push Constants 效果参数数据
/// @note 只返回 effect_params 部分16字节对应 Layer 3
/// Layer 2 的 widget_rect 和 base_color 由渲染器自动填充
[[nodiscard]] auto get_push_constant_effect_data() const
-> std::pair<const void*, size_t> override {
return {&(push_constant_effect().effect_params), sizeof(vec4f_t)};
}
private:
vec4f_t color1_{0.0f, 0.5f, 1.0f, 1.0f}; ///< 主色(暂存,需要通过颜色传递机制使用)
};
} // namespace mirage
private:
vec4f_t color1_{0.0f, 0.5f, 1.0f, 1.0f}; ///< 主色(暂存,需要通过颜色传递机制使用)
};
} // namespace mirage

View File

@@ -1,457 +0,0 @@
#pragma once
/**
* @file shader_spec_widget.h
* @deprecated This file contains a deprecated class. Use the specialized widget classes instead.
*
* Migration Guide:
* ================
*
* 1. Procedural mode (no source texture):
* Old: shader_spec_widget<MySpec>
* New: procedural_shader_widget<MySpec>
* File: ui/widgets/custom_shader/procedural/procedural_shader_widget.h
*
* 2. PostProcess mode (samples current render target):
* Old: shader_spec_widget<MySpec> with post_process mode
* New: post_process_shader_widget<MySpec>
* File: ui/widgets/custom_shader/post_process/post_process_shader_widget.h
*
* 3. Mask mode (two-pass rendering):
* Old: shader_spec_widget<MySpec> with mask mode
* New: mask_shader_widget<MySpec>
* File: ui/widgets/custom_shader/mask/mask_shader_widget.h
*
* 4. Full custom mode (custom vertex shader and geometry):
* Old: shader_spec_widget<MySpec, VertexT>
* New: full_custom_shader_widget<MySpec, VertexT>
* File: ui/widgets/custom_shader/full_custom/full_custom_shader_widget.h
*
* API Changes:
* ============
* - push_constant_effect() -> effect()
* - mark_push_constant_effect_dirty() -> mark_effect_dirty()
* - push_constant_effect_type -> effect_type
*/
#include "ui/widgets/custom_shader/custom_shader_widget_base.h"
#include "render/vertex_types.h"
#include "render/push_constant_traits.h"
#include <type_traits>
namespace mirage {
/// @brief shader_spec 概念定义
///
/// ShaderSpec 必须提供以下静态成员函数:
/// - get_vertex_spirv() -> std::span<const uint32_t>
/// - get_fragment_spirv() -> std::span<const uint32_t>
/// - get_bindings() -> std::span<const shader_binding_info>
/// - shader_id : uint32_t
/// - params_type : 参数类型
template <typename T>
concept shader_spec_concept = requires {
{ T::get_vertex_spirv() } -> std::convertible_to<std::span<const uint32_t>>;
{ T::get_fragment_spirv() } -> std::convertible_to<std::span<const uint32_t>>;
{ T::get_bindings() } -> std::convertible_to<std::span<const shader_binding_info>>;
{ T::shader_id } -> std::convertible_to<uint32_t>;
typename T::params_type;
};
/// @brief 检测 ShaderSpec 是否提供了 push_constant_effect_type
///
/// 如果 ShaderSpec 提供了 push_constant_effect_type则可以使用
/// shader_spec_widget 的 Push Constants 效果参数功能。
template <typename T>
concept has_push_constant_effect = requires {
typename T::push_constant_effect_type;
};
/// @brief 基于 shader_spec 的自定义着色器控件模板类
///
/// @tparam ShaderSpec 着色器规格类型(由着色器工具自动生成的 xxx_shader_spec
/// @tparam VertexT 顶点类型(默认使用 ui_vertex
///
/// 此模板类自动从 ShaderSpec 获取着色器 SPIR-V 和绑定信息,
/// 无需手动重写 get_vertex_shader_spirv()、get_fragment_shader_spirv() 和 get_bindings()。
///
/// 支持三种渲染模式:
/// - **程序化渲染**:使用着色器生成内容(无子控件,无源纹理)
/// - **后处理模式**:对子控件渲染结果或指定纹理应用着色器效果
/// - **自定义几何模式**:使用自定义顶点着色器和顶点缓冲
///
/// @deprecated This class is deprecated. Use the following replacements:
///
/// Migration Guide:
/// ================
///
/// 1. Procedural mode (no source texture):
/// Old: shader_spec_widget<MySpec>
/// New: procedural_shader_widget<MySpec>
/// File: ui/widgets/custom_shader/procedural/procedural_shader_widget.h
///
/// 2. PostProcess mode (samples current render target):
/// Old: shader_spec_widget<MySpec> with post_process mode
/// New: post_process_shader_widget<MySpec>
/// File: ui/widgets/custom_shader/post_process/post_process_shader_widget.h
///
/// 3. Mask mode (two-pass rendering):
/// Old: shader_spec_widget<MySpec> with mask mode
/// New: mask_shader_widget<MySpec>
/// File: ui/widgets/custom_shader/mask/mask_shader_widget.h
///
/// 4. Full custom mode (custom vertex shader and geometry):
/// Old: shader_spec_widget<MySpec, VertexT>
/// New: full_custom_shader_widget<MySpec, VertexT>
/// File: ui/widgets/custom_shader/full_custom/full_custom_shader_widget.h
///
/// API Changes:
/// ============
/// - push_constant_effect() -> effect()
/// - mark_push_constant_effect_dirty() -> mark_effect_dirty()
/// - push_constant_effect_type -> effect_type
///
/// @example
/// ```cpp
/// // 使用工具生成的 shader_spec
/// #include "vignette_vert_frag.h"
///
/// class vignette_widget : public shader_spec_widget<shaders::vignette_shader_spec<>> {
/// public:
/// vignette_widget() {
/// params().radius = 0.5f;
/// params().softness = 0.3f;
/// }
///
/// auto& set_radius(float r) {
/// params().radius = r;
/// mark_params_dirty();
/// return *this;
/// }
///
/// protected:
/// auto get_render_mode() const noexcept -> custom_shader_render_mode override {
/// return custom_shader_render_mode::post_process;
/// }
/// };
/// ```
template <typename ShaderSpec, typename VertexT = ui_vertex> requires shader_spec_concept<ShaderSpec>
class [[deprecated("Use procedural_shader_widget, post_process_shader_widget, mask_shader_widget, or full_custom_shader_widget instead")]]
shader_spec_widget : public custom_shader_widget_base {
public:
using shader_spec_type = ShaderSpec;
using params_type = ShaderSpec::params_type;
using vertex_type = VertexT;
/// @brief 条件性定义 push_constant_effect_type
/// @note 如果 ShaderSpec 没有提供 push_constant_effect_type则使用 void
using push_constant_effect_type = std::conditional_t<
has_push_constant_effect<ShaderSpec>,
typename ShaderSpec::push_constant_effect_type,
void
>;
// 静态断言:确保 params_type 满足要求
static_assert(std::is_standard_layout_v<params_type>,
"params_type must be standard layout for GPU compatibility");
static_assert(alignof(params_type) <= 16,
"params_type alignment must not exceed 16 bytes");
// 静态断言:验证效果 Push Constant 类型(如果存在)
// 验证要求128 字节分层布局):
// - Layer 3 效果扩展参数(偏移 112-127最大 16 字节
static_assert(validate_shader_spec_push_constants<ShaderSpec>(),
"Effect push constants validation failed: "
"size must not exceed 16 bytes (Layer 3: offset 112-127)");
shader_spec_widget() = default;
~shader_spec_widget() override = default;
// ========================================================================
// 参数访问
// ========================================================================
/// @brief 获取参数的可变引用
/// @note 修改后需要调用 mark_params_dirty()
[[nodiscard]] auto params() noexcept -> params_type& { return params_; }
/// @brief 获取参数的只读引用
[[nodiscard]] auto params() const noexcept -> const params_type& { return params_; }
/// @brief 标记参数已修改
void mark_params_dirty() {
params_dirty_ = true;
mark_render_dirty_internal();
}
// ========================================================================
// Push Constants 效果参数访问(仅当 ShaderSpec 提供了 push_constant_effect_type 时可用)
// ========================================================================
/// @brief 获取 Push Constants 效果参数的可变引用
/// @note 修改后需要调用 mark_push_constant_effect_dirty()
/// @note 仅当 ShaderSpec 提供了 push_constant_effect_type 时可用
[[nodiscard]] auto push_constant_effect() noexcept
-> push_constant_effect_type&
requires has_push_constant_effect<ShaderSpec>
{
return push_constant_effect_;
}
/// @brief 获取 Push Constants 效果参数的只读引用
/// @note 仅当 ShaderSpec 提供了 push_constant_effect_type 时可用
[[nodiscard]] auto push_constant_effect() const noexcept
-> const push_constant_effect_type&
requires has_push_constant_effect<ShaderSpec>
{
return push_constant_effect_;
}
/// @brief 标记 Push Constants 效果参数已修改
/// @note 仅当 ShaderSpec 提供了 push_constant_effect_type 时可用
void mark_push_constant_effect_dirty()
requires has_push_constant_effect<ShaderSpec>
{
push_constant_effect_dirty_ = true;
mark_render_dirty_internal();
}
protected:
// ========================================================================
// 实现基类纯虚函数 - 由 ShaderSpec 自动提供
// ========================================================================
/// @brief 获取着色器唯一标识符
[[nodiscard]] auto get_shader_id() const noexcept -> uint32_t override {
return ShaderSpec::shader_id;
}
/// @brief 获取顶点着色器 SPIR-V
[[nodiscard]] auto get_vertex_shader_spirv() const
-> std::span<const uint32_t> override {
return ShaderSpec::get_vertex_spirv();
}
/// @brief 获取片段着色器 SPIR-V
[[nodiscard]] auto get_fragment_shader_spirv() const
-> std::span<const uint32_t> override {
return ShaderSpec::get_fragment_spirv();
}
/// @brief 获取描述符绑定信息
[[nodiscard]] auto get_bindings() const
-> std::span<const shader_binding_info> override {
return ShaderSpec::get_bindings();
}
[[nodiscard]] auto get_params_data() const
-> std::pair<const void*, size_t> override {
return {&params_, sizeof(params_type)};
}
[[nodiscard]] auto is_params_dirty() const noexcept -> bool override {
return params_dirty_;
}
void clear_params_dirty() override {
params_dirty_ = false;
}
// ========================================================================
// Push Constants 效果参数实现
// ========================================================================
/// @brief 获取 Push Constants 效果参数数据指针和大小
[[nodiscard]] auto get_push_constant_effect_data() const
-> std::pair<const void*, size_t> override
{
if constexpr (has_push_constant_effect<ShaderSpec>) {
return {&push_constant_effect_, sizeof(push_constant_effect_type)};
} else {
return {nullptr, 0};
}
}
/// @brief 检查 Push Constants 效果参数是否已修改
[[nodiscard]] auto is_push_constant_effect_dirty() const noexcept
-> bool override
{
if constexpr (has_push_constant_effect<ShaderSpec>) {
return push_constant_effect_dirty_;
} else {
return false;
}
}
/// @brief 清除 Push Constants 效果参数脏标志
void clear_push_constant_effect_dirty() override
{
if constexpr (has_push_constant_effect<ShaderSpec>) {
push_constant_effect_dirty_ = false;
}
}
// ========================================================================
// 效果区域相关(用于 post_process 模式)
// ========================================================================
/// @brief 获取效果区域 rect
[[nodiscard]] auto get_effect_rect() const noexcept -> vec4f_t override
{
if constexpr (has_push_constant_effect<ShaderSpec>) {
return push_constant_effect_.effect_rect;
}
return vec4f_t{0.0f, 0.0f, 0.0f, 0.0f};
}
/// @brief 设置效果区域 rect
void set_effect_rect(const vec4f_t& rect) override
{
if constexpr (has_push_constant_effect<ShaderSpec>) {
push_constant_effect_.effect_rect = rect;
push_constant_effect_dirty_ = true;
mark_render_dirty_internal();
}
}
/// @brief 获取原始效果区域 rect用于 UV 计算)
[[nodiscard]] auto get_original_effect_rect() const noexcept -> vec4f_t override
{
if constexpr (has_push_constant_effect<ShaderSpec>) {
return push_constant_effect_.original_effect_rect;
}
return vec4f_t{0.0f, 0.0f, 0.0f, 0.0f};
}
/// @brief 设置原始效果区域 rect用于 UV 计算)
void set_original_effect_rect(const vec4f_t& rect) override
{
if constexpr (has_push_constant_effect<ShaderSpec>) {
push_constant_effect_.original_effect_rect = rect;
push_constant_effect_dirty_ = true;
mark_render_dirty_internal();
}
}
// ========================================================================
// 自定义顶点支持
// ========================================================================
/// @brief 标记顶点数据已修改
void mark_vertices_dirty() {
vertices_dirty_ = true;
mark_render_dirty_internal();
}
[[nodiscard]] auto is_vertices_dirty() const noexcept -> bool override {
return vertices_dirty_;
}
void clear_vertices_dirty() override {
vertices_dirty_ = false;
}
// ========================================================================
// 顶点数据管理(仅 custom_geometry 模式使用)
// ========================================================================
/// @brief 获取顶点数据
[[nodiscard]] auto get_vertices() const noexcept -> const std::vector<VertexT>& {
return vertices_;
}
/// @brief 获取顶点数据(可修改)
[[nodiscard]] auto get_vertices() noexcept -> std::vector<VertexT>& {
return vertices_;
}
/// @brief 设置顶点数据
void set_vertices(std::vector<VertexT> vertices) {
vertices_ = std::move(vertices);
mark_vertices_dirty();
}
/// @brief 获取索引数据
[[nodiscard]] auto get_indices() const noexcept -> const std::vector<uint32_t>& {
return indices_;
}
/// @brief 设置索引数据
void set_indices(std::vector<uint32_t> indices) {
indices_ = std::move(indices);
mark_vertices_dirty();
}
/// @brief 获取顶点缓冲配置
[[nodiscard]] auto get_vertex_buffer_config() const
-> std::optional<custom_vertex_buffer_config> override {
if (vertices_.empty()) {
return std::nullopt;
}
return custom_vertex_buffer_config{
.data = vertices_.data(),
.data_size = vertices_.size() * sizeof(VertexT),
.vertex_count = vertices_.size(),
.binding = get_vertex_binding_description(),
.attributes = get_vertex_attribute_descriptions()
};
}
/// @brief 获取索引缓冲配置
[[nodiscard]] auto get_index_buffer_config() const
-> std::optional<index_buffer_config> override {
if (indices_.empty()) {
return std::nullopt;
}
return index_buffer_config{
.data = indices_.data(),
.index_count = indices_.size()
};
}
/// @brief 获取顶点绑定描述(可重写)
[[nodiscard]] virtual auto get_vertex_binding_description() const
-> vk::VertexInputBindingDescription {
if constexpr (requires { VertexT::get_binding_description(); }) {
return VertexT::get_binding_description();
}
else {
return vk::VertexInputBindingDescription{
0, sizeof(VertexT), vk::VertexInputRate::eVertex
};
}
}
/// @brief 获取顶点属性描述(可重写)
[[nodiscard]] virtual auto get_vertex_attribute_descriptions() const
-> std::vector<vk::VertexInputAttributeDescription> {
if constexpr (requires { VertexT::get_attribute_descriptions(); }) {
auto attrs = VertexT::get_attribute_descriptions();
return std::vector<vk::VertexInputAttributeDescription>(
attrs.begin(), attrs.end());
}
else {
return {};
}
}
private:
params_type params_{};
bool params_dirty_ = true;
bool vertices_dirty_ = false;
/// @brief 条件性存储 push_constant_effect_
/// @note 使用 [[no_unique_address]] 避免 void 类型占用空间
[[no_unique_address]] std::conditional_t<
has_push_constant_effect<ShaderSpec>,
push_constant_effect_type,
std::monostate
> push_constant_effect_{};
bool push_constant_effect_dirty_ = true; ///< 初始为 true 以确保首次渲染
std::vector<VertexT> vertices_;
std::vector<uint32_t> indices_;
};
} // namespace mirage

View File

@@ -178,7 +178,7 @@ struct {{ shader_spec_name }} {
{%- if has_push_constant_effect %}
/// @brief Push Constants 效果部分类型
using push_constant_effect_type = {{ push_constant_effect_type_name }};
using effect_type = {{ push_constant_effect_type_name }};
{%- endif %}
{%- if has_push_constant_base_layout %}