summaryrefslogtreecommitdiff
path: root/src/gpu
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-01 18:56:47 +0100
committerskal <pascal.massimino@gmail.com>2026-02-01 18:56:47 +0100
commite3ef115804b46e8bfc594987b04b1059aed5e002 (patch)
tree3670f718ee23cf34e94984568900eac23022d1f0 /src/gpu
parent7fab8880cca269621cd32610b22f2820567771f2 (diff)
feat(gpu/assets): Fix tests, integrate bumpy 3D renderer and procedural assets
- Fixed test_sequence by restoring MainSequence::init_test for mocking. - Corrected CMakeLists.txt dependencies and source groupings to prevent duplicate symbols. - standardizing Effect constructor signature for seq_compiler compatibility. - Implemented Hybrid3DEffect using bumpy Renderer3D and procedural NOISE_TEX. - Updated MainSequence to support depth buffer for 3D elements. - Formatted all source files with clang-format.
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/demo_effects.h7
-rw-r--r--src/gpu/effect.cc16
-rw-r--r--src/gpu/effect.h3
-rw-r--r--src/gpu/effects/hybrid_3d_effect.cc83
-rw-r--r--src/gpu/effects/hybrid_3d_effect.h10
-rw-r--r--src/gpu/texture_manager.cc12
-rw-r--r--src/gpu/texture_manager.h5
7 files changed, 80 insertions, 56 deletions
diff --git a/src/gpu/demo_effects.h b/src/gpu/demo_effects.h
index 0ff75b9..1f3c526 100644
--- a/src/gpu/demo_effects.h
+++ b/src/gpu/demo_effects.h
@@ -2,13 +2,13 @@
// It declares the concrete effects used in the demo.
#pragma once
+#include "3d/camera.h"
+#include "3d/renderer.h"
+#include "3d/scene.h"
#include "effect.h"
#include "gpu/effects/post_process_helper.h"
#include "gpu/effects/shaders.h"
#include "gpu/gpu.h"
-#include "3d/renderer.h"
-#include "3d/scene.h"
-#include "3d/camera.h"
#include "gpu/texture_manager.h"
#include <memory>
@@ -118,6 +118,7 @@ class Hybrid3DEffect : public Effect {
void init(MainSequence* demo) override;
void render(WGPURenderPassEncoder pass, float time, float beat,
float intensity, float aspect_ratio) override;
+
private:
Renderer3D renderer_;
TextureManager texture_manager_;
diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc
index fdc604c..b2e0c4e 100644
--- a/src/gpu/effect.cc
+++ b/src/gpu/effect.cc
@@ -131,6 +131,14 @@ void MainSequence::create_framebuffers(int width, int height) {
depth_view_ = wgpuTextureCreateView(depth_texture_, &depth_view_desc);
}
+void MainSequence::init_test(WGPUDevice d, WGPUQueue q, WGPUTextureFormat f) {
+ device = d;
+ queue = q;
+ format = f;
+ // No framebuffers or passthrough effect created in test mode.
+ // Test effects should not rely on these being real.
+}
+
void MainSequence::init(WGPUDevice d, WGPUQueue q, WGPUTextureFormat f,
int width, int height) {
device = d;
@@ -197,7 +205,7 @@ void MainSequence::render_frame(float global_time, float beat, float peak,
#if !defined(DEMO_CROSS_COMPILE_WIN32)
scene_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
#endif /* !defined(DEMO_CROSS_COMPILE_WIN32) */
-
+
WGPURenderPassDepthStencilAttachment depth_attachment = {};
depth_attachment.view = depth_view_;
depth_attachment.depthLoadOp = WGPULoadOp_Clear;
@@ -206,7 +214,8 @@ void MainSequence::render_frame(float global_time, float beat, float peak,
WGPURenderPassDescriptor scene_desc = {.colorAttachmentCount = 1,
.colorAttachments = &scene_attachment,
- .depthStencilAttachment = &depth_attachment};
+ .depthStencilAttachment =
+ &depth_attachment};
WGPURenderPassEncoder scene_pass =
wgpuCommandEncoderBeginRenderPass(encoder, &scene_desc);
for (const SequenceItem* item : scene_effects) {
@@ -224,7 +233,8 @@ void MainSequence::render_frame(float global_time, float beat, float peak,
final_view = wgpuTextureCreateView(st.texture, nullptr);
// Safely cast to PostProcessEffect to call update_bind_group
- PostProcessEffect* pp_effect = (PostProcessEffect*)passthrough_effect_.get();
+ PostProcessEffect* pp_effect =
+ (PostProcessEffect*)passthrough_effect_.get();
pp_effect->update_bind_group(framebuffer_view_a_);
WGPURenderPassColorAttachment final_attachment = {};
diff --git a/src/gpu/effect.h b/src/gpu/effect.h
index 5d6b666..29f8e85 100644
--- a/src/gpu/effect.h
+++ b/src/gpu/effect.h
@@ -100,6 +100,7 @@ class MainSequence {
void init(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format,
int width, int height);
+ void init_test(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format);
void add_sequence(std::shared_ptr<Sequence> seq, float start_time,
int priority = 0);
void render_frame(float global_time, float beat, float peak,
@@ -122,7 +123,7 @@ class MainSequence {
WGPUTextureView framebuffer_view_a_ = nullptr;
WGPUTexture framebuffer_b_ = nullptr;
WGPUTextureView framebuffer_view_b_ = nullptr;
-
+
WGPUTexture depth_texture_ = nullptr;
WGPUTextureView depth_view_ = nullptr;
diff --git a/src/gpu/effects/hybrid_3d_effect.cc b/src/gpu/effects/hybrid_3d_effect.cc
index 41ede0b..6af2bd4 100644
--- a/src/gpu/effects/hybrid_3d_effect.cc
+++ b/src/gpu/effects/hybrid_3d_effect.cc
@@ -2,34 +2,38 @@
// It implements the Hybrid3DEffect.
#include "gpu/effects/hybrid_3d_effect.h"
-#include "util/asset_manager.h"
#include "generated/assets.h"
-#include <cmath>
+#include "util/asset_manager.h"
#include <cassert>
+#include <cmath>
#include <iostream>
-Hybrid3DEffect::Hybrid3DEffect(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format) : Effect(device, queue), width_(1280), height_(720) {
+Hybrid3DEffect::Hybrid3DEffect(WGPUDevice device, WGPUQueue queue,
+ WGPUTextureFormat format)
+ : Effect(device, queue), width_(1280), height_(720) {
(void)format; // Passed to base, not directly used here.
}
void Hybrid3DEffect::init(MainSequence* demo) {
- (void)demo;
- WGPUTextureFormat format = demo->format; // Get current format from MainSequence (might be different than constructor if resized)
-
+ (void)demo;
+ WGPUTextureFormat format =
+ demo->format; // Get current format from MainSequence (might be different
+ // than constructor if resized)
+
renderer_.init(device_, queue_, format);
renderer_.resize(width_, height_);
// Texture Manager
texture_manager_.init(device_, queue_);
-
+
// Load Noise Asset
size_t size = 0;
const uint8_t* noise_data = GetAsset(AssetId::ASSET_NOISE_TEX, &size);
if (noise_data && size == 256 * 256 * 4) {
- texture_manager_.create_texture("noise", 256, 256, noise_data);
- renderer_.set_noise_texture(texture_manager_.get_texture_view("noise"));
+ texture_manager_.create_texture("noise", 256, 256, noise_data);
+ renderer_.set_noise_texture(texture_manager_.get_texture_view("noise"));
} else {
- std::cerr << "Failed to load NOISE_TEX asset." << std::endl;
+ std::cerr << "Failed to load NOISE_TEX asset." << std::endl;
}
// Setup Scene
@@ -41,40 +45,45 @@ void Hybrid3DEffect::init(MainSequence* demo) {
for (int i = 0; i < 8; ++i) {
ObjectType type = ObjectType::SPHERE;
- if (i % 3 == 1) type = ObjectType::TORUS;
- if (i % 3 == 2) type = ObjectType::BOX;
-
+ if (i % 3 == 1)
+ type = ObjectType::TORUS;
+ if (i % 3 == 2)
+ type = ObjectType::BOX;
+
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.5f, 0.5f, 0.5f);
-
- if (type == ObjectType::SPHERE) obj.color = vec4(0, 1, 0, 1);
- else if (type == ObjectType::TORUS) obj.color = vec4(0, 0.5, 1, 1);
- else obj.color = vec4(1, 1, 0, 1);
-
+
+ if (type == ObjectType::SPHERE)
+ obj.color = vec4(0, 1, 0, 1);
+ else if (type == ObjectType::TORUS)
+ obj.color = vec4(0, 0.5, 1, 1);
+ else
+ obj.color = vec4(1, 1, 0, 1);
+
scene_.add_object(obj);
}
}
-void Hybrid3DEffect::render(WGPURenderPassEncoder pass, float time, float beat, float intensity, float aspect_ratio) {
- // Animate Objects
- for (size_t i = 1; i < scene_.objects.size(); ++i) {
- scene_.objects[i].rotation = quat::from_axis(vec3(0, 1, 0), time * 2.0f + i);
- scene_.objects[i].position.y = std::sin(time * 3.0f + i) * 1.5f;
- }
-
- // Animate Camera
- float cam_radius = 10.0f + std::sin(time * 0.3f) * 4.0f;
- float cam_height = 5.0f + std::cos(time * 0.4f) * 3.0f;
- camera_.set_look_at(
- vec3(std::sin(time * 0.5f) * cam_radius, cam_height, std::cos(time * 0.5f) * cam_radius),
- vec3(0, 0, 0),
- vec3(0, 1, 0)
- );
-
- camera_.aspect_ratio = aspect_ratio;
+void Hybrid3DEffect::render(WGPURenderPassEncoder pass, float time, float beat,
+ float intensity, float aspect_ratio) {
+ // Animate Objects
+ for (size_t i = 1; i < scene_.objects.size(); ++i) {
+ scene_.objects[i].rotation =
+ quat::from_axis(vec3(0, 1, 0), time * 2.0f + i);
+ scene_.objects[i].position.y = std::sin(time * 3.0f + i) * 1.5f;
+ }
+
+ // Animate Camera
+ float cam_radius = 10.0f + std::sin(time * 0.3f) * 4.0f;
+ float cam_height = 5.0f + std::cos(time * 0.4f) * 3.0f;
+ camera_.set_look_at(vec3(std::sin(time * 0.5f) * cam_radius, cam_height,
+ std::cos(time * 0.5f) * cam_radius),
+ vec3(0, 0, 0), vec3(0, 1, 0));
+
+ camera_.aspect_ratio = aspect_ratio;
- // Draw
- renderer_.draw(pass, scene_, camera_, time);
+ // Draw
+ renderer_.draw(pass, scene_, camera_, time);
}
diff --git a/src/gpu/effects/hybrid_3d_effect.h b/src/gpu/effects/hybrid_3d_effect.h
index 1b0eab7..ef62883 100644
--- a/src/gpu/effects/hybrid_3d_effect.h
+++ b/src/gpu/effects/hybrid_3d_effect.h
@@ -1,12 +1,13 @@
// This file is part of the 64k demo project.
-// It defines the Hybrid3DEffect, integrating the 3D renderer into the demo timeline.
+// It defines the Hybrid3DEffect, integrating the 3D renderer into the demo
+// timeline.
#pragma once
-#include "gpu/effect.h"
+#include "3d/camera.h"
#include "3d/renderer.h"
#include "3d/scene.h"
-#include "3d/camera.h"
+#include "gpu/effect.h"
#include "gpu/texture_manager.h"
class Hybrid3DEffect : public Effect {
@@ -15,7 +16,8 @@ class Hybrid3DEffect : public Effect {
virtual ~Hybrid3DEffect() override = default;
void init(MainSequence* demo) override;
- void render(WGPURenderPassEncoder pass, float time, float beat, float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass, float time, float beat,
+ float intensity, float aspect_ratio) override;
private:
Renderer3D renderer_;
diff --git a/src/gpu/texture_manager.cc b/src/gpu/texture_manager.cc
index f2d93ad..5da82c0 100644
--- a/src/gpu/texture_manager.cc
+++ b/src/gpu/texture_manager.cc
@@ -44,13 +44,13 @@ void TextureManager::create_procedural_texture(
#endif
}
-void TextureManager::create_texture(const std::string& name, int width, int height, const uint8_t* data) {
+void TextureManager::create_texture(const std::string& name, int width,
+ int height, const uint8_t* data) {
WGPUExtent3D tex_size = {(uint32_t)width, (uint32_t)height, 1};
// 2. Create GPU Texture
WGPUTextureDescriptor tex_desc = {};
- tex_desc.usage =
- WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
+ tex_desc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
tex_desc.dimension = WGPUTextureDimension_2D;
tex_desc.size = tex_size;
tex_desc.format = WGPUTextureFormat_RGBA8Unorm;
@@ -76,8 +76,8 @@ void TextureManager::create_texture(const std::string& name, int width, int heig
source_layout.bytesPerRow = width * 4;
source_layout.rowsPerImage = height;
- wgpuQueueWriteTexture(queue_, &destination, data,
- width * height * 4, &source_layout, &tex_size);
+ wgpuQueueWriteTexture(queue_, &destination, data, width * height * 4,
+ &source_layout, &tex_size);
// 4. Create View
WGPUTextureViewDescriptor view_desc = {};
@@ -97,7 +97,7 @@ void TextureManager::create_texture(const std::string& name, int width, int heig
gpu_tex.view = view;
gpu_tex.width = width;
gpu_tex.height = height;
-
+
textures_[name] = gpu_tex;
}
diff --git a/src/gpu/texture_manager.h b/src/gpu/texture_manager.h
index 54dcfeb..b97e6a8 100644
--- a/src/gpu/texture_manager.h
+++ b/src/gpu/texture_manager.h
@@ -37,9 +37,10 @@ class TextureManager {
// Registers and generates a texture immediately
void create_procedural_texture(const std::string& name,
const ProceduralTextureDef& def);
-
+
// Creates a texture from existing data (RGBA8)
- void create_texture(const std::string& name, int width, int height, const uint8_t* data);
+ void create_texture(const std::string& name, int width, int height,
+ const uint8_t* data);
// Retrieves a texture view by name (returns nullptr if not found)
WGPUTextureView get_texture_view(const std::string& name);