merge sort typo

This commit is contained in:
jacob 2025-01-16 14:33:13 -06:00
parent d2cfeed161
commit 6c5183fe0a
2 changed files with 447 additions and 437 deletions

View File

@ -18,6 +18,7 @@
#include "atomic.h"
#include "collider.h"
#include "rng.h"
#include "log.h"
struct bind_state {
b32 is_held; /* Is this bind held down this frame */
@ -433,7 +434,7 @@ INTERNAL void debug_draw_movement(struct entity *ent)
* Sort entities
* ========================== */
INTERNAL SORT_COMPARE_FUNC_DEF(sort_entities, arg_a, arg_b, udata)
INTERNAL SORT_COMPARE_FUNC_DEF(entity_draw_order_cmp, arg_a, arg_b, udata)
{
(UNUSED)udata;
struct entity *a = *(struct entity **)arg_a;
@ -914,490 +915,499 @@ INTERNAL void user_update(void)
u64 sorted_count = 0;
{
/* Copy valid entities */
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
struct entity *ent = &store->entities[entity_index];
if (entity_is_valid_and_active(ent)) {
*arena_push(scratch.arena, struct entity *) = ent;
++sorted_count;
{
__profscope(copy_sprites_for_sorting);
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
struct entity *ent = &store->entities[entity_index];
if (entity_is_valid_and_active(ent)) {
*arena_push(scratch.arena, struct entity *) = ent;
++sorted_count;
}
}
}
/* Sort */
merge_sort(sorted, sorted_count, sizeof(*sorted), sort_entities, NULL);
logf_info("Sorting %F sprites", FMT_UINT(sorted_count));
{
__profscope(sort_sprites);
merge_sort(sorted, sorted_count, sizeof(*sorted), entity_draw_order_cmp, NULL);
}
}
/* ========================== *
* Draw entities
* ========================== */
for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) {
__profscope(user_entity_iter);
struct entity *ent = sorted[sorted_index];
if (!entity_is_valid_and_active(ent)) continue;
//if (sprite_tag_is_nil(ent->sprite)) continue;
{
__profscope(draw_entities);
for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) {
struct entity *ent = sorted[sorted_index];
if (!entity_is_valid_and_active(ent)) continue;
//if (sprite_tag_is_nil(ent->sprite)) continue;
struct sprite_tag sprite = ent->sprite;
struct sprite_tag sprite = ent->sprite;
struct entity *parent = entity_from_handle(store, ent->parent);
struct entity *parent = entity_from_handle(store, ent->parent);
struct xform xf = entity_get_xform(ent);
struct xform parent_xf = entity_get_xform(parent);
struct xform xf = entity_get_xform(ent);
struct xform parent_xf = entity_get_xform(parent);
b32 skip_debug_draw = !G.debug_camera && ent == active_camera;
b32 skip_debug_draw_transform = entity_has_prop(ent, ENTITY_PROP_CAMERA);
skip_debug_draw_transform = true;
b32 skip_debug_draw = !G.debug_camera && ent == active_camera;
b32 skip_debug_draw_transform = entity_has_prop(ent, ENTITY_PROP_CAMERA);
skip_debug_draw_transform = true;
struct xform sprite_xform = xf;
struct xform sprite_xform = xf;
/* Draw tracer */
if (entity_has_prop(ent, ENTITY_PROP_TRACER)) {
struct v2 velocity = ent->tracer_start_velocity;
/* Draw tracer */
if (entity_has_prop(ent, ENTITY_PROP_TRACER)) {
struct v2 velocity = ent->tracer_start_velocity;
struct v2 a = ent->tracer_start;
struct v2 b = xf.og;
struct v2 c = ent->tracer_gradient_start;
struct v2 d = ent->tracer_gradient_end;
struct v2 a = ent->tracer_start;
struct v2 b = xf.og;
struct v2 c = ent->tracer_gradient_start;
struct v2 d = ent->tracer_gradient_end;
struct v2 vcd = v2_sub(d, c);
struct v2 vca = v2_sub(a, c);
struct v2 vdb = v2_sub(b, d);
struct v2 vdc = v2_neg(vcd);
struct v2 vcd = v2_sub(d, c);
struct v2 vca = v2_sub(a, c);
struct v2 vdb = v2_sub(b, d);
struct v2 vdc = v2_neg(vcd);
f32 opacity_a = 1;
if (v2_dot(velocity, vca) < 0) {
a = c;
opacity_a = 0;
} else {
opacity_a = v2_dot(vcd, vca) / v2_len_sq(vcd);
}
f32 opacity_b = clamp_f32(1.f - (v2_dot(vdc, vdb) / v2_len_sq(vdc)), 0, 1);
f32 thickness = 0.01;
u32 color_start = RGBA_32_F(1, 0.5, 0, opacity_a);
u32 color_end = RGBA_32_F(1, 0.8, 0.4, opacity_b);
if (opacity_b > 0.99f) {
draw_solid_circle(G.world_canvas, b, thickness / 2, color_end, 20);
}
draw_gradient_line(G.world_canvas, a, b, thickness, color_start, color_end);
f32 opacity_a = 1;
if (v2_dot(velocity, vca) < 0) {
a = c;
opacity_a = 0;
} else {
opacity_a = v2_dot(vcd, vca) / v2_len_sq(vcd);
}
f32 opacity_b = clamp_f32(1.f - (v2_dot(vdc, vdb) / v2_len_sq(vdc)), 0, 1);
/* Draw sprite */
//if ((false)) {
if (!sprite_tag_is_nil(sprite)) {
/* Calculate sprite xform */
sprite_xform = xform_mul(xf, ent->sprite_local_xform);
f32 thickness = 0.01;
u32 color_start = RGBA_32_F(1, 0.5, 0, opacity_a);
u32 color_end = RGBA_32_F(1, 0.8, 0.4, opacity_b);
if (opacity_b > 0.99f) {
draw_solid_circle(G.world_canvas, b, thickness / 2, color_end, 20);
}
draw_gradient_line(G.world_canvas, a, b, thickness, color_start, color_end);
}
/* Draw sprite */
//if ((false)) {
if (!sprite_tag_is_nil(sprite)) {
/* Calculate sprite xform */
sprite_xform = xform_mul(xf, ent->sprite_local_xform);
/* Async load */
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite);
struct sprite_texture *texture = sprite_texture_from_tag_async(sprite_frame_scope, sprite);
(UNUSED)texture;
/* TODO: Fade in placeholder if texture isn't loaded */
if (sheet->loaded) {
struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, ent->animation_frame);
struct quad quad = xform_mul_quad(sprite_xform, QUAD_UNIT_SQUARE_CENTERED);
struct draw_sprite_params params = DRAW_SPRITE_PARAMS(.sprite = sprite, .tint = ent->sprite_tint, .clip = frame.clip);
draw_sprite_quad(G.world_canvas, params, quad);
}
}
/* Debug draw entity info */
if (G.debug_draw && !skip_debug_draw) {
struct temp_arena temp = arena_temp_begin(scratch.arena);
if (entity_has_prop(ent, ENTITY_PROP_PHYSICAL_DYNAMIC) || entity_has_prop(ent, ENTITY_PROP_PHYSICAL_KINEMATIC)) {
debug_draw_movement(ent);
}
if (!skip_debug_draw_transform) {
u32 color_x = RGBA_32_F(1, 0, 0, 0.3);
u32 color_y = RGBA_32_F(0, 1, 0, 0.3);
debug_draw_xform(xf, color_x, color_y);
}
/* Draw focus arrow */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, ent->sprite);
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("attach.wep"), ent->animation_frame);
struct v2 start = xform_mul_v2(sprite_xform, slice.center);
start = xform_mul_v2(G.world_view, start);
struct v2 end = v2_add(xf.og, ent->control.focus);
end = xform_mul_v2(G.world_view, end);
draw_solid_arrow_line(G.viewport_canvas, start, end, 3, 10, RGBA_32_F(1, 1, 1, 0.5));
}
#if 0
/* Draw slices */
if (!sprite_tag_is_nil(ent->sprite)) {
/* Async load */
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite);
struct sprite_texture *texture = sprite_texture_from_tag_async(sprite_frame_scope, sprite);
(UNUSED)texture;
u32 quad_color = RGBA_32_F(1, 0, 0.5, 1);
u32 point_color = RGBA_32_F(1, 0, 0, 1);
u32 ray_color = RGBA_32_F(1, 0, 0.5, 1);
if (colliding) {
quad_color = RGBA_32_F(1, 1, 1, 1);
}
for (u64 i = 0; i < sheet->slice_groups_count; ++i) {
struct sprite_sheet_slice_group *group = &sheet->slice_groups[i];
if (string_ends_with(group->name, STR(".ray"))) continue;
for (u32 j = 0; j < group->per_frame_count; ++j) {
struct sprite_sheet_slice slice = group->frame_slices[(ent->animation_frame * group->per_frame_count) + j];
struct v2 center = xform_mul_v2(sprite_xform, slice.center);
center = xform_mul_v2(G.world_view, center);
if (!slice.has_ray) {
struct quad quad = quad_from_rect(slice.rect);
quad = xform_mul_quad(sprite_xform, quad);
quad = xform_mul_quad(G.world_view, quad);
draw_solid_quad_line(G.viewport_canvas, quad, 2, quad_color);
}
draw_solid_circle(G.viewport_canvas, center, 3, point_color, 20);
if (slice.has_ray) {
struct v2 ray = xform_basis_mul_v2(sprite_xform, slice.dir);
ray = xform_basis_mul_v2(G.world_view, ray);
ray = v2_with_len(ray, 25);
draw_solid_arrow_ray(G.viewport_canvas, center, ray, 2, 10, ray_color);
}
}
/* TODO: Fade in placeholder if texture isn't loaded */
if (sheet->loaded) {
struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, ent->animation_frame);
struct quad quad = xform_mul_quad(sprite_xform, QUAD_UNIT_SQUARE_CENTERED);
struct draw_sprite_params params = DRAW_SPRITE_PARAMS(.sprite = sprite, .tint = ent->sprite_tint, .clip = frame.clip);
draw_sprite_quad(G.world_canvas, params, quad);
}
}
#endif
/* Draw collider */
if (entity_has_prop(ent, ENTITY_PROP_PHYSICAL_DYNAMIC)) {
struct collider_shape collider = ent->local_collider;
u32 color = RGBA_32_F(1, 1, 0, 0.25);
f32 thickness = 2;
{
/* Draw collider using support points */
//u32 detail = 64;
u32 detail = 512;
draw_solid_collider_line(G.viewport_canvas, G.world_view, collider, xf, thickness, color, detail);
/* Debug draw entity info */
if (G.debug_draw && !skip_debug_draw) {
struct temp_arena temp = arena_temp_begin(scratch.arena);
if (entity_has_prop(ent, ENTITY_PROP_PHYSICAL_DYNAMIC) || entity_has_prop(ent, ENTITY_PROP_PHYSICAL_KINEMATIC)) {
debug_draw_movement(ent);
}
{
/* Draw collider shape points */
for (u32 i = 0; i < collider.count; ++i) {
struct v2 p = xform_mul_v2(xform_mul(G.world_view, xf), collider.points[i]);
draw_solid_circle(G.viewport_canvas, p, 3, COLOR_BLUE, 10);
}
if (!skip_debug_draw_transform) {
u32 color_x = RGBA_32_F(1, 0, 0, 0.3);
u32 color_y = RGBA_32_F(0, 1, 0, 0.3);
debug_draw_xform(xf, color_x, color_y);
}
if (collider.count == 1 && collider.radius > 0) {
/* Draw upwards line for circle */
struct v2 start = xf.og;
struct v2 end = collider_get_support_point(&collider, xf, v2_neg(xf.by)).p;
/* Draw focus arrow */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, ent->sprite);
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("attach.wep"), ent->animation_frame);
struct v2 start = xform_mul_v2(sprite_xform, slice.center);
start = xform_mul_v2(G.world_view, start);
struct v2 end = v2_add(xf.og, ent->control.focus);
end = xform_mul_v2(G.world_view, end);
draw_solid_line(G.viewport_canvas, start, end, thickness, color);
draw_solid_arrow_line(G.viewport_canvas, start, end, 3, 10, RGBA_32_F(1, 1, 1, 0.5));
}
#if 0
/* Draw support point at focus dir */
{
struct v2 p = collider_support_point(&collider, xf, ent->control.focus);
p = xform_mul_v2(G.world_view, p);
draw_solid_circle(G.viewport_canvas, p, 3, COLOR_RED, 10);
}
#endif
}
/* Draw contact constraint */
if (entity_has_prop(ent, ENTITY_PROP_CONTACT_CONSTRAINT)) {
struct phys_contact_constraint *data = &ent->contact_constraint_data;
struct entity *e0 = entity_from_handle(store, data->e0);
struct entity *e1 = entity_from_handle(store, data->e1);
(UNUSED)e0;
(UNUSED)e1;
#if 0
/* Draw slices */
if (!sprite_tag_is_nil(ent->sprite)) {
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite);
#if 1
/* Draw contact points */
{
f32 radius = 5;
for (u32 i = 0; i < data->num_points; ++i) {
struct phys_contact_point point = data->points[i];
#if 0
struct v2 p0 = xform_mul_v2(e0_xf, contact.point_local_e0);
struct v2 p1 = xform_mul_v2(e1_xf, contact.point_local_e1);
struct v2 point = v2_add(p0, v2_mul(v2_sub(p1, p0), 0.5f));
#else
struct v2 dbg_pt = point.dbg_pt;
#endif
/* Draw point */
{
//u32 color = contact.persisted ? RGBA_32_F(1, 1, 0, 0.50) : RGBA_32_F(1, 0, 0, 0.50);
u32 color = RGBA_32_F(1, 1, 0, 0.50);
//struct v2 point = xform_mul_v2(e0_xf, contact.p0_local);
//struct v2 point = contact.p0_initial_world;
draw_solid_circle(G.viewport_canvas, xform_mul_v2(G.world_view, dbg_pt), radius, color, 10);
u32 quad_color = RGBA_32_F(1, 0, 0.5, 1);
u32 point_color = RGBA_32_F(1, 0, 0, 1);
u32 ray_color = RGBA_32_F(1, 0, 0.5, 1);
if (colliding) {
quad_color = RGBA_32_F(1, 1, 1, 1);
}
for (u64 i = 0; i < sheet->slice_groups_count; ++i) {
struct sprite_sheet_slice_group *group = &sheet->slice_groups[i];
if (string_ends_with(group->name, STR(".ray"))) continue;
for (u32 j = 0; j < group->per_frame_count; ++j) {
struct sprite_sheet_slice slice = group->frame_slices[(ent->animation_frame * group->per_frame_count) + j];
struct v2 center = xform_mul_v2(sprite_xform, slice.center);
center = xform_mul_v2(G.world_view, center);
if (!slice.has_ray) {
struct quad quad = quad_from_rect(slice.rect);
quad = xform_mul_quad(sprite_xform, quad);
quad = xform_mul_quad(G.world_view, quad);
draw_solid_quad_line(G.viewport_canvas, quad, 2, quad_color);
}
draw_solid_circle(G.viewport_canvas, center, 3, point_color, 20);
if (slice.has_ray) {
struct v2 ray = xform_basis_mul_v2(sprite_xform, slice.dir);
ray = xform_basis_mul_v2(G.world_view, ray);
ray = v2_with_len(ray, 25);
draw_solid_arrow_ray(G.viewport_canvas, center, ray, 2, 10, ray_color);
}
}
}
}
#endif
/* Draw collider */
if (entity_has_prop(ent, ENTITY_PROP_PHYSICAL_DYNAMIC)) {
struct collider_shape collider = ent->local_collider;
u32 color = RGBA_32_F(1, 1, 0, 0.25);
f32 thickness = 2;
{
/* Draw collider using support points */
//u32 detail = 64;
u32 detail = 512;
draw_solid_collider_line(G.viewport_canvas, G.world_view, collider, xf, thickness, color, detail);
}
{
/* Draw collider shape points */
for (u32 i = 0; i < collider.count; ++i) {
struct v2 p = xform_mul_v2(xform_mul(G.world_view, xf), collider.points[i]);
draw_solid_circle(G.viewport_canvas, p, 3, COLOR_BLUE, 10);
}
}
if (collider.count == 1 && collider.radius > 0) {
/* Draw upwards line for circle */
struct v2 start = xf.og;
struct v2 end = collider_get_support_point(&collider, xf, v2_neg(xf.by)).p;
start = xform_mul_v2(G.world_view, start);
end = xform_mul_v2(G.world_view, end);
draw_solid_line(G.viewport_canvas, start, end, thickness, color);
}
#if 0
/* Draw support point at focus dir */
{
struct v2 p = collider_support_point(&collider, xf, ent->control.focus);
p = xform_mul_v2(G.world_view, p);
draw_solid_circle(G.viewport_canvas, p, 3, COLOR_RED, 10);
}
#endif
}
/* Draw contact constraint */
if (entity_has_prop(ent, ENTITY_PROP_CONTACT_CONSTRAINT)) {
struct phys_contact_constraint *data = &ent->contact_constraint_data;
struct entity *e0 = entity_from_handle(store, data->e0);
struct entity *e1 = entity_from_handle(store, data->e1);
(UNUSED)e0;
(UNUSED)e1;
#if 1
/* Draw contact points */
{
f32 radius = 5;
for (u32 i = 0; i < data->num_points; ++i) {
struct phys_contact_point point = data->points[i];
#if 0
struct v2 p0 = xform_mul_v2(e0_xf, contact.point_local_e0);
struct v2 p1 = xform_mul_v2(e1_xf, contact.point_local_e1);
struct v2 point = v2_add(p0, v2_mul(v2_sub(p1, p0), 0.5f));
#else
struct v2 dbg_pt = point.dbg_pt;
#endif
/* Draw point */
{
//u32 color = contact.persisted ? RGBA_32_F(1, 1, 0, 0.50) : RGBA_32_F(1, 0, 0, 0.50);
u32 color = RGBA_32_F(1, 1, 0, 0.50);
//struct v2 point = xform_mul_v2(e0_xf, contact.p0_local);
//struct v2 point = contact.p0_initial_world;
draw_solid_circle(G.viewport_canvas, xform_mul_v2(G.world_view, dbg_pt), radius, color, 10);
}
/* Draw normal */
{
u32 color = COLOR_WHITE;
f32 len = 0.1f;
f32 arrow_thickness = 2;
f32 arrow_height = 5;
struct v2 start = xform_mul_v2(G.world_view, dbg_pt);
struct v2 end = xform_mul_v2(G.world_view, v2_add(dbg_pt, v2_mul(v2_norm(data->normal), len)));
draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color);
}
#if 0
/* Draw contact info */
{
struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);
if (disp_font) {
f32 offset_px = 10;
struct string fmt = STR(
"e0 index: %F\n"
"e1 index: %F\n"
"id: 0x%F\n"
"impulse (n): %F\n"
"impulse (t): %F\n"
"separation: %F\n"
"normal: (%F, %F)\n"
"num contacts: %F"
);
struct string text = string_format(temp.arena, fmt,
FMT_UINT(e0->handle.idx),
FMT_UINT(e1->handle.idx),
FMT_HEX(point.id),
FMT_FLOAT_P(point.normal_impulse, 3),
FMT_FLOAT_P(point.tangent_impulse, 3),
FMT_FLOAT_P(point.starting_separation, 6),
FMT_FLOAT_P(data->normal.x, 6), FMT_FLOAT_P(data->normal.y, 6),
FMT_UINT(data->num_points));
draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, dbg_pt)), V2(0, offset_px)), text);
}
}
#endif
}
}
}
/* Draw collision debug */
#if COLLIDER_DEBUG
if (entity_has_prop(ent, ENTITY_PROP_COLLISION_DEBUG)) {
struct phys_collision_debug *data = &ent->collision_debug_data;
struct collider_collision_points_result collider_res = data->res;
struct entity *e0 = entity_from_handle(store, data->e0);
struct entity *e1 = entity_from_handle(store, data->e1);
struct collider_shape e0_collider = e0->local_collider;
struct collider_shape e1_collider = e1->local_collider;
(UNUSED)e0_collider;
(UNUSED)e1_collider;
/* Draw closest points */
#if 0
{
f32 radius = 4;
u32 color = RGBA_32_F(1, 1, 0, 0.5);
struct v2 a = xform_mul_v2(G.world_view, data->closest0);
struct v2 b = xform_mul_v2(G.world_view, data->closest1);
draw_solid_circle(G.viewport_canvas, a, radius, color, 10);
draw_solid_circle(G.viewport_canvas, b, radius, color, 10);
}
#endif
/* Draw clipping */
{
f32 thickness = 2;
f32 radius = 4;
u32 color_line = RGBA_32_F(1, 0, 1, 0.25);
u32 color_a = RGBA_32_F(1, 0, 0, 0.25);
u32 color_b = RGBA_32_F(0, 1, 0, 0.25);
u32 color_line_clipped = RGBA_32_F(1, 0, 1, 1);
u32 color_a_clipped = RGBA_32_F(1, 0, 0, 1);
u32 color_b_clipped = RGBA_32_F(0, 1, 0, 1);
{
struct v2 a = xform_mul_v2(G.world_view, collider_res.a0);
struct v2 b = xform_mul_v2(G.world_view, collider_res.b0);
draw_solid_line(G.viewport_canvas, a, b, thickness, color_line);
draw_solid_circle(G.viewport_canvas, a, radius, color_a, 10);
draw_solid_circle(G.viewport_canvas, b, radius, color_b, 10);
struct v2 a_clipped = xform_mul_v2(G.world_view, collider_res.a0_clipped);
struct v2 b_clipped = xform_mul_v2(G.world_view, collider_res.b0_clipped);
draw_solid_line(G.viewport_canvas, a_clipped, b_clipped, thickness, color_line_clipped);
draw_solid_circle(G.viewport_canvas, a_clipped, radius, color_a_clipped, 10);
draw_solid_circle(G.viewport_canvas, b_clipped, radius, color_b_clipped, 10);
}
{
struct v2 a = xform_mul_v2(G.world_view, collider_res.a1);
struct v2 b = xform_mul_v2(G.world_view, collider_res.b1);
draw_solid_line(G.viewport_canvas, a, b, thickness, color_line);
draw_solid_circle(G.viewport_canvas, a, radius, color_a, 10);
draw_solid_circle(G.viewport_canvas, b, radius, color_b, 10);
struct v2 a_clipped = xform_mul_v2(G.world_view, collider_res.a1_clipped);
struct v2 b_clipped = xform_mul_v2(G.world_view, collider_res.b1_clipped);
draw_solid_line(G.viewport_canvas, a_clipped, b_clipped, thickness, color_line_clipped);
draw_solid_circle(G.viewport_canvas, a_clipped, radius, color_a_clipped, 10);
draw_solid_circle(G.viewport_canvas, b_clipped, radius, color_b_clipped, 10);
}
}
#if COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI
struct xform e0_xf = data->xf0;
struct xform e1_xf = data->xf1;
#if 0
/* Only draw points with large separation */
b32 should_draw = false;
for (u32 i = 0; i < data->num_points; ++i) {
if (data->points[i].starting_separation < -0.1) {
should_draw = true;
break;
}
}
#else
b32 should_draw = true;
#endif
if (should_draw) {
#if 0
/* Test info */
{
struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);
if (disp_font) {
f32 offset_px = 10;
struct string fmt = STR(
"e0 pos: (%F, %F)\n"
"e0 rot: %F\n"
"e1 pos: (%F, %F)\n"
"e1 rot: %F\n"
);
struct string text = string_format(temp.arena, fmt,
FMT_FLOAT_P(e0_xf.og.x, 24), FMT_FLOAT_P(e0_xf.og.y, 24),
FMT_FLOAT_P(xform_get_rotation(e0_xf), 24),
FMT_FLOAT_P(e1_xf.og.x, 24), FMT_FLOAT_P(e1_xf.og.y, 24),
FMT_FLOAT_P(xform_get_rotation(e1_xf), 24));
draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, V2(0, 0))), V2(0, offset_px)), text);
}
}
#endif
/* Draw menkowski */
{
u32 color = collider_res.solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1);
f32 thickness = 2;
u32 detail = 512;
(UNUSED)thickness;
struct v2_array m = menkowski(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf, detail);
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(G.viewport_canvas, m, color);
}
/* Draw cloud */
{
u32 color = RGBA_32_F(1, 1, 1, 1);
f32 radius = 2;
struct v2_array m = cloud(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf);
for (u64 i = 0; i < m.count; ++i) {
struct v2 p = xform_mul_v2(G.world_view, m.points[i]);
draw_solid_circle(G.viewport_canvas, p, radius, color, 10);
}
}
/* Draw normal */
{
u32 color = COLOR_WHITE;
f32 len = 0.1f;
f32 arrow_thickness = 2;
f32 arrow_height = 5;
struct v2 start = xform_mul_v2(G.world_view, dbg_pt);
struct v2 end = xform_mul_v2(G.world_view, v2_add(dbg_pt, v2_mul(v2_norm(data->normal), len)));
struct v2 start = xform_mul_v2(G.world_view, V2(0, 0));
struct v2 end = xform_mul_v2(G.world_view, v2_mul(v2_norm(collider_res.normal), len));
draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color);
}
#if 0
/* Draw contact info */
/* Draw prototype */
{
struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);
if (disp_font) {
f32 offset_px = 10;
f32 thickness = 2;
u32 color = RGBA_32_F(1, 1, 1, 0.25);
struct string fmt = STR(
"e0 index: %F\n"
"e1 index: %F\n"
"id: 0x%F\n"
"impulse (n): %F\n"
"impulse (t): %F\n"
"separation: %F\n"
"normal: (%F, %F)\n"
"num contacts: %F"
);
struct string text = string_format(temp.arena, fmt,
FMT_UINT(e0->handle.idx),
FMT_UINT(e1->handle.idx),
FMT_HEX(point.id),
FMT_FLOAT_P(point.normal_impulse, 3),
FMT_FLOAT_P(point.tangent_impulse, 3),
FMT_FLOAT_P(point.starting_separation, 6),
FMT_FLOAT_P(data->normal.x, 6), FMT_FLOAT_P(data->normal.y, 6),
FMT_UINT(data->num_points));
struct v2_array m = {
.points = collider_res.prototype.points,
.count = collider_res.prototype.len
};
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);
for (u64 i = 0; i < m.count; ++i) draw_solid_circle(G.viewport_canvas, m.points[i], 10, color, 10);
}
/* Draw simplex */
{
f32 thickness = 2;
u32 line_color = COLOR_YELLOW;
u32 color_first = RGBA_32_F(1, 0, 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);
draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, dbg_pt)), V2(0, offset_px)), text);
struct collider_menkowski_simplex simplex = collider_res.simplex;
struct v2 simplex_points[] = { simplex.a.p, simplex.b.p, simplex.c.p };
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 };
if (simplex.len >= 1) {
u32 color = simplex.len == 1 ? color_first : (simplex.len == 2 ? color_second : color_third);
draw_solid_circle(G.viewport_canvas, simplex_array.points[0], thickness * 3, color, 10);
}
if (simplex.len >= 2) {
u32 color = simplex.len == 2 ? color_first : color_second;
draw_solid_circle(G.viewport_canvas, simplex_array.points[1], thickness * 3, color, 10);
}
if (simplex.len >= 3) {
u32 color = color_first;
draw_solid_circle(G.viewport_canvas, simplex_array.points[2], thickness * 3, color, 10);
}
if (simplex.len >= 2) {
draw_solid_poly_line(G.viewport_canvas, simplex_array, simplex.len > 2, thickness, line_color);
}
}
#endif
}
#endif
}
}
#endif
#endif
/* Draw collision debug */
#if COLLIDER_DEBUG
if (entity_has_prop(ent, ENTITY_PROP_COLLISION_DEBUG)) {
struct phys_collision_debug *data = &ent->collision_debug_data;
struct collider_collision_points_result collider_res = data->res;
struct entity *e0 = entity_from_handle(store, data->e0);
struct entity *e1 = entity_from_handle(store, data->e1);
struct collider_shape e0_collider = e0->local_collider;
struct collider_shape e1_collider = e1->local_collider;
(UNUSED)e0_collider;
(UNUSED)e1_collider;
/* Draw closest points */
#if 0
{
f32 radius = 4;
u32 color = RGBA_32_F(1, 1, 0, 0.5);
struct v2 a = xform_mul_v2(G.world_view, data->closest0);
struct v2 b = xform_mul_v2(G.world_view, data->closest1);
draw_solid_circle(G.viewport_canvas, a, radius, color, 10);
draw_solid_circle(G.viewport_canvas, b, radius, color, 10);
}
#endif
/* Draw clipping */
{
/* Draw hierarchy */
if (entity_has_prop(parent, ENTITY_PROP_ACTIVE) && !parent->is_root) {
u32 color = RGBA_32_F(0.6, 0.6, 1, 0.75);
f32 thickness = 2;
f32 radius = 4;
u32 color_line = RGBA_32_F(1, 0, 1, 0.25);
u32 color_a = RGBA_32_F(1, 0, 0, 0.25);
u32 color_b = RGBA_32_F(0, 1, 0, 0.25);
u32 color_line_clipped = RGBA_32_F(1, 0, 1, 1);
u32 color_a_clipped = RGBA_32_F(1, 0, 0, 1);
u32 color_b_clipped = RGBA_32_F(0, 1, 0, 1);
{
struct v2 a = xform_mul_v2(G.world_view, collider_res.a0);
struct v2 b = xform_mul_v2(G.world_view, collider_res.b0);
draw_solid_line(G.viewport_canvas, a, b, thickness, color_line);
draw_solid_circle(G.viewport_canvas, a, radius, color_a, 10);
draw_solid_circle(G.viewport_canvas, b, radius, color_b, 10);
f32 arrow_height = 15;
struct v2 a_clipped = xform_mul_v2(G.world_view, collider_res.a0_clipped);
struct v2 b_clipped = xform_mul_v2(G.world_view, collider_res.b0_clipped);
draw_solid_line(G.viewport_canvas, a_clipped, b_clipped, thickness, color_line_clipped);
draw_solid_circle(G.viewport_canvas, a_clipped, radius, color_a_clipped, 10);
draw_solid_circle(G.viewport_canvas, b_clipped, radius, color_b_clipped, 10);
}
{
struct v2 a = xform_mul_v2(G.world_view, collider_res.a1);
struct v2 b = xform_mul_v2(G.world_view, collider_res.b1);
draw_solid_line(G.viewport_canvas, a, b, thickness, color_line);
draw_solid_circle(G.viewport_canvas, a, radius, color_a, 10);
draw_solid_circle(G.viewport_canvas, b, radius, color_b, 10);
struct v2 a_clipped = xform_mul_v2(G.world_view, collider_res.a1_clipped);
struct v2 b_clipped = xform_mul_v2(G.world_view, collider_res.b1_clipped);
draw_solid_line(G.viewport_canvas, a_clipped, b_clipped, thickness, color_line_clipped);
draw_solid_circle(G.viewport_canvas, a_clipped, radius, color_a_clipped, 10);
draw_solid_circle(G.viewport_canvas, b_clipped, radius, color_b_clipped, 10);
}
struct v2 start = xform_mul_v2(G.world_view, xf.og);
struct v2 end = xform_mul_v2(G.world_view, parent_xf.og);
draw_solid_arrow_line(G.viewport_canvas, start, end, thickness, arrow_height, color);
}
#if COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI
struct xform e0_xf = data->xf0;
struct xform e1_xf = data->xf1;
/* Draw camera rect */
if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) {
u32 color = ent == active_camera ? RGBA_32_F(1, 1, 1, 0.5) : RGBA_32_F(0, 0.75, 0, 0.5);
f32 thickness = 3;
#if 0
/* Only draw points with large separation */
b32 should_draw = false;
for (u32 i = 0; i < data->num_points; ++i) {
if (data->points[i].starting_separation < -0.1) {
should_draw = true;
break;
}
struct xform quad_xf = xform_mul(xf, ent->camera_quad_xform);
struct quad quad = xform_mul_quad(quad_xf, QUAD_UNIT_SQUARE_CENTERED);
quad = xform_mul_quad(G.world_view, quad);
draw_solid_quad_line(G.viewport_canvas, quad, thickness, color);
}
#else
b32 should_draw = true;
#endif
if (should_draw) {
#if 0
/* Test info */
{
struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);
if (disp_font) {
f32 offset_px = 10;
struct string fmt = STR(
"e0 pos: (%F, %F)\n"
"e0 rot: %F\n"
"e1 pos: (%F, %F)\n"
"e1 rot: %F\n"
);
struct string text = string_format(temp.arena, fmt,
FMT_FLOAT_P(e0_xf.og.x, 24), FMT_FLOAT_P(e0_xf.og.y, 24),
FMT_FLOAT_P(xform_get_rotation(e0_xf), 24),
FMT_FLOAT_P(e1_xf.og.x, 24), FMT_FLOAT_P(e1_xf.og.y, 24),
FMT_FLOAT_P(xform_get_rotation(e1_xf), 24));
draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, V2(0, 0))), V2(0, offset_px)), text);
}
}
#endif
/* Draw menkowski */
{
u32 color = collider_res.solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1);
f32 thickness = 2;
u32 detail = 512;
(UNUSED)thickness;
struct v2_array m = menkowski(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf, detail);
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(G.viewport_canvas, m, color);
}
/* Draw cloud */
{
u32 color = RGBA_32_F(1, 1, 1, 1);
f32 radius = 2;
struct v2_array m = cloud(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf);
for (u64 i = 0; i < m.count; ++i) {
struct v2 p = xform_mul_v2(G.world_view, m.points[i]);
draw_solid_circle(G.viewport_canvas, p, radius, color, 10);
}
}
/* Draw normal */
{
u32 color = COLOR_WHITE;
f32 len = 0.1f;
f32 arrow_thickness = 2;
f32 arrow_height = 5;
struct v2 start = xform_mul_v2(G.world_view, V2(0, 0));
struct v2 end = xform_mul_v2(G.world_view, v2_mul(v2_norm(collider_res.normal), len));
draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color);
}
/* Draw prototype */
{
f32 thickness = 2;
u32 color = RGBA_32_F(1, 1, 1, 0.25);
struct v2_array m = {
.points = collider_res.prototype.points,
.count = collider_res.prototype.len
};
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);
for (u64 i = 0; i < m.count; ++i) draw_solid_circle(G.viewport_canvas, m.points[i], 10, color, 10);
}
/* Draw simplex */
{
f32 thickness = 2;
u32 line_color = COLOR_YELLOW;
u32 color_first = RGBA_32_F(1, 0, 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);
struct collider_menkowski_simplex simplex = collider_res.simplex;
struct v2 simplex_points[] = { simplex.a.p, simplex.b.p, simplex.c.p };
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 };
if (simplex.len >= 1) {
u32 color = simplex.len == 1 ? color_first : (simplex.len == 2 ? color_second : color_third);
draw_solid_circle(G.viewport_canvas, simplex_array.points[0], thickness * 3, color, 10);
}
if (simplex.len >= 2) {
u32 color = simplex.len == 2 ? color_first : color_second;
draw_solid_circle(G.viewport_canvas, simplex_array.points[1], thickness * 3, color, 10);
}
if (simplex.len >= 3) {
u32 color = color_first;
draw_solid_circle(G.viewport_canvas, simplex_array.points[2], thickness * 3, color, 10);
}
if (simplex.len >= 2) {
draw_solid_poly_line(G.viewport_canvas, simplex_array, simplex.len > 2, thickness, line_color);
}
}
}
#endif
arena_temp_end(temp);
}
#endif
#endif
/* Draw hierarchy */
if (entity_has_prop(parent, ENTITY_PROP_ACTIVE) && !parent->is_root) {
u32 color = RGBA_32_F(0.6, 0.6, 1, 0.75);
f32 thickness = 2;
f32 arrow_height = 15;
struct v2 start = xform_mul_v2(G.world_view, xf.og);
struct v2 end = xform_mul_v2(G.world_view, parent_xf.og);
draw_solid_arrow_line(G.viewport_canvas, start, end, thickness, arrow_height, color);
}
/* Draw camera rect */
if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) {
u32 color = ent == active_camera ? RGBA_32_F(1, 1, 1, 0.5) : RGBA_32_F(0, 0.75, 0, 0.5);
f32 thickness = 3;
struct xform quad_xf = xform_mul(xf, ent->camera_quad_xform);
struct quad quad = xform_mul_quad(quad_xf, QUAD_UNIT_SQUARE_CENTERED);
quad = xform_mul_quad(G.world_view, quad);
draw_solid_quad_line(G.viewport_canvas, quad, thickness, color);
}
arena_temp_end(temp);
}
}

