// 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/renderer_helpers.h" #include "3d/scene.h" #include "gpu/effects/shaders.h" #include "gpu/texture_manager.h" #include "platform/platform.h" #include "procedural/generator.h" #include "../common/test_3d_helpers.h" #include #include #include #include // 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 WGPUTextureFormat g_format = WGPUTextureFormat_Undefined; 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); } if (strcmp(argv[i], "--no-bvh") == 0) { g_renderer.SetBvhEnabled(false); } } #else (void)argc; (void)argv; #endif PlatformState platform_state = platform_init(false, 1280, 720); WgpuSurfaceContext wgpu_ctx = init_wgpu_with_surface(&platform_state); g_device = wgpu_ctx.device; g_queue = wgpu_ctx.queue; g_surface = wgpu_ctx.surface; g_format = wgpu_ctx.format; InitShaderComposer(); g_renderer.init(g_device, g_queue, g_format); g_renderer.resize(platform_state.width, platform_state.height); setup_standard_textures(g_renderer, g_textures, g_device, g_queue); 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 WGPUTextureView view = gpu_create_texture_view_2d(surface_tex.texture, g_format); 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; }