diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-08 07:40:29 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-08 07:40:29 +0100 |
| commit | c9195f997f3e797f03ab90464e4158717198a167 (patch) | |
| tree | 331304f42870246efdc64cc97ad42de59444ef3a /src/tests | |
| parent | b8e6929cafa41681f0b27ac104c9cf1d4e510837 (diff) | |
style: Apply clang-format to all source files
Diffstat (limited to 'src/tests')
| -rw-r--r-- | src/tests/effect_test_helpers.cc | 41 | ||||
| -rw-r--r-- | src/tests/effect_test_helpers.h | 17 | ||||
| -rw-r--r-- | src/tests/offscreen_render_target.cc | 20 | ||||
| -rw-r--r-- | src/tests/offscreen_render_target.h | 28 | ||||
| -rw-r--r-- | src/tests/test_3d_render.cc | 12 | ||||
| -rw-r--r-- | src/tests/test_demo_effects.cc | 108 | ||||
| -rw-r--r-- | src/tests/test_effect_base.cc | 33 | ||||
| -rw-r--r-- | src/tests/test_fft.cc | 45 | ||||
| -rw-r--r-- | src/tests/test_mesh.cc | 346 | ||||
| -rw-r--r-- | src/tests/test_post_process_helper.cc | 81 | ||||
| -rw-r--r-- | src/tests/test_scene_loader.cc | 225 | ||||
| -rw-r--r-- | src/tests/test_sequence.cc | 3 | ||||
| -rw-r--r-- | src/tests/test_shader_compilation.cc | 14 | ||||
| -rw-r--r-- | src/tests/test_spectral_brush.cc | 53 | ||||
| -rw-r--r-- | src/tests/test_texture_manager.cc | 34 | ||||
| -rw-r--r-- | src/tests/test_wav_dump.cc | 9 | ||||
| -rw-r--r-- | src/tests/webgpu_test_fixture.cc | 4 | ||||
| -rw-r--r-- | src/tests/webgpu_test_fixture.h | 35 |
18 files changed, 610 insertions, 498 deletions
diff --git a/src/tests/effect_test_helpers.cc b/src/tests/effect_test_helpers.cc index a31c447..8183362 100644 --- a/src/tests/effect_test_helpers.cc +++ b/src/tests/effect_test_helpers.cc @@ -2,7 +2,7 @@ // It implements reusable test helpers for GPU effect testing. // Provides pixel validation and lifecycle testing utilities. -#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary +#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary #include "effect_test_helpers.h" #include "gpu/effect.h" @@ -13,27 +13,24 @@ // ============================================================================ bool validate_pixels( - const std::vector<uint8_t>& pixels, - int width, - int height, + const std::vector<uint8_t>& pixels, int width, int height, std::function<bool(uint8_t r, uint8_t g, uint8_t b, uint8_t a)> predicate) { const size_t pixel_count = width * height; for (size_t i = 0; i < pixel_count; ++i) { - const size_t offset = i * 4; // BGRA8 = 4 bytes/pixel + const size_t offset = i * 4; // BGRA8 = 4 bytes/pixel const uint8_t b = pixels[offset + 0]; const uint8_t g = pixels[offset + 1]; const uint8_t r = pixels[offset + 2]; const uint8_t a = pixels[offset + 3]; if (predicate(r, g, b, a)) { - return true; // At least one pixel matches + return true; // At least one pixel matches } } - return false; // No pixels matched + return false; // No pixels matched } -bool has_rendered_content(const std::vector<uint8_t>& pixels, - int width, +bool has_rendered_content(const std::vector<uint8_t>& pixels, int width, int height) { return validate_pixels(pixels, width, height, [](uint8_t r, uint8_t g, uint8_t b, uint8_t a) { @@ -41,13 +38,9 @@ bool has_rendered_content(const std::vector<uint8_t>& pixels, }); } -bool all_pixels_match_color(const std::vector<uint8_t>& pixels, - int width, - int height, - uint8_t target_r, - uint8_t target_g, - uint8_t target_b, - uint8_t tolerance) { +bool all_pixels_match_color(const std::vector<uint8_t>& pixels, int width, + int height, uint8_t target_r, uint8_t target_g, + uint8_t target_b, uint8_t tolerance) { const size_t pixel_count = width * height; for (size_t i = 0; i < pixel_count; ++i) { const size_t offset = i * 4; @@ -61,10 +54,10 @@ bool all_pixels_match_color(const std::vector<uint8_t>& pixels, if (diff_r * diff_r + diff_g * diff_g + diff_b * diff_b > tolerance * tolerance) { - return false; // At least one pixel doesn't match + return false; // At least one pixel doesn't match } } - return true; // All pixels match + return true; // All pixels match } uint64_t hash_pixels(const std::vector<uint8_t>& pixels) { @@ -87,7 +80,7 @@ bool test_effect_lifecycle(Effect* effect, MainSequence* main_seq) { // Check initial state if (effect->is_initialized) { - return false; // Should not be initialized yet + return false; // Should not be initialized yet } // Initialize effect @@ -95,10 +88,10 @@ bool test_effect_lifecycle(Effect* effect, MainSequence* main_seq) { // Check initialized state if (!effect->is_initialized) { - return false; // Should be initialized now + return false; // Should be initialized now } - return true; // Lifecycle test passed + return true; // Lifecycle test passed } bool test_effect_render_smoke(Effect* effect) { @@ -108,14 +101,14 @@ bool test_effect_render_smoke(Effect* effect) { // If this doesn't crash, consider it a success // Note: This requires the effect to be initialized first if (!effect->is_initialized) { - return false; // Cannot render uninitialized effect + return false; // Cannot render uninitialized effect } // We cannot actually render without a full render pass setup // This is a placeholder for more sophisticated render testing // Real render tests should use OffscreenRenderTarget - return true; // Smoke test passed (no crash) + return true; // Smoke test passed (no crash) } -#endif /* !defined(STRIP_ALL) */ +#endif /* !defined(STRIP_ALL) */ diff --git a/src/tests/effect_test_helpers.h b/src/tests/effect_test_helpers.h index d48daa7..33355ee 100644 --- a/src/tests/effect_test_helpers.h +++ b/src/tests/effect_test_helpers.h @@ -19,24 +19,17 @@ class MainSequence; // Validate pixels using a predicate function // Returns true if at least one pixel matches the predicate bool validate_pixels( - const std::vector<uint8_t>& pixels, - int width, - int height, + const std::vector<uint8_t>& pixels, int width, int height, std::function<bool(uint8_t r, uint8_t g, uint8_t b, uint8_t a)> predicate); // Check if any pixel is non-black (rendered something) -bool has_rendered_content(const std::vector<uint8_t>& pixels, - int width, +bool has_rendered_content(const std::vector<uint8_t>& pixels, int width, int height); // Check if all pixels match a specific color (within tolerance) -bool all_pixels_match_color(const std::vector<uint8_t>& pixels, - int width, - int height, - uint8_t r, - uint8_t g, - uint8_t b, - uint8_t tolerance = 5); +bool all_pixels_match_color(const std::vector<uint8_t>& pixels, int width, + int height, uint8_t r, uint8_t g, uint8_t b, + uint8_t tolerance = 5); // Compute simple hash of pixel data (for deterministic output checks) uint64_t hash_pixels(const std::vector<uint8_t>& pixels); diff --git a/src/tests/offscreen_render_target.cc b/src/tests/offscreen_render_target.cc index 81ad082..36b7b26 100644 --- a/src/tests/offscreen_render_target.cc +++ b/src/tests/offscreen_render_target.cc @@ -2,7 +2,7 @@ // It implements offscreen rendering for headless GPU testing. // Provides pixel readback for validation. -#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary +#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary #include "offscreen_render_target.h" #include <cassert> @@ -10,14 +10,10 @@ #include <cstring> OffscreenRenderTarget::OffscreenRenderTarget(WGPUInstance instance, - WGPUDevice device, - int width, + WGPUDevice device, int width, int height, WGPUTextureFormat format) - : instance_(instance), - device_(device), - width_(width), - height_(height), + : instance_(instance), device_(device), width_(width), height_(height), format_(format) { // Create offscreen texture const WGPUTextureDescriptor texture_desc = { @@ -61,7 +57,7 @@ void OffscreenRenderTarget::map_callback(WGPUMapAsyncStatus status, } WGPUBuffer OffscreenRenderTarget::create_staging_buffer() { - const size_t buffer_size = width_ * height_ * 4; // BGRA8 = 4 bytes/pixel + const size_t buffer_size = width_ * height_ * 4; // BGRA8 = 4 bytes/pixel const WGPUBufferDescriptor buffer_desc = { .usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_MapRead, .size = buffer_size, @@ -70,7 +66,7 @@ WGPUBuffer OffscreenRenderTarget::create_staging_buffer() { } std::vector<uint8_t> OffscreenRenderTarget::read_pixels() { - const size_t buffer_size = width_ * height_ * 4; // BGRA8 + const size_t buffer_size = width_ * height_ * 4; // BGRA8 std::vector<uint8_t> pixels(buffer_size); // Create staging buffer for readback @@ -99,7 +95,7 @@ std::vector<uint8_t> OffscreenRenderTarget::read_pixels() { }; const WGPUExtent3D copy_size = {static_cast<uint32_t>(width_), - static_cast<uint32_t>(height_), 1}; + static_cast<uint32_t>(height_), 1}; wgpuCommandEncoderCopyTextureToBuffer(encoder, &src, &dst, ©_size); @@ -150,7 +146,7 @@ std::vector<uint8_t> OffscreenRenderTarget::read_pixels() { if (map_state.status != WGPUMapAsyncStatus_Success) { fprintf(stderr, "Buffer mapping failed: %d\n", map_state.status); wgpuBufferRelease(staging); - return pixels; // Return empty + return pixels; // Return empty } // Copy data from mapped buffer @@ -167,4 +163,4 @@ std::vector<uint8_t> OffscreenRenderTarget::read_pixels() { return pixels; } -#endif /* !defined(STRIP_ALL) */ +#endif /* !defined(STRIP_ALL) */ diff --git a/src/tests/offscreen_render_target.h b/src/tests/offscreen_render_target.h index 4163ec1..10c12aa 100644 --- a/src/tests/offscreen_render_target.h +++ b/src/tests/offscreen_render_target.h @@ -13,19 +13,27 @@ class OffscreenRenderTarget { public: // Create an offscreen render target with specified dimensions - OffscreenRenderTarget(WGPUInstance instance, - WGPUDevice device, - int width, - int height, - WGPUTextureFormat format = WGPUTextureFormat_BGRA8Unorm); + OffscreenRenderTarget( + WGPUInstance instance, WGPUDevice device, int width, int height, + WGPUTextureFormat format = WGPUTextureFormat_BGRA8Unorm); ~OffscreenRenderTarget(); // Accessors - WGPUTexture texture() const { return texture_; } - WGPUTextureView view() const { return view_; } - int width() const { return width_; } - int height() const { return height_; } - WGPUTextureFormat format() const { return format_; } + WGPUTexture texture() const { + return texture_; + } + WGPUTextureView view() const { + return view_; + } + int width() const { + return width_; + } + int height() const { + return height_; + } + WGPUTextureFormat format() const { + return format_; + } // Read pixels from the render target // Returns BGRA8 pixel data (width * height * 4 bytes) diff --git a/src/tests/test_3d_render.cc b/src/tests/test_3d_render.cc index a7c74e1..fa13a43 100644 --- a/src/tests/test_3d_render.cc +++ b/src/tests/test_3d_render.cc @@ -272,18 +272,18 @@ int main(int argc, char** argv) { Renderer3D::SetDebugEnabled(true); VisualDebug& dbg = g_renderer.GetVisualDebug(); dbg.add_cross(vec3(0, 0, 0), 1.0f, vec3(1, 0, 0)); - dbg.add_sphere(vec3(std::sin(time) * 2.0f, 3.0f, std::cos(time) * 2.0f), 0.5f, - vec3(0, 1, 1)); + dbg.add_sphere(vec3(std::sin(time) * 2.0f, 3.0f, std::cos(time) * 2.0f), + 0.5f, vec3(0, 1, 1)); dbg.add_line(vec3(0, 0, 0), vec3(0, 5, 0), vec3(1, 0, 1)); - + // Cone (Spotlight visualization) dbg.add_cone(vec3(0, 5, 0), vec3(0, -1, 0), 2.0f, 1.0f, vec3(1, 1, 0)); // Trajectory path std::vector<vec3> path; - for(int i=0; i<=32; ++i) { - float a = i * 6.28318f / 32.0f; - path.push_back(vec3(std::sin(a)*4.0f, 0.5f, std::cos(a)*4.0f)); + for (int i = 0; i <= 32; ++i) { + float a = i * 6.28318f / 32.0f; + path.push_back(vec3(std::sin(a) * 4.0f, 0.5f, std::cos(a) * 4.0f)); } dbg.add_trajectory(path, vec3(0, 0.5f, 1.0f)); #endif diff --git a/src/tests/test_demo_effects.cc b/src/tests/test_demo_effects.cc index ec1d68c..3c40bc5 100644 --- a/src/tests/test_demo_effects.cc +++ b/src/tests/test_demo_effects.cc @@ -1,23 +1,31 @@ // This file is part of the 64k demo project. // It tests all demo effect classes for basic construction and initialization. -// Validates that every effect can be instantiated and initialized without crashes. +// Validates that every effect can be instantiated and initialized without +// crashes. // // MAINTENANCE REQUIREMENT: When adding a new effect to demo_effects.h: -// 1. Add it to the appropriate test list (post_process_effects or scene_effects) +// 1. Add it to the appropriate test list (post_process_effects or +// scene_effects) // 2. Update EXPECTED_POST_PROCESS_COUNT or EXPECTED_SCENE_COUNT below // 3. Run test to verify: ./build/test_demo_effects -// 4. If the effect requires Renderer3D, add it to requires_3d check in test_scene_effects() +// 4. If the effect requires Renderer3D, add it to requires_3d check in +// test_scene_effects() -#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary +#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary // Expected effect counts - UPDATE THESE when adding new effects! -static constexpr int EXPECTED_POST_PROCESS_COUNT = 8; // FlashEffect, PassthroughEffect, GaussianBlurEffect, ChromaAberrationEffect, DistortEffect, SolarizeEffect, FadeEffect, ThemeModulationEffect -static constexpr int EXPECTED_SCENE_COUNT = 6; // HeptagonEffect, ParticlesEffect, ParticleSprayEffect, MovingEllipseEffect, FlashCubeEffect, Hybrid3DEffect +static constexpr int EXPECTED_POST_PROCESS_COUNT = + 8; // FlashEffect, PassthroughEffect, GaussianBlurEffect, + // ChromaAberrationEffect, DistortEffect, SolarizeEffect, FadeEffect, + // ThemeModulationEffect +static constexpr int EXPECTED_SCENE_COUNT = + 6; // HeptagonEffect, ParticlesEffect, ParticleSprayEffect, + // MovingEllipseEffect, FlashCubeEffect, Hybrid3DEffect #include "effect_test_helpers.h" -#include "webgpu_test_fixture.h" #include "gpu/demo_effects.h" #include "gpu/effect.h" +#include "webgpu_test_fixture.h" #include <cassert> #include <cstdio> #include <cstring> @@ -26,10 +34,8 @@ static constexpr int EXPECTED_SCENE_COUNT = 6; // HeptagonEffect, ParticlesEffe // Helper: Test effect construction and initialization // Returns: 0=failed, 1=passed, 2=skipped (requires full 3D setup) -static int test_effect_smoke(const char* name, - std::shared_ptr<Effect> effect, - MainSequence* main_seq, - bool requires_3d = false) { +static int test_effect_smoke(const char* name, std::shared_ptr<Effect> effect, + MainSequence* main_seq, bool requires_3d = false) { fprintf(stdout, " Testing %s...\n", name); // Check construction @@ -53,7 +59,7 @@ static int test_effect_smoke(const char* name, // These will fail in init_test() environment - skip them gracefully if (requires_3d) { fprintf(stdout, " ⚠ Skipped (requires full 3D pipeline setup)\n"); - return 2; // Skipped + return 2; // Skipped } seq->init(main_seq); @@ -65,7 +71,7 @@ static int test_effect_smoke(const char* name, } fprintf(stdout, " ✓ %s construction and initialization OK\n", name); - return 1; // Passed + return 1; // Passed } // Test 1: Post-process effects @@ -83,24 +89,17 @@ static void test_post_process_effects() { // Test each post-process effect std::vector<std::pair<const char*, std::shared_ptr<Effect>>> effects = { - {"FlashEffect", - std::make_shared<FlashEffect>(fixture.ctx())}, - {"PassthroughEffect", - std::make_shared<PassthroughEffect>(fixture.ctx())}, + {"FlashEffect", std::make_shared<FlashEffect>(fixture.ctx())}, + {"PassthroughEffect", std::make_shared<PassthroughEffect>(fixture.ctx())}, {"GaussianBlurEffect", std::make_shared<GaussianBlurEffect>(fixture.ctx())}, {"ChromaAberrationEffect", - std::make_shared<ChromaAberrationEffect>( - fixture.ctx())}, - {"DistortEffect", - std::make_shared<DistortEffect>(fixture.ctx())}, - {"SolarizeEffect", - std::make_shared<SolarizeEffect>(fixture.ctx())}, - {"FadeEffect", - std::make_shared<FadeEffect>(fixture.ctx())}, + std::make_shared<ChromaAberrationEffect>(fixture.ctx())}, + {"DistortEffect", std::make_shared<DistortEffect>(fixture.ctx())}, + {"SolarizeEffect", std::make_shared<SolarizeEffect>(fixture.ctx())}, + {"FadeEffect", std::make_shared<FadeEffect>(fixture.ctx())}, {"ThemeModulationEffect", - std::make_shared<ThemeModulationEffect>( - fixture.ctx())}, + std::make_shared<ThemeModulationEffect>(fixture.ctx())}, }; int passed = 0; @@ -121,10 +120,15 @@ static void test_post_process_effects() { // Validation: Ensure test coverage matches expected count const int tested_count = static_cast<int>(effects.size()); if (tested_count != EXPECTED_POST_PROCESS_COUNT) { - fprintf(stderr, " ✗ COVERAGE ERROR: Expected %d post-process effects, but only tested %d!\n", + fprintf(stderr, + " ✗ COVERAGE ERROR: Expected %d post-process effects, but only " + "tested %d!\n", EXPECTED_POST_PROCESS_COUNT, tested_count); - fprintf(stderr, " ✗ Did you add a new post-process effect without updating the test?\n"); - fprintf(stderr, " ✗ Update EXPECTED_POST_PROCESS_COUNT in test_demo_effects.cc\n"); + fprintf(stderr, + " ✗ Did you add a new post-process effect without updating the " + "test?\n"); + fprintf(stderr, + " ✗ Update EXPECTED_POST_PROCESS_COUNT in test_demo_effects.cc\n"); assert(false && "Post-process effect count mismatch - update test!"); } } @@ -144,18 +148,14 @@ static void test_scene_effects() { // Test each scene effect std::vector<std::pair<const char*, std::shared_ptr<Effect>>> effects = { - {"HeptagonEffect", - std::make_shared<HeptagonEffect>(fixture.ctx())}, - {"ParticlesEffect", - std::make_shared<ParticlesEffect>(fixture.ctx())}, + {"HeptagonEffect", std::make_shared<HeptagonEffect>(fixture.ctx())}, + {"ParticlesEffect", std::make_shared<ParticlesEffect>(fixture.ctx())}, {"ParticleSprayEffect", std::make_shared<ParticleSprayEffect>(fixture.ctx())}, {"MovingEllipseEffect", std::make_shared<MovingEllipseEffect>(fixture.ctx())}, - {"FlashCubeEffect", - std::make_shared<FlashCubeEffect>(fixture.ctx())}, - {"Hybrid3DEffect", - std::make_shared<Hybrid3DEffect>(fixture.ctx())}, + {"FlashCubeEffect", std::make_shared<FlashCubeEffect>(fixture.ctx())}, + {"Hybrid3DEffect", std::make_shared<Hybrid3DEffect>(fixture.ctx())}, }; int passed = 0; @@ -183,10 +183,14 @@ static void test_scene_effects() { // Validation: Ensure test coverage matches expected count const int tested_count = static_cast<int>(effects.size()); if (tested_count != EXPECTED_SCENE_COUNT) { - fprintf(stderr, " ✗ COVERAGE ERROR: Expected %d scene effects, but only tested %d!\n", - EXPECTED_SCENE_COUNT, tested_count); - fprintf(stderr, " ✗ Did you add a new scene effect without updating the test?\n"); - fprintf(stderr, " ✗ Update EXPECTED_SCENE_COUNT in test_demo_effects.cc\n"); + fprintf( + stderr, + " ✗ COVERAGE ERROR: Expected %d scene effects, but only tested %d!\n", + EXPECTED_SCENE_COUNT, tested_count); + fprintf(stderr, + " ✗ Did you add a new scene effect without updating the test?\n"); + fprintf(stderr, + " ✗ Update EXPECTED_SCENE_COUNT in test_demo_effects.cc\n"); assert(false && "Scene effect count mismatch - update test!"); } } @@ -202,21 +206,19 @@ static void test_effect_type_classification() { } // Post-process effects should return true - auto flash = std::make_shared<FlashEffect>( - fixture.ctx()); + auto flash = std::make_shared<FlashEffect>(fixture.ctx()); assert(flash->is_post_process() && "FlashEffect should be post-process"); - auto blur = std::make_shared<GaussianBlurEffect>( - fixture.ctx()); - assert(blur->is_post_process() && "GaussianBlurEffect should be post-process"); + auto blur = std::make_shared<GaussianBlurEffect>(fixture.ctx()); + assert(blur->is_post_process() && + "GaussianBlurEffect should be post-process"); // Scene effects should return false - auto heptagon = std::make_shared<HeptagonEffect>( - fixture.ctx()); - assert(!heptagon->is_post_process() && "HeptagonEffect should NOT be post-process"); + auto heptagon = std::make_shared<HeptagonEffect>(fixture.ctx()); + assert(!heptagon->is_post_process() && + "HeptagonEffect should NOT be post-process"); - auto particles = std::make_shared<ParticlesEffect>( - fixture.ctx()); + auto particles = std::make_shared<ParticlesEffect>(fixture.ctx()); assert(!particles->is_post_process() && "ParticlesEffect should NOT be post-process"); @@ -234,4 +236,4 @@ int main() { return 0; } -#endif /* !defined(STRIP_ALL) */ +#endif /* !defined(STRIP_ALL) */ diff --git a/src/tests/test_effect_base.cc b/src/tests/test_effect_base.cc index 8180535..5dc2dcc 100644 --- a/src/tests/test_effect_base.cc +++ b/src/tests/test_effect_base.cc @@ -3,10 +3,10 @@ // Verifies effect initialization, activation, and basic rendering. #include "effect_test_helpers.h" -#include "offscreen_render_target.h" -#include "webgpu_test_fixture.h" #include "gpu/demo_effects.h" #include "gpu/effect.h" +#include "offscreen_render_target.h" +#include "webgpu_test_fixture.h" #include <cassert> #include <cstdio> #include <memory> @@ -72,8 +72,7 @@ static void test_effect_construction() { } // Create FlashEffect (simple post-process effect) - auto effect = std::make_shared<FlashEffect>( - fixture.ctx()); + auto effect = std::make_shared<FlashEffect>(fixture.ctx()); assert(!effect->is_initialized && "Effect should not be initialized yet"); @@ -95,8 +94,7 @@ static void test_effect_initialization() { main_seq.init_test(fixture.ctx()); // Create FlashEffect - auto effect = std::make_shared<FlashEffect>( - fixture.ctx()); + auto effect = std::make_shared<FlashEffect>(fixture.ctx()); assert(!effect->is_initialized && "Effect should not be initialized yet"); @@ -107,7 +105,8 @@ static void test_effect_initialization() { // Initialize sequence (this sets effect->is_initialized) seq->init(&main_seq); - assert(effect->is_initialized && "Effect should be initialized after Sequence::init()"); + assert(effect->is_initialized && + "Effect should be initialized after Sequence::init()"); fprintf(stdout, " ✓ FlashEffect initialized via Sequence::init()\n"); } @@ -129,10 +128,10 @@ static void test_sequence_add_effect() { auto seq = std::make_shared<Sequence>(); // Create effect - auto effect = std::make_shared<FlashEffect>( - fixture.ctx()); + auto effect = std::make_shared<FlashEffect>(fixture.ctx()); - assert(!effect->is_initialized && "Effect should not be initialized before Sequence::init()"); + assert(!effect->is_initialized && + "Effect should not be initialized before Sequence::init()"); // Add effect to sequence (time range: 0.0 - 10.0, priority 0) seq->add_effect(effect, 0.0f, 10.0f, 0); @@ -140,9 +139,12 @@ static void test_sequence_add_effect() { // Initialize sequence (this should initialize the effect) seq->init(&main_seq); - assert(effect->is_initialized && "Effect should be initialized after Sequence::init()"); + assert(effect->is_initialized && + "Effect should be initialized after Sequence::init()"); - fprintf(stdout, " ✓ Effect added to sequence and initialized (time=0.0-10.0, priority=0)\n"); + fprintf(stdout, + " ✓ Effect added to sequence and initialized (time=0.0-10.0, " + "priority=0)\n"); } // Test 6: Sequence activation logic @@ -159,8 +161,7 @@ static void test_sequence_activation() { main_seq.init_test(fixture.ctx()); auto seq = std::make_shared<Sequence>(); - auto effect = std::make_shared<FlashEffect>( - fixture.ctx()); + auto effect = std::make_shared<FlashEffect>(fixture.ctx()); // Effect active from 5.0 to 10.0 seconds seq->add_effect(effect, 5.0f, 10.0f, 0); @@ -213,7 +214,7 @@ static void test_pixel_helpers() { "Black frame should have no content"); std::vector<uint8_t> colored_frame(256 * 256 * 4, 0); - colored_frame[0] = 255; // Set one red pixel + colored_frame[0] = 255; // Set one red pixel assert(has_rendered_content(colored_frame, 256, 256) && "Colored frame should have content"); @@ -222,7 +223,7 @@ static void test_pixel_helpers() { // Test all_pixels_match_color std::vector<uint8_t> red_frame(256 * 256 * 4, 0); for (size_t i = 0; i < 256 * 256; ++i) { - red_frame[i * 4 + 2] = 255; // BGRA: Red in position 2 + red_frame[i * 4 + 2] = 255; // BGRA: Red in position 2 } assert(all_pixels_match_color(red_frame, 256, 256, 255, 0, 0, 5) && "Red frame should match red color"); diff --git a/src/tests/test_fft.cc b/src/tests/test_fft.cc index ab5210b..2151608 100644 --- a/src/tests/test_fft.cc +++ b/src/tests/test_fft.cc @@ -43,23 +43,18 @@ static void idct_reference(const float* input, float* output, size_t N) { } // Compare two arrays with tolerance -// Note: FFT-based DCT accumulates slightly more rounding error than O(N²) direct method -// A tolerance of 5e-3 is acceptable for audio applications (< -46 dB error) -// Some input patterns (e.g., impulse at N/2, high-frequency sinusoids) have higher -// numerical error due to reordering and accumulated floating-point error -static bool arrays_match(const float* a, - const float* b, - size_t N, +// Note: FFT-based DCT accumulates slightly more rounding error than O(N²) +// direct method A tolerance of 5e-3 is acceptable for audio applications (< -46 +// dB error) Some input patterns (e.g., impulse at N/2, high-frequency +// sinusoids) have higher numerical error due to reordering and accumulated +// floating-point error +static bool arrays_match(const float* a, const float* b, size_t N, float tolerance = 5e-3f) { for (size_t i = 0; i < N; i++) { const float diff = fabsf(a[i] - b[i]); if (diff > tolerance) { - fprintf(stderr, - "Mismatch at index %zu: %.6f vs %.6f (diff=%.6e)\n", - i, - a[i], - b[i], - diff); + fprintf(stderr, "Mismatch at index %zu: %.6f vs %.6f (diff=%.6e)\n", i, + a[i], b[i], diff); return false; } } @@ -85,9 +80,10 @@ static void test_dct_correctness() { assert(arrays_match(output_ref, output_fft, N)); printf(" ✓ Impulse test passed\n"); - // Test case 2: Impulse at middle (SKIPPED - reordering method has issues with this pattern) - // The reordering FFT method has systematic sign errors for impulses at certain positions - // This doesn't affect typical audio signals (smooth spectra), only pathological cases + // Test case 2: Impulse at middle (SKIPPED - reordering method has issues with + // this pattern) The reordering FFT method has systematic sign errors for + // impulses at certain positions This doesn't affect typical audio signals + // (smooth spectra), only pathological cases // TODO: Investigate and fix, or switch to a different FFT-DCT algorithm // memset(input, 0, N * sizeof(float)); // input[N / 2] = 1.0f; @@ -96,10 +92,12 @@ static void test_dct_correctness() { // assert(arrays_match(output_ref, output_fft, N)); printf(" ⊘ Middle impulse test skipped (known limitation)\n"); - // Test case 3: Sinusoidal input (SKIPPED - FFT accumulates error for high-frequency components) - // The reordering method has accumulated floating-point error that grows with frequency index - // This doesn't affect audio synthesis quality (round-trip is what matters) - printf(" ⊘ Sinusoidal input test skipped (accumulated floating-point error)\n"); + // Test case 3: Sinusoidal input (SKIPPED - FFT accumulates error for + // high-frequency components) The reordering method has accumulated + // floating-point error that grows with frequency index This doesn't affect + // audio synthesis quality (round-trip is what matters) + printf( + " ⊘ Sinusoidal input test skipped (accumulated floating-point error)\n"); // Test case 4: Random-ish input (SKIPPED - same issue as sinusoidal) printf(" ⊘ Complex input test skipped (accumulated floating-point error)\n"); @@ -136,8 +134,11 @@ static void test_idct_correctness() { assert(arrays_match(output_ref, output_fft, N)); printf(" ✓ Single bin test passed\n"); - // Test case 3: Mixed frequencies (SKIPPED - accumulated error for complex spectra) - printf(" ⊘ Mixed frequencies test skipped (accumulated floating-point error)\n"); + // Test case 3: Mixed frequencies (SKIPPED - accumulated error for complex + // spectra) + printf( + " ⊘ Mixed frequencies test skipped (accumulated floating-point " + "error)\n"); printf("Test 2: PASSED ✓\n\n"); } diff --git a/src/tests/test_mesh.cc b/src/tests/test_mesh.cc index 992471a..0865f80 100644 --- a/src/tests/test_mesh.cc +++ b/src/tests/test_mesh.cc @@ -8,9 +8,8 @@ #include "gpu/effects/shaders.h" #include "gpu/texture_manager.h" #include "platform/platform.h" -#include "util/asset_manager_utils.h" -#include <webgpu.h> #include "procedural/generator.h" +#include "util/asset_manager_utils.h" #include <algorithm> #include <cmath> #include <cstdio> @@ -18,6 +17,7 @@ #include <fstream> #include <map> #include <vector> +#include <webgpu.h> // Global State static Renderer3D g_renderer; @@ -41,18 +41,20 @@ void on_adapter_request_ended(WGPURequestAdapterStatus status, if (status == WGPURequestAdapterStatus_Success) { *(WGPUAdapter*)userdata = adapter; } else { - fprintf(stderr, "Failed to request adapter.\n"); // Avoid WGPUStringView::s issues + fprintf(stderr, + "Failed to request adapter.\n"); // Avoid WGPUStringView::s issues } } -void on_device_request_ended(WGPURequestDeviceStatus status, - WGPUDevice device, WGPUStringView message, - void* userdata, void* user2) { +void on_device_request_ended(WGPURequestDeviceStatus status, WGPUDevice device, + WGPUStringView message, void* userdata, + void* user2) { (void)user2; if (status == WGPURequestDeviceStatus_Success) { *(WGPUDevice*)userdata = device; } else { - fprintf(stderr, "Failed to request device.\n"); // Avoid WGPUStringView::s issues + fprintf(stderr, + "Failed to request device.\n"); // Avoid WGPUStringView::s issues } } @@ -80,7 +82,7 @@ void init_wgpu(WGPUInstance instance, PlatformState* platform_state) { adapter_callback_info.userdata1 = &g_adapter; // Corrected to userdata1 wgpuInstanceRequestAdapter(instance, &adapter_opts, adapter_callback_info); - + // Busy-wait for adapter while (!g_adapter) { platform_wgpu_wait_any(instance); @@ -92,7 +94,7 @@ void init_wgpu(WGPUInstance instance, PlatformState* platform_state) { device_callback_info.mode = WGPUCallbackMode_WaitAnyOnly; device_callback_info.callback = on_device_request_ended; device_callback_info.userdata1 = &g_device; // Corrected to userdata1 - + wgpuAdapterRequestDevice(g_adapter, &device_desc, device_callback_info); // Busy-wait for device @@ -122,144 +124,196 @@ void init_wgpu(WGPUInstance instance, PlatformState* platform_state) { struct Vec3 { float x, y, z; - Vec3 operator+(const Vec3& o) const { return {x + o.x, y + o.y, z + o.z}; } - Vec3& operator+=(const Vec3& o) { x+=o.x; y+=o.y; z+=o.z; return *this; } - Vec3 operator-(const Vec3& o) const { return {x - o.x, y - o.y, z - o.z}; } - Vec3 operator*(float s) const { return {x * s, y * s, z * s}; } + Vec3 operator+(const Vec3& o) const { + return {x + o.x, y + o.y, z + o.z}; + } + Vec3& operator+=(const Vec3& o) { + x += o.x; + y += o.y; + z += o.z; + return *this; + } + Vec3 operator-(const Vec3& o) const { + return {x - o.x, y - o.y, z - o.z}; + } + Vec3 operator*(float s) const { + return {x * s, y * s, z * s}; + } static Vec3 cross(const Vec3& a, const Vec3& b) { - return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; + return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, + a.x * b.y - a.y * b.x}; } Vec3 normalize() const { float len = std::sqrt(x * x + y * y + z * z); - if (len > 1e-6f) return {x / len, y / len, z / len}; + if (len > 1e-6f) + return {x / len, y / len, z / len}; return {0, 0, 0}; } }; bool load_obj_and_create_buffers(const char* path, Object3D& out_obj) { - std::ifstream obj_file(path); - if (!obj_file.is_open()) { - fprintf(stderr, "Error: Could not open mesh file: %s\n", path); - return false; - } + std::ifstream obj_file(path); + if (!obj_file.is_open()) { + fprintf(stderr, "Error: Could not open mesh file: %s\n", path); + return false; + } - std::vector<float> v_pos, v_norm, v_uv; - struct RawFace { int v[3], vt[3], vn[3]; }; - std::vector<RawFace> raw_faces; - std::vector<MeshVertex> final_vertices; - std::vector<uint32_t> final_indices; - std::map<std::string, uint32_t> vertex_map; + std::vector<float> v_pos, v_norm, v_uv; + struct RawFace { + int v[3], vt[3], vn[3]; + }; + std::vector<RawFace> raw_faces; + std::vector<MeshVertex> final_vertices; + std::vector<uint32_t> final_indices; + std::map<std::string, uint32_t> vertex_map; - std::string obj_line; - while (std::getline(obj_file, obj_line)) { - if (obj_line.compare(0, 2, "v ") == 0) { - float x, y, z; - sscanf(obj_line.c_str(), "v %f %f %f", &x, &y, &z); - v_pos.insert(v_pos.end(), {x, y, z}); - } else if (obj_line.compare(0, 3, "vn ") == 0) { - float x, y, z; - sscanf(obj_line.c_str(), "vn %f %f %f", &x, &y, &z); - v_norm.insert(v_norm.end(), {x, y, z}); - } else if (obj_line.compare(0, 3, "vt ") == 0) { - float u, v; - sscanf(obj_line.c_str(), "vt %f %f", &u, &v); - v_uv.insert(v_uv.end(), {u, v}); - } else if (obj_line.compare(0, 2, "f ") == 0) { - char s1[64], s2[64], s3[64]; - if (sscanf(obj_line.c_str(), "f %s %s %s", s1, s2, s3) == 3) { - std::string parts[3] = {s1, s2, s3}; - RawFace face = {}; - for (int i = 0; i < 3; ++i) { - // Handle v//vn format - if (parts[i].find("//") != std::string::npos) { - sscanf(parts[i].c_str(), "%d//%d", &face.v[i], &face.vn[i]); - face.vt[i] = 0; - } else { - int res = sscanf(parts[i].c_str(), "%d/%d/%d", &face.v[i], &face.vt[i], &face.vn[i]); - if (res == 2) face.vn[i] = 0; - else if (res == 1) { face.vt[i] = 0; face.vn[i] = 0; } - } - } - raw_faces.push_back(face); + std::string obj_line; + while (std::getline(obj_file, obj_line)) { + if (obj_line.compare(0, 2, "v ") == 0) { + float x, y, z; + sscanf(obj_line.c_str(), "v %f %f %f", &x, &y, &z); + v_pos.insert(v_pos.end(), {x, y, z}); + } else if (obj_line.compare(0, 3, "vn ") == 0) { + float x, y, z; + sscanf(obj_line.c_str(), "vn %f %f %f", &x, &y, &z); + v_norm.insert(v_norm.end(), {x, y, z}); + } else if (obj_line.compare(0, 3, "vt ") == 0) { + float u, v; + sscanf(obj_line.c_str(), "vt %f %f", &u, &v); + v_uv.insert(v_uv.end(), {u, v}); + } else if (obj_line.compare(0, 2, "f ") == 0) { + char s1[64], s2[64], s3[64]; + if (sscanf(obj_line.c_str(), "f %s %s %s", s1, s2, s3) == 3) { + std::string parts[3] = {s1, s2, s3}; + RawFace face = {}; + for (int i = 0; i < 3; ++i) { + // Handle v//vn format + if (parts[i].find("//") != std::string::npos) { + sscanf(parts[i].c_str(), "%d//%d", &face.v[i], &face.vn[i]); + face.vt[i] = 0; + } else { + int res = sscanf(parts[i].c_str(), "%d/%d/%d", &face.v[i], + &face.vt[i], &face.vn[i]); + if (res == 2) + face.vn[i] = 0; + else if (res == 1) { + face.vt[i] = 0; + face.vn[i] = 0; } + } } + raw_faces.push_back(face); + } + } + } + + if (v_norm.empty() && !v_pos.empty()) { + std::vector<Vec3> temp_normals(v_pos.size() / 3, {0, 0, 0}); + for (auto& face : raw_faces) { + int i0 = face.v[0] - 1, i1 = face.v[1] - 1, i2 = face.v[2] - 1; + Vec3 p0 = {v_pos[i0 * 3], v_pos[i0 * 3 + 1], v_pos[i0 * 3 + 2]}; + Vec3 p1 = {v_pos[i1 * 3], v_pos[i1 * 3 + 1], v_pos[i1 * 3 + 2]}; + Vec3 p2 = {v_pos[i2 * 3], v_pos[i2 * 3 + 1], v_pos[i2 * 3 + 2]}; + Vec3 n = Vec3::cross(p1 - p0, p2 - p0).normalize(); + temp_normals[i0] += n; + temp_normals[i1] += n; + temp_normals[i2] += n; + } + for (const auto& n : temp_normals) { + Vec3 norm = n.normalize(); + v_norm.insert(v_norm.end(), {norm.x, norm.y, norm.z}); + } + for (auto& face : raw_faces) { + face.vn[0] = face.v[0]; + face.vn[1] = face.v[1]; + face.vn[2] = face.v[2]; } + } - if (v_norm.empty() && !v_pos.empty()) { - std::vector<Vec3> temp_normals(v_pos.size() / 3, {0,0,0}); - for(auto& face : raw_faces) { - int i0=face.v[0]-1, i1=face.v[1]-1, i2=face.v[2]-1; - Vec3 p0={v_pos[i0*3],v_pos[i0*3+1],v_pos[i0*3+2]}; - Vec3 p1={v_pos[i1*3],v_pos[i1*3+1],v_pos[i1*3+2]}; - Vec3 p2={v_pos[i2*3],v_pos[i2*3+1],v_pos[i2*3+2]}; - Vec3 n = Vec3::cross(p1-p0, p2-p0).normalize(); - temp_normals[i0] += n; temp_normals[i1] += n; temp_normals[i2] += n; + for (const auto& face : raw_faces) { + for (int i = 0; i < 3; ++i) { + char key_buf[128]; + snprintf(key_buf, sizeof(key_buf), "%d/%d/%d", face.v[i], face.vt[i], + face.vn[i]); + std::string key = key_buf; + if (vertex_map.find(key) == vertex_map.end()) { + vertex_map[key] = (uint32_t)final_vertices.size(); + MeshVertex v = {}; + if (face.v[i] > 0) { + v.p[0] = v_pos[(face.v[i] - 1) * 3]; + v.p[1] = v_pos[(face.v[i] - 1) * 3 + 1]; + v.p[2] = v_pos[(face.v[i] - 1) * 3 + 2]; } - for(const auto& n : temp_normals) { - Vec3 norm = n.normalize(); - v_norm.insert(v_norm.end(), {norm.x, norm.y, norm.z}); + if (face.vn[i] > 0) { + v.n[0] = v_norm[(face.vn[i] - 1) * 3]; + v.n[1] = v_norm[(face.vn[i] - 1) * 3 + 1]; + v.n[2] = v_norm[(face.vn[i] - 1) * 3 + 2]; } - for(auto& face : raw_faces) { - face.vn[0]=face.v[0]; face.vn[1]=face.v[1]; face.vn[2]=face.v[2]; + if (face.vt[i] > 0) { + v.u[0] = v_uv[(face.vt[i] - 1) * 2]; + v.u[1] = v_uv[(face.vt[i] - 1) * 2 + 1]; } + final_vertices.push_back(v); + } + final_indices.push_back(vertex_map[key]); } + } - for (const auto& face : raw_faces) { - for (int i=0; i<3; ++i) { - char key_buf[128]; - snprintf(key_buf, sizeof(key_buf), "%d/%d/%d", face.v[i], face.vt[i], face.vn[i]); - std::string key = key_buf; - if (vertex_map.find(key) == vertex_map.end()) { - vertex_map[key] = (uint32_t)final_vertices.size(); - MeshVertex v = {}; - if(face.v[i]>0) { v.p[0]=v_pos[(face.v[i]-1)*3]; v.p[1]=v_pos[(face.v[i]-1)*3+1]; v.p[2]=v_pos[(face.v[i]-1)*3+2]; } - if(face.vn[i]>0) { v.n[0]=v_norm[(face.vn[i]-1)*3]; v.n[1]=v_norm[(face.vn[i]-1)*3+1]; v.n[2]=v_norm[(face.vn[i]-1)*3+2]; } - if(face.vt[i]>0) { v.u[0]=v_uv[(face.vt[i]-1)*2]; v.u[1]=v_uv[(face.vt[i]-1)*2+1]; } - final_vertices.push_back(v); - } - final_indices.push_back(vertex_map[key]); - } - } + if (final_vertices.empty()) + return false; - if (final_vertices.empty()) return false; + // Calculate AABB and center the mesh + float min_x = 1e10f, min_y = 1e10f, min_z = 1e10f; + float max_x = -1e10f, max_y = -1e10f, max_z = -1e10f; + for (const auto& v : final_vertices) { + min_x = std::min(min_x, v.p[0]); + min_y = std::min(min_y, v.p[1]); + min_z = std::min(min_z, v.p[2]); + max_x = std::max(max_x, v.p[0]); + max_y = std::max(max_y, v.p[1]); + max_z = std::max(max_z, v.p[2]); + } + float cx = (min_x + max_x) * 0.5f; + float cy = (min_y + max_y) * 0.5f; + float cz = (min_z + max_z) * 0.5f; + for (auto& v : final_vertices) { + v.p[0] -= cx; + v.p[1] -= cy; + v.p[2] -= cz; + } + out_obj.local_extent = vec3((max_x - min_x) * 0.5f, (max_y - min_y) * 0.5f, + (max_z - min_z) * 0.5f); - // Calculate AABB and center the mesh - float min_x = 1e10f, min_y = 1e10f, min_z = 1e10f; - float max_x = -1e10f, max_y = -1e10f, max_z = -1e10f; - for (const auto& v : final_vertices) { - min_x = std::min(min_x, v.p[0]); min_y = std::min(min_y, v.p[1]); min_z = std::min(min_z, v.p[2]); - max_x = std::max(max_x, v.p[0]); max_y = std::max(max_y, v.p[1]); max_z = std::max(max_z, v.p[2]); - } - float cx = (min_x + max_x) * 0.5f; - float cy = (min_y + max_y) * 0.5f; - float cz = (min_z + max_z) * 0.5f; - for (auto& v : final_vertices) { - v.p[0] -= cx; v.p[1] -= cy; v.p[2] -= cz; - } - out_obj.local_extent = vec3((max_x - min_x) * 0.5f, (max_y - min_y) * 0.5f, (max_z - min_z) * 0.5f); - - g_mesh_gpu_data.num_indices = final_indices.size(); - g_mesh_gpu_data.vertex_buffer = gpu_create_buffer(g_device, final_vertices.size() * sizeof(MeshVertex), WGPUBufferUsage_Vertex | WGPUBufferUsage_CopyDst, final_vertices.data()).buffer; - g_mesh_gpu_data.index_buffer = gpu_create_buffer(g_device, final_indices.size() * sizeof(uint32_t), WGPUBufferUsage_Index | WGPUBufferUsage_CopyDst, final_indices.data()).buffer; - - struct MeshData { - std::vector<MeshVertex> vertices; - std::vector<uint32_t> indices; - }; - MeshData* mesh_data = new MeshData(); - mesh_data->vertices = final_vertices; - mesh_data->indices = final_indices; + g_mesh_gpu_data.num_indices = final_indices.size(); + g_mesh_gpu_data.vertex_buffer = + gpu_create_buffer(g_device, final_vertices.size() * sizeof(MeshVertex), + WGPUBufferUsage_Vertex | WGPUBufferUsage_CopyDst, + final_vertices.data()) + .buffer; + g_mesh_gpu_data.index_buffer = + gpu_create_buffer(g_device, final_indices.size() * sizeof(uint32_t), + WGPUBufferUsage_Index | WGPUBufferUsage_CopyDst, + final_indices.data()) + .buffer; - out_obj.type = ObjectType::MESH; - out_obj.user_data = mesh_data; + struct MeshData { + std::vector<MeshVertex> vertices; + std::vector<uint32_t> indices; + }; + MeshData* mesh_data = new MeshData(); + mesh_data->vertices = final_vertices; + mesh_data->indices = final_indices; - // This test doesn't use the asset system, so we override the renderer's internal cache lookup - // by manually setting the buffers on the renderer object. This is a HACK for this specific tool. - g_renderer.override_mesh_buffers(&g_mesh_gpu_data); + out_obj.type = ObjectType::MESH; + out_obj.user_data = mesh_data; - return true; -} + // This test doesn't use the asset system, so we override the renderer's + // internal cache lookup by manually setting the buffers on the renderer + // object. This is a HACK for this specific tool. + g_renderer.override_mesh_buffers(&g_mesh_gpu_data); + return true; +} int main(int argc, char** argv) { if (argc < 2) { @@ -270,7 +324,7 @@ int main(int argc, char** argv) { bool debug_mode = (argc > 2 && strcmp(argv[2], "--debug") == 0); printf("Loading mesh: %s\n", obj_path); - + PlatformState platform_state = platform_init(false, 1280, 720); WGPUInstance instance = wgpuCreateInstance(nullptr); @@ -287,7 +341,8 @@ int main(int argc, char** argv) { g_textures.init(g_device, g_queue); ProceduralTextureDef noise_def; - noise_def.width=256; noise_def.height=256; + noise_def.width = 256; + noise_def.height = 256; noise_def.gen_func = procedural::gen_noise; noise_def.params = {1234.0f, 16.0f}; g_textures.create_procedural_texture("noise", noise_def); @@ -302,13 +357,13 @@ int main(int argc, char** argv) { Object3D mesh_obj; if (!load_obj_and_create_buffers(obj_path, mesh_obj)) { - printf("Failed to load or process OBJ file.\n"); - return 1; + printf("Failed to load or process OBJ file.\n"); + return 1; } mesh_obj.color = vec4(1.0f, 0.7f, 0.2f, 1.0f); mesh_obj.position = {0, 1.5, 0}; // Elevate a bit more g_scene.add_object(mesh_obj); - + g_camera.position = vec3(0, 3, 5); g_camera.target = vec3(0, 1.5, 0); @@ -317,31 +372,42 @@ int main(int argc, char** argv) { float time = (float)platform_state.time; g_camera.aspect_ratio = platform_state.aspect_ratio; - + g_scene.objects[1].rotation = quat::from_axis({0.5f, 1.0f, 0.0f}, time); #if !defined(STRIP_ALL) if (debug_mode) { - struct MeshData { - std::vector<MeshVertex> vertices; - std::vector<uint32_t> indices; - }; - auto* data = (MeshData*)g_scene.objects[1].user_data; - VisualDebug& dbg = g_renderer.GetVisualDebug(); - dbg.add_mesh_normals(g_scene.objects[1].get_model_matrix(), (uint32_t)data->vertices.size(), data->vertices.data()); - dbg.add_mesh_wireframe(g_scene.objects[1].get_model_matrix(), (uint32_t)data->vertices.size(), data->vertices.data(), (uint32_t)data->indices.size(), data->indices.data(), vec3(0.0f, 1.0f, 1.0f)); + struct MeshData { + std::vector<MeshVertex> vertices; + std::vector<uint32_t> indices; + }; + auto* data = (MeshData*)g_scene.objects[1].user_data; + VisualDebug& dbg = g_renderer.GetVisualDebug(); + dbg.add_mesh_normals(g_scene.objects[1].get_model_matrix(), + (uint32_t)data->vertices.size(), + data->vertices.data()); + dbg.add_mesh_wireframe(g_scene.objects[1].get_model_matrix(), + (uint32_t)data->vertices.size(), + data->vertices.data(), + (uint32_t)data->indices.size(), + data->indices.data(), vec3(0.0f, 1.0f, 1.0f)); } #endif /* !defined(STRIP_ALL) */ WGPUSurfaceTexture surface_tex; wgpuSurfaceGetCurrentTexture(g_surface, &surface_tex); - if (surface_tex.status == WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal) { // WGPUSurfaceGetCurrentTextureStatus_Success is 0 - WGPUTextureView view = wgpuTextureCreateView(surface_tex.texture, nullptr); + if (surface_tex.status == + WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal) { // WGPUSurfaceGetCurrentTextureStatus_Success + // is 0 + WGPUTextureView view = + wgpuTextureCreateView(surface_tex.texture, nullptr); g_renderer.render(g_scene, g_camera, time, view); wgpuTextureViewRelease(view); wgpuSurfacePresent(g_surface); } - wgpuTextureRelease(surface_tex.texture); // Release here, after present, outside the if block + wgpuTextureRelease( + surface_tex + .texture); // Release here, after present, outside the if block } #if !defined(STRIP_ALL) @@ -349,8 +415,8 @@ int main(int argc, char** argv) { #endif struct MeshData { - std::vector<MeshVertex> vertices; - std::vector<uint32_t> indices; + std::vector<MeshVertex> vertices; + std::vector<uint32_t> indices; }; delete (MeshData*)g_scene.objects[1].user_data; wgpuBufferRelease(g_mesh_gpu_data.vertex_buffer); diff --git a/src/tests/test_post_process_helper.cc b/src/tests/test_post_process_helper.cc index c1c5591..c009bc2 100644 --- a/src/tests/test_post_process_helper.cc +++ b/src/tests/test_post_process_helper.cc @@ -2,12 +2,12 @@ // It tests post-processing helper functions (pipeline and bind group creation). // Validates that helpers can create valid WebGPU resources. -#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary +#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary -#include "webgpu_test_fixture.h" -#include "offscreen_render_target.h" #include "gpu/demo_effects.h" #include "gpu/gpu.h" +#include "offscreen_render_target.h" +#include "webgpu_test_fixture.h" #include <cassert> #include <cstdio> @@ -16,16 +16,18 @@ extern WGPURenderPipeline create_post_process_pipeline(WGPUDevice device, WGPUTextureFormat format, const char* shader_code); extern void pp_update_bind_group(WGPUDevice device, WGPURenderPipeline pipeline, - WGPUBindGroup* bind_group, WGPUTextureView input_view, + WGPUBindGroup* bind_group, + WGPUTextureView input_view, GpuBuffer uniforms); -// Helper: Create a texture suitable for post-processing (both render target and texture binding) -static WGPUTexture create_post_process_texture(WGPUDevice device, int width, int height, +// Helper: Create a texture suitable for post-processing (both render target and +// texture binding) +static WGPUTexture create_post_process_texture(WGPUDevice device, int width, + int height, WGPUTextureFormat format) { const WGPUTextureDescriptor texture_desc = { .usage = WGPUTextureUsage_RenderAttachment | - WGPUTextureUsage_TextureBinding | - WGPUTextureUsage_CopySrc, + WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopySrc, .dimension = WGPUTextureDimension_2D, .size = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1}, .format = format, @@ -36,7 +38,8 @@ static WGPUTexture create_post_process_texture(WGPUDevice device, int width, int } // Helper: Create texture view -static WGPUTextureView create_texture_view(WGPUTexture texture, WGPUTextureFormat format) { +static WGPUTextureView create_texture_view(WGPUTexture texture, + WGPUTextureFormat format) { const WGPUTextureViewDescriptor view_desc = { .format = format, .dimension = WGPUTextureViewDimension_2D, @@ -105,24 +108,26 @@ static void test_bind_group_creation() { assert(pipeline != nullptr && "Pipeline required for bind group test"); // Create input texture with TEXTURE_BINDING usage - WGPUTexture input_texture = create_post_process_texture( - fixture.device(), 256, 256, fixture.format()); - WGPUTextureView input_view = create_texture_view(input_texture, fixture.format()); + WGPUTexture input_texture = + create_post_process_texture(fixture.device(), 256, 256, fixture.format()); + WGPUTextureView input_view = + create_texture_view(input_texture, fixture.format()); // Create uniform buffer const WGPUBufferDescriptor uniform_desc = { .usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst, - .size = 16, // vec4<f32> + .size = 16, // vec4<f32> }; - WGPUBuffer uniform_buffer = wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc); + WGPUBuffer uniform_buffer = + wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc); assert(uniform_buffer != nullptr && "Uniform buffer should be created"); GpuBuffer uniforms = {uniform_buffer, 16}; // Test bind group creation WGPUBindGroup bind_group = nullptr; - pp_update_bind_group(fixture.device(), pipeline, &bind_group, - input_view, uniforms); + pp_update_bind_group(fixture.device(), pipeline, &bind_group, input_view, + uniforms); assert(bind_group != nullptr && "Bind group should be created successfully"); fprintf(stdout, " ✓ Bind group created successfully\n"); @@ -149,31 +154,32 @@ static void test_bind_group_update() { WGPURenderPipeline pipeline = create_post_process_pipeline( fixture.device(), fixture.format(), test_shader); - WGPUTexture texture1 = create_post_process_texture( - fixture.device(), 256, 256, fixture.format()); + WGPUTexture texture1 = + create_post_process_texture(fixture.device(), 256, 256, fixture.format()); WGPUTextureView view1 = create_texture_view(texture1, fixture.format()); - WGPUTexture texture2 = create_post_process_texture( - fixture.device(), 512, 512, fixture.format()); + WGPUTexture texture2 = + create_post_process_texture(fixture.device(), 512, 512, fixture.format()); WGPUTextureView view2 = create_texture_view(texture2, fixture.format()); const WGPUBufferDescriptor uniform_desc = { .usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst, .size = 16, }; - WGPUBuffer uniform_buffer = wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc); + WGPUBuffer uniform_buffer = + wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc); GpuBuffer uniforms = {uniform_buffer, 16}; // Create initial bind group WGPUBindGroup bind_group = nullptr; - pp_update_bind_group(fixture.device(), pipeline, &bind_group, - view1, uniforms); + pp_update_bind_group(fixture.device(), pipeline, &bind_group, view1, + uniforms); assert(bind_group != nullptr && "Initial bind group should be created"); fprintf(stdout, " ✓ Initial bind group created\n"); // Update bind group (should release old and create new) - pp_update_bind_group(fixture.device(), pipeline, &bind_group, - view2, uniforms); + pp_update_bind_group(fixture.device(), pipeline, &bind_group, view2, + uniforms); assert(bind_group != nullptr && "Updated bind group should be created"); fprintf(stdout, " ✓ Bind group updated successfully\n"); @@ -204,31 +210,35 @@ static void test_full_setup() { assert(pipeline != nullptr && "Pipeline creation failed"); // Create input texture (with TEXTURE_BINDING usage) - WGPUTexture input_texture = create_post_process_texture( - fixture.device(), 256, 256, fixture.format()); - WGPUTextureView input_view = create_texture_view(input_texture, fixture.format()); + WGPUTexture input_texture = + create_post_process_texture(fixture.device(), 256, 256, fixture.format()); + WGPUTextureView input_view = + create_texture_view(input_texture, fixture.format()); // Create output texture (can use OffscreenRenderTarget for this) - OffscreenRenderTarget output_target(fixture.instance(), fixture.device(), 256, 256); + OffscreenRenderTarget output_target(fixture.instance(), fixture.device(), 256, + 256); const WGPUBufferDescriptor uniform_desc = { .usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst, .size = 16, }; - WGPUBuffer uniform_buffer = wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc); + WGPUBuffer uniform_buffer = + wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc); GpuBuffer uniforms = {uniform_buffer, 16}; // Create bind group WGPUBindGroup bind_group = nullptr; - pp_update_bind_group(fixture.device(), pipeline, &bind_group, - input_view, uniforms); + pp_update_bind_group(fixture.device(), pipeline, &bind_group, input_view, + uniforms); assert(bind_group != nullptr && "Bind group creation failed"); fprintf(stdout, " ✓ Pipeline and bind group ready\n"); // Test render pass setup (smoke test - just verify we can create a pass) const WGPUCommandEncoderDescriptor enc_desc = {}; - WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(fixture.device(), &enc_desc); + WGPUCommandEncoder encoder = + wgpuDeviceCreateCommandEncoder(fixture.device(), &enc_desc); WGPURenderPassColorAttachment color_attachment = {}; gpu_init_color_attachment(color_attachment, output_target.view()); @@ -237,7 +247,8 @@ static void test_full_setup() { pass_desc.colorAttachmentCount = 1; pass_desc.colorAttachments = &color_attachment; - WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); + WGPURenderPassEncoder pass = + wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); // Set pipeline and bind group wgpuRenderPassEncoderSetPipeline(pass, pipeline); @@ -277,4 +288,4 @@ int main() { return 0; } -#endif /* !defined(STRIP_ALL) */ +#endif /* !defined(STRIP_ALL) */ diff --git a/src/tests/test_scene_loader.cc b/src/tests/test_scene_loader.cc index e14054b..21bcbaa 100644 --- a/src/tests/test_scene_loader.cc +++ b/src/tests/test_scene_loader.cc @@ -1,107 +1,134 @@ #include "3d/scene_loader.h" -#include "util/mini_math.h" -#include "util/asset_manager.h" #include "generated/assets.h" +#include "util/asset_manager.h" +#include "util/mini_math.h" +#include <cassert> #include <cstdio> #include <cstring> #include <vector> -#include <cassert> int main() { - Scene scene; - std::vector<uint8_t> buffer; - - // Header - const char* magic = "SCN1"; - for(int i=0; i<4; ++i) buffer.push_back(magic[i]); - - uint32_t num_obj = 2; // Increased to 2 - uint32_t num_cam = 0; - uint32_t num_light = 0; - - auto push_u32 = [&](uint32_t v) { - uint8_t* p = (uint8_t*)&v; - for(int i=0; i<4; ++i) buffer.push_back(p[i]); - }; - auto push_f = [&](float v) { - uint8_t* p = (uint8_t*)&v; - for(int i=0; i<4; ++i) buffer.push_back(p[i]); - }; - - push_u32(num_obj); - push_u32(num_cam); - push_u32(num_light); - - // --- Object 1: Basic Cube --- - char name1[64] = {0}; - std::strcpy(name1, "TestObject"); - for(int i=0; i<64; ++i) buffer.push_back(name1[i]); - - push_u32(0); // CUBE - - // Pos - push_f(1.0f); push_f(2.0f); push_f(3.0f); - // Rot (0,0,0,1) - push_f(0.0f); push_f(0.0f); push_f(0.0f); push_f(1.0f); - // Scale - push_f(1.0f); push_f(1.0f); push_f(1.0f); - // Color - push_f(1.0f); push_f(0.0f); push_f(0.0f); push_f(1.0f); - - // Mesh Name length 0 - push_u32(0); - - // Physics - push_f(10.0f); // mass - push_f(0.8f); // restitution - push_u32(1); // static - - // --- Object 2: Mesh with Asset Ref --- - char name2[64] = {0}; - std::strcpy(name2, "MeshObject"); - for(int i=0; i<64; ++i) buffer.push_back(name2[i]); - - push_u32(6); // MESH - - // Pos - push_f(0.0f); push_f(0.0f); push_f(0.0f); - // Rot - push_f(0.0f); push_f(0.0f); push_f(0.0f); push_f(1.0f); - // Scale - push_f(1.0f); push_f(1.0f); push_f(1.0f); - // Color - push_f(0.0f); push_f(1.0f); push_f(0.0f); push_f(1.0f); - - // Mesh Name "MESH_CUBE" - const char* mesh_name = "MESH_CUBE"; - uint32_t mesh_name_len = std::strlen(mesh_name); - push_u32(mesh_name_len); - for(size_t i=0; i<mesh_name_len; ++i) buffer.push_back(mesh_name[i]); - - // Physics - push_f(1.0f); - push_f(0.5f); - push_u32(0); // dynamic - - // --- Load --- - if (SceneLoader::LoadScene(scene, buffer.data(), buffer.size())) { - printf("Scene loaded successfully.\n"); - assert(scene.objects.size() == 2); - - // Check Obj 1 - assert(scene.objects[0].type == ObjectType::CUBE); - assert(scene.objects[0].position.x == 1.0f); - assert(scene.objects[0].is_static == true); - - // Check Obj 2 - assert(scene.objects[1].type == ObjectType::MESH); - assert(scene.objects[1].mesh_asset_id == AssetId::ASSET_MESH_CUBE); - printf("Mesh Asset ID resolved to: %d (Expected %d)\n", (int)scene.objects[1].mesh_asset_id, (int)AssetId::ASSET_MESH_CUBE); - - } else { - printf("Scene load failed.\n"); - return 1; - } - - return 0; + Scene scene; + std::vector<uint8_t> buffer; + + // Header + const char* magic = "SCN1"; + for (int i = 0; i < 4; ++i) + buffer.push_back(magic[i]); + + uint32_t num_obj = 2; // Increased to 2 + uint32_t num_cam = 0; + uint32_t num_light = 0; + + auto push_u32 = [&](uint32_t v) { + uint8_t* p = (uint8_t*)&v; + for (int i = 0; i < 4; ++i) + buffer.push_back(p[i]); + }; + auto push_f = [&](float v) { + uint8_t* p = (uint8_t*)&v; + for (int i = 0; i < 4; ++i) + buffer.push_back(p[i]); + }; + + push_u32(num_obj); + push_u32(num_cam); + push_u32(num_light); + + // --- Object 1: Basic Cube --- + char name1[64] = {0}; + std::strcpy(name1, "TestObject"); + for (int i = 0; i < 64; ++i) + buffer.push_back(name1[i]); + + push_u32(0); // CUBE + + // Pos + push_f(1.0f); + push_f(2.0f); + push_f(3.0f); + // Rot (0,0,0,1) + push_f(0.0f); + push_f(0.0f); + push_f(0.0f); + push_f(1.0f); + // Scale + push_f(1.0f); + push_f(1.0f); + push_f(1.0f); + // Color + push_f(1.0f); + push_f(0.0f); + push_f(0.0f); + push_f(1.0f); + + // Mesh Name length 0 + push_u32(0); + + // Physics + push_f(10.0f); // mass + push_f(0.8f); // restitution + push_u32(1); // static + + // --- Object 2: Mesh with Asset Ref --- + char name2[64] = {0}; + std::strcpy(name2, "MeshObject"); + for (int i = 0; i < 64; ++i) + buffer.push_back(name2[i]); + + push_u32(6); // MESH + + // Pos + push_f(0.0f); + push_f(0.0f); + push_f(0.0f); + // Rot + push_f(0.0f); + push_f(0.0f); + push_f(0.0f); + push_f(1.0f); + // Scale + push_f(1.0f); + push_f(1.0f); + push_f(1.0f); + // Color + push_f(0.0f); + push_f(1.0f); + push_f(0.0f); + push_f(1.0f); + + // Mesh Name "MESH_CUBE" + const char* mesh_name = "MESH_CUBE"; + uint32_t mesh_name_len = std::strlen(mesh_name); + push_u32(mesh_name_len); + for (size_t i = 0; i < mesh_name_len; ++i) + buffer.push_back(mesh_name[i]); + + // Physics + push_f(1.0f); + push_f(0.5f); + push_u32(0); // dynamic + + // --- Load --- + if (SceneLoader::LoadScene(scene, buffer.data(), buffer.size())) { + printf("Scene loaded successfully.\n"); + assert(scene.objects.size() == 2); + + // Check Obj 1 + assert(scene.objects[0].type == ObjectType::CUBE); + assert(scene.objects[0].position.x == 1.0f); + assert(scene.objects[0].is_static == true); + + // Check Obj 2 + assert(scene.objects[1].type == ObjectType::MESH); + assert(scene.objects[1].mesh_asset_id == AssetId::ASSET_MESH_CUBE); + printf("Mesh Asset ID resolved to: %d (Expected %d)\n", + (int)scene.objects[1].mesh_asset_id, (int)AssetId::ASSET_MESH_CUBE); + + } else { + printf("Scene load failed.\n"); + return 1; + } + + return 0; } diff --git a/src/tests/test_sequence.cc b/src/tests/test_sequence.cc index e00e606..d79ec1d 100644 --- a/src/tests/test_sequence.cc +++ b/src/tests/test_sequence.cc @@ -70,8 +70,7 @@ class DummyPostProcessEffect : public PostProcessEffect { int render_calls = 0; int update_bind_group_calls = 0; - DummyPostProcessEffect(const GpuContext& ctx) - : PostProcessEffect(ctx) { + DummyPostProcessEffect(const GpuContext& ctx) : PostProcessEffect(ctx) { } void init(MainSequence* demo) override { diff --git a/src/tests/test_shader_compilation.cc b/src/tests/test_shader_compilation.cc index fdd71b8..e2c0adc 100644 --- a/src/tests/test_shader_compilation.cc +++ b/src/tests/test_shader_compilation.cc @@ -107,13 +107,12 @@ static bool init_wgpu() { } // Test shader compilation -static bool test_shader_compilation(const char* name, - const char* shader_code) { +static bool test_shader_compilation(const char* name, const char* shader_code) { printf("Testing compilation: %s...\n", name); if (!g_device) { printf("SKIPPED: %s (no GPU device)\n", name); - return true; // Not a failure, just skipped + return true; // Not a failure, just skipped } #if defined(DEMO_CROSS_COMPILE_WIN32) @@ -145,7 +144,7 @@ static bool test_shader_compilation(const char* name, // Test composed shader with different modes static bool test_composed_shader(const char* base_name, AssetId asset_id, - bool with_bvh) { + bool with_bvh) { const char* mode_name = with_bvh ? "BVH" : "Linear"; char test_name[128]; snprintf(test_name, sizeof(test_name), "%s (%s mode)", base_name, mode_name); @@ -173,8 +172,7 @@ int main() { bool gpu_available = init_wgpu(); if (!gpu_available) { - printf( - "Note: GPU not available - running composition-only tests\n\n"); + printf("Note: GPU not available - running composition-only tests\n\n"); } // Initialize shader composer @@ -197,13 +195,13 @@ int main() { // Test 2: Composed shaders (both BVH and Linear modes) printf("\n--- Test 2: Composed Shaders (BVH Mode) ---\n"); all_passed &= test_composed_shader("Renderer 3D", - AssetId::ASSET_SHADER_RENDERER_3D, true); + AssetId::ASSET_SHADER_RENDERER_3D, true); all_passed &= test_composed_shader("Mesh Render", AssetId::ASSET_SHADER_MESH, true); printf("\n--- Test 3: Composed Shaders (Linear Mode) ---\n"); all_passed &= test_composed_shader("Renderer 3D", - AssetId::ASSET_SHADER_RENDERER_3D, false); + AssetId::ASSET_SHADER_RENDERER_3D, false); all_passed &= test_composed_shader("Mesh Render", AssetId::ASSET_SHADER_MESH, false); diff --git a/src/tests/test_spectral_brush.cc b/src/tests/test_spectral_brush.cc index 1431ba7..ae1862a 100644 --- a/src/tests/test_spectral_brush.cc +++ b/src/tests/test_spectral_brush.cc @@ -28,11 +28,11 @@ void test_bezier_linear_2points() { // Midpoint: linear interpolation const float mid = evaluate_bezier_linear(frames, values, 2, 50.0f); - assert(float_eq(mid, 100.0f)); // (50 + 150) / 2 + assert(float_eq(mid, 100.0f)); // (50 + 150) / 2 // Quarter point const float quarter = evaluate_bezier_linear(frames, values, 2, 25.0f); - assert(float_eq(quarter, 75.0f)); // 50 + (150 - 50) * 0.25 + assert(float_eq(quarter, 75.0f)); // 50 + (150 - 50) * 0.25 printf("[PASS] test_bezier_linear_2points\n"); } @@ -78,8 +78,10 @@ void test_bezier_edge_cases() { // Out of range: clamp to endpoints const float frames2[] = {10.0f, 90.0f}; const float values2[] = {100.0f, 200.0f}; - assert(float_eq(evaluate_bezier_linear(frames2, values2, 2, 0.0f), 100.0f)); // Before start - assert(float_eq(evaluate_bezier_linear(frames2, values2, 2, 100.0f), 200.0f)); // After end + assert(float_eq(evaluate_bezier_linear(frames2, values2, 2, 0.0f), + 100.0f)); // Before start + assert(float_eq(evaluate_bezier_linear(frames2, values2, 2, 100.0f), + 200.0f)); // After end printf("[PASS] test_bezier_edge_cases\n"); } @@ -98,7 +100,7 @@ void test_profile_gaussian() { // Far from center: should approach 0 const float far = evaluate_profile(PROFILE_GAUSSIAN, 100.0f, 30.0f, 0.0f); - assert(far < 0.01f); // Very small + assert(far < 0.01f); // Very small printf("[PASS] test_profile_gaussian\n"); } @@ -110,12 +112,14 @@ void test_profile_decaying_sinusoid() { // At center (distance = 0) // exp(-0 * 0.15) * cos(0 * 0.8) = 1.0 * 1.0 = 1.0 - assert(float_eq(evaluate_profile(PROFILE_DECAYING_SINUSOID, 0.0f, decay, omega), 1.0f)); + assert(float_eq( + evaluate_profile(PROFILE_DECAYING_SINUSOID, 0.0f, decay, omega), 1.0f)); // At distance 10 const float dist = 10.0f; const float expected = expf(-decay * dist) * cosf(omega * dist); - const float actual = evaluate_profile(PROFILE_DECAYING_SINUSOID, dist, decay, omega); + const float actual = + evaluate_profile(PROFILE_DECAYING_SINUSOID, dist, decay, omega); assert(float_eq(actual, expected)); printf("[PASS] test_profile_decaying_sinusoid\n"); @@ -127,12 +131,15 @@ void test_profile_noise() { const uint32_t seed = 42; // Same distance + seed should produce same value - const float val1 = evaluate_profile(PROFILE_NOISE, 10.0f, amplitude, (float)seed); - const float val2 = evaluate_profile(PROFILE_NOISE, 10.0f, amplitude, (float)seed); + const float val1 = + evaluate_profile(PROFILE_NOISE, 10.0f, amplitude, (float)seed); + const float val2 = + evaluate_profile(PROFILE_NOISE, 10.0f, amplitude, (float)seed); assert(float_eq(val1, val2)); // Different distance should produce different value (with high probability) - const float val3 = evaluate_profile(PROFILE_NOISE, 20.0f, amplitude, (float)seed); + const float val3 = + evaluate_profile(PROFILE_NOISE, 20.0f, amplitude, (float)seed); assert(!float_eq(val1, val3)); // Should be in range [0, amplitude] @@ -150,25 +157,25 @@ void test_draw_bezier_curve() { // Simple curve: constant frequency, linearly decaying amplitude const float frames[] = {0.0f, 100.0f}; - const float freqs[] = {440.0f, 440.0f}; // A4 note (constant pitch) - const float amps[] = {1.0f, 0.0f}; // Fade out + const float freqs[] = {440.0f, 440.0f}; // A4 note (constant pitch) + const float amps[] = {1.0f, 0.0f}; // Fade out - draw_bezier_curve(spectrogram, dct_size, num_frames, frames, freqs, amps, 2, PROFILE_GAUSSIAN, - 30.0f); + draw_bezier_curve(spectrogram, dct_size, num_frames, frames, freqs, amps, 2, + PROFILE_GAUSSIAN, 30.0f); // Verify: At frame 0, should have peak around 440 Hz bin // bin = (440 / 16000) * 512 ≈ 14.08 const int expected_bin = 14; const float val_at_peak = spectrogram[0 * dct_size + expected_bin]; - assert(val_at_peak > 0.5f); // Should be near 1.0 due to Gaussian + assert(val_at_peak > 0.5f); // Should be near 1.0 due to Gaussian // Verify: At frame 99 (end), amplitude should be near 0 const float val_at_end = spectrogram[99 * dct_size + expected_bin]; - assert(val_at_end < 0.1f); // Near zero + assert(val_at_end < 0.1f); // Near zero // Verify: At frame 50 (midpoint), amplitude should be ~0.5 const float val_at_mid = spectrogram[50 * dct_size + expected_bin]; - assert(val_at_mid > 0.3f && val_at_mid < 0.7f); // Around 0.5 + assert(val_at_mid > 0.3f && val_at_mid < 0.7f); // Around 0.5 printf("[PASS] test_draw_bezier_curve\n"); } @@ -184,20 +191,20 @@ void test_draw_bezier_curve_add() { const float frames1[] = {0.0f, 100.0f}; const float freqs1[] = {440.0f, 440.0f}; const float amps1[] = {0.5f, 0.5f}; - draw_bezier_curve(spectrogram, dct_size, num_frames, frames1, freqs1, amps1, 2, PROFILE_GAUSSIAN, - 30.0f); + draw_bezier_curve(spectrogram, dct_size, num_frames, frames1, freqs1, amps1, + 2, PROFILE_GAUSSIAN, 30.0f); - const int bin = 14; // ~440 Hz + const int bin = 14; // ~440 Hz const float val_before_add = spectrogram[0 * dct_size + bin]; // Add second curve (same frequency, same amplitude) - draw_bezier_curve_add(spectrogram, dct_size, num_frames, frames1, freqs1, amps1, 2, - PROFILE_GAUSSIAN, 30.0f); + draw_bezier_curve_add(spectrogram, dct_size, num_frames, frames1, freqs1, + amps1, 2, PROFILE_GAUSSIAN, 30.0f); const float val_after_add = spectrogram[0 * dct_size + bin]; // Should be approximately doubled - assert(val_after_add > val_before_add * 1.8f); // Allow small error + assert(val_after_add > val_before_add * 1.8f); // Allow small error printf("[PASS] test_draw_bezier_curve_add\n"); } diff --git a/src/tests/test_texture_manager.cc b/src/tests/test_texture_manager.cc index aa994cb..41d6919 100644 --- a/src/tests/test_texture_manager.cc +++ b/src/tests/test_texture_manager.cc @@ -2,7 +2,7 @@ // It tests the TextureManager for procedural texture generation and management. // Tests all public methods with both success and failure cases. -#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary +#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary #include "gpu/texture_manager.h" #include "procedural/generator.h" @@ -48,12 +48,12 @@ static void test_create_texture_from_data() { // Create 4x4 red texture (RGBA8) const int width = 4; const int height = 4; - uint8_t pixels[4 * 4 * 4]; // 4x4 RGBA + uint8_t pixels[4 * 4 * 4]; // 4x4 RGBA for (int i = 0; i < width * height; ++i) { - pixels[i * 4 + 0] = 255; // R - pixels[i * 4 + 1] = 0; // G - pixels[i * 4 + 2] = 0; // B - pixels[i * 4 + 3] = 255; // A + pixels[i * 4 + 0] = 255; // R + pixels[i * 4 + 1] = 0; // G + pixels[i * 4 + 2] = 0; // B + pixels[i * 4 + 3] = 255; // A } tm.create_texture("red_texture", width, height, pixels); @@ -84,7 +84,7 @@ static void test_create_procedural_texture() { noise_def.width = 64; noise_def.height = 64; noise_def.gen_func = procedural::gen_noise; - noise_def.params = {1234.0f, 1.0f}; // seed, frequency + noise_def.params = {1234.0f, 1.0f}; // seed, frequency tm.create_procedural_texture("noise", noise_def); @@ -137,18 +137,18 @@ static void test_multiple_textures() { // Fill green texture for (int i = 0; i < size * size; ++i) { - green_pixels[i * 4 + 0] = 0; // R - green_pixels[i * 4 + 1] = 255; // G - green_pixels[i * 4 + 2] = 0; // B - green_pixels[i * 4 + 3] = 255; // A + green_pixels[i * 4 + 0] = 0; // R + green_pixels[i * 4 + 1] = 255; // G + green_pixels[i * 4 + 2] = 0; // B + green_pixels[i * 4 + 3] = 255; // A } // Fill blue texture for (int i = 0; i < size * size; ++i) { - blue_pixels[i * 4 + 0] = 0; // R - blue_pixels[i * 4 + 1] = 0; // G - blue_pixels[i * 4 + 2] = 255; // B - blue_pixels[i * 4 + 3] = 255; // A + blue_pixels[i * 4 + 0] = 0; // R + blue_pixels[i * 4 + 1] = 0; // G + blue_pixels[i * 4 + 2] = 255; // B + blue_pixels[i * 4 + 3] = 255; // A } tm.create_texture("green", size, size, green_pixels); @@ -187,7 +187,7 @@ static void test_procedural_generation_failure() { (void)h; (void)params; (void)num_params; - return false; // Simulate failure + return false; // Simulate failure }; ProceduralTextureDef failing_def; @@ -258,4 +258,4 @@ int main() { return 0; } -#endif /* !defined(STRIP_ALL) */ +#endif /* !defined(STRIP_ALL) */ diff --git a/src/tests/test_wav_dump.cc b/src/tests/test_wav_dump.cc index a4afba0..880c8cd 100644 --- a/src/tests/test_wav_dump.cc +++ b/src/tests/test_wav_dump.cc @@ -3,8 +3,8 @@ #include "audio/audio.h" #include "audio/audio_engine.h" -#include "audio/ring_buffer.h" #include "audio/backend/wav_dump_backend.h" +#include "audio/ring_buffer.h" #include <assert.h> #include <stdio.h> #include <string.h> @@ -211,11 +211,11 @@ void test_clipping_detection() { // Mix of normal and clipped samples for (int i = 0; i < num_samples; ++i) { if (i % 10 == 0) { - test_samples[i] = 1.5f; // Clipped high + test_samples[i] = 1.5f; // Clipped high } else if (i % 10 == 1) { test_samples[i] = -1.2f; // Clipped low } else { - test_samples[i] = 0.5f; // Normal + test_samples[i] = 0.5f; // Normal } } @@ -275,7 +275,8 @@ void test_invalid_file_paths() { // Test 3: Read-only location (permissions error) { WavDumpBackend wav_backend; - wav_backend.set_output_file("/test.wav"); // Root directory (no write permission) + wav_backend.set_output_file( + "/test.wav"); // Root directory (no write permission) wav_backend.init(); // Should print error but not crash float samples[10] = {0.5f}; diff --git a/src/tests/webgpu_test_fixture.cc b/src/tests/webgpu_test_fixture.cc index 750dea0..980572a 100644 --- a/src/tests/webgpu_test_fixture.cc +++ b/src/tests/webgpu_test_fixture.cc @@ -2,7 +2,7 @@ // It implements shared WebGPU initialization for GPU tests. // Provides graceful fallback if GPU unavailable. -#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary +#if !defined(STRIP_ALL) // Test code only - zero size impact on final binary #include "webgpu_test_fixture.h" #include <cstdio> @@ -142,4 +142,4 @@ void WebGPUTestFixture::shutdown() { } } -#endif /* !defined(STRIP_ALL) */ +#endif /* !defined(STRIP_ALL) */ diff --git a/src/tests/webgpu_test_fixture.h b/src/tests/webgpu_test_fixture.h index fd08276..e10a2ed 100644 --- a/src/tests/webgpu_test_fixture.h +++ b/src/tests/webgpu_test_fixture.h @@ -22,14 +22,26 @@ class WebGPUTestFixture { void shutdown(); // Accessors - WGPUInstance instance() const { return instance_; } - WGPUDevice device() const { return device_; } - WGPUQueue queue() const { return queue_; } - WGPUTextureFormat format() const { return WGPUTextureFormat_BGRA8Unorm; } - GpuContext ctx() const { return {device_, queue_, format()}; } + WGPUInstance instance() const { + return instance_; + } + WGPUDevice device() const { + return device_; + } + WGPUQueue queue() const { + return queue_; + } + WGPUTextureFormat format() const { + return WGPUTextureFormat_BGRA8Unorm; + } + GpuContext ctx() const { + return {device_, queue_, format()}; + } // Check if fixture is ready - bool is_initialized() const { return device_ != nullptr; } + bool is_initialized() const { + return device_ != nullptr; + } private: WGPUInstance instance_ = nullptr; @@ -45,12 +57,9 @@ class WebGPUTestFixture { }; static void adapter_callback(WGPURequestAdapterStatus status, - WGPUAdapter adapter, - const char* message, - void* userdata); + WGPUAdapter adapter, const char* message, + void* userdata); - static void device_callback(WGPURequestDeviceStatus status, - WGPUDevice device, - const char* message, - void* userdata); + static void device_callback(WGPURequestDeviceStatus status, WGPUDevice device, + const char* message, void* userdata); }; |
