From b2ede3f0680edc894a54e28374cb87ab2690afa2 Mon Sep 17 00:00:00 2001 From: skal Date: Mon, 16 Feb 2026 14:32:59 +0100 Subject: refactor: remove v2 versioning artifacts, establish Sequence as canonical system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Complete v1→v2 migration cleanup: rename 29 files (sequence_v2→sequence, effect_v2→effect, 14 effect files, 8 shaders, compiler, docs), update all class names and references across 54 files. Archive v1 timeline. System now uses standard naming with all versioning removed. 30/34 tests passing. Co-Authored-By: Claude Sonnet 4.5 --- src/effects/gaussian_blur_effect.cc | 84 +++++++++++++++ src/effects/gaussian_blur_effect.h | 34 ++++++ src/effects/gaussian_blur_effect_v2.cc | 84 --------------- src/effects/gaussian_blur_effect_v2.h | 33 ------ src/effects/heptagon_effect.cc | 81 ++++++++++++++ src/effects/heptagon_effect.h | 25 +++++ src/effects/heptagon_effect_v2.cc | 81 -------------- src/effects/heptagon_effect_v2.h | 24 ----- src/effects/hybrid3_d_effect.cc | 114 ++++++++++++++++++++ src/effects/hybrid3_d_effect.h | 32 ++++++ src/effects/hybrid3_d_effect_v2.cc | 114 -------------------- src/effects/hybrid3_d_effect_v2.h | 32 ------ src/effects/particles_effect.cc | 96 +++++++++++++++++ src/effects/particles_effect.h | 36 +++++++ src/effects/particles_effect_v2.cc | 96 ----------------- src/effects/particles_effect_v2.h | 35 ------- src/effects/passthrough_effect.cc | 81 ++++++++++++++ src/effects/passthrough_effect.h | 21 ++++ src/effects/passthrough_effect_v2.cc | 81 -------------- src/effects/passthrough_effect_v2.h | 21 ---- src/effects/placeholder_effect.cc | 63 +++++++++++ src/effects/placeholder_effect.h | 25 +++++ src/effects/placeholder_effect_v2.cc | 63 ----------- src/effects/placeholder_effect_v2.h | 24 ----- src/effects/rotating_cube_effect.cc | 186 +++++++++++++++++++++++++++++++++ src/effects/rotating_cube_effect.h | 49 +++++++++ src/effects/rotating_cube_effect_v2.cc | 186 --------------------------------- src/effects/rotating_cube_effect_v2.h | 49 --------- 28 files changed, 927 insertions(+), 923 deletions(-) create mode 100644 src/effects/gaussian_blur_effect.cc create mode 100644 src/effects/gaussian_blur_effect.h delete mode 100644 src/effects/gaussian_blur_effect_v2.cc delete mode 100644 src/effects/gaussian_blur_effect_v2.h create mode 100644 src/effects/heptagon_effect.cc create mode 100644 src/effects/heptagon_effect.h delete mode 100644 src/effects/heptagon_effect_v2.cc delete mode 100644 src/effects/heptagon_effect_v2.h create mode 100644 src/effects/hybrid3_d_effect.cc create mode 100644 src/effects/hybrid3_d_effect.h delete mode 100644 src/effects/hybrid3_d_effect_v2.cc delete mode 100644 src/effects/hybrid3_d_effect_v2.h create mode 100644 src/effects/particles_effect.cc create mode 100644 src/effects/particles_effect.h delete mode 100644 src/effects/particles_effect_v2.cc delete mode 100644 src/effects/particles_effect_v2.h create mode 100644 src/effects/passthrough_effect.cc create mode 100644 src/effects/passthrough_effect.h delete mode 100644 src/effects/passthrough_effect_v2.cc delete mode 100644 src/effects/passthrough_effect_v2.h create mode 100644 src/effects/placeholder_effect.cc create mode 100644 src/effects/placeholder_effect.h delete mode 100644 src/effects/placeholder_effect_v2.cc delete mode 100644 src/effects/placeholder_effect_v2.h create mode 100644 src/effects/rotating_cube_effect.cc create mode 100644 src/effects/rotating_cube_effect.h delete mode 100644 src/effects/rotating_cube_effect_v2.cc delete mode 100644 src/effects/rotating_cube_effect_v2.h (limited to 'src/effects') diff --git a/src/effects/gaussian_blur_effect.cc b/src/effects/gaussian_blur_effect.cc new file mode 100644 index 0000000..17c657f --- /dev/null +++ b/src/effects/gaussian_blur_effect.cc @@ -0,0 +1,84 @@ +// Gaussian blur effect v2 implementation + +#include "effects/gaussian_blur_effect.h" +#include "gpu/post_process_helper.h" +#include "gpu/shaders.h" + +GaussianBlurEffect::GaussianBlurEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs) + : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), + sampler_(nullptr) { + // Create pipeline + pipeline_ = create_post_process_pipeline(ctx_.device, WGPUTextureFormat_RGBA8Unorm, + gaussian_blur_v2_shader_wgsl); + + // Create sampler + WGPUSamplerDescriptor sampler_desc = {}; + sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; + sampler_desc.magFilter = WGPUFilterMode_Linear; + sampler_desc.minFilter = WGPUFilterMode_Linear; + sampler_desc.maxAnisotropy = 1; + sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); + + // Init uniform buffers + params_buffer_.init(ctx_.device); + uniforms_buffer_.init(ctx_.device); +} + +void GaussianBlurEffect::render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) { + // Get input/output views + WGPUTextureView input_view = nodes.get_view(input_nodes_[0]); + WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); + + // Update uniforms + uniforms_buffer_.update(ctx_.queue, params); + params_buffer_.update(ctx_.queue, blur_params_); + + // Update bind group + WGPUBindGroupEntry entries[4] = {}; + entries[0].binding = PP_BINDING_SAMPLER; + entries[0].sampler = sampler_; + entries[1].binding = PP_BINDING_TEXTURE; + entries[1].textureView = input_view; + entries[2].binding = PP_BINDING_UNIFORMS; + entries[2].buffer = uniforms_buffer_.get().buffer; + entries[2].size = sizeof(UniformsSequenceParams); + entries[3].binding = PP_BINDING_EFFECT_PARAMS; + entries[3].buffer = params_buffer_.get().buffer; + entries[3].size = sizeof(GaussianBlurParams); + + WGPUBindGroupDescriptor bg_desc = {}; + bg_desc.layout = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0); + bg_desc.entryCount = 4; + bg_desc.entries = entries; + + if (bind_group_) { + wgpuBindGroupRelease(bind_group_); + } + bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); + + // Render pass + WGPURenderPassColorAttachment color_attachment = {}; + color_attachment.view = output_view; +#if !defined(DEMO_CROSS_COMPILE_WIN32) + color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; +#endif + color_attachment.loadOp = WGPULoadOp_Clear; + color_attachment.storeOp = WGPUStoreOp_Store; + color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0}; + + WGPURenderPassDescriptor pass_desc = {}; + pass_desc.colorAttachmentCount = 1; + pass_desc.colorAttachments = &color_attachment; + + WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); + wgpuRenderPassEncoderSetPipeline(pass, pipeline_); + wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); + wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); + wgpuRenderPassEncoderEnd(pass); + wgpuRenderPassEncoderRelease(pass); +} diff --git a/src/effects/gaussian_blur_effect.h b/src/effects/gaussian_blur_effect.h new file mode 100644 index 0000000..8bf34dc --- /dev/null +++ b/src/effects/gaussian_blur_effect.h @@ -0,0 +1,34 @@ +// Gaussian blur effect v2 - single-pass blur + +#pragma once + +#include "gpu/effect.h" +#include "gpu/uniform_helper.h" + +struct GaussianBlurParams { + float strength = 1.0f; + float strength_audio = 0.5f; + float stretch = 1.0f; + float _pad = 0.0f; +}; +static_assert(sizeof(GaussianBlurParams) == 16, + "GaussianBlurParams must be 16 bytes"); + +class GaussianBlurEffect : public Effect { + public: + GaussianBlurEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs); + + void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, + NodeRegistry& nodes) override; + + private: + WGPURenderPipeline pipeline_; + WGPUBindGroup bind_group_; + WGPUSampler sampler_; + GaussianBlurParams blur_params_; + UniformBuffer params_buffer_; + UniformBuffer uniforms_buffer_; +}; + diff --git a/src/effects/gaussian_blur_effect_v2.cc b/src/effects/gaussian_blur_effect_v2.cc deleted file mode 100644 index 0c90fa2..0000000 --- a/src/effects/gaussian_blur_effect_v2.cc +++ /dev/null @@ -1,84 +0,0 @@ -// Gaussian blur effect v2 implementation - -#include "effects/gaussian_blur_effect_v2.h" -#include "gpu/post_process_helper.h" -#include "gpu/shaders.h" - -GaussianBlurEffectV2::GaussianBlurEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs) - : EffectV2(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), - sampler_(nullptr) { - // Create pipeline - pipeline_ = create_post_process_pipeline(ctx_.device, WGPUTextureFormat_RGBA8Unorm, - gaussian_blur_v2_shader_wgsl); - - // Create sampler - WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.magFilter = WGPUFilterMode_Linear; - sampler_desc.minFilter = WGPUFilterMode_Linear; - sampler_desc.maxAnisotropy = 1; - sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); - - // Init uniform buffers - params_buffer_.init(ctx_.device); - uniforms_buffer_.init(ctx_.device); -} - -void GaussianBlurEffectV2::render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) { - // Get input/output views - WGPUTextureView input_view = nodes.get_view(input_nodes_[0]); - WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); - - // Update uniforms - uniforms_buffer_.update(ctx_.queue, params); - params_buffer_.update(ctx_.queue, blur_params_); - - // Update bind group - WGPUBindGroupEntry entries[4] = {}; - entries[0].binding = PP_BINDING_SAMPLER; - entries[0].sampler = sampler_; - entries[1].binding = PP_BINDING_TEXTURE; - entries[1].textureView = input_view; - entries[2].binding = PP_BINDING_UNIFORMS; - entries[2].buffer = uniforms_buffer_.get().buffer; - entries[2].size = sizeof(UniformsSequenceParams); - entries[3].binding = PP_BINDING_EFFECT_PARAMS; - entries[3].buffer = params_buffer_.get().buffer; - entries[3].size = sizeof(GaussianBlurParams); - - WGPUBindGroupDescriptor bg_desc = {}; - bg_desc.layout = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0); - bg_desc.entryCount = 4; - bg_desc.entries = entries; - - if (bind_group_) { - wgpuBindGroupRelease(bind_group_); - } - bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); - - // Render pass - WGPURenderPassColorAttachment color_attachment = {}; - color_attachment.view = output_view; -#if !defined(DEMO_CROSS_COMPILE_WIN32) - color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; -#endif - color_attachment.loadOp = WGPULoadOp_Clear; - color_attachment.storeOp = WGPUStoreOp_Store; - color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0}; - - WGPURenderPassDescriptor pass_desc = {}; - pass_desc.colorAttachmentCount = 1; - pass_desc.colorAttachments = &color_attachment; - - WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); - wgpuRenderPassEncoderEnd(pass); - wgpuRenderPassEncoderRelease(pass); -} diff --git a/src/effects/gaussian_blur_effect_v2.h b/src/effects/gaussian_blur_effect_v2.h deleted file mode 100644 index c5d88ff..0000000 --- a/src/effects/gaussian_blur_effect_v2.h +++ /dev/null @@ -1,33 +0,0 @@ -// Gaussian blur effect v2 - single-pass blur - -#pragma once - -#include "gpu/effect_v2.h" -#include "gpu/uniform_helper.h" - -struct GaussianBlurParams { - float strength = 1.0f; - float strength_audio = 0.5f; - float stretch = 1.0f; - float _pad = 0.0f; -}; -static_assert(sizeof(GaussianBlurParams) == 16, - "GaussianBlurParams must be 16 bytes"); - -class GaussianBlurEffectV2 : public EffectV2 { - public: - GaussianBlurEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs); - - void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, - NodeRegistry& nodes) override; - - private: - WGPURenderPipeline pipeline_; - WGPUBindGroup bind_group_; - WGPUSampler sampler_; - GaussianBlurParams blur_params_; - UniformBuffer params_buffer_; - UniformBuffer uniforms_buffer_; -}; diff --git a/src/effects/heptagon_effect.cc b/src/effects/heptagon_effect.cc new file mode 100644 index 0000000..27d59da --- /dev/null +++ b/src/effects/heptagon_effect.cc @@ -0,0 +1,81 @@ +// Heptagon effect v2 implementation + +#include "effects/heptagon_effect.h" +#include "gpu/gpu.h" +#include "gpu/post_process_helper.h" +#include "gpu/shaders.h" + +HeptagonEffect::HeptagonEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs) + : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), sampler_(nullptr) { + // Init uniforms + uniforms_buffer_.init(ctx_.device); + + // Create pipeline (standard v2 post-process, no depth) + pipeline_ = create_post_process_pipeline(ctx_.device, WGPUTextureFormat_RGBA8Unorm, + heptagon_v2_shader_wgsl); + + // Create dummy sampler (scene effects don't use texture input) + WGPUSamplerDescriptor sampler_desc = {}; + sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; + sampler_desc.magFilter = WGPUFilterMode_Nearest; + sampler_desc.minFilter = WGPUFilterMode_Nearest; + sampler_desc.maxAnisotropy = 1; + sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); + + // Create 1×1 dummy texture + WGPUTextureDescriptor tex_desc = {}; + tex_desc.size = {1, 1, 1}; + tex_desc.format = WGPUTextureFormat_RGBA8Unorm; + tex_desc.usage = WGPUTextureUsage_TextureBinding; + tex_desc.dimension = WGPUTextureDimension_2D; + tex_desc.mipLevelCount = 1; + tex_desc.sampleCount = 1; + dummy_texture_ = wgpuDeviceCreateTexture(ctx_.device, &tex_desc); + dummy_texture_view_ = wgpuTextureCreateView(dummy_texture_, nullptr); +} + +HeptagonEffect::~HeptagonEffect() { + if (bind_group_) wgpuBindGroupRelease(bind_group_); + if (pipeline_) wgpuRenderPipelineRelease(pipeline_); + if (sampler_) wgpuSamplerRelease(sampler_); + if (dummy_texture_view_) wgpuTextureViewRelease(dummy_texture_view_); + if (dummy_texture_) wgpuTextureRelease(dummy_texture_); +} + +void HeptagonEffect::render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) { + // Get output view (scene effects typically write to output, ignore input) + WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); + + // Update uniforms + uniforms_buffer_.update(ctx_.queue, params); + + // Create bind group (use dummy texture for scene effect) + pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, dummy_texture_view_, + uniforms_buffer_.get(), {nullptr, 0}); + + // Render pass + WGPURenderPassColorAttachment color_attachment = {}; + color_attachment.view = output_view; +#if !defined(DEMO_CROSS_COMPILE_WIN32) + color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; +#endif + color_attachment.loadOp = WGPULoadOp_Clear; + color_attachment.storeOp = WGPUStoreOp_Store; + color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0}; + + WGPURenderPassDescriptor pass_desc = {}; + pass_desc.colorAttachmentCount = 1; + pass_desc.colorAttachments = &color_attachment; + + WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); + wgpuRenderPassEncoderSetPipeline(pass, pipeline_); + wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); + wgpuRenderPassEncoderDraw(pass, 21, 1, 0, 0); // 7 triangles * 3 vertices + wgpuRenderPassEncoderEnd(pass); + wgpuRenderPassEncoderRelease(pass); +} diff --git a/src/effects/heptagon_effect.h b/src/effects/heptagon_effect.h new file mode 100644 index 0000000..9f148a1 --- /dev/null +++ b/src/effects/heptagon_effect.h @@ -0,0 +1,25 @@ +// Heptagon effect v2 - scene rendering effect + +#pragma once + +#include "gpu/effect.h" +#include "gpu/uniform_helper.h" + +class HeptagonEffect : public Effect { + public: + HeptagonEffect(const GpuContext& ctx, const std::vector& inputs, + const std::vector& outputs); + ~HeptagonEffect(); + + void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, + NodeRegistry& nodes) override; + + private: + WGPURenderPipeline pipeline_; + WGPUBindGroup bind_group_; + WGPUSampler sampler_; + WGPUTexture dummy_texture_; + WGPUTextureView dummy_texture_view_; + UniformBuffer uniforms_buffer_; +}; + diff --git a/src/effects/heptagon_effect_v2.cc b/src/effects/heptagon_effect_v2.cc deleted file mode 100644 index 6a2135e..0000000 --- a/src/effects/heptagon_effect_v2.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Heptagon effect v2 implementation - -#include "effects/heptagon_effect_v2.h" -#include "gpu/gpu.h" -#include "gpu/post_process_helper.h" -#include "gpu/shaders.h" - -HeptagonEffectV2::HeptagonEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs) - : EffectV2(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), sampler_(nullptr) { - // Init uniforms - uniforms_buffer_.init(ctx_.device); - - // Create pipeline (standard v2 post-process, no depth) - pipeline_ = create_post_process_pipeline(ctx_.device, WGPUTextureFormat_RGBA8Unorm, - heptagon_v2_shader_wgsl); - - // Create dummy sampler (scene effects don't use texture input) - WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.magFilter = WGPUFilterMode_Nearest; - sampler_desc.minFilter = WGPUFilterMode_Nearest; - sampler_desc.maxAnisotropy = 1; - sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); - - // Create 1×1 dummy texture - WGPUTextureDescriptor tex_desc = {}; - tex_desc.size = {1, 1, 1}; - tex_desc.format = WGPUTextureFormat_RGBA8Unorm; - tex_desc.usage = WGPUTextureUsage_TextureBinding; - tex_desc.dimension = WGPUTextureDimension_2D; - tex_desc.mipLevelCount = 1; - tex_desc.sampleCount = 1; - dummy_texture_ = wgpuDeviceCreateTexture(ctx_.device, &tex_desc); - dummy_texture_view_ = wgpuTextureCreateView(dummy_texture_, nullptr); -} - -HeptagonEffectV2::~HeptagonEffectV2() { - if (bind_group_) wgpuBindGroupRelease(bind_group_); - if (pipeline_) wgpuRenderPipelineRelease(pipeline_); - if (sampler_) wgpuSamplerRelease(sampler_); - if (dummy_texture_view_) wgpuTextureViewRelease(dummy_texture_view_); - if (dummy_texture_) wgpuTextureRelease(dummy_texture_); -} - -void HeptagonEffectV2::render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) { - // Get output view (scene effects typically write to output, ignore input) - WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); - - // Update uniforms - uniforms_buffer_.update(ctx_.queue, params); - - // Create bind group (use dummy texture for scene effect) - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, dummy_texture_view_, - uniforms_buffer_.get(), {nullptr, 0}); - - // Render pass - WGPURenderPassColorAttachment color_attachment = {}; - color_attachment.view = output_view; -#if !defined(DEMO_CROSS_COMPILE_WIN32) - color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; -#endif - color_attachment.loadOp = WGPULoadOp_Clear; - color_attachment.storeOp = WGPUStoreOp_Store; - color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0}; - - WGPURenderPassDescriptor pass_desc = {}; - pass_desc.colorAttachmentCount = 1; - pass_desc.colorAttachments = &color_attachment; - - WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 21, 1, 0, 0); // 7 triangles * 3 vertices - wgpuRenderPassEncoderEnd(pass); - wgpuRenderPassEncoderRelease(pass); -} diff --git a/src/effects/heptagon_effect_v2.h b/src/effects/heptagon_effect_v2.h deleted file mode 100644 index 1737a46..0000000 --- a/src/effects/heptagon_effect_v2.h +++ /dev/null @@ -1,24 +0,0 @@ -// Heptagon effect v2 - scene rendering effect - -#pragma once - -#include "gpu/effect_v2.h" -#include "gpu/uniform_helper.h" - -class HeptagonEffectV2 : public EffectV2 { - public: - HeptagonEffectV2(const GpuContext& ctx, const std::vector& inputs, - const std::vector& outputs); - ~HeptagonEffectV2(); - - void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, - NodeRegistry& nodes) override; - - private: - WGPURenderPipeline pipeline_; - WGPUBindGroup bind_group_; - WGPUSampler sampler_; - WGPUTexture dummy_texture_; - WGPUTextureView dummy_texture_view_; - UniformBuffer uniforms_buffer_; -}; diff --git a/src/effects/hybrid3_d_effect.cc b/src/effects/hybrid3_d_effect.cc new file mode 100644 index 0000000..ced5b42 --- /dev/null +++ b/src/effects/hybrid3_d_effect.cc @@ -0,0 +1,114 @@ +// This file is part of the 64k demo project. +// It implements Hybrid3DEffect (simplified v2 port). +// TODO: Full Renderer3D integration with texture manager, noise assets + +#include "effects/hybrid3_d_effect.h" +#include + +Hybrid3DEffect::Hybrid3DEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs) + : Effect(ctx, inputs, outputs), depth_node_(outputs[0] + "_depth"), + dummy_texture_(nullptr), dummy_texture_view_(nullptr) { + // Initialize renderer (format is always RGBA8Unorm for v2) + renderer_.init(ctx_.device, ctx_.queue, WGPUTextureFormat_RGBA8Unorm); + + // Create 1×1 white dummy texture for noise/sky (Renderer3D requires these) + WGPUTextureDescriptor tex_desc = {}; + tex_desc.size = {1, 1, 1}; + tex_desc.format = WGPUTextureFormat_RGBA8Unorm; + tex_desc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst; + tex_desc.dimension = WGPUTextureDimension_2D; + tex_desc.mipLevelCount = 1; + tex_desc.sampleCount = 1; + dummy_texture_ = wgpuDeviceCreateTexture(ctx_.device, &tex_desc); + dummy_texture_view_ = wgpuTextureCreateView(dummy_texture_, nullptr); + + // Write white pixel + uint32_t white_pixel = 0xFFFFFFFF; +#if defined(DEMO_CROSS_COMPILE_WIN32) + WGPUImageCopyTexture dst = { + .texture = dummy_texture_, + .mipLevel = 0, + .origin = {0, 0, 0} + }; + WGPUTextureDataLayout data_layout = { + .bytesPerRow = 4, + .rowsPerImage = 1 + }; +#else + WGPUTexelCopyTextureInfo dst = { + .texture = dummy_texture_, + .mipLevel = 0, + .origin = {0, 0, 0} + }; + WGPUTexelCopyBufferLayout data_layout = { + .bytesPerRow = 4, + .rowsPerImage = 1 + }; +#endif + WGPUExtent3D size = {1, 1, 1}; + wgpuQueueWriteTexture(ctx_.queue, &dst, &white_pixel, 4, &data_layout, &size); + + renderer_.set_noise_texture(dummy_texture_view_); + renderer_.set_sky_texture(dummy_texture_view_); + + initialized_ = true; + + // Setup simple scene (1 center cube + 8 surrounding objects) + scene_.clear(); + Object3D center(ObjectType::BOX); + center.position = vec3(0, 0, 0); + center.color = vec4(1, 0, 0, 1); + scene_.add_object(center); + + for (int i = 0; i < 8; ++i) { + ObjectType type = (i % 3 == 1) ? ObjectType::TORUS : + (i % 3 == 2) ? ObjectType::BOX : ObjectType::SPHERE; + + Object3D obj(type); + float angle = (i / 8.0f) * 6.28318f; + obj.position = vec3(std::cos(angle) * 4.0f, 0, std::sin(angle) * 4.0f); + obj.scale = vec3(0.7f, 0.7f, 0.7f); + + if (type == ObjectType::SPHERE) + obj.color = vec4(0, 1, 0, 1); + else if (type == ObjectType::TORUS) + obj.color = vec4(0, 0.5f, 1, 1); + else + obj.color = vec4(1, 1, 0, 1); + + scene_.add_object(obj); + } +} + +Hybrid3DEffect::~Hybrid3DEffect() { + if (dummy_texture_view_) + wgpuTextureViewRelease(dummy_texture_view_); + if (dummy_texture_) + wgpuTextureRelease(dummy_texture_); + renderer_.shutdown(); +} + +void Hybrid3DEffect::declare_nodes(NodeRegistry& registry) { + // Declare depth buffer node + registry.declare_node(depth_node_, NodeType::DEPTH24, -1, -1); +} + +void Hybrid3DEffect::render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) { + // Update camera (orbiting) + float angle = params.time * 0.3f; + vec3 cam_pos = vec3(std::cos(angle) * 10.0f, 5.0f, std::sin(angle) * 10.0f); + camera_.position = cam_pos; + camera_.target = vec3(0, 0, 0); + camera_.aspect_ratio = params.aspect_ratio; + + // Get output views + WGPUTextureView color_view = nodes.get_view(output_nodes_[0]); + WGPUTextureView depth_view = nodes.get_view(depth_node_); + + // Render 3D scene + renderer_.render(scene_, camera_, params.time, color_view, depth_view); +} diff --git a/src/effects/hybrid3_d_effect.h b/src/effects/hybrid3_d_effect.h new file mode 100644 index 0000000..e6e0f49 --- /dev/null +++ b/src/effects/hybrid3_d_effect.h @@ -0,0 +1,32 @@ +// This file is part of the 64k demo project. +// It declares Hybrid3DEffect (simplified v2 port). +// TODO: Full Renderer3D integration with Scene/Camera + +#pragma once + +#include "3d/camera.h" +#include "3d/renderer.h" +#include "3d/scene.h" +#include "gpu/effect.h" + +class Hybrid3DEffect : public Effect { + public: + Hybrid3DEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs); + ~Hybrid3DEffect() override; + + void declare_nodes(NodeRegistry& registry) override; + void render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) override; + + private: + Renderer3D renderer_; + Scene scene_; + Camera camera_; + bool initialized_ = false; + std::string depth_node_; + WGPUTexture dummy_texture_; + WGPUTextureView dummy_texture_view_; +}; diff --git a/src/effects/hybrid3_d_effect_v2.cc b/src/effects/hybrid3_d_effect_v2.cc deleted file mode 100644 index 38e4e66..0000000 --- a/src/effects/hybrid3_d_effect_v2.cc +++ /dev/null @@ -1,114 +0,0 @@ -// This file is part of the 64k demo project. -// It implements Hybrid3DEffectV2 (simplified v2 port). -// TODO: Full Renderer3D integration with texture manager, noise assets - -#include "effects/hybrid3_d_effect_v2.h" -#include - -Hybrid3DEffectV2::Hybrid3DEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs) - : EffectV2(ctx, inputs, outputs), depth_node_(outputs[0] + "_depth"), - dummy_texture_(nullptr), dummy_texture_view_(nullptr) { - // Initialize renderer (format is always RGBA8Unorm for v2) - renderer_.init(ctx_.device, ctx_.queue, WGPUTextureFormat_RGBA8Unorm); - - // Create 1×1 white dummy texture for noise/sky (Renderer3D requires these) - WGPUTextureDescriptor tex_desc = {}; - tex_desc.size = {1, 1, 1}; - tex_desc.format = WGPUTextureFormat_RGBA8Unorm; - tex_desc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst; - tex_desc.dimension = WGPUTextureDimension_2D; - tex_desc.mipLevelCount = 1; - tex_desc.sampleCount = 1; - dummy_texture_ = wgpuDeviceCreateTexture(ctx_.device, &tex_desc); - dummy_texture_view_ = wgpuTextureCreateView(dummy_texture_, nullptr); - - // Write white pixel - uint32_t white_pixel = 0xFFFFFFFF; -#if defined(DEMO_CROSS_COMPILE_WIN32) - WGPUImageCopyTexture dst = { - .texture = dummy_texture_, - .mipLevel = 0, - .origin = {0, 0, 0} - }; - WGPUTextureDataLayout data_layout = { - .bytesPerRow = 4, - .rowsPerImage = 1 - }; -#else - WGPUTexelCopyTextureInfo dst = { - .texture = dummy_texture_, - .mipLevel = 0, - .origin = {0, 0, 0} - }; - WGPUTexelCopyBufferLayout data_layout = { - .bytesPerRow = 4, - .rowsPerImage = 1 - }; -#endif - WGPUExtent3D size = {1, 1, 1}; - wgpuQueueWriteTexture(ctx_.queue, &dst, &white_pixel, 4, &data_layout, &size); - - renderer_.set_noise_texture(dummy_texture_view_); - renderer_.set_sky_texture(dummy_texture_view_); - - initialized_ = true; - - // Setup simple scene (1 center cube + 8 surrounding objects) - scene_.clear(); - Object3D center(ObjectType::BOX); - center.position = vec3(0, 0, 0); - center.color = vec4(1, 0, 0, 1); - scene_.add_object(center); - - for (int i = 0; i < 8; ++i) { - ObjectType type = (i % 3 == 1) ? ObjectType::TORUS : - (i % 3 == 2) ? ObjectType::BOX : ObjectType::SPHERE; - - Object3D obj(type); - float angle = (i / 8.0f) * 6.28318f; - obj.position = vec3(std::cos(angle) * 4.0f, 0, std::sin(angle) * 4.0f); - obj.scale = vec3(0.7f, 0.7f, 0.7f); - - if (type == ObjectType::SPHERE) - obj.color = vec4(0, 1, 0, 1); - else if (type == ObjectType::TORUS) - obj.color = vec4(0, 0.5f, 1, 1); - else - obj.color = vec4(1, 1, 0, 1); - - scene_.add_object(obj); - } -} - -Hybrid3DEffectV2::~Hybrid3DEffectV2() { - if (dummy_texture_view_) - wgpuTextureViewRelease(dummy_texture_view_); - if (dummy_texture_) - wgpuTextureRelease(dummy_texture_); - renderer_.shutdown(); -} - -void Hybrid3DEffectV2::declare_nodes(NodeRegistry& registry) { - // Declare depth buffer node - registry.declare_node(depth_node_, NodeType::DEPTH24, -1, -1); -} - -void Hybrid3DEffectV2::render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) { - // Update camera (orbiting) - float angle = params.time * 0.3f; - vec3 cam_pos = vec3(std::cos(angle) * 10.0f, 5.0f, std::sin(angle) * 10.0f); - camera_.position = cam_pos; - camera_.target = vec3(0, 0, 0); - camera_.aspect_ratio = params.aspect_ratio; - - // Get output views - WGPUTextureView color_view = nodes.get_view(output_nodes_[0]); - WGPUTextureView depth_view = nodes.get_view(depth_node_); - - // Render 3D scene - renderer_.render(scene_, camera_, params.time, color_view, depth_view); -} diff --git a/src/effects/hybrid3_d_effect_v2.h b/src/effects/hybrid3_d_effect_v2.h deleted file mode 100644 index c8116b0..0000000 --- a/src/effects/hybrid3_d_effect_v2.h +++ /dev/null @@ -1,32 +0,0 @@ -// This file is part of the 64k demo project. -// It declares Hybrid3DEffectV2 (simplified v2 port). -// TODO: Full Renderer3D integration with Scene/Camera - -#pragma once - -#include "3d/camera.h" -#include "3d/renderer.h" -#include "3d/scene.h" -#include "gpu/effect_v2.h" - -class Hybrid3DEffectV2 : public EffectV2 { - public: - Hybrid3DEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs); - ~Hybrid3DEffectV2() override; - - void declare_nodes(NodeRegistry& registry) override; - void render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) override; - - private: - Renderer3D renderer_; - Scene scene_; - Camera camera_; - bool initialized_ = false; - std::string depth_node_; - WGPUTexture dummy_texture_; - WGPUTextureView dummy_texture_view_; -}; diff --git a/src/effects/particles_effect.cc b/src/effects/particles_effect.cc new file mode 100644 index 0000000..9d73bf7 --- /dev/null +++ b/src/effects/particles_effect.cc @@ -0,0 +1,96 @@ +// This file is part of the 64k demo project. +// It implements the ParticlesEffect. + +#include "effects/particles_effect.h" +#include "gpu/gpu.h" +#include "gpu/shaders.h" +#include + +ParticlesEffect::ParticlesEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs) + : Effect(ctx, inputs, outputs) { + // Initialize uniforms + uniforms_.init(ctx_.device); + + // Initialize particles buffer + std::vector init_p(NUM_PARTICLES); + for (int i = 0; i < NUM_PARTICLES; ++i) { + float x = (float)(i % 100) / 50.0f - 1.0f; + float y = (float)(i / 100) / 100.0f * 3.0f - 1.5f; + init_p[i].pos[0] = x; + init_p[i].pos[1] = y; + init_p[i].pos[2] = ((float)i / NUM_PARTICLES) * 0.5f; + init_p[i].pos[3] = 1.0f; + init_p[i].vel[0] = 0.0f; + init_p[i].vel[1] = 0.0f; + init_p[i].vel[2] = 0.0f; + init_p[i].vel[3] = 0.0f; + init_p[i].rot[0] = 0.0f; + init_p[i].rot[1] = ((float)(i % 7) / 7.0f) * 3.14159f; + init_p[i].rot[2] = 0.0f; + init_p[i].rot[3] = 0.0f; + float hue = (float)(i % 100) / 100.0f; + init_p[i].color[0] = 0.5f + 0.5f * hue; + init_p[i].color[1] = 0.3f + 0.7f * (1.0f - hue); + init_p[i].color[2] = 0.8f; + init_p[i].color[3] = 0.8f; + } + + particles_buffer_ = gpu_create_buffer( + ctx_.device, sizeof(Particle) * NUM_PARTICLES, + WGPUBufferUsage_Storage | WGPUBufferUsage_Vertex, init_p.data()); + + // Create compute shader (particle simulation) + ResourceBinding compute_bindings[] = { + {particles_buffer_, WGPUBufferBindingType_Storage}, + {uniforms_.get(), WGPUBufferBindingType_Uniform}}; + compute_pass_ = gpu_create_compute_pass(ctx_.device, particle_compute_v2_wgsl, + compute_bindings, 2); + compute_pass_.workgroup_size_x = (NUM_PARTICLES + 63) / 64; + + // Create render shader (particle rendering) + ResourceBinding render_bindings[] = { + {particles_buffer_, WGPUBufferBindingType_ReadOnlyStorage}, + {uniforms_.get(), WGPUBufferBindingType_Uniform}}; + render_pass_ = gpu_create_render_pass(ctx_.device, WGPUTextureFormat_RGBA8Unorm, + particle_render_v2_wgsl, render_bindings, 2); + render_pass_.vertex_count = 6; + render_pass_.instance_count = NUM_PARTICLES; +} + +void ParticlesEffect::render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) { + // Update uniforms + uniforms_.update(ctx_.queue, params); + + // Run compute pass (particle simulation) + WGPUComputePassEncoder compute = wgpuCommandEncoderBeginComputePass(encoder, nullptr); + wgpuComputePassEncoderSetPipeline(compute, compute_pass_.pipeline); + wgpuComputePassEncoderSetBindGroup(compute, 0, compute_pass_.bind_group, 0, nullptr); + wgpuComputePassEncoderDispatchWorkgroups(compute, compute_pass_.workgroup_size_x, 1, 1); + wgpuComputePassEncoderEnd(compute); + + // Run render pass (draw particles to output) + WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); + + WGPURenderPassColorAttachment color_attachment = { + .view = output_view, +#if !defined(DEMO_CROSS_COMPILE_WIN32) + .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, +#endif + .loadOp = WGPULoadOp_Clear, + .storeOp = WGPUStoreOp_Store, + .clearValue = {0.0, 0.0, 0.0, 1.0}}; + + WGPURenderPassDescriptor render_desc = { + .colorAttachmentCount = 1, + .colorAttachments = &color_attachment}; + + WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &render_desc); + wgpuRenderPassEncoderSetPipeline(pass, render_pass_.pipeline); + wgpuRenderPassEncoderSetBindGroup(pass, 0, render_pass_.bind_group, 0, nullptr); + wgpuRenderPassEncoderDraw(pass, render_pass_.vertex_count, render_pass_.instance_count, 0, 0); + wgpuRenderPassEncoderEnd(pass); +} diff --git a/src/effects/particles_effect.h b/src/effects/particles_effect.h new file mode 100644 index 0000000..76c2ef4 --- /dev/null +++ b/src/effects/particles_effect.h @@ -0,0 +1,36 @@ +// This file is part of the 64k demo project. +// It declares the ParticlesEffect. + +#pragma once + +#include "gpu/effect.h" +#include "gpu/gpu.h" +#include "gpu/uniform_helper.h" +#include + +// Particle structure +static const int NUM_PARTICLES = 10000; + +struct Particle { + float pos[4]; + float vel[4]; + float rot[4]; + float color[4]; +}; + +class ParticlesEffect : public Effect { + public: + ParticlesEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs); + void render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) override; + + private: + ComputePass compute_pass_; + RenderPass render_pass_; + GpuBuffer particles_buffer_; + UniformBuffer uniforms_; +}; + diff --git a/src/effects/particles_effect_v2.cc b/src/effects/particles_effect_v2.cc deleted file mode 100644 index 69da4da..0000000 --- a/src/effects/particles_effect_v2.cc +++ /dev/null @@ -1,96 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the ParticlesEffectV2. - -#include "effects/particles_effect_v2.h" -#include "gpu/gpu.h" -#include "gpu/shaders.h" -#include - -ParticlesEffectV2::ParticlesEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs) - : EffectV2(ctx, inputs, outputs) { - // Initialize uniforms - uniforms_.init(ctx_.device); - - // Initialize particles buffer - std::vector init_p(NUM_PARTICLES); - for (int i = 0; i < NUM_PARTICLES; ++i) { - float x = (float)(i % 100) / 50.0f - 1.0f; - float y = (float)(i / 100) / 100.0f * 3.0f - 1.5f; - init_p[i].pos[0] = x; - init_p[i].pos[1] = y; - init_p[i].pos[2] = ((float)i / NUM_PARTICLES) * 0.5f; - init_p[i].pos[3] = 1.0f; - init_p[i].vel[0] = 0.0f; - init_p[i].vel[1] = 0.0f; - init_p[i].vel[2] = 0.0f; - init_p[i].vel[3] = 0.0f; - init_p[i].rot[0] = 0.0f; - init_p[i].rot[1] = ((float)(i % 7) / 7.0f) * 3.14159f; - init_p[i].rot[2] = 0.0f; - init_p[i].rot[3] = 0.0f; - float hue = (float)(i % 100) / 100.0f; - init_p[i].color[0] = 0.5f + 0.5f * hue; - init_p[i].color[1] = 0.3f + 0.7f * (1.0f - hue); - init_p[i].color[2] = 0.8f; - init_p[i].color[3] = 0.8f; - } - - particles_buffer_ = gpu_create_buffer( - ctx_.device, sizeof(Particle) * NUM_PARTICLES, - WGPUBufferUsage_Storage | WGPUBufferUsage_Vertex, init_p.data()); - - // Create compute shader (particle simulation) - ResourceBinding compute_bindings[] = { - {particles_buffer_, WGPUBufferBindingType_Storage}, - {uniforms_.get(), WGPUBufferBindingType_Uniform}}; - compute_pass_ = gpu_create_compute_pass(ctx_.device, particle_compute_v2_wgsl, - compute_bindings, 2); - compute_pass_.workgroup_size_x = (NUM_PARTICLES + 63) / 64; - - // Create render shader (particle rendering) - ResourceBinding render_bindings[] = { - {particles_buffer_, WGPUBufferBindingType_ReadOnlyStorage}, - {uniforms_.get(), WGPUBufferBindingType_Uniform}}; - render_pass_ = gpu_create_render_pass(ctx_.device, WGPUTextureFormat_RGBA8Unorm, - particle_render_v2_wgsl, render_bindings, 2); - render_pass_.vertex_count = 6; - render_pass_.instance_count = NUM_PARTICLES; -} - -void ParticlesEffectV2::render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) { - // Update uniforms - uniforms_.update(ctx_.queue, params); - - // Run compute pass (particle simulation) - WGPUComputePassEncoder compute = wgpuCommandEncoderBeginComputePass(encoder, nullptr); - wgpuComputePassEncoderSetPipeline(compute, compute_pass_.pipeline); - wgpuComputePassEncoderSetBindGroup(compute, 0, compute_pass_.bind_group, 0, nullptr); - wgpuComputePassEncoderDispatchWorkgroups(compute, compute_pass_.workgroup_size_x, 1, 1); - wgpuComputePassEncoderEnd(compute); - - // Run render pass (draw particles to output) - WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); - - WGPURenderPassColorAttachment color_attachment = { - .view = output_view, -#if !defined(DEMO_CROSS_COMPILE_WIN32) - .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, -#endif - .loadOp = WGPULoadOp_Clear, - .storeOp = WGPUStoreOp_Store, - .clearValue = {0.0, 0.0, 0.0, 1.0}}; - - WGPURenderPassDescriptor render_desc = { - .colorAttachmentCount = 1, - .colorAttachments = &color_attachment}; - - WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &render_desc); - wgpuRenderPassEncoderSetPipeline(pass, render_pass_.pipeline); - wgpuRenderPassEncoderSetBindGroup(pass, 0, render_pass_.bind_group, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, render_pass_.vertex_count, render_pass_.instance_count, 0, 0); - wgpuRenderPassEncoderEnd(pass); -} diff --git a/src/effects/particles_effect_v2.h b/src/effects/particles_effect_v2.h deleted file mode 100644 index f0f260c..0000000 --- a/src/effects/particles_effect_v2.h +++ /dev/null @@ -1,35 +0,0 @@ -// This file is part of the 64k demo project. -// It declares the ParticlesEffectV2. - -#pragma once - -#include "gpu/effect_v2.h" -#include "gpu/gpu.h" -#include "gpu/uniform_helper.h" -#include - -// Particle structure -static const int NUM_PARTICLES = 10000; - -struct Particle { - float pos[4]; - float vel[4]; - float rot[4]; - float color[4]; -}; - -class ParticlesEffectV2 : public EffectV2 { - public: - ParticlesEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs); - void render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) override; - - private: - ComputePass compute_pass_; - RenderPass render_pass_; - GpuBuffer particles_buffer_; - UniformBuffer uniforms_; -}; diff --git a/src/effects/passthrough_effect.cc b/src/effects/passthrough_effect.cc new file mode 100644 index 0000000..ba98657 --- /dev/null +++ b/src/effects/passthrough_effect.cc @@ -0,0 +1,81 @@ +// Passthrough effect v2 implementation + +#include "effects/passthrough_effect.h" +#include "gpu/post_process_helper.h" +#include "gpu/shaders.h" + +PassthroughEffect::PassthroughEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs) + : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), + sampler_(nullptr) { + // Init uniform buffer + uniforms_buffer_.init(ctx_.device); + // Create pipeline (simple version without effect params) + pipeline_ = create_post_process_pipeline_simple(ctx_.device, WGPUTextureFormat_RGBA8Unorm, + passthrough_v2_shader_wgsl); + + // Create sampler + WGPUSamplerDescriptor sampler_desc = {}; + sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; + sampler_desc.magFilter = WGPUFilterMode_Linear; + sampler_desc.minFilter = WGPUFilterMode_Linear; + sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Nearest; + sampler_desc.maxAnisotropy = 1; + sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); +} + +void PassthroughEffect::render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) { + // Get input/output views + WGPUTextureView input_view = nodes.get_view(input_nodes_[0]); + WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); + + // Update uniforms + uniforms_buffer_.update(ctx_.queue, params); + + // Manually create bind group with only 3 entries (no effect params needed) + WGPUBindGroupEntry entries[3] = {}; + entries[0].binding = PP_BINDING_SAMPLER; + entries[0].sampler = sampler_; + entries[1].binding = PP_BINDING_TEXTURE; + entries[1].textureView = input_view; + entries[2].binding = PP_BINDING_UNIFORMS; + entries[2].buffer = uniforms_buffer_.get().buffer; + entries[2].size = sizeof(UniformsSequenceParams); + + WGPUBindGroupDescriptor bg_desc = {}; + bg_desc.layout = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0); + bg_desc.entryCount = 3; + bg_desc.entries = entries; + + if (bind_group_) { + wgpuBindGroupRelease(bind_group_); + } + bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); + + // Render pass + WGPURenderPassColorAttachment color_attachment = { + .view = output_view, +#if !defined(DEMO_CROSS_COMPILE_WIN32) + .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, +#endif + .loadOp = WGPULoadOp_Clear, + .storeOp = WGPUStoreOp_Store, + .clearValue = {0.0, 0.0, 0.0, 1.0} + }; + + WGPURenderPassDescriptor pass_desc = {}; + pass_desc.colorAttachmentCount = 1; + pass_desc.colorAttachments = &color_attachment; + + WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); + wgpuRenderPassEncoderSetPipeline(pass, pipeline_); + wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); + wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); // Fullscreen triangle + wgpuRenderPassEncoderEnd(pass); + wgpuRenderPassEncoderRelease(pass); +} diff --git a/src/effects/passthrough_effect.h b/src/effects/passthrough_effect.h new file mode 100644 index 0000000..125ac5a --- /dev/null +++ b/src/effects/passthrough_effect.h @@ -0,0 +1,21 @@ +// Passthrough effect v2 - simple copy input to output + +#pragma once + +#include "gpu/effect.h" +#include "gpu/uniform_helper.h" + +class PassthroughEffect : public Effect { + public: + PassthroughEffect(const GpuContext& ctx, const std::vector& inputs, + const std::vector& outputs); + + void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, + NodeRegistry& nodes) override; + + private: + WGPURenderPipeline pipeline_; + WGPUBindGroup bind_group_; + WGPUSampler sampler_; + UniformBuffer uniforms_buffer_; +}; diff --git a/src/effects/passthrough_effect_v2.cc b/src/effects/passthrough_effect_v2.cc deleted file mode 100644 index 38bb63a..0000000 --- a/src/effects/passthrough_effect_v2.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Passthrough effect v2 implementation - -#include "effects/passthrough_effect_v2.h" -#include "gpu/post_process_helper.h" -#include "gpu/shaders.h" - -PassthroughEffectV2::PassthroughEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs) - : EffectV2(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), - sampler_(nullptr) { - // Init uniform buffer - uniforms_buffer_.init(ctx_.device); - // Create pipeline (simple version without effect params) - pipeline_ = create_post_process_pipeline_simple(ctx_.device, WGPUTextureFormat_RGBA8Unorm, - passthrough_v2_shader_wgsl); - - // Create sampler - WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; - sampler_desc.magFilter = WGPUFilterMode_Linear; - sampler_desc.minFilter = WGPUFilterMode_Linear; - sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Nearest; - sampler_desc.maxAnisotropy = 1; - sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); -} - -void PassthroughEffectV2::render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) { - // Get input/output views - WGPUTextureView input_view = nodes.get_view(input_nodes_[0]); - WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); - - // Update uniforms - uniforms_buffer_.update(ctx_.queue, params); - - // Manually create bind group with only 3 entries (no effect params needed) - WGPUBindGroupEntry entries[3] = {}; - entries[0].binding = PP_BINDING_SAMPLER; - entries[0].sampler = sampler_; - entries[1].binding = PP_BINDING_TEXTURE; - entries[1].textureView = input_view; - entries[2].binding = PP_BINDING_UNIFORMS; - entries[2].buffer = uniforms_buffer_.get().buffer; - entries[2].size = sizeof(UniformsSequenceParams); - - WGPUBindGroupDescriptor bg_desc = {}; - bg_desc.layout = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0); - bg_desc.entryCount = 3; - bg_desc.entries = entries; - - if (bind_group_) { - wgpuBindGroupRelease(bind_group_); - } - bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); - - // Render pass - WGPURenderPassColorAttachment color_attachment = { - .view = output_view, -#if !defined(DEMO_CROSS_COMPILE_WIN32) - .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, -#endif - .loadOp = WGPULoadOp_Clear, - .storeOp = WGPUStoreOp_Store, - .clearValue = {0.0, 0.0, 0.0, 1.0} - }; - - WGPURenderPassDescriptor pass_desc = {}; - pass_desc.colorAttachmentCount = 1; - pass_desc.colorAttachments = &color_attachment; - - WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); // Fullscreen triangle - wgpuRenderPassEncoderEnd(pass); - wgpuRenderPassEncoderRelease(pass); -} diff --git a/src/effects/passthrough_effect_v2.h b/src/effects/passthrough_effect_v2.h deleted file mode 100644 index a272b87..0000000 --- a/src/effects/passthrough_effect_v2.h +++ /dev/null @@ -1,21 +0,0 @@ -// Passthrough effect v2 - simple copy input to output - -#pragma once - -#include "gpu/effect_v2.h" -#include "gpu/uniform_helper.h" - -class PassthroughEffectV2 : public EffectV2 { - public: - PassthroughEffectV2(const GpuContext& ctx, const std::vector& inputs, - const std::vector& outputs); - - void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, - NodeRegistry& nodes) override; - - private: - WGPURenderPipeline pipeline_; - WGPUBindGroup bind_group_; - WGPUSampler sampler_; - UniformBuffer uniforms_buffer_; -}; diff --git a/src/effects/placeholder_effect.cc b/src/effects/placeholder_effect.cc new file mode 100644 index 0000000..d3308de --- /dev/null +++ b/src/effects/placeholder_effect.cc @@ -0,0 +1,63 @@ +// Placeholder effect v2 implementation - logs TODO warning once + +#include "effects/placeholder_effect.h" +#include "gpu/post_process_helper.h" +#include "gpu/shaders.h" +#include + +PlaceholderEffect::PlaceholderEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs, + const char* placeholder_name) + : Effect(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), + sampler_(nullptr), name_(placeholder_name) { + // Log once on construction + fprintf(stderr, "TODO: %s not yet ported to v2, using passthrough\n", name_); + + uniforms_buffer_.init(ctx_.device); + pipeline_ = create_post_process_pipeline(ctx_.device, WGPUTextureFormat_RGBA8Unorm, + passthrough_v2_shader_wgsl); + + WGPUSamplerDescriptor sampler_desc = {}; + sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; + sampler_desc.magFilter = WGPUFilterMode_Linear; + sampler_desc.minFilter = WGPUFilterMode_Linear; + sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Nearest; + sampler_desc.maxAnisotropy = 1; + sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); +} + +void PlaceholderEffect::render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) { + WGPUTextureView input_view = nodes.get_view(input_nodes_[0]); + WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); + + uniforms_buffer_.update(ctx_.queue, params); + + pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, + uniforms_buffer_.get(), {nullptr, 0}); + + WGPURenderPassColorAttachment color_attachment = { + .view = output_view, +#if !defined(DEMO_CROSS_COMPILE_WIN32) + .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, +#endif + .loadOp = WGPULoadOp_Clear, + .storeOp = WGPUStoreOp_Store, + .clearValue = {0.0, 0.0, 0.0, 1.0} + }; + + WGPURenderPassDescriptor pass_desc = {}; + pass_desc.colorAttachmentCount = 1; + pass_desc.colorAttachments = &color_attachment; + + WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); + wgpuRenderPassEncoderSetPipeline(pass, pipeline_); + wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); + wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); + wgpuRenderPassEncoderEnd(pass); + wgpuRenderPassEncoderRelease(pass); +} diff --git a/src/effects/placeholder_effect.h b/src/effects/placeholder_effect.h new file mode 100644 index 0000000..f7917ab --- /dev/null +++ b/src/effects/placeholder_effect.h @@ -0,0 +1,25 @@ +// Placeholder effect v2 - temporary passthrough for unported effects +// TODO: Replace with actual effect implementations + +#pragma once + +#include "gpu/effect.h" +#include "gpu/uniform_helper.h" + +class PlaceholderEffect : public Effect { + public: + PlaceholderEffect(const GpuContext& ctx, const std::vector& inputs, + const std::vector& outputs, + const char* placeholder_name = "UnknownEffect"); + + void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, + NodeRegistry& nodes) override; + + private: + WGPURenderPipeline pipeline_; + WGPUBindGroup bind_group_; + WGPUSampler sampler_; + UniformBuffer uniforms_buffer_; + const char* name_; +}; + diff --git a/src/effects/placeholder_effect_v2.cc b/src/effects/placeholder_effect_v2.cc deleted file mode 100644 index d1fa212..0000000 --- a/src/effects/placeholder_effect_v2.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Placeholder effect v2 implementation - logs TODO warning once - -#include "effects/placeholder_effect_v2.h" -#include "gpu/post_process_helper.h" -#include "gpu/shaders.h" -#include - -PlaceholderEffectV2::PlaceholderEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs, - const char* placeholder_name) - : EffectV2(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), - sampler_(nullptr), name_(placeholder_name) { - // Log once on construction - fprintf(stderr, "TODO: %s not yet ported to v2, using passthrough\n", name_); - - uniforms_buffer_.init(ctx_.device); - pipeline_ = create_post_process_pipeline(ctx_.device, WGPUTextureFormat_RGBA8Unorm, - passthrough_v2_shader_wgsl); - - WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; - sampler_desc.magFilter = WGPUFilterMode_Linear; - sampler_desc.minFilter = WGPUFilterMode_Linear; - sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Nearest; - sampler_desc.maxAnisotropy = 1; - sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); -} - -void PlaceholderEffectV2::render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) { - WGPUTextureView input_view = nodes.get_view(input_nodes_[0]); - WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); - - uniforms_buffer_.update(ctx_.queue, params); - - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, - uniforms_buffer_.get(), {nullptr, 0}); - - WGPURenderPassColorAttachment color_attachment = { - .view = output_view, -#if !defined(DEMO_CROSS_COMPILE_WIN32) - .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, -#endif - .loadOp = WGPULoadOp_Clear, - .storeOp = WGPUStoreOp_Store, - .clearValue = {0.0, 0.0, 0.0, 1.0} - }; - - WGPURenderPassDescriptor pass_desc = {}; - pass_desc.colorAttachmentCount = 1; - pass_desc.colorAttachments = &color_attachment; - - WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); - wgpuRenderPassEncoderEnd(pass); - wgpuRenderPassEncoderRelease(pass); -} diff --git a/src/effects/placeholder_effect_v2.h b/src/effects/placeholder_effect_v2.h deleted file mode 100644 index aa9ed75..0000000 --- a/src/effects/placeholder_effect_v2.h +++ /dev/null @@ -1,24 +0,0 @@ -// Placeholder effect v2 - temporary passthrough for unported effects -// TODO: Replace with actual effect implementations - -#pragma once - -#include "gpu/effect_v2.h" -#include "gpu/uniform_helper.h" - -class PlaceholderEffectV2 : public EffectV2 { - public: - PlaceholderEffectV2(const GpuContext& ctx, const std::vector& inputs, - const std::vector& outputs, - const char* placeholder_name = "UnknownEffect"); - - void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, - NodeRegistry& nodes) override; - - private: - WGPURenderPipeline pipeline_; - WGPUBindGroup bind_group_; - WGPUSampler sampler_; - UniformBuffer uniforms_buffer_; - const char* name_; -}; diff --git a/src/effects/rotating_cube_effect.cc b/src/effects/rotating_cube_effect.cc new file mode 100644 index 0000000..3f1d445 --- /dev/null +++ b/src/effects/rotating_cube_effect.cc @@ -0,0 +1,186 @@ +// This file is part of the 64k demo project. +// It implements RotatingCubeEffect (simplified v2 port). + +#include "effects/rotating_cube_effect.h" +#include "gpu/bind_group_builder.h" +#include "gpu/gpu.h" +#include "gpu/shaders.h" + +RotatingCubeEffect::RotatingCubeEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs) + : Effect(ctx, inputs, outputs), depth_node_(outputs[0] + "_depth") { + // Create uniform buffers + uniform_buffer_ = + gpu_create_buffer(ctx_.device, sizeof(Uniforms), + WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst); + object_buffer_ = + gpu_create_buffer(ctx_.device, sizeof(ObjectData), + WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst); + + // Create bind group layout + WGPUBindGroupLayout bgl = + BindGroupLayoutBuilder() + .uniform(0, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment, + sizeof(Uniforms)) + .storage(1, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment, + sizeof(ObjectData)) + .build(ctx_.device); + + const WGPUBindGroupLayout bgls[] = {bgl}; + const WGPUPipelineLayoutDescriptor pl_desc = { + .bindGroupLayoutCount = 1, + .bindGroupLayouts = bgls, + }; + WGPUPipelineLayout pipeline_layout = + wgpuDeviceCreatePipelineLayout(ctx_.device, &pl_desc); + + // Load shader (TODO: create rotating_cube_v2.wgsl) + WGPUShaderSourceWGSL wgsl_src = {}; + wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; + wgsl_src.code = str_view(rotating_cube_v2_wgsl); + + WGPUShaderModuleDescriptor shader_desc = {}; + shader_desc.nextInChain = &wgsl_src.chain; + WGPUShaderModule shader_module = + wgpuDeviceCreateShaderModule(ctx_.device, &shader_desc); + + const WGPUColorTargetState color_target = { + .format = WGPUTextureFormat_RGBA8Unorm, + .writeMask = WGPUColorWriteMask_All, + }; + + const WGPUDepthStencilState depth_stencil = { + .format = WGPUTextureFormat_Depth24Plus, + .depthWriteEnabled = WGPUOptionalBool_True, + .depthCompare = WGPUCompareFunction_Less, + }; + + WGPUFragmentState fragment = {}; + fragment.module = shader_module; + fragment.entryPoint = str_view("fs_main"); + fragment.targetCount = 1; + fragment.targets = &color_target; + + WGPURenderPipelineDescriptor pipeline_desc = {}; + pipeline_desc.layout = pipeline_layout; + pipeline_desc.vertex.module = shader_module; + pipeline_desc.vertex.entryPoint = str_view("vs_main"); + pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; + pipeline_desc.primitive.cullMode = WGPUCullMode_Back; + pipeline_desc.depthStencil = &depth_stencil; + pipeline_desc.multisample.count = 1; + pipeline_desc.multisample.mask = 0xFFFFFFFF; + pipeline_desc.fragment = &fragment; + + pipeline_ = wgpuDeviceCreateRenderPipeline(ctx_.device, &pipeline_desc); + wgpuShaderModuleRelease(shader_module); + wgpuPipelineLayoutRelease(pipeline_layout); + + // Create bind group + const WGPUBindGroupEntry entries[] = { + {.binding = 0, + .buffer = uniform_buffer_.buffer, + .size = sizeof(Uniforms)}, + {.binding = 1, + .buffer = object_buffer_.buffer, + .size = sizeof(ObjectData)}, + }; + + const WGPUBindGroupDescriptor bg_desc = { + .layout = bgl, + .entryCount = 2, + .entries = entries, + }; + bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); + wgpuBindGroupLayoutRelease(bgl); +} + +RotatingCubeEffect::~RotatingCubeEffect() { + if (bind_group_) + wgpuBindGroupRelease(bind_group_); + if (pipeline_) + wgpuRenderPipelineRelease(pipeline_); +} + +void RotatingCubeEffect::declare_nodes(NodeRegistry& registry) { + // Declare depth buffer node + registry.declare_node(depth_node_, NodeType::DEPTH24, -1, -1); +} + +void RotatingCubeEffect::render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) { + rotation_ += 0.016f * 1.5f; + + // Camera setup + const vec3 camera_pos = vec3(0, 0, 5); + const vec3 target = vec3(0, 0, 0); + const vec3 up = vec3(0, 1, 0); + + const mat4 view = mat4::look_at(camera_pos, target, up); + const float fov = 60.0f * 3.14159f / 180.0f; + const mat4 proj = mat4::perspective(fov, params.aspect_ratio, 0.1f, 100.0f); + const mat4 view_proj = proj * view; + + // Cube transform + const quat rot = quat::from_axis(vec3(0.3f, 1.0f, 0.2f), rotation_); + const mat4 T = mat4::translate(vec3(0, 0, 0)); + const mat4 R = rot.to_mat(); + const mat4 S = mat4::scale(vec3(1.5f, 1.5f, 1.5f)); + const mat4 model = T * R * S; + + // Update uniforms + const Uniforms uniforms = { + .view_proj = view_proj, + .inv_view_proj = view_proj.inverse(), + .camera_pos_time = vec4(camera_pos.x, camera_pos.y, camera_pos.z, params.time), + .params = vec4(1.0f, 0.0f, 0.0f, 0.0f), + .resolution = params.resolution, + .aspect_ratio = params.aspect_ratio, + }; + + const ObjectData obj_data = { + .model = model, + .inv_model = model.inverse(), + .color = vec4(0.8f, 0.4f, 0.2f, 1.0f), + .params = vec4(1.0f, 0.0f, 0.0f, 0.0f), + }; + + wgpuQueueWriteBuffer(ctx_.queue, uniform_buffer_.buffer, 0, &uniforms, + sizeof(Uniforms)); + wgpuQueueWriteBuffer(ctx_.queue, object_buffer_.buffer, 0, &obj_data, + sizeof(ObjectData)); + + // Get output views + WGPUTextureView color_view = nodes.get_view(output_nodes_[0]); + WGPUTextureView depth_view = nodes.get_view(depth_node_); + + // Render pass with depth + WGPURenderPassColorAttachment color_attachment = { + .view = color_view, +#if !defined(DEMO_CROSS_COMPILE_WIN32) + .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, +#endif + .loadOp = WGPULoadOp_Clear, + .storeOp = WGPUStoreOp_Store, + .clearValue = {0.0, 0.0, 0.0, 1.0}}; + + WGPURenderPassDepthStencilAttachment depth_attachment = { + .view = depth_view, + .depthLoadOp = WGPULoadOp_Clear, + .depthStoreOp = WGPUStoreOp_Discard, + .depthClearValue = 1.0f}; + + WGPURenderPassDescriptor pass_desc = { + .colorAttachmentCount = 1, + .colorAttachments = &color_attachment, + .depthStencilAttachment = &depth_attachment}; + + WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); + wgpuRenderPassEncoderSetPipeline(pass, pipeline_); + wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); + wgpuRenderPassEncoderDraw(pass, 36, 1, 0, 0); // 36 vertices for cube + wgpuRenderPassEncoderEnd(pass); + wgpuRenderPassEncoderRelease(pass); +} diff --git a/src/effects/rotating_cube_effect.h b/src/effects/rotating_cube_effect.h new file mode 100644 index 0000000..1c0155a --- /dev/null +++ b/src/effects/rotating_cube_effect.h @@ -0,0 +1,49 @@ +// This file is part of the 64k demo project. +// It declares RotatingCubeEffect (simplified v2 port). + +#pragma once + +#include "gpu/effect.h" +#include "gpu/gpu.h" +#include "gpu/uniform_helper.h" +#include "util/mini_math.h" + +class RotatingCubeEffect : public Effect { + public: + RotatingCubeEffect(const GpuContext& ctx, + const std::vector& inputs, + const std::vector& outputs); + ~RotatingCubeEffect() override; + + void declare_nodes(NodeRegistry& registry) override; + void render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) override; + + private: + struct Uniforms { + mat4 view_proj; + mat4 inv_view_proj; + vec4 camera_pos_time; + vec4 params; + vec2 resolution; + float aspect_ratio; + float _pad; + }; + static_assert(sizeof(Uniforms) == 176, "Uniforms size mismatch"); + + struct ObjectData { + mat4 model; + mat4 inv_model; + vec4 color; + vec4 params; + }; + static_assert(sizeof(ObjectData) == 160, "ObjectData size mismatch"); + + WGPURenderPipeline pipeline_ = nullptr; + WGPUBindGroup bind_group_ = nullptr; + GpuBuffer uniform_buffer_; + GpuBuffer object_buffer_; + float rotation_ = 0.0f; + std::string depth_node_; +}; diff --git a/src/effects/rotating_cube_effect_v2.cc b/src/effects/rotating_cube_effect_v2.cc deleted file mode 100644 index 1a28cad..0000000 --- a/src/effects/rotating_cube_effect_v2.cc +++ /dev/null @@ -1,186 +0,0 @@ -// This file is part of the 64k demo project. -// It implements RotatingCubeEffectV2 (simplified v2 port). - -#include "effects/rotating_cube_effect_v2.h" -#include "gpu/bind_group_builder.h" -#include "gpu/gpu.h" -#include "gpu/shaders.h" - -RotatingCubeEffectV2::RotatingCubeEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs) - : EffectV2(ctx, inputs, outputs), depth_node_(outputs[0] + "_depth") { - // Create uniform buffers - uniform_buffer_ = - gpu_create_buffer(ctx_.device, sizeof(Uniforms), - WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst); - object_buffer_ = - gpu_create_buffer(ctx_.device, sizeof(ObjectData), - WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst); - - // Create bind group layout - WGPUBindGroupLayout bgl = - BindGroupLayoutBuilder() - .uniform(0, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment, - sizeof(Uniforms)) - .storage(1, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment, - sizeof(ObjectData)) - .build(ctx_.device); - - const WGPUBindGroupLayout bgls[] = {bgl}; - const WGPUPipelineLayoutDescriptor pl_desc = { - .bindGroupLayoutCount = 1, - .bindGroupLayouts = bgls, - }; - WGPUPipelineLayout pipeline_layout = - wgpuDeviceCreatePipelineLayout(ctx_.device, &pl_desc); - - // Load shader (TODO: create rotating_cube_v2.wgsl) - WGPUShaderSourceWGSL wgsl_src = {}; - wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_src.code = str_view(rotating_cube_v2_wgsl); - - WGPUShaderModuleDescriptor shader_desc = {}; - shader_desc.nextInChain = &wgsl_src.chain; - WGPUShaderModule shader_module = - wgpuDeviceCreateShaderModule(ctx_.device, &shader_desc); - - const WGPUColorTargetState color_target = { - .format = WGPUTextureFormat_RGBA8Unorm, - .writeMask = WGPUColorWriteMask_All, - }; - - const WGPUDepthStencilState depth_stencil = { - .format = WGPUTextureFormat_Depth24Plus, - .depthWriteEnabled = WGPUOptionalBool_True, - .depthCompare = WGPUCompareFunction_Less, - }; - - WGPUFragmentState fragment = {}; - fragment.module = shader_module; - fragment.entryPoint = str_view("fs_main"); - fragment.targetCount = 1; - fragment.targets = &color_target; - - WGPURenderPipelineDescriptor pipeline_desc = {}; - pipeline_desc.layout = pipeline_layout; - pipeline_desc.vertex.module = shader_module; - pipeline_desc.vertex.entryPoint = str_view("vs_main"); - pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; - pipeline_desc.primitive.cullMode = WGPUCullMode_Back; - pipeline_desc.depthStencil = &depth_stencil; - pipeline_desc.multisample.count = 1; - pipeline_desc.multisample.mask = 0xFFFFFFFF; - pipeline_desc.fragment = &fragment; - - pipeline_ = wgpuDeviceCreateRenderPipeline(ctx_.device, &pipeline_desc); - wgpuShaderModuleRelease(shader_module); - wgpuPipelineLayoutRelease(pipeline_layout); - - // Create bind group - const WGPUBindGroupEntry entries[] = { - {.binding = 0, - .buffer = uniform_buffer_.buffer, - .size = sizeof(Uniforms)}, - {.binding = 1, - .buffer = object_buffer_.buffer, - .size = sizeof(ObjectData)}, - }; - - const WGPUBindGroupDescriptor bg_desc = { - .layout = bgl, - .entryCount = 2, - .entries = entries, - }; - bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); - wgpuBindGroupLayoutRelease(bgl); -} - -RotatingCubeEffectV2::~RotatingCubeEffectV2() { - if (bind_group_) - wgpuBindGroupRelease(bind_group_); - if (pipeline_) - wgpuRenderPipelineRelease(pipeline_); -} - -void RotatingCubeEffectV2::declare_nodes(NodeRegistry& registry) { - // Declare depth buffer node - registry.declare_node(depth_node_, NodeType::DEPTH24, -1, -1); -} - -void RotatingCubeEffectV2::render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) { - rotation_ += 0.016f * 1.5f; - - // Camera setup - const vec3 camera_pos = vec3(0, 0, 5); - const vec3 target = vec3(0, 0, 0); - const vec3 up = vec3(0, 1, 0); - - const mat4 view = mat4::look_at(camera_pos, target, up); - const float fov = 60.0f * 3.14159f / 180.0f; - const mat4 proj = mat4::perspective(fov, params.aspect_ratio, 0.1f, 100.0f); - const mat4 view_proj = proj * view; - - // Cube transform - const quat rot = quat::from_axis(vec3(0.3f, 1.0f, 0.2f), rotation_); - const mat4 T = mat4::translate(vec3(0, 0, 0)); - const mat4 R = rot.to_mat(); - const mat4 S = mat4::scale(vec3(1.5f, 1.5f, 1.5f)); - const mat4 model = T * R * S; - - // Update uniforms - const Uniforms uniforms = { - .view_proj = view_proj, - .inv_view_proj = view_proj.inverse(), - .camera_pos_time = vec4(camera_pos.x, camera_pos.y, camera_pos.z, params.time), - .params = vec4(1.0f, 0.0f, 0.0f, 0.0f), - .resolution = params.resolution, - .aspect_ratio = params.aspect_ratio, - }; - - const ObjectData obj_data = { - .model = model, - .inv_model = model.inverse(), - .color = vec4(0.8f, 0.4f, 0.2f, 1.0f), - .params = vec4(1.0f, 0.0f, 0.0f, 0.0f), - }; - - wgpuQueueWriteBuffer(ctx_.queue, uniform_buffer_.buffer, 0, &uniforms, - sizeof(Uniforms)); - wgpuQueueWriteBuffer(ctx_.queue, object_buffer_.buffer, 0, &obj_data, - sizeof(ObjectData)); - - // Get output views - WGPUTextureView color_view = nodes.get_view(output_nodes_[0]); - WGPUTextureView depth_view = nodes.get_view(depth_node_); - - // Render pass with depth - WGPURenderPassColorAttachment color_attachment = { - .view = color_view, -#if !defined(DEMO_CROSS_COMPILE_WIN32) - .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, -#endif - .loadOp = WGPULoadOp_Clear, - .storeOp = WGPUStoreOp_Store, - .clearValue = {0.0, 0.0, 0.0, 1.0}}; - - WGPURenderPassDepthStencilAttachment depth_attachment = { - .view = depth_view, - .depthLoadOp = WGPULoadOp_Clear, - .depthStoreOp = WGPUStoreOp_Discard, - .depthClearValue = 1.0f}; - - WGPURenderPassDescriptor pass_desc = { - .colorAttachmentCount = 1, - .colorAttachments = &color_attachment, - .depthStencilAttachment = &depth_attachment}; - - WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 36, 1, 0, 0); // 36 vertices for cube - wgpuRenderPassEncoderEnd(pass); - wgpuRenderPassEncoderRelease(pass); -} diff --git a/src/effects/rotating_cube_effect_v2.h b/src/effects/rotating_cube_effect_v2.h deleted file mode 100644 index 19ef410..0000000 --- a/src/effects/rotating_cube_effect_v2.h +++ /dev/null @@ -1,49 +0,0 @@ -// This file is part of the 64k demo project. -// It declares RotatingCubeEffectV2 (simplified v2 port). - -#pragma once - -#include "gpu/effect_v2.h" -#include "gpu/gpu.h" -#include "gpu/uniform_helper.h" -#include "util/mini_math.h" - -class RotatingCubeEffectV2 : public EffectV2 { - public: - RotatingCubeEffectV2(const GpuContext& ctx, - const std::vector& inputs, - const std::vector& outputs); - ~RotatingCubeEffectV2() override; - - void declare_nodes(NodeRegistry& registry) override; - void render(WGPUCommandEncoder encoder, - const UniformsSequenceParams& params, - NodeRegistry& nodes) override; - - private: - struct Uniforms { - mat4 view_proj; - mat4 inv_view_proj; - vec4 camera_pos_time; - vec4 params; - vec2 resolution; - float aspect_ratio; - float _pad; - }; - static_assert(sizeof(Uniforms) == 176, "Uniforms size mismatch"); - - struct ObjectData { - mat4 model; - mat4 inv_model; - vec4 color; - vec4 params; - }; - static_assert(sizeof(ObjectData) == 160, "ObjectData size mismatch"); - - WGPURenderPipeline pipeline_ = nullptr; - WGPUBindGroup bind_group_ = nullptr; - GpuBuffer uniform_buffer_; - GpuBuffer object_buffer_; - float rotation_ = 0.0f; - std::string depth_node_; -}; -- cgit v1.2.3