summaryrefslogtreecommitdiff
path: root/src/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/demo_effects.h19
-rw-r--r--src/gpu/effect.cc47
-rw-r--r--src/gpu/effect.h9
-rw-r--r--src/gpu/effects/hybrid_3d_effect.cc80
-rw-r--r--src/gpu/effects/hybrid_3d_effect.h14
-rw-r--r--src/gpu/gpu.cc7
-rw-r--r--src/gpu/texture_manager.cc33
-rw-r--r--src/gpu/texture_manager.h3
8 files changed, 177 insertions, 35 deletions
diff --git a/src/gpu/demo_effects.h b/src/gpu/demo_effects.h
index fb8d531..0ff75b9 100644
--- a/src/gpu/demo_effects.h
+++ b/src/gpu/demo_effects.h
@@ -6,6 +6,10 @@
#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>
static const int NUM_PARTICLES = 10000;
@@ -108,6 +112,21 @@ class ChromaAberrationEffect : public PostProcessEffect {
void update_bind_group(WGPUTextureView input_view) override;
};
+class Hybrid3DEffect : public Effect {
+ public:
+ Hybrid3DEffect(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format);
+ 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_;
+ Scene scene_;
+ Camera camera_;
+ int width_ = 1280;
+ int height_ = 720;
+};
+
// Auto-generated function to populate the timeline
void LoadTimeline(MainSequence& main_seq, WGPUDevice device, WGPUQueue queue,
WGPUTextureFormat format); \ No newline at end of file
diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc
index 81d5952..fdc604c 100644
--- a/src/gpu/effect.cc
+++ b/src/gpu/effect.cc
@@ -111,14 +111,24 @@ void MainSequence::create_framebuffers(int width, int height) {
framebuffer_view_a_ = wgpuTextureCreateView(framebuffer_a_, &view_desc);
framebuffer_view_b_ = wgpuTextureCreateView(framebuffer_b_, &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.
+ // Depth Buffer
+ WGPUTextureDescriptor depth_desc = {};
+ depth_desc.usage = WGPUTextureUsage_RenderAttachment;
+ depth_desc.dimension = WGPUTextureDimension_2D;
+ depth_desc.size = {(uint32_t)width, (uint32_t)height, 1};
+ depth_desc.format = WGPUTextureFormat_Depth24Plus;
+ depth_desc.mipLevelCount = 1;
+ depth_desc.sampleCount = 1;
+ depth_texture_ = wgpuDeviceCreateTexture(device, &depth_desc);
+
+ WGPUTextureViewDescriptor depth_view_desc = {};
+ depth_view_desc.format = WGPUTextureFormat_Depth24Plus;
+ depth_view_desc.dimension = WGPUTextureViewDimension_2D;
+ depth_view_desc.aspect = WGPUTextureAspect_DepthOnly;
+ depth_view_desc.mipLevelCount = 1;
+ depth_view_desc.arrayLayerCount = 1;
+ depth_view_ = wgpuTextureCreateView(depth_texture_, &depth_view_desc);
}
void MainSequence::init(WGPUDevice d, WGPUQueue q, WGPUTextureFormat f,
@@ -139,6 +149,10 @@ void MainSequence::init(WGPUDevice d, WGPUQueue q, WGPUTextureFormat f,
void MainSequence::add_sequence(std::shared_ptr<Sequence> seq, float start_time,
int priority) {
sequences_.push_back({seq, start_time, priority});
+ // If MainSequence is already initialized, init the new sequence immediately
+ if (device) {
+ seq->init(this);
+ }
std::sort(sequences_.begin(), sequences_.end(),
[](const ActiveSequence& a, const ActiveSequence& b) {
return a.priority < b.priority;
@@ -183,8 +197,16 @@ 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;
+ depth_attachment.depthStoreOp = WGPUStoreOp_Store;
+ depth_attachment.depthClearValue = 1.0f;
+
WGPURenderPassDescriptor scene_desc = {.colorAttachmentCount = 1,
- .colorAttachments = &scene_attachment};
+ .colorAttachments = &scene_attachment,
+ .depthStencilAttachment = &depth_attachment};
WGPURenderPassEncoder scene_pass =
wgpuCommandEncoderBeginRenderPass(encoder, &scene_desc);
for (const SequenceItem* item : scene_effects) {
@@ -200,7 +222,10 @@ void MainSequence::render_frame(float global_time, float beat, float peak,
if (post_effects.empty()) {
wgpuSurfaceGetCurrentTexture(surface, &st);
final_view = wgpuTextureCreateView(st.texture, nullptr);
- passthrough_effect_->update_bind_group(framebuffer_view_a_);
+
+ // Safely cast to PostProcessEffect to call update_bind_group
+ PostProcessEffect* pp_effect = (PostProcessEffect*)passthrough_effect_.get();
+ pp_effect->update_bind_group(framebuffer_view_a_);
WGPURenderPassColorAttachment final_attachment = {};
final_attachment.view = final_view;
@@ -274,6 +299,10 @@ void MainSequence::shutdown() {
wgpuTextureViewRelease(framebuffer_view_b_);
if (framebuffer_b_)
wgpuTextureRelease(framebuffer_b_);
+ if (depth_view_)
+ wgpuTextureViewRelease(depth_view_);
+ if (depth_texture_)
+ wgpuTextureRelease(depth_texture_);
for (ActiveSequence& entry : sequences_) {
entry.seq->reset();
}
diff --git a/src/gpu/effect.h b/src/gpu/effect.h
index 51b3883..5d6b666 100644
--- a/src/gpu/effect.h
+++ b/src/gpu/effect.h
@@ -122,12 +122,11 @@ class MainSequence {
WGPUTextureView framebuffer_view_a_ = nullptr;
WGPUTexture framebuffer_b_ = nullptr;
WGPUTextureView framebuffer_view_b_ = nullptr;
+
+ WGPUTexture depth_texture_ = nullptr;
+ WGPUTextureView depth_view_ = nullptr;
- public: // Made public for testing
- void init_test(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format);
-
- private: // Restore private access for other members
- std::unique_ptr<PostProcessEffect> passthrough_effect_;
+ std::unique_ptr<Effect> passthrough_effect_;
void create_framebuffers(int width, int height);
};
diff --git a/src/gpu/effects/hybrid_3d_effect.cc b/src/gpu/effects/hybrid_3d_effect.cc
new file mode 100644
index 0000000..41ede0b
--- /dev/null
+++ b/src/gpu/effects/hybrid_3d_effect.cc
@@ -0,0 +1,80 @@
+// This file is part of the 64k demo project.
+// It implements the Hybrid3DEffect.
+
+#include "gpu/effects/hybrid_3d_effect.h"
+#include "util/asset_manager.h"
+#include "generated/assets.h"
+#include <cmath>
+#include <cassert>
+#include <iostream>
+
+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)
+
+ 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"));
+ } else {
+ std::cerr << "Failed to load NOISE_TEX asset." << std::endl;
+ }
+
+ // Setup Scene
+ scene_.clear();
+ Object3D center(ObjectType::BOX); // Use BOX for bumps
+ 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 = ObjectType::SPHERE;
+ 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);
+
+ 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;
+
+ // 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 a0a82b5..1b0eab7 100644
--- a/src/gpu/effects/hybrid_3d_effect.h
+++ b/src/gpu/effects/hybrid_3d_effect.h
@@ -7,21 +7,21 @@
#include "3d/renderer.h"
#include "3d/scene.h"
#include "3d/camera.h"
+#include "gpu/texture_manager.h"
class Hybrid3DEffect : public Effect {
public:
- Hybrid3DEffect();
+ Hybrid3DEffect(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format);
virtual ~Hybrid3DEffect() override = default;
- void init(WGPUDevice device, WGPUQueue queue, int width, int height) override;
- void render(WGPURenderPassEncoder pass, float time, float beat, float alpha) override;
+ 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_;
Scene scene_;
Camera camera_;
- WGPUDevice device_ = nullptr;
- WGPUQueue queue_ = nullptr;
- int width_ = 0;
- int height_ = 0;
+ int width_ = 1280;
+ int height_ = 720;
};
diff --git a/src/gpu/gpu.cc b/src/gpu/gpu.cc
index 3cdf9aa..17d32ee 100644
--- a/src/gpu/gpu.cc
+++ b/src/gpu/gpu.cc
@@ -147,6 +147,13 @@ RenderPass gpu_create_render_pass(WGPUDevice device, WGPUTextureFormat format,
pipeline_desc.multisample.mask = 0xFFFFFFFF;
pipeline_desc.fragment = &fragment_state;
+ // Depth Stencil State (Required for compatibility with MainSequence pass)
+ WGPUDepthStencilState depth_stencil = {};
+ depth_stencil.format = WGPUTextureFormat_Depth24Plus;
+ depth_stencil.depthWriteEnabled = WGPUOptionalBool_False;
+ depth_stencil.depthCompare = WGPUCompareFunction_Always;
+ pipeline_desc.depthStencil = &depth_stencil;
+
pass.pipeline = wgpuDeviceCreateRenderPipeline(device, &pipeline_desc);
return pass;
diff --git a/src/gpu/texture_manager.cc b/src/gpu/texture_manager.cc
index 4240245..f2d93ad 100644
--- a/src/gpu/texture_manager.cc
+++ b/src/gpu/texture_manager.cc
@@ -36,11 +36,21 @@ void TextureManager::create_procedural_texture(
def.gen_func(pixel_data.data(), def.width, def.height, def.params.data(),
(int)def.params.size());
- WGPUExtent3D tex_size = {(uint32_t)def.width, (uint32_t)def.height, 1};
+ create_texture(name, def.width, def.height, pixel_data.data());
+
+#if !defined(STRIP_ALL)
+ std::cout << "Generated procedural texture: " << name << " (" << def.width
+ << "x" << def.height << ")" << std::endl;
+#endif
+}
+
+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;
@@ -63,11 +73,11 @@ void TextureManager::create_procedural_texture(
WGPU_TEX_DATA_LAYOUT source_layout = {};
source_layout.offset = 0;
- source_layout.bytesPerRow = def.width * 4;
- source_layout.rowsPerImage = def.height;
+ source_layout.bytesPerRow = width * 4;
+ source_layout.rowsPerImage = height;
- wgpuQueueWriteTexture(queue_, &destination, pixel_data.data(),
- pixel_data.size(), &source_layout, &tex_size);
+ wgpuQueueWriteTexture(queue_, &destination, data,
+ width * height * 4, &source_layout, &tex_size);
// 4. Create View
WGPUTextureViewDescriptor view_desc = {};
@@ -85,15 +95,10 @@ void TextureManager::create_procedural_texture(
GpuTexture gpu_tex;
gpu_tex.texture = texture;
gpu_tex.view = view;
- gpu_tex.width = def.width;
- gpu_tex.height = def.height;
-
+ gpu_tex.width = width;
+ gpu_tex.height = height;
+
textures_[name] = gpu_tex;
-
-#if !defined(STRIP_ALL)
- std::cout << "Generated procedural texture: " << name << " (" << def.width
- << "x" << def.height << ")" << std::endl;
-#endif
}
WGPUTextureView TextureManager::get_texture_view(const std::string& name) {
diff --git a/src/gpu/texture_manager.h b/src/gpu/texture_manager.h
index 3faf74c..54dcfeb 100644
--- a/src/gpu/texture_manager.h
+++ b/src/gpu/texture_manager.h
@@ -37,6 +37,9 @@ 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);
// Retrieves a texture view by name (returns nullptr if not found)
WGPUTextureView get_texture_view(const std::string& name);