working aim from hold slice correctly
This commit is contained in:
parent
630afc411b
commit
3049e02b57
@ -277,6 +277,7 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
|
||||
#define COLOR_RED RGB_32(0xFF, 0 , 0 )
|
||||
#define COLOR_GREEN RGB_32(0 , 0xFF, 0 )
|
||||
#define COLOR_BLUE RGB_32(0 , 0 , 0xFF)
|
||||
#define COLOR_YELLOW RGB_32(0xFF, 0xFF, 0 )
|
||||
|
||||
/* Barrier */
|
||||
#if COMPILER_MSVC
|
||||
@ -347,6 +348,9 @@ GLOBAL const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64;
|
||||
#define F32_INFINITY (*_f32_infinity)
|
||||
#define F64_INFINITY (*_f64_infinity)
|
||||
|
||||
#define F32_IS_NAN(x) (x != x)
|
||||
#define F64_IS_NAN(x) (x != x)
|
||||
|
||||
#define PI ((f32)3.14159265358979323846)
|
||||
#define TAU ((f32)6.28318530717958647693)
|
||||
|
||||
|
||||
22
src/draw.c
22
src/draw.c
@ -196,6 +196,28 @@ void draw_solid_poly_line(struct renderer_canvas *canvas, struct v2_array array,
|
||||
}
|
||||
}
|
||||
|
||||
void draw_solid_circle_line(struct renderer_canvas *canvas, struct v2 pos, f32 radius, 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) {
|
||||
struct v2 p = V2(
|
||||
radius * math_cos(i * (PI * 2.f) / detail),
|
||||
radius * math_sin(i * (PI * 2.f) / detail)
|
||||
);
|
||||
points[i] = v2_add(pos, p);
|
||||
}
|
||||
|
||||
struct v2_array a = {
|
||||
.points = points,
|
||||
.count = detail
|
||||
};
|
||||
draw_solid_poly_line(canvas, a, true, thickness, color);
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
void draw_solid_quad_line(struct renderer_canvas *canvas, struct quad quad, f32 thickness, u32 color)
|
||||
{
|
||||
struct v2 points[] = { quad.p1, quad.p2, quad.p3, quad.p4 };
|
||||
|
||||
@ -33,6 +33,7 @@ void draw_solid_rect(struct renderer_canvas *canvas, struct rect rect, u32 color
|
||||
void draw_solid_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, f32 thickness, u32 color);
|
||||
void draw_solid_ray(struct renderer_canvas *canvas, struct v2 start, struct v2 ray, f32 thickness, u32 color);
|
||||
void draw_solid_poly_line(struct renderer_canvas *canvas, struct v2_array array, b32 loop, f32 thickness, u32 color);
|
||||
void draw_solid_circle_line(struct renderer_canvas *canvas, struct v2 pos, f32 radius, f32 thickness, u32 color, u32 detail);
|
||||
void draw_solid_quad_line(struct renderer_canvas *canvas, struct quad quad, 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);
|
||||
|
||||
54
src/game.c
54
src/game.c
@ -179,6 +179,7 @@ INTERNAL void game_update(void)
|
||||
|
||||
e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase"));
|
||||
//e->sprite_span_name = STR("idle.unarmed");
|
||||
//e->sprite_span_name = STR("idle.one_handed");
|
||||
e->sprite_span_name = STR("idle.two_handed");
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
||||
@ -309,7 +310,7 @@ INTERNAL void game_update(void)
|
||||
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 v2 sprite_size = v2_div(sheet->frame_size, (f32)PIXELS_PER_UNIT);
|
||||
struct v2 pivot_pos = v2_mul_v2(slice.center_norm, sprite_size);
|
||||
struct v2 pivot_pos = v2_mul_v2(slice.center, sprite_size);
|
||||
ent->sprite_xform = xform_with_scale(XFORM_POS(v2_neg(pivot_pos)), sprite_size);
|
||||
}
|
||||
|
||||
@ -349,21 +350,64 @@ INTERNAL void game_update(void)
|
||||
/* Update focus */
|
||||
ent->focus = G.world.player_aim;
|
||||
|
||||
#if 0
|
||||
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("hold"), ent->animation_frame);
|
||||
|
||||
struct v2 hold_pos = xform_mul_v2(ent->xform_world, xform_mul_v2(ent->sprite_xform, slice.center_norm));
|
||||
struct v2 hold_dir = xform_basis_mul_v2(ent->xform_world, xform_basis_mul_v2(ent->sprite_xform, slice.dir_norm));
|
||||
struct v2 hold_pos = xform_mul_v2(ent->xform_world, xform_mul_v2(ent->sprite_xform, slice.center));
|
||||
struct v2 hold_dir = xform_basis_mul_v2(ent->xform_world, xform_basis_mul_v2(ent->sprite_xform, slice.dir));
|
||||
|
||||
struct v2 focus_pos = v2_add(ent->xform_world.og, ent->focus);
|
||||
struct v2 hold_focus_dir = v2_sub(focus_pos, hold_pos);
|
||||
|
||||
/* Only rotate if rotation to focus around origin is possible */
|
||||
f32 ent_hold_len = v2_len(v2_sub(hold_pos, ent->xform_world.og));
|
||||
f32 min_hold_radius = 0;
|
||||
{
|
||||
struct v2 center = xform_mul_v2(ent->sprite_xform_world, slice.center);
|
||||
struct v2 center_dir = v2_norm(xform_basis_mul_v2(ent->sprite_xform_world, slice.dir));
|
||||
struct v2 minpoint = v2_closest_point_ray(center, center_dir, ent->xform_world.og);
|
||||
min_hold_radius = v2_len(v2_sub(minpoint, ent->xform_world.og));
|
||||
}
|
||||
f32 ent_focus_len = v2_len(v2_sub(focus_pos, ent->xform_world.og));
|
||||
if (ent_focus_len > ent_hold_len) {
|
||||
if (ent_focus_len > min_hold_radius) {
|
||||
ent->xform = xform_rotate(ent->xform, v2_angle_from_dirs(hold_dir, hold_focus_dir));
|
||||
}
|
||||
#else
|
||||
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("hold"), ent->animation_frame);
|
||||
|
||||
struct xform xf = ent->xform;
|
||||
|
||||
struct v2 ent_pos = ent->xform_world.og;
|
||||
struct v2 focus_pos = v2_add(ent_pos, ent->focus);
|
||||
struct v2 hold_pos = xform_mul_v2(ent->xform_world, xform_mul_v2(ent->sprite_xform, slice.center));
|
||||
|
||||
struct v2 hold_dir = xform_basis_mul_v2(ent->xform_world, xform_basis_mul_v2(ent->sprite_xform, slice.dir));
|
||||
struct v2 hold_ent_dir = v2_sub(ent_pos, hold_pos);
|
||||
struct v2 focus_ent_dir = v2_sub(ent_pos, focus_pos);
|
||||
|
||||
f32 hold_ent_len = v2_len(hold_ent_dir);
|
||||
f32 focus_ent_len = v2_len(focus_ent_dir);
|
||||
|
||||
f32 final_hold_angle_btw_ent_and_focus = v2_angle_from_dirs(v2_norm(hold_ent_dir), v2_norm(hold_dir));
|
||||
f32 final_focus_angle_btw_ent_and_hold = math_asin((math_sin(final_hold_angle_btw_ent_and_focus) * hold_ent_len) / focus_ent_len);
|
||||
f32 final_ent_angle_btw_focus_and_hold = PI - (final_focus_angle_btw_ent_and_hold + final_hold_angle_btw_ent_and_focus);
|
||||
|
||||
f32 final_hold_ent_angle_offset;
|
||||
{
|
||||
struct xform ent_world_xform_unrotated = xform_with_rotation(ent->xform_world, 0);
|
||||
struct v2 hold_pos_unrotated = xform_mul_v2(ent_world_xform_unrotated, xform_mul_v2(ent->sprite_xform, slice.center));
|
||||
final_hold_ent_angle_offset = v2_angle_from_dirs(V2(0, -1), v2_norm(v2_sub(hold_pos_unrotated, ent_world_xform_unrotated.og)));
|
||||
}
|
||||
|
||||
f32 final_ent_angle = v2_angle_from_dirs(V2(0, -1), v2_sub(focus_pos, ent_pos)) + final_ent_angle_btw_focus_and_hold - final_hold_ent_angle_offset;
|
||||
|
||||
if (!F32_IS_NAN(final_ent_angle)) {
|
||||
xf = xform_with_rotation(xf, final_ent_angle);
|
||||
}
|
||||
|
||||
ent->xform = xf;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
|
||||
@ -641,6 +641,14 @@ INLINE f32 v2_angle_from_points(struct v2 pt1, struct v2 pt2)
|
||||
return v2_angle(v2_sub(pt2, pt1));
|
||||
}
|
||||
|
||||
INLINE struct v2 v2_closest_point_ray(struct v2 ray_pos, struct v2 ray_dir_norm, struct v2 p)
|
||||
{
|
||||
struct v2 ray_p_dir = v2_sub(p, ray_pos);
|
||||
f32 dot = v2_dot(ray_dir_norm, ray_p_dir);
|
||||
struct v2 ray_dir_closest = v2_mul(ray_dir_norm, dot);
|
||||
return v2_add(ray_pos, ray_dir_closest);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Mat4x4
|
||||
* ========================== */
|
||||
|
||||
62
src/sprite.c
62
src/sprite.c
@ -518,39 +518,37 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
struct sprite_sheet_slice *slice = &slice_group->frame_slices[(start * slice_group->per_frame_count) + index_in_frame];
|
||||
slice->original = true;
|
||||
|
||||
f32 x1 = ase_slice->x1;
|
||||
f32 y1 = ase_slice->y1;
|
||||
f32 x2 = ase_slice->x2;
|
||||
f32 y2 = ase_slice->y2;
|
||||
f32 x1_px = ase_slice->x1;
|
||||
f32 y1_px = ase_slice->y1;
|
||||
f32 x2_px = ase_slice->x2;
|
||||
f32 y2_px = ase_slice->y2;
|
||||
f32 width_px = x2_px - x1_px;
|
||||
f32 height_px = y2_px - y1_px;
|
||||
|
||||
f32 x1 = (x1_px - frame_center.x) / frame_size.x;
|
||||
f32 y1 = (y1_px - frame_center.y) / frame_size.y;
|
||||
f32 x2 = (x2_px - frame_center.x) / frame_size.x;
|
||||
f32 y2 = (y2_px - frame_center.y) / frame_size.y;
|
||||
f32 width = x2 - x1;
|
||||
f32 height = y2 - y1;
|
||||
|
||||
f32 x1_norm = (x1 - frame_center.x) / frame_size.x;
|
||||
f32 y1_norm = (y1 - frame_center.y) / frame_size.y;
|
||||
f32 x2_norm = (x2 - frame_center.x) / frame_size.x;
|
||||
f32 y2_norm = (y2 - frame_center.y) / frame_size.y;
|
||||
f32 width_norm = x2_norm - x1_norm;
|
||||
f32 height_norm = y2_norm - y1_norm;
|
||||
|
||||
/* Rect */
|
||||
struct rect rect_px = RECT(x1_px, y1_px, width_px, height_px);
|
||||
struct rect rect = RECT(x1, y1, width, height);
|
||||
/* Rect norm */
|
||||
struct rect rect_norm = RECT(x1_norm, y1_norm, width_norm, height_norm);
|
||||
/* Center */
|
||||
struct v2 center_px = V2(x1_px + (width_px * 0.5f), y1_px + (height_px * 0.5f));
|
||||
struct v2 center = V2(x1 + (width * 0.5f), y1 + (height * 0.5f));
|
||||
/* Center norm */
|
||||
struct v2 center_norm = V2(x1_norm + (width_norm * 0.5f), y1_norm + (height_norm * 0.5f));
|
||||
/* Dir */
|
||||
struct v2 dir = V2(center.x, 0);
|
||||
/* Dir norm */
|
||||
struct v2 dir_norm = V2(0, -0.5);
|
||||
struct v2 dir_px = V2(center_px.x, 0);
|
||||
struct v2 dir = V2(0, -0.5);
|
||||
|
||||
slice->rect_px = rect_px;
|
||||
slice->center_px = center_px;
|
||||
slice->dir_px = dir_px;
|
||||
|
||||
slice->rect = rect;
|
||||
slice->rect_norm = rect_norm;
|
||||
slice->center = center;
|
||||
slice->center_norm = center_norm;
|
||||
slice->dir = dir;
|
||||
slice->dir_norm = dir_norm;
|
||||
|
||||
node->index_in_frame = index_in_frame;
|
||||
if (start < node->earliest_frame) {
|
||||
@ -618,14 +616,15 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
for (u32 i = 0; i < ase.num_frames; ++i) {
|
||||
/* Use ray slice in ray group */
|
||||
struct sprite_sheet_slice *ray_slice = &ray_slice_group->frame_slices[i * point_slices_per_frame];
|
||||
struct v2 ray_end = ray_slice->center;
|
||||
struct v2 ray_end_norm = ray_slice->center_norm;
|
||||
struct v2 ray_end = ray_slice->center_px;
|
||||
struct v2 ray_end_norm = ray_slice->center;
|
||||
|
||||
/* Apply to each point slice in point group */
|
||||
for (u32 j = 0; j < point_slices_per_frame; ++j) {
|
||||
struct sprite_sheet_slice *point_slice = &point_slice_group->frame_slices[(i * point_slices_per_frame) + j];
|
||||
point_slice->dir = v2_sub(ray_end, point_slice->center);
|
||||
point_slice->dir_norm = v2_sub(ray_end_norm, point_slice->center_norm);
|
||||
point_slice->dir_px = v2_sub(ray_end, point_slice->center_px);
|
||||
point_slice->dir = v2_sub(ray_end_norm, point_slice->center);
|
||||
point_slice->has_ray = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -971,10 +970,17 @@ struct sprite_sheet_slice sprite_sheet_get_slice(struct sprite_sheet *sheet, str
|
||||
return group->frame_slices[frame_index * group->per_frame_count];
|
||||
}
|
||||
}
|
||||
|
||||
/* Return 'pivot' by default */
|
||||
struct sprite_sheet_slice res = { 0 };
|
||||
res.center = v2_mul(sheet->frame_size, 0.5f);
|
||||
res.dir = V2(res.center.x, 0);
|
||||
res.dir_norm = V2(0, -0.5);
|
||||
if (string_eq(name, STR("pivot"))) {
|
||||
res.center_px = v2_mul(sheet->frame_size, 0.5f);
|
||||
res.dir_px = V2(res.center_px.x, 0);
|
||||
res.dir = V2(0, -0.5);
|
||||
} else {
|
||||
res = sprite_sheet_get_slice(sheet, STR("pivot"), frame_index);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
15
src/sprite.h
15
src/sprite.h
@ -93,14 +93,21 @@ struct sprite_sheet_span {
|
||||
};
|
||||
|
||||
struct sprite_sheet_slice {
|
||||
/* Values suffixed with '_norm' are in the range -0.5 (top / left edge) -> +0.5 (bottom / right edge) */
|
||||
/* If true, this slice was not copied over from another frame in the sprite sheet */
|
||||
b32 original;
|
||||
|
||||
/* If true, the slice has a corresponding '.ray' slice affecting the 'dir' fields */
|
||||
b32 has_ray;
|
||||
|
||||
/* Values are in the range -0.5 (top / left edge) -> +0.5 (bottom / right edge) */
|
||||
struct rect rect;
|
||||
struct rect rect_norm;
|
||||
struct v2 center;
|
||||
struct v2 center_norm;
|
||||
struct v2 dir;
|
||||
struct v2 dir_norm;
|
||||
|
||||
/* '_px' values retain the original sprite pixel dimensions */
|
||||
struct rect rect_px;
|
||||
struct v2 center_px;
|
||||
struct v2 dir_px;
|
||||
};
|
||||
|
||||
struct sprite_sheet_slice_array {
|
||||
|
||||
@ -100,7 +100,7 @@ struct string string_from_float(struct arena *arena, f64 f, u32 precision)
|
||||
u8 *final_text = arena_dry_push(arena, u8);
|
||||
u64 final_len = 0;
|
||||
|
||||
if (f != f) {
|
||||
if (F32_IS_NAN(f)) {
|
||||
final_len += string_copy(arena, STR("NaN")).len;
|
||||
} else if (f == F64_INFINITY) {
|
||||
final_len += string_copy(arena, STR("inf")).len;
|
||||
|
||||
45
src/user.c
45
src/user.c
@ -433,8 +433,9 @@ INTERNAL void user_update(void)
|
||||
|
||||
world_copy_replace(&G.world, t1);
|
||||
|
||||
/* Blend time */
|
||||
/* Blend world globals */
|
||||
G.world.time = math_lerp64(t0->time, t1->time, (f64)tick_blend);
|
||||
G.world.player_aim = v2_lerp(t0->player_aim, t1->player_aim, tick_blend);
|
||||
|
||||
/* Blend entities */
|
||||
struct entity_array t0_entities = entity_store_as_array(&t0->entity_store);
|
||||
@ -823,6 +824,17 @@ INTERNAL void user_update(void)
|
||||
debug_draw_xform(ent->xform_world);
|
||||
}
|
||||
|
||||
/* Draw aim 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("hold"), ent->animation_frame);
|
||||
struct v2 start = xform_mul_v2(ent->sprite_xform_world, slice.center);
|
||||
start = xform_mul_v2(G.world_view, start);
|
||||
struct v2 end = v2_add(ent->xform.og, ent->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));
|
||||
}
|
||||
|
||||
/* Draw slices */
|
||||
if (!sprite_tag_is_nil(ent->sprite)) {
|
||||
struct sprite_tag sprite = ent->sprite;
|
||||
@ -830,12 +842,29 @@ INTERNAL void user_update(void)
|
||||
|
||||
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 quad quad = quad_from_rect(slice.rect_norm);
|
||||
|
||||
struct v2 center = xform_mul_v2(ent->sprite_xform_world, slice.center);
|
||||
center = xform_mul_v2(G.world_view, center);
|
||||
|
||||
if (!slice.has_ray) {
|
||||
struct quad quad = quad_from_rect(slice.rect);
|
||||
quad = quad_mul_xform(quad, ent->sprite_xform_world);
|
||||
draw_solid_quad_line(G.viewport_canvas, quad_mul_xform(quad, G.world_view), 3, COLOR_RED);
|
||||
quad = quad_mul_xform(quad, G.world_view);
|
||||
draw_solid_quad_line(G.viewport_canvas, quad, 2, RGBA_32_F(1, 0, 0.5, 1));
|
||||
}
|
||||
|
||||
draw_solid_circle(G.viewport_canvas, center, 3, RGBA_32_F(1, 0, 0, 1), 20);
|
||||
|
||||
if (slice.has_ray) {
|
||||
struct v2 ray = xform_basis_mul_v2(ent->sprite_xform_world, slice.dir);
|
||||
ray = xform_basis_mul_v2(G.world_view, ray);
|
||||
ray = v2_mul(v2_norm(ray), 50);
|
||||
draw_solid_arrow_ray(G.viewport_canvas, center, ray, 2, 10, RGBA_32_F(1, 0, 0.5, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -852,16 +881,6 @@ INTERNAL void user_update(void)
|
||||
draw_solid_arrow_line(G.viewport_canvas, start, end, thickness, arrow_height, color);
|
||||
}
|
||||
|
||||
/* Draw aim */
|
||||
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||
u32 color = RGBA_32_F(0.75, 0, 0.75, 0.5);
|
||||
f32 thickness = 3;
|
||||
f32 arrow_height = 10;
|
||||
struct v2 pos = xform_mul_v2(G.world_view, ent->xform_world.og);
|
||||
struct v2 aim_ray = xform_basis_mul_v2(G.world_view, ent->focus);
|
||||
draw_solid_arrow_ray(G.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_32_F(1, 1, 1, 0.5) : RGBA_32_F(0, 0.75, 0, 0.5);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user