wip collider shapes

This commit is contained in:
jacob 2024-10-08 12:15:11 -05:00
parent 5ef8ee3f40
commit d52effe5c1
10 changed files with 1460 additions and 200 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,28 @@
#ifndef COLLIDER_H #ifndef COLLIDER_H
#define COLLIDER_H #define COLLIDER_H
#define COLLIDER_DEBUG RTC
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
extern u32 collider_debug_steps; extern u32 collider_debug_steps;
#endif #endif
struct collider_menkowski_point { struct v2 collider_support_point(struct collider_shape *a, struct xform xf, struct v2 dir);
struct v2 p0; /* Support point of first shape in dir */
struct v2 p1; /* Support point of second shape in -dir */
struct v2 p; /* Menkowski difference point */
};
#if 0
/* Returns simple true or false indicating shape collision */ /* Returns simple true or false indicating shape collision */
b32 collider_collision_boolean(struct v2_array shape0, struct v2_array shape1); b32 collider_collision_boolean(struct collider_shape *shape0, struct collider_shape *shape1);
#endif
struct collider_simplex { struct collider_simplex {
u32 len; u32 len;
struct v2 a, b, c; struct v2 a, b, c;
}; };
struct collider_menkowski_point {
struct v2 p0; /* Support point of first shape in dir */
struct v2 p1; /* Support point of second shape in -dir */
struct v2 p; /* Menkowski difference point */
};
struct collider_collision_point { struct collider_collision_point {
struct v2 point; struct v2 point;
f32 separation; f32 separation;
@ -39,11 +41,12 @@ struct collider_collision_points_result {
i32 path; i32 path;
struct collider_simplex simplex; struct collider_simplex simplex;
struct collider_prototype prototype; struct collider_prototype prototype;
struct v2 a0, b0, a1, b1; /* Clipping faces */
}; };
struct collider_collision_points_result collider_collision_points(struct v2_array shape0, struct v2_array shape1); struct collider_collision_points_result collider_collision_points(struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
struct v2_array menkowski(struct arena *arena, struct v2_array poly0, struct v2_array poly1); struct v2_array menkowski(struct arena *arena, struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
struct v2_array cloud(struct arena *arena, struct v2_array poly0, struct v2_array poly1); struct v2_array cloud(struct arena *arena, struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
#endif #endif

View File

@ -615,6 +615,16 @@ struct trs {
f32 r; f32 r;
}; };
/* ========================== *
* Collider types
* ========================== */
struct collider_shape {
struct v2 points[8];
u32 count;
f32 radius;
};
/* ========================== * /* ========================== *
* Common utilities * Common utilities
* ========================== */ * ========================== */

View File

@ -45,6 +45,8 @@
#define USER_INTERP_OFFSET_TICK_RATIO 1.1 #define USER_INTERP_OFFSET_TICK_RATIO 1.1
#define USER_INTERP_ENABLED 0 #define USER_INTERP_ENABLED 0
#define COLLIDER_DEBUG RTC
/* ========================== * /* ========================== *
* Settings * Settings
* ========================== */ * ========================== */

View File

@ -4,6 +4,7 @@
#include "font.h" #include "font.h"
#include "scratch.h" #include "scratch.h"
#include "sprite.h" #include "sprite.h"
#include "collider.h"
GLOBAL struct { GLOBAL struct {
struct renderer_handle solid_white; struct renderer_handle solid_white;
@ -269,6 +270,25 @@ void draw_solid_arrow_ray(struct renderer_canvas *canvas, struct v2 pos, struct
draw_solid_arrow_line(canvas, pos, end, thickness, arrowhead_height, color); draw_solid_arrow_line(canvas, pos, end, thickness, arrowhead_height, color);
} }
void draw_solid_collider_line(struct renderer_canvas *canvas, struct xform draw_xf, struct collider_shape shape, struct xform shape_xf, f32 thickness, u32 color, u32 detail)
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct v2 *points = arena_push_array(scratch.arena, struct v2, detail);
for (u32 i = 0; i < detail; ++i) {
f32 angle = ((f32)i / (f32)detail) * (2 * PI);
struct v2 dir = V2(math_cos(angle), math_sin(angle));
struct v2 p = collider_support_point(&shape, shape_xf, dir);
p = xform_mul_v2(draw_xf, p);
points[i] = p;
}
struct v2_array poly = { .points = points, .count = detail };
draw_solid_poly_line(canvas, poly, true, thickness, color);
scratch_end(scratch);
}
/* ========================== * /* ========================== *
* Text * Text
* ========================== */ * ========================== */

View File

@ -38,6 +38,7 @@ void draw_solid_quad_line(struct renderer_canvas *canvas, struct quad quad, f32
void draw_solid_rect_line(struct renderer_canvas *canvas, struct rect rect, f32 thickness, u32 color); void draw_solid_rect_line(struct renderer_canvas *canvas, struct rect rect, f32 thickness, u32 color);
void draw_solid_arrow_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, f32 thickness, f32 arrowhead_height, u32 color); void draw_solid_arrow_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, f32 thickness, f32 arrowhead_height, u32 color);
void draw_solid_arrow_ray(struct renderer_canvas *canvas, struct v2 pos, struct v2 rel, f32 thickness, f32 arrowhead_height, u32 color); void draw_solid_arrow_ray(struct renderer_canvas *canvas, struct v2 pos, struct v2 rel, f32 thickness, f32 arrowhead_height, u32 color);
void draw_solid_collider_line(struct renderer_canvas *canvas, struct xform draw_xf, struct collider_shape shape, struct xform shape_xf, f32 thickness, u32 color, u32 detail);
void draw_text(struct renderer_canvas *canvas, struct font *font, struct v2 pos, struct string str); void draw_text(struct renderer_canvas *canvas, struct font *font, struct v2 pos, struct string str);
void draw_text_ex(struct renderer_canvas *canvas, struct font *font, struct v2 pos, f32 scale, struct string str); void draw_text_ex(struct renderer_canvas *canvas, struct font *font, struct v2 pos, f32 scale, struct string str);

View File

@ -115,17 +115,12 @@ struct entity {
/* TODO: Remove this (testing) */ /* TODO: Remove this (testing) */
struct entity_handle colliding_with; b32 colliding;
struct collider_simplex simplex; struct collider_collision_points_result res;
struct collider_prototype prototype;
struct v2 pendir;
b32 solved;
i32 path;
b32 test_torque_applied; b32 test_torque_applied;
struct collider_shape local_collider;

View File

@ -131,9 +131,9 @@ INTERNAL void spawn_test_entities(f32 offset)
struct entity *player_ent; struct entity *player_ent;
{ {
//struct v2 pos = V2(0.25, -10); //struct v2 pos = V2(0.25, -10);
struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -7);
//struct v2 pos = V2(0.25, -5.27); //struct v2 pos = V2(0.25, -5.27);
//struct v2 pos = V2(0.25, -2); struct v2 pos = V2(0.25, -2);
//struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */ //struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */
//struct v2 pos = V2(1.1230469346046448864129274625156 - 0.0001, -1); /* Touching right side of box */ //struct v2 pos = V2(1.1230469346046448864129274625156 - 0.0001, -1); /* Touching right side of box */
//struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */ //struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */
@ -165,8 +165,8 @@ INTERNAL void spawn_test_entities(f32 offset)
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
//e->control_force = 4500; //e->control_force = 4500;
//e->control_force = 1200; e->control_force = 1200;
e->control_force = 250; //e->control_force = 250;
e->control_torque = 10; e->control_torque = 10;
e->control.focus = V2(0, -1); e->control.focus = V2(0, -1);
@ -205,13 +205,13 @@ INTERNAL void spawn_test_entities(f32 offset)
} }
/* Box */ /* Box */
#if 1
if (!G.first_spawn) { if (!G.first_spawn) {
struct v2 pos = V2(0.5, -1);
//struct v2 pos = V2(0.5, -1); //struct v2 pos = V2(0.5, 20);
struct v2 pos = V2(0.5, 20);
//struct v2 pos = V2(1, -1); //struct v2 pos = V2(1, -1);
//struct v2 size = V2(1, 1); struct v2 size = V2(1, 1);
struct v2 size = V2(500, 50); //struct v2 size = V2(500, 50);
//f32 rot = PI / 4; //f32 rot = PI / 4;
f32 rot = 0; f32 rot = 0;
struct entity *e = entity_alloc(root); struct entity *e = entity_alloc(root);
@ -233,6 +233,7 @@ INTERNAL void spawn_test_entities(f32 offset)
entity_set_xform(e, XFORM_TRS(.t = pos, .s = size, .r = rot)); entity_set_xform(e, XFORM_TRS(.t = pos, .s = size, .r = rot));
} }
#endif
/* Camera */ /* Camera */
if (!G.first_spawn) { if (!G.first_spawn) {
@ -279,27 +280,14 @@ INTERNAL void create_contact_manifolds(void)
/* FIXME: I think it's technically possible for manifold entities to swap between iterations */ /* FIXME: I think it's technically possible for manifold entities to swap between iterations */
struct entity_store *store = G.tick.entity_store; struct entity_store *store = G.tick.entity_store;
struct sprite_scope *sprite_frame_scope = G.sprite_frame_scope;
struct entity *root = G.root; struct entity *root = G.root;
for (u64 e0_index = 0; e0_index < store->reserved; ++e0_index) { for (u64 e0_index = 0; e0_index < store->reserved; ++e0_index) {
struct entity *e0 = &store->entities[e0_index]; struct entity *e0 = &store->entities[e0_index];
if (!entity_is_valid_and_active(e0)) continue; if (!entity_is_valid_and_active(e0)) continue;
if (!entity_has_prop(e0, ENTITY_PROP_PHYSICAL)) continue; if (!entity_has_prop(e0, ENTITY_PROP_PHYSICAL)) continue;
/* Calculate entity 0 shape */
struct xform e0_xf = entity_get_xform(e0); struct xform e0_xf = entity_get_xform(e0);
struct quad e0_quad; struct collider_shape e0_collider = e0->local_collider;
struct v2_array e0_poly;
{
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e0->sprite);
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e0->animation_frame);
e0_quad = xform_mul_quad(e0->sprite_local_xform, quad_from_rect(slice.rect));
e0_quad = xform_mul_quad(e0_xf, e0_quad);
e0_poly = (struct v2_array) {
.count = ARRAY_COUNT(e0_quad.e),
.points = e0_quad.e
};
}
for (u64 e1_index = 0; e1_index < store->reserved; ++e1_index) { for (u64 e1_index = 0; e1_index < store->reserved; ++e1_index) {
struct entity *e1 = &store->entities[e1_index]; struct entity *e1 = &store->entities[e1_index];
@ -351,34 +339,17 @@ INTERNAL void create_contact_manifolds(void)
/* Calculate entity 1 shape */ /* Calculate entity 1 shape */
struct xform e1_xf = entity_get_xform(e1); struct xform e1_xf = entity_get_xform(e1);
struct quad e1_quad; struct collider_shape e1_collider = e1->local_collider;
struct v2_array e1_poly;
{
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e1->sprite);
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e1->animation_frame);
e1_quad = xform_mul_quad(e1->sprite_local_xform, quad_from_rect(slice.rect));
e1_quad = xform_mul_quad(e1_xf, e1_quad);
e1_poly = (struct v2_array) {
.count = ARRAY_COUNT(e1_quad.e),
.points = e1_quad.e
};
}
struct collider_collision_points_result res = collider_collision_points(e0_poly, e1_poly); struct collider_collision_points_result res = collider_collision_points(&e0_collider, &e1_collider, e0_xf, e1_xf);
/* Parts of algorithm are hard-coded to support 2 contact points */ /* Parts of algorithm are hard-coded to support 2 contact points */
CT_ASSERT(ARRAY_COUNT(manifold->contacts) == 2); CT_ASSERT(ARRAY_COUNT(manifold->contacts) == 2);
CT_ASSERT(ARRAY_COUNT(res.points) == 2); CT_ASSERT(ARRAY_COUNT(res.points) == 2);
/* TODO: Remove this (debugging) */
if (manifold) {
manifold->prototype = res.prototype;
manifold->simplex = res.simplex;
manifold->solved = res.solved;
manifold->path = res.path;
}
if (res.num_points > 0) { /* TODO: Move this down */
if (res.num_points > 0 || COLLIDER_DEBUG) {
if (!manifold) { if (!manifold) {
manifold = entity_alloc(root); manifold = entity_alloc(root);
manifold->manifold_e0 = e0->handle; manifold->manifold_e0 = e0->handle;
@ -394,19 +365,21 @@ INTERNAL void create_contact_manifolds(void)
*entry = manifold->handle; *entry = manifold->handle;
fixed_dict_set(&dict_arena, &dict, manifold_key, entry); fixed_dict_set(&dict_arena, &dict, manifold_key, entry);
} }
}
manifold->manifold_normal = res.normal;
/* TODO: Remove this (debugging) */ /* TODO: Remove this (debugging) */
{ {
manifold->prototype = res.prototype; e0->colliding = true;
manifold->simplex = res.simplex; e1->colliding = true;
manifold->solved = res.solved; manifold->res = res;
} }
} }
if (res.num_points > 0) {
struct v2 normal = res.normal; struct v2 normal = res.normal;
struct v2 tangent = v2_perp(normal); struct v2 tangent = v2_perp(normal);
manifold->manifold_normal = normal;
/* Delete old contacts that are no longer present */ /* Delete old contacts that are no longer present */
for (u32 i = 0; i < manifold->num_contacts; ++i) { for (u32 i = 0; i < manifold->num_contacts; ++i) {
struct contact *old = &manifold->contacts[i]; struct contact *old = &manifold->contacts[i];
@ -500,16 +473,14 @@ INTERNAL void create_contact_manifolds(void)
} else if (manifold) { } else if (manifold) {
#if COLLIDER_DEBUG
if (e0->valid) e0->colliding = false;
if (e1->valid) e1->colliding = false;
manifold->num_contacts = 0;
#else
/* No longer colliding, delete manifold */ /* No longer colliding, delete manifold */
#if 0
manifold->num_contacts = 0; manifold->num_contacts = 0;
entity_enable_prop(manifold, ENTITY_PROP_RELEASE); entity_enable_prop(manifold, ENTITY_PROP_RELEASE);
#else
if (res.solved) {
manifold->prototype.len = 0;
manifold->simplex.len = 0;
}
manifold->num_contacts = 0;
#endif #endif
} }
} }
@ -600,7 +571,7 @@ INTERNAL struct soft_result make_soft(f32 hertz, f32 zeta, f32 h)
INTERNAL void solve_collisions(f32 dt, b32 apply_bias) INTERNAL void solve_collisions(f32 dt, b32 apply_bias)
{ {
#if 1 #if 0
struct entity_store *store = G.tick.entity_store; struct entity_store *store = G.tick.entity_store;
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
struct entity *manifold = &store->entities[entity_index]; struct entity *manifold = &store->entities[entity_index];
@ -878,7 +849,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
case GAME_CMD_KIND_SPAWN_TEST: case GAME_CMD_KIND_SPAWN_TEST:
{ {
logf_info("Spawning (test)"); logf_info("Spawning (test)");
#if 1 #if 0
for (u32 i = 0; i < 50; ++i) { for (u32 i = 0; i < 50; ++i) {
spawn_test_entities(-(f32)i); spawn_test_entities(-(f32)i);
} }
@ -924,7 +895,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
} }
/* ========================== * /* ========================== *
* Update animations from sprite * Update entity from sprite
* ========================== */ * ========================== */
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
@ -934,8 +905,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
/* Update animation */ /* Update animation */
{
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite);
{
struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name); struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name);
f64 time_in_frame = ent->animation_time_in_frame + G.tick.dt; f64 time_in_frame = ent->animation_time_in_frame + G.tick.dt;
@ -961,7 +932,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
/* Update sprite local xform */ /* Update sprite local xform */
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); {
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("pivot"), ent->animation_frame); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("pivot"), ent->animation_frame);
struct v2 sprite_size = v2_div(sheet->frame_size, (f32)PIXELS_PER_UNIT); struct v2 sprite_size = v2_div(sheet->frame_size, (f32)PIXELS_PER_UNIT);
@ -975,6 +946,14 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
ent->sprite_local_xform = xf; ent->sprite_local_xform = xf;
} }
/* Update collider */
{
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), ent->animation_frame);
ent->local_collider = collider_from_quad(xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect)));
ent->local_collider.radius = 0.1;
}
}
/* ========================== * /* ========================== *
* Update attachments * Update attachments
* ========================== */ * ========================== */
@ -1208,7 +1187,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
* Create forces from control focus (aim) * Create forces from control focus (aim)
* ========================== */ * ========================== */
#if 0 #if 1
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
struct entity *ent = &store->entities[entity_index]; struct entity *ent = &store->entities[entity_index];
if (!entity_is_valid_and_active(ent)) continue; if (!entity_is_valid_and_active(ent)) continue;
@ -1361,7 +1340,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
* Create ground friction force (gravity) * Create ground friction force (gravity)
* ========================== */ * ========================== */
#if 0 #if 1
/* TODO: Do this globally rather than creating entities for constant forces */ /* TODO: Do this globally rather than creating entities for constant forces */
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
struct entity *ent = &store->entities[entity_index]; struct entity *ent = &store->entities[entity_index];
@ -1423,31 +1402,28 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
* Physics * Physics
* ========================== */ * ========================== */
#if 1
{ {
integrate_velocities_from_forces(dt); integrate_velocities_from_forces(dt);
create_contact_manifolds(); create_contact_manifolds();
(UNUSED)create_contact_manifolds;
(UNUSED)solve_collisions;
(UNUSED)integrate_positions_from_velocities;
(UNUSED)warm_start_contacts;
f32 substep_dt = dt / GAME_PHYSICS_SUBSTEPS; f32 substep_dt = dt / GAME_PHYSICS_SUBSTEPS;
for (u32 i = 0; i < GAME_PHYSICS_SUBSTEPS; ++i) { for (u32 i = 0; i < GAME_PHYSICS_SUBSTEPS; ++i) {
#if 1
#if GAME_PHYSICS_ENABLE_WARM_STARTING #if GAME_PHYSICS_ENABLE_WARM_STARTING
warm_start_contacts(); warm_start_contacts();
#endif #endif
solve_collisions(substep_dt, true); solve_collisions(substep_dt, true);
integrate_positions_from_velocities(substep_dt); integrate_positions_from_velocities(substep_dt);
solve_collisions(substep_dt, false); /* Relaxation */ solve_collisions(substep_dt, false); /* Relaxation */
}
}
#else #else
//solve_collisions(substep_dt, true); (UNUSED)create_contact_manifolds;
solve_collisions(substep_dt, false); (UNUSED)solve_collisions;
integrate_positions_from_velocities(substep_dt); (UNUSED)integrate_velocities_from_forces;
(UNUSED)integrate_positions_from_velocities;
(UNUSED)warm_start_contacts;
#endif #endif
}
}
/* ========================== * /* ========================== *
* Initialize bullet kinematics from sources * Initialize bullet kinematics from sources
@ -1465,7 +1441,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
struct v2 pos = xform_mul_v2(src_xf, ent->bullet_src_pos); struct v2 pos = xform_mul_v2(src_xf, ent->bullet_src_pos);
struct v2 impulse = xform_basis_mul_v2(src_xf, ent->bullet_src_dir); struct v2 impulse = xform_basis_mul_v2(src_xf, ent->bullet_src_dir);
impulse = v2_mul(v2_norm(impulse), ent->bullet_impulse); impulse = v2_with_len(impulse, ent->bullet_impulse);
struct xform xf = XFORM_TRS(.t = pos, .r = v2_angle(impulse) + PI / 2); struct xform xf = XFORM_TRS(.t = pos, .r = v2_angle(impulse) + PI / 2);
entity_set_xform(ent, xf); entity_set_xform(ent, xf);

View File

@ -671,12 +671,11 @@ INLINE struct v2 v2_perp_towards_dir(struct v2 v, struct v2 dir)
return v2_perp_mul(v, (wedge >= 0) - (wedge < 0)); return v2_perp_mul(v, (wedge >= 0) - (wedge < 0));
} }
INLINE struct v2 v2_norm(struct v2 a) INLINE struct v2 v2_with_len(struct v2 a, f32 len)
{ {
f32 l_sq = a.x * a.x + a.y * a.y; f32 l_sq = a.x * a.x + a.y * a.y;
if (l_sq != 0) { if (l_sq != 0) {
/* TODO: Benchmark vs math_rqsrt(l) */ f32 denom = len / math_sqrt(l_sq);
f32 denom = 1.f / math_sqrt(l_sq);
a.x *= denom; a.x *= denom;
a.y *= denom; a.y *= denom;
} }
@ -694,6 +693,11 @@ INLINE struct v2 v2_clamp_len(struct v2 a, f32 max)
return a; return a;
} }
INLINE struct v2 v2_norm(struct v2 a)
{
return v2_with_len(a, 1.f);
}
INLINE struct v2 v2_round(struct v2 a) INLINE struct v2 v2_round(struct v2 a)
{ {
return V2(math_round(a.x), math_round(a.y)); return V2(math_round(a.x), math_round(a.y));
@ -923,8 +927,8 @@ INLINE struct xform xform_rotated_to(struct xform xf, f32 r)
INLINE struct xform xform_scaled_to(struct xform xf, struct v2 s) INLINE struct xform xform_scaled_to(struct xform xf, struct v2 s)
{ {
xf.bx = v2_mul(v2_norm(xf.bx), s.x); xf.bx = v2_with_len(xf.bx, s.x);
xf.by = v2_mul(v2_norm(xf.by), s.y); xf.by = v2_with_len(xf.by, s.y);
return xf; return xf;
} }
@ -1095,7 +1099,6 @@ INLINE struct quad quad_from_rect(struct rect rect)
(struct v2) { rect.x + rect.width, rect.y }, /* Top right */ (struct v2) { rect.x + rect.width, rect.y }, /* Top right */
(struct v2) { rect.x + rect.width, rect.y + rect.height }, /* Bottom right */ (struct v2) { rect.x + rect.width, rect.y + rect.height }, /* Bottom right */
(struct v2) { rect.x, rect.y + rect.height }, /* Bottom left */ (struct v2) { rect.x, rect.y + rect.height }, /* Bottom left */
}; };
} }
@ -1151,6 +1154,22 @@ INLINE struct quad quad_floor(struct quad quad)
}; };
} }
/* ========================== *
* Collider
* ========================== */
INLINE struct collider_shape collider_from_quad(struct quad quad)
{
struct collider_shape res;
res.points[0] = quad.p1;
res.points[1] = quad.p2;
res.points[2] = quad.p3;
res.points[3] = quad.p4;
res.count = 4;
res.radius = 0;
return res;
}
/* ========================== * /* ========================== *
* Convex polygon * Convex polygon
* ========================== */ * ========================== */

