diff --git a/core/entity.jai b/core/entity.jai index 9f14261..afa60ff 100644 --- a/core/entity.jai +++ b/core/entity.jai @@ -79,10 +79,8 @@ Entity :: struct { animator: Animator; @DontSerialize // Physics - body : Physics_Body; - collider : Collider; - physx_static: *PhysX.PxRigidStatic; - physx_dynamic: *PhysX.PxRigidDynamic; + physx_handle: PhysX_Handle; + velocity: Vector3; // End physics @@ -208,10 +206,6 @@ entity_should_be_rendered :: (e: *Entity) -> bool { destroy_entity :: (e: *Entity) { call_correct_deinit_entity(e); - if e.collider.mesh.vertices.data != null { - array_free(e.collider.mesh.vertices); - } - for 0..e.renderable.num_nodes-1 { node_data := e.renderable.nodes[it]; diff --git a/core/mesh_entity.jai b/core/mesh_entity.jai index db9691a..e72773f 100644 --- a/core/mesh_entity.jai +++ b/core/mesh_entity.jai @@ -7,11 +7,13 @@ Mesh_Entity :: struct { } init_entity :: (e: *Mesh_Entity) { + log_error("Missing collision on Mesh Entities\n"); + assert(false); if e.model_path.count > 0 { load_model_into_entity(e, get_or_load_model(e.model_path)); - e.flags |= .COLLISION | .STATIC; - e.collider.type = .MESH; - e.collider.bake_mode = .FULL_MESH; + //e.flags |= .COLLISION | .STATIC; + //e.collider.type = .MESH; + //e.collider.bake_mode = .FULL_MESH; } } diff --git a/core/scene.jai b/core/scene.jai index 17528b0..493d15d 100644 --- a/core/scene.jai +++ b/core/scene.jai @@ -22,7 +22,7 @@ Scene :: struct { mode: Engine_Mode; - physx_scene: *PhysX.PxScene; + physx_scene: PhysX_Scene; using custom_fields: _Custom_Scene_Fields; } @@ -76,8 +76,6 @@ load_scene :: (name: string, make_current: bool = true) -> *Scene { next_entity_id = cast(Entity_Id)(highest + 1); update_transforms(scene); - calculate_aabbs(scene); - make_sure_nothing_collides(scene); if engine.procs.on_scene_loaded != null { engine.procs.on_scene_loaded(scene, engine.mode); @@ -144,7 +142,7 @@ unload_scene :: (scene: *Scene) { destroy_entity(e); } - PhysX.PxScene_release(scene.physx_scene); + deinit_physx_scene(scene); free(scene.name); fini(*scene.pool); @@ -195,7 +193,7 @@ create_scene :: (name: string = "", max_entities: s64 = 256) -> *Scene { array_reserve(*scene.entities, max_entities); - scene.physx_scene = create_physx_scene(); + init_physx_scene(scene); scene.directional_light.color_and_intensity = .{1,1,1,2}; scene.directional_light.direction = to_v4(normalize(Vector3.{0.4, -0.7, 0.4})); diff --git a/core/transform.jai b/core/transform.jai index d92eb87..aa744bf 100644 --- a/core/transform.jai +++ b/core/transform.jai @@ -170,6 +170,16 @@ set_scale :: (transform: *Transform, scale: float, calculate_matrix: bool = true if calculate_matrix update_matrix(transform); } +set_position_rotation :: (transform: *Transform, position: Vector3, rotation: Quaternion, calculate_matrix: bool = true) { + transform.position = position; + transform.orientation = rotation; + if calculate_matrix update_matrix(transform); +} + +set_position_rotation :: (e: *Entity, position: Vector3, rotation: Quaternion, calculate_matrix: bool = true) { + set_position_rotation(*e.transform, position, rotation, calculate_matrix); +} + set_position_rotation_scale :: (transform: *Transform, position: Vector3, rotation: Quaternion, scale: Vector3, calculate_matrix: bool = true) { transform.position = position; transform.orientation = rotation; diff --git a/module.jai b/module.jai index 6e5aef0..5744dc6 100644 --- a/module.jai +++ b/module.jai @@ -157,16 +157,18 @@ coven_run :: (game_update_proc: (float), game_editor_update_proc: (float), game_ if engine.current_scene != null && !engine.paused { update_animators(clamped_dt); - update_mesh_colliders(engine.current_scene); - update_physics(engine.current_scene, clamped_dt); - tick_physx(engine.current_scene.physx_scene, clamped_dt); + + pre_physx_sync(engine.current_scene); + tick_physx(*engine.current_scene.physx_scene, clamped_dt); + post_physx_sync(engine.current_scene); + game_update_post_physics_proc(clamped_dt); } } else { game_editor_update_proc(clamped_dt); if engine.current_scene != null { - update_trigger_mesh_colliders(engine.current_scene); + //update_trigger_mesh_colliders(engine.current_scene); } } @@ -220,7 +222,6 @@ switch_engine_mode :: (to_mode: Engine_Mode) { #load "renderer/engine_buffers.jai"; #load "renderer/renderer.jai"; #load "windowing/window.jai"; -#load "physics/physics.jai"; #load "core/mesh_entity.jai"; #load "core/string_helpers.jai"; diff --git a/physics/physics.jai b/physics/physics.jai deleted file mode 100644 index be99732..0000000 --- a/physics/physics.jai +++ /dev/null @@ -1,511 +0,0 @@ -#load "gjk.jai"; - -WORLD_UP :: Vector3.{0,1,0}; -GRAVITY :: -20.8; - -Collider_Type :: enum { - AABB; - SPHERE; - MESH; - BOX; -} - -Sphere :: struct { - radius: float; -} - -Mesh_Collider :: struct { - vertices : [..] Vector3; - is_baked: bool; -} - -Trigger_Overlap :: struct { - entity: *Entity; - frame_index: u64; -} - -MAX_TRIGGER_OVERLAPS :: 16; - -Collision_Layers :: enum_flags { - NONE; - - LAYER1; - LAYER2; - LAYER3; - LAYER4; - LAYER5; - LAYER6; - LAYER7; - LAYER8; - LAYER9; - LAYER10; - - ALL :: .LAYER1 | LAYER2 | .LAYER3 | .LAYER4 | .LAYER5 | .LAYER6 | .LAYER7 | .LAYER8 | .LAYER9 | .LAYER10; -} - -Collider_Bake_Mode :: enum { - AABB; - - FULL_MESH; - - ONLY_FACING_UP; -} - -Collider :: struct { - type : Collider_Type; - - bake_mode: Collider_Bake_Mode; - - layer: Collision_Layers = .LAYER1; - collides_with_layers: Collision_Layers = .LAYER1; - - override_aabb: bool; - render_aabb: bool; - aabb_color: Vector4 = .{0,1,0,1}; - aabb: AABB; - - union { - sphere: Sphere; @DontSerialize - mesh : Mesh_Collider; @DontSerialize - } - - overlaps: [MAX_TRIGGER_OVERLAPS] Trigger_Overlap; @DontSerialize - num_overlaps: s64; @DontSerialize - - ignore: bool; @DontSerialize -} - -Physics_Body :: struct { - enabled: bool = true; - velocity: Vector3; @DontSerialize - - friction : float = 0.0; @DontSerialize - bounciness : float = 0.0; @DontSerialize - linear_damping : float = 0.0; @DontSerialize - - check_for_grounded: bool; @DontSerialize - grounded: bool; @DontSerialize -} - -update_mesh_collider :: (e: *Entity) { - if e.collider.bake_mode == { - case .AABB; { - if e.collider.mesh.vertices.count == 0 { - array_resize(*e.collider.mesh.vertices, 8); - } - - m := e.transform.model_matrix; - e.collider.mesh.vertices[0] = transform_position(e.collider.aabb.min, m); - e.collider.mesh.vertices[1] = transform_position(e.collider.aabb.max, m); - e.collider.mesh.vertices[2] = transform_position(.{e.collider.aabb.min.x, e.collider.aabb.min.y, e.collider.aabb.max.z}, m); - e.collider.mesh.vertices[3] = transform_position(.{e.collider.aabb.max.x, e.collider.aabb.min.y, e.collider.aabb.max.z}, m); - e.collider.mesh.vertices[4] = transform_position(.{e.collider.aabb.max.x, e.collider.aabb.min.y, e.collider.aabb.min.z}, m); - e.collider.mesh.vertices[5] = transform_position(.{e.collider.aabb.min.x, e.collider.aabb.max.y, e.collider.aabb.max.z}, m); - e.collider.mesh.vertices[6] = transform_position(.{e.collider.aabb.max.x, e.collider.aabb.max.y, e.collider.aabb.min.z}, m); - e.collider.mesh.vertices[7] = transform_position(.{e.collider.aabb.min.x, e.collider.aabb.max.y, e.collider.aabb.min.z}, m); - } - case .FULL_MESH; { - //update_entity_transform(e); - - model := get_model_by_handle(e.renderable.model); - if model { - for i: 0..e.renderable.num_nodes-1 { - render_node := e.renderable.nodes[i]; - model_node := model.nodes[i]; - - for mesh_handle: model_node.meshes { - mesh := parray_get(*engine.renderer.meshes, mesh_handle); - - for p: mesh.positions { - position := transform_position(p, render_node.transform.world_matrix); - array_add(*e.collider.mesh.vertices, position); - } - } - } - } - } - } - - e.collider.mesh.is_baked = true; -} - -update_trigger_mesh_colliders :: (scene: *Scene) { - for e: scene.entities { - if e.flags & .TRIGGER { - if e.collider.type == .MESH { - update_mesh_collider(e); - } - } - } -} - -update_mesh_colliders :: (scene: *Scene) { - for e: scene.entities { - if e.flags & .COLLISION { - if e.collider.type == .MESH { - if e.flags & .STATIC && e.collider.mesh.is_baked continue; - - update_mesh_collider(e); - } - } - } -} - -make_sure_entity_does_not_collide :: (e: *Entity, scene: *Scene) { - if e.flags & .PHYSICS { - aabb := e.collider.aabb; - aabb.min += e.transform.position; - aabb.max += e.transform.position; - - for other_e: scene.entities { - if e == other_e continue; - - if other_e.flags & .COLLISION { - other_aabb := other_e.collider.aabb; - other_aabb.min += other_e.transform.position; - other_aabb.max += other_e.transform.position; - if aabb_vs_aabb(aabb, other_aabb) { - offset := resolve_aabb_vs_aabb(aabb, other_aabb); - set_position(*e.transform, e.transform.position + offset * 1.0001); - } - } - } - } -} - -make_sure_nothing_collides :: (scene: *Scene) { - for e: scene.entities { - make_sure_entity_does_not_collide(e, scene); - } -} - -update_gravity :: (scene: *Scene, dt: float) { - for e: scene.entities { - if !e.enabled continue; - if !e.body.enabled continue; - - if e.flags & .PHYSICS { - #if NETWORKING { if e.is_proxy continue; } - - if e.collider.ignore continue; - e.body.velocity.y += GRAVITY * dt; - } - } -} - -update_positions :: (scene: *Scene, dt: float) { - for e: scene.entities { - if !e.enabled continue; - if !e.body.enabled continue; - - #if NETWORKING { if e.is_proxy continue; } - - if e.collider.ignore continue; - - if e.flags & .PHYSICS { - delta := e.body.velocity * dt; - set_position(*e.transform, e.transform.position + delta); - - // @Speed: Only do this, if we actually moved - m := e.transform.model_matrix; - if e.collider.mesh.vertices.count < 8 continue; - - e.collider.mesh.vertices[0] = transform_position(e.collider.aabb.min, m); - e.collider.mesh.vertices[1] = transform_position(e.collider.aabb.max, m); - e.collider.mesh.vertices[2] = transform_position(.{e.collider.aabb.min.x, e.collider.aabb.min.y, e.collider.aabb.max.z}, m); - e.collider.mesh.vertices[3] = transform_position(.{e.collider.aabb.max.x, e.collider.aabb.min.y, e.collider.aabb.max.z}, m); - e.collider.mesh.vertices[4] = transform_position(.{e.collider.aabb.max.x, e.collider.aabb.min.y, e.collider.aabb.min.z}, m); - e.collider.mesh.vertices[5] = transform_position(.{e.collider.aabb.min.x, e.collider.aabb.max.y, e.collider.aabb.max.z}, m); - e.collider.mesh.vertices[6] = transform_position(.{e.collider.aabb.max.x, e.collider.aabb.max.y, e.collider.aabb.min.z}, m); - e.collider.mesh.vertices[7] = transform_position(.{e.collider.aabb.min.x, e.collider.aabb.max.y, e.collider.aabb.min.z}, m); - } - } -} - -add_trigger_overlap_if_new :: (triggered_entity: *Entity, triggered_by_entity: *Entity) { - for 0..triggered_entity.collider.num_overlaps-1 { - overlap := *triggered_entity.collider.overlaps[it]; - if overlap.entity == triggered_by_entity { - overlap.frame_index = frame_index; - return; - } - } - - if engine.procs.on_trigger_enter != null { - engine.procs.on_trigger_enter(triggered_entity, triggered_by_entity); - } - - triggered_entity.collider.overlaps[triggered_entity.collider.num_overlaps] = .{ triggered_by_entity, frame_index }; - triggered_entity.collider.num_overlaps += 1; -} - -can_collide :: (e: *Entity, other: *Entity) -> bool { - return xx (e.collider.collides_with_layers & other.collider.layer); -} - -physics_step :: (scene: *Scene, timestep: float) { - update_gravity(scene, timestep); - update_positions(scene, timestep); - - for e: scene.entities { - if !e.enabled continue; - if !e.body.enabled continue; - #if NETWORKING { if e.is_proxy continue;} - if e.collider.ignore continue; - - if e.flags & .PHYSICS { - if e.body.check_for_grounded { - e.body.grounded = false; - } - - for other_e: scene.entities { - if e == other_e continue; - if other_e.collider.ignore continue; - if !other_e.enabled continue; - if !other_e.body.enabled continue; - if !can_collide(e, other_e) continue; - - if other_e.flags & .COLLISION { - if other_e.collider.type == .AABB { - success :, inv_matrix := inverse(other_e.transform.model_matrix); - aabb := other_e.collider.aabb; - if point_inside_aabb(aabb, transform_position(e.transform.position, inv_matrix)) { - add_trigger_overlap_if_new(other_e, e); - } - } else { - point := gjk(e.collider, other_e.collider); - - if point.has_collision { - if other_e.flags & .TRIGGER { - // TRIGGER CALLBACK - add_trigger_overlap_if_new(other_e, e); - } else { - n := -point.normal; - speed_along_normal := dot(e.body.velocity, n); - - restitution := e.body.bounciness; - impulse := n * (-(1.0 + restitution) * speed_along_normal); - e.body.velocity += impulse; - - percent := 0.1; - slop := 0.005; - correction := n * max(point.penetration_depth - slop, 0.0) / (1.0 / percent); - set_position(*e.transform, e.transform.position + correction); - - if e.body.check_for_grounded { - e.body.grounded = dot(n, WORLD_UP) > 0.6; // @Incomplete: Add allowed angle variable at some point? - } - - // @Incomplete: This shouldn't be in here - //if e.type == Diamond && length(impulse) > 2.0 { - // play_audio_event(sfx_diamond_hit); - //} - } - } - } - } - } - } - } -} - -update_physics :: (scene: *Scene, dt: float) { - for scene.entities { - if it.collider.type == .MESH { - if !it.collider.mesh.is_baked { - update_mesh_collider(it); - } - } - } - - iterations := 4; - step_time := dt / cast(float)iterations; - for 0..iterations-1 { - physics_step(scene, step_time); - - for e: scene.entities { - if e.flags & .PHYSICS { - //if e.body.friction > 0.0 { - // e.body.velocity *= 1.0 - (e.body.friction / cast(float)iterations); - //} - - e.body.velocity *= (1.0 - e.body.linear_damping / cast(float)iterations); - } - } - } - - for e: scene.entities { - index := 0; - while index < e.collider.num_overlaps { - defer index += 1; - - if e.collider.overlaps[index].frame_index < frame_index { - if engine.procs.on_trigger_exit != null { - engine.procs.on_trigger_exit(e, e.collider.overlaps[index].entity); - } - - if e.collider.num_overlaps > 1 { - e.collider.overlaps[index] = e.collider.overlaps[e.collider.num_overlaps-1]; - } - - e.collider.num_overlaps -= 1; - } - } - } -} - -// DISCRETE -aabb_vs_aabb :: (box1: AABB, box2: AABB) -> bool { - // Check for no overlap along any axis - if box1.max.x < box2.min.x || box1.min.x > box2.max.x return false; - if box1.max.y < box2.min.y || box1.min.y > box2.max.y return false; - if box1.max.z < box2.min.z || box1.min.z > box2.max.z return false; - - return true; -} - -resolve_aabb_vs_aabb :: (moving_box: AABB, static_box: AABB) -> Vector3 { - overlap_x := min(moving_box.max.x, static_box.max.x) - max(moving_box.min.x, static_box.min.x); - overlap_y := min(moving_box.max.y, static_box.max.y) - max(moving_box.min.y, static_box.min.y); - overlap_z := min(moving_box.max.z, static_box.max.z) - max(moving_box.min.z, static_box.min.z); - - offset : Vector3; - - // Resolve overlap on each axis - if (overlap_x > 0 && overlap_y > 0 && overlap_z > 0) { - // Determine which axis has the smallest overlap - if (overlap_x <= overlap_y && overlap_x <= overlap_z) { - // Resolve overlap on X-axis - if (moving_box.max.x < static_box.max.x) { - offset.x -= overlap_x; - } else { - offset.x += overlap_x; - } - } else if (overlap_y <= overlap_x && overlap_y <= overlap_z) { - // Resolve overlap on Y-axis - if (moving_box.max.y < static_box.max.y) { - offset.y -= overlap_y; - } else { - offset.y += overlap_y; - } - } else { - // Resolve overlap on Z-axis - if (moving_box.max.z < static_box.max.z) { - offset.z -= overlap_z; - } else { - offset.z += overlap_z; - } - } - } - - return offset; -} - -// SWEPT -// Check for collision between two AABBs over a specified time interval -swept_aabb_collision :: (box1: AABB, box2: AABB, delta: Vector3) -> bool, t_enter: float, t_exit: float { - d_inv := 1.0 / delta; - - tx_enter, tx_exit, ty_enter, ty_exit, tz_enter, tz_exit : float; - - if (delta.x >= 0) { - tx_enter = (box2.min.x - box1.max.x) * d_inv.x; - tx_exit = (box2.max.x - box1.min.x) * d_inv.x; - } else { - tx_enter = (box2.max.x - box1.min.x) * d_inv.x; - tx_exit = (box2.min.x - box1.max.x) * d_inv.x; - } - - if (delta.y >= 0) { - ty_enter = (box2.min.y - box1.max.y) * d_inv.y; - ty_exit = (box2.max.y - box1.min.y) * d_inv.y; - } else { - ty_enter = (box2.max.y - box1.min.y) * d_inv.y; - ty_exit = (box2.min.y - box1.max.y) * d_inv.y; - } - - if (delta.z >= 0) { - tz_enter = (box2.min.z - box1.max.z) * d_inv.z; - tz_exit = (box2.max.z - box1.min.z) * d_inv.z; - } else { - tz_enter = (box2.max.z - box1.min.z) * d_inv.z; - tz_exit = (box2.min.z - box1.max.z) * d_inv.z; - } - - t_enter := max(max(tx_enter, ty_enter), tz_enter); - t_exit := min(min(tx_exit, ty_exit), tz_exit); - - return t_enter <= t_exit && t_exit >= 0 && t_enter <= 1, t_enter, t_exit; -} - -calculate_aabbs :: (scene: *Scene) { - for e: scene.entities { - if e.flags & .COLLISION && e.flags & .RENDERABLE { - if e.collider.override_aabb continue; - if e.renderable.model == 0 continue; - - aabb : AABB; - model := get_model_by_handle(e.renderable.model); - - for n : model.nodes { - if n.parent == 0 { - bake_aabb(*aabb, Matrix4_Identity, e, n); - } - } - - e.collider.aabb = aabb; - } - } -} - -bake_aabb :: (aabb: *AABB, parent_matrix: Matrix4, e: *Entity, n: Node) { - update_matrix(*n.transform); - node_matrix := parent_matrix * n.transform.model_matrix; - - for handle : n.meshes { - index := 0; - m := parray_get(*engine.renderer.meshes, handle); - if m.indices.count > 0 { - while index < m.indices.count { - i1 := m.indices[index]; - i2 := m.indices[index + 1]; - i3 := m.indices[index + 2]; - p0 := to_v3(node_matrix * to_v4(m.positions[i1])); - p1 := to_v3(node_matrix * to_v4(m.positions[i2])); - p2 := to_v3(node_matrix * to_v4(m.positions[i3])); - - apply_min_max(*aabb.min, *aabb.max, p0); - apply_min_max(*aabb.min, *aabb.max, p1); - apply_min_max(*aabb.min, *aabb.max, p2); - - index += 3; - } - // assert("Meshes with indices currently for aabb collision baking." && false); - } else { - while index < m.positions.count - 1 { - p0 := to_v3(node_matrix * to_v4(m.positions[index])); - p1 := to_v3(node_matrix * to_v4(m.positions[index + 1])); - p2 := to_v3(node_matrix * to_v4(m.positions[index + 2])); - - apply_min_max(*aabb.min, *aabb.max, p0); - apply_min_max(*aabb.min, *aabb.max, p1); - apply_min_max(*aabb.min, *aabb.max, p2); - - index += 3; - } - } - } - - model := get_model_by_handle(e.renderable.model); - - for n.children { - child := *model.nodes[it - 1]; - bake_aabb(aabb, node_matrix, e, child); - } - - if abs(aabb.min.y - aabb.max.y) < 0.00001 { - aabb.min.y -= 0.001; - } -} - - diff --git a/physics/physx.jai b/physics/physx.jai index 313b575..beb47f3 100644 --- a/physics/physx.jai +++ b/physics/physx.jai @@ -1,3 +1,28 @@ +PHYSX_TEST :: false; PHYSX_DEFAULT_SHAPE_FLAGS :: cast(u8)(PhysX.PxShapeFlags.Visualization | PhysX.PxShapeFlags.SceneQueryShape | PhysX.PxShapeFlags.SimulationShape); + +PhysX_Handle :: #type, distinct u32; + +PhysX_Actor_Type :: enum { + STATIC; + DYNAMIC; +} + +PhysX_Actor :: struct { + type : PhysX_Actor_Type; + + sync_rotation_from_physx: bool = true; + + union { + static: *PhysX.PxRigidStatic; + dynamic: *PhysX.PxRigidDynamic; + } +} + +PhysX_Scene :: struct { + scene: *PhysX.PxScene; + actors : PArray(PhysX_Actor, PhysX_Handle); +} + init_physx :: () { default_allocator = PhysX.get_default_allocator(); default_error_callback = PhysX.get_default_error_callback(); @@ -14,21 +39,19 @@ init_physx :: () { tolerance_scale : PhysX.PxTolerancesScale; tolerance_scale.length = 1; - tolerance_scale.speed = 981; + tolerance_scale.speed = 10; physics = PhysX.PxCreatePhysics(PhysX.PX_PHYSICS_VERSION, foundation, *tolerance_scale, true, pvd, null); dispatcher = PhysX.PxDefaultCpuDispatcherCreate(2); - material = PhysX.PxPhysics_createMaterial(physics, 0.5, 0.5, 0.6); + material = PhysX.PxPhysics_createMaterial(physics, 0.0, 0.0, 0.6); } -tick_physx :: (scene: *PhysX.PxScene, dt: float) { - PhysX.PxScene_simulate(scene, 1.0/60.0, null, null, 0, true); - PhysX.PxScene_fetchResults(scene, true, null); +tick_physx :: (scene: *PhysX_Scene, dt: float) { + PhysX.PxScene_simulate(scene.scene, dt, null, null, 0, true); + PhysX.PxScene_fetchResults(scene.scene, true, null); } -plane : Plane3; - -create_physx_scene :: () -> *PhysX.PxScene { +init_physx_scene :: (game_scene: *Scene) { tolerance_scale : PhysX.PxTolerancesScale; tolerance_scale.length = 1; tolerance_scale.speed = 10; @@ -48,41 +71,113 @@ create_physx_scene :: () -> *PhysX.PxScene { PhysX.PxPvdSceneClient_setScenePvdFlag(pvd_client, xx PhysX.PxPvdSceneFlag.TRANSMIT_CONTACTS, true); PhysX.PxPvdSceneClient_setScenePvdFlag(pvd_client, xx PhysX.PxPvdSceneFlag.TRANSMIT_SCENEQUERIES, true); } - { - plane_point := Vector3.{0,0,0}; - plane_normal := Vector3.{0,1,0}; - plane = PhysX.PxPlane_new(*plane_point, *plane_normal); - ground_plane := PhysX.PxCreatePlane(physics, *plane, material); - PhysX.PxScene_addActor(scene, ground_plane, null); - } - stack_z := 0.0; - for i: 0..4 { - stack_pos := Vector3.{0,10,stack_z}; - stack_z -= 10.0; - create_stack(scene, PhysX.PxTransform_new(*stack_pos), 10, 2.0); - } + physx_scene : PhysX_Scene; + physx_scene.scene = scene; + physx_scene.actors.data.allocator = game_scene.allocator; + physx_scene.actors.indices.allocator = game_scene.allocator; - { - pos := Vector3.{0,20,100}; - geo := PhysX.PxSphereGeometry_new(5); - vel := Vector3.{0,-25,-100}; - - ball := create_dynamic(scene, PhysX.PxTransform_new(*pos), *geo, vel); - density := 1000.0; - PhysX.PxRigidBodyExt_updateMassAndInertia(ball, density, null, true); - } - - return scene; + game_scene.physx_scene = physx_scene; } -PxShapeFlags :: enum_flags u8 { - SimulationShape :: 1 << 0; - SceneQueryShape :: 1 << 1; - TriggerShape :: 1 << 2; - Visualization :: 1 << 3; + +deinit_physx_scene :: (game_scene: *Scene) { + PhysX.PxScene_release(game_scene.physx_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); + } + } + } +} + +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; + + 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); + } + } + } + } +} + +add_physx_capsule :: (entity: *Entity, half_height: float, radius: float) -> PhysX_Handle { + geo := PhysX.PxCapsuleGeometry_new(radius, half_height-radius); + + 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(*entity.transform.position, *rotation); + 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); + + material := PhysX.PxPhysics_createMaterial(physics, 0.0, 0.0, 0.0); + + PhysX.PxMaterial_setRestitutionCombineMode(material,1); // Turn off restitution no matter the other material + + shape := PhysX.PxPhysics_createShape(physics, *geo, material, false, PHYSX_DEFAULT_SHAPE_FLAGS); + PhysX.PxRigidActor_attachShape(actor, shape); + + + PhysX.PxRigidBodyExt_updateMassAndInertia(actor, 0.1, null, false); + PhysX.PxScene_addActor(entity.scene.physx_scene.scene, actor, null); + + PhysX.PxShape_release(shape); + // @Incomplete + //PhysX.PxMaterial_release(material); + + physics_actor : PhysX_Actor; + physics_actor.type = .DYNAMIC; + physics_actor.sync_rotation_from_physx = false; + physics_actor.dynamic = actor; + + entity.physx_handle = parray_add(*entity.scene.physx_scene.actors, physics_actor); + return entity.physx_handle; +} + +add_physx_box :: (entity: *Entity, half_extent: Vector3) -> PhysX_Handle { + shape := PhysX.PxPhysics_createShape(physics, PhysX.PxBoxGeometry_new(half_extent), material, false, PHYSX_DEFAULT_SHAPE_FLAGS); + t := PhysX.PxTransform_new(*entity.transform.position); + + body := PhysX.PxPhysics_createRigidStatic(physics, *t); + PhysX.PxRigidActor_attachShape(body, shape); + PhysX.PxScene_addActor(entity.scene.physx_scene.scene, body, null); + + PhysX.PxShape_release(shape); + + physics_actor : PhysX_Actor; + physics_actor.type = .STATIC; + physics_actor.static = body; + + entity.physx_handle = parray_add(*entity.scene.physx_scene.actors, physics_actor); + return entity.physx_handle; + +} + create_stack :: (scene: *PhysX.PxScene, t: PhysX.PxTransform, size: u32, half_extent: float) { - shape := PhysX.PxPhysics_createShape(physics, PhysX.PxBoxGeometry_new(half_extent, half_extent, half_extent), material, false, xx (PhysX.PxShapeFlags.Visualization | PhysX.PxShapeFlags.SceneQueryShape | PhysX.PxShapeFlags.SimulationShape)); + shape := PhysX.PxPhysics_createShape(physics, PhysX.PxBoxGeometry_new(half_extent, half_extent, half_extent), material, false, PHYSX_DEFAULT_SHAPE_FLAGS); for i: 0..size-1 { for j: 0..size-i-1 { pos := Vector3.{cast(float)(j*2) - cast(float)(size-i), cast(float)(i*2+1), 0} * half_extent; @@ -97,6 +192,16 @@ create_stack :: (scene: *PhysX.PxScene, t: PhysX.PxTransform, size: u32, half_ex //shape->release(); } +Hit :: struct { + +} + +physx_raycast :: (origin: Vector3, direction: Vector3, max_distance: float = 1000.0) -> bool, Hit { + hit : PhysX.PxRaycastHit; + filter_data := PhysX.PxQueryFilterData_new(); + has_hit := PhysX.PxSceneQueryExt_raycastSingle(engine.current_scene.physx_scene.scene, *origin, *direction, max_distance, 0, *hit, *filter_data, null, null); + return has_hit, .{}; +} create_dynamic :: (scene: *PhysX.PxScene, t: PhysX.PxTransform, geometry: *PhysX.PxGeometry, velocity: Vector3 = .{}) -> *PhysX.PxRigidDynamic { p := Vector3.{0,0,0};