View File

@ -55,15 +55,15 @@ INLINE u128 hash_fnv128(u128 seed, struct buffer buff)
#define SORT_COMPARE_FUNC_DEF(name, arg_a, arg_b, arg_udata) i32 name(void *arg_a, void *arg_b, void *arg_udata)
typedef SORT_COMPARE_FUNC_DEF(sort_compare_func, a, b, udata);
INLINE void merge_sort_internal(void *left, void *right, void *items, u64 left_count, u64 right_count, u64 item_size, sort_compare_func *callback, void *udata)
INLINE void merge_sort_internal(u8 *left, u8 *right, u8 *items, u64 left_count, u64 right_count, u64 item_size, sort_compare_func *callback, void *udata)
{
u64 i = 0;
u64 l = 0;
u64 r = 0;
while (l < left_count && r < right_count) {
u8 *dst = ((u8 *)items) + (i * item_size);
u8 *left_item = ((u8 *)left) + (l * item_size);
u8 *right_item = ((u8 *)right) + (r * item_size);
u8 *dst = items + (i * item_size);
u8 *left_item = left + (l * item_size);
u8 *right_item = right + (r * item_size);
++i;
if (callback(left_item, right_item, udata) > 0) {
MEMCPY(dst, left_item, item_size);
@ -77,18 +77,18 @@ INLINE void merge_sort_internal(void *left, void *right, void *items, u64 left_c
u64 left_remaining_bytes = (left_count - l) * item_size;
u64 right_remaining_bytes = (right_count - r) * item_size;
if (left_remaining_bytes > 0) {
u8 *dst = ((u8 *)items) + (i * item_size);
u8 *src = ((u8 *)left) + (l * item_size);
u8 *dst = items + (i * item_size);
u8 *src = left + (l * item_size);
MEMCPY(dst, src, left_remaining_bytes);
i += left_count - l;
l = left_remaining_bytes;
l = left_count;
}
if (right_remaining_bytes > 0) {
u8 *dst = ((u8 *)items) + (i * item_size);
u8 *src = ((u8 *)right) + (r * item_size);
u8 *dst = items + (i * item_size);
u8 *src = right + (r * item_size);
MEMCPY(dst, src, right_remaining_bytes);
i += right_count - r;
l = right_remaining_bytes;
r = right_count;
}
}
@ -109,7 +109,7 @@ INLINE void merge_sort(void *items, u64 item_count, u64 item_size, sort_compare_
merge_sort(left, left_count, item_size, callback, udata);
merge_sort(right, right_count, item_size, callback, udata);
merge_sort_internal(left, right, items, left_count, right_count, item_size, callback, udata);
merge_sort_internal(left, right, (u8 *)items, left_count, right_count, item_size, callback, udata);
scratch_end(scratch);
}
}