From fb2e026665d5e261a47e1a0848e407a9caff72d6 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 2 Mar 2024 02:09:01 -0600 Subject: [PATCH] entity & sprite translation --- CMakeLists.txt | 2 +- res/graphics/timmy.ase | 2 +- src/common.h | 37 +++++++-- src/draw.c | 106 ++++++++++++++++++++++++- src/draw.h | 9 ++- src/entity.h | 67 +++++++++++----- src/game.c | 85 +++++++++++++------- src/math.h | 154 ++++++++++++++++++++++++++---------- src/renderer_d3d11.c | 2 +- src/resource.c | 2 + src/string.c | 2 + src/sys_win32.c | 1 + src/user.c | 174 ++++++++++++++++++++++++++++++++--------- 13 files changed, 502 insertions(+), 141 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1af9a979..a333b758 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,7 @@ add_executable(powerplay_exe ${sources}) set_target_properties( powerplay_exe PROPERTIES C_STANDARD 99 - OUTPUT_NAME "${PROJECT_NAME}.exe" + OUTPUT_NAME "PowerPlay.exe" ) # Add precompiled header diff --git a/res/graphics/timmy.ase b/res/graphics/timmy.ase index 2eefedb1..0afb493e 100644 --- a/res/graphics/timmy.ase +++ b/res/graphics/timmy.ase @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e129a1f8bbc289db1cf1e9fe2f78ccff40cc01f50411b495cdef2dded3be74e9 +oid sha256:2cc35b342e0b9c29d64b53620ad18c019ddd01f0c97bbbb87fe0e0cacf8cb5cf size 5313 diff --git a/src/common.h b/src/common.h index 20522ea5..aba7ddd9 100644 --- a/src/common.h +++ b/src/common.h @@ -380,16 +380,31 @@ struct v2 { f32 x, y; }; +struct v2_array { + struct v2 *points; + u64 count; +}; + #define V3(x, y, z) ((struct v3) { (x), (y), (z) }) struct v3 { f32 x, y, z; }; +struct v3_array { + struct v3 *points; + u64 count; +}; + #define V4(x, y, z, w) ((struct v4) { (x), (y), (z), (w) }) struct v4 { f32 x, y, z, w; }; +struct v4_array { + struct v4 *points; + u64 count; +}; + struct mat3x3 { union { f32 e[3][3]; @@ -409,17 +424,27 @@ struct rect { f32 x, y, width, height; }; - /* Values expected to be normalized 0.0 -> 1.0 */ #define CLIP_ALL ((struct clip_rect) { { 0.0f, 0.0f }, { 1.0f, 1.0f } }) struct clip_rect { struct v2 p1, p2; }; +#define QUAD_UNIT_SQUARE (struct quad) { V2(0, 0), V2(0, 1), V2(1, 1), V2(1, 0) } +#define QUAD_UNIT_SQUARE_CENTERED (struct quad) { V2(-0.5f, -0.5f), V2(0.5f, -0.5f), V2(0.5f, 0.5f), V2(-0.5f, 0.5f) } + struct quad { struct v2 p1, p2, p3, p4; }; +/* (T)ranslation, (R)otation, (S)cale */ +#define TRS(...) ((struct trs) { .t = V2(0,0), .s = V2(1, 1), .r = 0, __VA_ARGS__ }) +struct trs { + struct v2 t; + struct v2 s; + f32 r; +}; + /* ========================== * * Common utilities * ========================== */ @@ -465,13 +490,13 @@ INLINE u64 cstr_len(char *cstr) /* Clang/GCC cleanup macros */ #if COMPILER_CLANG || COMPILER_GCC # if !TRACY_NO_CALLSTACK -# define __prof static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, __func__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx ctx = __attribute((cleanup(__prof_zone_cleanup_func))) ___tracy_emit_zone_begin_callstack( &CAT(__tracy_source_location,__LINE__), TRACY_CALLSTACK, true ); -# define __proscope(name) static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, name, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx ctx = __attribute((cleanup(__prof_zone_cleanup_func))) ___tracy_emit_zone_begin_callstack( &CAT(__tracy_source_location,__LINE__), TRACY_CALLSTACK, true ); +# define __prof static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, __func__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx __tracy_ctx = __attribute((cleanup(__prof_zone_cleanup_func))) ___tracy_emit_zone_begin_callstack( &CAT(__tracy_source_location,__LINE__), TRACY_CALLSTACK, true ); +# define __proscope(name) static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, name, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx __tracy_ctx = __attribute((cleanup(__prof_zone_cleanup_func))) ___tracy_emit_zone_begin_callstack( &CAT(__tracy_source_location,__LINE__), TRACY_CALLSTACK, true ); # endif -# define __prof static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, __func__, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx ctx = ___tracy_emit_zone_begin( &CAT(__tracy_source_location,__LINE__), true ); -# define __profscope(name) static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, #name, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx ctx = ___tracy_emit_zone_begin( &CAT(__tracy_source_location,__LINE__), true ); +# define __prof static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, __func__, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx __tracy_ctx = ___tracy_emit_zone_begin( &CAT(__tracy_source_location,__LINE__), true ); +# define __profscope(name) static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, #name, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx __tracy_ctx = ___tracy_emit_zone_begin( &CAT(__tracy_source_location,__LINE__), true ); #endif -INLINE void __prof_zone_cleanup_func(TracyCZoneCtx *ctx) { TracyCZoneEnd(*ctx); } +INLINE void __prof_zone_cleanup_func(TracyCZoneCtx *__tracy_ctx) { TracyCZoneEnd(*__tracy_ctx); } #define __profalloc(ptr, size) TracyCAlloc(ptr, size) #define __proffree(ptr) TracyCFree(ptr) diff --git a/src/draw.c b/src/draw.c index 37b544b6..ccf16eb2 100644 --- a/src/draw.c +++ b/src/draw.c @@ -90,9 +90,69 @@ void draw_texture_rect(struct renderer_canvas *canvas, struct draw_texture_param } /* ========================== * - * Shapes + * Solid fill shapes * ========================== */ +void draw_solid_poly(struct renderer_canvas *canvas, struct v2_array array, u32 color) +{ + if (array.count < 3) { + return; + } + + renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); + + u32 num_tris = array.count - 2; + u32 num_indices = num_tris * 3; + + struct texture_shader_vertex *vertices = NULL; + vidx *indices = NULL; + size_t idx_offset = renderer_canvas_push_vertices(canvas, (u8 **)&vertices, &indices, array.count, num_indices); + + /* Fill vertices */ + for (u32 i = 0; i < array.count; ++i) { + vertices[i] = (struct texture_shader_vertex) { + .pos = array.points[i], + .color = color + }; + } + + /* Fill indices */ + for (u32 i = 0; i < num_tris; ++i) { + u32 tri_offset = i * 3; + indices[tri_offset + 0] = idx_offset + 0; + indices[tri_offset + 1] = idx_offset + (i + 1); + indices[tri_offset + 2] = idx_offset + (i + 2); + } +} + +void draw_solid_circle(struct renderer_canvas *canvas, struct v2 pos, f32 radius, 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(canvas, a, color); + + scratch_end(scratch); +} + +void draw_solid_quad(struct renderer_canvas *canvas, struct quad quad, u32 color) +{ + renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); + draw_texture_quad_internal(canvas, CLIP_ALL, color, quad); +} + void draw_solid_rect(struct renderer_canvas *canvas, struct rect rect, u32 color) { renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); @@ -100,6 +160,17 @@ void draw_solid_rect(struct renderer_canvas *canvas, struct rect rect, u32 color draw_texture_quad_internal(canvas, CLIP_ALL, color, quad); } +/* ========================== * + * Solid line shapes + * ========================== */ + +void draw_solid_ray(struct renderer_canvas *canvas, struct v2 pos, struct v2 rel, f32 thickness, u32 color) +{ + renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); + struct quad quad = quad_from_ray(pos, rel, thickness); + draw_texture_quad_internal(canvas, CLIP_ALL, color, quad); +} + void draw_solid_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, f32 thickness, u32 color) { renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); @@ -107,11 +178,38 @@ void draw_solid_line(struct renderer_canvas *canvas, struct v2 start, struct v2 draw_texture_quad_internal(canvas, CLIP_ALL, color, quad); } -void draw_solid_ray(struct renderer_canvas *canvas, struct v2 pos, struct v2 rel, f32 thickness, u32 color) +void draw_solid_poly_line(struct renderer_canvas *canvas, struct v2_array array, b32 loop, f32 thickness, u32 color) { + if (array.count < 2) { + return; + } + renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); - struct quad quad = quad_from_ray(pos, rel, thickness); - draw_texture_quad_internal(canvas, CLIP_ALL, color, quad); + for (u64 i = 1; i < array.count; ++i) { + struct v2 p1 = array.points[i - 1]; + struct v2 p2 = array.points[i]; + struct quad q = quad_from_line(p1, p2, thickness); + draw_texture_quad_internal(canvas, CLIP_ALL, color, q); + } + if (loop && array.count > 2) { + struct v2 p1 = array.points[array.count - 1]; + struct v2 p2 = array.points[0]; + struct quad q = quad_from_line(p1, p2, thickness); + draw_texture_quad_internal(canvas, CLIP_ALL, color, q); + } +} + +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 }; + struct v2_array a = { .points = points, .count = ARRAY_COUNT(points) }; + draw_solid_poly_line(canvas, a, true, thickness, color); +} + +void draw_solid_rect_line(struct renderer_canvas *canvas, struct rect rect, f32 thickness, u32 color) +{ + struct quad q = quad_from_rect(rect); + draw_solid_quad_line(canvas, q, thickness, color); } /* ========================== * diff --git a/src/draw.h b/src/draw.h index 952ea704..54e0c126 100644 --- a/src/draw.h +++ b/src/draw.h @@ -20,9 +20,16 @@ void draw_startup(void); void draw_texture_quad(struct renderer_canvas *canvas, struct draw_texture_params params, struct quad quad); void draw_texture_rect(struct renderer_canvas *canvas, struct draw_texture_params params, struct rect rect); +void draw_solid_poly(struct renderer_canvas *canvas, struct v2_array array, u32 color); +void draw_solid_circle(struct renderer_canvas *canvas, struct v2 pos, f32 radius, u32 color, u32 detail); +void draw_solid_quad(struct renderer_canvas *canvas, struct quad quad, u32 color); 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_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, 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_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_text(struct renderer_canvas *canvas, struct font *font, struct v2 pos, struct string str); void draw_text_ex(struct renderer_canvas *canvas, struct font *font, struct v2 pos, f32 scale, struct string str); diff --git a/src/entity.h b/src/entity.h index 5e8a8925..475ca144 100644 --- a/src/entity.h +++ b/src/entity.h @@ -8,14 +8,23 @@ * Entity * ========================== */ +struct entity_handle { + u64 idx; + u64 gen; +}; + enum entity_prop { ENTITY_PROP_NONE, + + ENTITY_PROP_SPRITE_ANIMATED, + ENTITY_PROP_PLAYER_CONTROLLED, + ENTITY_PROP_CAMERA, + + /* Test props */ + ENTITY_PROP_TEST, ENTITY_PROP_TEST_FOLLOW_MOUSE, ENTITY_PROP_TEST_SOUND_EMITTER, - ENTITY_PROP_TEXTURED, - ENTITY_PROP_ANIMATED, - ENTITY_PROP_PLAYER_CONTROLLED, ENTITY_PROP_COUNT }; @@ -24,36 +33,52 @@ struct entity { b32 active; u64 gen; u64 continuity_gen; + u64 props[(ENTITY_PROP_COUNT + 63) / 64]; struct entity *next_free; - struct v2 pos; + /* TODO: Entity tree */ - /* ENTITY_PROP_TEST */ - struct v2 start_pos; + /* ====================================================================== */ + /* Translation, rotation, scale in relation to parent entity */ - /* ENTITY_PROP_TEST_SOUND_EMITTER */ - struct string sound_name; - struct mixer_desc sound_desc; - struct mixer_track_handle sound_handle; + struct trs rel_trs; - /* ENTITY_PROP_TEXTURED */ - struct string texture_name; - struct v2 draw_size; + /* ====================================================================== */ + /* Sprite */ - /* ENTITY_PROP_ANIMATED */ - /* Use entity_start_animation */ + struct string sprite_name; + struct trs sprite_trs; + struct v2 sprite_pivot; /* Normalized. <0, 0> is center, <1, 1> is bottom right corner, etc. */ + + /* ====================================================================== */ + /* Animation */ + + /* ENTITY_PROP_SPRITE_ANIMATED */ struct string animation_name; u64 animation_flags; f64 animation_time_in_frame; u64 animation_start_gen; u64 animation_gen; - struct sheet_frame frame; -}; + struct sheet_frame animation_frame; + + /* ====================================================================== */ + /* ENTITY_PROP_TEST */ + + b32 test_initialized; + struct trs test_trs; + + /* ====================================================================== */ + /* ENTITY_PROP_TEST_SOUND_EMITTER */ + + struct string sound_name; + struct mixer_desc sound_desc; + struct mixer_track_handle sound_handle; + + /* ====================================================================== */ + /* ENTITY_PROP_CAMERA */ + /* TODO */ -struct entity_handle { - u64 idx; - u64 gen; }; /* ========================== * @@ -91,7 +116,7 @@ INLINE b32 entity_has_prop(struct entity *entity, enum entity_prop prop) INLINE void entity_start_animation(struct entity *entity, struct string animation_name, u64 flags) { - entity_enable_prop(entity, ENTITY_PROP_ANIMATED); + entity_enable_prop(entity, ENTITY_PROP_SPRITE_ANIMATED); entity->animation_name = animation_name; entity->animation_flags = flags; entity->animation_time_in_frame = 0; diff --git a/src/game.c b/src/game.c index 496552f5..4220ee5a 100644 --- a/src/game.c +++ b/src/game.c @@ -141,17 +141,27 @@ INTERNAL void game_update(void) /* Player ent */ { - struct entity *e = entity_alloc(); - e->active = true; - e->pos = V2(0, 0.25); - entity_enable_prop(e, ENTITY_PROP_TEXTURED); + struct string sprite_name = STR("res/graphics/timmy.ase"); - e->texture_name = STR("res/graphics/timmy.ase"); - - struct sheet *sheet = sheet_load(e->texture_name); + struct sheet *sheet = sheet_load(sprite_name); f32 meters_width = sheet->image_size.x / PIXELS_PER_UNIT; f32 meters_height = sheet->image_size.y / PIXELS_PER_UNIT; - e->draw_size = V2(meters_width, meters_height); + + struct v2 pos = V2(0, 0); + //f32 rot = PI / 2; + f32 rot = 0; + struct v2 size = V2(meters_width, meters_height); + + struct entity *e = entity_alloc(); + e->active = true; + e->rel_trs = TRS(.t = pos, .r = rot, .s = V2(2, 2)); + + e->sprite_name = sprite_name; + e->sprite_trs = TRS(.t = V2(1, 0), .r = 0, .s = size); + e->sprite_pivot = V2(0, -0.5); + + entity_enable_prop(e, ENTITY_PROP_TEST); + entity_enable_prop(e, ENTITY_PROP_TEST_FOLLOW_MOUSE); } } @@ -172,31 +182,44 @@ INTERNAL void game_update(void) }; } + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ + /* ========================== * * Update entities * ========================== */ - for (u64 i = 0; i < ARRAY_COUNT(L.tick.entities); ++i) { - struct entity *ent = &L.tick.entities[i]; + for (u64 entity_index = 0; entity_index < ARRAY_COUNT(L.tick.entities); ++entity_index) { + struct entity *ent = &L.tick.entities[entity_index]; if (!ent->active) continue; /* ========================== * - * Animation + * Initialize * ========================== */ - if (entity_has_prop(ent, ENTITY_PROP_ANIMATED)) { - struct sheet *sheet = sheet_load(ent->texture_name); + /* ENTITY_PROP_TEST */ + if (entity_has_prop(ent, ENTITY_PROP_TEST) && !ent->test_initialized) { + ent->test_initialized = true; + ent->test_trs = ent->rel_trs; + } + + /* ========================== * + * Update animation + * ========================== */ + + if (entity_has_prop(ent, ENTITY_PROP_SPRITE_ANIMATED)) { + struct sheet *sheet = sheet_load(ent->sprite_name); struct sheet_tag tag = sheet_get_tag(sheet, ent->animation_name); if (ent->animation_start_gen == ent->animation_gen) { ent->animation_time_in_frame += L.dt; } else { - ent->frame = sheet_get_frame(sheet, tag.start); + ent->animation_frame = sheet_get_frame(sheet, tag.start); ent->animation_start_gen = ent->animation_gen; } - while (ent->frame.duration != 0 && ent->animation_time_in_frame > ent->frame.duration) { - u64 new_frame_index = ent->frame.index + 1; + while (ent->animation_frame.duration != 0 && ent->animation_time_in_frame > ent->animation_frame.duration) { + u64 new_frame_index = ent->animation_frame.index + 1; if (new_frame_index > tag.end) { if (ent->animation_flags & ANIMATION_FLAG_LOOPING) { /* Restart animation */ @@ -207,28 +230,33 @@ INTERNAL void game_update(void) goto break_animation; } } - ent->frame = sheet_get_frame(sheet, new_frame_index); - ent->animation_time_in_frame -= ent->frame.duration; + ent->animation_frame = sheet_get_frame(sheet, new_frame_index); + ent->animation_time_in_frame -= ent->animation_frame.duration; } } break_animation: /* ========================== * - * Update entity positions + * Update position * ========================== */ + /* ENTITY_PROP_TEST_FOLLOW_MOUSE */ if (entity_has_prop(ent, ENTITY_PROP_TEST_FOLLOW_MOUSE)) { - //ent->pos = v2_sub(L.tick.focus, v2_mul(ent->draw_size, 0.5f)); - ent->pos = L.tick.player_focus; - ent->start_pos = ent->pos; + ent->rel_trs.t = L.tick.player_focus; + ent->test_trs.t = L.tick.player_focus; } - /* Update pos */ + /* ENTITY_PROP_TEST */ if (entity_has_prop(ent, ENTITY_PROP_TEST)) { f32 t = ((f32)L.time); - f32 x = (math_cos(t * 2.f) / 10.f); - f32 y = (math_sin(t * 2.f) / 10.f); - ent->pos = v2_add(ent->start_pos, V2(x, y)); + f32 r = t * 0.5f; + + ent->sprite_trs.r = ent->test_trs.r + (r * 3.0f); + + ent->rel_trs.r = ent->test_trs.r + (r * 0.25f); + + //f32 s = 1 + (math_abs_f32(math_sin(t * 5)) * 0.5f); + //ent->rel_trs.s = v2_mul(ent->test_trs.s, s); } /* ========================== * @@ -238,7 +266,7 @@ break_animation: if (entity_has_prop(ent, ENTITY_PROP_TEST_SOUND_EMITTER)) { struct mixer_desc desc = ent->sound_desc; desc.speed = L.timescale; - desc.pos = ent->pos; + desc.pos = ent->rel_trs.t; struct sound *sound = sound_load_async(ent->sound_name, 0); b32 played = ent->sound_handle.gen != 0; if (sound) { @@ -251,6 +279,9 @@ break_animation: } } + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ + /* Publish tick */ publish_game_tick(); __profframe("Game"); diff --git a/src/math.h b/src/math.h index 4751c02a..a7223db3 100644 --- a/src/math.h +++ b/src/math.h @@ -238,6 +238,11 @@ INLINE struct v2 v2_mul_v2(struct v2 a, struct v2 b) return V2(a.x * b.x, a.y * b.y); } +INLINE struct v2 v2_neg(struct v2 a) +{ + return V2(-a.x, -a.y); +} + INLINE struct v2 v2_add(struct v2 a, struct v2 b) { return V2(a.x + b.x, a.y + b.y); @@ -306,6 +311,42 @@ INLINE struct v2 v2_lerp(struct v2 val0, struct v2 val1, f32 t) * Mat3x3 * ========================== */ +INLINE struct mat3x3 mat3x3_ident(void) +{ + return (struct mat3x3) { + .e = { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 } + } + }; +} + +INLINE struct mat3x3 mat3x3_mul(struct mat3x3 a, struct mat3x3 b) +{ + f32 a00 = a.e[0][0], a01 = a.e[0][1], a02 = a.e[0][2], + a10 = a.e[1][0], a11 = a.e[1][1], a12 = a.e[1][2], + a20 = a.e[2][0], a21 = a.e[2][1], a22 = a.e[2][2], + b00 = b.e[0][0], b01 = b.e[0][1], b02 = b.e[0][2], + b10 = b.e[1][0], b11 = b.e[1][1], b12 = b.e[1][2], + b20 = b.e[2][0], b21 = b.e[2][1], b22 = b.e[2][2]; + + struct mat3x3 res; + + res.e[0][0] = a00 * b00 + a10 * b01 + a20 * b02; + res.e[0][1] = a01 * b00 + a11 * b01 + a21 * b02; + res.e[0][2] = a02 * b00 + a12 * b01 + a22 * b02; + res.e[1][0] = a00 * b10 + a10 * b11 + a20 * b12; + res.e[1][1] = a01 * b10 + a11 * b11 + a21 * b12; + res.e[1][2] = a02 * b10 + a12 * b11 + a22 * b12; + res.e[2][0] = a00 * b20 + a10 * b21 + a20 * b22; + res.e[2][1] = a01 * b20 + a11 * b21 + a21 * b22; + res.e[2][2] = a02 * b20 + a12 * b21 + a22 * b22; + + return res; + +} + INLINE struct mat3x3 mat3x3_from_translate(struct v2 v) { return (struct mat3x3) { @@ -347,14 +388,6 @@ INLINE struct mat3x3 mat3x3_rotate(struct mat3x3 m, f32 angle) return res; } -INLINE struct mat3x3 mat3x3_rotate_pivot(struct mat3x3 m, f32 angle, struct v2 pivot) -{ - m = mat3x3_translate(m, V2(pivot.x, pivot.y)); /* Start pivot */ - m = mat3x3_rotate(m, angle); - m = mat3x3_translate(m, V2(-pivot.x, -pivot.y)); /* End pivot */ - return m; -} - INLINE struct mat3x3 mat3x3_scale(struct mat3x3 m, struct v3 v) { m.e[0][0] *= v.x; @@ -369,46 +402,37 @@ INLINE struct mat3x3 mat3x3_scale(struct mat3x3 m, struct v3 v) return m; } -INLINE struct mat3x3 mat3x3_scale_pivot(struct mat3x3 m, struct v3 v, struct v2 pivot) +INLINE struct mat3x3 mat3x3_from_trs(struct trs trs) { - m = mat3x3_translate(m, V2(pivot.x, pivot.y)); /* Start pivot */ - m = mat3x3_scale(m, v); - m = mat3x3_translate(m, V2(-pivot.x, -pivot.y)); /* End pivot */ + struct mat3x3 m = mat3x3_from_translate(trs.t); + m = mat3x3_rotate(m, trs.r); + m = mat3x3_scale(m, V3(trs.s.x, trs.s.y, 1)); return m; } -INLINE struct mat3x3 mat3x3_from_trs(struct v2 pos, f32 rot, struct v2 scale) +INLINE struct mat3x3 mat3x3_trs(struct mat3x3 m, struct trs trs) { - struct mat3x3 m = mat3x3_from_translate(pos); - m = mat3x3_rotate(m, rot); - m = mat3x3_scale(m, V3(scale.x, scale.y, 1)); + m = mat3x3_translate(m, trs.t); + m = mat3x3_rotate(m, trs.r); + m = mat3x3_scale(m, V3(trs.s.x, trs.s.y, 1)); return m; } -INLINE struct mat3x3 mat3x3_from_trs_pivot(struct v2 pos, f32 rot, struct v2 scale, struct v2 pivot) +INLINE struct mat3x3 mat3x3_trs_pivot_r(struct mat3x3 m, struct trs trs, struct v2 pivot) { - struct mat3x3 m = mat3x3_from_translate(pos); - m = mat3x3_translate(m, V2(pivot.x, pivot.y)); /* Start pivot */ - m = mat3x3_rotate(m, rot); - m = mat3x3_scale(m, V3(scale.x, scale.y, 1)); - m = mat3x3_translate(m, V2(-pivot.x, -pivot.y)); /* End pivot */ + m = mat3x3_translate(m, trs.t); + m = mat3x3_rotate(m, trs.r); + m = mat3x3_translate(m, v2_neg(pivot)); + m = mat3x3_scale(m, V3(trs.s.x, trs.s.y, 1)); return m; } -INLINE struct mat3x3 mat3x3_trs(struct mat3x3 m, struct v2 pos, f32 rot, struct v2 scale) +INLINE struct mat3x3 mat3x3_trs_pivot_rs(struct mat3x3 m, struct trs trs, struct v2 pivot) { - m = mat3x3_translate(m, pos); - m = mat3x3_rotate(m, rot); - m = mat3x3_scale(m, V3(scale.x, scale.y, 1)); - return m; -} - -INLINE struct mat3x3 mat3x3_trs_pivot(struct mat3x3 m, struct v2 pos, f32 rot, struct v2 scale , struct v2 pivot) -{ - m = mat3x3_translate(m, V2(pos.x + pivot.x, pos.y + pivot.y)); /* Start pivot */ - m = mat3x3_rotate(m, rot); - m = mat3x3_scale(m, V3(scale.x, scale.y, 1)); - m = mat3x3_translate(m, V2(-pivot.x, -pivot.y)); /* End pivot */ + m = mat3x3_translate(m, trs.t); + m = mat3x3_rotate(m, trs.r); + m = mat3x3_scale(m, V3(trs.s.x, trs.s.y, 1)); + m = mat3x3_translate(m, v2_neg(pivot)); return m; } @@ -421,6 +445,15 @@ INLINE struct v3 mat3x3_mul_v3(struct mat3x3 m, struct v3 v) return res; } +/* Equivalent to multiplying by V3(v.x, v.y, 1.0) */ +INLINE struct v2 mat3x3_mul_v2(struct mat3x3 m, struct v2 v) +{ + struct v2 res; + res.x = m.e[0][0] * v.x + m.e[1][0] * v.y + m.e[2][0]; + res.y = m.e[0][1] * v.x + m.e[1][1] * v.y + m.e[2][1]; + return res; +} + INLINE struct mat3x3 mat3x3_inverse(struct mat3x3 m) { f32 a = m.e[0][0], b = m.e[0][1], c = m.e[0][2], @@ -444,26 +477,31 @@ INLINE struct mat3x3 mat3x3_inverse(struct mat3x3 m) return res; } -INLINE struct v2 mat3x3_right(struct mat3x3 m) +INLINE struct v2 mat3x3_get_right(struct mat3x3 m) { return V2(m.e[0][0], m.e[0][1]); } -INLINE struct v2 mat3x3_left(struct mat3x3 m) +INLINE struct v2 mat3x3_get_left(struct mat3x3 m) { return V2(-m.e[0][0], -m.e[0][1]); } -INLINE struct v2 mat3x3_up(struct mat3x3 m) +INLINE struct v2 mat3x3_get_up(struct mat3x3 m) { return V2(-m.e[1][0], -m.e[1][1]); } -INLINE struct v2 mat3x3_down(struct mat3x3 m) +INLINE struct v2 mat3x3_get_down(struct mat3x3 m) { return V2(m.e[1][0], m.e[1][1]); } +INLINE struct v2 mat3x3_get_pos(struct mat3x3 m) +{ + return V2(m.e[2][0], m.e[2][1]); +} + /* ========================== * * Mat4x4 * ========================== */ @@ -522,6 +560,19 @@ INLINE struct mat4x4 mat4x4_mul(struct mat4x4 m1, struct mat4x4 m2) return res; } +/* ========================== * + * Trs + * ========================== */ + +INLINE struct trs trs_lerp(struct trs a, struct trs b, f32 t) +{ + struct trs res; + res.t = v2_lerp(a.t, b.t, t); + res.r = math_lerp_f32(a.r, b.r, t); + res.s = v2_lerp(a.s, b.s, t); + return res; +} + /* ========================== * * Quad * ========================== */ @@ -555,10 +606,33 @@ INLINE struct quad quad_from_line(struct v2 start, struct v2 end, f32 thickness) }; } -INLINE struct quad quad_from_ray(struct v2 pos, struct v2 rel, f32 thickness) +INLINE struct quad quad_from_ray(struct v2 pos, struct v2 rel, f32 thickness) { struct v2 end = v2_add(pos, rel); return quad_from_line(pos, end, thickness); } +INLINE struct quad quad_scale(struct quad q, f32 s) +{ + q.p1 = v2_mul(q.p1, s); + q.p2 = v2_mul(q.p2, s); + q.p3 = v2_mul(q.p3, s); + q.p4 = v2_mul(q.p4, s); + return q; +} + +INLINE struct quad quad_mul_mat3x3(struct quad quad, struct mat3x3 m) +{ + struct v3 p1_v3 = mat3x3_mul_v3(m, V3(quad.p1.x, quad.p1.y, 1)); + struct v3 p2_v3 = mat3x3_mul_v3(m, V3(quad.p2.x, quad.p2.y, 1)); + struct v3 p3_v3 = mat3x3_mul_v3(m, V3(quad.p3.x, quad.p3.y, 1)); + struct v3 p4_v3 = mat3x3_mul_v3(m, V3(quad.p4.x, quad.p4.y, 1)); + return (struct quad) { + V2(p1_v3.x, p1_v3.y), + V2(p2_v3.x, p2_v3.y), + V2(p3_v3.x, p3_v3.y), + V2(p4_v3.x, p4_v3.y) + }; +} + #endif diff --git a/src/renderer_d3d11.c b/src/renderer_d3d11.c index 793f657f..c5ae0d5b 100644 --- a/src/renderer_d3d11.c +++ b/src/renderer_d3d11.c @@ -632,7 +632,7 @@ struct renderer_canvas *renderer_canvas_alloc(void) MEMZERO_STRUCT(canvas); canvas->cpu_cmd_store.arena = arena_alloc(GIGABYTE(8)); canvas->gpu_cmd_store.arena = arena_alloc(GIGABYTE(8)); - canvas->view = mat3x3_from_trs(V2(0, 0), 0, V2(1, 1)); + canvas->view = mat3x3_from_trs(TRS()); canvas->valid = true; /* Initialize buffers, skipping index 0 (SHADER_NONE) */ diff --git a/src/resource.c b/src/resource.c index b3129bd5..1649174e 100644 --- a/src/resource.c +++ b/src/resource.c @@ -35,6 +35,7 @@ void resource_startup(void) b32 resource_exists(struct string path) { + __prof; #if RESOURCES_EMBEDDED struct tar_entry *entry = tar_get(&L.archive, path); return entry && !entry->is_dir; @@ -45,6 +46,7 @@ b32 resource_exists(struct string path) struct resource resource_open(struct string path) { + __prof; #if RESOURCES_EMBEDDED struct tar_entry *entry = tar_get(&L.archive, path); return (struct resource) { diff --git a/src/string.c b/src/string.c index 7dfc4100..33bd59ab 100644 --- a/src/string.c +++ b/src/string.c @@ -439,6 +439,8 @@ wchar_t *string_to_wstr(struct arena *arena, struct string str) */ struct string string_formatv(struct arena *arena, struct string fmt, va_list args) { + __prof; + u64 final_len = 0; u8 *final_text = arena_dry_push(arena, u8); diff --git a/src/sys_win32.c b/src/sys_win32.c index ef09a88b..61f86e94 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -216,6 +216,7 @@ struct string sys_get_write_path(struct arena *arena) b32 sys_is_file(struct string path) { + __prof; struct temp_arena scratch = scratch_begin_no_conflict(); const char *path_cstr = string_to_cstr(scratch.arena, path); DWORD attributes = GetFileAttributes(path_cstr); diff --git a/src/user.c b/src/user.c index ccdceaaf..070f0fac 100644 --- a/src/user.c +++ b/src/user.c @@ -182,7 +182,16 @@ INTERNAL void push_game_cmds(struct game_cmd_list *list) INTERNAL struct mat3x3 view_get_xform(struct view view) { f32 scale = view.zoom * view.px_per_unit; - struct mat3x3 res = mat3x3_from_trs_pivot(v2_sub(L.screen_center, view.center), view.rot, V2(scale, scale), view.center); + struct trs trs = TRS( + .t = v2_sub(L.screen_center, view.center), + .r = view.rot, + .s = V2(scale, scale) + ); + + struct v2 pivot = view.center; + struct mat3x3 res = mat3x3_from_translate(pivot); + res = mat3x3_trs_pivot_rs(res, trs, pivot); + return res; } @@ -198,6 +207,24 @@ INTERNAL struct v2 view_mouse_pos(struct view view) return view_inverse_point(view, L.screen_mouse); } +/* TODO: remove this (testing) */ +INTERNAL void debug_draw_xform(struct mat3x3 mtx) +{ + f32 thickness = 2.f / PIXELS_PER_UNIT / L.world_view.zoom; + u32 color = RGBA_F(0, 1, 1, 0.3); + u32 color_x = RGBA_F(1, 0, 0, 0.3); + u32 color_y = RGBA_F(0, 1, 0, 0.3); + + struct v2 pos = mat3x3_get_pos(mtx); + struct v2 x_ray = mat3x3_get_right(mtx); + struct v2 y_ray = mat3x3_get_down(mtx); + struct quad quad = quad_mul_mat3x3(quad_scale(QUAD_UNIT_SQUARE, 0.075), mtx); + + draw_solid_ray(L.world_canvas, pos, x_ray, thickness, color_x); + draw_solid_ray(L.world_canvas, pos, y_ray, thickness, color_y); + draw_solid_quad(L.world_canvas, quad, color); +} + /* ========================== * * Update * ========================== */ @@ -228,9 +255,13 @@ INTERNAL void user_update(void) L.screen_mouse = sys_window_get_mouse_pos(L.window); struct sys_event_array events = pull_sys_events(scratch.arena); + /* ========================== * + * Read sys events + * ========================== */ + i32 zooms_to_apply = 0; - for (u64 i = 0; i < events.count; ++i) { - struct sys_event *event = &events.events[i]; + for (u64 entity_index = 0; entity_index < events.count; ++entity_index) { + struct sys_event *event = &events.events[entity_index]; /* Send event to console. Skip if consumed. */ if (console_process_event(*event)) { @@ -337,7 +368,9 @@ INTERNAL void user_update(void) struct entity *e0 = &t0->entities[i]; struct entity *e1 = &t1->entities[i]; if (e0->gen == e1->gen && e0->continuity_gen == e1->continuity_gen) { - e->pos = v2_lerp(e0->pos, e1->pos, blend); + e->rel_trs = trs_lerp(e0->rel_trs, e1->rel_trs, blend); + e->sprite_trs = trs_lerp(e0->sprite_trs, e1->sprite_trs, blend); + e->sprite_pivot = v2_lerp(e0->sprite_pivot, e1->sprite_pivot, blend); } } #else @@ -384,55 +417,118 @@ INTERNAL void user_update(void) } } + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ /* ========================== * * Iterate entities * ========================== */ - { - __profscope(iterate_ents); - /* Iterate entities */ - for (u64 i = 0; i < tick->entities_count; ++i) { - struct entity *ent = &tick->entities[i]; - if (!ent->active) continue; + /* Iterate entities */ + for (u64 entity_index = 0; entity_index < tick->entities_count; ++entity_index) { + struct entity *ent = &tick->entities[entity_index]; + if (!ent->active) continue; + + /* Debug draw transform */ + { + struct mat3x3 mtx = mat3x3_from_trs(ent->rel_trs); + debug_draw_xform(mtx); + } + + /* Draw sprite */ + if (ent->sprite_name.len > 0) { + struct string tex_name = ent->sprite_name; /* Draw texture */ - if (entity_has_prop(ent, ENTITY_PROP_TEXTURED)) { - if (ent->texture_name.len > 0) { - struct string tex_name = ent->texture_name; - struct v2 pos = ent->pos; - struct v2 size = ent->draw_size; + struct quad quad = QUAD_UNIT_SQUARE_CENTERED; - /* Draw texture */ - struct texture *texture = texture_load_async(tex_name); - if (texture) { - struct rect rect = { pos.x, pos.y, size.x, size.y }; - struct draw_texture_params params; - if (entity_has_prop(ent, ENTITY_PROP_ANIMATED)) { - struct sheet_frame frame = ent->frame; - params = DRAW_TEXTURE_PARAMS(.texture = texture, .clip = frame.clip); - } else { - params = DRAW_TEXTURE_PARAMS(.texture = texture); - } - draw_texture_rect(L.world_canvas, params, rect); - } + /* TODO: Do this calculation in game loop */ + struct mat3x3 mtx; + { + /* Entity trs */ + mtx = mat3x3_from_trs(ent->rel_trs); - /* Draw name */ - if (entity_has_prop(ent, ENTITY_PROP_TEST)) { - struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); - if (disp_font) { - struct string disp_name = { - .len = tex_name.len - 13, - .text = tex_name.text + 13 - }; - draw_text_ex(L.world_canvas, disp_font, V2(pos.x, pos.y - (disp_font->point_size / PIXELS_PER_UNIT) * 2), 1.0f / PIXELS_PER_UNIT, disp_name); - } - } + /* Sprite trs & pivot */ + struct v2 pivot = v2_mul_v2(ent->sprite_pivot, v2_mul(ent->sprite_trs.s, 0.5f)); + mtx = mat3x3_trs_pivot_r(mtx, ent->sprite_trs, pivot); + + quad = quad_mul_mat3x3(quad, mtx); + } + + struct texture *texture = texture_load_async(tex_name); + if (texture) { + + struct draw_texture_params params; + if (entity_has_prop(ent, ENTITY_PROP_SPRITE_ANIMATED)) { + struct sheet_frame frame = ent->animation_frame; + params = DRAW_TEXTURE_PARAMS(.texture = texture, .clip = frame.clip); + } else { + params = DRAW_TEXTURE_PARAMS(.texture = texture); + } + draw_texture_quad(L.world_canvas, params, quad); + } + + /* Debug draw sprite quad */ + { + f32 thickness = 2.f; + u32 color = RGBA_F(1, 1, 0, 0.25); + draw_solid_quad_line(L.world_canvas, quad, (thickness / PIXELS_PER_UNIT / L.world_view.zoom), color); + } + + /* Debug draw sprite transform */ + { + debug_draw_xform(mtx); + } + + /* Debug draw sprite pivot */ + { + u32 color = RGBA_F(1, 0, 0, 1); + + struct mat3x3 mtx_pre_pivot = mat3x3_from_trs(ent->rel_trs); + mtx_pre_pivot = mat3x3_trs(mtx_pre_pivot, ent->sprite_trs); + + struct v2 p = mat3x3_get_pos(mtx_pre_pivot); + draw_solid_circle(L.world_canvas, p, 0.05, color, 20); + + draw_solid_circle(L.world_canvas, mat3x3_get_pos(mtx_pre_pivot), 0.05, color, 20); + } + + /* Debug draw sprite name */ + if (entity_has_prop(ent, ENTITY_PROP_TEST)) { + struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); + + f32 offset = 0.3; + + struct v2 dir = v2_mul(mat3x3_get_up(mtx), 0.5f); + dir = v2_add(dir, v2_mul(v2_norm(dir), offset)); + + struct v2 pos = v2_add(mat3x3_get_pos(mtx), dir); + + + if (disp_font) { + struct string disp_name = { .len = tex_name.len - 13, .text = tex_name.text + 13 }; + + struct string fmt = STR( + "sprite name: %F,\n" + "rel rot: %F,\n" + "sprite rot: %F\n" + ); + struct string text = string_format(scratch.arena, fmt, + FMT_STR(disp_name), + FMT_FLOAT((f64)ent->rel_trs.r), + FMT_FLOAT((f64)ent->sprite_trs.r) + ); + + + draw_text_ex(L.world_canvas, disp_font, pos, 1.0f / PIXELS_PER_UNIT, text); } } } } + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ + /* Update listener using world view */ mixer_set_listener(L.world_view.center, V2(-math_sin(L.world_view.rot), -math_cos(L.world_view.rot)));