Compare commits
25 Commits
5f61c04912
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 21b22653b5 | |||
| 0736eb77b2 | |||
| 17c3469602 | |||
| 8e2bc651b9 | |||
| dc18060729 | |||
| 0d35175aed | |||
| 98058856a6 | |||
| ada1acb402 | |||
| be4775ff93 | |||
| f62203973f | |||
| 9c2f32f5a3 | |||
| e0f1dd5e70 | |||
| 0d51dc8236 | |||
| 659c25dbe5 | |||
| 9f9189e60e | |||
| 487175f126 | |||
| a5bde6194a | |||
| 99827fce44 | |||
| 9353bc3e07 | |||
| 2f6ca9d15b | |||
| 1b339f087b | |||
| 602dd870df | |||
| 9dd12a55bf | |||
| 1fe051d275 | |||
| d5a21cb3ee |
110
core/entity.jai
110
core/entity.jai
@@ -1,20 +1,17 @@
|
|||||||
Entity_Id :: #type, isa s64;
|
Entity_Id :: #type, isa s64;
|
||||||
|
|
||||||
Entity_Flags :: enum_flags u16 {
|
Entity_Flags :: enum_flags u16 {
|
||||||
NONE;
|
NONE :: 0;
|
||||||
RENDERABLE;
|
RENDERABLE :: 1;
|
||||||
COLLISION;
|
PHYSICS :: 2;
|
||||||
PHYSICS;
|
|
||||||
STATIC;
|
|
||||||
TRIGGER;
|
|
||||||
|
|
||||||
ANIMATED;
|
ANIMATED :: 4;
|
||||||
|
|
||||||
SNAP_TO_GRID;
|
SNAP_TO_GRID :: 8;
|
||||||
UNIFORM_SCALE;
|
UNIFORM_SCALE :: 16;
|
||||||
|
|
||||||
DONT_SAVE;
|
DONT_SAVE :: 32;
|
||||||
DELETED;
|
DELETED :: 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderable_Type :: enum {
|
Renderable_Type :: enum {
|
||||||
@@ -44,6 +41,8 @@ Renderable :: struct {
|
|||||||
visible: bool = true;
|
visible: bool = true;
|
||||||
type : Renderable_Type; @DontSerialize
|
type : Renderable_Type; @DontSerialize
|
||||||
|
|
||||||
|
use_default_pipeline: bool = true;
|
||||||
|
|
||||||
model: Model_Handle; @DontSerialize
|
model: Model_Handle; @DontSerialize
|
||||||
nodes: [MAX_NODES] Node_Render_Data; @DontSerialize
|
nodes: [MAX_NODES] Node_Render_Data; @DontSerialize
|
||||||
num_nodes: s64; @DontSerialize
|
num_nodes: s64; @DontSerialize
|
||||||
@@ -53,6 +52,63 @@ Renderable :: struct {
|
|||||||
|
|
||||||
MAX_CHILDREN :: 16;
|
MAX_CHILDREN :: 16;
|
||||||
|
|
||||||
|
#if PHYSICS {
|
||||||
|
Collider_Type :: enum {
|
||||||
|
SPHERE;
|
||||||
|
BOX;
|
||||||
|
CAPSULE;
|
||||||
|
TRIANGLE_MESH;
|
||||||
|
CONVEX_MESH;
|
||||||
|
CHARACTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
render_collider: bool;
|
||||||
|
collider_color: Color;
|
||||||
|
|
||||||
|
lock: Physics_Lock;
|
||||||
|
offset: Vector3;
|
||||||
|
|
||||||
|
type: Collider_Type;
|
||||||
|
union {
|
||||||
|
sphere : struct {
|
||||||
|
radius: float;
|
||||||
|
}
|
||||||
|
box : struct {
|
||||||
|
half_extent: Vector3;
|
||||||
|
}
|
||||||
|
capsule : struct {
|
||||||
|
radius: float;
|
||||||
|
half_height: float;
|
||||||
|
}
|
||||||
|
character : struct {
|
||||||
|
radius: float;
|
||||||
|
height: float;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
physx_handle: PhysX_Handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Entity :: struct {
|
Entity :: struct {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@@ -78,21 +134,16 @@ Entity :: struct {
|
|||||||
renderable: Renderable;
|
renderable: Renderable;
|
||||||
animator: Animator; @DontSerialize
|
animator: Animator; @DontSerialize
|
||||||
|
|
||||||
// Physics
|
#if PHYSICS {
|
||||||
body : Physics_Body;
|
physics: Physics_Body; @DontSerialize
|
||||||
collider : Collider;
|
}
|
||||||
|
|
||||||
physx_handle: PhysX_Handle;
|
#if NETWORKING {
|
||||||
velocity: Vector3;
|
remote_id: Entity_Id; @DontSerialize
|
||||||
|
client_id: Client_Id; @DontSerialize
|
||||||
// End physics
|
is_proxy: bool; @DontSerialize
|
||||||
|
last_replication_time: float; @DontSerialize
|
||||||
#if NETWORKING {
|
}
|
||||||
remote_id: Entity_Id; @DontSerialize
|
|
||||||
client_id: Client_Id; @DontSerialize
|
|
||||||
is_proxy: bool; @DontSerialize
|
|
||||||
last_replication_time: float; @DontSerialize
|
|
||||||
}
|
|
||||||
|
|
||||||
_locator: Bucket_Locator; @DontSerialize
|
_locator: Bucket_Locator; @DontSerialize
|
||||||
scene: *Scene; @DontSerialize
|
scene: *Scene; @DontSerialize
|
||||||
@@ -164,6 +215,11 @@ get_node_world_position :: (e: *Entity, node_name: string) -> Vector3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
load_model_into_entity :: (e: *Entity, handle: Model_Handle) {
|
load_model_into_entity :: (e: *Entity, handle: Model_Handle) {
|
||||||
|
if handle == 0 {
|
||||||
|
log_error("MODEL: Attempted to load model into entity of type %, but the model handle is zero. This probably means that the model has not been loaded properly.\n", e.type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
model := get_model_by_handle(handle);
|
model := get_model_by_handle(handle);
|
||||||
|
|
||||||
e.renderable.type = .MODEL;
|
e.renderable.type = .MODEL;
|
||||||
@@ -209,10 +265,6 @@ entity_should_be_rendered :: (e: *Entity) -> bool {
|
|||||||
destroy_entity :: (e: *Entity) {
|
destroy_entity :: (e: *Entity) {
|
||||||
call_correct_deinit_entity(e);
|
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 {
|
for 0..e.renderable.num_nodes-1 {
|
||||||
node_data := e.renderable.nodes[it];
|
node_data := e.renderable.nodes[it];
|
||||||
|
|
||||||
|
|||||||
@@ -42,13 +42,6 @@ Vector3i :: struct {
|
|||||||
z: int;
|
z: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color :: #type,isa Vector4;
|
|
||||||
|
|
||||||
Colored_Vert :: struct {
|
|
||||||
position: Vector2;
|
|
||||||
color : Color;
|
|
||||||
}
|
|
||||||
|
|
||||||
AABB :: struct {
|
AABB :: struct {
|
||||||
min: Vector3 = .{FLOAT32_INFINITY, FLOAT32_INFINITY, FLOAT32_INFINITY};
|
min: Vector3 = .{FLOAT32_INFINITY, FLOAT32_INFINITY, FLOAT32_INFINITY};
|
||||||
max: Vector3 = .{-FLOAT32_INFINITY, -FLOAT32_INFINITY, -FLOAT32_INFINITY};
|
max: Vector3 = .{-FLOAT32_INFINITY, -FLOAT32_INFINITY, -FLOAT32_INFINITY};
|
||||||
@@ -423,6 +416,60 @@ ease_in_out_sine :: (x: float) -> float {
|
|||||||
return -(cos(PI * x) - 1.0) * 0.5;
|
return -(cos(PI * x) - 1.0) * 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Color
|
||||||
|
Color :: #type,isa Vector4;
|
||||||
|
|
||||||
|
Colored_Vert :: struct {
|
||||||
|
position: Vector2;
|
||||||
|
color : Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
linear_to_srgb :: (c: float) -> float {
|
||||||
|
if (c <= 0.0031308)
|
||||||
|
return 12.92 * c;
|
||||||
|
else
|
||||||
|
return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
|
||||||
|
}
|
||||||
|
|
||||||
|
linear_to_srgb :: (c: Vector3) -> Vector3 {
|
||||||
|
return Vector3.{
|
||||||
|
linear_to_srgb(c.x),
|
||||||
|
linear_to_srgb(c.y),
|
||||||
|
linear_to_srgb(c.z)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
linear_to_srgb :: (c: $T) -> T {
|
||||||
|
srgb_color := c;
|
||||||
|
srgb_color.x = linear_to_srgb(c.x);
|
||||||
|
srgb_color.y = linear_to_srgb(c.y);
|
||||||
|
srgb_color.z = linear_to_srgb(c.z);
|
||||||
|
return srgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
srgb_to_linear :: (c: float) -> float {
|
||||||
|
if c <= 0.04045
|
||||||
|
return c / 12.92;
|
||||||
|
else
|
||||||
|
return pow((c + 0.055) / 1.055, 2.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
srgb_to_linear :: (c: Vector3) -> Vector3 {
|
||||||
|
return float3(
|
||||||
|
srgbToLinear(c.r),
|
||||||
|
srgbToLinear(c.g),
|
||||||
|
srgbToLinear(c.b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
srgb_to_linear :: (c: $T) -> T {
|
||||||
|
linear_color := c;
|
||||||
|
linear_color.x = srgb_to_linear(c.x);
|
||||||
|
linear_color.y = srgb_to_linear(c.y);
|
||||||
|
linear_color.z = srgb_to_linear(c.z);
|
||||||
|
return linear_color;
|
||||||
|
}
|
||||||
|
|
||||||
#import "PCG";
|
#import "PCG";
|
||||||
#import "Math";
|
#import "Math";
|
||||||
#load "frustum.jai";
|
#load "frustum.jai";
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ Mesh_Entity :: struct {
|
|||||||
init_entity :: (e: *Mesh_Entity) {
|
init_entity :: (e: *Mesh_Entity) {
|
||||||
if e.model_path.count > 0 {
|
if e.model_path.count > 0 {
|
||||||
load_model_into_entity(e, get_or_load_model(e.model_path));
|
load_model_into_entity(e, get_or_load_model(e.model_path));
|
||||||
e.flags |= .COLLISION | .STATIC;
|
#if PHYSICS {
|
||||||
e.collider.type = .MESH;
|
e.flags |= .PHYSICS;
|
||||||
e.collider.bake_mode = .FULL_MESH;
|
e.physics.type = .TRIANGLE_MESH;
|
||||||
|
}
|
||||||
|
//e.physics.box.half_extent = .{0.5,0.5,0.5};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +37,7 @@ mesh_entity_visitor :: (info : *File_Visit_Info, files: *[..] Mesh_Entity_Info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
find_all_mesh_entities :: () {
|
find_all_mesh_entities :: () {
|
||||||
path := "../assets/models/level_design/";
|
path := "../assets/models/level_design";
|
||||||
|
|
||||||
visit_files(path, true, *mesh_entity_files, mesh_entity_visitor);
|
visit_files(path, true, *mesh_entity_files, mesh_entity_visitor);
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,9 @@ Scene :: struct {
|
|||||||
|
|
||||||
mode: Engine_Mode;
|
mode: Engine_Mode;
|
||||||
|
|
||||||
physx_scene: PhysX_Scene;
|
#if PHYSICS {
|
||||||
|
physx_scene: PhysX_Scene;
|
||||||
|
}
|
||||||
|
|
||||||
using custom_fields: _Custom_Scene_Fields;
|
using custom_fields: _Custom_Scene_Fields;
|
||||||
}
|
}
|
||||||
@@ -76,8 +78,6 @@ load_scene :: (name: string, make_current: bool = true) -> *Scene {
|
|||||||
next_entity_id = cast(Entity_Id)(highest + 1);
|
next_entity_id = cast(Entity_Id)(highest + 1);
|
||||||
|
|
||||||
update_transforms(scene);
|
update_transforms(scene);
|
||||||
calculate_aabbs(scene);
|
|
||||||
make_sure_nothing_collides(scene);
|
|
||||||
|
|
||||||
if engine.procs.on_scene_loaded != null {
|
if engine.procs.on_scene_loaded != null {
|
||||||
engine.procs.on_scene_loaded(scene, engine.mode);
|
engine.procs.on_scene_loaded(scene, engine.mode);
|
||||||
@@ -144,7 +144,9 @@ unload_scene :: (scene: *Scene) {
|
|||||||
destroy_entity(e);
|
destroy_entity(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit_physx_scene(scene);
|
#if PHYSICS {
|
||||||
|
deinit_physx_scene(scene);
|
||||||
|
}
|
||||||
|
|
||||||
free(scene.name);
|
free(scene.name);
|
||||||
fini(*scene.pool);
|
fini(*scene.pool);
|
||||||
@@ -163,7 +165,7 @@ reload_scene :: (scene: *Scene) {
|
|||||||
load_scene(name);
|
load_scene(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
create_scene :: (name: string = "", max_entities: s64 = 256) -> *Scene {
|
create_scene :: (name: string = "", max_entities: s64 = 256, trigger_callbacks := false) -> *Scene {
|
||||||
scene := New(Scene);
|
scene := New(Scene);
|
||||||
new_name := name;
|
new_name := name;
|
||||||
|
|
||||||
@@ -195,7 +197,9 @@ create_scene :: (name: string = "", max_entities: s64 = 256) -> *Scene {
|
|||||||
|
|
||||||
array_reserve(*scene.entities, max_entities);
|
array_reserve(*scene.entities, max_entities);
|
||||||
|
|
||||||
init_physx_scene(scene);
|
#if PHYSICS {
|
||||||
|
init_physx_scene(scene);
|
||||||
|
}
|
||||||
|
|
||||||
scene.directional_light.color_and_intensity = .{1,1,1,2};
|
scene.directional_light.color_and_intensity = .{1,1,1,2};
|
||||||
scene.directional_light.direction = to_v4(normalize(Vector3.{0.4, -0.7, 0.4}));
|
scene.directional_light.direction = to_v4(normalize(Vector3.{0.4, -0.7, 0.4}));
|
||||||
@@ -205,6 +209,12 @@ create_scene :: (name: string = "", max_entities: s64 = 256) -> *Scene {
|
|||||||
dir_light_data.direction = scene.directional_light.direction;
|
dir_light_data.direction = scene.directional_light.direction;
|
||||||
upload_data_to_buffer(engine.renderer, engine.directional_light_buffer, *dir_light_data, size_of(Directional_Light_Buffer_Data));
|
upload_data_to_buffer(engine.renderer, engine.directional_light_buffer, *dir_light_data, size_of(Directional_Light_Buffer_Data));
|
||||||
|
|
||||||
|
if trigger_callbacks {
|
||||||
|
if engine.procs.on_scene_loaded != null {
|
||||||
|
engine.procs.on_scene_loaded(scene, engine.mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ Editor :: struct {
|
|||||||
camera: Camera;
|
camera: Camera;
|
||||||
transform_gizmo: Transform_Gizmo;
|
transform_gizmo: Transform_Gizmo;
|
||||||
selected_entities: [..] *Entity;
|
selected_entities: [..] *Entity;
|
||||||
|
selected_entity_transforms : Table(*Entity, Transform);
|
||||||
|
|
||||||
mouse_viewport_state: Interaction_State;
|
mouse_viewport_state: Interaction_State;
|
||||||
last_right_mouse_click_time: float;
|
last_right_mouse_click_time: float;
|
||||||
@@ -171,19 +172,31 @@ init_transform_gizmo :: () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool {
|
update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool {
|
||||||
if engine.editor.selected_entities.count != 1 return false;
|
if engine.editor.selected_entities.count != 1 {
|
||||||
|
// Hardcode to world + translation when selecting multiple entities
|
||||||
selected_entity := engine.editor.selected_entities[0];
|
// We currently don't need to do anything but translate in world space, when having multiple entities selected
|
||||||
|
engine.editor.transform_gizmo.space = .WORLD;
|
||||||
if key_down(.TAB) {
|
engine.editor.transform_gizmo.transform_type = .TRANSLATION;
|
||||||
if engine.editor.transform_gizmo.space == {
|
} else {
|
||||||
case .WORLD;
|
if key_down(.TAB) {
|
||||||
|
if engine.editor.transform_gizmo.space == {
|
||||||
|
case .WORLD;
|
||||||
engine.editor.transform_gizmo.space = .LOCAL;
|
engine.editor.transform_gizmo.space = .LOCAL;
|
||||||
case .LOCAL;
|
case .LOCAL;
|
||||||
engine.editor.transform_gizmo.space = .WORLD;
|
engine.editor.transform_gizmo.space = .WORLD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
position : Vector3;
|
||||||
|
for e: engine.editor.selected_entities {
|
||||||
|
position += e.transform.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
position /= cast(float)engine.editor.selected_entities.count;
|
||||||
|
|
||||||
|
selected_entity := engine.editor.selected_entities[0];
|
||||||
|
|
||||||
if engine.editor.transform_gizmo.space == {
|
if engine.editor.transform_gizmo.space == {
|
||||||
case .WORLD;
|
case .WORLD;
|
||||||
set_rotation(*engine.editor.transform_gizmo.transform, .{0,0,0,1});
|
set_rotation(*engine.editor.transform_gizmo.transform, .{0,0,0,1});
|
||||||
@@ -191,34 +204,59 @@ update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool {
|
|||||||
set_rotation(*engine.editor.transform_gizmo.transform, selected_entity.transform.orientation);
|
set_rotation(*engine.editor.transform_gizmo.transform, selected_entity.transform.orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
engine.editor.transform_gizmo.actual_entity_position = position;
|
||||||
|
|
||||||
if engine.editor.transform_gizmo.transform_type == {
|
if engine.editor.transform_gizmo.transform_type == {
|
||||||
case .TRANSLATION;
|
case .TRANSLATION;
|
||||||
if !key_pressed(.MOUSE_LEFT) {
|
if !key_pressed(.MOUSE_LEFT) {
|
||||||
selected_axis, t := intersect_translation_gizmo(ray);
|
if key_pressed(.CTRL) {
|
||||||
engine.editor.transform_gizmo.selected_axis = selected_axis;
|
engine.editor.transform_gizmo.selected_axis = .NONE;
|
||||||
|
table_reset(*engine.editor.selected_entity_transforms);
|
||||||
|
} else {
|
||||||
|
selected_axis, t := intersect_translation_gizmo(ray);
|
||||||
|
engine.editor.transform_gizmo.selected_axis = selected_axis;
|
||||||
|
table_reset(*engine.editor.selected_entity_transforms);
|
||||||
|
}
|
||||||
} else if engine.editor.transform_gizmo.can_use && engine.editor.transform_gizmo.selected_axis != .NONE {
|
} else if engine.editor.transform_gizmo.can_use && engine.editor.transform_gizmo.selected_axis != .NONE {
|
||||||
first_update := key_down(.MOUSE_LEFT);
|
first_update := key_down(.MOUSE_LEFT);
|
||||||
|
|
||||||
if first_update {
|
if first_update {
|
||||||
engine.editor.transform_gizmo.actual_entity_position = selected_entity.transform.position;
|
|
||||||
push_transform_undo(engine.editor.selected_entities[0]);
|
for engine.editor.selected_entities {
|
||||||
|
push_transform_undo(it);
|
||||||
|
table_add(*engine.editor.selected_entity_transforms, it, it.transform);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the currently selected entity along the selected axis
|
// Move the currently selected entity along the selected axis
|
||||||
axis_vec : Vector3;
|
axis_vec : Vector3;
|
||||||
|
|
||||||
if engine.editor.transform_gizmo.selected_axis == {
|
if engine.editor.transform_gizmo.space == {
|
||||||
case .UP;
|
case .WORLD; {
|
||||||
axis_vec.y = 1;
|
if engine.editor.transform_gizmo.selected_axis == {
|
||||||
case .FORWARD;
|
case .UP;
|
||||||
axis_vec.z = 1;
|
axis_vec.y = 1;
|
||||||
case .RIGHT;
|
case .FORWARD;
|
||||||
axis_vec.x = 1;
|
axis_vec.z = 1;
|
||||||
|
case .RIGHT;
|
||||||
|
axis_vec.x = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .LOCAL; {
|
||||||
|
if engine.editor.transform_gizmo.selected_axis == {
|
||||||
|
case .UP;
|
||||||
|
axis_vec = get_up(selected_entity.transform);
|
||||||
|
case .FORWARD;
|
||||||
|
axis_vec = get_forward(selected_entity.transform);
|
||||||
|
case .RIGHT;
|
||||||
|
axis_vec = get_right(selected_entity.transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r1 : Ray;
|
r1 : Ray;
|
||||||
r1.origin = selected_entity.transform.position;
|
r1.origin = position;
|
||||||
r1.direction = rotate(axis_vec, engine.editor.transform_gizmo.transform.orientation);
|
r1.direction = axis_vec;
|
||||||
|
|
||||||
r2 := normalized_screen_to_ray(*engine.editor.camera, mouse_position);
|
r2 := normalized_screen_to_ray(*engine.editor.camera, mouse_position);
|
||||||
|
|
||||||
@@ -232,21 +270,28 @@ update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool {
|
|||||||
|
|
||||||
position_change := new_position - engine.editor.transform_gizmo.first_hit_position;
|
position_change := new_position - engine.editor.transform_gizmo.first_hit_position;
|
||||||
|
|
||||||
entity_position := engine.editor.transform_gizmo.actual_entity_position + position_change;
|
for e: engine.editor.selected_entities {
|
||||||
|
found, transform := table_find_new(*engine.editor.selected_entity_transforms, e);
|
||||||
|
assert(found);
|
||||||
|
|
||||||
if engine.editor.transform_gizmo.snap_to_grid {
|
entity_position := transform.position + position_change;
|
||||||
snap_interval := Vector3.{1,1,1};
|
if engine.editor.transform_gizmo.snap_to_grid {
|
||||||
entity_position.x -= fmod_cycling(entity_position.x - selected_entity.snap_offset.x, snap_interval.x);// + selected_entity.snap_offset.x;
|
snap_interval := Vector3.{1,1,1};
|
||||||
entity_position.y -= fmod_cycling(entity_position.y - selected_entity.snap_offset.y, snap_interval.y);// + selected_entity.snap_offset.y;
|
entity_position.x -= fmod_cycling(entity_position.x - e.snap_offset.x, snap_interval.x);// + selected_entity.snap_offset.x;
|
||||||
entity_position.z -= fmod_cycling(entity_position.z - selected_entity.snap_offset.z, snap_interval.z);// + selected_entity.snap_offset.z;
|
entity_position.y -= fmod_cycling(entity_position.y - e.snap_offset.y, snap_interval.y);// + selected_entity.snap_offset.y;
|
||||||
} else if selected_entity.flags & Entity_Flags.SNAP_TO_GRID {
|
entity_position.z -= fmod_cycling(entity_position.z - e.snap_offset.z, snap_interval.z);// + selected_entity.snap_offset.z;
|
||||||
entity_position.x -= fmod_cycling(entity_position.x - selected_entity.snap_offset.x, selected_entity.snap_intervals.x);// + selected_entity.snap_offset.x;
|
} else if selected_entity.flags & Entity_Flags.SNAP_TO_GRID {
|
||||||
entity_position.y -= fmod_cycling(entity_position.y - selected_entity.snap_offset.y, selected_entity.snap_intervals.y);// + selected_entity.snap_offset.y;
|
entity_position.x -= fmod_cycling(entity_position.x - e.snap_offset.x, e.snap_intervals.x);// + selected_entity.snap_offset.x;
|
||||||
entity_position.z -= fmod_cycling(entity_position.z - selected_entity.snap_offset.z, selected_entity.snap_intervals.z);// + selected_entity.snap_offset.z;
|
entity_position.y -= fmod_cycling(entity_position.y - e.snap_offset.y, e.snap_intervals.y);// + selected_entity.snap_offset.y;
|
||||||
|
entity_position.z -= fmod_cycling(entity_position.z - e.snap_offset.z, e.snap_intervals.z);// + selected_entity.snap_offset.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.transform.position = entity_position;
|
||||||
|
e.transform.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
selected_entity.transform.position = entity_position;
|
entity_position := engine.editor.transform_gizmo.actual_entity_position + position_change;
|
||||||
selected_entity.transform.dirty = true;
|
engine.editor.transform_gizmo.actual_entity_position = entity_position;
|
||||||
set_position(*engine.editor.transform_gizmo.transform, entity_position);
|
set_position(*engine.editor.transform_gizmo.transform, entity_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,8 +701,16 @@ intersect_rotation_gizmo :: (ray: Ray) -> Transform_Axis, Vector3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_gizmo_buffers :: () {
|
update_gizmo_buffers :: () {
|
||||||
|
position : Vector3;
|
||||||
|
for e: engine.editor.selected_entities {
|
||||||
|
position += e.transform.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
position /= cast(float)engine.editor.selected_entities.count;
|
||||||
|
|
||||||
entity := engine.editor.selected_entities[0];
|
entity := engine.editor.selected_entities[0];
|
||||||
engine.editor.transform_gizmo.transform.position = entity.transform.position;
|
|
||||||
|
engine.editor.transform_gizmo.transform.position = position;
|
||||||
engine.editor.transform_gizmo.transform.orientation = ifx engine.editor.transform_gizmo.space == .LOCAL then entity.transform.orientation else .{0,0,0,1};
|
engine.editor.transform_gizmo.transform.orientation = ifx engine.editor.transform_gizmo.space == .LOCAL then entity.transform.orientation else .{0,0,0,1};
|
||||||
update_matrix(*engine.editor.transform_gizmo.transform);
|
update_matrix(*engine.editor.transform_gizmo.transform);
|
||||||
|
|
||||||
@@ -675,7 +728,7 @@ update_gizmo_buffers :: () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render_transform_gizmo :: () {
|
render_transform_gizmo :: () {
|
||||||
if engine.editor.selected_entities.count == 1 {
|
if engine.editor.selected_entities.count > 0 {
|
||||||
update_gizmo_buffers();
|
update_gizmo_buffers();
|
||||||
renderer := engine.renderer;
|
renderer := engine.renderer;
|
||||||
push_cmd_set_draw_mode(renderer, .FILL);
|
push_cmd_set_draw_mode(renderer, .FILL);
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ pick_scene_view_at :: (camera: Camera, coordinates: Vector2) {
|
|||||||
engine.editor.selected_entities.count = 0;
|
engine.editor.selected_entities.count = 0;
|
||||||
}
|
}
|
||||||
array_add(*engine.editor.selected_entities, hit_entity);
|
array_add(*engine.editor.selected_entities, hit_entity);
|
||||||
|
} else {
|
||||||
|
array_unordered_remove_by_value(*engine.editor.selected_entities, hit_entity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
engine.editor.selected_entities.count = 0;
|
engine.editor.selected_entities.count = 0;
|
||||||
@@ -167,12 +169,14 @@ base_editor_update :: () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
camera := *engine.editor.camera;
|
camera := *engine.editor.camera;
|
||||||
blocking_input := ImGui.GetIO().WantCaptureMouse || ImGui.GetIO().WantCaptureKeyboard;
|
|
||||||
|
capture_mouse := ImGui.GetIO().WantCaptureMouse;
|
||||||
|
capture_keyboard := ImGui.GetIO().WantCaptureKeyboard;
|
||||||
|
|
||||||
if engine.editor.focused_widget == null && engine.mode == .EDITING {
|
if engine.editor.focused_widget == null && engine.mode == .EDITING {
|
||||||
engine.editor.should_check_entities = true;
|
engine.editor.should_check_entities = true;
|
||||||
|
|
||||||
if engine.editor.selected_entities.count == 1 {
|
if engine.editor.selected_entities.count > 0 {
|
||||||
entity := engine.editor.selected_entities[0];
|
entity := engine.editor.selected_entities[0];
|
||||||
gizmo_scale := distance(entity.transform.position, engine.editor.camera.position) * 0.1 * 0.5;
|
gizmo_scale := distance(entity.transform.position, engine.editor.camera.position) * 0.1 * 0.5;
|
||||||
engine.editor.transform_gizmo.uniform_gizmo_scale = gizmo_scale;
|
engine.editor.transform_gizmo.uniform_gizmo_scale = gizmo_scale;
|
||||||
@@ -184,14 +188,14 @@ base_editor_update :: () {
|
|||||||
//coordinates := Vector2.{engine.editor.mouse_viewport_state.normalized_local_mouse_coordinates.x, 1.0 - engine.editor.mouse_viewport_state.normalized_local_mouse_coordinates.y};
|
//coordinates := Vector2.{engine.editor.mouse_viewport_state.normalized_local_mouse_coordinates.x, 1.0 - engine.editor.mouse_viewport_state.normalized_local_mouse_coordinates.y};
|
||||||
ray := normalized_screen_to_ray(engine.editor.camera, coordinates);
|
ray := normalized_screen_to_ray(engine.editor.camera, coordinates);
|
||||||
|
|
||||||
if !blocking_input {
|
if !capture_mouse {
|
||||||
if update_transform_gizmo(ray, coordinates) {
|
if update_transform_gizmo(ray, coordinates) {
|
||||||
engine.editor.should_check_entities = false;
|
engine.editor.should_check_entities = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !blocking_input {
|
if !capture_keyboard {
|
||||||
if key_pressed(.CTRL) && key_down(.Z) {
|
if key_pressed(.CTRL) && key_down(.Z) {
|
||||||
undo();
|
undo();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,7 +228,9 @@ generate_member_ui_imgui :: (type: *Type_Info_Struct, builder: *String_Builder,
|
|||||||
} else if info_struct.name == "Vector3" {
|
} else if info_struct.name == "Vector3" {
|
||||||
print_to_builder(builder, "\tImGui.DragFloat3(tprint_c(\"%\"), *e.%.component);\n", new_path, new_path);
|
print_to_builder(builder, "\tImGui.DragFloat3(tprint_c(\"%\"), *e.%.component);\n", new_path, new_path);
|
||||||
} else if info_struct.name == "Color" || info_struct.name == "Vector4" {
|
} else if info_struct.name == "Color" || info_struct.name == "Vector4" {
|
||||||
print_to_builder(builder, "\tImGui.ColorEdit4(tprint_c(\"%\"), *e.%.component);\n", new_path, new_path);
|
print_to_builder(builder, "\tsrgb_color := linear_to_srgb(e.%);\n", new_path);
|
||||||
|
print_to_builder(builder, "\tImGui.ColorEdit4(tprint_c(\"%\"), *srgb_color.component);\n", new_path);
|
||||||
|
print_to_builder(builder, "\te.% = srgb_to_linear(srgb_color);\n", new_path);
|
||||||
} else {
|
} else {
|
||||||
generate_member_ui_imgui(info_struct, builder, new_path);
|
generate_member_ui_imgui(info_struct, builder, new_path);
|
||||||
}
|
}
|
||||||
|
|||||||
48
module.jai
48
module.jai
@@ -1,4 +1,4 @@
|
|||||||
#module_parameters(WITH_EDITOR := true, WITH_NETWORKING := false, action_type : Type, entity_fields: Type, scene_fields: Type);
|
#module_parameters(WITH_EDITOR := true, WITH_NETWORKING := false, WITH_PHYSICS := false, action_type : Type, entity_fields: Type, scene_fields: Type);
|
||||||
|
|
||||||
// TODO: Add a fallback, if none we're specified
|
// TODO: Add a fallback, if none we're specified
|
||||||
_Custom_Entity_Fields :: entity_fields;
|
_Custom_Entity_Fields :: entity_fields;
|
||||||
@@ -8,6 +8,7 @@ Action :: action_type;
|
|||||||
EDITOR :: WITH_EDITOR;
|
EDITOR :: WITH_EDITOR;
|
||||||
DEBUG :: true;
|
DEBUG :: true;
|
||||||
NETWORKING :: WITH_NETWORKING;
|
NETWORKING :: WITH_NETWORKING;
|
||||||
|
PHYSICS :: WITH_PHYSICS;
|
||||||
|
|
||||||
#if EDITOR {
|
#if EDITOR {
|
||||||
//#load "../editor/scene_editor.jai";
|
//#load "../editor/scene_editor.jai";
|
||||||
@@ -45,8 +46,11 @@ Engine_Core :: struct {
|
|||||||
on_scene_loaded: (*Scene, Engine_Mode);
|
on_scene_loaded: (*Scene, Engine_Mode);
|
||||||
on_pre_scene_loaded: (*Scene, Engine_Mode);
|
on_pre_scene_loaded: (*Scene, Engine_Mode);
|
||||||
on_pre_scene_unloaded: (*Scene);
|
on_pre_scene_unloaded: (*Scene);
|
||||||
on_trigger_enter: (*Entity, *Entity);
|
|
||||||
on_trigger_exit: (*Entity, *Entity);
|
#if PHYSICS {
|
||||||
|
on_trigger_enter: (*Entity, *Entity);
|
||||||
|
on_trigger_exit: (*Entity, *Entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paused: bool;
|
paused: bool;
|
||||||
@@ -82,8 +86,11 @@ coven_init :: (window_title: string, window_width: u32, window_height: u32, full
|
|||||||
init_input();
|
init_input();
|
||||||
init_audio_system();
|
init_audio_system();
|
||||||
init_console();
|
init_console();
|
||||||
|
init_line_rendering();
|
||||||
|
|
||||||
init_physx();
|
#if PHYSICS {
|
||||||
|
init_physx();
|
||||||
|
}
|
||||||
|
|
||||||
#if EDITOR {
|
#if EDITOR {
|
||||||
init_editor();
|
init_editor();
|
||||||
@@ -100,11 +107,13 @@ coven_init :: (window_title: string, window_width: u32, window_height: u32, full
|
|||||||
}
|
}
|
||||||
|
|
||||||
coven_run :: (game_update_proc: (float), game_editor_update_proc: (float), game_update_post_physics_proc: (float)) {
|
coven_run :: (game_update_proc: (float), game_editor_update_proc: (float), game_update_post_physics_proc: (float)) {
|
||||||
if engine.current_scene == null && engine.automatically_load_last_opened_scene {
|
#if EDITOR {
|
||||||
last_opened_scene := get_last_opened_scene_file();
|
if engine.current_scene == null && engine.automatically_load_last_opened_scene {
|
||||||
if last_opened_scene.count > 0 {
|
last_opened_scene := get_last_opened_scene_file();
|
||||||
engine.current_scene = load_scene(last_opened_scene);
|
if last_opened_scene.count > 0 {
|
||||||
free(last_opened_scene);
|
engine.current_scene = load_scene(last_opened_scene);
|
||||||
|
free(last_opened_scene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,20 +166,21 @@ coven_run :: (game_update_proc: (float), game_editor_update_proc: (float), game_
|
|||||||
|
|
||||||
if engine.current_scene != null && !engine.paused {
|
if engine.current_scene != null && !engine.paused {
|
||||||
update_animators(clamped_dt);
|
update_animators(clamped_dt);
|
||||||
update_mesh_colliders(engine.current_scene);
|
|
||||||
update_physics(engine.current_scene, clamped_dt);
|
|
||||||
|
|
||||||
pre_physx_sync(engine.current_scene);
|
#if PHYSICS {
|
||||||
tick_physx(*engine.current_scene.physx_scene, clamped_dt);
|
pre_physx_sync(engine.current_scene);
|
||||||
post_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);
|
// TODO: Move this out into engine.procs
|
||||||
|
game_update_post_physics_proc(clamped_dt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
game_editor_update_proc(clamped_dt);
|
game_editor_update_proc(clamped_dt);
|
||||||
|
|
||||||
if engine.current_scene != null {
|
if engine.current_scene != null {
|
||||||
update_trigger_mesh_colliders(engine.current_scene);
|
//update_trigger_mesh_colliders(engine.current_scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +226,10 @@ switch_engine_mode :: (to_mode: Engine_Mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PHYSICS {
|
||||||
|
#load "physics/physx.jai";
|
||||||
|
}
|
||||||
|
|
||||||
#if NETWORKING {
|
#if NETWORKING {
|
||||||
#load "networking/networking.jai";
|
#load "networking/networking.jai";
|
||||||
}
|
}
|
||||||
@@ -224,7 +238,6 @@ switch_engine_mode :: (to_mode: Engine_Mode) {
|
|||||||
#load "renderer/engine_buffers.jai";
|
#load "renderer/engine_buffers.jai";
|
||||||
#load "renderer/renderer.jai";
|
#load "renderer/renderer.jai";
|
||||||
#load "windowing/window.jai";
|
#load "windowing/window.jai";
|
||||||
#load "physics/physics.jai";
|
|
||||||
|
|
||||||
#load "core/mesh_entity.jai";
|
#load "core/mesh_entity.jai";
|
||||||
#load "core/string_helpers.jai";
|
#load "core/string_helpers.jai";
|
||||||
@@ -241,7 +254,6 @@ switch_engine_mode :: (to_mode: Engine_Mode) {
|
|||||||
#load "core/console.jai";
|
#load "core/console.jai";
|
||||||
#load "audio/audio.jai";
|
#load "audio/audio.jai";
|
||||||
#load "core/fps.jai";
|
#load "core/fps.jai";
|
||||||
#load "physics/physx.jai";
|
|
||||||
|
|
||||||
#scope_export
|
#scope_export
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,17 +1,33 @@
|
|||||||
PHYSX_TEST :: false;
|
PHYSX_DEFAULT_SIMULATION_SHAPE_FLAGS :: cast(u8)(PhysX.PxShapeFlags.Visualization | PhysX.PxShapeFlags.SceneQueryShape | PhysX.PxShapeFlags.SimulationShape);
|
||||||
PHYSX_DEFAULT_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_GRAVITY :: Vector3.{0, -9.81, 0};
|
||||||
|
|
||||||
PhysX_Handle :: #type, distinct u32;
|
PhysX_Handle :: #type, distinct u32;
|
||||||
|
|
||||||
|
PhysX_Actor_Type :: enum {
|
||||||
|
STATIC;
|
||||||
|
DYNAMIC;
|
||||||
|
CHARACTER;
|
||||||
|
}
|
||||||
|
|
||||||
PhysX_Actor :: struct {
|
PhysX_Actor :: struct {
|
||||||
|
type : PhysX_Actor_Type;
|
||||||
|
|
||||||
|
sync_rotation_from_physx: bool = true;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
static: *PhysX.PxRigidStatic;
|
static: *PhysX.PxRigidStatic;
|
||||||
dynamic: *PhysX.PxRigidDynamic;
|
dynamic: *PhysX.PxRigidDynamic;
|
||||||
|
controller: *PhysX.PxController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysX_Scene :: struct {
|
PhysX_Scene :: struct {
|
||||||
scene: *PhysX.PxScene;
|
scene: *PhysX.PxScene;
|
||||||
actors : PArray(PhysX_Actor, PhysX_Handle);
|
actors : PArray(PhysX_Actor, PhysX_Handle);
|
||||||
|
|
||||||
|
controller_manager: *PhysX.PxControllerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_physx :: () {
|
init_physx :: () {
|
||||||
@@ -30,18 +46,83 @@ init_physx :: () {
|
|||||||
|
|
||||||
tolerance_scale : PhysX.PxTolerancesScale;
|
tolerance_scale : PhysX.PxTolerancesScale;
|
||||||
tolerance_scale.length = 1;
|
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);
|
physics = PhysX.PxCreatePhysics(PhysX.PX_PHYSICS_VERSION, foundation, *tolerance_scale, true, pvd, null);
|
||||||
|
|
||||||
|
cooking_params = PhysX.PxCookingParams_new(*tolerance_scale);
|
||||||
|
|
||||||
dispatcher = PhysX.PxDefaultCpuDispatcherCreate(2);
|
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);
|
||||||
|
|
||||||
|
// 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) {
|
tick_physx :: (scene: *PhysX_Scene, dt: float) {
|
||||||
|
// Move all character controllers first
|
||||||
|
filter_data := PhysX.PxFilterData_new();
|
||||||
|
filter := PhysX.PxControllerFilters_new(*filter_data, null, null);
|
||||||
|
for e: engine.current_scene.entities {
|
||||||
|
if e.flags & .PHYSICS {
|
||||||
|
if e.physics.physx_handle != 0 {
|
||||||
|
physx_actor := parray_get(*engine.current_scene.physx_scene.actors, e.physics.physx_handle);
|
||||||
|
if physx_actor {
|
||||||
|
if physx_actor.type == .CHARACTER {
|
||||||
|
vel := e.physics.velocity + PHYSX_GRAVITY * dt;;
|
||||||
|
movement := vel * dt;
|
||||||
|
print("Velocity %\n", movement);
|
||||||
|
flags := PhysX.PxController_move(physx_actor.controller, *movement, 0.0, dt, *filter, null);
|
||||||
|
new_position := PhysX.PxController_getPosition(physx_actor.controller);
|
||||||
|
position := Vector3.{xx new_position.x, xx new_position.y, xx new_position.z};
|
||||||
|
e.physics.velocity = (position - e.transform.position) / dt;
|
||||||
|
set_position(e, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate
|
||||||
PhysX.PxScene_simulate(scene.scene, dt, null, null, 0, true);
|
PhysX.PxScene_simulate(scene.scene, dt, null, null, 0, true);
|
||||||
|
|
||||||
|
// Sync results back
|
||||||
PhysX.PxScene_fetchResults(scene.scene, true, null);
|
PhysX.PxScene_fetchResults(scene.scene, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//custom_filter_shader :: (attributes0: u32, filterData0: PhysX.PxFilterData, attributes1: u32, filterData1: PhysX.PxFilterData, pairFlags: *PhysX.PxPairFlags, constantBlock: *void, constantBlockSize: u32) -> PhysX.PxFilterFlags #c_call {
|
||||||
|
// pairFlags.* = PhysX.PxPairFlags.ContactDefault;
|
||||||
|
// return PhysX.PxFilterFlags.Default;
|
||||||
|
//}
|
||||||
|
|
||||||
|
custom_filter_shader :: (attributes0: *u32, filterData0: *PhysX.PxFilterData, attributes1: *u32, filterData1: *PhysX.PxFilterData, pairFlags: *PhysX.PxPairFlags) -> u16 #c_call {
|
||||||
|
pairFlags.* = PhysX.PxPairFlags.ContactDefault;
|
||||||
|
return xx PhysX.PxFilterFlags.Default;
|
||||||
|
}
|
||||||
|
|
||||||
init_physx_scene :: (game_scene: *Scene) {
|
init_physx_scene :: (game_scene: *Scene) {
|
||||||
tolerance_scale : PhysX.PxTolerancesScale;
|
tolerance_scale : PhysX.PxTolerancesScale;
|
||||||
tolerance_scale.length = 1;
|
tolerance_scale.length = 1;
|
||||||
@@ -51,7 +132,11 @@ init_physx_scene :: (game_scene: *Scene) {
|
|||||||
scene_desc.gravity.y = -9.81;
|
scene_desc.gravity.y = -9.81;
|
||||||
|
|
||||||
scene_desc.cpuDispatcher = xx dispatcher;
|
scene_desc.cpuDispatcher = xx dispatcher;
|
||||||
PhysX.set_default_filter_shader(*scene_desc);
|
scene_desc.simulationEventCallback = event_callback;
|
||||||
|
PhysX.set_custom_filter_shader(*scene_desc, PhysX.create_custom_filter_shader(custom_filter_shader));
|
||||||
|
//scene_desc.filterShader = custom_filter_shader;//
|
||||||
|
//scene_desc.filterShaderData = null;
|
||||||
|
//scene_desc.filterShaderDataSize = 0;
|
||||||
|
|
||||||
scene := PhysX.PxPhysics_createScene(physics, *scene_desc);
|
scene := PhysX.PxPhysics_createScene(physics, *scene_desc);
|
||||||
|
|
||||||
@@ -63,37 +148,11 @@ init_physx_scene :: (game_scene: *Scene) {
|
|||||||
PhysX.PxPvdSceneClient_setScenePvdFlag(pvd_client, xx PhysX.PxPvdSceneFlag.TRANSMIT_SCENEQUERIES, true);
|
PhysX.PxPvdSceneClient_setScenePvdFlag(pvd_client, xx PhysX.PxPvdSceneFlag.TRANSMIT_SCENEQUERIES, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
plane_point := Vector3.{0,10.5,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);
|
|
||||||
}
|
|
||||||
#if PHYSX_TEST {
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
physx_scene : PhysX_Scene;
|
physx_scene : PhysX_Scene;
|
||||||
physx_scene.scene = scene;
|
physx_scene.scene = scene;
|
||||||
physx_scene.actors.data.allocator = game_scene.allocator;
|
physx_scene.actors.data.allocator = game_scene.allocator;
|
||||||
physx_scene.actors.indices.allocator = game_scene.allocator;
|
physx_scene.actors.indices.allocator = game_scene.allocator;
|
||||||
|
physx_scene.controller_manager = PhysX.PxCreateControllerManager(scene, false);
|
||||||
|
|
||||||
game_scene.physx_scene = physx_scene;
|
game_scene.physx_scene = physx_scene;
|
||||||
}
|
}
|
||||||
@@ -104,81 +163,279 @@ deinit_physx_scene :: (game_scene: *Scene) {
|
|||||||
|
|
||||||
pre_physx_sync :: (game_scene: *Scene) {
|
pre_physx_sync :: (game_scene: *Scene) {
|
||||||
for game_scene.entities {
|
for game_scene.entities {
|
||||||
if it.physx_handle != 0 {
|
if it.flags & .PHYSICS {
|
||||||
// @Incomplete: Update the transform!
|
if it.physics.physx_handle != 0 {
|
||||||
physx_actor := parray_get(*game_scene.physx_scene.actors, it.physx_handle);
|
// @Incomplete: Update the transform!
|
||||||
PhysX.PxRigidDynamic_setLinearVelocity(physx_actor.dynamic, *it.velocity, true);
|
physx_actor := parray_get(*game_scene.physx_scene.actors, it.physics.physx_handle);
|
||||||
|
if physx_actor.type == {
|
||||||
|
case .DYNAMIC; {
|
||||||
|
pose := PhysX.PxTransform_new(*it.transform.position, *it.transform.orientation);
|
||||||
|
PhysX.PxRigidActor_setGlobalPose(physx_actor.dynamic, *pose, true);
|
||||||
|
// @Incomplete: Might wanna do this differently or at least not every frame?
|
||||||
|
// We could potentially cache the last saved position and not update the pose, if PhysX is synced up
|
||||||
|
PhysX.PxRigidDynamic_setLinearVelocity(physx_actor.dynamic, *it.physics.velocity, true);
|
||||||
|
}
|
||||||
|
case .STATIC; {
|
||||||
|
pose := PhysX.PxTransform_new(*it.transform.position, *it.transform.orientation);
|
||||||
|
PhysX.PxRigidActor_setGlobalPose(physx_actor.static, *pose, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
create_physx_actor(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post_physx_sync :: (game_scene: *Scene) {
|
post_physx_sync :: (game_scene: *Scene) {
|
||||||
for game_scene.entities {
|
for game_scene.entities {
|
||||||
if it.physx_handle != 0 {
|
if it.flags & .PHYSICS {
|
||||||
physx_actor := parray_get(*game_scene.physx_scene.actors, it.physx_handle);
|
if it.physics.physx_handle != 0 {
|
||||||
vel := PhysX.PxRigidDynamic_getLinearVelocity(physx_actor.dynamic);
|
physx_actor := parray_get(*game_scene.physx_scene.actors, it.physics.physx_handle);
|
||||||
transform := PhysX.PxRigidActor_getGlobalPose(physx_actor.dynamic);
|
if physx_actor.type == .DYNAMIC {
|
||||||
it.velocity = vel;
|
vel := PhysX.PxRigidDynamic_getLinearVelocity(physx_actor.dynamic);
|
||||||
set_position_rotation(it, transform.p, transform.q);
|
it.physics.velocity = vel;
|
||||||
|
|
||||||
|
transform := PhysX.PxRigidActor_getGlobalPose(physx_actor.dynamic);
|
||||||
|
|
||||||
|
if physx_actor.sync_rotation_from_physx || it.physics.type == .SPHERE {
|
||||||
|
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 {
|
create_physx_actor :: (e: *Entity) {
|
||||||
geo := PhysX.PxCapsuleGeometry_new(radius, half_height);
|
if e.physics.type == .CHARACTER {
|
||||||
transform := PhysX.PxTransform_new(*entity.transform.position);
|
material := PhysX.PxPhysics_createMaterial(physics, e.physics.static_friction, e.physics.dynamic_friction, e.physics.restitution);
|
||||||
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.5, 0.5, 0.0);
|
desc := PhysX.PxCapsuleControllerDesc_new_alloc();
|
||||||
|
desc.height = e.physics.character.height;
|
||||||
|
desc.radius = e.physics.character.radius;
|
||||||
|
desc.stepOffset = 0.2;
|
||||||
|
desc.slopeLimit = cos(PI * 0.25);
|
||||||
|
desc.contactOffset = desc.stepOffset * 0.1;
|
||||||
|
desc.material = material;
|
||||||
|
desc.position = .{xx e.transform.position.x, xx e.transform.position.y, xx e.transform.position.z};
|
||||||
|
desc.density = 40.0;
|
||||||
|
desc.userData = null;
|
||||||
|
|
||||||
PhysX.PxMaterial_setRestitutionCombineMode(material,1); // Turn off restitution no matter the other material
|
scene := engine.current_scene.physx_scene;
|
||||||
|
controller := PhysX.PxControllerManager_createController(scene.controller_manager, desc);
|
||||||
|
PhysX.PxCapsuleControllerDesc_delete(desc);
|
||||||
|
|
||||||
shape := PhysX.PxPhysics_createShape(physics, *geo, material, false, PHYSX_DEFAULT_SHAPE_FLAGS);
|
physics_actor : PhysX_Actor;
|
||||||
PhysX.PxRigidActor_attachShape(actor, shape);
|
physics_actor.type = .CHARACTER;
|
||||||
|
physics_actor.sync_rotation_from_physx = false;//e.physics.type != .CAPSULE; // @Incomplete
|
||||||
|
|
||||||
|
physics_actor.controller = controller;
|
||||||
|
|
||||||
PhysX.PxRigidBodyExt_updateMassAndInertia(actor, 10, null, false);
|
e.physics.physx_handle = parray_add(*e.scene.physx_scene.actors, physics_actor);
|
||||||
PhysX.PxScene_addActor(entity.scene.physx_scene.scene, actor, null);
|
e.physics.enabled = true;
|
||||||
|
} else {
|
||||||
|
actor : *PhysX.PxRigidActor;
|
||||||
|
transform : PhysX.PxTransform;
|
||||||
|
position := e.transform.position + e.physics.offset;
|
||||||
|
|
||||||
PhysX.PxShape_release(shape);
|
if e.physics.type == .CAPSULE {
|
||||||
// @Incomplete
|
angle := PI * 0.5;
|
||||||
//PhysX.PxMaterial_release(material);
|
half_angle := angle * 0.5;
|
||||||
|
|
||||||
physics_actor : PhysX_Actor;
|
sin_half := sin(half_angle);
|
||||||
physics_actor.dynamic = actor;
|
cos_half := cos(half_angle);
|
||||||
|
|
||||||
entity.physx_handle = parray_add(*entity.scene.physx_scene.actors, physics_actor);
|
rotation := Quaternion.{0, 0, sin(-PI * 0.25), cos(-PI * 0.25)};
|
||||||
return entity.physx_handle;
|
transform = PhysX.PxTransform_new(*position, *rotation);
|
||||||
|
} else {
|
||||||
|
transform = PhysX.PxTransform_new(*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);
|
||||||
|
}
|
||||||
|
case .CONVEX_MESH; {
|
||||||
|
if e.flags & .RENDERABLE {
|
||||||
|
points : [..] Vector3;
|
||||||
|
points.allocator = temp;
|
||||||
|
indices : [..] u32;
|
||||||
|
indices.allocator = temp;
|
||||||
|
|
||||||
|
model := get_model_by_handle(e.renderable.model);
|
||||||
|
|
||||||
|
for node, node_index: model.nodes {
|
||||||
|
render_data := e.renderable.nodes[node_index];
|
||||||
|
|
||||||
|
success, inv_matrix := inverse(e.transform.model_matrix);
|
||||||
|
// We need to undo the local to world part of every world matrix
|
||||||
|
matrix := inv_matrix * render_data.transform.world_matrix;
|
||||||
|
|
||||||
|
if node.meshes.count > 0 {
|
||||||
|
for m, mi: node.meshes {
|
||||||
|
index_start : u32 = xx indices.count;
|
||||||
|
mesh := parray_get(*engine.renderer.meshes, m);
|
||||||
|
for v: mesh.positions {
|
||||||
|
array_add(*points, v);//transform_position(v, matrix));
|
||||||
|
}
|
||||||
|
|
||||||
|
for i: mesh.indices {
|
||||||
|
array_add(*indices, index_start + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mesh_desc := PhysX.PxConvexMeshDesc_new();
|
||||||
|
mesh_desc.points.count = xx points.count;
|
||||||
|
mesh_desc.points.stride = size_of(Vector3);
|
||||||
|
mesh_desc.points.data = points.data;
|
||||||
|
|
||||||
|
mesh_desc.polygons.count = cast(u32)(indices.count / 3);
|
||||||
|
mesh_desc.polygons.stride = 3 * size_of(u32);
|
||||||
|
mesh_desc.polygons.data = indices.data;
|
||||||
|
|
||||||
|
if !PhysX.PxValidateConvexMesh(*cooking_params, *mesh_desc) {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream : PhysX.PxOutputStream;
|
||||||
|
callback := PhysX.PxGetStandaloneInsertionCallback();
|
||||||
|
//read_buffer : PhysX.PxDefaultMemoryInputData_new(;
|
||||||
|
cond : s32;
|
||||||
|
mesh := PhysX.PxCreateConvexMesh(*cooking_params, *mesh_desc, callback, null);
|
||||||
|
scale := PhysX.PxMeshScale_new(*e.transform.scale);
|
||||||
|
geo = PhysX.PxConvexMeshGeometry_new(mesh, *scale, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .TRIANGLE_MESH; {
|
||||||
|
if e.flags & .RENDERABLE {
|
||||||
|
points : [..] Vector3;
|
||||||
|
points.allocator = temp;
|
||||||
|
indices : [..] u32;
|
||||||
|
indices.allocator = temp;
|
||||||
|
|
||||||
|
model := get_model_by_handle(e.renderable.model);
|
||||||
|
|
||||||
|
for node, node_index: model.nodes {
|
||||||
|
render_data := e.renderable.nodes[node_index];
|
||||||
|
|
||||||
|
success, inv_matrix := inverse(e.transform.model_matrix);
|
||||||
|
// We need to undo the local to world part of every world matrix
|
||||||
|
matrix := inv_matrix * render_data.transform.world_matrix;
|
||||||
|
|
||||||
|
if node.meshes.count > 0 {
|
||||||
|
for m, mi: node.meshes {
|
||||||
|
index_start : u32 = xx indices.count;
|
||||||
|
mesh := parray_get(*engine.renderer.meshes, m);
|
||||||
|
for v: mesh.positions {
|
||||||
|
array_add(*points, transform_position(v, matrix));
|
||||||
|
}
|
||||||
|
|
||||||
|
for i: mesh.indices {
|
||||||
|
array_add(*indices, index_start + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mesh_desc : PhysX.PxTriangleMeshDesc;
|
||||||
|
mesh_desc.points.count = xx points.count;
|
||||||
|
mesh_desc.points.stride = size_of(Vector3);
|
||||||
|
mesh_desc.points.data = points.data;
|
||||||
|
|
||||||
|
mesh_desc.triangles.count = cast(u32)(indices.count / 3);
|
||||||
|
mesh_desc.triangles.stride = 3 * size_of(u32);
|
||||||
|
mesh_desc.triangles.data = indices.data;
|
||||||
|
|
||||||
|
//if !PhysX.PxValidateTriangleMesh(*cooking_params, *mesh_desc) {
|
||||||
|
// assert(false);
|
||||||
|
//}
|
||||||
|
|
||||||
|
callback := PhysX.PxGetStandaloneInsertionCallback();
|
||||||
|
mesh := PhysX.PxCreateTriangleMesh(*cooking_params, *mesh_desc, callback, null);
|
||||||
|
scale := PhysX.PxMeshScale_new(*e.transform.scale);
|
||||||
|
geo = PhysX.PxTriangleMeshGeometry_new(mesh, *scale, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shape := PhysX.PxPhysics_createShape(physics, geo, material, false, ifx e.physics.trigger then PHYSX_DEFAULT_TRIGGER_SHAPE_FLAGS else PHYSX_DEFAULT_SIMULATION_SHAPE_FLAGS);
|
||||||
|
|
||||||
|
// Setup layers
|
||||||
|
filter_data := PhysX.PxFilterData_new();
|
||||||
|
filter_data.word0 = 1;
|
||||||
|
filter_data.word1 = 1;
|
||||||
|
filter_data.word2 = 1;
|
||||||
|
filter_data.word3 = 1;
|
||||||
|
|
||||||
|
PhysX.PxShape_setSimulationFilterData(shape, *filter_data);
|
||||||
|
PhysX.PxShape_setQueryFilterData(shape, *filter_data);
|
||||||
|
|
||||||
|
PhysX.PxRigidActor_attachShape(actor, shape);
|
||||||
|
|
||||||
|
if e.physics.dynamic {
|
||||||
|
PhysX.PxRigidBodyExt_updateMassAndInertia(cast(*PhysX.PxRigidBody)actor, 1000.0, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
create_stack :: (scene: *PhysX.PxScene, t: PhysX.PxTransform, size: u32, half_extent: float) {
|
Hit :: struct {
|
||||||
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;
|
|
||||||
local_tm := PhysX.PxTransform_new(*pos);
|
|
||||||
|
|
||||||
body := PhysX.PxPhysics_createRigidDynamic(physics, *PhysX.PxTransform_transform(*t, *local_tm));
|
|
||||||
PhysX.PxRigidActor_attachShape(body, shape);
|
|
||||||
PhysX.PxRigidBodyExt_updateMassAndInertia(body, 10., null, false);
|
|
||||||
PhysX.PxScene_addActor(scene, body, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//shape->release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
physx_raycast :: (origin: Vector3, direction: Vector3, max_distance: float = 1000.0) -> bool, Hit {
|
||||||
create_dynamic :: (scene: *PhysX.PxScene, t: PhysX.PxTransform, geometry: *PhysX.PxGeometry, velocity: Vector3 = .{}) -> *PhysX.PxRigidDynamic {
|
hit : PhysX.PxRaycastHit;
|
||||||
p := Vector3.{0,0,0};
|
filter_data := PhysX.PxQueryFilterData_new();
|
||||||
transform := PhysX.PxTransform_new(cast(s32)PhysX.PxIDENTITY.PxIdentity);
|
has_hit := PhysX.PxSceneQueryExt_raycastSingle(engine.current_scene.physx_scene.scene, *origin, *direction, max_distance, 0, *hit, *filter_data, null, null);
|
||||||
dynamic := PhysX.PxCreateDynamic(physics, *t, geometry, material, 10.0, *transform);
|
return has_hit, .{};
|
||||||
PhysX.PxRigidBody_setAngularDamping(dynamic, 0.5);
|
|
||||||
PhysX.PxRigidDynamic_setLinearVelocity(dynamic, *velocity, true);
|
|
||||||
PhysX.PxScene_addActor(scene, dynamic, null);
|
|
||||||
return dynamic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysX :: #import "PhysX";
|
PhysX :: #import "PhysX";
|
||||||
@@ -186,9 +443,11 @@ PhysX :: #import "PhysX";
|
|||||||
#scope_file
|
#scope_file
|
||||||
|
|
||||||
physics : *PhysX.PxPhysics;
|
physics : *PhysX.PxPhysics;
|
||||||
|
cooking_params: PhysX.PxCookingParams;
|
||||||
material : *PhysX.PxMaterial;
|
material : *PhysX.PxMaterial;
|
||||||
default_allocator : PhysX.PxAllocatorCallback;
|
default_allocator : PhysX.PxAllocatorCallback;
|
||||||
default_error_callback : PhysX.PxErrorCallback;
|
default_error_callback : PhysX.PxErrorCallback;
|
||||||
default_filter_shader : PhysX.SimulationFilterShader;
|
default_filter_shader : PhysX.SimulationFilterShader;
|
||||||
dispatcher : *PhysX.PxDefaultCpuDispatcher;
|
dispatcher : *PhysX.PxDefaultCpuDispatcher;
|
||||||
|
event_callback : *PhysX.PxSimulationEventCallback;
|
||||||
|
|
||||||
|
|||||||
@@ -1115,7 +1115,7 @@ create_backend_render_target :: (using backend: *D3D11_Backend, width: u32, heig
|
|||||||
texture_desc.Height = height;
|
texture_desc.Height = height;
|
||||||
texture_desc.MipLevels = 1;
|
texture_desc.MipLevels = 1;
|
||||||
texture_desc.ArraySize = 1;
|
texture_desc.ArraySize = 1;
|
||||||
texture_desc.Format = .DXGI_FORMAT_R32G32B32A32_FLOAT; // @Incomplete
|
texture_desc.Format = .DXGI_FORMAT_R16G16B16A16_FLOAT; // @Incomplete
|
||||||
texture_desc.SampleDesc.Count = 1;
|
texture_desc.SampleDesc.Count = 1;
|
||||||
texture_desc.Usage = .D3D11_USAGE_DEFAULT;
|
texture_desc.Usage = .D3D11_USAGE_DEFAULT;
|
||||||
texture_desc.BindFlags = D3D11_BIND_FLAG.RENDER_TARGET | D3D11_BIND_FLAG.SHADER_RESOURCE;
|
texture_desc.BindFlags = D3D11_BIND_FLAG.RENDER_TARGET | D3D11_BIND_FLAG.SHADER_RESOURCE;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
calc_tight_light_projection :: (camera: Camera, light_direction: Vector3) -> Matrix4 {
|
calc_tight_light_projection :: (camera: Camera, light_direction: Vector3) -> Matrix4 {
|
||||||
// View space camera frustum
|
// View space camera frustum
|
||||||
aspect_ratio := cast(float)engine.renderer.render_target_height / cast(float)engine.renderer.render_target_width;
|
aspect_ratio := cast(float)engine.renderer.render_target_height / cast(float)engine.renderer.render_target_width;
|
||||||
frustum := get_frustum(camera.fov, aspect_ratio, camera.z_near-20.0, camera.z_far+20);
|
frustum := get_frustum(camera.fov, aspect_ratio, camera.z_near, camera.z_far);
|
||||||
|
|
||||||
// View frustum back to world space
|
// View frustum back to world space
|
||||||
success :, inv_camera_view := inverse(camera.view_matrix);
|
success :, inv_camera_view := inverse(camera.view_matrix);
|
||||||
|
|||||||
89
renderer/line_rendering.jai
Normal file
89
renderer/line_rendering.jai
Normal file
@@ -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;
|
||||||
@@ -293,7 +293,7 @@ parse_fbx_node :: (model: *Model, fbx_node: *ufbx_node) {
|
|||||||
num_vertices := ufbx_generate_indices(streams.data, num_streams, indices.data, num_indices, null, *error);
|
num_vertices := ufbx_generate_indices(streams.data, num_streams, indices.data, num_indices, null, *error);
|
||||||
|
|
||||||
if error.type != .UFBX_ERROR_NONE {
|
if error.type != .UFBX_ERROR_NONE {
|
||||||
log_error("Failed to generate index buffer\n");
|
log_error("FBX_LOADING: Failed to generate index buffer\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
array_reserve(*mesh.indices, xx num_indices);
|
array_reserve(*mesh.indices, xx num_indices);
|
||||||
@@ -603,7 +603,12 @@ load_fbx :: (path: string) -> Model_Handle, bool {
|
|||||||
scene := ufbx_load_file(to_temp_c_string(path), *opts, *error);
|
scene := ufbx_load_file(to_temp_c_string(path), *opts, *error);
|
||||||
|
|
||||||
if scene == null {
|
if scene == null {
|
||||||
log_error("FBX '%' could not be loaded", path);
|
log_error("FBX_LOADING: FBX '%' could not be loaded.\n", path);
|
||||||
|
return 0, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if scene.materials.count == 0 {
|
||||||
|
log_error("FBX_LOADING: FBX '%' doesn't contain any material data. Currently Coven only supports fbx files that have materials on every mesh.\n", path);
|
||||||
return 0, false;
|
return 0, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,35 +618,49 @@ load_fbx :: (path: string) -> Model_Handle, bool {
|
|||||||
model.name = copy_string(path);
|
model.name = copy_string(path);
|
||||||
|
|
||||||
// Materials
|
// Materials
|
||||||
for i: 0..scene.materials.count - 1 {
|
if scene.materials.count > 0 {
|
||||||
mat := scene.materials.data[i];
|
for i: 0..scene.materials.count - 1 {
|
||||||
model_material : Model_Material;
|
model_material : Model_Material;
|
||||||
model_material.textures.base_color = load_fbx_texture(mat.pbr.base_color, format=.R8G8B8A8_UNORM_SRGB);
|
model_material.base_color.x = 0.3;
|
||||||
model_material.textures.normal = load_fbx_texture(mat.pbr.normal_map, format=.R8G8B8A8_UNORM);
|
model_material.base_color.y = 0.3;
|
||||||
|
model_material.base_color.z = 0.3;
|
||||||
|
model_material.base_color.w = 1.0;
|
||||||
|
|
||||||
for 0..mat.props.props.count-1 {
|
mat := scene.materials.data[i];
|
||||||
prop := mat.props.props.data[it];
|
model_material.textures.base_color = load_fbx_texture(mat.pbr.base_color, format=.R8G8B8A8_UNORM_SRGB);
|
||||||
prop_name := to_string(prop.name.data,, allocator=temp);
|
model_material.textures.normal = load_fbx_texture(mat.pbr.normal_map, format=.R8G8B8A8_UNORM);
|
||||||
if prop_name == "DiffuseColor" {
|
|
||||||
model_material.base_color.x = xx prop.value_vec3.x;
|
for 0..mat.props.props.count-1 {
|
||||||
model_material.base_color.y = xx prop.value_vec3.y;
|
prop := mat.props.props.data[it];
|
||||||
model_material.base_color.z = xx prop.value_vec3.z;
|
prop_name := to_string(prop.name.data,, allocator=temp);
|
||||||
model_material.base_color.w = 1.0;
|
if prop_name == "DiffuseColor" {
|
||||||
|
model_material.base_color.x = xx prop.value_vec3.x;
|
||||||
|
model_material.base_color.y = xx prop.value_vec3.y;
|
||||||
|
model_material.base_color.z = xx prop.value_vec3.z;
|
||||||
|
model_material.base_color.w = 1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//mat.pbr.base_factor;
|
||||||
|
//create_texture :: (using renderer: *Renderer, data: *void, width: u32, height: u32, channels: u32, path: string = "", generate_mips: bool = true) -> Texture_Handle {
|
||||||
|
//Material &dst = materials[i + 1];
|
||||||
|
//dst.base_factor.value.x = 1.0f;
|
||||||
|
//setup_texture(dst.base_factor, mat->pbr.base_factor);
|
||||||
|
//setup_texture(dst.base_color, mat->pbr.base_color);
|
||||||
|
//setup_texture(dst.roughness, mat->pbr.roughness);
|
||||||
|
//setup_texture(dst.metallic, mat->pbr.metalness);
|
||||||
|
//setup_texture(dst.emission_factor, mat->pbr.emission_factor);
|
||||||
|
//setup_texture(dst.emission_color, mat->pbr.emission_color);
|
||||||
|
//dst.base_color.image.srgb = true;
|
||||||
|
//dst.emission_color.image.srgb = true;
|
||||||
|
array_add(*model.materials, model_material);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
model_material : Model_Material;
|
||||||
|
model_material.base_color.x = 0.3;
|
||||||
|
model_material.base_color.y = 0.3;
|
||||||
|
model_material.base_color.z = 0.3;
|
||||||
|
model_material.base_color.w = 1.0;
|
||||||
|
|
||||||
//mat.pbr.base_factor;
|
|
||||||
//create_texture :: (using renderer: *Renderer, data: *void, width: u32, height: u32, channels: u32, path: string = "", generate_mips: bool = true) -> Texture_Handle {
|
|
||||||
//Material &dst = materials[i + 1];
|
|
||||||
//dst.base_factor.value.x = 1.0f;
|
|
||||||
//setup_texture(dst.base_factor, mat->pbr.base_factor);
|
|
||||||
//setup_texture(dst.base_color, mat->pbr.base_color);
|
|
||||||
//setup_texture(dst.roughness, mat->pbr.roughness);
|
|
||||||
//setup_texture(dst.metallic, mat->pbr.metalness);
|
|
||||||
//setup_texture(dst.emission_factor, mat->pbr.emission_factor);
|
|
||||||
//setup_texture(dst.emission_color, mat->pbr.emission_color);
|
|
||||||
//dst.base_color.image.srgb = true;
|
|
||||||
//dst.emission_color.image.srgb = true;
|
|
||||||
array_add(*model.materials, model_material);
|
array_add(*model.materials, model_material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ Renderer :: struct {
|
|||||||
|
|
||||||
default_pipelines : struct {
|
default_pipelines : struct {
|
||||||
message_text : Pipeline_State_Handle;
|
message_text : Pipeline_State_Handle;
|
||||||
|
entity_pipeline : Pipeline_State_Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
default_samplers : struct {
|
default_samplers : struct {
|
||||||
@@ -684,6 +685,7 @@ create_renderer :: (window: *Window) -> *Renderer {
|
|||||||
init_freetype();
|
init_freetype();
|
||||||
init_default_meshes();
|
init_default_meshes();
|
||||||
init_trigger_line_rendering();
|
init_trigger_line_rendering();
|
||||||
|
init_default_pipelines();
|
||||||
|
|
||||||
array_reserve(*engine.renderer.command_buffer.commands, 4096);
|
array_reserve(*engine.renderer.command_buffer.commands, 4096);
|
||||||
|
|
||||||
@@ -698,36 +700,36 @@ create_renderer :: (window: *Window) -> *Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init_default_pipelines :: () {
|
init_default_pipelines :: () {
|
||||||
{
|
//{
|
||||||
vs := create_vertex_shader(renderer, "../modules/Coven/shaders/font.hlsl", "VS");
|
// vs := create_vertex_shader(renderer, "../modules/Coven/shaders/font.hlsl", "VS");
|
||||||
ps := create_pixel_shader(renderer, "../modules/Coven/shaders/font.hlsl", "PS");
|
// ps := create_pixel_shader(renderer, "../modules/Coven/shaders/font.hlsl", "PS");
|
||||||
|
|
||||||
layout : [3] Vertex_Data_Info;
|
// layout : [3] Vertex_Data_Info;
|
||||||
layout[0] = .{0,.POSITION2D, 0};
|
// layout[0] = .{0,.POSITION2D, 0};
|
||||||
layout[1] = .{0,.TEXCOORD0, 0};
|
// layout[1] = .{0,.TEXCOORD0, 0};
|
||||||
layout[2] = .{0,.COLOR_WITH_ALPHA, 0};
|
// layout[2] = .{0,.COLOR_WITH_ALPHA, 0};
|
||||||
|
|
||||||
params : [2] Shader_Parameter;
|
// params : [2] Shader_Parameter;
|
||||||
params[0].shader = .PIXEL;
|
// params[0].shader = .PIXEL;
|
||||||
params[0].type = .SAMPLER;
|
// params[0].type = .SAMPLER;
|
||||||
params[0].name = "ss";
|
// params[0].name = "ss";
|
||||||
params[0].slot = 0;
|
// params[0].slot = 0;
|
||||||
params[0].mapping = .CLAMP_SAMPLER;
|
// params[0].mapping = .CLAMP_SAMPLER;
|
||||||
|
|
||||||
params[1].shader = .PIXEL;
|
// params[1].shader = .PIXEL;
|
||||||
params[1].type = .TEXTURE;
|
// params[1].type = .TEXTURE;
|
||||||
params[1].name = "tex";
|
// params[1].name = "tex";
|
||||||
params[1].slot = 1;
|
// params[1].slot = 1;
|
||||||
|
|
||||||
engine.renderer.default_pipelines.message_text = create_pipeline_state(renderer, vs, ps, layout, params, blend_type=.TRANSPARENT);
|
// engine.renderer.default_pipelines.message_text = create_pipeline_state(renderer, vs, ps, layout, params, blend_type=.TRANSPARENT);
|
||||||
}
|
//}
|
||||||
|
|
||||||
{
|
//{
|
||||||
vs := create_vertex_shader_from_source(engine.renderer, FALLBACK_SHADER, "VS", mesh_data_types = .[.POSITION]);
|
// vs := create_vertex_shader_from_source(engine.renderer, "fallback", FALLBACK_SHADER, "VS", mesh_data_types = .[.POSITION]);
|
||||||
ps := create_pixel_shader_from_source(engine.renderer, FALLBACK_SHADER, "PS");
|
// ps := create_pixel_shader_from_source(engine.renderer, "fallback", FALLBACK_SHADER, "PS");
|
||||||
|
|
||||||
projectile_pipeline = create_pipeline_state2(engine.renderer, vs, ps, blend_type=.OPAQUE);
|
// projectile_pipeline = create_pipeline_state2(engine.renderer, vs, ps, blend_type=.OPAQUE);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
init_default_meshes :: () {
|
init_default_meshes :: () {
|
||||||
@@ -736,20 +738,20 @@ init_default_meshes :: () {
|
|||||||
// Since this is used for sprites, we want the origin to be in the center in x, but at the bottom in y
|
// Since this is used for sprites, we want the origin to be in the center in x, but at the bottom in y
|
||||||
mesh : Mesh;
|
mesh : Mesh;
|
||||||
mesh.name = copy_string("Plane");
|
mesh.name = copy_string("Plane");
|
||||||
array_add(*mesh.positions, .{1, 0, 1});
|
array_add(*mesh.positions, .{0.5, 0, 0.5});
|
||||||
array_add(*mesh.positions, .{-1, 0, -1});
|
array_add(*mesh.positions, .{-0.5, 0, -0.5});
|
||||||
array_add(*mesh.positions, .{1, 0, -1});
|
array_add(*mesh.positions, .{0.5, 0, -0.5});
|
||||||
array_add(*mesh.positions, .{-1, 0, 1});
|
array_add(*mesh.positions, .{-0.5, 0, 0.5});
|
||||||
|
|
||||||
array_add(*mesh.normals, .{0, 1, 0});
|
array_add(*mesh.normals, .{0, 1, 0});
|
||||||
array_add(*mesh.normals, .{0, 1, 0});
|
array_add(*mesh.normals, .{0, 1, 0});
|
||||||
array_add(*mesh.normals, .{0, 1, 0});
|
array_add(*mesh.normals, .{0, 1, 0});
|
||||||
array_add(*mesh.normals, .{0, 1, 0});
|
array_add(*mesh.normals, .{0, 1, 0});
|
||||||
|
|
||||||
array_add(*mesh.texcoords, .{1, 0});
|
|
||||||
array_add(*mesh.texcoords, .{0, 1});
|
|
||||||
array_add(*mesh.texcoords, .{1, 1});
|
array_add(*mesh.texcoords, .{1, 1});
|
||||||
array_add(*mesh.texcoords, .{0, 0});
|
array_add(*mesh.texcoords, .{0, 0});
|
||||||
|
array_add(*mesh.texcoords, .{1, 0});
|
||||||
|
array_add(*mesh.texcoords, .{0, 1});
|
||||||
|
|
||||||
array_add(*mesh.indices, 2);
|
array_add(*mesh.indices, 2);
|
||||||
array_add(*mesh.indices, 1);
|
array_add(*mesh.indices, 1);
|
||||||
@@ -862,6 +864,10 @@ deinit_renderer :: (renderer: *Renderer) {
|
|||||||
deinit_backend(engine.renderer.backend);
|
deinit_backend(engine.renderer.backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_default_entity_pipeline :: (pipeline: Pipeline_State_Handle) {
|
||||||
|
engine.renderer.default_pipelines.entity_pipeline = pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
get_shader :: (handle: Shader_Handle) -> Shader {
|
get_shader :: (handle: Shader_Handle) -> Shader {
|
||||||
assert(handle - 1 < xx engine.renderer.shaders.count);
|
assert(handle - 1 < xx engine.renderer.shaders.count);
|
||||||
return engine.renderer.shaders[handle-1];
|
return engine.renderer.shaders[handle-1];
|
||||||
@@ -1689,6 +1695,55 @@ render :: () {
|
|||||||
// #load "ui.jai";
|
// #load "ui.jai";
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
render_default_renderable_entities :: () {
|
||||||
|
for e: engine.current_scene.entities {
|
||||||
|
if e.enabled && e.flags & .RENDERABLE && e.renderable.use_default_pipeline {
|
||||||
|
render_entity(e, engine.renderer.default_pipelines.entity_pipeline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render_entity :: (e: *Entity, pipeline: Pipeline_State_Handle) {
|
||||||
|
if e.renderable.type == {
|
||||||
|
case .MODEL; {
|
||||||
|
model := get_model_by_handle(e.renderable.model);
|
||||||
|
if model == null return;
|
||||||
|
|
||||||
|
for node, node_index: model.nodes {
|
||||||
|
render_data := e.renderable.nodes[node_index];
|
||||||
|
if !render_data.enabled continue;
|
||||||
|
|
||||||
|
if node.meshes.count > 0 {
|
||||||
|
for m, mi: node.meshes {
|
||||||
|
push_cmd_set_pipeline_state(engine.renderer, pipeline);
|
||||||
|
push_cmd_set_constant_buffer(engine.renderer, 1, engine.directional_light_buffer, .VERTEX);
|
||||||
|
push_cmd_set_constant_buffer(engine.renderer, 1, engine.directional_light_buffer, .PIXEL);
|
||||||
|
|
||||||
|
push_cmd_set_constant_buffer(engine.renderer, 2, render_data.transform_buffer, .VERTEX);
|
||||||
|
push_cmd_set_constant_buffer(engine.renderer, 3, render_data.material_buffer, .PIXEL);
|
||||||
|
|
||||||
|
if node.num_bones > 0 {
|
||||||
|
push_cmd_set_constant_buffer(engine.renderer, 4, render_data.bone_buffers[mi], .VERTEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh := parray_get(*engine.renderer.meshes, m);
|
||||||
|
|
||||||
|
vb := get_mesh_vb(mesh);
|
||||||
|
push_cmd_set_vertex_buffer(engine.renderer, vb);
|
||||||
|
|
||||||
|
if mesh.ib != 0 {
|
||||||
|
push_cmd_set_index_buffer(engine.renderer, mesh.ib);
|
||||||
|
push_cmd_draw_indexed(engine.renderer, mesh.indices.count);
|
||||||
|
} else {
|
||||||
|
push_cmd_draw(engine.renderer, mesh.positions.count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#scope_module
|
#scope_module
|
||||||
#load "dx11_renderer.jai";
|
#load "dx11_renderer.jai";
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#load "line_rendering.jai";
|
||||||
|
|
||||||
TRIGGER_VERTEX_SHADER :: #string END
|
TRIGGER_VERTEX_SHADER :: #string END
|
||||||
cbuffer CameraData : register(b0)
|
cbuffer CameraData : register(b0)
|
||||||
{
|
{
|
||||||
@@ -59,65 +61,32 @@ init_trigger_line_rendering :: () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render_trigger_lines :: () {
|
render_trigger_lines :: () {
|
||||||
vertices: [..] Trigger_Line_Vertex;
|
#if PHYSICS {
|
||||||
vertices.allocator = temp;
|
for e: engine.current_scene.entities {
|
||||||
|
if e.physics.type == .BOX {
|
||||||
|
if !e.physics.render_collider continue;
|
||||||
|
|
||||||
for e: engine.current_scene.entities {
|
color := Color.{0,0,1,1};//e.collider.aabb_color;
|
||||||
if e.collider.render_aabb {
|
aabb := AABB.{-e.physics.box.half_extent, e.physics.box.half_extent};
|
||||||
color := e.collider.aabb_color;
|
|
||||||
scale := e.transform.scale;
|
|
||||||
aabb := e.collider.aabb;
|
|
||||||
|
|
||||||
min := transform_position(aabb.min, e.transform.model_matrix);
|
min := aabb.min;
|
||||||
max := transform_position(aabb.max, e.transform.model_matrix);
|
max := aabb.max;
|
||||||
|
|
||||||
array_add(*vertices, .{.{min.x, min.y, min.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);
|
||||||
array_add(*vertices, .{.{min.x, min.y, max.z}, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
array_add(*vertices, .{.{max.x, min.y, min.z}, color});
|
render_lines();
|
||||||
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});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user