summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-03 18:44:41 +0100
committerskal <pascal.massimino@gmail.com>2026-02-03 18:44:41 +0100
commitbf46e44e1cb6027a072819a2a3aa3be32651f6e1 (patch)
tree21267e7ef52fd91e7b99271ed87e275e91b3de3c /src
parent815c428dea14a6a1ea5c421c400985d0c14d473d (diff)
refactor: Task #20 - Platform & Code Hygiene
- Consolidated all WebGPU shims and platform-specific logic into src/platform.h. - Refactored platform_init to return PlatformState by value and platform_poll to automatically refresh time and aspect_ratio. - Removed STL dependencies (std::map, std::vector, std::string) from AssetManager and Procedural subsystems. - Fixed Windows cross-compilation by adjusting include paths and linker flags in CMakeLists.txt and updating build_win.sh. - Removed redundant direct inclusions of GLFW/glfw3.h and WebGPU headers across the project. - Applied clang-format and updated documentation. handoff(Gemini): Completed Task #20 and 20.1. Platform abstraction is now unified, and core paths are STL-free. Windows build is stable.
Diffstat (limited to 'src')
-rw-r--r--src/audio/tracker.cc13
-rw-r--r--src/gpu/effect.h6
-rw-r--r--src/gpu/effects/post_process_helper.h1
-rw-r--r--src/gpu/effects/shaders.cc36
-rw-r--r--src/gpu/gpu.cc37
-rw-r--r--src/gpu/gpu.h77
-rw-r--r--src/gpu/texture_manager.h6
-rw-r--r--src/main.cc55
-rw-r--r--src/platform.cc67
-rw-r--r--src/platform.h106
-rw-r--r--src/procedural/generator.cc19
-rw-r--r--src/procedural/generator.h1
-rw-r--r--src/tests/test_3d_render.cc45
-rw-r--r--src/tests/test_shader_assets.cc111
-rw-r--r--src/tests/test_shader_composer.cc46
-rw-r--r--src/tests/test_texture_manager.cc34
-rw-r--r--src/tests/test_tracker.cc21
-rw-r--r--src/util/asset_manager.cc45
18 files changed, 341 insertions, 385 deletions
diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc
index 470123a..8f3da38 100644
--- a/src/audio/tracker.cc
+++ b/src/audio/tracker.cc
@@ -69,8 +69,10 @@ void tracker_update(float time_sec) {
if (data && size >= sizeof(SpecHeader)) {
const SpecHeader* header = (const SpecHeader*)data;
note_frames = header->num_frames;
- const float* src_spectral_data = (const float*)(data + sizeof(SpecHeader));
- note_data.assign(src_spectral_data, src_spectral_data + (size_t)note_frames * DCT_SIZE);
+ const float* src_spectral_data =
+ (const float*)(data + sizeof(SpecHeader));
+ note_data.assign(src_spectral_data,
+ src_spectral_data + (size_t)note_frames * DCT_SIZE);
}
} else {
const NoteParams& params = g_tracker_samples[event.sample_id];
@@ -78,9 +80,10 @@ void tracker_update(float time_sec) {
}
if (note_frames > 0) {
- int frame_offset = (int)(event.beat * beat_to_sec * 32000.0f / DCT_SIZE);
- paste_spectrogram(pattern_data, &dest_num_frames, note_data, note_frames,
- frame_offset);
+ int frame_offset =
+ (int)(event.beat * beat_to_sec * 32000.0f / DCT_SIZE);
+ paste_spectrogram(pattern_data, &dest_num_frames, note_data,
+ note_frames, frame_offset);
}
}
diff --git a/src/gpu/effect.h b/src/gpu/effect.h
index 7e5e2ce..77504bd 100644
--- a/src/gpu/effect.h
+++ b/src/gpu/effect.h
@@ -4,12 +4,6 @@
#include <memory>
#include <vector>
-#if defined(DEMO_CROSS_COMPILE_WIN32)
-#include <webgpu/webgpu.h>
-#else
-#include <webgpu.h>
-#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */
-
class MainSequence;
class PostProcessEffect;
diff --git a/src/gpu/effects/post_process_helper.h b/src/gpu/effects/post_process_helper.h
index d3a37bd..1986ff3 100644
--- a/src/gpu/effects/post_process_helper.h
+++ b/src/gpu/effects/post_process_helper.h
@@ -4,7 +4,6 @@
#pragma once
#include "gpu/gpu.h"
-#include <webgpu.h>
// Helper to create a standard post-processing pipeline
WGPURenderPipeline create_post_process_pipeline(WGPUDevice device,
diff --git a/src/gpu/effects/shaders.cc b/src/gpu/effects/shaders.cc
index cd516cd..b2d184d 100644
--- a/src/gpu/effects/shaders.cc
+++ b/src/gpu/effects/shaders.cc
@@ -3,8 +3,6 @@
#include "../demo_effects.h"
-
-
#if defined(USE_TEST_ASSETS)
#include "test_assets.h"
@@ -15,36 +13,23 @@
#endif
-
-
#include "gpu/effects/shader_composer.h"
#include "util/asset_manager.h"
-
-
void InitShaderComposer() {
-
auto& sc = ShaderComposer::Get();
-
-
auto register_if_exists = [&](const char* name, AssetId id) {
+ size_t size;
- size_t size;
-
- const char* data = (const char*)GetAsset(id, &size);
-
- if (data) {
-
- sc.RegisterSnippet(name, std::string(data, size));
-
- }
+ const char* data = (const char*)GetAsset(id, &size);
+ if (data) {
+ sc.RegisterSnippet(name, std::string(data, size));
+ }
};
-
-
register_if_exists("common_uniforms", AssetId::ASSET_SHADER_COMMON_UNIFORMS);
register_if_exists("sdf_primitives", AssetId::ASSET_SHADER_SDF_PRIMITIVES);
@@ -52,23 +37,16 @@ void InitShaderComposer() {
register_if_exists("lighting", AssetId::ASSET_SHADER_LIGHTING);
register_if_exists("ray_box", AssetId::ASSET_SHADER_RAY_BOX);
-
}
-
-
// Helper to get asset string or empty string
static const char* SafeGetAsset(AssetId id) {
+ const uint8_t* data = GetAsset(id);
- const uint8_t* data = GetAsset(id);
-
- return data ? (const char*)data : "";
-
+ return data ? (const char*)data : "";
}
-
-
const char* main_shader_wgsl = SafeGetAsset(AssetId::ASSET_SHADER_MAIN);
const char* particle_compute_wgsl =
diff --git a/src/gpu/gpu.cc b/src/gpu/gpu.cc
index 8342c94..1f71711 100644
--- a/src/gpu/gpu.cc
+++ b/src/gpu/gpu.cc
@@ -5,15 +5,13 @@
#include "gpu.h"
#include "demo_effects.h"
#include "effect.h"
-#include "platform.h"
#include "gpu/effects/shaders.h"
+#include "platform.h"
-#include <GLFW/glfw3.h>
-#include <math.h>
-
-#include <algorithm>
#include <cassert>
+#include <cmath>
#include <cstdint>
+#include <cstdio>
#include <cstring>
#include <vector>
@@ -21,29 +19,6 @@
#include <iostream>
#endif /* !defined(STRIP_ALL) */
-// --- WebGPU Headers & Compatibility ---
-#if defined(DEMO_CROSS_COMPILE_WIN32)
-// Renamed Types/Enums
-#define WGPUOptionalBool_False false
-#define WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal \
- WGPUSurfaceGetCurrentTextureStatus_Success
-#define WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal \
- WGPUSurfaceGetCurrentTextureStatus_Success
-#define WGPUCallbackMode_WaitAnyOnly 0
-static void wgpuInstanceWaitAny(WGPUInstance instance, size_t, void*,
- uint64_t) {
- wgpuInstanceProcessEvents(instance);
-}
-static void set_error_callback(WGPUDevice device, WGPUErrorCallback callback) {
- wgpuDeviceSetUncapturedErrorCallback(device, callback, nullptr);
-}
-#else
-static void set_error_callback(WGPUDevice device,
- WGPUUncapturedErrorCallback callback) {
- // Handled in descriptor for new API.
-}
-#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */
-
static WGPUInstance g_instance = nullptr;
static WGPUAdapter g_adapter = nullptr;
static WGPUDevice g_device = nullptr;
@@ -331,7 +306,7 @@ void gpu_init(PlatformState* platform_state) {
wgpuInstanceRequestAdapter(g_instance, &adapter_opts, adapter_cb);
#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */
while (!g_adapter)
- wgpuInstanceWaitAny(g_instance, 0, nullptr, 0);
+ platform_wgpu_wait_any(g_instance);
WGPUDeviceDescriptor device_desc = {};
#if !defined(STRIP_ALL)
@@ -351,10 +326,10 @@ void gpu_init(PlatformState* platform_state) {
wgpuAdapterRequestDevice(g_adapter, &device_desc, device_cb);
#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */
while (!g_device)
- wgpuInstanceWaitAny(g_instance, 0, nullptr, 0);
+ platform_wgpu_wait_any(g_instance);
#if defined(DEMO_CROSS_COMPILE_WIN32) && !defined(STRIP_ALL)
- set_error_callback(g_device, handle_device_error);
+ platform_wgpu_set_error_callback(g_device, handle_device_error);
#endif /* defined(DEMO_CROSS_COMPILE_WIN32) && !defined(STRIP_ALL) */
g_queue = wgpuDeviceGetQueue(g_device);
diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h
index 45c6413..40274b9 100644
--- a/src/gpu/gpu.h
+++ b/src/gpu/gpu.h
@@ -4,74 +4,7 @@
#pragma once
-#include <webgpu.h>
-
-#include <cstring> // For strlen
-
-#if defined(DEMO_CROSS_COMPILE_WIN32)
-
-// Windows (MinGW) using wgpu-native v0.19.4.1
-#define WGPUOptionalBool_True true
-#define WGPUOptionalBool_False false
-
-#include <webgpu/webgpu.h>
-
-#include <webgpu/wgpu.h>
-
-static inline const char* str_view(const char* str) {
- return str;
-}
-
-static inline const char* label_view(const char* str) {
- return str;
-}
-
-#define WGPUSType_ShaderSourceWGSL WGPUSType_ShaderModuleWGSLDescriptor
-
-using WGPUShaderSourceWGSL = WGPUShaderModuleWGSLDescriptor;
-
-#define WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal \
- WGPUSurfaceGetCurrentTextureStatus_Success
-
-#define WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal \
- WGPUSurfaceGetCurrentTextureStatus_Success
-
-#define WGPUCallbackMode_WaitAnyOnly 0
-
-#else
-
-// Native (macOS/Linux) using newer wgpu-native
-
-#include <webgpu.h>
-
-#include <wgpu.h>
-
-static inline WGPUStringView str_view(const char* str) {
- if (!str)
- return {nullptr, 0};
-
- return {str, strlen(str)};
-}
-
-static inline WGPUStringView label_view(const char* str) {
-
-#if !defined(STRIP_ALL)
-
- if (!str)
- return {nullptr, 0};
-
- return {str, strlen(str)};
-
-#else
-
- (void)str;
-
- return {nullptr, 0};
-
-#endif /* !defined(STRIP_ALL) */
-}
-
-#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */
+#include "platform.h"
struct PlatformState; // Forward declaration
@@ -123,7 +56,11 @@ inline void gpu_init_color_attachment(WGPURenderPassColorAttachment& attachment,
attachment.view = view;
attachment.loadOp = WGPULoadOp_Clear;
attachment.storeOp = WGPUStoreOp_Store;
-#if !defined(DEMO_CROSS_COMPILE_WIN32)
+ attachment.clearValue = {0.0f, 0.0f, 0.0f, 1.0f};
+#if defined(DEMO_CROSS_COMPILE_WIN32)
+ // depthSlice is handled via macro in platform.h if needed,
+ // but usually it's better to just avoid setting it on older wgpu-native
+#else
attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
#endif
}
@@ -137,4 +74,4 @@ RenderPass
gpu_create_render_pass(WGPUDevice device,
WGPUTextureFormat format, // Needed for render pipeline
const char* shader_code, ResourceBinding* bindings,
- int num_bindings);
+ int num_bindings); \ No newline at end of file
diff --git a/src/gpu/texture_manager.h b/src/gpu/texture_manager.h
index b97e6a8..f49e827 100644
--- a/src/gpu/texture_manager.h
+++ b/src/gpu/texture_manager.h
@@ -9,12 +9,6 @@
#include <string>
#include <vector>
-#if defined(DEMO_CROSS_COMPILE_WIN32)
-#include <webgpu/webgpu.h>
-#else
-#include <webgpu.h>
-#endif
-
struct ProceduralTextureDef {
int width;
int height;
diff --git a/src/main.cc b/src/main.cc
index 76e366a..aba8d4b 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -11,11 +11,10 @@
#include "gpu/gpu.h"
#include "platform.h"
#include "util/math.h"
-#include <GLFW/glfw3.h>
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
-#include <vector>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#define SPEC_FRAMES 16
@@ -47,12 +46,11 @@ float* generate_tone(float* buffer, float freq) {
}
int main(int argc, char** argv) {
- PlatformState platform_state = {};
+ PlatformState platform_state;
bool fullscreen_enabled = false;
float seek_time = 0.0f;
- int* width_ptr = nullptr;
- int* height_ptr = nullptr;
- int custom_width, custom_height;
+ int width = 1280;
+ int height = 720;
#if !defined(STRIP_ALL)
for (int i = 1; i < argc; ++i) {
@@ -63,9 +61,10 @@ int main(int argc, char** argv) {
++i;
} else if (strcmp(argv[i], "--resolution") == 0 && i + 1 < argc) {
const char* res_str = argv[++i];
- if (sscanf(res_str, "%dx%d", &custom_width, &custom_height) == 2) {
- width_ptr = &custom_width;
- height_ptr = &custom_height;
+ int w, h;
+ if (sscanf(res_str, "%dx%d", &w, &h) == 2) {
+ width = w;
+ height = h;
}
} else if (strcmp(argv[i], "--debug") == 0) {
Renderer3D::SetDebugEnabled(true);
@@ -77,7 +76,7 @@ int main(int argc, char** argv) {
fullscreen_enabled = true;
#endif /* STRIP_ALL */
- platform_init(&platform_state, fullscreen_enabled, width_ptr, height_ptr);
+ platform_state = platform_init(fullscreen_enabled, width, height);
gpu_init(&platform_state);
audio_init();
synth_init();
@@ -98,22 +97,22 @@ int main(int argc, char** argv) {
auto update_game_logic = [&](double t) {
if (t - last_beat_time > (60.0f / g_tracker_score.bpm) / 2.0) { // 8th notes
- last_beat_time = t; // Sync to t
+ last_beat_time = t; // Sync to t
const int step = beat_count % 16;
-/*
- // Bass pattern
- if (step % 4 == 0) {
- float* back_buffer = synth_begin_update(bass_id);
- if (back_buffer) {
- float bass_freq = (step < 8) ? 110.0f : 164.82f; // A3 then E3
- generate_tone(back_buffer, bass_freq);
- synth_commit_update(bass_id);
- }
- synth_trigger_voice(bass_id, 0.9f, 1.2f);
- }
-*/
+ /*
+ // Bass pattern
+ if (step % 4 == 0) {
+ float* back_buffer = synth_begin_update(bass_id);
+ if (back_buffer) {
+ float bass_freq = (step < 8) ? 110.0f : 164.82f; // A3 then E3
+ generate_tone(back_buffer, bass_freq);
+ synth_commit_update(bass_id);
+ }
+ synth_trigger_voice(bass_id, 0.9f, 1.2f);
+ }
+ */
++beat_count;
}
tracker_update((float)t);
@@ -152,11 +151,11 @@ int main(int argc, char** argv) {
gpu_resize(last_width, last_height);
}
- double current_time = platform_get_time() + seek_time; // Offset logic time
+ double current_time = platform_state.time + seek_time; // Offset logic time
update_game_logic(current_time);
- float aspect_ratio = platform_get_aspect_ratio(&platform_state);
+ float aspect_ratio = platform_state.aspect_ratio;
// Adjusted multiplier for visuals (preventing constant 1.0 saturation)
float raw_peak = synth_get_output_peak();
diff --git a/src/platform.cc b/src/platform.cc
index 5d5c082..fbd1d51 100644
--- a/src/platform.cc
+++ b/src/platform.cc
@@ -14,6 +14,9 @@ static void framebuffer_size_callback(GLFWwindow* window, int width,
if (state) {
state->width = width;
state->height = height;
+ if (height > 0) {
+ state->aspect_ratio = (float)width / (float)height;
+ }
}
}
@@ -32,37 +35,49 @@ static void glfw_key_callback(GLFWwindow* window, int key, int scancode,
// --- Public API Implementation ---
-void platform_init(PlatformState* state, bool fullscreen, int* width_ptr,
- int* height_ptr) {
- if (width_ptr && height_ptr) {
- state->width = *width_ptr;
- state->height = *height_ptr;
- }
+PlatformState platform_init(bool fullscreen, int width, int height) {
+ PlatformState state = {};
+ state.width = width;
+ state.height = height;
+ state.is_fullscreen = fullscreen;
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- state->window = glfwCreateWindow(state->width, state->height, "demo64k",
- nullptr, nullptr);
-
- // Store our state pointer in the window for callbacks
- glfwSetWindowUserPointer(state->window, state);
+ state.window =
+ glfwCreateWindow(state.width, state.height, "demo64k", nullptr, nullptr);
// Immediately query the actual framebuffer size for high-DPI displays
- glfwGetFramebufferSize(state->window, &state->width, &state->height);
+ glfwGetFramebufferSize(state.window, &state.width, &state.height);
+ if (state.height > 0) {
+ state.aspect_ratio = (float)state.width / (float)state.height;
+ }
- glfwSetKeyCallback(state->window, glfw_key_callback);
- glfwSetFramebufferSizeCallback(state->window, framebuffer_size_callback);
+ // Store our state in a static pointer or use the window pointer?
+ // We'll use a pointer to a persistent state.
+ // For this demo, we can assume the PlatformState persists in main().
+ // But we return by value. This is a bit tricky with callbacks.
+ // We'll fix the callbacks in platform_poll if needed, or just let main pass
+ // the pointer back.
+
+ glfwSetWindowUserPointer(state.window,
+ nullptr); // Will be set in main's state
+
+ glfwSetKeyCallback(state.window, glfw_key_callback);
+ glfwSetFramebufferSizeCallback(state.window, framebuffer_size_callback);
- state->is_fullscreen = fullscreen;
if (fullscreen) {
- glfwGetWindowPos(state->window, &state->windowed_x, &state->windowed_y);
- glfwGetWindowSize(state->window, &state->windowed_w, &state->windowed_h);
+ glfwGetWindowPos(state.window, &state.windowed_x, &state.windowed_y);
+ glfwGetWindowSize(state.window, &state.windowed_w, &state.windowed_h);
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
- glfwSetWindowMonitor(state->window, monitor, 0, 0, mode->width,
- mode->height, mode->refreshRate);
+ glfwSetWindowMonitor(state.window, monitor, 0, 0, mode->width, mode->height,
+ mode->refreshRate);
}
+
+ state.time = glfwGetTime();
+
+ return state;
}
void platform_shutdown(PlatformState* state) {
@@ -73,7 +88,16 @@ void platform_shutdown(PlatformState* state) {
}
void platform_poll(PlatformState* state) {
+ // Ensure the window has the current state pointer for callbacks
+ if (glfwGetWindowUserPointer(state->window) != state) {
+ glfwSetWindowUserPointer(state->window, state);
+ }
+
glfwPollEvents();
+ state->time = glfwGetTime();
+ if (state->height > 0) {
+ state->aspect_ratio = (float)state->width / (float)state->height;
+ }
}
bool platform_should_close(PlatformState* state) {
@@ -102,5 +126,6 @@ WGPUSurface platform_create_wgpu_surface(WGPUInstance instance,
return glfwCreateWindowWGPUSurface(instance, state->window);
}
-// Note: platform_get_* functions are now inline in the header.
-// platform_get_time() remains global.
+double platform_get_time() {
+ return glfwGetTime();
+} \ No newline at end of file
diff --git a/src/platform.h b/src/platform.h
index 152a38d..0a98850 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -1,7 +1,76 @@
// Handles windowing, input, and native surface creation.
+// Consolidates platform-specific shims for WebGPU.
#pragma once
+#include <cstdint>
+#include <cstring>
+
+// WebGPU specific headers and shims
+#if defined(DEMO_CROSS_COMPILE_WIN32)
+#include <webgpu/webgpu.h>
+#include <webgpu/wgpu.h>
+
+#define WGPUOptionalBool_True true
+#define WGPUOptionalBool_False false
+#define WGPUSType_ShaderSourceWGSL WGPUSType_ShaderModuleWGSLDescriptor
+#define WGPU_DEPTH_SLICE_UNDEFINED 0xffffffff
+#define WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal \
+ WGPUSurfaceGetCurrentTextureStatus_Success
+#define WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal \
+ WGPUSurfaceGetCurrentTextureStatus_Success
+#define WGPUCallbackMode_WaitAnyOnly 0
+
+typedef WGPUShaderModuleWGSLDescriptor WGPUShaderSourceWGSL;
+
+static inline const char* str_view(const char* str) {
+ return str;
+}
+static inline const char* label_view(const char* str) {
+ return str;
+}
+
+static inline void platform_wgpu_wait_any(WGPUInstance instance) {
+ wgpuInstanceProcessEvents(instance);
+}
+static inline void
+platform_wgpu_set_error_callback(WGPUDevice device,
+ WGPUErrorCallback callback) {
+ wgpuDeviceSetUncapturedErrorCallback(device, callback, nullptr);
+}
+
+#else
+#include <webgpu.h>
+#include <wgpu.h>
+
+static inline WGPUStringView str_view(const char* str) {
+ if (!str)
+ return {nullptr, 0};
+ return {str, strlen(str)};
+}
+
+static inline WGPUStringView label_view(const char* str) {
+#if !defined(STRIP_ALL)
+ if (!str)
+ return {nullptr, 0};
+ return {str, strlen(str)};
+#else
+ (void)str;
+ return {nullptr, 0};
+#endif
+}
+
+static inline void platform_wgpu_wait_any(WGPUInstance instance) {
+ wgpuInstanceWaitAny(instance, 0, nullptr, 0);
+}
+static inline void
+platform_wgpu_set_error_callback(WGPUDevice device,
+ WGPUUncapturedErrorCallback callback) {
+ // Handled in descriptor for new API, but provided for compatibility if needed
+ // elsewhere
+}
+#endif
+
// Forward declare GLFWwindow to avoid including the full header here.
struct GLFWwindow;
@@ -9,46 +78,23 @@ struct PlatformState {
GLFWwindow* window = nullptr;
int width = 1280;
int height = 720;
+ float aspect_ratio = 1.0f;
+ double time = 0.0;
bool is_fullscreen = false;
// Store windowed geometry for fullscreen toggle
int windowed_x = 0, windowed_y = 0, windowed_w = 0, windowed_h = 0;
};
-void platform_init(PlatformState* state, bool fullscreen, int* width_ptr,
- int* height_ptr);
+// Refactored platform API
+PlatformState platform_init(bool fullscreen, int width, int height);
void platform_shutdown(PlatformState* state);
void platform_poll(PlatformState* state);
bool platform_should_close(PlatformState* state);
void platform_toggle_fullscreen(PlatformState* state);
-// Inline getters for direct access
-inline GLFWwindow* platform_get_window(PlatformState* state) {
- return state->window;
-}
-inline int platform_get_width(PlatformState* state) {
- return state->width;
-}
-inline int platform_get_height(PlatformState* state) {
- return state->height;
-}
-inline float platform_get_aspect_ratio(PlatformState* state) {
- if (state->height == 0)
- return 1.0f;
- return (float)state->width / (float)state->height;
-}
-
-// glfwGetTime is a simple global query, so it doesn't need the state struct.
-// Include the header directly to get the proper linkage.
-#include <GLFW/glfw3.h>
-inline double platform_get_time() {
- return glfwGetTime();
-}
-
// WebGPU specific surface creation
-#if defined(DEMO_CROSS_COMPILE_WIN32)
-#include <webgpu/webgpu.h>
-#else
-#include <wgpu.h>
-#endif
WGPUSurface platform_create_wgpu_surface(WGPUInstance instance,
PlatformState* state);
+
+// Global time query (if needed without state)
+double platform_get_time(); \ No newline at end of file
diff --git a/src/procedural/generator.cc b/src/procedural/generator.cc
index 12dcb56..5ae83e4 100644
--- a/src/procedural/generator.cc
+++ b/src/procedural/generator.cc
@@ -8,8 +8,12 @@
namespace procedural {
// Smoothstep
-constexpr float smooth(float x) { return x * x * (3.f - 2.f * x); }
-constexpr float mix(float a, float b, float t) { return (a * (1.0f - t) + b * t); }
+constexpr float smooth(float x) {
+ return x * x * (3.f - 2.f * x);
+}
+constexpr float mix(float a, float b, float t) {
+ return (a * (1.0f - t) + b * t);
+}
// Simple smooth noise generator (Value Noise-ish)
// Params[0]: Seed
@@ -24,9 +28,13 @@ void gen_noise(uint8_t* buffer, int w, int h, const float* params,
// Create a small lattice of random values
const int lattice_w = (int)ceil(freq);
const int lattice_h = (int)ceil(freq);
- std::vector<float> lattice(lattice_w * lattice_h);
- for (float& v : lattice) {
- v = (float)rand() / RAND_MAX;
+ float* lattice =
+ (float*)malloc((size_t)lattice_w * lattice_h * sizeof(float));
+ if (!lattice)
+ return;
+
+ for (int i = 0; i < lattice_w * lattice_h; ++i) {
+ lattice[i] = (float)rand() / RAND_MAX;
}
const float scale_u = 1.f * (lattice_w - 1) / w;
const float scale_v = 1.f * (lattice_h - 1) / h;
@@ -59,6 +67,7 @@ void gen_noise(uint8_t* buffer, int w, int h, const float* params,
dst[4 * x + 3] = 255; // A
}
}
+ free(lattice);
}
// Simple grid generator
diff --git a/src/procedural/generator.h b/src/procedural/generator.h
index 8a9e757..72682b0 100644
--- a/src/procedural/generator.h
+++ b/src/procedural/generator.h
@@ -5,7 +5,6 @@
#pragma once
#include <cstdint>
-#include <vector>
// Procedural generation function signature
// buffer: Pointer to RGBA8 buffer (size w * h * 4)
diff --git a/src/tests/test_3d_render.cc b/src/tests/test_3d_render.cc
index cc7dce6..6e639cd 100644
--- a/src/tests/test_3d_render.cc
+++ b/src/tests/test_3d_render.cc
@@ -5,21 +5,15 @@
#include "3d/object.h"
#include "3d/renderer.h"
#include "3d/scene.h"
-#include "gpu/texture_manager.h"
#include "gpu/effects/shaders.h"
+#include "gpu/texture_manager.h"
#include "platform.h"
#include "procedural/generator.h"
#include <cmath>
+#include <cstdio>
#include <cstring>
-#include <iostream>
#include <vector>
-#if defined(DEMO_CROSS_COMPILE_WIN32)
-#include <webgpu/webgpu.h>
-#else
-#include <webgpu.h>
-#endif
-
// Global State
static Renderer3D g_renderer;
static TextureManager g_textures;
@@ -35,13 +29,13 @@ static WGPUTextureFormat g_format = WGPUTextureFormat_Undefined;
void init_wgpu(PlatformState* platform_state) {
WGPUInstance instance = wgpuCreateInstance(nullptr);
if (!instance) {
- std::cerr << "Failed to create WGPU instance." << std::endl;
+ fprintf(stderr, "Failed to create WGPU instance.\n");
exit(1);
}
g_surface = platform_create_wgpu_surface(instance, platform_state);
if (!g_surface) {
- std::cerr << "Failed to create WGPU surface." << std::endl;
+ fprintf(stderr, "Failed to create WGPU surface.\n");
exit(1);
}
@@ -60,6 +54,7 @@ void init_wgpu(PlatformState* platform_state) {
#else
auto on_adapter = [](WGPURequestAdapterStatus status, WGPUAdapter adapter,
WGPUStringView message, void* userdata, void* user2) {
+ (void)user2;
if (status == WGPURequestAdapterStatus_Success) {
*(WGPUAdapter*)userdata = adapter;
}
@@ -71,15 +66,8 @@ void init_wgpu(PlatformState* platform_state) {
wgpuInstanceRequestAdapter(instance, &adapter_opts, adapter_cb);
#endif
-#if !defined(DEMO_CROSS_COMPILE_WIN32)
while (!g_adapter) {
- wgpuInstanceProcessEvents(instance);
- }
-#endif
-
- if (!g_adapter) {
- std::cerr << "Failed to get adapter." << std::endl;
- exit(1);
+ platform_wgpu_wait_any(instance);
}
WGPUDeviceDescriptor device_desc = {};
@@ -95,6 +83,7 @@ void init_wgpu(PlatformState* platform_state) {
#else
auto on_device = [](WGPURequestDeviceStatus status, WGPUDevice device,
WGPUStringView message, void* userdata, void* user2) {
+ (void)user2;
if (status == WGPURequestDeviceStatus_Success) {
*(WGPUDevice*)userdata = device;
}
@@ -106,15 +95,8 @@ void init_wgpu(PlatformState* platform_state) {
wgpuAdapterRequestDevice(g_adapter, &device_desc, device_cb);
#endif
-#if !defined(DEMO_CROSS_COMPILE_WIN32)
while (!g_device) {
- wgpuInstanceProcessEvents(instance);
- }
-#endif
-
- if (!g_device) {
- std::cerr << "Failed to get device." << std::endl;
- exit(1);
+ platform_wgpu_wait_any(instance);
}
g_queue = wgpuDeviceGetQueue(g_device);
@@ -206,8 +188,7 @@ int main(int argc, char** argv) {
(void)argv;
#endif
- PlatformState platform_state = {};
- platform_init(&platform_state, false, nullptr, nullptr);
+ PlatformState platform_state = platform_init(false, 1280, 720);
// The test's own WGPU init sequence
init_wgpu(&platform_state);
@@ -222,7 +203,8 @@ int main(int argc, char** argv) {
noise_def.width = 256;
noise_def.height = 256;
noise_def.gen_func = gen_periodic_noise;
- noise_def.params = {1234.0f, 16.0f};
+ noise_def.params.push_back(1234.0f);
+ noise_def.params.push_back(16.0f);
g_textures.create_procedural_texture("noise", noise_def);
g_renderer.set_noise_texture(g_textures.get_texture_view("noise"));
@@ -232,17 +214,16 @@ int main(int argc, char** argv) {
g_camera.position = vec3(0, 5, 10);
g_camera.target = vec3(0, 0, 0);
- float time = 0.0f;
while (!platform_should_close(&platform_state)) {
platform_poll(&platform_state);
- time = (float)platform_get_time();
+ float time = (float)platform_state.time;
float cam_radius = 10.0f + std::sin(time * 0.3f) * 4.0f;
float cam_height = 5.0f + std::cos(time * 0.4f) * 3.0f;
g_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));
- g_camera.aspect_ratio = platform_get_aspect_ratio(&platform_state);
+ g_camera.aspect_ratio = platform_state.aspect_ratio;
for (size_t i = 1; i < g_scene.objects.size(); ++i) {
// Rotation around a random-ish 3D axis
diff --git a/src/tests/test_shader_assets.cc b/src/tests/test_shader_assets.cc
index 42d1c4c..f1562ea 100644
--- a/src/tests/test_shader_assets.cc
+++ b/src/tests/test_shader_assets.cc
@@ -8,59 +8,84 @@
#include <string>
#include <vector>
-bool validate_shader(AssetId id, const char* name, const std::vector<const char*>& expected_keywords) {
- printf("Validating shader: %s...\n", name);
- size_t size = 0;
- const char* data = (const char*)GetAsset(id, &size);
+bool validate_shader(AssetId id, const char* name,
+ const std::vector<const char*>& expected_keywords) {
+ printf("Validating shader: %s...\n", name);
+ size_t size = 0;
+ const char* data = (const char*)GetAsset(id, &size);
- if (data == nullptr || size == 0) {
- printf("FAILED: Shader %s is missing or empty!\n", name);
- return false;
- }
+ if (data == nullptr || size == 0) {
+ printf("FAILED: Shader %s is missing or empty!\n", name);
+ return false;
+ }
- std::string code(data, size);
- for (const char* keyword : expected_keywords) {
- if (code.find(keyword) == std::string::npos) {
- printf("FAILED: Shader %s missing expected keyword '%s'!\n", name, keyword);
- // printf("Code snippet:\n%.100s...\n", data);
- return false;
- }
+ std::string code(data, size);
+ for (const char* keyword : expected_keywords) {
+ if (code.find(keyword) == std::string::npos) {
+ printf("FAILED: Shader %s missing expected keyword '%s'!\n", name,
+ keyword);
+ // printf("Code snippet:\n%.100s...\n", data);
+ return false;
}
+ }
- printf("PASSED: %s (%zu bytes)\n", name, size);
- return true;
+ printf("PASSED: %s (%zu bytes)\n", name, size);
+ return true;
}
int main() {
- printf("--- RUNNING SHADER ASSET VALIDATION ---\n");
+ printf("--- RUNNING SHADER ASSET VALIDATION ---\n");
- bool all_passed = true;
+ bool all_passed = true;
- // Snippets
- all_passed &= validate_shader(AssetId::ASSET_SHADER_COMMON_UNIFORMS, "COMMON_UNIFORMS", {"struct", "GlobalUniforms"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_SDF_PRIMITIVES, "SDF_PRIMITIVES", {"fn", "sd"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_LIGHTING, "LIGHTING", {"fn", "calc"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_RAY_BOX, "RAY_BOX", {"fn", "intersect"});
+ // Snippets
+ all_passed &=
+ validate_shader(AssetId::ASSET_SHADER_COMMON_UNIFORMS, "COMMON_UNIFORMS",
+ {"struct", "GlobalUniforms"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_SDF_PRIMITIVES,
+ "SDF_PRIMITIVES", {"fn", "sd"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_LIGHTING, "LIGHTING",
+ {"fn", "calc"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_RAY_BOX, "RAY_BOX",
+ {"fn", "intersect"});
- // Full Shaders (Entry points)
- all_passed &= validate_shader(AssetId::ASSET_SHADER_RENDERER_3D, "RENDERER_3D", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_MAIN, "MAIN", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_PARTICLE_COMPUTE, "PARTICLE_COMPUTE", {"@compute", "main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_PARTICLE_RENDER, "PARTICLE_RENDER", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_PASSTHROUGH, "PASSTHROUGH", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_ELLIPSE, "ELLIPSE", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_PARTICLE_SPRAY_COMPUTE, "PARTICLE_SPRAY_COMPUTE", {"@compute", "main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_SOLARIZE, "SOLARIZE", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_DISTORT, "DISTORT", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_CHROMA_ABERRATION, "CHROMA_ABERRATION", {"@vertex", "vs_main", "@fragment", "fs_main"});
- all_passed &= validate_shader(AssetId::ASSET_SHADER_VISUAL_DEBUG, "VISUAL_DEBUG", {"@vertex", "vs_main", "@fragment", "fs_main"});
+ // Full Shaders (Entry points)
+ all_passed &=
+ validate_shader(AssetId::ASSET_SHADER_RENDERER_3D, "RENDERER_3D",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_MAIN, "MAIN",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_PARTICLE_COMPUTE,
+ "PARTICLE_COMPUTE", {"@compute", "main"});
+ all_passed &=
+ validate_shader(AssetId::ASSET_SHADER_PARTICLE_RENDER, "PARTICLE_RENDER",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &=
+ validate_shader(AssetId::ASSET_SHADER_PASSTHROUGH, "PASSTHROUGH",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_ELLIPSE, "ELLIPSE",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_PARTICLE_SPRAY_COMPUTE,
+ "PARTICLE_SPRAY_COMPUTE", {"@compute", "main"});
+ all_passed &=
+ validate_shader(AssetId::ASSET_SHADER_GAUSSIAN_BLUR, "GAUSSIAN_BLUR",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_SOLARIZE, "SOLARIZE",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_DISTORT, "DISTORT",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &= validate_shader(AssetId::ASSET_SHADER_CHROMA_ABERRATION,
+ "CHROMA_ABERRATION",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
+ all_passed &=
+ validate_shader(AssetId::ASSET_SHADER_VISUAL_DEBUG, "VISUAL_DEBUG",
+ {"@vertex", "vs_main", "@fragment", "fs_main"});
- if (!all_passed) {
- printf("--- SHADER ASSET VALIDATION FAILED ---\n");
- return 1;
- }
+ if (!all_passed) {
+ printf("--- SHADER ASSET VALIDATION FAILED ---\n");
+ return 1;
+ }
- printf("--- ALL SHADER ASSETS VALIDATED ---\n");
- return 0;
+ printf("--- ALL SHADER ASSETS VALIDATED ---\n");
+ return 0;
}
diff --git a/src/tests/test_shader_composer.cc b/src/tests/test_shader_composer.cc
index 7efcd83..16dabba 100644
--- a/src/tests/test_shader_composer.cc
+++ b/src/tests/test_shader_composer.cc
@@ -15,7 +15,6 @@
// Forward declaration for asset loading
const uint8_t* GetAsset(AssetId asset_id, size_t* out_size);
-
void test_composition() {
std::cout << "Testing Shader Composition..." << std::endl;
auto& sc = ShaderComposer::Get();
@@ -42,35 +41,38 @@ void test_composition() {
}
void test_asset_composition() {
- std::cout << "Testing Asset-Based Shader Composition..." << std::endl;
+ std::cout << "Testing Asset-Based Shader Composition..." << std::endl;
- // Use test assets
- auto& sc = ShaderComposer::Get();
+ // Use test assets
+ auto& sc = ShaderComposer::Get();
- size_t snippet_a_size;
- const char* snippet_a_code = (const char*)GetAsset(AssetId::ASSET_SHADER_SNIPPET_A, &snippet_a_size);
- assert(snippet_a_code != nullptr);
- sc.RegisterSnippet("SNIPPET_A", std::string(snippet_a_code, snippet_a_size));
+ size_t snippet_a_size;
+ const char* snippet_a_code =
+ (const char*)GetAsset(AssetId::ASSET_SHADER_SNIPPET_A, &snippet_a_size);
+ assert(snippet_a_code != nullptr);
+ sc.RegisterSnippet("SNIPPET_A", std::string(snippet_a_code, snippet_a_size));
- size_t snippet_b_size;
- const char* snippet_b_code = (const char*)GetAsset(AssetId::ASSET_SHADER_SNIPPET_B, &snippet_b_size);
- sc.RegisterSnippet("SNIPPET_B", std::string(snippet_b_code, snippet_b_size));
+ size_t snippet_b_size;
+ const char* snippet_b_code =
+ (const char*)GetAsset(AssetId::ASSET_SHADER_SNIPPET_B, &snippet_b_size);
+ sc.RegisterSnippet("SNIPPET_B", std::string(snippet_b_code, snippet_b_size));
- std::string main_code = "fn main() -> f32 { return snippet_a() + snippet_b(); }";
- std::string result = sc.Compose({"SNIPPET_A", "SNIPPET_B"}, main_code);
+ std::string main_code =
+ "fn main() -> f32 { return snippet_a() + snippet_b(); }";
+ std::string result = sc.Compose({"SNIPPET_A", "SNIPPET_B"}, main_code);
- assert(result.find("fn snippet_a()") != std::string::npos);
- assert(result.find("fn snippet_b()") != std::string::npos);
- assert(result.find("fn main()") != std::string::npos);
+ assert(result.find("fn snippet_a()") != std::string::npos);
+ assert(result.find("fn snippet_b()") != std::string::npos);
+ assert(result.find("fn main()") != std::string::npos);
- size_t pos_a = result.find("snippet_a");
- size_t pos_b = result.find("snippet_b");
- size_t pos_main = result.find("main");
+ size_t pos_a = result.find("snippet_a");
+ size_t pos_b = result.find("snippet_b");
+ size_t pos_main = result.find("main");
- assert(pos_a < pos_b);
- assert(pos_b < pos_main);
+ assert(pos_a < pos_b);
+ assert(pos_b < pos_main);
- std::cout << "Asset-based composition logic verified." << std::endl;
+ std::cout << "Asset-based composition logic verified." << std::endl;
}
int main() {
diff --git a/src/tests/test_texture_manager.cc b/src/tests/test_texture_manager.cc
index 5741d8c..75d897d 100644
--- a/src/tests/test_texture_manager.cc
+++ b/src/tests/test_texture_manager.cc
@@ -3,40 +3,18 @@
// with valid device).
#include "gpu/texture_manager.h"
+#include "platform.h"
#include "procedural/generator.h"
-#include <iostream>
-
-#include <GLFW/glfw3.h>
-#if defined(DEMO_CROSS_COMPILE_WIN32)
-#include <webgpu/webgpu.h>
-#else
-#include <webgpu.h>
-#endif
-
-// Forward decls from platform.h or similar (simplifying for test)
-// Note: This test requires a valid WebGPU device, which is hard in CI/headless.
-// We will structure it to compile, but runtime might skip if no device.
-// For now, we just test the C++ side logic if possible, but TextureManager
-// depends heavily on WGPU calls.
-
-// We will use a "Headless" approach if possible, or just skip if Init fails.
-// Actually, let's just make it a compilation test + basic logic check if we can
-// mock or stub. Since we don't have a mocking framework, we'll try to init
-// wgpu-native.
+#include <cstdio>
int main() {
- // Need to init GLFW for surface creation usually, even for headless in some
- // impls?
- if (!glfwInit()) {
- std::cerr << "Failed to init GLFW" << std::endl;
+ PlatformState state = platform_init(false, 100, 100);
+ if (!state.window) {
+ fprintf(stderr, "Failed to init platform\n");
return 1;
}
- // NOTE: In a real CI environment without GPU, this will likely fail or hang.
- // For this "demo" context, we assume the user has a GPU or we just verify it
- // compiles. We'll skip actual GPU init for this simple test to avoid hanging
- // the agent if no GPU.
- std::cout << "TextureManager Compilation Test Passed." << std::endl;
+ fprintf(stdout, "TextureManager Compilation Test Passed.\n");
/*
TextureManager tm;
diff --git a/src/tests/test_tracker.cc b/src/tests/test_tracker.cc
index ad84163..2a9239c 100644
--- a/src/tests/test_tracker.cc
+++ b/src/tests/test_tracker.cc
@@ -1,17 +1,16 @@
// This file is part of the 64k demo project.
// It tests the core functionality of the audio tracker engine.
-#include "audio/tracker.h"
-#include "audio/synth.h"
#include "audio/gen.h"
+#include "audio/synth.h"
+#include "audio/tracker.h"
// #include "generated/music_data.h" // Will be generated by tracker_compiler
#include <assert.h>
#include <stdio.h>
-// Forward declaration for generated data to avoid compilation issues before generation
-// extern const NoteParams g_tracker_samples[];
-// extern const uint32_t g_tracker_samples_count;
-// extern const TrackerPattern g_tracker_patterns[];
+// Forward declaration for generated data to avoid compilation issues before
+// generation extern const NoteParams g_tracker_samples[]; extern const uint32_t
+// g_tracker_samples_count; extern const TrackerPattern g_tracker_patterns[];
// extern const uint32_t g_tracker_patterns_count;
// extern const TrackerScore g_tracker_score;
@@ -28,7 +27,8 @@ void test_tracker_pattern_triggering() {
// Test 1: Trigger patterns at 0.0f
tracker_update(0.0f);
printf("Actual active voice count: %d\n", synth_get_active_voice_count());
- // Expect 3 voices (one for each pattern triggered at 0.0f: drum_loop, hihat_roll, em_melody)
+ // Expect 3 voices (one for each pattern triggered at 0.0f: drum_loop,
+ // hihat_roll, em_melody)
assert(synth_get_active_voice_count() == 3);
// Test 2: Advance time slightly
@@ -39,9 +39,10 @@ void test_tracker_pattern_triggering() {
tracker_update(3.0f);
// Voices from 0.0f triggers might have ended, but new ones haven't started.
// synth_get_active_voice_count might drop if previous voices ended.
- // For this test, we assume voices triggered at 0.0f are still active for a short duration.
- // A more robust test would check for specific spectrograms or mock synth.
- // For now, we expect voices to still be somewhat active or new ones to be triggered if there's overlap
+ // For this test, we assume voices triggered at 0.0f are still active for a
+ // short duration. A more robust test would check for specific spectrograms or
+ // mock synth. For now, we expect voices to still be somewhat active or new
+ // ones to be triggered if there's overlap
assert(synth_get_active_voice_count() > 0);
printf("Tracker pattern triggering test PASSED\n");
diff --git a/src/util/asset_manager.cc b/src/util/asset_manager.cc
index d9ecfe1..9294560 100644
--- a/src/util/asset_manager.cc
+++ b/src/util/asset_manager.cc
@@ -8,21 +8,26 @@
#include "generated/assets.h"
#endif /* defined(USE_TEST_ASSETS) */
-#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 <cstdio> // For fprintf
+#include <cstdlib> // For free
+#include <cstring> // For strcmp
+#include <new> // For placement new
#include "procedural/generator.h" // For ProcGenFunc and procedural functions
// Map of procedural function names to their pointers (for runtime dispatch)
-static const std::map<std::string, ProcGenFunc> kAssetManagerProcGenFuncMap = {
+struct ProcGenEntry {
+ const char* name;
+ ProcGenFunc func;
+};
+
+static const ProcGenEntry kAssetManagerProcGenFuncs[] = {
{"gen_noise", procedural::gen_noise},
{"gen_grid", procedural::gen_grid},
{"make_periodic", procedural::make_periodic},
};
+static const size_t kNumProcGenFuncs =
+ sizeof(kAssetManagerProcGenFuncs) / sizeof(kAssetManagerProcGenFuncs[0]);
// Array-based cache for assets.
// Initialized to all zeros (nullptr data, 0 size, false is_procedural)
@@ -63,31 +68,37 @@ const uint8_t* GetAsset(AssetId asset_id, size_t* out_size) {
}
AssetRecord source_record = assets[index];
-
+
AssetRecord cached_record = source_record;
if (source_record.is_procedural) {
// Dynamically generate the asset
- 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;
+ ProcGenFunc proc_gen_func_ptr = nullptr;
+ for (size_t i = 0; i < kNumProcGenFuncs; ++i) {
+ if (strcmp(source_record.proc_func_name_str,
+ kAssetManagerProcGenFuncs[i].name) == 0) {
+ proc_gen_func_ptr = kAssetManagerProcGenFuncs[i].func;
+ break;
+ }
+ }
+
+ if (proc_gen_func_ptr == nullptr) {
+ fprintf(stderr, "Error: Unknown procedural function at runtime: %s\n",
+ source_record.proc_func_name_str);
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.
int width = 256, height = 256;
- size_t data_size = width * height * 4; // RGBA8
+ size_t data_size = (size_t)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;
+ fprintf(stderr,
+ "Error: Failed to allocate memory for procedural asset.\n");
if (out_size)
*out_size = 0;
return nullptr;