ase slice parsing first pass
This commit is contained in:
parent
91ea995209
commit
a314f1b8f4
73
src/ase.c
73
src/ase.c
@ -830,11 +830,14 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff
|
|||||||
u64 image_height = frame_height * frames_y;
|
u64 image_height = frame_height * frames_y;
|
||||||
make_image_dimensions_squareish(&ase_header, &frames_x, &frames_y, &image_width, &image_height);
|
make_image_dimensions_squareish(&ase_header, &frames_x, &frames_y, &image_width, &image_height);
|
||||||
|
|
||||||
|
u32 num_frames = 0;
|
||||||
|
struct ase_frame *frame_head = NULL;
|
||||||
|
|
||||||
u32 num_spans = 0;
|
u32 num_spans = 0;
|
||||||
struct ase_span *span_head = NULL;
|
struct ase_span *span_head = NULL;
|
||||||
|
|
||||||
u32 num_frames = 0;
|
u32 num_slice_keys = 0;
|
||||||
struct ase_frame *frame_head = NULL;
|
struct ase_slice_key *slice_key_head = NULL;
|
||||||
|
|
||||||
/* Iterate frames */
|
/* Iterate frames */
|
||||||
for (u16 i = 0; i < ase_header.frames; ++i) {
|
for (u16 i = 0; i < ase_header.frames; ++i) {
|
||||||
@ -851,6 +854,9 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff
|
|||||||
frame->next = frame_head;
|
frame->next = frame_head;
|
||||||
frame_head = frame;
|
frame_head = frame;
|
||||||
|
|
||||||
|
frame->index = i;
|
||||||
|
frame->duration = frame_header.frame_duration_ms / 1000.0;
|
||||||
|
|
||||||
u32 frame_tile_x = i % frames_x;
|
u32 frame_tile_x = i % frames_x;
|
||||||
u32 frame_tile_y = i / frames_x;
|
u32 frame_tile_y = i / frames_x;
|
||||||
|
|
||||||
@ -858,13 +864,13 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff
|
|||||||
u32 frame_y1 = frame_tile_y * frame_height;
|
u32 frame_y1 = frame_tile_y * frame_height;
|
||||||
u32 frame_x2 = frame_x1 + frame_width;
|
u32 frame_x2 = frame_x1 + frame_width;
|
||||||
u32 frame_y2 = frame_y1 + frame_height;
|
u32 frame_y2 = frame_y1 + frame_height;
|
||||||
|
frame->x1 = frame_x1;
|
||||||
struct v2 clip_p1 = { (f32)frame_x1 / (f32)image_width, (f32)frame_y1 / (f32)image_height };
|
frame->y1 = frame_y1;
|
||||||
struct v2 clip_p2 = { (f32)frame_x2 / (f32)image_width, (f32)frame_y2 / (f32)image_height };
|
frame->x2 = frame_x2;
|
||||||
|
frame->y2 = frame_y2;
|
||||||
|
|
||||||
frame->index = i;
|
frame->index = i;
|
||||||
frame->duration = frame_header.frame_duration_ms / 1000.0;
|
frame->duration = frame_header.frame_duration_ms / 1000.0;
|
||||||
frame->clip = (struct clip_rect) { clip_p1, clip_p2 };
|
|
||||||
|
|
||||||
/* Iterate chunks in frame */
|
/* Iterate chunks in frame */
|
||||||
for (u32 j = 0; j < num_chunks; ++j) {
|
for (u32 j = 0; j < num_chunks; ++j) {
|
||||||
@ -903,9 +909,60 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff
|
|||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case CHUNK_TYPE_SLICE: {
|
||||||
|
struct ase_slice_key *slice_key = arena_push_zero(arena, struct ase_slice_key);
|
||||||
|
slice_key->next = slice_key_head;
|
||||||
|
slice_key_head = slice_key;
|
||||||
|
|
||||||
|
u32 num_slices = br_read_u32(&br);
|
||||||
|
slice_key->num_slices = num_slices;
|
||||||
|
|
||||||
|
u32 flags = br_read_u32(&br);
|
||||||
|
br_seek(&br, 4);
|
||||||
|
|
||||||
|
struct string name;
|
||||||
|
{
|
||||||
|
u16 str_len = br_read_u16(&br);
|
||||||
|
u8 *str_bytes = br_read_raw(&br, str_len);
|
||||||
|
name = (struct string) {
|
||||||
|
str_len,
|
||||||
|
arena_push_array(arena, u8, str_len)
|
||||||
|
};
|
||||||
|
MEMCPY(name.text, str_bytes, str_len);
|
||||||
|
}
|
||||||
|
slice_key->name = name;
|
||||||
|
|
||||||
|
for (u32 k = 0; k < num_slices; ++k) {
|
||||||
|
struct ase_slice *slice = arena_push_zero(arena, struct ase_slice);
|
||||||
|
slice->next = slice_key->slice_head;
|
||||||
|
slice_key->slice_head = slice;
|
||||||
|
|
||||||
|
u32 start = br_read_u32(&br);
|
||||||
|
i32 x = br_read_i32(&br);
|
||||||
|
i32 y = br_read_i32(&br);
|
||||||
|
u32 width = br_read_u32(&br);
|
||||||
|
u32 height = br_read_u32(&br);
|
||||||
|
if (flags & 0x01) {
|
||||||
|
/* Skip 9-patches info */
|
||||||
|
br_seek(&br, 128);
|
||||||
|
}
|
||||||
|
if (flags & 0x02) {
|
||||||
|
/* Skip pivot info */
|
||||||
|
br_seek(&br, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
slice->start = start;
|
||||||
|
slice->x1 = x;
|
||||||
|
slice->y1 = y;
|
||||||
|
slice->x2 = max_u32((x + width) - 1, 0);
|
||||||
|
slice->y2 = max_u32((y + height) - 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
++num_slice_keys;
|
||||||
|
} break;
|
||||||
|
|
||||||
/* TODO */
|
/* TODO */
|
||||||
//case CHUNK_TYPE_USER_DATA
|
//case CHUNK_TYPE_USER_DATA
|
||||||
//case CHUNK_TYPE_SLICE
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
br_seek_to(&br, chunk_end_pos);
|
br_seek_to(&br, chunk_end_pos);
|
||||||
@ -922,8 +979,10 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff
|
|||||||
res.frame_size = V2(frame_width, frame_height);
|
res.frame_size = V2(frame_width, frame_height);
|
||||||
res.num_frames = num_frames;
|
res.num_frames = num_frames;
|
||||||
res.num_spans = num_spans;
|
res.num_spans = num_spans;
|
||||||
|
res.num_slice_keys = num_slice_keys;
|
||||||
res.frame_head = frame_head;
|
res.frame_head = frame_head;
|
||||||
res.span_head = span_head;
|
res.span_head = span_head;
|
||||||
|
res.slice_key_head = slice_key_head;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/ase.h
23
src/ase.h
@ -12,6 +12,22 @@ struct ase_error_list {
|
|||||||
struct ase_error *last;
|
struct ase_error *last;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ase_slice {
|
||||||
|
u32 start;
|
||||||
|
i32 x1;
|
||||||
|
i32 y1;
|
||||||
|
i32 x2;
|
||||||
|
i32 y2;
|
||||||
|
struct ase_slice *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ase_slice_key {
|
||||||
|
struct string name;
|
||||||
|
u32 num_slices;
|
||||||
|
struct ase_slice *slice_head;
|
||||||
|
struct ase_slice_key *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct ase_span {
|
struct ase_span {
|
||||||
struct string name;
|
struct string name;
|
||||||
u32 start;
|
u32 start;
|
||||||
@ -21,8 +37,11 @@ struct ase_span {
|
|||||||
|
|
||||||
struct ase_frame {
|
struct ase_frame {
|
||||||
u32 index;
|
u32 index;
|
||||||
|
u32 x1;
|
||||||
|
u32 y1;
|
||||||
|
u32 x2;
|
||||||
|
u32 y2;
|
||||||
f64 duration;
|
f64 duration;
|
||||||
struct clip_rect clip;
|
|
||||||
struct ase_frame *next;
|
struct ase_frame *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,8 +55,10 @@ struct ase_decode_sheet_result {
|
|||||||
struct v2 frame_size;
|
struct v2 frame_size;
|
||||||
u32 num_frames;
|
u32 num_frames;
|
||||||
u32 num_spans;
|
u32 num_spans;
|
||||||
|
u32 num_slice_keys;
|
||||||
struct ase_frame *frame_head;
|
struct ase_frame *frame_head;
|
||||||
struct ase_span *span_head;
|
struct ase_span *span_head;
|
||||||
|
struct ase_slice_key *slice_key_head;
|
||||||
struct ase_error_list errors;
|
struct ase_error_list errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -75,7 +75,7 @@ struct entity {
|
|||||||
|
|
||||||
/* ENTITY_PROP_ANIMATING */
|
/* ENTITY_PROP_ANIMATING */
|
||||||
f64 animation_time_in_frame;
|
f64 animation_time_in_frame;
|
||||||
u64 animation_frame;
|
u32 animation_frame;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Testing */
|
/* Testing */
|
||||||
|
|||||||
@ -194,6 +194,7 @@ INTERNAL void game_update(void)
|
|||||||
e->sprite_span_name = STR("idle.unarmed");
|
e->sprite_span_name = STR("idle.unarmed");
|
||||||
//e->sprite_span_name = STR("idle.two_handed");
|
//e->sprite_span_name = STR("idle.two_handed");
|
||||||
|
|
||||||
|
#if 0
|
||||||
struct v2 sprite_pos = V2(0, 0);
|
struct v2 sprite_pos = V2(0, 0);
|
||||||
f32 sprite_rot = 0;
|
f32 sprite_rot = 0;
|
||||||
struct v2 sprite_size = V2(0.5f, 0.5f);
|
struct v2 sprite_size = V2(0.5f, 0.5f);
|
||||||
@ -211,6 +212,7 @@ INTERNAL void game_update(void)
|
|||||||
sprite_xf = xform_translate(sprite_xf, v2_neg(sprite_pivot));
|
sprite_xf = xform_translate(sprite_xf, v2_neg(sprite_pivot));
|
||||||
sprite_xf = xform_scale(sprite_xf, sprite_size);
|
sprite_xf = xform_scale(sprite_xf, sprite_size);
|
||||||
e->sprite_quad_xform = sprite_xf;
|
e->sprite_quad_xform = sprite_xf;
|
||||||
|
#endif
|
||||||
e->sprite_tint = COLOR_WHITE;
|
e->sprite_tint = COLOR_WHITE;
|
||||||
|
|
||||||
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#define RENDERER_H
|
#define RENDERER_H
|
||||||
|
|
||||||
struct sys_window;
|
struct sys_window;
|
||||||
|
struct sprite_scope;
|
||||||
|
|
||||||
#define RENDERER_TEXTURE_MAX_WIDTH 16384
|
#define RENDERER_TEXTURE_MAX_WIDTH 16384
|
||||||
#define RENDERER_TEXTURE_MAX_HEIGHT 16384
|
#define RENDERER_TEXTURE_MAX_HEIGHT 16384
|
||||||
@ -69,7 +70,7 @@ void renderer_canvas_ensure_texture_cmd(struct renderer_canvas *canvas, struct t
|
|||||||
|
|
||||||
void renderer_canvas_send_to_gpu(struct renderer_canvas *canvas);
|
void renderer_canvas_send_to_gpu(struct renderer_canvas *canvas);
|
||||||
|
|
||||||
void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_count, struct v2 screen_size, struct rect viewport, i32 vsync);
|
void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_count, struct v2 screen_size, struct rect viewport, i32 vsync, struct sprite_scope *sprite_scope);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Texture
|
* Texture
|
||||||
|
|||||||
@ -838,12 +838,10 @@ INTERNAL void resize_viewport(struct rect viewport)
|
|||||||
* research if that is smart first).
|
* research if that is smart first).
|
||||||
*
|
*
|
||||||
* I'm thinking we may also just need to lock texture modification access while presenting */
|
* I'm thinking we may also just need to lock texture modification access while presenting */
|
||||||
void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_count, struct v2 screen_size, struct rect viewport, i32 vsync)
|
void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_count, struct v2 screen_size, struct rect viewport, i32 vsync, struct sprite_scope *sprite_scope)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
|
|
||||||
struct sprite_scope *sprite_scope = sprite_scope_begin();
|
|
||||||
|
|
||||||
/* Resize back buffer */
|
/* Resize back buffer */
|
||||||
if (!v2_eq(G.backbuffer_size, screen_size)) {
|
if (!v2_eq(G.backbuffer_size, screen_size)) {
|
||||||
resize_backbuffer(screen_size);
|
resize_backbuffer(screen_size);
|
||||||
@ -925,8 +923,6 @@ void renderer_canvas_present(struct renderer_canvas **canvases, u32 canvases_cou
|
|||||||
__profframe(0);
|
__profframe(0);
|
||||||
}
|
}
|
||||||
renderer_capture_image_for_profiler(viewport.width, viewport.height);
|
renderer_capture_image_for_profiler(viewport.width, viewport.height);
|
||||||
|
|
||||||
sprite_scope_end(sprite_scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
135
src/sprite.c
135
src/sprite.c
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#define SHEET_ARENA_RESERVE MEGABYTE(64)
|
#define SHEET_ARENA_RESERVE MEGABYTE(64)
|
||||||
#define SHEET_SPAN_LOOKUP_TABLE_BUCKET_RATIO 2.0
|
#define SHEET_SPAN_LOOKUP_TABLE_BUCKET_RATIO 2.0
|
||||||
|
#define SHEET_SLICE_LOOKUP_TABLE_BUCKET_RATIO 2.0
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Loader cmd structs
|
* Loader cmd structs
|
||||||
@ -398,10 +399,14 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
|||||||
sheet.frames_count = 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) {
|
for (struct ase_frame *ase_frame = ase.frame_head; ase_frame; ase_frame = ase_frame->next) {
|
||||||
u32 index = ase_frame->index;
|
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 };
|
||||||
|
|
||||||
sheet.frames[index] = (struct sprite_sheet_frame) {
|
sheet.frames[index] = (struct sprite_sheet_frame) {
|
||||||
.index = index,
|
.index = index,
|
||||||
.duration = ase_frame->duration,
|
.duration = ase_frame->duration,
|
||||||
.clip = ase_frame->clip
|
.clip = (struct clip_rect) { clip_p1, clip_p2 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +424,135 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
|||||||
};
|
};
|
||||||
fixed_dict_set(arena, &sheet.spans_dict, name, span);
|
fixed_dict_set(arena, &sheet.spans_dict, name, span);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init slices */
|
||||||
|
if (ase.num_slice_keys > 0) {
|
||||||
|
struct temp_arena scratch = scratch_begin(arena);
|
||||||
|
|
||||||
|
struct temp_ase_slice_key_node {
|
||||||
|
struct ase_slice_key *key;
|
||||||
|
struct temp_ase_slice_key_node *next;
|
||||||
|
|
||||||
|
u32 index_in_frame;
|
||||||
|
u32 earliest_frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct temp_slice_group_node {
|
||||||
|
struct string name;
|
||||||
|
u64 per_frame_count;
|
||||||
|
struct temp_ase_slice_key_node *temp_ase_slice_key_head;
|
||||||
|
struct temp_slice_group_node *next;
|
||||||
|
|
||||||
|
struct sprite_slice_group *final_slice_group;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Group slices by name and find out counts per frame */
|
||||||
|
u64 num_temp_slice_group_nodes = 0;
|
||||||
|
struct temp_slice_group_node *temp_slice_group_head = NULL;
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
temp_slice_group_node->name = name;
|
||||||
|
fixed_dict_set(scratch.arena, &temp_slice_dict, name, temp_slice_group_node);
|
||||||
|
|
||||||
|
++num_temp_slice_group_nodes;
|
||||||
|
temp_slice_group_node->next = temp_slice_group_head;
|
||||||
|
temp_slice_group_head = temp_slice_group_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
|
temp_slice_group_node->temp_ase_slice_key_head = node;
|
||||||
|
|
||||||
|
++temp_slice_group_node->per_frame_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate slice groups & fill originals in 2d array */
|
||||||
|
sheet.slice_groups_count = num_temp_slice_group_nodes;
|
||||||
|
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);
|
||||||
|
slice_group->name = string_copy(arena, temp_slice_group_node->name);
|
||||||
|
slice_group->per_frame_count = temp_slice_group_node->per_frame_count;
|
||||||
|
|
||||||
|
arena_align(arena, alignof(struct sprite_sheet_slice));
|
||||||
|
slice_group->frame_slices = (struct sprite_sheet_slice *)arena_push_array_zero(arena, u8, (ase.num_frames * slice_group->per_frame_count) * sizeof(struct sprite_sheet_slice));
|
||||||
|
|
||||||
|
u64 index_in_frame = 0;
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (struct ase_slice *ase_slice = key->slice_head; ase_slice; ase_slice = ase_slice->next) {
|
||||||
|
u32 start = ase_slice->start;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
slice->center = V2(x1 + ((x2 - x1) / 2.f), y1 + ((y2 - y1) / 2.f));
|
||||||
|
|
||||||
|
node->index_in_frame = index_in_frame;
|
||||||
|
if (start < node->earliest_frame) {
|
||||||
|
node->earliest_frame = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++index_in_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_slice_group_node->final_slice_group = slice_group;
|
||||||
|
fixed_dict_set(arena, &sheet.slice_groups_dict, slice_group->name, slice_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
u32 index_in_frame = node->index_in_frame;
|
||||||
|
for (struct ase_slice *ase_slice = key->slice_head; ase_slice; ase_slice = ase_slice->next) {
|
||||||
|
u32 start = ase_slice->start;
|
||||||
|
|
||||||
|
struct sprite_sheet_slice *slice = &slice_group->frame_slices[(start * slice_group->per_frame_count) + index_in_frame];
|
||||||
|
|
||||||
|
/* Propogate earliest slice to all previous frames */
|
||||||
|
if (start == node->earliest_frame && start > 0) {
|
||||||
|
for (u32 i = start; i-- > 0;) {
|
||||||
|
struct sprite_sheet_slice *target = &slice_group->frame_slices[(i * slice_group->per_frame_count) + index_in_frame];
|
||||||
|
*target = *slice;
|
||||||
|
target->original = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Propogate slice to forward frames until original is found */
|
||||||
|
for (u32 i = start + 1; i < ase.num_frames; ++i) {
|
||||||
|
struct sprite_sheet_slice *target = &slice_group->frame_slices[(i * slice_group->per_frame_count) + index_in_frame];
|
||||||
|
if (target->original) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*target = *slice;
|
||||||
|
target->original = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sheet;
|
return sheet;
|
||||||
|
|||||||
13
src/sprite.h
13
src/sprite.h
@ -62,6 +62,19 @@ struct sprite_sheet {
|
|||||||
struct sprite_sheet_frame *frames;
|
struct sprite_sheet_frame *frames;
|
||||||
u32 spans_count;
|
u32 spans_count;
|
||||||
struct fixed_dict spans_dict;
|
struct fixed_dict spans_dict;
|
||||||
|
u32 slice_groups_count;
|
||||||
|
struct fixed_dict slice_groups_dict;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sprite_sheet_slice {
|
||||||
|
b32 original;
|
||||||
|
struct v2 center;
|
||||||
|
};
|
||||||
|
|
||||||
|
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] */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sprite_sheet_span {
|
struct sprite_sheet_span {
|
||||||
|
|||||||
102
src/user.c
102
src/user.c
@ -400,7 +400,6 @@ INTERNAL void user_update(void)
|
|||||||
* Begin frame cache scopes
|
* Begin frame cache scopes
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* TODO: Remove texture scope once renderer is rewritten to work with tags */
|
|
||||||
struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
|
struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -759,6 +758,104 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
/* Draw sprite */
|
/* Draw sprite */
|
||||||
if (!sprite_tag_is_nil(ent->sprite)) {
|
if (!sprite_tag_is_nil(ent->sprite)) {
|
||||||
|
#if 1
|
||||||
|
struct sprite_tag sprite = 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;
|
||||||
|
|
||||||
|
if (sheet->loaded) {
|
||||||
|
struct sprite_sheet_frame frame;
|
||||||
|
{
|
||||||
|
struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name);
|
||||||
|
u32 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 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
|
||||||
|
);
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
struct v2 pivot_pos;
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pivot */
|
||||||
|
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 */
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Fade in placeholder if texture isn't loaded */
|
||||||
|
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 */
|
/* Draw texture */
|
||||||
struct sprite_tag sprite = ent->sprite;
|
struct sprite_tag sprite = ent->sprite;
|
||||||
|
|
||||||
@ -794,6 +891,7 @@ INTERNAL void user_update(void)
|
|||||||
if (sheet->loaded && texture->loaded) {
|
if (sheet->loaded && texture->loaded) {
|
||||||
draw_sprite_quad(G.world_canvas, params, quad);
|
draw_sprite_quad(G.world_canvas, params, quad);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Debug draw info */
|
/* Debug draw info */
|
||||||
@ -1053,7 +1151,7 @@ INTERNAL void user_update(void)
|
|||||||
++canvases_count;
|
++canvases_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer_canvas_present(canvases, canvases_count, G.screen_size, RECT_FROM_V2(G.viewport_screen_offset, G.viewport_size), vsync);
|
renderer_canvas_present(canvases, canvases_count, G.screen_size, RECT_FROM_V2(G.viewport_screen_offset, G.viewport_size), vsync, sprite_frame_scope);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* End frame cache scopes
|
* End frame cache scopes
|
||||||
|
|||||||
@ -84,7 +84,7 @@ INLINE void fixed_dict_set(struct arena *arena, struct fixed_dict *dict, struct
|
|||||||
|
|
||||||
struct fixed_dict_entry *entry = bucket->entry_head;
|
struct fixed_dict_entry *entry = bucket->entry_head;
|
||||||
while (entry) {
|
while (entry) {
|
||||||
if (hash == entry->hash && string_eq(key, entry->key)) {
|
if (hash == entry->hash) {
|
||||||
/* Existing match found, replace its contents */
|
/* Existing match found, replace its contents */
|
||||||
entry->key = key;
|
entry->key = key;
|
||||||
entry->value = value;
|
entry->value = value;
|
||||||
@ -112,7 +112,7 @@ INLINE void *fixed_dict_get(const struct fixed_dict *dict, struct string key)
|
|||||||
struct fixed_dict_bucket *bucket = &dict->buckets[index];
|
struct fixed_dict_bucket *bucket = &dict->buckets[index];
|
||||||
|
|
||||||
for (struct fixed_dict_entry *entry = bucket->entry_head; entry; entry = entry->next) {
|
for (struct fixed_dict_entry *entry = bucket->entry_head; entry; entry = entry->next) {
|
||||||
if (hash == entry->hash && string_eq(key, entry->key)) {
|
if (hash == entry->hash) {
|
||||||
/* Match found */
|
/* Match found */
|
||||||
return entry->value;
|
return entry->value;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user