View File

@ -889,8 +889,6 @@ INTERNAL void user_update(void)
if (G.debug_draw && !skip_debug_draw) { if (G.debug_draw && !skip_debug_draw) {
struct temp_arena temp = arena_temp_begin(scratch.arena); struct temp_arena temp = arena_temp_begin(scratch.arena);
b32 colliding = false;
#if 0 #if 0
struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);
if (disp_font) { if (disp_font) {
@ -949,6 +947,7 @@ INTERNAL void user_update(void)
} }
#endif #endif
#if 0
/* Draw slices */ /* Draw slices */
if (!sprite_tag_is_nil(ent->sprite)) { if (!sprite_tag_is_nil(ent->sprite)) {
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite); struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite);
@ -983,65 +982,46 @@ INTERNAL void user_update(void)
if (slice.has_ray) { if (slice.has_ray) {
struct v2 ray = xform_basis_mul_v2(sprite_xform, slice.dir); struct v2 ray = xform_basis_mul_v2(sprite_xform, slice.dir);
ray = xform_basis_mul_v2(G.world_view, ray); ray = xform_basis_mul_v2(G.world_view, ray);
ray = v2_mul(v2_norm(ray), 25); ray = v2_with_len(ray, 25);
draw_solid_arrow_ray(G.viewport_canvas, center, ray, 2, 10, ray_color); draw_solid_arrow_ray(G.viewport_canvas, center, ray, 2, 10, ray_color);
} }
} }
} }
} }
#endif
/* Draw collider */
if (entity_has_prop(ent, ENTITY_PROP_PHYSICAL)) {
struct collider_shape collider = ent->local_collider;
u32 color = ent->colliding ? RGBA_32_F(1, 1, 1, 1) : RGBA_32_F(1, 1, 1, 0.25);
f32 thickness = 2;
u32 detail = 32;
//draw_solid_collider_line(G.viewport_canvas, collider, xform_mul(G.world_view, xf), thickness, color, detail);
draw_solid_collider_line(G.viewport_canvas, G.world_view, collider, xf, thickness, color, detail);
}
/* Draw collision */ /* Draw collision */
if (entity_has_prop(ent, ENTITY_PROP_MANIFOLD)) { if (entity_has_prop(ent, ENTITY_PROP_MANIFOLD)) {
struct entity *e0 = entity_from_handle(store, ent->manifold_e0); struct entity *e0 = entity_from_handle(store, ent->manifold_e0);
struct entity *e1 = entity_from_handle(store, ent->manifold_e1); struct entity *e1 = entity_from_handle(store, ent->manifold_e1);
(UNUSED)e1; (UNUSED)e1;
(UNUSED)colliding;
struct xform e0_xf = entity_get_xform(e0); struct xform e0_xf = entity_get_xform(e0);
struct xform e1_xf = entity_get_xform(e1); struct xform e1_xf = entity_get_xform(e1);
/* Create shapes */ struct collider_shape e0_collider = e0->local_collider;
struct quad e0_quad; struct collider_shape e1_collider = e1->local_collider;
struct v2_array e0_poly;
struct quad e1_quad;
struct v2_array e1_poly;
{
{
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e0->sprite);
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e0->animation_frame);
e0_quad = xform_mul_quad(e0->sprite_local_xform, quad_from_rect(slice.rect));
e0_quad = xform_mul_quad(e0_xf, e0_quad);
e0_poly = (struct v2_array) {
.count = ARRAY_COUNT(e0_quad.e),
.points = e0_quad.e
};
}
{
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e1->sprite);
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e1->animation_frame);
e1_quad = xform_mul_quad(e1->sprite_local_xform, quad_from_rect(slice.rect));
e1_quad = xform_mul_quad(e1_xf, e1_quad);
e1_poly = (struct v2_array) {
.count = ARRAY_COUNT(e1_quad.e),
.points = e1_quad.e
};
}
}
(UNUSED)e0_quad;
(UNUSED)e0_poly;
(UNUSED)e1_quad;
(UNUSED)e1_poly;
#if 0 #if 1
/* Draw menkowski */ /* Draw menkowski */
{ {
u32 color = ent->solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1); u32 color = ent->res.solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1);
f32 thickness = 2; f32 thickness = 2;
(UNUSED)thickness; (UNUSED)thickness;
struct v2_array m = menkowski(temp.arena, e0_poly, e1_poly); struct v2_array m = menkowski(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf);
//struct v2_array m = menkowski(temp.arena, e0_poly, e1_poly, v2_sub(ent->xf1.og, ent->xf0.og)); //struct v2_array m = menkowski(temp.arena, e0_collider, e1_collider, v2_sub(ent->xf1.og, ent->xf0.og));
for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]); for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]);
draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color); draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color);
@ -1053,7 +1033,7 @@ INTERNAL void user_update(void)
u32 color = RGBA_32_F(1, 1, 1, 1); u32 color = RGBA_32_F(1, 1, 1, 1);
f32 radius = 2; f32 radius = 2;
struct v2_array m = cloud(temp.arena, e0_poly, e1_poly); struct v2_array m = cloud(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf);
for (u64 i = 0; i < m.count; ++i) { for (u64 i = 0; i < m.count; ++i) {
struct v2 p = xform_mul_v2(G.world_view, m.points[i]);; struct v2 p = xform_mul_v2(G.world_view, m.points[i]);;
@ -1080,8 +1060,8 @@ INTERNAL void user_update(void)
u32 color = RGBA_32_F(1, 1, 1, 0.25); u32 color = RGBA_32_F(1, 1, 1, 0.25);
struct v2_array m = { struct v2_array m = {
.points = ent->prototype.points, .points = ent->res.prototype.points,
.count = ent->prototype.len .count = ent->res.prototype.len
}; };
for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]); for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]);
draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color); draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color);
@ -1090,12 +1070,12 @@ INTERNAL void user_update(void)
/* Draw simplex */ /* Draw simplex */
{ {
f32 thickness = 2; f32 thickness = 2;
u32 line_color = colliding ? COLOR_WHITE: COLOR_YELLOW; u32 line_color = COLOR_YELLOW;
u32 color_first = RGBA_32_F(1, 0, 0, 0.75); u32 color_first = RGBA_32_F(1, 0, 0, 0.75);
u32 color_second = RGBA_32_F(0, 1, 0, 0.75); u32 color_second = RGBA_32_F(0, 1, 0, 0.75);
u32 color_third = RGBA_32_F(0, 0, 1, 0.75); u32 color_third = RGBA_32_F(0, 0, 1, 0.75);
struct collider_simplex simplex = ent->simplex; struct collider_simplex simplex = ent->res.simplex;
struct v2 simplex_points[] = { simplex.a, simplex.b, simplex.c }; struct v2 simplex_points[] = { simplex.a, simplex.b, simplex.c };
for (u64 i = 0; i < ARRAY_COUNT(simplex_points); ++i) simplex_points[i] = xform_mul_v2(G.world_view, simplex_points[i]); for (u64 i = 0; i < ARRAY_COUNT(simplex_points); ++i) simplex_points[i] = xform_mul_v2(G.world_view, simplex_points[i]);
struct v2_array simplex_array = { .count = simplex.len, .points = simplex_points }; struct v2_array simplex_array = { .count = simplex.len, .points = simplex_points };
@ -1145,7 +1125,8 @@ INTERNAL void user_update(void)
struct v2 end = xform_mul_v2(G.world_view, v2_add(point, v2_mul(v2_norm(ent->manifold_normal), len))); struct v2 end = xform_mul_v2(G.world_view, v2_add(point, v2_mul(v2_norm(ent->manifold_normal), len)));
draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color);
} }
/* Draw id */ #if 0
/* Draw info text */
{ {
struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);
if (disp_font) { if (disp_font) {
@ -1161,7 +1142,7 @@ INTERNAL void user_update(void)
"separation: %F" "separation: %F"
); );
struct string text = string_format(temp.arena, fmt, struct string text = string_format(temp.arena, fmt,
FMT_SINT(ent->path), FMT_SINT(ent->res.path),
FMT_UINT(e0->handle.idx), FMT_UINT(e0->handle.idx),
FMT_UINT(e1->handle.idx), FMT_UINT(e1->handle.idx),
FMT_HEX(contact.id), FMT_HEX(contact.id),
@ -1173,6 +1154,23 @@ INTERNAL void user_update(void)
draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, point)), V2(0, offset_px)), text); draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, point)), V2(0, offset_px)), text);
} }
} }
#endif
}
}
/* Draw clipping */
{
f32 thickness = 2;
u32 color = RGBA_32_F(1, 0, 1, 0.75);
{
struct v2 start = xform_mul_v2(G.world_view, ent->res.a0);
struct v2 end = xform_mul_v2(G.world_view, ent->res.b0);
draw_solid_line(G.viewport_canvas, start, end, thickness, color);
}
{
struct v2 start = xform_mul_v2(G.world_view, ent->res.a1);
struct v2 end = xform_mul_v2(G.world_view, ent->res.b1);
draw_solid_line(G.viewport_canvas, start, end, thickness, color);
} }
} }
#endif #endif