diff --git a/src/user.c b/src/user.c index 2f99831a..70b980ba 100644 --- a/src/user.c +++ b/src/user.c @@ -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); } } diff --git a/src/util.h b/src/util.h index 6e4b0485..a3136dee 100644 --- a/src/util.h +++ b/src/util.h @@ -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); } }