summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3d/renderer.cc52
-rw-r--r--src/3d/renderer.h23
-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
-rw-r--r--src/tests/test_assets.cc16
-rw-r--r--src/tests/test_sequence.cc4
-rw-r--r--src/util/asset_manager.cc68
-rw-r--r--src/util/asset_manager.h18
13 files changed, 166 insertions, 151 deletions
diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc
index 0a2ae9a..db9d73d 100644
--- a/src/3d/renderer.cc
+++ b/src/3d/renderer.cc
@@ -3,8 +3,8 @@
#include "3d/renderer.h"
#include <algorithm>
-#include <cstring>
#include <cassert>
+#include <cstring>
#include <iostream>
static const char* kShaderCode = R"(
@@ -429,17 +429,14 @@ void Renderer3D::update_uniforms(const Scene& scene, const Camera& camera,
}
}
-void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene, const Camera& camera, float time) {
-
+void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene,
+ const Camera& camera, float time) {
update_uniforms(scene, camera, time);
-
-
// Lazy Bind Group creation
- if (bind_group_) wgpuBindGroupRelease(bind_group_);
-
-
+ if (bind_group_)
+ wgpuBindGroupRelease(bind_group_);
WGPUBindGroupEntry bg_entries[4] = {};
@@ -463,8 +460,6 @@ void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene, const Came
bg_entries[3].sampler = default_sampler_;
-
-
WGPUBindGroupDescriptor bg_desc = {};
bg_desc.layout = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0);
@@ -477,35 +472,26 @@ void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene, const Came
wgpuBindGroupLayoutRelease(bg_desc.layout);
-
-
wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr);
-
-
- uint32_t instance_count = (uint32_t)std::min((size_t)kMaxObjects, scene.objects.size());
+ uint32_t instance_count =
+ (uint32_t)std::min((size_t)kMaxObjects, scene.objects.size());
if (instance_count > 0) {
-
wgpuRenderPassEncoderDraw(pass, 36, instance_count, 0, 0);
-
}
-
}
-
-
void Renderer3D::render(const Scene& scene, const Camera& camera, float time,
- WGPUTextureView target_view, WGPUTextureView depth_view_opt) {
-
+ WGPUTextureView target_view,
+ WGPUTextureView depth_view_opt) {
WGPUTextureView depth_view = depth_view_opt ? depth_view_opt : depth_view_;
- if (!depth_view) return;
-
-
+ if (!depth_view)
+ return;
WGPURenderPassColorAttachment color_attachment = {};
@@ -513,8 +499,6 @@ void Renderer3D::render(const Scene& scene, const Camera& camera, float time,
color_attachment.clearValue = {0.05, 0.05, 0.1, 1.0};
-
-
WGPURenderPassDepthStencilAttachment depth_attachment = {};
depth_attachment.view = depth_view;
@@ -525,8 +509,6 @@ void Renderer3D::render(const Scene& scene, const Camera& camera, float time,
depth_attachment.depthClearValue = 1.0f;
-
-
WGPURenderPassDescriptor pass_desc = {};
pass_desc.colorAttachmentCount = 1;
@@ -535,30 +517,22 @@ void Renderer3D::render(const Scene& scene, const Camera& camera, float time,
pass_desc.depthStencilAttachment = &depth_attachment;
-
-
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device_, nullptr);
- WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc);
-
-
+ WGPURenderPassEncoder pass =
+ wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc);
draw(pass, scene, camera, time);
-
-
wgpuRenderPassEncoderEnd(pass);
WGPUCommandBuffer commands = wgpuCommandEncoderFinish(encoder, nullptr);
wgpuQueueSubmit(queue_, 1, &commands);
-
-
wgpuRenderPassEncoderRelease(pass);
wgpuCommandBufferRelease(commands);
wgpuCommandEncoderRelease(encoder);
-
} \ No newline at end of file
diff --git a/src/3d/renderer.h b/src/3d/renderer.h
index e87d47a..8cb379b 100644
--- a/src/3d/renderer.h
+++ b/src/3d/renderer.h
@@ -28,25 +28,24 @@ class Renderer3D {
void init(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format);
void shutdown();
- // Renders the scene to the given texture view (Convenience: creates a pass)
+ // Renders the scene to the given texture view (Convenience: creates a pass)
- void render(const Scene& scene, const Camera& camera, float time,
+ void render(const Scene& scene, const Camera& camera, float time,
- WGPUTextureView target_view, WGPUTextureView depth_view_opt = nullptr);
+ WGPUTextureView target_view,
+ WGPUTextureView depth_view_opt = nullptr);
-
+ // Records draw commands to an existing pass.
- // Records draw commands to an existing pass.
+ // Assumes the pass has a compatible pipeline (or we set it here).
- // Assumes the pass has a compatible pipeline (or we set it here).
+ // Note: Caller must ensure depth/color attachments are set up correctly in
+ // the pass.
- // Note: Caller must ensure depth/color attachments are set up correctly in the pass.
+ void draw(WGPURenderPassEncoder pass, const Scene& scene,
+ const Camera& camera, float time);
- void draw(WGPURenderPassEncoder pass, const Scene& scene, const Camera& camera, float time);
-
-
-
- void set_noise_texture(WGPUTextureView noise_view);
+ void set_noise_texture(WGPUTextureView noise_view);
// Resize handler (if needed for internal buffers)
void resize(int width, int height);
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);
diff --git a/src/tests/test_assets.cc b/src/tests/test_assets.cc
index dd77b73..c7d41e5 100644
--- a/src/tests/test_assets.cc
+++ b/src/tests/test_assets.cc
@@ -51,11 +51,13 @@ int main() {
// Test procedural asset
printf("\nRunning Procedural Asset test...\n");
size_t proc_size = 0;
- const uint8_t* proc_data_1 = GetAsset(AssetId::ASSET_PROC_NOISE_256, &proc_size);
+ const uint8_t* proc_data_1 =
+ GetAsset(AssetId::ASSET_PROC_NOISE_256, &proc_size);
assert(proc_data_1 != nullptr);
assert(proc_size == 256 * 256 * 4); // 256x256 RGBA8
-
- // Verify first few bytes are not all zero (noise should produce non-zero data)
+
+ // Verify first few bytes are not all zero (noise should produce non-zero
+ // data)
bool non_zero_data = false;
for (size_t i = 0; i < 16; ++i) { // Check first 16 bytes
if (proc_data_1[i] != 0) {
@@ -69,10 +71,12 @@ int main() {
// Test DropAsset for procedural asset and re-generation
DropAsset(AssetId::ASSET_PROC_NOISE_256, proc_data_1);
// After dropping, GetAsset should generate new data
- const uint8_t* proc_data_2 = GetAsset(AssetId::ASSET_PROC_NOISE_256, &proc_size);
+ const uint8_t* proc_data_2 =
+ GetAsset(AssetId::ASSET_PROC_NOISE_256, &proc_size);
assert(proc_data_2 != nullptr);
- // assert(proc_data_1 != proc_data_2); // Removed: Allocator might reuse the same address
-
+ // assert(proc_data_1 != proc_data_2); // Removed: Allocator might reuse the
+ // same address
+
// Verify content again to ensure it was re-generated correctly
non_zero_data = false;
for (size_t i = 0; i < 16; ++i) {
diff --git a/src/tests/test_sequence.cc b/src/tests/test_sequence.cc
index a48c733..788e0b1 100644
--- a/src/tests/test_sequence.cc
+++ b/src/tests/test_sequence.cc
@@ -99,7 +99,7 @@ class DummyPostProcessEffect : public PostProcessEffect {
void test_effect_lifecycle() {
printf(" test_effect_lifecycle...\n");
MainSequence main_seq;
- main_seq.init(dummy_device, dummy_queue, dummy_format, 320, 200);
+ main_seq.init_test(dummy_device, dummy_queue, dummy_format);
auto effect1 = std::make_shared<DummyEffect>(dummy_device, dummy_queue);
auto seq1 = std::make_shared<Sequence>();
@@ -145,7 +145,7 @@ void test_simulate_until() {
#if !defined(STRIP_ALL)
printf(" test_simulate_until...\n");
MainSequence main_seq;
- main_seq.init(dummy_device, dummy_queue, dummy_format, 320, 240);
+ main_seq.init_test(dummy_device, dummy_queue, dummy_format);
auto effect1 = std::make_shared<DummyEffect>(dummy_device, dummy_queue);
auto seq1 = std::make_shared<Sequence>();
diff --git a/src/util/asset_manager.cc b/src/util/asset_manager.cc
index 2ad8ef9..845934b 100644
--- a/src/util/asset_manager.cc
+++ b/src/util/asset_manager.cc
@@ -8,12 +8,12 @@
#include "generated/assets.h"
#endif /* defined(USE_TEST_ASSETS) */
-#include <vector> // For potential dynamic allocation for procedural assets
-#include <new> // For placement new
-#include <cstdlib> // For free
-#include <iostream> // For std::cerr
-#include <map> // For kAssetManagerProcGenFuncMap
-#include <string> // For std::string in map
+#include <cstdlib> // For free
+#include <iostream> // For std::cerr
+#include <map> // For kAssetManagerProcGenFuncMap
+#include <new> // For placement new
+#include <string> // For std::string in map
+#include <vector> // For potential dynamic allocation for procedural assets
#include "procedural/generator.h" // For ProcGenFunc and procedural functions
@@ -41,17 +41,17 @@ const uint8_t* GetAsset(AssetId asset_id, size_t* out_size) {
uint16_t index = (uint16_t)asset_id;
// Assert that ASSET_LAST_ID is not used for retrieval.
- // This ensures the size of the cache is correctly used and not accessed out of bounds.
- // If this assert fails, it means assets.txt has an ID larger than expected
- // or ASSET_LAST_ID is not correctly generated/updated.
- // This is a design decision: ASSET_LAST_ID is purely for sizing and range checking,
- // not for a valid asset retrieval itself.
+ // This ensures the size of the cache is correctly used and not accessed out
+ // of bounds. If this assert fails, it means assets.txt has an ID larger than
+ // expected or ASSET_LAST_ID is not correctly generated/updated. This is a
+ // design decision: ASSET_LAST_ID is purely for sizing and range checking, not
+ // for a valid asset retrieval itself.
if (index >= (uint16_t)AssetId::ASSET_LAST_ID) {
if (out_size)
*out_size = 0;
return nullptr; // Invalid asset_id
}
-
+
// Check cache first
if (g_asset_cache[index].data != nullptr) {
if (out_size)
@@ -59,7 +59,8 @@ const uint8_t* GetAsset(AssetId asset_id, size_t* out_size) {
return g_asset_cache[index].data;
}
- // Not in cache, retrieve from static data (packed in binary) or generate procedurally
+ // Not in cache, retrieve from static data (packed in binary) or generate
+ // procedurally
if (index >= g_assets_count) {
if (out_size)
*out_size = 0;
@@ -71,36 +72,44 @@ const uint8_t* GetAsset(AssetId asset_id, size_t* out_size) {
if (source_record.is_procedural) {
// Dynamically generate the asset
- auto it = kAssetManagerProcGenFuncMap.find(source_record.proc_func_name_str);
+ auto it =
+ kAssetManagerProcGenFuncMap.find(source_record.proc_func_name_str);
if (it == kAssetManagerProcGenFuncMap.end()) {
- std::cerr << "Error: Unknown procedural function at runtime: " << source_record.proc_func_name_str << std::endl;
- if (out_size) *out_size = 0;
- return nullptr; // Procedural asset without a generation function.
+ std::cerr << "Error: Unknown procedural function at runtime: "
+ << source_record.proc_func_name_str << std::endl;
+ if (out_size)
+ *out_size = 0;
+ return nullptr; // Procedural asset without a generation function.
}
ProcGenFunc proc_gen_func_ptr = it->second;
- // For this demo, assuming procedural textures are RGBA8 256x256 (for simplicity and bump mapping).
- // A more generic solution would pass dimensions in proc_params.
+ // For this demo, assuming procedural textures are RGBA8 256x256 (for
+ // simplicity and bump mapping). A more generic solution would pass
+ // dimensions in proc_params.
int width = 256, height = 256;
size_t data_size = width * height * 4; // RGBA8
uint8_t* generated_data = new (std::nothrow) uint8_t[data_size];
if (!generated_data) {
- std::cerr << "Error: Failed to allocate memory for procedural asset." << std::endl;
- if (out_size) *out_size = 0;
- return nullptr;
+ std::cerr << "Error: Failed to allocate memory for procedural asset."
+ << std::endl;
+ if (out_size)
+ *out_size = 0;
+ return nullptr;
}
- proc_gen_func_ptr(generated_data, width, height, source_record.proc_params, source_record.num_proc_params);
-
+ proc_gen_func_ptr(generated_data, width, height, source_record.proc_params,
+ source_record.num_proc_params);
+
cached_record.data = generated_data;
cached_record.size = data_size;
cached_record.is_procedural = true;
- // proc_gen_func, proc_params, num_proc_params already copied from source_record
+ // proc_gen_func, proc_params, num_proc_params already copied from
+ // source_record
} else {
// Static asset (copy from g_assets)
cached_record.is_procedural = false;
}
-
+
// Store in cache for future use
g_asset_cache[index] = cached_record;
@@ -115,9 +124,10 @@ void DropAsset(AssetId asset_id, const uint8_t* asset) {
return; // Invalid asset_id
}
- // Check if the asset is in cache and is procedural, and if the pointer matches.
- // This prevents accidentally freeing static data or freeing twice.
- if (g_asset_cache[index].data == asset && g_asset_cache[index].is_procedural) {
+ // Check if the asset is in cache and is procedural, and if the pointer
+ // matches. This prevents accidentally freeing static data or freeing twice.
+ if (g_asset_cache[index].data == asset &&
+ g_asset_cache[index].is_procedural) {
delete[] g_asset_cache[index].data;
g_asset_cache[index] = {}; // Zero out the struct to force re-generation
}
diff --git a/src/util/asset_manager.h b/src/util/asset_manager.h
index 00aafc0..b9cd778 100644
--- a/src/util/asset_manager.h
+++ b/src/util/asset_manager.h
@@ -8,16 +8,20 @@
enum class AssetId : uint16_t; // Forward declaration
-// Type for procedural generation functions: (buffer, width, height, params, num_params)
+// Type for procedural generation functions: (buffer, width, height, params,
+// num_params)
typedef void (*ProcGenFunc)(uint8_t*, int, int, const float*, int);
struct AssetRecord {
- const uint8_t* data; // Pointer to asset data (static or dynamic)
- size_t size; // Size of the asset data
- bool is_procedural; // True if data was dynamically allocated by a procedural generator
- const char* proc_func_name_str; // Name of procedural generation function (string literal)
- const float* proc_params; // Parameters for procedural generation (static, from assets.txt)
- int num_proc_params; // Number of procedural parameters
+ const uint8_t* data; // Pointer to asset data (static or dynamic)
+ size_t size; // Size of the asset data
+ bool is_procedural; // True if data was dynamically allocated by a procedural
+ // generator
+ const char* proc_func_name_str; // Name of procedural generation function
+ // (string literal)
+ const float* proc_params; // Parameters for procedural generation (static,
+ // from assets.txt)
+ int num_proc_params; // Number of procedural parameters
};
// Generic interface