diff --git a/src/sprite.c b/src/sprite.c index 4fff468a..3cea7e28 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -11,6 +11,7 @@ #include "thread_local.h" #include "app.h" #include "renderer.h" +#include "math.h" #define CACHE_MEMORY_BUDGET (MEGABYTE(256)) #define CACHE_BUCKETS_COUNT 1024 @@ -388,31 +389,36 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, struct ase_decode_sheet_result ase) { + __prof; struct sprite_sheet sheet = { 0 }; ASSERT(ase.num_frames >= 1); /* Init frames */ - sheet.image_size = ase.image_size; - sheet.frame_size = ase.frame_size; - sheet.frames = arena_push_array_zero(arena, struct sprite_sheet_frame, ase.num_frames); - sheet.frames_count = ase.num_frames; - for (struct ase_frame *ase_frame = ase.frame_head; ase_frame; ase_frame = ase_frame->next) { - u32 index = ase_frame->index; + { + __profscope(init_frames); + sheet.image_size = ase.image_size; + sheet.frame_size = ase.frame_size; + sheet.frames = arena_push_array_zero(arena, struct sprite_sheet_frame, ase.num_frames); + sheet.frames_count = ase.num_frames; + for (struct ase_frame *ase_frame = ase.frame_head; ase_frame; ase_frame = ase_frame->next) { + u32 index = ase_frame->index; - struct v2 clip_p1 = { (f32)ase_frame->x1 / (f32)ase.image_size.x, (f32)ase_frame->y1 / (f32)ase.image_size.y }; - struct v2 clip_p2 = { (f32)ase_frame->x2 / (f32)ase.image_size.x, (f32)ase_frame->y2 / (f32)ase.image_size.y }; + struct v2 clip_p1 = { (f32)ase_frame->x1 / (f32)ase.image_size.x, (f32)ase_frame->y1 / (f32)ase.image_size.y }; + struct v2 clip_p2 = { (f32)ase_frame->x2 / (f32)ase.image_size.x, (f32)ase_frame->y2 / (f32)ase.image_size.y }; - sheet.frames[index] = (struct sprite_sheet_frame) { - .index = index, - .duration = ase_frame->duration, - .clip = (struct clip_rect) { clip_p1, clip_p2 } - }; + sheet.frames[index] = (struct sprite_sheet_frame) { + .index = index, + .duration = ase_frame->duration, + .clip = (struct clip_rect) { clip_p1, clip_p2 } + }; + } } /* Init spans */ sheet.spans_count = ase.num_spans; if (ase.num_spans > 0) { + __profscope(init_spans); sheet.spans_dict = fixed_dict_init(arena, (u64)(ase.num_spans * SHEET_SPAN_LOOKUP_TABLE_BUCKET_RATIO)); for (struct ase_span *ase_span = ase.span_head; ase_span; ase_span = ase_span->next) { struct string name = string_copy(arena, ase_span->name); @@ -428,6 +434,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str /* Init slices */ if (ase.num_slice_keys > 0) { + __profscope(init_slices); struct temp_arena scratch = scratch_begin(arena); struct temp_ase_slice_key_node { @@ -444,7 +451,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str struct temp_ase_slice_key_node *temp_ase_slice_key_head; struct temp_slice_group_node *next; - struct sprite_slice_group *final_slice_group; + struct sprite_sheet_slice_group *final_slice_group; }; /* Group slices by name and find out counts per frame */ @@ -454,6 +461,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str struct fixed_dict temp_slice_dict = fixed_dict_init(scratch.arena, (u64)(ase.num_slice_keys * 2)); for (struct ase_slice_key *ase_slice_key = ase.slice_key_head; ase_slice_key; ase_slice_key = ase_slice_key->next) { struct string name = ase_slice_key->name; + struct temp_slice_group_node *temp_slice_group_node = fixed_dict_get(&temp_slice_dict, name); if (!temp_slice_group_node) { temp_slice_group_node = arena_push_zero(scratch.arena, struct temp_slice_group_node); @@ -468,7 +476,8 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str struct temp_ase_slice_key_node *node = arena_push_zero(scratch.arena, struct temp_ase_slice_key_node); node->key = ase_slice_key; node->next = temp_slice_group_node->temp_ase_slice_key_head; - node->earliest_frame = node->key->slice_head->start; /* To be overwritten later after iterating */ + node->earliest_frame = U32_MAX; /* To be overwritten later after iterating */ + temp_slice_group_node->temp_ase_slice_key_head = node; ++temp_slice_group_node->per_frame_count; @@ -480,7 +489,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str sheet.slice_groups_dict = fixed_dict_init(arena, (u64)(num_temp_slice_group_nodes * SHEET_SLICE_LOOKUP_TABLE_BUCKET_RATIO)); for (struct temp_slice_group_node *temp_slice_group_node = temp_slice_group_head; temp_slice_group_node; temp_slice_group_node = temp_slice_group_node->next) { - struct sprite_slice_group *slice_group = arena_push_zero(arena, struct sprite_slice_group); + struct sprite_sheet_slice_group *slice_group = arena_push_zero(arena, struct sprite_sheet_slice_group); slice_group->name = string_copy(arena, temp_slice_group_node->name); slice_group->per_frame_count = temp_slice_group_node->per_frame_count; @@ -502,7 +511,9 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str f32 x2 = ase_slice->x2; f32 y2 = ase_slice->y2; - slice->center = V2(x1 + ((x2 - x1) / 2.f), y1 + ((y2 - y1) / 2.f)); + struct v2 center = V2(x1 + ((x2 - x1) / 2.f), y1 + ((y2 - y1) / 2.f)); + slice->center = center; + slice->dir = V2(0, -1); node->index_in_frame = index_in_frame; if (start < node->earliest_frame) { @@ -519,7 +530,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str /* Propogate original slices into next frames (and first slices into previous frames) */ for (struct temp_slice_group_node *temp_slice_group_node = temp_slice_group_head; temp_slice_group_node; temp_slice_group_node = temp_slice_group_node->next) { - struct sprite_slice_group *slice_group = temp_slice_group_node->final_slice_group; + struct sprite_sheet_slice_group *slice_group = temp_slice_group_node->final_slice_group; for (struct temp_ase_slice_key_node *node = temp_slice_group_node->temp_ase_slice_key_head; node; node = node->next) { struct ase_slice_key *key = node->key; @@ -552,6 +563,36 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str } } + /* Calculate rays */ + for (struct temp_slice_group_node *temp_slice_group_node = temp_slice_group_head; temp_slice_group_node; temp_slice_group_node = temp_slice_group_node->next) { + struct string ray_suffix = STR(".ray"); + + struct sprite_sheet_slice_group *ray_slice_group = temp_slice_group_node->final_slice_group; + struct string ray_slice_name = ray_slice_group->name; + if (string_ends_with(ray_slice_name, ray_suffix)) { + struct string point_slice_name = ray_slice_name; + point_slice_name.len -= ray_suffix.len; + + struct sprite_sheet_slice_group *point_slice_group = fixed_dict_get(&sheet.slice_groups_dict, point_slice_name); + if (point_slice_group) { + u32 point_slices_per_frame = point_slice_group->per_frame_count; + + 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; + + /* 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); + } + } + + } + } + } + scratch_end(scratch); } @@ -857,6 +898,22 @@ struct sprite_sheet *sprite_sheet_from_tag_async(struct sprite_scope *scope, str return (struct sprite_sheet *)data_from_tag_internal(scope, tag, CACHE_NODE_KIND_SHEET, false); } +struct sprite_sheet_frame sprite_sheet_get_frame(struct sprite_sheet *sheet, u32 index) +{ + __prof; + if (sheet->frames_count > 0) { + index = min_u32(sheet->frames_count - 1, index); + return sheet->frames[index]; + } else { + return (struct sprite_sheet_frame) + { + .index = 0, + .duration = 0.1, + .clip = CLIP_ALL + }; + } +} + struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struct string name) { __prof; @@ -870,19 +927,29 @@ struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struc return res; } -struct sprite_sheet_frame sprite_sheet_get_frame(struct sprite_sheet *sheet, u32 index) +struct sprite_sheet_slice sprite_sheet_get_slice(struct sprite_sheet *sheet, struct string name, u32 frame_index) { - __prof; - if (sheet->frames_count > 0) { - index = min_u32(sheet->frames_count - 1, index); - return sheet->frames[index]; - } else { - return (struct sprite_sheet_frame) { - .index = 0, - .duration = 0.1, - .clip = CLIP_ALL - }; + struct sprite_sheet_slice res = { 0 }; + + struct sprite_sheet_slice_group *group = fixed_dict_get(&sheet->slice_groups_dict, name); + if (group) { + res = group->frame_slices[frame_index * group->per_frame_count]; } + + return res; +} + +struct sprite_sheet_slice_array sprite_sheet_get_slices(struct sprite_sheet *sheet, struct string name, u32 frame_index) +{ + struct sprite_sheet_slice_array res = { 0 }; + + struct sprite_sheet_slice_group *group = fixed_dict_get(&sheet->slice_groups_dict, name); + if (group) { + res.count = group->per_frame_count; + res.slices = &group->frame_slices[frame_index * group->per_frame_count]; + } + + return res; } /* ========================== * diff --git a/src/sprite.h b/src/sprite.h index 2467dba0..8bb59047 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -35,7 +35,7 @@ struct sprite_scope *sprite_scope_begin(void); void sprite_scope_end(struct sprite_scope *scope); /* ========================== * - * Texture + * Texture load * ========================== */ struct sprite_texture { @@ -50,7 +50,7 @@ struct sprite_texture *sprite_texture_from_tag_await(struct sprite_scope *scope, struct sprite_texture *sprite_texture_from_tag_async(struct sprite_scope *scope, struct sprite_tag tag); /* ========================== * - * Sheet + * Sheet load * ========================== */ struct sprite_sheet { @@ -66,15 +66,17 @@ struct sprite_sheet { struct fixed_dict slice_groups_dict; }; -struct sprite_sheet_slice { - b32 original; - struct v2 center; -}; +struct sprite_sheet *sprite_sheet_from_tag_await(struct sprite_scope *scope, struct sprite_tag tag); +struct sprite_sheet *sprite_sheet_from_tag_async(struct sprite_scope *scope, struct sprite_tag tag); -struct sprite_slice_group { - struct string name; - u64 per_frame_count; - struct sprite_sheet_slice *frame_slices; /* 2d array of slices with length (num frames) * (num slices per frame). Index with [(frame index * per frame count) + slice index in frame] */ +/* ========================== * + * Sheet query + * ========================== */ + +struct sprite_sheet_frame { + u32 index; + f64 duration; + struct clip_rect clip; }; struct sprite_sheet_span { @@ -83,18 +85,34 @@ struct sprite_sheet_span { u32 end; }; -struct sprite_sheet_frame { - u32 index; - f64 duration; - struct clip_rect clip; +struct sprite_sheet_slice { + b32 original; + struct v2 center; + struct v2 dir; }; -/* Load */ -struct sprite_sheet *sprite_sheet_from_tag_await(struct sprite_scope *scope, struct sprite_tag tag); -struct sprite_sheet *sprite_sheet_from_tag_async(struct sprite_scope *scope, struct sprite_tag tag); +struct sprite_sheet_slice_array { + u64 count; + struct sprite_sheet_slice *slices; +}; + +struct sprite_sheet_slice_group { + struct string name; + u64 per_frame_count; + + /* 2d array of slices with length (num frames) * (num slices per frame). + * Index with [(frame index * num slices per frame) + slice index in frame] */ + struct sprite_sheet_slice *frame_slices; +}; -/* Index */ -struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struct string name); struct sprite_sheet_frame sprite_sheet_get_frame(struct sprite_sheet *sheet, u32 index); +struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struct string name); + +/* Returns first slice with name in frame */ +struct sprite_sheet_slice sprite_sheet_get_slice(struct sprite_sheet *sheet, struct string name, u32 frame_index); + +/* Returns all slices with name in frame */ +struct sprite_sheet_slice_array sprite_sheet_get_slices(struct sprite_sheet *sheet, struct string name, u32 frame_index); + #endif diff --git a/src/user.c b/src/user.c index 6ec743bd..949ac10c 100644 --- a/src/user.c +++ b/src/user.c @@ -758,7 +758,6 @@ INTERNAL void user_update(void) /* Draw sprite */ if (!sprite_tag_is_nil(ent->sprite)) { -#if 1 struct sprite_tag sprite = ent->sprite; /* Async load */ @@ -789,61 +788,35 @@ INTERNAL void user_update(void) struct quad quad; { -#if 1 struct xform sprite_xf = XFORM_IDENT; { - struct v2 sprite_size_meters = V2( - sheet->frame_size.x / (f32)PIXELS_PER_UNIT, - sheet->frame_size.y / (f32)PIXELS_PER_UNIT - ); + struct v2 sprite_size_meters = v2_div(sheet->frame_size, (f32)PIXELS_PER_UNIT); -#if 1 + /* TODO: Cache these in slice */ struct v2 pivot_pos; + f32 pivot_rot; { - struct v2 pivot_pos_norm = V2(0, 0); /* Pivot x & y are each normalized about sprite dimensions. <0, 0> is center, <1, 1> is bottom right corner, etc. */ - struct v2 half_size = v2_mul(sprite_size_meters, 0.5f); - pivot_pos = v2_mul_v2(pivot_pos_norm, half_size); + struct sprite_sheet_slice pivot_slice = sprite_sheet_get_slice(sheet, STR("pivot"), frame.index); + + /* Pivot pos */ + struct v2 pivot_pos_norm = pivot_slice.center; + pivot_pos_norm = v2_mul(pivot_pos_norm, 2); + pivot_pos_norm = v2_sub(pivot_pos_norm, sheet->frame_size); + pivot_pos_norm = v2_div_v2(pivot_pos_norm, sheet->frame_size); + pivot_pos = v2_mul_v2(pivot_pos_norm, v2_mul(sprite_size_meters, 0.5f)); + + /* Pivot rot */ + pivot_rot = -v2_angle(pivot_slice.dir) - (TAU / 4.0f); } - /* Pivot */ + /* Apply Pivot */ + sprite_xf = xform_rotate(sprite_xf, pivot_rot); sprite_xf = xform_translate(sprite_xf, v2_neg(pivot_pos)); sprite_xf = xform_scale(sprite_xf, sprite_size_meters); -#else - struct sprite_sheet_slice pivot_slice = sprite_sheet_get_slice(STR("pivot"), frame.index); - struct v2 pivot_pos_norm = pivot_slice.center_norm; - f32 pivot_rot = pivot_slice.rot; - /* Pivot */ - sprite_xf = xform_rotate(sprite_xf, pivot_rot); - sprite_xf = xform_translate(sprite_xf, v2_neg(pivot_pos_norm)); - sprite_xf = xform_scale(sprite_xf, sprite_size_meters); -#endif - - /* Apply entity xform to sprite xform */ + /* Apply entity sprite xform */ sprite_xf = xform_mul(sprite_xf, ent->sprite_quad_xform); } -#else - - struct v2 sprite_pos = V2(0, 0); - f32 sprite_rot = 0; - struct v2 sprite_size = V2(0.5f, 0.5f); - // struct v2 sprite_size = sprite_sheet_size_meters(sprite_sheet_tag); - - struct v2 sprite_pivot; - { - struct v2 sprite_pivot_norm = V2(0, 0); /* Pivot x & y are each normalized about sprite dimensions. <0, 0> is center, <1, 1> is bottom right corner, etc. */ - struct v2 half_size = v2_mul(sprite_size, 0.5f); - sprite_pivot = v2_mul_v2(sprite_pivot_norm, half_size); - } - - struct xform sprite_xf = XFORM_POS(sprite_pos); - 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); - - struct xform xf = { 0 }; - xf = xform_mul(ent->world_xform, sprite_xf); -#endif quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xform_mul(ent->world_xform, sprite_xf)); } @@ -852,46 +825,6 @@ INTERNAL void user_update(void) 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); } - - - -#else - /* Draw texture */ - struct sprite_tag sprite = ent->sprite; - - 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; - - struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite); - struct sprite_sheet_frame frame = { 0 }; - { - struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name); - u64 frame_index = span.start + ent->animation_frame; - frame = sprite_sheet_get_frame(sheet, frame_index); - if (entity_has_prop(ent, ENTITY_PROP_ANIMATING)) { - f64 time_in_frame = ent->animation_time_in_frame; - while (time_in_frame > frame.duration) { - time_in_frame -= frame.duration; - ++frame_index; - if (frame_index > span.end) { - /* Loop animation */ - frame_index = span.start; - } - frame = sprite_sheet_get_frame(sheet, frame_index); - } - } - } - - struct draw_sprite_params params = DRAW_SPRITE_PARAMS(.sprite = sprite, .tint = tint, .clip = frame.clip); - - /* TODO: Fade in a placeholder or something instead of drawing nothing. */ - struct sprite_texture *texture = sprite_texture_from_tag_async(sprite_frame_scope, sprite); - if (sheet->loaded && texture->loaded) { - draw_sprite_quad(G.world_canvas, params, quad); - } -#endif } /* Debug draw info */