From 9353bc3e077d47a6f10f6f11ddd0553ec34cc86c Mon Sep 17 00:00:00 2001 From: Daniel Bross Date: Sat, 19 Jul 2025 13:02:38 +0200 Subject: [PATCH] Added width to trigger line rendering, abstracted PhysX away a bit --- core/entity.jai | 70 +++++++++++---- module.jai | 1 + physics/physx.jai | 153 ++++++++++++++++++++++++++++----- renderer/line_rendering.jai | 89 +++++++++++++++++++ renderer/trigger_rendering.jai | 75 +++++----------- 5 files changed, 297 insertions(+), 91 deletions(-) create mode 100644 renderer/line_rendering.jai diff --git a/core/entity.jai b/core/entity.jai index 9cfd41b..ce2775b 100644 --- a/core/entity.jai +++ b/core/entity.jai @@ -1,20 +1,17 @@ Entity_Id :: #type, isa s64; Entity_Flags :: enum_flags u16 { - NONE; - RENDERABLE; - COLLISION; - PHYSICS; - STATIC; - TRIGGER; + NONE :: 0; + RENDERABLE :: 1; + PHYSICS :: 2; - ANIMATED; + ANIMATED :: 4; - SNAP_TO_GRID; - UNIFORM_SCALE; + SNAP_TO_GRID :: 8; + UNIFORM_SCALE :: 16; - DONT_SAVE; - DELETED; + DONT_SAVE :: 32; + DELETED :: 64; } Renderable_Type :: enum { @@ -53,6 +50,52 @@ Renderable :: struct { MAX_CHILDREN :: 16; +#if PHYSICS { + Collider_Type :: enum { + SPHERE; + BOX; + CAPSULE; + } + + Physics_Lock :: enum_flags u8 { + LINEAR_X; + LINEAR_Y; + LINEAR_Z; + ANGULAR_X; + ANGULAR_Y; + ANGULAR_Z; + } + + Physics_Body :: struct { + enabled: bool; + trigger: bool; + dynamic: bool; + velocity: Vector3; + + static_friction: float; + dynamic_friction: float; + restitution: float; + + lock: Physics_Lock; + + type: Collider_Type; + union { + sphere : struct { + radius: float; + } + box : struct { + half_extent: Vector3; + } + capsule : struct { + radius: float; + half_height: float; + } + } + + physx_handle: PhysX_Handle; + } +} + Entity :: struct { name: string; @@ -79,10 +122,7 @@ Entity :: struct { animator: Animator; @DontSerialize #if PHYSICS { - // Physics - physx_handle: PhysX_Handle; - velocity: Vector3; - // End physics + physics: Physics_Body; @DontSerialize } #if NETWORKING { diff --git a/module.jai b/module.jai index 0ac5cca..f2f1a49 100644 --- a/module.jai +++ b/module.jai @@ -83,6 +83,7 @@ coven_init :: (window_title: string, window_width: u32, window_height: u32, full init_input(); init_audio_system(); init_console(); + init_line_rendering(); #if PHYSICS { init_physx(); diff --git a/physics/physx.jai b/physics/physx.jai index ba44bd0..e0922e2 100644 --- a/physics/physx.jai +++ b/physics/physx.jai @@ -1,4 +1,5 @@ -PHYSX_DEFAULT_SHAPE_FLAGS :: cast(u8)(PhysX.PxShapeFlags.Visualization | PhysX.PxShapeFlags.SceneQueryShape | PhysX.PxShapeFlags.SimulationShape); +PHYSX_DEFAULT_SIMULATION_SHAPE_FLAGS :: cast(u8)(PhysX.PxShapeFlags.Visualization | PhysX.PxShapeFlags.SceneQueryShape | PhysX.PxShapeFlags.SimulationShape); +PHYSX_DEFAULT_TRIGGER_SHAPE_FLAGS :: cast(u8)(PhysX.PxShapeFlags.Visualization | PhysX.PxShapeFlags.SceneQueryShape | PhysX.PxShapeFlags.TriggerShape); PhysX_Handle :: #type, distinct u32; @@ -44,6 +45,33 @@ init_physx :: () { dispatcher = PhysX.PxDefaultCpuDispatcherCreate(2); material = PhysX.PxPhysics_createMaterial(physics, 0.0, 0.0, 0.6); + + // Callbacks + info : PhysX.SimulationEventCallbackInfo; + info.triggerCallback = on_physx_trigger; + event_callback = PhysX.create_simulation_event_callbacks(*info); +} + +internal_on_trigger_enter :: (trigger: *Entity, other: *Entity) { + print("% entered by %\n", trigger.type, other.type); +} + +internal_on_trigger_exit :: (trigger: *Entity, other: *Entity) { + print("% exited by %\n", trigger.type, other.type); +} + +on_physx_trigger :: (_u: *void, pair: *PhysX.PxTriggerPair, count: u32) #c_call { + push_context { + trigger := cast(*Entity)pair.triggerActor.userData; + other := cast(*Entity)pair.otherActor.userData; + + status := cast(PhysX.PxPairFlags)pair.status; + if status & .NotifyTouchFound { + internal_on_trigger_enter(trigger, other); + } else if status & .NotifyTouchLost { + internal_on_trigger_exit(trigger, other); + } + } } tick_physx :: (scene: *PhysX_Scene, dt: float) { @@ -60,6 +88,7 @@ init_physx_scene :: (game_scene: *Scene) { scene_desc.gravity.y = -9.81; scene_desc.cpuDispatcher = xx dispatcher; + scene_desc.simulationEventCallback = event_callback; PhysX.set_default_filter_shader(*scene_desc); scene := PhysX.PxPhysics_createScene(physics, *scene_desc); @@ -86,11 +115,15 @@ deinit_physx_scene :: (game_scene: *Scene) { pre_physx_sync :: (game_scene: *Scene) { for game_scene.entities { - if it.physx_handle != 0 { - // @Incomplete: Update the transform! - physx_actor := parray_get(*game_scene.physx_scene.actors, it.physx_handle); - if physx_actor.type == .DYNAMIC { - PhysX.PxRigidDynamic_setLinearVelocity(physx_actor.dynamic, *it.velocity, true); + if it.flags & .PHYSICS { + if it.physics.physx_handle != 0 { + // @Incomplete: Update the transform! + physx_actor := parray_get(*game_scene.physx_scene.actors, it.physics.physx_handle); + if physx_actor.type == .DYNAMIC { + PhysX.PxRigidDynamic_setLinearVelocity(physx_actor.dynamic, *it.physics.velocity, true); + } + } else { + create_physx_actor(it); } } } @@ -98,33 +131,106 @@ pre_physx_sync :: (game_scene: *Scene) { post_physx_sync :: (game_scene: *Scene) { for game_scene.entities { - if it.physx_handle != 0 { - physx_actor := parray_get(*game_scene.physx_scene.actors, it.physx_handle); - if physx_actor.type == .DYNAMIC { - vel := PhysX.PxRigidDynamic_getLinearVelocity(physx_actor.dynamic); - it.velocity = vel; + if it.flags & .PHYSICS { + if it.physics.physx_handle != 0 { + physx_actor := parray_get(*game_scene.physx_scene.actors, it.physics.physx_handle); + if physx_actor.type == .DYNAMIC { + vel := PhysX.PxRigidDynamic_getLinearVelocity(physx_actor.dynamic); + it.physics.velocity = vel; - transform := PhysX.PxRigidActor_getGlobalPose(physx_actor.dynamic); + transform := PhysX.PxRigidActor_getGlobalPose(physx_actor.dynamic); - if physx_actor.sync_rotation_from_physx { - set_position_rotation(it, transform.p, transform.q); - } else { - set_position(it, transform.p); + if physx_actor.sync_rotation_from_physx { + set_position_rotation(it, transform.p, transform.q); + } else { + set_position(it, transform.p); + } } } } } } +create_physx_actor :: (e: *Entity) { + actor : *PhysX.PxRigidActor; + transform : PhysX.PxTransform; + + if e.physics.type == .CAPSULE { + angle := PI * 0.5; + half_angle := angle * 0.5; + + sin_half := sin(half_angle); + cos_half := cos(half_angle); + + rotation := Quaternion.{0, 0, sin(-PI * 0.25), cos(-PI * 0.25)}; + transform = PhysX.PxTransform_new(*e.transform.position, *rotation); + } else { + transform = PhysX.PxTransform_new(*e.transform.position, *e.transform.orientation); + } + + if e.physics.dynamic { + dynamic := PhysX.PxPhysics_createRigidDynamic(physics, *transform); + actor = dynamic; + + if e.physics.lock & .ANGULAR_X { + PhysX.PxRigidDynamic_setRigidDynamicLockFlag(dynamic, xx PhysX.PxRigidDynamicLockFlags.LockAngularX, true); + } + if e.physics.lock & .ANGULAR_Y { + PhysX.PxRigidDynamic_setRigidDynamicLockFlag(dynamic, xx PhysX.PxRigidDynamicLockFlags.LockAngularY, true); + } + if e.physics.lock & .ANGULAR_Z { + PhysX.PxRigidDynamic_setRigidDynamicLockFlag(dynamic, xx PhysX.PxRigidDynamicLockFlags.LockAngularZ, true); + } + } else { + actor = PhysX.PxPhysics_createRigidStatic(physics, *transform); + } + + material := PhysX.PxPhysics_createMaterial(physics, e.physics.static_friction, e.physics.dynamic_friction, e.physics.restitution); + geo : *PhysX.PxGeometry; + + actor.userData = e; + + if e.physics.type == { + case .SPHERE; { + geo = PhysX.PxSphereGeometry_new(e.physics.sphere.radius); + } + case .BOX; { + geo = PhysX.PxBoxGeometry_new(e.physics.box.half_extent*e.transform.scale); + } + case .CAPSULE; { + geo = PhysX.PxCapsuleGeometry_new(e.physics.capsule.radius, e.physics.capsule.half_height-e.physics.capsule.radius); + } + } + + shape := PhysX.PxPhysics_createShape(physics, geo, material, false, ifx e.physics.trigger then PHYSX_DEFAULT_TRIGGER_SHAPE_FLAGS else PHYSX_DEFAULT_SIMULATION_SHAPE_FLAGS); + + PhysX.PxRigidActor_attachShape(actor, shape); + + PhysX.PxScene_addActor(e.scene.physx_scene.scene, actor, null); + + PhysX.PxShape_release(shape); + PhysX.PxBase_release(material); + + physics_actor : PhysX_Actor; + physics_actor.type = ifx e.physics.dynamic then .DYNAMIC else .STATIC; + physics_actor.sync_rotation_from_physx = e.physics.type != .CAPSULE; // @Incomplete + + if physics_actor.type == .DYNAMIC { + physics_actor.dynamic = xx actor; + } else { + physics_actor.static = xx actor; + } + + e.physics.physx_handle = parray_add(*e.scene.physx_scene.actors, physics_actor); + e.physics.enabled = true; +} add_physx_sphere :: (entity: *Entity, radius: float) -> PhysX_Handle { geo := PhysX.PxSphereGeometry_new(radius); transform := PhysX.PxTransform_new(*entity.transform.position); actor := PhysX.PxPhysics_createRigidDynamic(physics, *transform); - //PhysX.PxRigidDynamic_setRigidDynamicLockFlag(actor, xx PhysX.PxRigidDynamicLockFlags.LockAngularX, true); - //PhysX.PxRigidDynamic_setRigidDynamicLockFlag(actor, xx PhysX.PxRigidDynamicLockFlags.LockAngularY, true); - //PhysX.PxRigidDynamic_setRigidDynamicLockFlag(actor, xx PhysX.PxRigidDynamicLockFlags.LockAngularZ, true); + actor.userData = entity; material := PhysX.PxPhysics_createMaterial(physics, 0.1, 0.1, 0.5); @@ -160,7 +266,10 @@ add_physx_capsule :: (entity: *Entity, half_height: float, radius: float) -> Phy rotation := Quaternion.{0, 0, sin(-PI * 0.25), cos(-PI * 0.25)}; transform := PhysX.PxTransform_new(*entity.transform.position, *rotation); + actor := PhysX.PxPhysics_createRigidDynamic(physics, *transform); + actor.userData = entity; + PhysX.PxRigidDynamic_setRigidDynamicLockFlag(actor, xx PhysX.PxRigidDynamicLockFlags.LockAngularX, true); PhysX.PxRigidDynamic_setRigidDynamicLockFlag(actor, xx PhysX.PxRigidDynamicLockFlags.LockAngularY, true); PhysX.PxRigidDynamic_setRigidDynamicLockFlag(actor, xx PhysX.PxRigidDynamicLockFlags.LockAngularZ, true); @@ -184,7 +293,7 @@ add_physx_capsule :: (entity: *Entity, half_height: float, radius: float) -> Phy physics_actor.dynamic = actor; entity.physx_handle = parray_add(*entity.scene.physx_scene.actors, physics_actor); - return entity.physx_handle; + return entity.physics.physx_handle; } add_physx_box :: (entity: *Entity, half_extent: Vector3, offset: Vector3 = .{}) -> PhysX_Handle { @@ -193,6 +302,7 @@ add_physx_box :: (entity: *Entity, half_extent: Vector3, offset: Vector3 = .{}) t := PhysX.PxTransform_new(*pos, *entity.transform.orientation); body := PhysX.PxPhysics_createRigidStatic(physics, *t); + body.userData = entity; PhysX.PxRigidActor_attachShape(body, shape); PhysX.PxScene_addActor(entity.scene.physx_scene.scene, body, null); @@ -203,7 +313,7 @@ add_physx_box :: (entity: *Entity, half_extent: Vector3, offset: Vector3 = .{}) physics_actor.static = body; entity.physx_handle = parray_add(*entity.scene.physx_scene.actors, physics_actor); - return entity.physx_handle; + return entity.physics.physx_handle; } @@ -254,4 +364,5 @@ default_allocator : PhysX.PxAllocatorCallback; default_error_callback : PhysX.PxErrorCallback; default_filter_shader : PhysX.SimulationFilterShader; dispatcher : *PhysX.PxDefaultCpuDispatcher; +event_callback : *PhysX.PxSimulationEventCallback; diff --git a/renderer/line_rendering.jai b/renderer/line_rendering.jai new file mode 100644 index 0000000..73b43e3 --- /dev/null +++ b/renderer/line_rendering.jai @@ -0,0 +1,89 @@ +MAX_LINES :: 4096; +line_pipeline: Pipeline_State_Handle; + +Line_Point :: struct { + position: Vector3; + width: float; +} + +Line :: struct { + points: Static_Array(Line_Point, 1024); + color: Color; +} + +lines: [..] Line; + +init_line_rendering :: () { + line_vertex_buffer = create_vertex_buffer(engine.renderer, null, size_of(Line_Vertex) * MAX_LINES * 6, stride=size_of(Line_Vertex), mappable=true); + + { + vs := create_vertex_shader(engine.renderer, "../assets/shaders/line.hlsl", "VS", mesh_data_types = .[.POSITION, .COLOR]); + ps := create_pixel_shader(engine.renderer, "../assets/shaders/line.hlsl", "PS"); + + line_pipeline = create_pipeline_state(engine.renderer, vs, ps, blend_type=.TRANSPARENT); + } + + array_reserve(*lines, 4096); +} + +begin_line :: (color: Color) { + current_line = .{}; + current_line.color = color; +} + +end_line :: () { + array_add(*lines, current_line); +} + +add_line_point :: (position: Vector3, width: float) { + array_add(*current_line.points, .{position, width}); +} + +add_line :: (from: Vector3, to: Vector3, color: Color = .{1,1,1,1}, line_width: float = 0.1) { + hw := line_width*0.5; // @Incomplete + + up := -engine.current_scene.camera.forward; + forward := normalize(to - from); + right := cross(up, forward); + + line_dir := normalize(to - from); + view_dir := normalize(engine.current_scene.camera.position - (from + to) * 0.5); + offset_dir := normalize(cross(line_dir, view_dir)) * hw; + + array_add(*line_vertices, .{from + offset_dir, color}); + array_add(*line_vertices, .{to + offset_dir, color}); + array_add(*line_vertices, .{from - offset_dir, color}); + + array_add(*line_vertices, .{to + offset_dir, color}); + array_add(*line_vertices, .{to - offset_dir, color}); + array_add(*line_vertices, .{from - offset_dir, color}); +} + +render_lines :: () { + if line_vertices.count > 0 { + upload_data_to_buffer(engine.renderer, line_vertex_buffer, line_vertices.data, size_of(Line_Vertex) * line_vertices.count); + + push_cmd_set_draw_mode(engine.renderer, .FILL); + push_cmd_set_depth_write(engine.renderer, true); + push_cmd_set_cull_face(engine.renderer, .NONE); + push_cmd_set_pipeline_state(engine.renderer, line_pipeline); + + push_cmd_set_constant_buffer(engine.renderer, 0, engine.camera_buffer, .VERTEX); + + push_cmd_set_vertex_buffer(engine.renderer, line_vertex_buffer); + + push_cmd_draw(engine.renderer, xx line_vertices.count); + } + + line_vertices.count = 0; +} + +#scope_file + +Line_Vertex :: struct { + position: Vector3; + color: Color; +} + +line_vertex_buffer: Buffer_Handle; +line_vertices: [..] Line_Vertex; diff --git a/renderer/trigger_rendering.jai b/renderer/trigger_rendering.jai index 1ae5ea4..1be9749 100644 --- a/renderer/trigger_rendering.jai +++ b/renderer/trigger_rendering.jai @@ -1,3 +1,5 @@ +#load "line_rendering.jai"; + TRIGGER_VERTEX_SHADER :: #string END cbuffer CameraData : register(b0) { @@ -59,65 +61,28 @@ init_trigger_line_rendering :: () { } render_trigger_lines :: () { - vertices: [..] Trigger_Line_Vertex; - vertices.allocator = temp; - for e: engine.current_scene.entities { - if e.collider.render_aabb { - color := e.collider.aabb_color; - scale := e.transform.scale; - aabb := e.collider.aabb; + if e.physics.type == .BOX { + color := Color.{0,0,1,1};//e.collider.aabb_color; + aabb := AABB.{-e.physics.box.half_extent, e.physics.box.half_extent}; - min := transform_position(aabb.min, e.transform.model_matrix); - max := transform_position(aabb.max, e.transform.model_matrix); + min := aabb.min; + max := aabb.max; - array_add(*vertices, .{.{min.x, min.y, min.z}, color}); - array_add(*vertices, .{.{min.x, min.y, max.z}, color}); - - array_add(*vertices, .{.{max.x, min.y, min.z}, color}); - array_add(*vertices, .{.{max.x, min.y, max.z}, color}); - - array_add(*vertices, .{.{min.x, max.y, min.z}, color}); - array_add(*vertices, .{.{min.x, max.y, max.z}, color}); - - array_add(*vertices, .{.{max.x, max.y, min.z}, color}); - array_add(*vertices, .{.{max.x, max.y, max.z}, color}); - - array_add(*vertices, .{.{min.x, min.y, min.z}, color}); - array_add(*vertices, .{.{min.x, max.y, min.z}, color}); - - array_add(*vertices, .{.{max.x, min.y, min.z}, color}); - array_add(*vertices, .{.{max.x, max.y, min.z}, color}); - - array_add(*vertices, .{.{max.x, min.y, max.z}, color}); - array_add(*vertices, .{.{max.x, max.y, max.z}, color}); - - array_add(*vertices, .{.{min.x, min.y, max.z}, color}); - array_add(*vertices, .{.{min.x, max.y, max.z}, color}); - - array_add(*vertices, .{.{min.x, min.y, min.z}, color}); - array_add(*vertices, .{.{max.x, min.y, min.z}, color}); - array_add(*vertices, .{.{min.x, max.y, min.z}, color}); - array_add(*vertices, .{.{max.x, max.y, min.z}, color}); - - array_add(*vertices, .{.{min.x, min.y, max.z}, color}); - array_add(*vertices, .{.{max.x, min.y, max.z}, color}); - - array_add(*vertices, .{.{min.x, max.y, max.z}, color}); - array_add(*vertices, .{.{max.x, max.y, max.z}, color}); + add_line(transform_position(.{min.x, min.y, min.z}, e.transform.model_matrix), transform_position(.{min.x, min.y, max.z}, e.transform.model_matrix), color); + add_line(transform_position(.{max.x, min.y, min.z}, e.transform.model_matrix), transform_position(.{max.x, min.y, max.z}, e.transform.model_matrix), color); + add_line(transform_position(.{min.x, max.y, min.z}, e.transform.model_matrix), transform_position(.{min.x, max.y, max.z}, e.transform.model_matrix), color); + add_line(transform_position(.{max.x, max.y, min.z}, e.transform.model_matrix), transform_position(.{max.x, max.y, max.z}, e.transform.model_matrix), color); + add_line(transform_position(.{min.x, min.y, min.z}, e.transform.model_matrix), transform_position(.{min.x, max.y, min.z}, e.transform.model_matrix), color); + add_line(transform_position(.{max.x, min.y, min.z}, e.transform.model_matrix), transform_position(.{max.x, max.y, min.z}, e.transform.model_matrix), color); + add_line(transform_position(.{max.x, min.y, max.z}, e.transform.model_matrix), transform_position(.{max.x, max.y, max.z}, e.transform.model_matrix), color); + add_line(transform_position(.{min.x, min.y, max.z}, e.transform.model_matrix), transform_position(.{min.x, max.y, max.z}, e.transform.model_matrix), color); + add_line(transform_position(.{min.x, min.y, min.z}, e.transform.model_matrix), transform_position(.{max.x, min.y, min.z}, e.transform.model_matrix), color); + add_line(transform_position(.{min.x, max.y, min.z}, e.transform.model_matrix), transform_position(.{max.x, max.y, min.z}, e.transform.model_matrix), color); + add_line(transform_position(.{min.x, min.y, max.z}, e.transform.model_matrix), transform_position(.{max.x, min.y, max.z}, e.transform.model_matrix), color); + add_line(transform_position(.{min.x, max.y, max.z}, e.transform.model_matrix), transform_position(.{max.x, max.y, max.z}, e.transform.model_matrix), color); } } - upload_data_to_buffer(engine.renderer, trigger_line_buffer, vertices.data, vertices.count * size_of(Trigger_Line_Vertex)); - - push_cmd_set_draw_mode(engine.renderer, .WIREFRAME); - push_cmd_set_depth_write(engine.renderer, true); - push_cmd_set_cull_face(engine.renderer, .NONE); - push_cmd_set_pipeline_state(engine.renderer, trigger_pipeline); - - push_cmd_set_constant_buffer(engine.renderer, 0, engine.camera_buffer, .VERTEX); - - push_cmd_set_vertex_buffer(engine.renderer, trigger_line_buffer); - - push_cmd_draw(engine.renderer, xx vertices.count, 0, topology=.LINE_LIST); + render_lines(); }