camera debug drawing and less direct rel xform application

This commit is contained in:
jacob 2024-03-20 13:36:57 -05:00
parent c6ca5c0c9a
commit 0a1761627b
6 changed files with 105 additions and 70 deletions

View File

@ -6,7 +6,7 @@
#define RESOURCES_EMBEDDED !(DEVELOPER)
#define DEFAULT_CAMERA_WIDTH (6)
#define DEFAULT_CAMERA_ASPECT_RATIO (16.0 / 9.0)
#define DEFAULT_CAMERA_HEIGHT (DEFAULT_CAMERA_WIDTH / (16.0 / 9.0))
#define PIXELS_PER_UNIT 256

View File

@ -4,7 +4,7 @@
READONLY struct entity _g_entity_nil = {
.rel_xform = XFORM_IDENT,
.world_xform = XFORM_IDENT,
.sprite_xform = XFORM_IDENT,
.sprite_quad_xform = XFORM_IDENT,
.sprite_tint = COLOR_WHITE
};

View File

@ -65,7 +65,7 @@ struct entity {
/* ====================================================================== */
/* Sprite */
struct xform sprite_xform;
struct xform sprite_quad_xform;
struct string sprite_name;
struct string sprite_tag_name;
u32 sprite_tint;
@ -94,10 +94,11 @@ struct entity {
/* ENTITY_PROP_CAMERA */
struct entity_handle camera_follow;
struct xform camera_target_xform; /* Calculated from camera_follow */
struct v2 camera_size;
struct xform camera_quad_xform;
f32 camera_lerp; /* Rate at which camera xform approaches target xform */
u32 camera_lerp_gen;
struct xform camera_rel_xform_target; /* Calculated from camera_follow */
u32 camera_applied_lerp_gen_plus_one; /* Calculated */
};
@ -161,7 +162,6 @@ struct entity *entity_from_handle(struct entity_store *store, struct entity_hand
struct entity *entity_find_first_match_one(struct entity_store *store, enum entity_prop prop);
struct entity *entity_find_first_match_all(struct entity_store *store, struct entity_prop_array props);
void entity_link(struct entity_store *store, struct entity *parent, struct entity *child);
#endif

View File

@ -73,6 +73,43 @@ INTERNAL void publish_game_tick(void)
sys_mutex_unlock(&L.published_tick_mutex);
}
INTERNAL void recalculate_world_xform_recurse(struct entity *parent)
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct stack_node {
struct entity *entity;
struct xform parent_xform;
};
/* Depth first iteration */
*arena_push(scratch.arena, struct stack_node) = (struct stack_node) { .entity = parent, .parent_xform = XFORM_IDENT };
u64 stack_count = 1;
while (stack_count > 0) {
/* Pull from top of stack */
struct stack_node node = *arena_pop(scratch.arena, struct stack_node);
--stack_count;
/* Calculate child world xform */
struct entity *child = node.entity;
struct xform world_xform = xform_mul(node.parent_xform, child->rel_xform);
child->world_xform = world_xform;
/* Append sub-children to stack */
struct entity *subchild = entity_from_handle(&L.world.entity_store, child->last);
while (subchild->valid) {
*arena_push(scratch.arena, struct stack_node) = (struct stack_node) {
.entity = subchild,
.parent_xform = world_xform
};
++stack_count;
subchild = entity_from_handle(&L.world.entity_store, subchild->prev);
}
}
scratch_end(scratch);
}
INTERNAL void game_update(void)
{
__prof;
@ -117,7 +154,7 @@ INTERNAL void game_update(void)
sprite_xf = xform_rotate(sprite_xf, sprite_rot);
sprite_xf = xform_translate(sprite_xf, v2_neg(sprite_pivot));
sprite_xf = xform_scale(sprite_xf, sprite_size);
e->sprite_xform = sprite_xf;
e->sprite_quad_xform = sprite_xf;
e->sprite_name = sprite_name;
e->sprite_tag_name = sprite_tag_name;
@ -168,7 +205,7 @@ INTERNAL void game_update(void)
sprite_xf = xform_rotate(sprite_xf, sprite_rot);
sprite_xf = xform_translate(sprite_xf, v2_neg(sprite_pivot));
sprite_xf = xform_scale(sprite_xf, sprite_size);
e->sprite_xform = sprite_xf;
e->sprite_quad_xform = sprite_xf;
e->sprite_name = sprite_name;
e->sprite_tag_name = sprite_tag_name;
@ -181,7 +218,6 @@ INTERNAL void game_update(void)
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
//entity_enable_prop(e, ENTITY_PROP_TEST);
//entity_enable_prop(e, ENTITY_PROP_TEST_FOLLOW_MOUSE);
entity_link(&L.world.entity_store, parent, e);
@ -202,13 +238,14 @@ INTERNAL void game_update(void)
e->valid = true;
e->rel_xform = XFORM_IDENT;
entity_enable_prop(e, ENTITY_PROP_CAMERA);
entity_enable_prop(e, ENTITY_PROP_CAMERA_ACTIVE);
e->camera_follow = player_ent->handle;
f32 width = (f32)DEFAULT_CAMERA_WIDTH;
f32 height = width / (f32)DEFAULT_CAMERA_ASPECT_RATIO;
e->camera_size = V2(width, height);
f32 height = (f32)DEFAULT_CAMERA_HEIGHT;
e->camera_quad_xform = XFORM_TRS(.s = V2(width, height));
}
/* Sound ent */
@ -223,7 +260,7 @@ INTERNAL void game_update(void)
f32 meters_height = sheet->frame_size.y / PIXELS_PER_UNIT;
struct v2 sprite_size = V2(meters_width, meters_height);
e->sprite_xform = xform_with_scale(XFORM_IDENT, sprite_size);
e->sprite_quad_xform = xform_with_scale(XFORM_IDENT, sprite_size);
e->sprite_name = sprite_name;
e->sprite_tint = RGBA_F(1, 1, 0, 1);
@ -295,7 +332,7 @@ INTERNAL void game_update(void)
if (entity_has_prop(ent, ENTITY_PROP_TEST) && !ent->test_initialized) {
ent->test_initialized = true;
ent->test_start_rel_xform = ent->rel_xform;
ent->test_start_sprite_xform = ent->sprite_xform;
ent->test_start_sprite_xform = ent->sprite_quad_xform;
}
/* ========================== *
@ -409,41 +446,7 @@ INTERNAL void game_update(void)
* Calculate xforms
* ========================== */
{
struct temp_arena stack = arena_temp_begin(scratch.arena);
struct xform_stack_node {
struct entity *entity;
struct xform parent_xform;
};
/* Depth first iteration */
*arena_push(stack.arena, struct xform_stack_node) = (struct xform_stack_node) { .entity = ent, .parent_xform = XFORM_IDENT };
u64 stack_count = 1;
while (stack_count > 0) {
/* Pull from top of stack */
struct xform_stack_node node = *arena_pop(stack.arena, struct xform_stack_node);
--stack_count;
/* Calculate child world xform */
struct entity *child = node.entity;
struct xform world_xform = xform_mul(node.parent_xform, child->rel_xform);
child->world_xform = world_xform;
/* Append sub-children to stack */
struct entity *subchild = entity_from_handle(&L.world.entity_store, child->last);
while (subchild->valid) {
*arena_push(stack.arena, struct xform_stack_node) = (struct xform_stack_node) {
.entity = subchild,
.parent_xform = world_xform
};
++stack_count;
subchild = entity_from_handle(&L.world.entity_store, subchild->prev);
}
}
arena_temp_end(stack);
}
recalculate_world_xform_recurse(ent);
}
/* ========================== *
@ -461,9 +464,6 @@ INTERNAL void game_update(void)
/* Camera follow */
if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) {
struct entity *follow = entity_from_handle(&L.world.entity_store, ent->camera_follow);
ent->camera_target_xform = follow->world_xform;
ent->camera_target_xform = xform_with_rotation(ent->camera_target_xform, 0);
ent->camera_target_xform = xform_with_scale(ent->camera_target_xform, V2(1, 1));
if (entity_has_prop(follow, ENTITY_PROP_PLAYER_CONTROLLED)) {
#if 0
@ -472,32 +472,40 @@ INTERNAL void game_update(void)
//f32 target_dist_y = target_dist_x * (16.0f / 9.0f);
f32 target_dist_y = target_dist_x;
struct v2 target_dir = v2_mul_v2(v2_norm(follow->player_aim), V2(target_dist_x, target_dist_y));
struct v2 target_pos = v2_add(ent->camera_target_xform.og, target_dir);
ent->camera_target_xform.og = target_pos;
struct v2 target_pos = v2_add(ent->camera_rel_xform_target.og, target_dir);
ent->camera_rel_xform_target = ent->rel_xform;
ent->camera_rel_xform_target.og = target_pos;
#else
/* "Look" style camera */
f32 aspect_ratio = 1.0;
if (!v2_eq(ent->camera_size, V2(0, 0))) {
aspect_ratio = ent->camera_size.x / ent->camera_size.y;
{
struct xform quad_xf = xform_mul(ent->world_xform, ent->camera_quad_xform);
struct v2 camera_size = xform_get_scale(quad_xf);
if (!v2_eq(camera_size, V2(0, 0))) {
aspect_ratio = camera_size.x / camera_size.y;
}
}
f32 ratio_y = 0.33f;
f32 ratio_x = ratio_y / aspect_ratio;
struct v2 camera_focus_dir = v2_mul_v2(follow->player_aim, V2(ratio_x, ratio_y));
struct v2 camera_focus_pos = v2_add(follow->world_xform.og, camera_focus_dir);
ent->camera_target_xform.og = camera_focus_pos;
ent->camera_rel_xform_target = ent->rel_xform;
ent->camera_rel_xform_target.og = camera_focus_pos;
#endif
}
/* Lerp camera */
if (ent->camera_applied_lerp_gen_plus_one == ent->camera_lerp_gen + 1) {
f32 t = 1 - math_pow(2.f, -20.f * (f32)L.world.dt);
ent->rel_xform = xform_lerp(ent->rel_xform, ent->camera_target_xform, t);
ent->rel_xform = xform_lerp(ent->rel_xform, ent->camera_rel_xform_target, t);
} else {
/* Skip lerp */
ent->rel_xform = ent->camera_target_xform;
ent->rel_xform = ent->camera_rel_xform_target;
}
ent->camera_applied_lerp_gen_plus_one = ent->camera_lerp_gen + 1;
ent->world_xform = ent->rel_xform;
/* Recalculate xform tree */
recalculate_world_xform_recurse(ent);
}
/* ========================== *

View File

@ -98,7 +98,7 @@ struct sys_window_settings settings_default_window_settings(struct sys_window *w
struct v2 monitor_size = sys_window_get_monitor_size(window);
i32 width = 1280;
i32 height = math_round(width / (f32)DEFAULT_CAMERA_ASPECT_RATIO);
i32 height = math_round(width / (f32)(DEFAULT_CAMERA_WIDTH / DEFAULT_CAMERA_HEIGHT));
i32 x = math_round(monitor_size.x / 2.f - width / 2);
i32 y = math_round(monitor_size.y / 2.f - height / 2);

View File

@ -396,11 +396,11 @@ INTERNAL void user_update(void)
e->player_acceleration = math_lerp(e0->player_acceleration, e1->player_acceleration, tick_blend);
e->player_aim = v2_lerp(e0->player_aim, e1->player_aim, tick_blend);
e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend);
e->sprite_quad_xform = xform_lerp(e0->sprite_quad_xform, e1->sprite_quad_xform, tick_blend);
e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
e->camera_size = v2_lerp(e0->camera_size, e1->camera_size, tick_blend);
e->camera_target_xform = xform_lerp(e0->camera_target_xform, e1->camera_target_xform, tick_blend);
e->camera_quad_xform = xform_lerp(e0->camera_quad_xform, e1->camera_quad_xform, tick_blend);
e->camera_rel_xform_target = xform_lerp(e0->camera_rel_xform_target, e1->camera_rel_xform_target, tick_blend);
}
}
#else
@ -541,8 +541,12 @@ INTERNAL void user_update(void)
/* Determine viewport size by camera & window dimensions */
f32 aspect_ratio = 1.0;
if (!v2_eq(active_camera->camera_size, V2(0, 0))) {
aspect_ratio = active_camera->camera_size.x / active_camera->camera_size.y;
{
struct xform quad_xf = xform_mul(active_camera->world_xform, active_camera->camera_quad_xform);
struct v2 camera_size = xform_get_scale(quad_xf);
if (!v2_eq(camera_size, V2(0, 0))) {
aspect_ratio = camera_size.x / camera_size.y;
}
}
f32 width = L.screen_size.x;
f32 height = L.screen_size.y;
@ -569,6 +573,8 @@ INTERNAL void user_update(void)
* ========================== */
if (L.debug_camera) {
L.world_view = xform_with_rotation(L.world_view, 0);
/* Pan view */
if (L.bind_states[USER_BIND_KIND_PAN].is_held) {
if (!L.debug_camera_panning) {
@ -611,8 +617,12 @@ INTERNAL void user_update(void)
/* Scale view into viewport based on camera size */
struct v2 size = L.viewport_size;
if (!v2_eq(active_camera->camera_size, V2(0, 0))) {
size = v2_div_v2(size, active_camera->camera_size);
{
struct xform quad_xf = xform_mul(active_camera->world_xform, active_camera->camera_quad_xform);
struct v2 camera_size = xform_get_scale(quad_xf);
if (!v2_eq(camera_size, V2(0, 0))) {
size = v2_div_v2(size, camera_size);
}
}
f32 scale = min_f32(size.x, size.y);
@ -701,7 +711,8 @@ INTERNAL void user_update(void)
struct entity *ent = &entities_array.entities[entity_index];
if (!ent->valid) continue;
b32 skip_debug_draw = entity_has_prop(ent, ENTITY_PROP_CAMERA);
b32 skip_debug_draw = !L.debug_camera && ent == active_camera;
b32 skip_debug_draw_transform = ent == active_camera;
/* Draw sprite */
if (ent->sprite_name.len > 0) {
@ -711,7 +722,7 @@ INTERNAL void user_update(void)
struct texture *texture = texture_load_async(tex_name);
if (texture) {
struct xform xf = xform_mul(ent->world_xform, ent->sprite_xform);
struct xform xf = xform_mul(ent->world_xform, ent->sprite_quad_xform);
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xf);
u32 tint = ent->sprite_tint;
@ -806,9 +817,12 @@ INTERNAL void user_update(void)
}
#endif
debug_draw_xform(ent->world_xform);
debug_draw_movement(ent);
if (!skip_debug_draw_transform) {
debug_draw_xform(ent->world_xform);
}
/* Draw hierarchy */
struct entity *parent = entity_from_handle(&L.world.entity_store, ent->parent);
if (parent->valid) {
@ -831,6 +845,19 @@ INTERNAL void user_update(void)
draw_solid_arrow_ray(L.viewport_canvas, pos, aim_ray, thickness, arrow_height, color);
}
/* Draw camera rect */
if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) {
u32 color = ent == active_camera ? RGBA_F(1, 1, 1, 0.5) : RGBA_F(0, 0.75, 0, 0.5);
f32 thickness = 3;
struct xform quad_xf = xform_mul(ent->world_xform, ent->camera_quad_xform);
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, quad_xf);
quad = quad_mul_xform(quad, L.world_view);
draw_solid_quad_line(L.viewport_canvas, quad, thickness, color);
}
arena_temp_end(temp);
}
}