wip collider shapes
This commit is contained in:
parent
5ef8ee3f40
commit
d52effe5c1
1318
src/collider.c
1318
src/collider.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||||
|
|||||||
10
src/common.h
10
src/common.h
@ -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
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
@ -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
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
20
src/draw.c
20
src/draw.c
@ -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
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
11
src/entity.h
11
src/entity.h
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
152
src/game.c
152
src/game.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Remove this (debugging) */
|
|
||||||
{
|
|
||||||
manifold->prototype = res.prototype;
|
|
||||||
manifold->simplex = res.simplex;
|
|
||||||
manifold->solved = res.solved;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
manifold->manifold_normal = res.normal;
|
||||||
|
|
||||||
|
/* TODO: Remove this (debugging) */
|
||||||
|
{
|
||||||
|
e0->colliding = true;
|
||||||
|
e1->colliding = true;
|
||||||
|
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,18 +932,26 @@ 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);
|
||||||
|
|
||||||
struct v2 dir = v2_mul_v2(sprite_size, slice.dir);
|
struct v2 dir = v2_mul_v2(sprite_size, slice.dir);
|
||||||
f32 rot = v2_angle(dir) + PI / 2;
|
f32 rot = v2_angle(dir) + PI / 2;
|
||||||
|
|
||||||
struct xform xf = XFORM_IDENT;
|
struct xform xf = XFORM_IDENT;
|
||||||
xf = xform_rotated(xf, -rot);
|
xf = xform_rotated(xf, -rot);
|
||||||
xf = xform_scaled(xf, sprite_size);
|
xf = xform_scaled(xf, sprite_size);
|
||||||
xf = xform_translated(xf, v2_neg(slice.center));
|
xf = xform_translated(xf, v2_neg(slice.center));
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -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
|
|
||||||
//solve_collisions(substep_dt, true);
|
|
||||||
solve_collisions(substep_dt, false);
|
|
||||||
integrate_positions_from_velocities(substep_dt);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
(UNUSED)create_contact_manifolds;
|
||||||
|
(UNUSED)solve_collisions;
|
||||||
|
(UNUSED)integrate_velocities_from_forces;
|
||||||
|
(UNUSED)integrate_positions_from_velocities;
|
||||||
|
(UNUSED)warm_start_contacts;
|
||||||
|
#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);
|
||||||
|
|||||||
31
src/math.h
31
src/math.h
@ -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
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
90
src/user.c
90
src/user.c
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user