summaryrefslogtreecommitdiff
path: root/src/tests/test_3d_physics.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/test_3d_physics.cc')
-rw-r--r--src/tests/test_3d_physics.cc293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/tests/test_3d_physics.cc b/src/tests/test_3d_physics.cc
new file mode 100644
index 0000000..84be333
--- /dev/null
+++ b/src/tests/test_3d_physics.cc
@@ -0,0 +1,293 @@
+// This file is part of the 64k demo project.
+// Standalone "mini-demo" for testing the 3D physics engine.
+
+#include "3d/bvh.h"
+#include "3d/camera.h"
+#include "3d/object.h"
+#include "3d/physics.h"
+#include "3d/renderer.h"
+#include "3d/scene.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 <vector>
+
+// Global State
+static Renderer3D g_renderer;
+static TextureManager g_textures;
+static Scene g_scene;
+static Camera g_camera;
+static PhysicsSystem g_physics;
+static WGPUDevice g_device = nullptr;
+static WGPUQueue g_queue = nullptr;
+static WGPUSurface g_surface = nullptr;
+static WGPUAdapter g_adapter = nullptr;
+static WGPUTextureFormat g_format = WGPUTextureFormat_Undefined;
+
+// ... (init_wgpu implementation same as before)
+void init_wgpu(PlatformState* platform_state) {
+ WGPUInstance instance = wgpuCreateInstance(nullptr);
+ if (!instance) {
+ fprintf(stderr, "Failed to create WGPU instance.\n");
+ exit(1);
+ }
+
+ g_surface = platform_create_wgpu_surface(instance, platform_state);
+ if (!g_surface) {
+ fprintf(stderr, "Failed to create WGPU surface.\n");
+ exit(1);
+ }
+
+ WGPURequestAdapterOptions adapter_opts = {};
+ adapter_opts.compatibleSurface = g_surface;
+ adapter_opts.powerPreference = WGPUPowerPreference_HighPerformance;
+
+#if defined(DEMO_CROSS_COMPILE_WIN32)
+ auto on_adapter = [](WGPURequestAdapterStatus status, WGPUAdapter adapter,
+ const char* message, void* userdata) {
+ if (status == WGPURequestAdapterStatus_Success) {
+ *(WGPUAdapter*)userdata = adapter;
+ }
+ };
+ wgpuInstanceRequestAdapter(instance, &adapter_opts, on_adapter, &g_adapter);
+#else
+ auto on_adapter = [](WGPURequestAdapterStatus status, WGPUAdapter adapter,
+ WGPUStringView message, void* userdata, void* user2) {
+ (void)user2;
+ if (status == WGPURequestAdapterStatus_Success) {
+ *(WGPUAdapter*)userdata = adapter;
+ }
+ };
+ WGPURequestAdapterCallbackInfo adapter_cb = {};
+ adapter_cb.mode = WGPUCallbackMode_WaitAnyOnly;
+ adapter_cb.callback = on_adapter;
+ adapter_cb.userdata1 = &g_adapter;
+ wgpuInstanceRequestAdapter(instance, &adapter_opts, adapter_cb);
+#endif
+
+ while (!g_adapter) {
+ platform_wgpu_wait_any(instance);
+ }
+
+ WGPUDeviceDescriptor device_desc = {};
+
+#if defined(DEMO_CROSS_COMPILE_WIN32)
+ auto on_device = [](WGPURequestDeviceStatus status, WGPUDevice device,
+ const char* message, void* userdata) {
+ if (status == WGPURequestDeviceStatus_Success) {
+ *(WGPUDevice*)userdata = device;
+ }
+ };
+ wgpuAdapterRequestDevice(g_adapter, &device_desc, on_device, &g_device);
+#else
+ auto on_device = [](WGPURequestDeviceStatus status, WGPUDevice device,
+ WGPUStringView message, void* userdata, void* user2) {
+ (void)user2;
+ if (status == WGPURequestDeviceStatus_Success) {
+ *(WGPUDevice*)userdata = device;
+ }
+ };
+ WGPURequestDeviceCallbackInfo device_cb = {};
+ device_cb.mode = WGPUCallbackMode_WaitAnyOnly;
+ device_cb.callback = on_device;
+ device_cb.userdata1 = &g_device;
+ wgpuAdapterRequestDevice(g_adapter, &device_desc, device_cb);
+#endif
+
+ while (!g_device) {
+ platform_wgpu_wait_any(instance);
+ }
+
+ g_queue = wgpuDeviceGetQueue(g_device);
+
+ WGPUSurfaceCapabilities caps = {};
+ wgpuSurfaceGetCapabilities(g_surface, g_adapter, &caps);
+ g_format = caps.formats[0];
+
+ WGPUSurfaceConfiguration config = {};
+ config.device = g_device;
+ config.format = g_format;
+ config.usage = WGPUTextureUsage_RenderAttachment;
+ config.width = platform_state->width;
+ config.height = platform_state->height;
+ config.presentMode = WGPUPresentMode_Fifo;
+ config.alphaMode = WGPUCompositeAlphaMode_Opaque;
+ wgpuSurfaceConfigure(g_surface, &config);
+}
+
+void setup_scene() {
+ g_scene.clear();
+ srand(12345); // Fixed seed
+
+ // Large floor, use BOX type (SDF) at index 0
+ Object3D floor(ObjectType::BOX);
+ floor.position = vec3(0, -2.0f, 0);
+ floor.scale = vec3(25.0f, 0.2f, 25.0f);
+ floor.color = vec4(0.8f, 0.8f, 0.8f, 1.0f);
+ floor.is_static = true;
+ g_scene.add_object(floor);
+
+ // Large center Torus (SDF)
+ Object3D center(ObjectType::TORUS);
+ center.position = vec3(0, 1.0f, 0);
+ center.scale = vec3(2.5f, 2.5f, 2.5f);
+ center.color = vec4(1, 0.2, 0.2, 1);
+ center.is_static = false;
+ center.restitution = 0.8f;
+ g_scene.add_object(center);
+
+ // Moving Sphere (SDF)
+ Object3D sphere(ObjectType::SPHERE);
+ sphere.position = vec3(4.0f, 2.0f, 0);
+ sphere.scale = vec3(1.5f, 1.5f, 1.5f);
+ sphere.color = vec4(0.2, 1, 0.2, 1);
+ sphere.is_static = false;
+ sphere.velocity = vec3(-2.0f, 5.0f, 1.0f);
+ g_scene.add_object(sphere);
+
+ // Random objects
+ for (int i = 0; i < 30; ++i) {
+ ObjectType type = ObjectType::SPHERE;
+ int r = rand() % 3;
+ if (r == 1)
+ type = ObjectType::TORUS;
+ if (r == 2)
+ type = ObjectType::BOX;
+
+ Object3D obj(type);
+ float angle = (rand() % 360) * 0.01745f;
+ float dist = 3.0f + (rand() % 100) * 0.05f;
+ float height = 5.0f + (rand() % 100) * 0.04f; // Start higher
+ obj.position = vec3(std::cos(angle) * dist, height, std::sin(angle) * dist);
+
+ // Random non-uniform scale for debugging
+ float s = 0.6f + (rand() % 100) * 0.008f;
+ obj.scale = vec3(s, s * 1.2f, s * 0.8f);
+
+ obj.color = vec4((rand() % 100) / 100.0f, (rand() % 100) / 100.0f,
+ (rand() % 100) / 100.0f, 1.0f);
+ obj.is_static = false;
+ obj.velocity =
+ vec3((rand() % 100 - 50) * 0.01f, 0, (rand() % 100 - 50) * 0.01f);
+ g_scene.add_object(obj);
+ }
+}
+
+// Wrapper to generate periodic noise
+bool gen_periodic_noise(uint8_t* buffer, int w, int h, const float* params,
+ int num_params) {
+ if (!procedural::gen_noise(buffer, w, h, params, num_params))
+ return false;
+ float p_params[] = {0.1f}; // 10% overlap
+ return procedural::make_periodic(buffer, w, h, p_params, 1);
+}
+
+int main(int argc, char** argv) {
+ printf("Running 3D Physics Test...\n");
+
+#if !defined(STRIP_ALL)
+ for (int i = 1; i < argc; ++i) {
+ if (strcmp(argv[i], "--debug") == 0) {
+ Renderer3D::SetDebugEnabled(true);
+ }
+ }
+#else
+ (void)argc;
+ (void)argv;
+#endif
+
+ PlatformState platform_state = platform_init(false, 1280, 720);
+
+ // The test's own WGPU init sequence
+ init_wgpu(&platform_state);
+
+ InitShaderComposer();
+
+ g_renderer.init(g_device, g_queue, g_format);
+ g_renderer.resize(platform_state.width, platform_state.height);
+
+ g_textures.init(g_device, g_queue);
+ ProceduralTextureDef noise_def;
+ noise_def.width = 256;
+ noise_def.height = 256;
+ noise_def.gen_func = gen_periodic_noise;
+ 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"));
+
+ ProceduralTextureDef sky_def;
+ sky_def.width = 512;
+ sky_def.height = 256;
+ sky_def.gen_func = procedural::gen_perlin;
+ sky_def.params = {42.0f, 4.0f, 1.0f, 0.5f, 6.0f};
+ g_textures.create_procedural_texture("sky", sky_def);
+
+ g_renderer.set_sky_texture(g_textures.get_texture_view("sky"));
+
+ setup_scene();
+
+ g_camera.position = vec3(0, 5, 10);
+ g_camera.target = vec3(0, 0, 0);
+
+ while (!platform_should_close(&platform_state)) {
+ platform_poll(&platform_state);
+ 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_state.aspect_ratio;
+
+ static double last_time = 0;
+ float dt = (float)(platform_state.time - last_time);
+ if (dt > 0.1f)
+ dt = 0.1f; // Cap dt for stability
+ last_time = platform_state.time;
+
+ g_physics.update(g_scene, dt);
+
+ BVH bvh;
+ BVHBuilder::build(bvh, g_scene.objects);
+ for (const auto& node : bvh.nodes) {
+ g_renderer.add_debug_aabb({node.min_x, node.min_y, node.min_z},
+ {node.max_x, node.max_y, node.max_z},
+ {0.0f, 1.0f, 0.0f});
+ }
+
+#if !defined(STRIP_ALL)
+ Renderer3D::SetDebugEnabled(true);
+#endif
+
+ WGPUSurfaceTexture surface_tex;
+ wgpuSurfaceGetCurrentTexture(g_surface, &surface_tex);
+ if (surface_tex.status ==
+ WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal) {
+ const WGPUTextureViewDescriptor view_desc = {
+ .format = g_format,
+ .dimension = WGPUTextureViewDimension_2D,
+ .mipLevelCount = 1,
+ .arrayLayerCount = 1,
+ };
+
+ const WGPUTextureView view =
+ wgpuTextureCreateView(surface_tex.texture, &view_desc);
+ g_renderer.render(g_scene, g_camera, time, view);
+ wgpuTextureViewRelease(view);
+ wgpuSurfacePresent(g_surface);
+ wgpuTextureRelease(surface_tex.texture);
+ }
+ }
+
+ g_renderer.shutdown();
+ g_textures.shutdown();
+ platform_shutdown(&platform_state);
+ return 0;
+} \ No newline at end of file