typedef & PascalCase for ALL structs and enums
This commit is contained in:
		| @@ -13,9 +13,9 @@ | |||||||
| void game_tick(void) { | void game_tick(void) { | ||||||
|     if (ctx.initialization_needed) { |     if (ctx.initialization_needed) { | ||||||
|         if (!ctx.udata) { |         if (!ctx.udata) { | ||||||
|             ctx.udata = ccalloc(1, sizeof (struct state)); |             ctx.udata = ccalloc(1, sizeof (State)); | ||||||
|  |  | ||||||
|             struct state *state = ctx.udata; |             State *state = ctx.udata; | ||||||
|             state->ctx = &ctx; |             state->ctx = &ctx; | ||||||
|             state->scene = title_scene(state); |             state->scene = title_scene(state); | ||||||
|         } |         } | ||||||
| @@ -48,7 +48,7 @@ void game_tick(void) { | |||||||
|         input_bind_action_scancode(&ctx.input, "mouse_capture_toggle", SDL_SCANCODE_ESCAPE); |         input_bind_action_scancode(&ctx.input, "mouse_capture_toggle", SDL_SCANCODE_ESCAPE); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     struct state *state = ctx.udata; |     State *state = ctx.udata; | ||||||
|  |  | ||||||
|     if (input_is_action_just_pressed(&ctx.input, "debug_toggle")) { |     if (input_is_action_just_pressed(&ctx.input, "debug_toggle")) { | ||||||
|         ctx.debug = !ctx.debug; |         ctx.debug = !ctx.debug; | ||||||
| @@ -67,7 +67,7 @@ void game_tick(void) { | |||||||
|  |  | ||||||
|  |  | ||||||
| void game_end(void) { | void game_end(void) { | ||||||
|     struct state *state = ctx.udata; |     State *state = ctx.udata; | ||||||
|     state->scene->end(state); |     state->scene->end(state); | ||||||
|     free(state); |     free(state); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,14 +10,14 @@ | |||||||
| #include <tgmath.h> | #include <tgmath.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| static void update_timers(struct player *player) { | static void update_timers(Player *player) { | ||||||
|      tick_timer(&player->jump_air_timer); |      tick_timer(&player->jump_air_timer); | ||||||
|      tick_timer(&player->jump_coyote_timer); |      tick_timer(&player->jump_coyote_timer); | ||||||
|      tick_timer(&player->jump_buffer_timer); |      tick_timer(&player->jump_buffer_timer); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void input_move(struct input_state *input, struct player *player) { | static void input_move(InputState *input, Player *player) { | ||||||
|     /* apply horizontal damping when the player stops moving */ |     /* apply horizontal damping when the player stops moving */ | ||||||
|     /* in other words, make it decelerate to a standstill */ |     /* in other words, make it decelerate to a standstill */ | ||||||
|     if (!input_is_action_pressed(input, "player_left") && |     if (!input_is_action_pressed(input, "player_left") && | ||||||
| @@ -44,7 +44,7 @@ static void input_move(struct input_state *input, struct player *player) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void jump(struct player *player) { | static void jump(Player *player) { | ||||||
|     player->jump_coyote_timer = 0; |     player->jump_coyote_timer = 0; | ||||||
|     player->jump_buffer_timer = 0; |     player->jump_buffer_timer = 0; | ||||||
|     player->dy = player->jump_force_initial; |     player->dy = player->jump_force_initial; | ||||||
| @@ -53,7 +53,7 @@ static void jump(struct player *player) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void input_jump(struct input_state *input, struct player *player) { | static void input_jump(InputState *input, Player *player) { | ||||||
|     player->current_gravity_multiplier = player->jump_default_multiplier; |     player->current_gravity_multiplier = player->jump_default_multiplier; | ||||||
|  |  | ||||||
|     if (input_is_action_just_pressed(input, "player_jump")) { |     if (input_is_action_just_pressed(input, "player_jump")) { | ||||||
| @@ -74,7 +74,7 @@ static void input_jump(struct input_state *input, struct player *player) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void update_collider_x(struct player *player) { | static void update_collider_x(Player *player) { | ||||||
|     player->collider_x.w = player->rect.w; |     player->collider_x.w = player->rect.w; | ||||||
|     player->collider_x.h = player->rect.h - 8; |     player->collider_x.h = player->rect.h - 8; | ||||||
|     player->collider_x.x = player->rect.x; |     player->collider_x.x = player->rect.x; | ||||||
| @@ -82,7 +82,7 @@ static void update_collider_x(struct player *player) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void update_collider_y(struct player *player) { | static void update_collider_y(Player *player) { | ||||||
|     player->collider_y.w = player->rect.w; |     player->collider_y.w = player->rect.w; | ||||||
|     player->collider_y.h = player->rect.h; |     player->collider_y.h = player->rect.h; | ||||||
|     player->collider_y.x = player->rect.x + ((player->rect.w - player->collider_y.w) / 2); |     player->collider_y.x = player->rect.x + ((player->rect.w - player->collider_y.w) / 2); | ||||||
| @@ -90,7 +90,7 @@ static void update_collider_y(struct player *player) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void apply_gravity(struct player *player, float gravity) { | static void apply_gravity(Player *player, float gravity) { | ||||||
|     player->dy -= gravity * player->current_gravity_multiplier; |     player->dy -= gravity * player->current_gravity_multiplier; | ||||||
|     player->dy = fmax(player->dy, -player->terminal_velocity); |     player->dy = fmax(player->dy, -player->terminal_velocity); | ||||||
|  |  | ||||||
| @@ -106,7 +106,7 @@ static void apply_gravity(struct player *player, float gravity) { | |||||||
|  |  | ||||||
|  |  | ||||||
| /* returns whether or not a correction was applied */ | /* returns whether or not a correction was applied */ | ||||||
| static bool corner_correct(struct player *player, t_frect collision) { | static bool corner_correct(Player *player, Rect collision) { | ||||||
|     /* |     /* | ||||||
|      * somewhat of a hack here. we only want to do corner correction |      * somewhat of a hack here. we only want to do corner correction | ||||||
|      * if the corner in question really is the corner of a "platform," |      * if the corner in question really is the corner of a "platform," | ||||||
| @@ -145,16 +145,16 @@ static bool corner_correct(struct player *player, t_frect collision) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void calc_collisions_x(struct player *player) { | static void calc_collisions_x(Player *player) { | ||||||
|     t_frect collision; |     Rect collision; | ||||||
|     bool is_colliding = world_find_intersect_frect(player->world, player->collider_x, &collision); |     bool is_colliding = world_find_intersect_frect(player->world, player->collider_x, &collision); | ||||||
|     if (!is_colliding) return; |     if (!is_colliding) return; | ||||||
|  |  | ||||||
|     float player_center_x = player->collider_x.x + (player->collider_x.w / 2); |     float player_center_x = player->collider_x.x + (player->collider_x.w / 2); | ||||||
|     float collision_center_x = collision.x + (collision.w / 2);  |     float collision_center_x = collision.x + (collision.w / 2);  | ||||||
|  |  | ||||||
|     enum collision_direction { COLLISION_LEFT = -1, COLLISION_RIGHT = 1 }; |     typedef enum CollisionDirection { COLLISION_LEFT = -1, COLLISION_RIGHT = 1 } CollisionDirection; | ||||||
|     enum collision_direction dir_x = |     CollisionDirection dir_x = | ||||||
|         player_center_x > collision_center_x ? COLLISION_LEFT : COLLISION_RIGHT; |         player_center_x > collision_center_x ? COLLISION_LEFT : COLLISION_RIGHT; | ||||||
|  |  | ||||||
|     player->rect.x -= collision.w * (float)dir_x; |     player->rect.x -= collision.w * (float)dir_x; | ||||||
| @@ -162,16 +162,16 @@ static void calc_collisions_x(struct player *player) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void calc_collisions_y(struct player *player) { | static void calc_collisions_y(Player *player) { | ||||||
|     t_frect collision; |     Rect collision; | ||||||
|     bool is_colliding = world_find_intersect_frect(player->world, player->collider_y, &collision); |     bool is_colliding = world_find_intersect_frect(player->world, player->collider_y, &collision); | ||||||
|     if (!is_colliding) return; |     if (!is_colliding) return; | ||||||
|  |  | ||||||
|     float player_center_y = player->collider_y.y + (player->collider_y.h / 2); |     float player_center_y = player->collider_y.y + (player->collider_y.h / 2); | ||||||
|     float collision_center_y = collision.y + (collision.h / 2);  |     float collision_center_y = collision.y + (collision.h / 2);  | ||||||
|  |  | ||||||
|     enum collision_direction { COLLISION_ABOVE = -1, COLLISION_BELOW = 1 }; |     typedef enum CollisionDirection { COLLISION_ABOVE = -1, COLLISION_BELOW = 1 } CollisionDirection; | ||||||
|     enum collision_direction dir_y = |     CollisionDirection dir_y = | ||||||
|         player_center_y > collision_center_y ? COLLISION_ABOVE : COLLISION_BELOW; |         player_center_y > collision_center_y ? COLLISION_ABOVE : COLLISION_BELOW; | ||||||
|  |  | ||||||
|     /* before the resolution */ |     /* before the resolution */ | ||||||
| @@ -202,16 +202,16 @@ static void calc_collisions_y(struct player *player) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| struct player *player_create(struct world *world) { | Player *player_create(World *world) { | ||||||
|     struct player *player = cmalloc(sizeof *player); |     Player *player = cmalloc(sizeof *player); | ||||||
|  |  | ||||||
|     *player = (struct player) { |     *player = (Player) { | ||||||
|         .world = world, |         .world = world, | ||||||
|  |  | ||||||
|         .sprite_w = 48, |         .sprite_w = 48, | ||||||
|         .sprite_h = 48, |         .sprite_h = 48, | ||||||
|  |  | ||||||
|         .rect = (t_frect) { |         .rect = (Rect) { | ||||||
|             .x = 92, |             .x = 92, | ||||||
|             .y = 200, |             .y = 200, | ||||||
|             .w = 16, |             .w = 16, | ||||||
| @@ -243,22 +243,22 @@ struct player *player_create(struct world *world) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void drawdef(struct player *player) { | static void drawdef(Player *player) { | ||||||
|     m_sprite("/assets/player/baron-walk.png", |     m_sprite("/assets/player/baron-walk.png", | ||||||
|             (t_frect) { |             (Rect) { | ||||||
|                 .x = player->rect.x + ((player->rect.w - player->sprite_w) / 2), |                 .x = player->rect.x + ((player->rect.w - player->sprite_w) / 2), | ||||||
|                 .y = player->rect.y - 8, |                 .y = player->rect.y - 8, | ||||||
|                 .w = player->sprite_w, |                 .w = player->sprite_w, | ||||||
|                 .h = player->sprite_h, |                 .h = player->sprite_h, | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|     push_circle((t_fvec2) { 256, 128 }, |     push_circle((Vec2) { 256, 128 }, | ||||||
|                 24, |                 24, | ||||||
|                 (t_color) { 255, 0, 0, 255 }); |                 (Color) { 255, 0, 0, 255 }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void drawdef_debug(struct player *player) { | static void drawdef_debug(Player *player) { | ||||||
|     if (!ctx.debug) |     if (!ctx.debug) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
| @@ -269,19 +269,19 @@ static void drawdef_debug(struct player *player) { | |||||||
|     /* }; */ |     /* }; */ | ||||||
|  |  | ||||||
|     push_rectangle(player->collider_x, |     push_rectangle(player->collider_x, | ||||||
|                    (t_color){ 0, 0, 255, 128 }); |                    (Color){ 0, 0, 255, 128 }); | ||||||
|  |  | ||||||
|     push_rectangle(player->collider_y, |     push_rectangle(player->collider_y, | ||||||
|                    (t_color){ 0, 0, 255, 128 }); |                    (Color){ 0, 0, 255, 128 }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void player_destroy(struct player *player) { | void player_destroy(Player *player) { | ||||||
|     free(player); |     free(player); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void player_calc(struct player *player) { | void player_calc(Player *player) { | ||||||
|     update_timers(player); |     update_timers(player); | ||||||
|  |  | ||||||
|     input_move(&ctx.input, player); |     input_move(&ctx.input, player); | ||||||
|   | |||||||
| @@ -4,32 +4,32 @@ | |||||||
| #include "twn_game_api.h" | #include "twn_game_api.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| struct world; | typedef struct World World; | ||||||
|  |  | ||||||
|  |  | ||||||
| enum player_action { | typedef enum PlayerAction { | ||||||
|     PLAYER_ACTION_GROUND, |     PLAYER_ACTION_GROUND, | ||||||
|     PLAYER_ACTION_FALL, |     PLAYER_ACTION_FALL, | ||||||
|     PLAYER_ACTION_JUMP, |     PLAYER_ACTION_JUMP, | ||||||
| }; | } PlayerAction; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct player { | typedef struct Player { | ||||||
|     struct world *world; |     World *world; | ||||||
|  |  | ||||||
|     /* visual */ |     /* visual */ | ||||||
|     float sprite_w; |     float sprite_w; | ||||||
|     float sprite_h; |     float sprite_h; | ||||||
|  |  | ||||||
|     /* body */ |     /* body */ | ||||||
|     t_frect rect; |     Rect rect; | ||||||
|  |  | ||||||
|     /* state */ |     /* state */ | ||||||
|     enum player_action action; |     PlayerAction action; | ||||||
|  |  | ||||||
|     /* physics */ |     /* physics */ | ||||||
|     t_frect collider_x; |     Rect collider_x; | ||||||
|     t_frect collider_y; |     Rect collider_y; | ||||||
|     int collider_thickness; |     int collider_thickness; | ||||||
|     float dx; |     float dx; | ||||||
|     float dy; |     float dy; | ||||||
| @@ -54,12 +54,12 @@ struct player { | |||||||
|     float jump_boosted_multiplier; |     float jump_boosted_multiplier; | ||||||
|  |  | ||||||
|     float jump_corner_correction_offset; /* from center */ |     float jump_corner_correction_offset; /* from center */ | ||||||
| }; | } Player; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct player *player_create(struct world *world); | Player *player_create(World *world); | ||||||
| void player_destroy(struct player *player); | void player_destroy(Player *player); | ||||||
| void player_calc(struct player *player); | void player_calc(Player *player); | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -8,8 +8,8 @@ | |||||||
| #include <stb_perlin.h> | #include <stb_perlin.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| static void ingame_tick(struct state *state) { | static void ingame_tick(State *state) { | ||||||
|     struct scene_ingame *scn = (struct scene_ingame *)state->scene; |     SceneIngame *scn = (SceneIngame *)state->scene; | ||||||
|  |  | ||||||
|     world_drawdef(scn->world); |     world_drawdef(scn->world); | ||||||
|     player_calc(scn->player); |     player_calc(scn->player); | ||||||
| @@ -23,26 +23,26 @@ static void ingame_tick(struct state *state) { | |||||||
|         const float yaw_rad = scn->yaw * (float)DEG2RAD; |         const float yaw_rad = scn->yaw * (float)DEG2RAD; | ||||||
|         const float pitch_rad = scn->pitch * (float)DEG2RAD; |         const float pitch_rad = scn->pitch * (float)DEG2RAD; | ||||||
|  |  | ||||||
|         scn->cam.target = m_vec_norm(((t_fvec3){ |         scn->cam.target = m_vec_norm(((Vec3){ | ||||||
|             cosf(yaw_rad) * cosf(pitch_rad), |             cosf(yaw_rad) * cosf(pitch_rad), | ||||||
|             sinf(pitch_rad), |             sinf(pitch_rad), | ||||||
|             sinf(yaw_rad) * cosf(pitch_rad) |             sinf(yaw_rad) * cosf(pitch_rad) | ||||||
|         })); |         })); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const t_fvec3 right = m_vec_norm(m_vec_cross(scn->cam.target, scn->cam.up)); |     const Vec3 right = m_vec_norm(m_vec_cross(scn->cam.target, scn->cam.up)); | ||||||
|     const float speed = 0.04f; /* TODO: put this in a better place */ |     const float speed = 0.04f; /* TODO: put this in a better place */ | ||||||
|     if (input_is_action_pressed(&ctx.input, "player_left")) |     if (input_is_action_pressed(&ctx.input, "player_left")) | ||||||
|         scn->cam.pos = fvec3_sub(scn->cam.pos, m_vec_scale(right, speed)); |         scn->cam.pos = vec3_sub(scn->cam.pos, m_vec_scale(right, speed)); | ||||||
|  |  | ||||||
|     if (input_is_action_pressed(&ctx.input, "player_right")) |     if (input_is_action_pressed(&ctx.input, "player_right")) | ||||||
|         scn->cam.pos = fvec3_add(scn->cam.pos, m_vec_scale(right, speed)); |         scn->cam.pos = vec3_add(scn->cam.pos, m_vec_scale(right, speed)); | ||||||
|  |  | ||||||
|     if (input_is_action_pressed(&ctx.input, "player_forward")) |     if (input_is_action_pressed(&ctx.input, "player_forward")) | ||||||
|         scn->cam.pos = fvec3_add(scn->cam.pos, m_vec_scale(scn->cam.target, speed)); |         scn->cam.pos = vec3_add(scn->cam.pos, m_vec_scale(scn->cam.target, speed)); | ||||||
|  |  | ||||||
|     if (input_is_action_pressed(&ctx.input, "player_backward")) |     if (input_is_action_pressed(&ctx.input, "player_backward")) | ||||||
|         scn->cam.pos = fvec3_sub(scn->cam.pos, m_vec_scale(scn->cam.target, speed)); |         scn->cam.pos = vec3_sub(scn->cam.pos, m_vec_scale(scn->cam.target, speed)); | ||||||
|  |  | ||||||
|     if (input_is_action_pressed(&ctx.input, "player_jump")) |     if (input_is_action_pressed(&ctx.input, "player_jump")) | ||||||
|         scn->cam.pos.y += speed; |         scn->cam.pos.y += speed; | ||||||
| @@ -56,27 +56,27 @@ static void ingame_tick(struct state *state) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     m_sprite(m_set(path,  "/assets/9slice.png"), |     m_sprite(m_set(path,  "/assets/9slice.png"), | ||||||
|              m_set(rect,  ((t_frect){ 16, 16, 128, 128 })), |              m_set(rect,  ((Rect){ 16, 16, 128, 128 })), | ||||||
|              m_opt(texture_region, ((t_frect){ 0, 0, (float)(ctx.tick_count % 48), (float)(ctx.tick_count % 48) }))); |              m_opt(texture_region, ((Rect){ 0, 0, (float)(ctx.tick_count % 48), (float)(ctx.tick_count % 48) }))); | ||||||
|  |  | ||||||
|     m_sprite(m_set(path,  "/assets/light.png"), |     m_sprite(m_set(path,  "/assets/light.png"), | ||||||
|              m_set(rect,  ((t_frect){ 48, 64, 64, 64 })), |              m_set(rect,  ((Rect){ 48, 64, 64, 64 })), | ||||||
|              m_opt(color, ((t_color){ 255, 0, 0, 255 }))); |              m_opt(color, ((Color){ 255, 0, 0, 255 }))); | ||||||
|  |  | ||||||
|     m_sprite(m_set(path,  "/assets/light.png"), |     m_sprite(m_set(path,  "/assets/light.png"), | ||||||
|              m_set(rect,  ((t_frect){ 64, 64, 64, 64 })), |              m_set(rect,  ((Rect){ 64, 64, 64, 64 })), | ||||||
|              m_opt(color, ((t_color){ 0, 255, 0, 255 }))); |              m_opt(color, ((Color){ 0, 255, 0, 255 }))); | ||||||
|  |  | ||||||
|     m_sprite(m_set(path,  "/assets/light.png"), |     m_sprite(m_set(path,  "/assets/light.png"), | ||||||
|              m_set(rect,  ((t_frect){ 80, 64, 64, 64 })), |              m_set(rect,  ((Rect){ 80, 64, 64, 64 })), | ||||||
|              m_opt(color, ((t_color){ 0, 0, 255, 255 }))); |              m_opt(color, ((Color){ 0, 0, 255, 255 }))); | ||||||
|  |  | ||||||
|     m_sprite(m_set(path,     "/assets/player/baron-walk.png"), |     m_sprite(m_set(path,     "/assets/player/baron-walk.png"), | ||||||
|              m_set(rect,     ((t_frect){ 32, 32, 64, 64 })), |              m_set(rect,     ((Rect){ 32, 32, 64, 64 })), | ||||||
|              m_opt(rotation, (float)M_PI * 2 * (float)(ctx.tick_count % 64) / 64 )); |              m_opt(rotation, (float)M_PI * 2 * (float)(ctx.tick_count % 64) / 64 )); | ||||||
|  |  | ||||||
|     m_sprite(m_set(path,     "/assets/player/baron-walk.png"), |     m_sprite(m_set(path,     "/assets/player/baron-walk.png"), | ||||||
|              m_set(rect,     ((t_frect){ 128, 32, 128, 64 })), |              m_set(rect,     ((Rect){ 128, 32, 128, 64 })), | ||||||
|              m_opt(rotation, (float)M_PI * 2 * (float)(ctx.tick_count % 64) / 64 )); |              m_opt(rotation, (float)M_PI * 2 * (float)(ctx.tick_count % 64) / 64 )); | ||||||
|  |  | ||||||
|     set_camera(&scn->cam); |     set_camera(&scn->cam); | ||||||
| @@ -91,51 +91,51 @@ static void ingame_tick(struct state *state) { | |||||||
|             float d3 = stb_perlin_noise3((float)x       * TERRAIN_FREQUENCY, (float)(y - 1) * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 20 - 6; |             float d3 = stb_perlin_noise3((float)x       * TERRAIN_FREQUENCY, (float)(y - 1) * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 20 - 6; | ||||||
|  |  | ||||||
|             unfurl_triangle("/assets/grass.gif", |             unfurl_triangle("/assets/grass.gif", | ||||||
|                             (t_fvec3){ (float)x,     d0, (float)y }, |                             (Vec3){ (float)x,     d0, (float)y }, | ||||||
|                             (t_fvec3){ (float)x + 1, d1, (float)y }, |                             (Vec3){ (float)x + 1, d1, (float)y }, | ||||||
|                             (t_fvec3){ (float)x,     d3, (float)y - 1 }, |                             (Vec3){ (float)x,     d3, (float)y - 1 }, | ||||||
|                             (t_shvec2){ 1024, 768 }, |                             (Vec2sh){ 1024, 768 }, | ||||||
|                             (t_shvec2){ 1024, 0 }, |                             (Vec2sh){ 1024, 0 }, | ||||||
|                             (t_shvec2){ 0, 768 }); |                             (Vec2sh){ 0, 768 }); | ||||||
|  |  | ||||||
|             unfurl_triangle("/assets/grass.gif", |             unfurl_triangle("/assets/grass.gif", | ||||||
|                             (t_fvec3){ (float)x + 1, d1, (float)y }, |                             (Vec3){ (float)x + 1, d1, (float)y }, | ||||||
|                             (t_fvec3){ (float)x + 1, d2, (float)y - 1 }, |                             (Vec3){ (float)x + 1, d2, (float)y - 1 }, | ||||||
|                             (t_fvec3){ (float)x,     d3, (float)y - 1 }, |                             (Vec3){ (float)x,     d3, (float)y - 1 }, | ||||||
|                             (t_shvec2){ 1024, 0 }, |                             (Vec2sh){ 1024, 0 }, | ||||||
|                             (t_shvec2){ 0, 0 }, |                             (Vec2sh){ 0, 0 }, | ||||||
|                             (t_shvec2){ 0, 768 }); |                             (Vec2sh){ 0, 768 }); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void ingame_end(struct state *state) { | static void ingame_end(State *state) { | ||||||
|     struct scene_ingame *scn = (struct scene_ingame *)state->scene; |     SceneIngame *scn = (SceneIngame *)state->scene; | ||||||
|     player_destroy(scn->player); |     player_destroy(scn->player); | ||||||
|     world_destroy(scn->world); |     world_destroy(scn->world); | ||||||
|     free(state->scene); |     free(state->scene); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| struct scene *ingame_scene(struct state *state) { | Scene *ingame_scene(State *state) { | ||||||
|     (void)state; |     (void)state; | ||||||
|  |  | ||||||
|     struct scene_ingame *new_scene = ccalloc(1, sizeof *new_scene); |     SceneIngame *new_scene = ccalloc(1, sizeof *new_scene); | ||||||
|     new_scene->base.tick = ingame_tick; |     new_scene->base.tick = ingame_tick; | ||||||
|     new_scene->base.end = ingame_end; |     new_scene->base.end = ingame_end; | ||||||
|  |  | ||||||
|     new_scene->world = world_create(); |     new_scene->world = world_create(); | ||||||
|     new_scene->player = player_create(new_scene->world); |     new_scene->player = player_create(new_scene->world); | ||||||
|  |  | ||||||
|     new_scene->cam = (t_camera){ .pos = { 32, 0, 1 }, .up = { 0, 1, 0 }, .fov = (float)M_PI_2 }; |     new_scene->cam = (Camera){ .pos = { 32, 0, 1 }, .up = { 0, 1, 0 }, .fov = (float)M_PI_2 }; | ||||||
|  |  | ||||||
|     play_audio_ex("music/mod65.xm", "soundtrack", (t_play_audio_args){ |     audio_play_ex("music/mod65.xm", "soundtrack", (PlayAudioArgs){ | ||||||
|         .repeat = true, |         .repeat = true, | ||||||
|         .volume = 1.0f |         .volume = 1.0f | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     input_set_mouse_captured(&ctx.input, true); |     input_set_mouse_captured(&ctx.input, true); | ||||||
|  |  | ||||||
|     return (struct scene *)new_scene; |     return (Scene *)new_scene; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,22 +9,22 @@ | |||||||
| #include "../world.h" | #include "../world.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| struct scene_ingame { | typedef struct SceneIngame { | ||||||
|     struct scene base; |     Scene base; | ||||||
|  |  | ||||||
|     struct world *world; |     World *world; | ||||||
|     struct player *player; |     Player *player; | ||||||
|  |  | ||||||
|     t_camera cam; |     Camera cam; | ||||||
|  |  | ||||||
|     /* TODO: put this in a better place */ |     /* TODO: put this in a better place */ | ||||||
|     float yaw; |     float yaw; | ||||||
|     float pitch; |     float pitch; | ||||||
|     float roll; |     float roll; | ||||||
| }; | } SceneIngame; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct scene *ingame_scene(struct state *state); | Scene *ingame_scene(State *state); | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| #include "../state.h" | #include "../state.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| void switch_to(struct state *state, struct scene *(*scene_func)(struct state *)) { | void switch_to(State *state, Scene *(*scene_func)(State *)) { | ||||||
|     state->next_scene = scene_func(state); |     state->next_scene = scene_func(state); | ||||||
|     state->is_scene_switching = true; |     state->is_scene_switching = true; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,15 +2,15 @@ | |||||||
| #define SCENE_H | #define SCENE_H | ||||||
|  |  | ||||||
|  |  | ||||||
| struct state; | typedef struct State State; | ||||||
| struct scene { | typedef struct Scene { | ||||||
|     char *id; |     char *id; | ||||||
|     void (*tick)(struct state *); |     void (*tick)(State *); | ||||||
|     void (*end)(struct state *); |     void (*end)(State *); | ||||||
| }; | } Scene; | ||||||
|  |  | ||||||
|  |  | ||||||
| void switch_to(struct state *state, struct scene *(*scene_func)(struct state *)); | void switch_to(State *state, Scene *(*scene_func)(State *)); | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -8,8 +8,8 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| static void title_tick(struct state *state) { | static void title_tick(State *state) { | ||||||
|     struct scene_title *scn = (struct scene_title *)state->scene; |     SceneTitle *scn = (SceneTitle *)state->scene; | ||||||
|     (void)scn; |     (void)scn; | ||||||
|  |  | ||||||
|     if (input_is_action_just_pressed(&state->ctx->input, "ui_accept")) { |     if (input_is_action_just_pressed(&state->ctx->input, "ui_accept")) { | ||||||
| @@ -17,7 +17,7 @@ static void title_tick(struct state *state) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     m_sprite("/assets/title.png", ((t_frect) { |     m_sprite("/assets/title.png", ((Rect) { | ||||||
|             ((float)RENDER_BASE_WIDTH / 2) - ((float)320 / 2), 64, 320, 128 })); |             ((float)RENDER_BASE_WIDTH / 2) - ((float)320 / 2), 64, 320, 128 })); | ||||||
|      |      | ||||||
|      |      | ||||||
| @@ -31,42 +31,42 @@ static void title_tick(struct state *state) { | |||||||
|     int text_w = get_text_width(text_str, text_h, font); |     int text_w = get_text_width(text_str, text_h, font); | ||||||
|  |  | ||||||
|     push_rectangle( |     push_rectangle( | ||||||
|         (t_frect) { |         (Rect) { | ||||||
|             .x = 0, |             .x = 0, | ||||||
|             .y = 0, |             .y = 0, | ||||||
|             .w = (float)text_w, |             .w = (float)text_w, | ||||||
|             .h = (float)text_h, |             .h = (float)text_h, | ||||||
|         }, |         }, | ||||||
|         (t_color) { 0, 0, 0, 255 } |         (Color) { 0, 0, 0, 255 } | ||||||
|     ); |     ); | ||||||
|     push_text( |     push_text( | ||||||
|         text_str, |         text_str, | ||||||
|         (t_fvec2){ 0, 0 }, |         (Vec2){ 0, 0 }, | ||||||
|         text_h, |         text_h, | ||||||
|         (t_color) { 255, 255, 255, 255 }, |         (Color) { 255, 255, 255, 255 }, | ||||||
|         font |         font | ||||||
|     ); |     ); | ||||||
|     free(text_str); |     free(text_str); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void title_end(struct state *state) { | static void title_end(State *state) { | ||||||
|     struct scene_title *scn = (struct scene_title *)state->scene; |     SceneTitle *scn = (SceneTitle *)state->scene; | ||||||
|     player_destroy(scn->player); |     player_destroy(scn->player); | ||||||
|     world_destroy(scn->world); |     world_destroy(scn->world); | ||||||
|     free(state->scene); |     free(state->scene); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| struct scene *title_scene(struct state *state) { | Scene *title_scene(State *state) { | ||||||
|     (void)state; |     (void)state; | ||||||
|  |  | ||||||
|     struct scene_title *new_scene = ccalloc(1, sizeof *new_scene); |     SceneTitle *new_scene = ccalloc(1, sizeof *new_scene); | ||||||
|     new_scene->base.tick = title_tick; |     new_scene->base.tick = title_tick; | ||||||
|     new_scene->base.end = title_end; |     new_scene->base.end = title_end; | ||||||
|  |  | ||||||
|     new_scene->world = world_create(); |     new_scene->world = world_create(); | ||||||
|     new_scene->player = player_create(new_scene->world); |     new_scene->player = player_create(new_scene->world); | ||||||
|  |  | ||||||
|     return (struct scene *)new_scene; |     return (Scene *)new_scene; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,15 +7,15 @@ | |||||||
| #include "../world.h" | #include "../world.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| struct scene_title { | typedef struct SceneTitle { | ||||||
|     struct scene base; |     Scene base; | ||||||
|  |  | ||||||
|     struct world *world; |     World *world; | ||||||
|     struct player *player; |     Player *player; | ||||||
| }; | } SceneTitle; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct scene *title_scene(struct state *state); | Scene *title_scene(State *state); | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -6,12 +6,15 @@ | |||||||
|  |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
| struct state { |  | ||||||
|     t_ctx *ctx; | typedef struct Scene Scene; | ||||||
|     struct scene *scene; |  | ||||||
|     struct scene *next_scene; | typedef struct State { | ||||||
|  |     Context *ctx; | ||||||
|  |     Scene *scene; | ||||||
|  |     Scene *next_scene; | ||||||
|     bool is_scene_switching; |     bool is_scene_switching; | ||||||
| }; | } State; | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -8,11 +8,11 @@ | |||||||
| #include <tgmath.h> | #include <tgmath.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| static void update_tiles(struct world *world) { | static void update_tiles(struct World *world) { | ||||||
|     for (size_t row = 0; row < world->tilemap_height; ++row) { |     for (size_t row = 0; row < world->tilemap_height; ++row) { | ||||||
|         for (size_t col = 0; col < world->tilemap_width; ++col) { |         for (size_t col = 0; col < world->tilemap_width; ++col) { | ||||||
|             world->tiles[(row * world->tilemap_width) + col] = (struct tile) { |             world->tiles[(row * world->tilemap_width) + col] = (struct Tile) { | ||||||
|                 .rect = (t_rect) { |                 .rect = (Recti) { | ||||||
|                     .x = (int)col * world->tile_size, |                     .x = (int)col * world->tile_size, | ||||||
|                     .y = (int)row * world->tile_size, |                     .y = (int)row * world->tile_size, | ||||||
|                     .w = world->tile_size, |                     .w = world->tile_size, | ||||||
| @@ -25,30 +25,30 @@ static void update_tiles(struct world *world) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static t_vec2 to_grid_location(struct world *world, float x, float y) { | static Vec2i to_grid_location(struct World *world, float x, float y) { | ||||||
|     return (t_vec2) { |     return (Vec2i) { | ||||||
|         .x = (int)floor(x / (float)world->tile_size), |         .x = (int)floor(x / (float)world->tile_size), | ||||||
|         .y = (int)floor(y / (float)world->tile_size), |         .y = (int)floor(y / (float)world->tile_size), | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void drawdef_debug(struct world *world) { | static void drawdef_debug(struct World *world) { | ||||||
|     if (!ctx.debug) return; |     if (!ctx.debug) return; | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < world->tilemap_height * world->tilemap_width; ++i) { |     for (size_t i = 0; i < world->tilemap_height * world->tilemap_width; ++i) { | ||||||
|         if (world->tiles[i].type == TILE_TYPE_VOID) continue; |         if (world->tiles[i].type == TILE_TYPE_VOID) continue; | ||||||
|  |  | ||||||
|         push_rectangle(to_frect(world->tiles[i].rect), |         push_rectangle(to_frect(world->tiles[i].rect), | ||||||
|                         (t_color) { 255, 0, 255, 128 }); |                         (Color) { 255, 0, 255, 128 }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| struct world *world_create(void) { | struct World *world_create(void) { | ||||||
|     struct world *world = cmalloc(sizeof *world); |     struct World *world = cmalloc(sizeof *world); | ||||||
|  |  | ||||||
|     *world = (struct world) { |     *world = (struct World) { | ||||||
|         .tiles = NULL, |         .tiles = NULL, | ||||||
|         .tile_size = 42, |         .tile_size = 42, | ||||||
|         .tilemap_width = 20, |         .tilemap_width = 20, | ||||||
| @@ -89,7 +89,7 @@ struct world *world_create(void) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void world_destroy(struct world *world) { | void world_destroy(struct World *world) { | ||||||
|     free(world->tiles); |     free(world->tiles); | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < world->tilemap_height; ++i) { |     for (size_t i = 0; i < world->tilemap_height; ++i) { | ||||||
| @@ -101,7 +101,7 @@ void world_destroy(struct world *world) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void world_drawdef(struct world *world) { | void world_drawdef(struct World *world) { | ||||||
|     for (size_t i = 0; i < world->tilemap_height * world->tilemap_width; ++i) { |     for (size_t i = 0; i < world->tilemap_height * world->tilemap_width; ++i) { | ||||||
|         if (world->tiles[i].type == TILE_TYPE_VOID) |         if (world->tiles[i].type == TILE_TYPE_VOID) | ||||||
|             continue; |             continue; | ||||||
| @@ -113,7 +113,7 @@ void world_drawdef(struct world *world) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool world_find_intersect_frect(struct world *world, t_frect rect, t_frect *intersection) { | bool world_find_intersect_frect(struct World *world, Rect rect, Rect *intersection) { | ||||||
|     bool is_intersecting = false; |     bool is_intersecting = false; | ||||||
|  |  | ||||||
|     const size_t tile_count = world->tilemap_height * world->tilemap_width; |     const size_t tile_count = world->tilemap_height * world->tilemap_width; | ||||||
| @@ -121,7 +121,7 @@ bool world_find_intersect_frect(struct world *world, t_frect rect, t_frect *inte | |||||||
|         if (world->tiles[i].type == TILE_TYPE_VOID) |         if (world->tiles[i].type == TILE_TYPE_VOID) | ||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|         t_frect tile_frect = { |         Rect tile_frect = { | ||||||
|             .x = (float)(world->tiles[i].rect.x), |             .x = (float)(world->tiles[i].rect.x), | ||||||
|             .y = (float)(world->tiles[i].rect.y), |             .y = (float)(world->tiles[i].rect.y), | ||||||
|             .w = (float)(world->tiles[i].rect.w), |             .w = (float)(world->tiles[i].rect.w), | ||||||
| @@ -129,7 +129,7 @@ bool world_find_intersect_frect(struct world *world, t_frect rect, t_frect *inte | |||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         if (intersection == NULL) { |         if (intersection == NULL) { | ||||||
|             t_frect temp; |             Rect temp; | ||||||
|             is_intersecting = overlap_frect(&rect, &tile_frect, &temp); |             is_intersecting = overlap_frect(&rect, &tile_frect, &temp); | ||||||
|         } else { |         } else { | ||||||
|             is_intersecting = overlap_frect(&rect, &tile_frect, intersection); |             is_intersecting = overlap_frect(&rect, &tile_frect, intersection); | ||||||
| @@ -143,7 +143,7 @@ bool world_find_intersect_frect(struct world *world, t_frect rect, t_frect *inte | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool world_find_intersect_rect(struct world *world, t_rect rect, t_rect *intersection) { | bool world_find_intersect_rect(struct World *world, Recti rect, Recti *intersection) { | ||||||
|     bool is_intersecting = false; |     bool is_intersecting = false; | ||||||
|  |  | ||||||
|     const size_t tile_count = world->tilemap_height * world->tilemap_width; |     const size_t tile_count = world->tilemap_height * world->tilemap_width; | ||||||
| @@ -151,10 +151,10 @@ bool world_find_intersect_rect(struct world *world, t_rect rect, t_rect *interse | |||||||
|         if (world->tiles[i].type == TILE_TYPE_VOID) |         if (world->tiles[i].type == TILE_TYPE_VOID) | ||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|         t_rect *tile_rect = &world->tiles[i].rect; |         Recti *tile_rect = &world->tiles[i].rect; | ||||||
|  |  | ||||||
|         if (intersection == NULL) { |         if (intersection == NULL) { | ||||||
|             t_rect temp; |             Recti temp; | ||||||
|             is_intersecting = overlap_rect(&rect, tile_rect, &temp); |             is_intersecting = overlap_rect(&rect, tile_rect, &temp); | ||||||
|         } else { |         } else { | ||||||
|             is_intersecting = overlap_rect(&rect, tile_rect, intersection); |             is_intersecting = overlap_rect(&rect, tile_rect, intersection); | ||||||
| @@ -168,21 +168,21 @@ bool world_find_intersect_rect(struct world *world, t_rect rect, t_rect *interse | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool world_is_tile_at(struct world *world, float x, float y) { | bool world_is_tile_at(struct World *world, float x, float y) { | ||||||
|     t_vec2 position_in_grid = to_grid_location(world, x, y); |     Vec2i position_in_grid = to_grid_location(world, x, y); | ||||||
|     return world->tilemap[position_in_grid.y][position_in_grid.x] != TILE_TYPE_VOID; |     return world->tilemap[position_in_grid.y][position_in_grid.x] != TILE_TYPE_VOID; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void world_place_tile(struct world *world, float x, float y) { | void world_place_tile(struct World *world, float x, float y) { | ||||||
|     t_vec2 position_in_grid = to_grid_location(world, x, y); |     Vec2i position_in_grid = to_grid_location(world, x, y); | ||||||
|     world->tilemap[position_in_grid.y][position_in_grid.x] = TILE_TYPE_SOLID; |     world->tilemap[position_in_grid.y][position_in_grid.x] = TILE_TYPE_SOLID; | ||||||
|     update_tiles(world); |     update_tiles(world); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void world_remove_tile(struct world *world, float x, float y) { | void world_remove_tile(struct World *world, float x, float y) { | ||||||
|     t_vec2 position_in_grid = to_grid_location(world, x, y); |     Vec2i position_in_grid = to_grid_location(world, x, y); | ||||||
|     world->tilemap[position_in_grid.y][position_in_grid.x] = TILE_TYPE_VOID; |     world->tilemap[position_in_grid.y][position_in_grid.x] = TILE_TYPE_VOID; | ||||||
|     update_tiles(world); |     update_tiles(world); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,42 +1,44 @@ | |||||||
| #ifndef WORLD_H | #ifndef WORLD_H | ||||||
| #define WORLD_H | #define WORLD_H | ||||||
|  |  | ||||||
|  | #include "twn_game_api.h" | ||||||
|  |  | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| enum tile_type { | typedef enum TileType { | ||||||
|     TILE_TYPE_VOID, |     TILE_TYPE_VOID, | ||||||
|     TILE_TYPE_SOLID, |     TILE_TYPE_SOLID, | ||||||
| }; | } TileType; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct tile { | typedef struct Tile { | ||||||
|     t_rect rect; |     Recti rect; | ||||||
|     enum tile_type type; |     TileType type; | ||||||
| }; | } Tile; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct world { | typedef struct World { | ||||||
|     enum tile_type **tilemap; |     TileType **tilemap; | ||||||
|     struct tile *tiles; |     Tile *tiles; | ||||||
|      |      | ||||||
|     int tile_size; |     int tile_size; | ||||||
|     unsigned int tilemap_width; |     unsigned int tilemap_width; | ||||||
|     unsigned int tilemap_height; |     unsigned int tilemap_height; | ||||||
|     size_t tile_nonvoid_count; |     size_t tile_nonvoid_count; | ||||||
|     float gravity; |     float gravity; | ||||||
| }; | } World; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct world *world_create(void); | World *world_create(void); | ||||||
| void world_destroy(struct world *world); | void world_destroy(World *world); | ||||||
| void world_drawdef(struct world *world); | void world_drawdef(World *world); | ||||||
| bool world_find_intersect_frect(struct world *world, t_frect rect, t_frect *intersection); | bool world_find_intersect_frect(World *world, Rect rect, Rect *intersection); | ||||||
| bool world_find_intersect_rect(struct world *world, t_rect rect, t_rect *intersection); | bool world_find_intersect_rect(World *world, Recti rect, Recti *intersection); | ||||||
| bool world_is_tile_at(struct world *world, float x, float y); | bool world_is_tile_at(World *world, float x, float y); | ||||||
| void world_place_tile(struct world *world, float x, float y); | void world_place_tile(World *world, float x, float y); | ||||||
| void world_remove_tile(struct world *world, float x, float y); | void world_remove_tile(World *world, float x, float y); | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								data/assets/9slice.png
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/assets/9slice.png
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -6,7 +6,7 @@ | |||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct play_audio_args { | typedef struct PlayAudioArgs { | ||||||
|     /* default: false */ |     /* default: false */ | ||||||
|     bool repeat; |     bool repeat; | ||||||
|     /* crossfade between already playing audio on a given channel, if any */ |     /* crossfade between already playing audio on a given channel, if any */ | ||||||
| @@ -18,21 +18,21 @@ typedef struct play_audio_args { | |||||||
|     /* range: -1.0 to 1.0f */ |     /* range: -1.0 to 1.0f */ | ||||||
|     /* default: 0.0f */ |     /* default: 0.0f */ | ||||||
|     float panning; |     float panning; | ||||||
| } t_play_audio_args; | } PlayAudioArgs; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* plays audio file at specified channel or anywhere if NULL is passed */ | /* plays audio file at specified channel or anywhere if NULL is passed */ | ||||||
| /* path must contain valid file extension to infer which file format it is */ | /* path must contain valid file extension to infer which file format it is */ | ||||||
| /* supported formats: .ogg, .xm */ | /* supported formats: .ogg, .xm */ | ||||||
| /* preserves args that are already specified on the channel */ | /* preserves args that are already specified on the channel */ | ||||||
| TWN_API void play_audio(const char *path, const char *channel); | TWN_API void audio_play(const char *path, const char *channel); | ||||||
|  |  | ||||||
| TWN_API void play_audio_ex(const char *path, const char *channel, t_play_audio_args args); | TWN_API void audio_play_ex(const char *path, const char *channel, PlayAudioArgs args); | ||||||
|  |  | ||||||
| /* could be used for modifying args */ | /* could be used for modifying args */ | ||||||
| /* warn: is only valid if no other calls to audio are made */ | /* warn: is only valid if no other calls to audio are made */ | ||||||
| TWN_API t_play_audio_args *get_audio_args(const char *channel); | TWN_API PlayAudioArgs *audio_get_args(const char *channel); | ||||||
|  |  | ||||||
| TWN_API t_play_audio_args get_default_audio_args(void); | TWN_API PlayAudioArgs audio_get_default_args(void); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -8,15 +8,15 @@ | |||||||
| /*       for example, perspective matrix only needs recaluclation on FOV change */ | /*       for example, perspective matrix only needs recaluclation on FOV change */ | ||||||
|  |  | ||||||
| /* first person camera class */ | /* first person camera class */ | ||||||
| typedef struct camera { | typedef struct Camera { | ||||||
|     t_fvec3 pos;        /* eye position */ |     Vec3 pos;        /* eye position */ | ||||||
|     t_fvec3 target;     /* normalized target vector */ |     Vec3 target;     /* normalized target vector */ | ||||||
|     t_fvec3 up;         /* normalized up vector */ |     Vec3 up;         /* normalized up vector */ | ||||||
|     float fov;          /* field of view, in radians */ |     float fov;          /* field of view, in radians */ | ||||||
| } t_camera; | } Camera; | ||||||
|  |  | ||||||
| TWN_API t_matrix4 camera_look_at(const t_camera *camera); | TWN_API Matrix4 camera_look_at(const Camera *camera); | ||||||
|  |  | ||||||
| TWN_API t_matrix4 camera_perspective(const t_camera *const camera); | TWN_API Matrix4 camera_perspective(const Camera *const camera); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -8,8 +8,8 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct context { | typedef struct Context { | ||||||
|     struct input_state input; |     struct InputState input; | ||||||
|  |  | ||||||
|     int64_t delta_time; /* preserves real time frame delta with no manipilation */ |     int64_t delta_time; /* preserves real time frame delta with no manipilation */ | ||||||
|     uint64_t tick_count; |     uint64_t tick_count; | ||||||
| @@ -31,10 +31,10 @@ typedef struct context { | |||||||
|     bool is_running; |     bool is_running; | ||||||
|     bool window_size_has_changed; |     bool window_size_has_changed; | ||||||
|     bool initialization_needed; |     bool initialization_needed; | ||||||
| } t_ctx; | } Context; | ||||||
|  |  | ||||||
| #ifndef TWN_ENGINE_CONTEXT_C_H | #ifndef TWN_ENGINE_CONTEXT_C_H | ||||||
| TWN_API extern t_ctx ctx; | TWN_API extern Context ctx; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -12,16 +12,16 @@ | |||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| enum button_source { | typedef enum ButtonSource { | ||||||
|     BUTTON_SOURCE_NOT_SET, |     BUTTON_SOURCE_NOT_SET, | ||||||
|     BUTTON_SOURCE_KEYBOARD_PHYSICAL, |     BUTTON_SOURCE_KEYBOARD_PHYSICAL, | ||||||
|     BUTTON_SOURCE_KEYBOARD_CHARACTER, |     BUTTON_SOURCE_KEYBOARD_CHARACTER, | ||||||
|     BUTTON_SOURCE_GAMEPAD, |     BUTTON_SOURCE_GAMEPAD, | ||||||
|     BUTTON_SOURCE_MOUSE, |     BUTTON_SOURCE_MOUSE, | ||||||
| }; | } ButtonSource; | ||||||
|  |  | ||||||
|  |  | ||||||
| union button_code { | union ButtonCode { | ||||||
|     SDL_Scancode scancode; |     SDL_Scancode scancode; | ||||||
|     SDL_Keycode keycode; |     SDL_Keycode keycode; | ||||||
|     SDL_GameControllerButton gamepad_button; |     SDL_GameControllerButton gamepad_button; | ||||||
| @@ -31,71 +31,71 @@ union button_code { | |||||||
|  |  | ||||||
| /* an input to which an action is bound */ | /* an input to which an action is bound */ | ||||||
| /* it is not limited to literal buttons */ | /* it is not limited to literal buttons */ | ||||||
| struct button { | typedef struct Button { | ||||||
|     enum button_source source; |     enum ButtonSource source; | ||||||
|     union button_code code; |     union ButtonCode code; | ||||||
| }; | } Button; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* represents the collective state of a group of buttons */ | /* represents the collective state of a group of buttons */ | ||||||
| /* that is, changes in the states of any of the bound buttons will affect it */ | /* that is, changes in the states of any of the bound buttons will affect it */ | ||||||
| struct action { | typedef struct Action { | ||||||
|     size_t num_bindings; |     size_t num_bindings; | ||||||
|  |  | ||||||
|     /* if you bind more than NUM_KEYBIND_SLOTS (set in config.h) */ |     /* if you bind more than NUM_KEYBIND_SLOTS (set in config.h) */ | ||||||
|     /* it forgets the first button to add the new one at the end */ |     /* it forgets the first Button to add the new one at the end */ | ||||||
|     struct button bindings[NUM_KEYBIND_SLOTS]; |     Button bindings[NUM_KEYBIND_SLOTS]; | ||||||
|  |  | ||||||
|     t_fvec2 position;        /* set if applicable, e.g. mouse click */ |     Vec2 position;        /* set if applicable, e.g. mouse click */ | ||||||
|     bool is_pressed; |     bool is_pressed; | ||||||
|     bool just_changed; |     bool just_changed; | ||||||
| }; | } Action; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct action_hash_item { | typedef struct ActionHashItem { | ||||||
|     char *key; |     char *key; | ||||||
|     struct action value; |     Action value; | ||||||
| }; | } ActionHashItem; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct input_state { | typedef struct InputState { | ||||||
|     struct action_hash_item *action_hash; |     ActionHashItem *action_hash; | ||||||
|     const uint8_t *keyboard_state; /* array of booleans indexed by scancode */ |     const uint8_t *keyboard_state; /* array of booleans indexed by scancode */ | ||||||
|     uint32_t mouse_state;          /* SDL mouse button bitmask */ |     uint32_t mouse_state;          /* SDL mouse button bitmask */ | ||||||
|     t_vec2 mouse_window_position; |     Vec2i mouse_window_position; | ||||||
|     t_vec2 mouse_relative_position; |     Vec2i mouse_relative_position; | ||||||
|     enum button_source last_active_source; |     ButtonSource last_active_source; | ||||||
|     bool is_anything_just_pressed; |     bool is_anything_just_pressed; | ||||||
| }; | } InputState; | ||||||
|  |  | ||||||
|  |  | ||||||
| TWN_API void input_state_init(struct input_state *input); | TWN_API void input_state_init(InputState *input); | ||||||
| TWN_API void input_state_deinit(struct input_state *input); | TWN_API void input_state_deinit(InputState *input); | ||||||
| TWN_API void input_state_update(struct input_state *input); | TWN_API void input_state_update(InputState *input); | ||||||
|  |  | ||||||
| TWN_API void input_bind_action_scancode(struct input_state *input, | TWN_API void input_bind_action_scancode(InputState *input, | ||||||
|                                 char *action_name, |                                 char *action_name, | ||||||
|                                 SDL_Scancode scancode); |                                 SDL_Scancode scancode); | ||||||
| TWN_API void input_unbind_action_scancode(struct input_state *input, | TWN_API void input_unbind_action_scancode(InputState *input, | ||||||
|                                   char *action_name, |                                   char *action_name, | ||||||
|                                   SDL_Scancode scancode); |                                   SDL_Scancode scancode); | ||||||
| TWN_API void input_bind_action_mouse(struct input_state *input, | TWN_API void input_bind_action_mouse(InputState *input, | ||||||
|                              char *action_name, |                              char *action_name, | ||||||
|                              uint8_t mouse_button); |                              uint8_t mouse_button); | ||||||
| TWN_API void input_unbind_action_mouse(struct input_state *input, | TWN_API void input_unbind_action_mouse(InputState *input, | ||||||
|                                char *action_name, |                                char *action_name, | ||||||
|                                uint8_t mouse_button); |                                uint8_t mouse_button); | ||||||
|  |  | ||||||
| TWN_API void input_add_action(struct input_state *input, char *action_name); | TWN_API void input_add_action(InputState *input, char *action_name); | ||||||
| TWN_API void input_delete_action(struct input_state *input, char *action_name); | TWN_API void input_delete_action(InputState *input, char *action_name); | ||||||
|  |  | ||||||
| TWN_API bool input_is_action_pressed(struct input_state *input, char *action_name); | TWN_API bool input_is_action_pressed(InputState *input, char *action_name); | ||||||
| TWN_API bool input_is_action_just_pressed(struct input_state *input, char *action_name); | TWN_API bool input_is_action_just_pressed(InputState *input, char *action_name); | ||||||
| TWN_API bool input_is_action_just_released(struct input_state *input, char *action_name); | TWN_API bool input_is_action_just_released(InputState *input, char *action_name); | ||||||
|  |  | ||||||
| TWN_API t_fvec2 input_get_action_position(struct input_state *input, char *action_name); | TWN_API Vec2 input_get_action_position(InputState *input, char *action_name); | ||||||
|  |  | ||||||
| TWN_API void input_set_mouse_captured(struct input_state *input, bool value); | TWN_API void input_set_mouse_captured(InputState *input, bool value); | ||||||
| TWN_API bool input_is_mouse_captured(struct input_state *input); | TWN_API bool input_is_mouse_captured(InputState *input); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -10,67 +10,67 @@ | |||||||
|  |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
| typedef struct push_sprite_args { | typedef struct PushSpriteArgs { | ||||||
|     char *path; |     char *path; | ||||||
|     t_frect rect; |     Rect rect; | ||||||
|  |  | ||||||
|     m_option_list( |     m_option_list( | ||||||
|         t_frect, texture_region, |         Rect, texture_region, | ||||||
|         t_color, color, |         Color, color, | ||||||
|         float,   rotation, |         float,   rotation, | ||||||
|         bool,    flip_x, |         bool,    flip_x, | ||||||
|         bool,    flip_y, |         bool,    flip_y, | ||||||
|         bool,    stretch ) |         bool,    stretch ) | ||||||
| } t_push_sprite_args; | } PushSpriteArgs; | ||||||
|  |  | ||||||
| /* pushes a sprite onto the sprite render queue */ | /* pushes a sprite onto the sprite render queue */ | ||||||
| /* this is a simplified version of push_sprite_ex for the most common case. */ | /* this is a simplified version of push_sprite_ex for the most common case. */ | ||||||
| /* it assumes you want no color modulation, no rotation, no flip */ | /* it assumes you want no color modulation, no rotation, no flip */ | ||||||
| TWN_API void push_sprite(t_push_sprite_args args); | TWN_API void push_sprite(PushSpriteArgs args); | ||||||
| #define m_sprite(...) (push_sprite((t_push_sprite_args){__VA_ARGS__})) | #define m_sprite(...) (push_sprite((PushSpriteArgs){__VA_ARGS__})) | ||||||
|  |  | ||||||
| /* pushes a filled rectangle onto the rectangle render queue */ | /* pushes a filled rectangle onto the rectangle render queue */ | ||||||
| TWN_API void push_rectangle(t_frect rect, t_color color); | TWN_API void push_rectangle(Rect rect, Color color); | ||||||
|  |  | ||||||
| /* pushes a filled circle onto the circle render queue */ | /* pushes a filled circle onto the circle render queue */ | ||||||
| TWN_API void push_circle(t_fvec2 position, float radius, t_color color); | TWN_API void push_circle(Vec2 position, float radius, Color color); | ||||||
|  |  | ||||||
| TWN_API void push_text(char *string, t_fvec2 position, int height_px, t_color color, const char *font_path); | TWN_API void push_text(char *string, Vec2 position, int height_px, Color color, const char *font_path); | ||||||
| TWN_API int get_text_width(char *string, int height_px, const char *font_path); | TWN_API int get_text_width(char *string, int height_px, const char *font_path); | ||||||
|  |  | ||||||
| /* pushes a textured 3d triangle onto the render queue */ | /* pushes a textured 3d triangle onto the render queue */ | ||||||
| /* vertices are in absolute coordinates, relative to world origin */ | /* vertices are in absolute coordinates, relative to world origin */ | ||||||
| /* texture coordinates are in pixels */ | /* texture coordinates are in pixels */ | ||||||
| TWN_API void unfurl_triangle(const char *path, | TWN_API void unfurl_triangle(const char *path, | ||||||
|                             t_fvec3 v0, |                             Vec3 v0, | ||||||
|                             t_fvec3 v1, |                             Vec3 v1, | ||||||
|                             t_fvec3 v2, |                             Vec3 v2, | ||||||
|                             t_shvec2 uv0, |                             Vec2sh uv0, | ||||||
|                             t_shvec2 uv1, |                             Vec2sh uv1, | ||||||
|                             t_shvec2 uv2); |                             Vec2sh uv2); | ||||||
|  |  | ||||||
| // TODO: decide whether it's needed to begin with? | // TODO: decide whether it's needed to begin with? | ||||||
| //       intended usage for it is baked lighting, i would think. | //       intended usage for it is baked lighting, i would think. | ||||||
| /* pushes a colored textured 3d triangle onto the render queue */ | /* pushes a colored textured 3d triangle onto the render queue */ | ||||||
| // void unfurl_colored_triangle(const char *path, | // void unfurl_colored_triangle(const char *path, | ||||||
| //                              t_fvec3 v0, | //                              Vec3 v0, | ||||||
| //                              t_fvec3 v1, | //                              Vec3 v1, | ||||||
| //                              t_fvec3 v2, | //                              Vec3 v2, | ||||||
| //                              t_shvec2 uv0, | //                              Vec2sh uv0, | ||||||
| //                              t_shvec2 uv1, | //                              Vec2sh uv1, | ||||||
| //                              t_shvec2 uv2, | //                              Vec2sh uv2, | ||||||
| //                              t_color c0, | //                              Color c0, | ||||||
| //                              t_color c1, | //                              Color c1, | ||||||
| //                              t_color c2); | //                              Color c2); | ||||||
|  |  | ||||||
| // TODO: | // TODO: | ||||||
| // http://www.lighthouse3d.com/opengl/billboarding/index.php?billCheat2 | // http://www.lighthouse3d.com/opengl/billboarding/index.php?billCheat2 | ||||||
| // void unfurl_billboard(const char *path, | // void unfurl_billboard(const char *path, | ||||||
| //                       t_fvec3 position, | //                       Vec2 position, | ||||||
| //                       t_fvec2 scaling, | //                       Vec2 scaling, | ||||||
| //                       t_frect uvs); | //                       Rect uvs); | ||||||
|  |  | ||||||
| /* pushes a camera state to be used for all future unfurl_* commands */ | /* pushes a camera state to be used for all future unfurl_* commands */ | ||||||
| TWN_API void set_camera(const t_camera *camera); | TWN_API void set_camera(const Camera *camera); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -2,10 +2,10 @@ | |||||||
| #define TWN_TEXTURES_MODES_H | #define TWN_TEXTURES_MODES_H | ||||||
|  |  | ||||||
| /* alpha channel information */ | /* alpha channel information */ | ||||||
| enum texture_mode { | typedef enum TextureMode { | ||||||
|     TEXTURE_MODE_OPAQUE,        /* all pixels are solid */ |     TEXTURE_MODE_OPAQUE,        /* all pixels are solid */ | ||||||
|     TEXTURE_MODE_SEETHROUGH,  	/* some pixels are alpha zero */ |     TEXTURE_MODE_SEETHROUGH,  	/* some pixels are alpha zero */ | ||||||
|     TEXTURE_MODE_GHOSTLY,       /* arbitrary alpha values */ |     TEXTURE_MODE_GHOSTLY,       /* arbitrary alpha values */ | ||||||
| }; | } TextureMode; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -80,54 +80,54 @@ TWN_API TWN_API bool strends(const char *str, const char *suffix); | |||||||
| /*                      */ | /*                      */ | ||||||
|  |  | ||||||
| /* 32-bit color data */ | /* 32-bit color data */ | ||||||
| typedef struct color { | typedef struct Color { | ||||||
| _Alignas(4) | _Alignas(4) | ||||||
|     uint8_t r; |     uint8_t r; | ||||||
|     uint8_t g; |     uint8_t g; | ||||||
|     uint8_t b; |     uint8_t b; | ||||||
|     uint8_t a; |     uint8_t a; | ||||||
| } t_color; | } Color; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a rectangle with the origin at the upper left (integer) */ | /* a rectangle with the origin at the upper left (integer) */ | ||||||
| typedef struct rect { | typedef struct Recti { | ||||||
| _Alignas(16) | _Alignas(16) | ||||||
|     int32_t x; |     int32_t x; | ||||||
|     int32_t y; |     int32_t y; | ||||||
|     int32_t w; |     int32_t w; | ||||||
|     int32_t h; |     int32_t h; | ||||||
| } t_rect; | } Recti; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a rectangle with the origin at the upper left (floating point) */ | /* a rectangle with the origin at the upper left (floating point) */ | ||||||
| typedef struct frect { | typedef struct Rect { | ||||||
| _Alignas(16) | _Alignas(16) | ||||||
|     float x; |     float x; | ||||||
|     float y; |     float y; | ||||||
|     float w; |     float w; | ||||||
|     float h; |     float h; | ||||||
| } t_frect; | } Rect; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* calculates the overlap of two rectangles and places it in result. */ | /* calculates the overlap of two rectangles and places it in result. */ | ||||||
| /* result may be NULL. if this is the case, it will simply be ignored. */ | /* result may be NULL. if this is the case, it will simply be ignored. */ | ||||||
| /* returns true if the rectangles are indeed intersecting. */ | /* returns true if the rectangles are indeed intersecting. */ | ||||||
| TWN_API bool overlap_rect(const t_rect *a, const t_rect *b, t_rect *result); | TWN_API bool overlap_rect(const Recti *a, const Recti *b, Recti *result); | ||||||
| TWN_API bool overlap_frect(const t_frect *a, const t_frect *b, t_frect *result); | TWN_API bool overlap_frect(const Rect *a, const Rect *b, Rect *result); | ||||||
|  |  | ||||||
| /* returns true if two rectangles are intersecting */ | /* returns true if two rectangles are intersecting */ | ||||||
| TWN_API bool intersect_rect(const t_rect *a, const t_rect *b); | TWN_API bool intersect_rect(const Recti *a, const Recti *b); | ||||||
| TWN_API bool intersect_frect(const t_frect *a, const t_frect *b); | TWN_API bool intersect_frect(const Rect *a, const Rect *b); | ||||||
|  |  | ||||||
| /* TODO: generics and specials (see m_to_fvec2() for an example)*/ | /* TODO: generics and specials (see m_vec2_from() for an example)*/ | ||||||
| TWN_API t_frect to_frect(t_rect rect); | TWN_API Rect to_frect(Recti rect); | ||||||
|  |  | ||||||
| TWN_API t_fvec2 frect_center(t_frect rect); | TWN_API Vec2 frect_center(Rect rect); | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct matrix4 { | typedef struct Matrix4 { | ||||||
|     t_fvec4 row[4]; |     Vec4 row[4]; | ||||||
| } t_matrix4; | } Matrix4; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* decrements an lvalue (which should be an int), stopping at 0 */ | /* decrements an lvalue (which should be an int), stopping at 0 */ | ||||||
| @@ -162,9 +162,9 @@ static inline float fast_sqrt(float x) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static inline t_fvec2 fast_cossine(float a) { | static inline Vec2 fast_cossine(float a) { | ||||||
|     const float s = sinf(a); |     const float s = sinf(a); | ||||||
|     return (t_fvec2){ |     return (Vec2){ | ||||||
|         .x = fast_sqrt(1.0f - s * s) * (a >= (float)M_PI_2 && a < (float)(M_PI + M_PI_2) ? -1 : 1), |         .x = fast_sqrt(1.0f - s * s) * (a >= (float)M_PI_2 && a < (float)(M_PI + M_PI_2) ? -1 : 1), | ||||||
|         .y = s |         .y = s | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -6,92 +6,92 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| /* a point in some space (integer) */ | /* a point in some space (integer) */ | ||||||
| typedef struct vec2 { | typedef struct Vec2i { | ||||||
| _Alignas(8) | _Alignas(8) | ||||||
|     int32_t x; |     int32_t x; | ||||||
|     int32_t y; |     int32_t y; | ||||||
| } t_vec2; | } Vec2i; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a point in some space (floating point) */ | /* a point in some space (floating point) */ | ||||||
| typedef struct fvec2 { | typedef struct Vec2 { | ||||||
| _Alignas(8) | _Alignas(8) | ||||||
|     float x; |     float x; | ||||||
|     float y; |     float y; | ||||||
| } t_fvec2; | } Vec2; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a point in some three dimension space (floating point) */ | /* a point in some three dimension space (floating point) */ | ||||||
| /* y goes up, x goes to the right */ | /* y goes up, x goes to the right */ | ||||||
| typedef struct fvec3 { | typedef struct Vec3 { | ||||||
| _Alignas(16) | _Alignas(16) | ||||||
|     float x; |     float x; | ||||||
|     float y; |     float y; | ||||||
|     float z; |     float z; | ||||||
| } t_fvec3; | } Vec3; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a point in some three dimension space (floating point) */ | /* a point in some three dimension space (floating point) */ | ||||||
| /* y goes up, x goes to the right */ | /* y goes up, x goes to the right */ | ||||||
| typedef struct fvec4 { | typedef struct Vec4 { | ||||||
| _Alignas(16) | _Alignas(16) | ||||||
|     float x; |     float x; | ||||||
|     float y; |     float y; | ||||||
|     float z; |     float z; | ||||||
|     float w; |     float w; | ||||||
| } t_fvec4; | } Vec4; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a point in some space (short) */ | /* a point in some space (short) */ | ||||||
| typedef struct shvec2 { | typedef struct Vec2sh { | ||||||
| _Alignas(4) | _Alignas(4) | ||||||
|     int16_t x; |     int16_t x; | ||||||
|     int16_t y; |     int16_t y; | ||||||
| } t_shvec2; | } Vec2sh; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* aren't macros to prevent double evaluation with side effects */ | /* aren't macros to prevent double evaluation with side effects */ | ||||||
| /* maybe could be inlined? i hope LTO will resolve this */ | /* maybe could be inlined? i hope LTO will resolve this */ | ||||||
| static inline t_fvec2 fvec2_from_vec2(t_vec2 vec) { | static inline Vec2 vec2_from_vec2i(Vec2i vec) { | ||||||
|     return (t_fvec2) { |     return (Vec2) { | ||||||
|         .x = (float)vec.x, |         .x = (float)vec.x, | ||||||
|         .y = (float)vec.y, |         .y = (float)vec.y, | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline t_fvec2 fvec2_from_shvec2(t_shvec2 vec) { | static inline Vec2 vec2_from_vec2sh(Vec2sh vec) { | ||||||
|     return (t_fvec2) { |     return (Vec2) { | ||||||
|         .x = (float)vec.x, |         .x = (float)vec.x, | ||||||
|         .y = (float)vec.y, |         .y = (float)vec.y, | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline t_fvec3 fvec3_add(t_fvec3 a, t_fvec3 b) { | static inline Vec3 vec3_add(Vec3 a, Vec3 b) { | ||||||
|     return (t_fvec3) { a.x + b.x, a.y + b.y, a.z + b.z }; |     return (Vec3) { a.x + b.x, a.y + b.y, a.z + b.z }; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline t_fvec3 fvec3_sub(t_fvec3 a, t_fvec3 b) { | static inline Vec3 vec3_sub(Vec3 a, Vec3 b) { | ||||||
|     return (t_fvec3) { a.x - b.x, a.y - b.y, a.z - b.z }; |     return (Vec3) { a.x - b.x, a.y - b.y, a.z - b.z }; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline t_fvec2 fvec2_div(t_fvec2 a, t_fvec2 b) { | static inline Vec2 vec2_div(Vec2 a, Vec2 b) { | ||||||
|     return (t_fvec2) { a.x / b.x, a.y / b.y }; |     return (Vec2) { a.x / b.x, a.y / b.y }; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline t_fvec2 fvec2_scale(t_fvec2 a, float s) { | static inline Vec2 vec2_scale(Vec2 a, float s) { | ||||||
|     return (t_fvec2) { a.x * s, a.y * s }; |     return (Vec2) { a.x * s, a.y * s }; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline t_fvec3 fvec3_scale(t_fvec3 a, float s) { | static inline Vec3 vec3_scale(Vec3 a, float s) { | ||||||
|     return (t_fvec3) { a.x * s, a.y * s, a.z * s }; |     return (Vec3) { a.x * s, a.y * s, a.z * s }; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline float fvec3_dot(t_fvec3 a, t_fvec3 b) { | static inline float vec3_dot(Vec3 a, Vec3 b) { | ||||||
|     return a.x * b.x + a.y * b.y + a.z * b.z; |     return a.x * b.x + a.y * b.y + a.z * b.z; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline t_fvec3 fvec3_cross(t_fvec3 a, t_fvec3 b) { | static inline Vec3 vec3_cross(Vec3 a, Vec3 b) { | ||||||
|     return (t_fvec3) { |     return (Vec3) { | ||||||
|         a.y * b.z - a.z * b.y, |         a.y * b.z - a.z * b.y, | ||||||
|         a.z * b.x - a.x * b.z, |         a.z * b.x - a.x * b.z, | ||||||
|         a.x * b.y - a.y * b.x, |         a.x * b.y - a.y * b.x, | ||||||
| @@ -99,66 +99,66 @@ static inline t_fvec3 fvec3_cross(t_fvec3 a, t_fvec3 b) { | |||||||
| } | } | ||||||
|  |  | ||||||
| /* TODO: fast_sqrt version? */ | /* TODO: fast_sqrt version? */ | ||||||
| static inline t_fvec3 fvec3_norm(t_fvec3 a) { | static inline Vec3 vec3_norm(Vec3 a) { | ||||||
|     const float n = sqrtf(fvec3_dot(a, a)); |     const float n = sqrtf(vec3_dot(a, a)); | ||||||
|     /* TODO: do we need truncating over epsilon as cglm does? */ |     /* TODO: do we need truncating over epsilon as cglm does? */ | ||||||
|     return fvec3_scale(a, 1.0f / n); |     return vec3_scale(a, 1.0f / n); | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline t_fvec3 fvec3_rotate(t_fvec3 v, float angle, t_fvec3 axis) { | static inline Vec3 vec3_rotate(Vec3 v, float angle, Vec3 axis) { | ||||||
|     /* from cglm */ |     /* from cglm */ | ||||||
|     t_fvec3 v1, v2, k; |     Vec3 v1, v2, k; | ||||||
|     float c, s; |     float c, s; | ||||||
|  |  | ||||||
|     c = cosf(angle); |     c = cosf(angle); | ||||||
|     s = sinf(angle); |     s = sinf(angle); | ||||||
|  |  | ||||||
|     k = fvec3_norm(axis); |     k = vec3_norm(axis); | ||||||
|  |  | ||||||
|     /* Right Hand, Rodrigues' rotation formula: |     /* Right Hand, Rodrigues' rotation formula: | ||||||
|         v = v*cos(t) + (kxv)sin(t) + k*(k.v)(1 - cos(t)) |         v = v*cos(t) + (kxv)sin(t) + k*(k.v)(1 - cos(t)) | ||||||
|     */ |     */ | ||||||
|     v1 = fvec3_scale(v, c); |     v1 = vec3_scale(v, c); | ||||||
|  |  | ||||||
|     v2 = fvec3_cross(k, v); |     v2 = vec3_cross(k, v); | ||||||
|     v2 = fvec3_scale(v2, s); |     v2 = vec3_scale(v2, s); | ||||||
|  |  | ||||||
|     v1 = fvec3_add(v1, v2); |     v1 = vec3_add(v1, v2); | ||||||
|  |  | ||||||
|     v2 = fvec3_scale(k, fvec3_dot(k, v) * (1.0f - c)); |     v2 = vec3_scale(k, vec3_dot(k, v) * (1.0f - c)); | ||||||
|     v = fvec3_add(v1, v2); |     v = vec3_add(v1, v2); | ||||||
|  |  | ||||||
|     return v; |     return v; | ||||||
| } | } | ||||||
|  |  | ||||||
| #define m_to_fvec2(p_any_vec2) (_Generic((p_any_vec2),          \ | #define m_vec2_from(p_any_vec2) (_Generic((p_any_vec2),       \ | ||||||
|                                     t_vec2:   fvec2_from_vec2,  \ |                                     Vec2i:  vec2_from_vec2i,  \ | ||||||
|                                     t_shvec2: fvec2_from_shvec2 \ |                                     Vec2sh: vec2_from_vec2sh  \ | ||||||
|                                 )(p_any_vec2)) |                                 )(p_any_vec2)) | ||||||
|  |  | ||||||
| #define m_vec_sub(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0),   \ | #define m_vec_sub(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0),   \ | ||||||
|                                     t_fvec3:   fvec3_sub            \ |                                     Vec3:   vec3_sub                \ | ||||||
|                                 )(p_any_vec0, p_any_vec1)) |                                 )(p_any_vec0, p_any_vec1)) | ||||||
|  |  | ||||||
| #define m_vec_div(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0),   \ | #define m_vec_div(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0),   \ | ||||||
|                                     t_fvec2:   fvec2_div            \ |                                     Vec2:   vec2_div                \ | ||||||
|                                 )(p_any_vec0, p_any_vec1)) |                                 )(p_any_vec0, p_any_vec1)) | ||||||
|  |  | ||||||
| #define m_vec_scale(p_any_vec, p_any_scalar) (_Generic((p_any_vec),    \ | #define m_vec_scale(p_any_vec, p_any_scalar) (_Generic((p_any_vec),    \ | ||||||
|                                     t_fvec2:   fvec2_scale,             \ |                                     Vec2:   vec2_scale,                \ | ||||||
|                                     t_fvec3:   fvec3_scale              \ |                                     Vec3:   vec3_scale                 \ | ||||||
|                                 )(p_any_vec, p_any_scalar)) |                                 )(p_any_vec, p_any_scalar)) | ||||||
|  |  | ||||||
| #define m_vec_dot(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0),   \ | #define m_vec_dot(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0),   \ | ||||||
|                                     t_fvec3:   fvec3_dot            \ |                                     Vec3:   vec3_dot                \ | ||||||
|                                 )(p_any_vec0, p_any_vec1)) |                                 )(p_any_vec0, p_any_vec1)) | ||||||
|  |  | ||||||
| #define m_vec_cross(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0),      \ | #define m_vec_cross(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0),      \ | ||||||
|                                     t_fvec3:   fvec3_cross              \ |                                     Vec3:   vec3_cross                   \ | ||||||
|                                 )(p_any_vec0, p_any_vec1)) |                                 )(p_any_vec0, p_any_vec1)) | ||||||
|  |  | ||||||
| #define m_vec_norm(p_any_vec) (_Generic((p_any_vec),            \ | #define m_vec_norm(p_any_vec) (_Generic((p_any_vec),            \ | ||||||
|                                     t_fvec3:   fvec3_norm       \ |                                     Vec3:   vec3_norm           \ | ||||||
|                                 )(p_any_vec)) |                                 )(p_any_vec)) | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -7,14 +7,14 @@ | |||||||
| #include <stb_ds.h> | #include <stb_ds.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| void push_circle(t_fvec2 position, float radius, t_color color) { | void push_circle(Vec2 position, float radius, Color color) { | ||||||
|     struct circle_primitive circle = { |     CirclePrimitive circle = { | ||||||
|         .radius = radius, |         .radius = radius, | ||||||
|         .color = color, |         .color = color, | ||||||
|         .position = position, |         .position = position, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     struct primitive_2d primitive = { |     Primitive2D primitive = { | ||||||
|         .type = PRIMITIVE_2D_CIRCLE, |         .type = PRIMITIVE_2D_CIRCLE, | ||||||
|         .circle = circle, |         .circle = circle, | ||||||
|     }; |     }; | ||||||
| @@ -24,8 +24,8 @@ void push_circle(t_fvec2 position, float radius, t_color color) { | |||||||
|  |  | ||||||
| /* TODO: caching and reuse scheme */ | /* TODO: caching and reuse scheme */ | ||||||
| /* vertices_out and indices_out MUST BE FREED */ | /* vertices_out and indices_out MUST BE FREED */ | ||||||
| void create_circle_geometry(t_fvec2 position, | void create_circle_geometry(Vec2 position, | ||||||
|                                    t_color color, |                                    Color color, | ||||||
|                                    float radius, |                                    float radius, | ||||||
|                                    size_t num_vertices, |                                    size_t num_vertices, | ||||||
|                                    SDL_Vertex **vertices_out, |                                    SDL_Vertex **vertices_out, | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| #include "twn_util.h" | #include "twn_util.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| gpu_texture create_gpu_texture(enum texture_filter filter, bool generate_mipmaps) { | GPUTexture create_gpu_texture(TextureFilter filter, bool generate_mipmaps) { | ||||||
|     GLuint texture; |     GLuint texture; | ||||||
|     glGenTextures(1, &texture); |     glGenTextures(1, &texture); | ||||||
|     glBindTexture(GL_TEXTURE_2D, texture); |     glBindTexture(GL_TEXTURE_2D, texture); | ||||||
| @@ -29,12 +29,12 @@ gpu_texture create_gpu_texture(enum texture_filter filter, bool generate_mipmaps | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void delete_gpu_texture(gpu_texture texture) { | void delete_gpu_texture(GPUTexture texture) { | ||||||
|     glDeleteTextures(1, &texture); |     glDeleteTextures(1, &texture); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void upload_gpu_texture(gpu_texture texture, void *pixels, int channels, int width, int height) { | void upload_gpu_texture(GPUTexture texture, void *pixels, int channels, int width, int height) { | ||||||
|     glBindTexture(GL_TEXTURE_2D, texture); |     glBindTexture(GL_TEXTURE_2D, texture); | ||||||
|  |  | ||||||
|     int format_internal, format; |     int format_internal, format; | ||||||
| @@ -66,6 +66,6 @@ void upload_gpu_texture(gpu_texture texture, void *pixels, int channels, int wid | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void bind_gpu_texture(gpu_texture texture) { | void bind_gpu_texture(GPUTexture texture) { | ||||||
|     glBindTexture(GL_TEXTURE_2D, texture); |     glBindTexture(GL_TEXTURE_2D, texture); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,50 +11,50 @@ | |||||||
| /* TODO: use int16_t for uvs */ | /* TODO: use int16_t for uvs */ | ||||||
| /* TODO: use packed types? */ | /* TODO: use packed types? */ | ||||||
| /* TODO: int16_t could be used for positioning, but we would need to have more CPU calcs */ | /* TODO: int16_t could be used for positioning, but we would need to have more CPU calcs */ | ||||||
| struct element_indexed_quad { | typedef struct ElementIndexedQuad { | ||||||
|     /* upper-left */ |     /* upper-left */ | ||||||
|     t_fvec2 v0; |     Vec2 v0; | ||||||
|     t_fvec2 uv0; |     Vec2 uv0; | ||||||
|     t_color c0; |     Color c0; | ||||||
|     /* bottom-left */ |     /* bottom-left */ | ||||||
|     t_fvec2 v1; |     Vec2 v1; | ||||||
|     t_fvec2 uv1; |     Vec2 uv1; | ||||||
|     t_color c1; |     Color c1; | ||||||
|     /* bottom-right */ |     /* bottom-right */ | ||||||
|     t_fvec2 v2; |     Vec2 v2; | ||||||
|     t_fvec2 uv2; |     Vec2 uv2; | ||||||
|     t_color c2; |     Color c2; | ||||||
|     /* upper-right */ |     /* upper-right */ | ||||||
|     t_fvec2 v3; |     Vec2 v3; | ||||||
|     t_fvec2 uv3; |     Vec2 uv3; | ||||||
|     t_color c3; |     Color c3; | ||||||
| }; | } ElementIndexedQuad; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct element_indexed_quad_without_color { | typedef struct ElementIndexedQuadWithoutColor { | ||||||
|     /* upper-left */ |     /* upper-left */ | ||||||
|     t_fvec2 v0; |     Vec2 v0; | ||||||
|     t_fvec2 uv0; |     Vec2 uv0; | ||||||
|     /* bottom-left */ |     /* bottom-left */ | ||||||
|     t_fvec2 v1; |     Vec2 v1; | ||||||
|     t_fvec2 uv1; |     Vec2 uv1; | ||||||
|     /* bottom-right */ |     /* bottom-right */ | ||||||
|     t_fvec2 v2; |     Vec2 v2; | ||||||
|     t_fvec2 uv2; |     Vec2 uv2; | ||||||
|     /* upper-right */ |     /* upper-right */ | ||||||
|     t_fvec2 v3; |     Vec2 v3; | ||||||
|     t_fvec2 uv3; |     Vec2 uv3; | ||||||
| }; | } ElementIndexedQuadWithoutColor; | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef enum { | typedef enum { | ||||||
|     PIPELINE_NO, |     PIPELINE_NO, | ||||||
|     PIPELINE_SPACE, |     PIPELINE_SPACE, | ||||||
|     PIPELINE_2D, |     PIPELINE_2D, | ||||||
| } pipeline; | } Pipeline; | ||||||
|  |  | ||||||
|  |  | ||||||
| static pipeline pipeline_last_used = PIPELINE_NO; | static Pipeline pipeline_last_used = PIPELINE_NO; | ||||||
|  |  | ||||||
|  |  | ||||||
| void use_space_pipeline(void) { | void use_space_pipeline(void) { | ||||||
| @@ -117,7 +117,7 @@ void use_2d_pipeline(void) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void upload_quad_vertices(t_frect rect) { | void upload_quad_vertices(Rect rect) { | ||||||
|     /* client memory needs to be reachable on glDraw*, so */ |     /* client memory needs to be reachable on glDraw*, so */ | ||||||
|     static float vertices[6 * 2]; |     static float vertices[6 * 2]; | ||||||
|  |  | ||||||
| @@ -132,7 +132,7 @@ void upload_quad_vertices(t_frect rect) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void render_rectangle(const struct rect_primitive *rectangle) { | void render_rectangle(const RectPrimitive *rectangle) { | ||||||
|     glColor4ub(rectangle->color.r, rectangle->color.g, |     glColor4ub(rectangle->color.r, rectangle->color.g, | ||||||
|                rectangle->color.b, rectangle->color.a); |                rectangle->color.b, rectangle->color.a); | ||||||
|  |  | ||||||
| @@ -144,7 +144,7 @@ void render_rectangle(const struct rect_primitive *rectangle) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void render_circle(const struct circle_primitive *circle) { | void render_circle(const CirclePrimitive *circle) { | ||||||
|     SDL_Vertex *vertices = NULL; |     SDL_Vertex *vertices = NULL; | ||||||
|     int *indices = NULL; |     int *indices = NULL; | ||||||
|     int num_vertices = (int)circle->radius; |     int num_vertices = (int)circle->radius; | ||||||
| @@ -181,7 +181,7 @@ void render_circle(const struct circle_primitive *circle) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void use_texture_mode(enum texture_mode mode) { | void use_texture_mode(TextureMode mode) { | ||||||
|     if (mode == TEXTURE_MODE_GHOSTLY) { |     if (mode == TEXTURE_MODE_GHOSTLY) { | ||||||
|         glEnable(GL_BLEND); |         glEnable(GL_BLEND); | ||||||
|         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||||
| @@ -203,21 +203,21 @@ void use_texture_mode(enum texture_mode mode) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| vertex_buffer_builder build_vertex_buffer(vertex_buffer buffer, size_t bytes) { | VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes) { | ||||||
|     glBindBuffer(GL_ARRAY_BUFFER, buffer); |     glBindBuffer(GL_ARRAY_BUFFER, buffer); | ||||||
|     glBufferData(GL_ARRAY_BUFFER, bytes, NULL, GL_STREAM_DRAW); |     glBufferData(GL_ARRAY_BUFFER, bytes, NULL, GL_STREAM_DRAW); | ||||||
|     void *mapping = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); |     void *mapping = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); | ||||||
|     if (!mapping) |     if (!mapping) | ||||||
|         CRY("build_vertex_buffer", "Error mapping a vertex array buffer"); |         CRY("build_vertex_buffer", "Error mapping a vertex array buffer"); | ||||||
|  |  | ||||||
|     return (vertex_buffer_builder) { |     return (VertexBufferBuilder) { | ||||||
|         .mapping = mapping, |         .mapping = mapping, | ||||||
|         .bytes_left = bytes, |         .bytes_left = bytes, | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool push_to_vertex_buffer_builder(vertex_buffer_builder *builder, | bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder, | ||||||
|                                    void *bytes, size_t size) { |                                    void *bytes, size_t size) { | ||||||
|     if (builder->bytes_left == 0) |     if (builder->bytes_left == 0) | ||||||
|         return false; |         return false; | ||||||
| @@ -237,9 +237,9 @@ bool push_to_vertex_buffer_builder(vertex_buffer_builder *builder, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void finally_render_sprites(const struct primitive_2d primitives[], | void finally_render_sprites(const Primitive2D primitives[], | ||||||
|                             const struct sprite_batch batch, |                             const struct SpriteBatch batch, | ||||||
|                             const vertex_buffer buffer) |                             const VertexBuffer buffer) | ||||||
| { | { | ||||||
|     /* TODO: maybe do, dunno */ |     /* TODO: maybe do, dunno */ | ||||||
|     // glBindBuffer(GL_VERTEX_ARRAY, vertex_buffer); |     // glBindBuffer(GL_VERTEX_ARRAY, vertex_buffer); | ||||||
| @@ -250,13 +250,13 @@ void finally_render_sprites(const struct primitive_2d primitives[], | |||||||
|     GLsizei uvoff; |     GLsizei uvoff; | ||||||
|  |  | ||||||
|     if (!batch.constant_colored) { |     if (!batch.constant_colored) { | ||||||
|         off   = offsetof(struct element_indexed_quad, v1); |         off   = offsetof(ElementIndexedQuad, v1); | ||||||
|         voff  = offsetof(struct element_indexed_quad, v0); |         voff  = offsetof(ElementIndexedQuad, v0); | ||||||
|         uvoff = offsetof(struct element_indexed_quad, uv0); |         uvoff = offsetof(ElementIndexedQuad, uv0); | ||||||
|     } else { |     } else { | ||||||
|         off   = offsetof(struct element_indexed_quad_without_color, v1); |         off   = offsetof(ElementIndexedQuadWithoutColor, v1); | ||||||
|         voff  = offsetof(struct element_indexed_quad_without_color, v0); |         voff  = offsetof(ElementIndexedQuadWithoutColor, v0); | ||||||
|         uvoff = offsetof(struct element_indexed_quad_without_color, uv0); |         uvoff = offsetof(ElementIndexedQuadWithoutColor, uv0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* vertex specification */ |     /* vertex specification */ | ||||||
| @@ -278,7 +278,7 @@ void finally_render_sprites(const struct primitive_2d primitives[], | |||||||
|         glColorPointer(4, |         glColorPointer(4, | ||||||
|                        GL_UNSIGNED_BYTE, |                        GL_UNSIGNED_BYTE, | ||||||
|                        off, |                        off, | ||||||
|                        (void *)offsetof(struct element_indexed_quad, c0)); |                        (void *)offsetof(ElementIndexedQuad, c0)); | ||||||
|     } else |     } else | ||||||
|         glColor4ub(primitives[0].sprite.color.r, |         glColor4ub(primitives[0].sprite.color.r, | ||||||
|                    primitives[0].sprite.color.g, |                    primitives[0].sprite.color.g, | ||||||
| @@ -307,22 +307,22 @@ void finally_render_sprites(const struct primitive_2d primitives[], | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| size_t get_sprite_payload_size(struct sprite_batch batch) { | size_t get_sprite_payload_size(struct SpriteBatch batch) { | ||||||
|     if (batch.constant_colored) |     if (batch.constant_colored) | ||||||
|         return sizeof (struct element_indexed_quad_without_color); |         return sizeof (ElementIndexedQuadWithoutColor); | ||||||
|     else |     else | ||||||
|         return sizeof (struct element_indexed_quad); |         return sizeof (ElementIndexedQuad); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool push_sprite_payload_to_vertex_buffer_builder(struct sprite_batch batch, | bool push_sprite_payload_to_vertex_buffer_builder(struct SpriteBatch batch, | ||||||
|                                                   vertex_buffer_builder *builder, |                                                   VertexBufferBuilder *builder, | ||||||
|                                                   t_fvec2 v0, t_fvec2 v1, t_fvec2 v2, t_fvec2 v3, |                                                   Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3, | ||||||
|                                                   t_fvec2 uv0, t_fvec2 uv1, t_fvec2 uv2, t_fvec2 uv3, |                                                   Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3, | ||||||
|                                                   t_color color) |                                                   Color color) | ||||||
| { | { | ||||||
|     if (!batch.constant_colored) { |     if (!batch.constant_colored) { | ||||||
|         struct element_indexed_quad buffer_element = { |         ElementIndexedQuad buffer_element = { | ||||||
|             .v0 = v0, |             .v0 = v0, | ||||||
|             .v1 = v1, |             .v1 = v1, | ||||||
|             .v2 = v2, |             .v2 = v2, | ||||||
| @@ -343,7 +343,7 @@ bool push_sprite_payload_to_vertex_buffer_builder(struct sprite_batch batch, | |||||||
|         return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element); |         return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element); | ||||||
|  |  | ||||||
|     } else { |     } else { | ||||||
|         struct element_indexed_quad_without_color buffer_element = { |         ElementIndexedQuadWithoutColor buffer_element = { | ||||||
|             .v0 = v0, |             .v0 = v0, | ||||||
|             .v1 = v1, |             .v1 = v1, | ||||||
|             .v2 = v2, |             .v2 = v2, | ||||||
| @@ -360,9 +360,9 @@ bool push_sprite_payload_to_vertex_buffer_builder(struct sprite_batch batch, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void finally_draw_uncolored_space_traingle_batch(const struct mesh_batch *batch, | void finally_draw_uncolored_space_traingle_batch(const MeshBatch *batch, | ||||||
|                                                  const t_texture_key texture_key, |                                                  const TextureKey texture_key, | ||||||
|                                                  const vertex_buffer buffer) |                                                  const VertexBuffer buffer) | ||||||
| { | { | ||||||
|     const size_t primitives_len = arrlenu(batch->primitives); |     const size_t primitives_len = arrlenu(batch->primitives); | ||||||
|  |  | ||||||
| @@ -374,15 +374,15 @@ void finally_draw_uncolored_space_traingle_batch(const struct mesh_batch *batch, | |||||||
|     glEnableClientState(GL_VERTEX_ARRAY); |     glEnableClientState(GL_VERTEX_ARRAY); | ||||||
|     glVertexPointer(3, |     glVertexPointer(3, | ||||||
|                     GL_FLOAT, |                     GL_FLOAT, | ||||||
|                     offsetof(struct uncolored_space_triangle_payload, v1), |                     offsetof(struct UncoloredSpaceTrianglePayload, v1), | ||||||
|                     (void *)offsetof(struct uncolored_space_triangle_payload, v0)); |                     (void *)offsetof(struct UncoloredSpaceTrianglePayload, v0)); | ||||||
|  |  | ||||||
|     glEnableClientState(GL_TEXTURE_COORD_ARRAY); |     glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|     glClientActiveTexture(GL_TEXTURE0); |     glClientActiveTexture(GL_TEXTURE0); | ||||||
|     glTexCoordPointer(2, |     glTexCoordPointer(2, | ||||||
|                       GL_FLOAT, |                       GL_FLOAT, | ||||||
|                       offsetof(struct uncolored_space_triangle_payload, v1), |                       offsetof(struct UncoloredSpaceTrianglePayload, v1), | ||||||
|                       (void *)offsetof(struct uncolored_space_triangle_payload, uv0)); |                       (void *)offsetof(struct UncoloredSpaceTrianglePayload, uv0)); | ||||||
|  |  | ||||||
|     /* commit for drawing */ |     /* commit for drawing */ | ||||||
|     glDrawArrays(GL_TRIANGLES, 0, 3 * (GLint)primitives_len); |     glDrawArrays(GL_TRIANGLES, 0, 3 * (GLint)primitives_len); | ||||||
| @@ -396,32 +396,32 @@ void finally_draw_uncolored_space_traingle_batch(const struct mesh_batch *batch, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool push_text_payload_to_vertex_buffer_builder(struct font_data const *font_data, | bool push_text_payload_to_vertex_buffer_builder(FontData const *font_data, | ||||||
|                                                 vertex_buffer_builder *builder, |                                                 VertexBufferBuilder *builder, | ||||||
|                                                 stbtt_aligned_quad quad) |                                                 stbtt_aligned_quad quad) | ||||||
| { | { | ||||||
|     (void)font_data; |     (void)font_data; | ||||||
|  |  | ||||||
|     struct element_indexed_quad_without_color buffer_element = { |     ElementIndexedQuadWithoutColor buffer_element = { | ||||||
|         .v0 = (t_fvec2){ quad.x0, quad.y0 }, |         .v0 = (Vec2){ quad.x0, quad.y0 }, | ||||||
|         .v1 = (t_fvec2){ quad.x1, quad.y0 }, |         .v1 = (Vec2){ quad.x1, quad.y0 }, | ||||||
|         .v2 = (t_fvec2){ quad.x1, quad.y1 }, |         .v2 = (Vec2){ quad.x1, quad.y1 }, | ||||||
|         .v3 = (t_fvec2){ quad.x0, quad.y1 }, |         .v3 = (Vec2){ quad.x0, quad.y1 }, | ||||||
|  |  | ||||||
|         .uv0 = (t_fvec2){ quad.s0, quad.t0 }, |         .uv0 = (Vec2){ quad.s0, quad.t0 }, | ||||||
|         .uv1 = (t_fvec2){ quad.s1, quad.t0 }, |         .uv1 = (Vec2){ quad.s1, quad.t0 }, | ||||||
|         .uv2 = (t_fvec2){ quad.s1, quad.t1 }, |         .uv2 = (Vec2){ quad.s1, quad.t1 }, | ||||||
|         .uv3 = (t_fvec2){ quad.s0, quad.t1 }, |         .uv3 = (Vec2){ quad.s0, quad.t1 }, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element); |     return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void finally_draw_text(struct font_data const *font_data, | void finally_draw_text(FontData const *font_data, | ||||||
|                        size_t len, |                        size_t len, | ||||||
|                        t_color color, |                        Color color, | ||||||
|                        vertex_buffer buffer) |                        VertexBuffer buffer) | ||||||
| { | { | ||||||
|     (void)buffer; |     (void)buffer; | ||||||
|  |  | ||||||
| @@ -429,15 +429,15 @@ void finally_draw_text(struct font_data const *font_data, | |||||||
|     glEnableClientState(GL_VERTEX_ARRAY); |     glEnableClientState(GL_VERTEX_ARRAY); | ||||||
|     glVertexPointer(2, |     glVertexPointer(2, | ||||||
|                     GL_FLOAT, |                     GL_FLOAT, | ||||||
|                     offsetof(struct element_indexed_quad_without_color, v1), |                     offsetof(ElementIndexedQuadWithoutColor, v1), | ||||||
|                     (void *)(size_t)offsetof(struct element_indexed_quad_without_color, v0)); |                     (void *)(size_t)offsetof(ElementIndexedQuadWithoutColor, v0)); | ||||||
|  |  | ||||||
|     glEnableClientState(GL_TEXTURE_COORD_ARRAY); |     glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|     glClientActiveTexture(GL_TEXTURE0); |     glClientActiveTexture(GL_TEXTURE0); | ||||||
|     glTexCoordPointer(2, |     glTexCoordPointer(2, | ||||||
|                       GL_FLOAT, |                       GL_FLOAT, | ||||||
|                       offsetof(struct element_indexed_quad_without_color, v1), |                       offsetof(ElementIndexedQuadWithoutColor, v1), | ||||||
|                       (void *)(size_t)offsetof(struct element_indexed_quad_without_color, uv0)); |                       (void *)(size_t)offsetof(ElementIndexedQuadWithoutColor, uv0)); | ||||||
|  |  | ||||||
|     bind_quad_element_buffer(); |     bind_quad_element_buffer(); | ||||||
|  |  | ||||||
| @@ -462,5 +462,5 @@ void finally_draw_text(struct font_data const *font_data, | |||||||
|  |  | ||||||
|  |  | ||||||
| size_t get_text_payload_size(void) { | size_t get_text_payload_size(void) { | ||||||
|     return sizeof (struct element_indexed_quad_without_color); |     return sizeof (ElementIndexedQuadWithoutColor); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -14,19 +14,19 @@ void setup_viewport(int x, int y, int width, int height) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| vertex_buffer create_vertex_buffer(void) { | VertexBuffer create_vertex_buffer(void) { | ||||||
|     GLuint result; |     GLuint result; | ||||||
|     glGenBuffers(1, &result); |     glGenBuffers(1, &result); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void delete_vertex_buffer(vertex_buffer buffer) { | void delete_vertex_buffer(VertexBuffer buffer) { | ||||||
|     glDeleteBuffers(1, &buffer); |     glDeleteBuffers(1, &buffer); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void specify_vertex_buffer(vertex_buffer buffer, void *data, size_t bytes) { | void specify_vertex_buffer(VertexBuffer buffer, void *data, size_t bytes) { | ||||||
|     glBindBuffer(GL_ARRAY_BUFFER, buffer); |     glBindBuffer(GL_ARRAY_BUFFER, buffer); | ||||||
|     glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW); |     glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,19 +3,19 @@ | |||||||
|  |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
| typedef GLuint gpu_texture; | typedef GLuint GPUTexture; | ||||||
|  |  | ||||||
| enum texture_filter { | typedef enum TextureFilter { | ||||||
|     TEXTURE_FILTER_NEAREAST, |     TEXTURE_FILTER_NEAREAST, | ||||||
|     TEXTURE_FILTER_LINEAR, |     TEXTURE_FILTER_LINEAR, | ||||||
| }; | } TextureFilter; | ||||||
|  |  | ||||||
| gpu_texture create_gpu_texture(enum texture_filter filter, bool generate_mipmaps); | GPUTexture create_gpu_texture(TextureFilter filter, bool generate_mipmaps); | ||||||
|  |  | ||||||
| void delete_gpu_texture(gpu_texture texture); | void delete_gpu_texture(GPUTexture texture); | ||||||
|  |  | ||||||
| void upload_gpu_texture(gpu_texture texture, void *pixels, int channels, int width, int height); | void upload_gpu_texture(GPUTexture texture, void *pixels, int channels, int width, int height); | ||||||
|  |  | ||||||
| void bind_gpu_texture(gpu_texture texture); | void bind_gpu_texture(GPUTexture texture); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -17,8 +17,8 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| /* TODO: have a default initialized one */ | /* TODO: have a default initialized one */ | ||||||
| t_matrix4 camera_projection_matrix; | Matrix4 camera_projection_matrix; | ||||||
| t_matrix4 camera_look_at_matrix; | Matrix4 camera_look_at_matrix; | ||||||
|  |  | ||||||
|  |  | ||||||
| void render_queue_clear(void) { | void render_queue_clear(void) { | ||||||
| @@ -41,13 +41,13 @@ void render_queue_clear(void) { | |||||||
|  |  | ||||||
|  |  | ||||||
| /* rectangle */ | /* rectangle */ | ||||||
| void push_rectangle(t_frect rect, t_color color) { | void push_rectangle(Rect rect, Color color) { | ||||||
|     struct rect_primitive rectangle = { |     RectPrimitive rectangle = { | ||||||
|         .rect = rect, |         .rect = rect, | ||||||
|         .color = color, |         .color = color, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     struct primitive_2d primitive = { |     Primitive2D primitive = { | ||||||
|         .type = PRIMITIVE_2D_RECT, |         .type = PRIMITIVE_2D_RECT, | ||||||
|         .rect = rectangle, |         .rect = rectangle, | ||||||
|     }; |     }; | ||||||
| @@ -64,11 +64,11 @@ static void render_2d(void) { | |||||||
|     size_t batch_count = 0; |     size_t batch_count = 0; | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < render_queue_len; ++i) { |     for (size_t i = 0; i < render_queue_len; ++i) { | ||||||
|         const struct primitive_2d *current = &ctx.render_queue_2d[i]; |         const Primitive2D *current = &ctx.render_queue_2d[i]; | ||||||
|  |  | ||||||
|         switch (current->type) { |         switch (current->type) { | ||||||
|             case PRIMITIVE_2D_SPRITE: { |             case PRIMITIVE_2D_SPRITE: { | ||||||
|                 const struct sprite_batch batch = |                 const struct SpriteBatch batch = | ||||||
|                     collect_sprite_batch(current, render_queue_len - i); |                     collect_sprite_batch(current, render_queue_len - i); | ||||||
|  |  | ||||||
|                 /* TODO: what's even the point? just use OR_EQUAL comparison */ |                 /* TODO: what's even the point? just use OR_EQUAL comparison */ | ||||||
| @@ -140,7 +140,7 @@ void render(void) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void set_camera(const t_camera *const camera) { | void set_camera(const Camera *const camera) { | ||||||
|     /* TODO: skip recaulculating if it's the same? */ |     /* TODO: skip recaulculating if it's the same? */ | ||||||
|     camera_projection_matrix = camera_perspective(camera); |     camera_projection_matrix = camera_perspective(camera); | ||||||
|     camera_look_at_matrix    = camera_look_at(camera); |     camera_look_at_matrix    = camera_look_at(camera); | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
| #define TWN_RENDERING_C_H | #define TWN_RENDERING_C_H | ||||||
|  |  | ||||||
| #include "twn_textures_c.h" | #include "twn_textures_c.h" | ||||||
|  | #include "twn_text_c.h" | ||||||
| #include "twn_util.h" | #include "twn_util.h" | ||||||
| #include "twn_option.h" | #include "twn_option.h" | ||||||
|  |  | ||||||
| @@ -16,107 +17,107 @@ | |||||||
|  |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
| extern t_matrix4 camera_projection_matrix; | extern Matrix4 camera_projection_matrix; | ||||||
| extern t_matrix4 camera_look_at_matrix; | extern Matrix4 camera_look_at_matrix; | ||||||
|  |  | ||||||
| #define QUAD_ELEMENT_BUFFER_LENGTH (65536 / 6) | #define QUAD_ELEMENT_BUFFER_LENGTH (65536 / 6) | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef GLuint vertex_buffer; | typedef GLuint VertexBuffer; | ||||||
|  |  | ||||||
| typedef struct vertex_buffer_builder { | typedef struct VertexBufferBuilder { | ||||||
|     size_t bytes_left; |     size_t bytes_left; | ||||||
|     void *mapping; |     void *mapping; | ||||||
| } vertex_buffer_builder; | } VertexBufferBuilder; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct sprite_primitive { | typedef struct SpritePrimitive { | ||||||
|     t_frect rect; |     Rect rect; | ||||||
|     t_color color; |     Color color; | ||||||
|     float rotation; |     float rotation; | ||||||
|     t_texture_key texture_key; |     TextureKey texture_key; | ||||||
|     bool flip_x; |     bool flip_x; | ||||||
|     bool flip_y; |     bool flip_y; | ||||||
|     bool repeat; |     bool repeat; | ||||||
|  |  | ||||||
|     m_option_list( |     m_option_list( | ||||||
|         t_frect, texture_region ) |         Rect, texture_region ) | ||||||
| }; | } SpritePrimitive; | ||||||
|  |  | ||||||
| struct rect_primitive { | typedef struct RectPrimitive { | ||||||
|     t_frect rect; |     Rect rect; | ||||||
|     t_color color; |     Color color; | ||||||
| }; | } RectPrimitive; | ||||||
|  |  | ||||||
| struct circle_primitive { | typedef struct CirclePrimitive { | ||||||
|     float radius; |     float radius; | ||||||
|     t_color color; |     Color color; | ||||||
|     t_fvec2 position; |     Vec2 position; | ||||||
| }; | } CirclePrimitive; | ||||||
|  |  | ||||||
| struct text_primitive { | typedef struct TextPrimitive { | ||||||
|     t_color color; |     Color color; | ||||||
|     t_fvec2 position; |     Vec2 position; | ||||||
|     char *text; |     char *text; | ||||||
|     const char *font; |     const char *font; | ||||||
|     int height_px; |     int height_px; | ||||||
| }; | } TextPrimitive; | ||||||
|  |  | ||||||
| enum primitive_2d_type { | typedef enum Primitive2DType { | ||||||
|     PRIMITIVE_2D_SPRITE, |     PRIMITIVE_2D_SPRITE, | ||||||
|     PRIMITIVE_2D_RECT, |     PRIMITIVE_2D_RECT, | ||||||
|     PRIMITIVE_2D_CIRCLE, |     PRIMITIVE_2D_CIRCLE, | ||||||
|     PRIMITIVE_2D_TEXT, |     PRIMITIVE_2D_TEXT, | ||||||
| }; | } Primitive2DType; | ||||||
|  |  | ||||||
| struct primitive_2d { | typedef struct Primitive2D { | ||||||
|     enum primitive_2d_type type; |     Primitive2DType type; | ||||||
|  |  | ||||||
|     union { |     union { | ||||||
|         struct sprite_primitive sprite; |         SpritePrimitive sprite; | ||||||
|         struct rect_primitive rect; |         RectPrimitive rect; | ||||||
|         struct circle_primitive circle; |         CirclePrimitive circle; | ||||||
|         struct text_primitive text; |         TextPrimitive text; | ||||||
|     }; |     }; | ||||||
| }; | } Primitive2D; | ||||||
|  |  | ||||||
| /* union for in-place recalculation of texture coordinates */ | /* union for in-place recalculation of texture coordinates */ | ||||||
| union uncolored_space_triangle { | union UncoloredSpaceTriangle { | ||||||
|     /* pending for sending, uvs are not final as texture atlases could update */ |     /* pending for sending, uvs are not final as texture atlases could update */ | ||||||
|     struct uncolored_space_triangle_primitive { |     struct UncoloredSpaceTrianglePrimitive { | ||||||
|         t_fvec3 v0; |         Vec3 v0; | ||||||
|         t_fvec2 uv0; /* in pixels */ |         Vec2 uv0; /* in pixels */ | ||||||
|         t_fvec3 v1; |         Vec3 v1; | ||||||
|         t_fvec2 uv1; /* in pixels */ |         Vec2 uv1; /* in pixels */ | ||||||
|         t_fvec3 v2; |         Vec3 v2; | ||||||
|         t_fvec2 uv2; /* in pixels */ |         Vec2 uv2; /* in pixels */ | ||||||
|     } primitive; |     } primitive; | ||||||
|  |  | ||||||
|     /* TODO: have it packed? */ |     /* TODO: have it packed? */ | ||||||
|     /* structure that is passed in opengl vertex array */ |     /* structure that is passed in opengl vertex array */ | ||||||
|     struct uncolored_space_triangle_payload { |     struct UncoloredSpaceTrianglePayload { | ||||||
|         t_fvec3 v0; |         Vec3 v0; | ||||||
|         t_fvec2 uv0; |         Vec2 uv0; | ||||||
|         t_fvec3 v1; |         Vec3 v1; | ||||||
|         t_fvec2 uv1; |         Vec2 uv1; | ||||||
|         t_fvec3 v2; |         Vec3 v2; | ||||||
|         t_fvec2 uv2; |         Vec2 uv2; | ||||||
|     } payload; |     } payload; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* batch of primitives with overlapping properties */ | /* batch of primitives with overlapping properties */ | ||||||
| struct mesh_batch { | typedef struct MeshBatch { | ||||||
|     uint8_t *primitives; |     uint8_t *primitives; | ||||||
| }; | } MeshBatch; | ||||||
|  |  | ||||||
| struct mesh_batch_item { | typedef struct MeshBatchItem { | ||||||
|     t_texture_key key; |     TextureKey key; | ||||||
|     struct mesh_batch value; |     struct MeshBatch value; | ||||||
| }; | } MeshBatchItem; | ||||||
|  |  | ||||||
| struct text_cache { | typedef struct TextCache { | ||||||
|     struct font_data **data; |     struct FontData **data; | ||||||
| }; | } TextCache; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* renders the background, then the primitives in all render queues */ | /* renders the background, then the primitives in all render queues */ | ||||||
| @@ -125,47 +126,47 @@ void render(void); | |||||||
| /* clears all render queues */ | /* clears all render queues */ | ||||||
| void render_queue_clear(void); | void render_queue_clear(void); | ||||||
|  |  | ||||||
| void create_circle_geometry(t_fvec2 position, | void create_circle_geometry(Vec2 position, | ||||||
|                             t_color color, |                             Color color, | ||||||
|                             float radius, |                             float radius, | ||||||
|                             size_t num_vertices, |                             size_t num_vertices, | ||||||
|                             SDL_Vertex **vertices_out, |                             SDL_Vertex **vertices_out, | ||||||
|                             int **indices_out); |                             int **indices_out); | ||||||
|  |  | ||||||
| struct sprite_batch { | struct SpriteBatch { | ||||||
|     size_t size;             /* how many primitives are in current batch */ |     size_t size;             /* how many primitives are in current batch */ | ||||||
|     enum texture_mode mode; |     TextureMode mode; | ||||||
|     bool constant_colored;   /* whether colored batch is uniformly colored */ |     bool constant_colored;   /* whether colored batch is uniformly colored */ | ||||||
|     bool repeat;             /* whether repeat is needed */ |     bool repeat;             /* whether repeat is needed */ | ||||||
| } collect_sprite_batch(const struct primitive_2d primitives[], size_t len); | } collect_sprite_batch(const Primitive2D primitives[], size_t len); | ||||||
|  |  | ||||||
| void render_sprites(const struct primitive_2d primitives[], | void render_sprites(const Primitive2D primitives[], | ||||||
|                     const struct sprite_batch batch); |                     const struct SpriteBatch batch); | ||||||
|  |  | ||||||
| void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, | void draw_uncolored_space_traingle_batch(MeshBatch *batch, | ||||||
|                                          t_texture_key texture_key); |                                          TextureKey texture_key); | ||||||
|  |  | ||||||
| /* text */ | /* text */ | ||||||
|  |  | ||||||
| void render_text(const struct text_primitive *text); | void render_text(const TextPrimitive *text); | ||||||
|  |  | ||||||
| void text_cache_init(struct text_cache *cache); | void text_cache_init(TextCache *cache); | ||||||
|  |  | ||||||
| void text_cache_deinit(struct text_cache *cache); | void text_cache_deinit(TextCache *cache); | ||||||
|  |  | ||||||
| /* vertex buffer */ | /* vertex buffer */ | ||||||
|  |  | ||||||
| vertex_buffer create_vertex_buffer(void); | VertexBuffer create_vertex_buffer(void); | ||||||
|  |  | ||||||
| void delete_vertex_buffer(vertex_buffer buffer); | void delete_vertex_buffer(VertexBuffer buffer); | ||||||
|  |  | ||||||
| void specify_vertex_buffer(vertex_buffer buffer, void *data, size_t bytes); | void specify_vertex_buffer(VertexBuffer buffer, void *data, size_t bytes); | ||||||
|  |  | ||||||
| /* uses present in 1.5 buffer mapping feature */ | /* uses present in 1.5 buffer mapping feature */ | ||||||
| vertex_buffer_builder build_vertex_buffer(vertex_buffer buffer, size_t bytes); | VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes); | ||||||
|  |  | ||||||
| /* collects bytes for sending to the gpu until all is pushed, which is when false is returned */ | /* collects bytes for sending to the gpu until all is pushed, which is when false is returned */ | ||||||
| bool push_to_vertex_buffer_builder(vertex_buffer_builder *builder, | bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder, | ||||||
|                                    void *bytes, |                                    void *bytes, | ||||||
|                                    size_t size); |                                    size_t size); | ||||||
|  |  | ||||||
| @@ -181,41 +182,41 @@ void set_depth_range(double low, double high); | |||||||
|  |  | ||||||
| void bind_quad_element_buffer(void); | void bind_quad_element_buffer(void); | ||||||
|  |  | ||||||
| void render_circle(const struct circle_primitive *circle); | void render_circle(const CirclePrimitive *circle); | ||||||
|  |  | ||||||
| void render_rectangle(const struct rect_primitive *rectangle); | void render_rectangle(const RectPrimitive *rectangle); | ||||||
|  |  | ||||||
| void use_space_pipeline(void); | void use_space_pipeline(void); | ||||||
|  |  | ||||||
| void use_2d_pipeline(void); | void use_2d_pipeline(void); | ||||||
|  |  | ||||||
| void use_texture_mode(enum texture_mode mode); | void use_texture_mode(TextureMode mode); | ||||||
|  |  | ||||||
| void finally_render_sprites(struct primitive_2d const primitives[], | void finally_render_sprites(Primitive2D const primitives[], | ||||||
|                             struct sprite_batch batch, |                             struct SpriteBatch batch, | ||||||
|                             vertex_buffer buffer); |                             VertexBuffer buffer); | ||||||
|  |  | ||||||
| size_t get_sprite_payload_size(struct sprite_batch batch); | size_t get_sprite_payload_size(struct SpriteBatch batch); | ||||||
|  |  | ||||||
| bool push_sprite_payload_to_vertex_buffer_builder(struct sprite_batch batch, | bool push_sprite_payload_to_vertex_buffer_builder(struct SpriteBatch batch, | ||||||
|                                                   vertex_buffer_builder *builder, |                                                   VertexBufferBuilder *builder, | ||||||
|                                                   t_fvec2 v0, t_fvec2 v1, t_fvec2 v2, t_fvec2 v3, |                                                   Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3, | ||||||
|                                                   t_fvec2 uv0, t_fvec2 uv1, t_fvec2 uv2, t_fvec2 uv3, |                                                   Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3, | ||||||
|                                                   t_color color); |                                                   Color color); | ||||||
|  |  | ||||||
| void finally_draw_uncolored_space_traingle_batch(struct mesh_batch const *batch, | void finally_draw_uncolored_space_traingle_batch(MeshBatch const *batch, | ||||||
|                                                  t_texture_key texture_key, |                                                  TextureKey texture_key, | ||||||
|                                                  vertex_buffer buffer); |                                                  VertexBuffer buffer); | ||||||
|  |  | ||||||
| size_t get_text_payload_size(void); | size_t get_text_payload_size(void); | ||||||
|  |  | ||||||
| bool push_text_payload_to_vertex_buffer_builder(struct font_data const *font_data, | bool push_text_payload_to_vertex_buffer_builder(FontData const *font_data, | ||||||
|                                                 vertex_buffer_builder *builder, |                                                 VertexBufferBuilder *builder, | ||||||
|                                                 stbtt_aligned_quad quad); |                                                 stbtt_aligned_quad quad); | ||||||
|  |  | ||||||
| void finally_draw_text(struct font_data const *font_data, | void finally_draw_text(FontData const *font_data, | ||||||
|                        size_t len, |                        size_t len, | ||||||
|                        t_color color, |                        Color color, | ||||||
|                        vertex_buffer buffer); |                        VertexBuffer buffer); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -17,10 +17,10 @@ | |||||||
|  */ |  */ | ||||||
| /* TODO: it might make sense to infer alpha channel presence / meaningfulness for textures in atlas */ | /* TODO: it might make sense to infer alpha channel presence / meaningfulness for textures in atlas */ | ||||||
| /*          so that they are rendered with no blend / batched in a way to reduce overdraw automatically */ | /*          so that they are rendered with no blend / batched in a way to reduce overdraw automatically */ | ||||||
| void push_sprite(const t_push_sprite_args args) { | void push_sprite(const PushSpriteArgs args) { | ||||||
|     struct sprite_primitive sprite = { |     SpritePrimitive sprite = { | ||||||
|         .rect = args.rect, |         .rect = args.rect, | ||||||
|         .color = m_or(args, color, ((t_color) { 255, 255, 255, 255 })), |         .color = m_or(args, color, ((Color) { 255, 255, 255, 255 })), | ||||||
|         .rotation = m_or(args, rotation, 0.0f), |         .rotation = m_or(args, rotation, 0.0f), | ||||||
|         .texture_key = textures_get_key(&ctx.texture_cache, args.path), |         .texture_key = textures_get_key(&ctx.texture_cache, args.path), | ||||||
|         .flip_x = m_or(args, flip_x, false), |         .flip_x = m_or(args, flip_x, false), | ||||||
| @@ -29,7 +29,7 @@ void push_sprite(const t_push_sprite_args args) { | |||||||
|         m_opt_from(texture_region, args, texture_region) |         m_opt_from(texture_region, args, texture_region) | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     struct primitive_2d primitive = { |     Primitive2D primitive = { | ||||||
|         .type = PRIMITIVE_2D_SPRITE, |         .type = PRIMITIVE_2D_SPRITE, | ||||||
|         .sprite = sprite, |         .sprite = sprite, | ||||||
|     }; |     }; | ||||||
| @@ -38,12 +38,12 @@ void push_sprite(const t_push_sprite_args args) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| struct sprite_batch collect_sprite_batch(const struct primitive_2d primitives[], size_t len) { | struct SpriteBatch collect_sprite_batch(const Primitive2D primitives[], size_t len) { | ||||||
|     /* assumes that first primitive is already a sprite */ |     /* assumes that first primitive is already a sprite */ | ||||||
|     const uint16_t texture_key_id = primitives[0].sprite.texture_key.id; |     const uint16_t texture_key_id = primitives[0].sprite.texture_key.id; | ||||||
|     const int atlas_id = textures_get_atlas_id(&ctx.texture_cache, primitives[0].sprite.texture_key); |     const int atlas_id = textures_get_atlas_id(&ctx.texture_cache, primitives[0].sprite.texture_key); | ||||||
|  |  | ||||||
|     struct sprite_batch batch = { |     struct SpriteBatch batch = { | ||||||
|         .mode = textures_get_mode(&ctx.texture_cache, primitives[0].sprite.texture_key), |         .mode = textures_get_mode(&ctx.texture_cache, primitives[0].sprite.texture_key), | ||||||
|         .constant_colored = true, |         .constant_colored = true, | ||||||
|         .repeat = primitives[0].sprite.repeat, |         .repeat = primitives[0].sprite.repeat, | ||||||
| @@ -56,14 +56,14 @@ struct sprite_batch collect_sprite_batch(const struct primitive_2d primitives[], | |||||||
|         len = QUAD_ELEMENT_BUFFER_LENGTH; |         len = QUAD_ELEMENT_BUFFER_LENGTH; | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < len; ++i) { |     for (size_t i = 0; i < len; ++i) { | ||||||
|         const struct primitive_2d *const current = &primitives[i]; |         const Primitive2D *const current = &primitives[i]; | ||||||
|  |  | ||||||
|         /* don't touch things other than sprites */ |         /* don't touch things other than sprites */ | ||||||
|         if (current->type != PRIMITIVE_2D_SPRITE) |         if (current->type != PRIMITIVE_2D_SPRITE) | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         /* only collect the same blend modes */ |         /* only collect the same blend modes */ | ||||||
|         const enum texture_mode mode = textures_get_mode(&ctx.texture_cache, current->sprite.texture_key); |         const TextureMode mode = textures_get_mode(&ctx.texture_cache, current->sprite.texture_key); | ||||||
|         if (mode != batch.mode) |         if (mode != batch.mode) | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
| @@ -94,32 +94,32 @@ struct sprite_batch collect_sprite_batch(const struct primitive_2d primitives[], | |||||||
|  |  | ||||||
|  |  | ||||||
| /* assumes that orthogonal matrix setup is done already */ | /* assumes that orthogonal matrix setup is done already */ | ||||||
| void render_sprites(const struct primitive_2d primitives[], | void render_sprites(const Primitive2D primitives[], | ||||||
|                            const struct sprite_batch batch) |                     const struct SpriteBatch batch) | ||||||
| { | { | ||||||
|     /* single vertex array is used for every batch with NULL glBufferData() trick at the end */ |     /* single vertex array is used for every batch with NULL glBufferData() trick at the end */ | ||||||
|     static vertex_buffer vertex_array = 0; |     static VertexBuffer vertex_array = 0; | ||||||
|     if (vertex_array == 0) |     if (vertex_array == 0) | ||||||
|         vertex_array = create_vertex_buffer(); |         vertex_array = create_vertex_buffer(); | ||||||
|  |  | ||||||
|     use_texture_mode(batch.mode); |     use_texture_mode(batch.mode); | ||||||
|  |  | ||||||
|     const t_frect dims = |     const Rect dims = | ||||||
|         textures_get_dims(&ctx.texture_cache, primitives->sprite.texture_key); |         textures_get_dims(&ctx.texture_cache, primitives->sprite.texture_key); | ||||||
|  |  | ||||||
|     /* vertex population over a vertex buffer builder interface */ |     /* vertex population over a vertex buffer builder interface */ | ||||||
|     { |     { | ||||||
|         vertex_buffer_builder payload = build_vertex_buffer(vertex_array, get_sprite_payload_size(batch) * batch.size); |         VertexBufferBuilder payload = build_vertex_buffer(vertex_array, get_sprite_payload_size(batch) * batch.size); | ||||||
|  |  | ||||||
|         for (size_t i = 0; i < batch.size; ++i) { |         for (size_t i = 0; i < batch.size; ++i) { | ||||||
|             /* render opaques front to back */ |             /* render opaques front to back */ | ||||||
|             const size_t cur = batch.mode == TEXTURE_MODE_GHOSTLY ? i : batch.size - i - 1; |             const size_t cur = batch.mode == TEXTURE_MODE_GHOSTLY ? i : batch.size - i - 1; | ||||||
|             const struct sprite_primitive sprite = primitives[cur].sprite; |             const SpritePrimitive sprite = primitives[cur].sprite; | ||||||
|  |  | ||||||
|             const t_frect srcrect = |             const Rect srcrect = | ||||||
|                 textures_get_srcrect(&ctx.texture_cache, primitives[cur].sprite.texture_key); |                 textures_get_srcrect(&ctx.texture_cache, primitives[cur].sprite.texture_key); | ||||||
|  |  | ||||||
|             t_fvec2 uv0, uv1, uv2, uv3; |             Vec2 uv0, uv1, uv2, uv3; | ||||||
|  |  | ||||||
|             if (!sprite.repeat) { |             if (!sprite.repeat) { | ||||||
|                 const float wr = srcrect.w / dims.w; |                 const float wr = srcrect.w / dims.w; | ||||||
| @@ -128,20 +128,20 @@ void render_sprites(const struct primitive_2d primitives[], | |||||||
|                 const float yr = srcrect.y / dims.h; |                 const float yr = srcrect.y / dims.h; | ||||||
|  |  | ||||||
|                 if (!m_is_set(sprite, texture_region)) { |                 if (!m_is_set(sprite, texture_region)) { | ||||||
|                     uv0 = (t_fvec2){ xr + wr *  sprite.flip_x, yr + hr *  sprite.flip_y }; |                     uv0 = (Vec2){ xr + wr *  sprite.flip_x, yr + hr *  sprite.flip_y }; | ||||||
|                     uv1 = (t_fvec2){ xr + wr *  sprite.flip_x, yr + hr * !sprite.flip_y }; |                     uv1 = (Vec2){ xr + wr *  sprite.flip_x, yr + hr * !sprite.flip_y }; | ||||||
|                     uv2 = (t_fvec2){ xr + wr * !sprite.flip_x, yr + hr * !sprite.flip_y }; |                     uv2 = (Vec2){ xr + wr * !sprite.flip_x, yr + hr * !sprite.flip_y }; | ||||||
|                     uv3 = (t_fvec2){ xr + wr * !sprite.flip_x, yr + hr *  sprite.flip_y }; |                     uv3 = (Vec2){ xr + wr * !sprite.flip_x, yr + hr *  sprite.flip_y }; | ||||||
|                 } else { |                 } else { | ||||||
|                     const float offx = (sprite.texture_region_opt.x / srcrect.w) * (srcrect.w / dims.w); |                     const float offx = (sprite.texture_region_opt.x / srcrect.w) * (srcrect.w / dims.w); | ||||||
|                     const float offy = (sprite.texture_region_opt.y / srcrect.h) * (srcrect.h / dims.h); |                     const float offy = (sprite.texture_region_opt.y / srcrect.h) * (srcrect.h / dims.h); | ||||||
|                     const float offw = (1.0f - (sprite.texture_region_opt.w / srcrect.w)) * (srcrect.w / dims.w); |                     const float offw = (1.0f - (sprite.texture_region_opt.w / srcrect.w)) * (srcrect.w / dims.w); | ||||||
|                     const float offh = (1.0f - (sprite.texture_region_opt.h / srcrect.h)) * (srcrect.h / dims.h); |                     const float offh = (1.0f - (sprite.texture_region_opt.h / srcrect.h)) * (srcrect.h / dims.h); | ||||||
|  |  | ||||||
|                     uv0 = (t_fvec2){ xr + offx + wr *  sprite.flip_x, yr + offy + hr *  sprite.flip_y }; |                     uv0 = (Vec2){ xr + offx + wr *  sprite.flip_x, yr + offy + hr *  sprite.flip_y }; | ||||||
|                     uv1 = (t_fvec2){ xr + offx + wr *  sprite.flip_x, yr - offh + hr * !sprite.flip_y }; |                     uv1 = (Vec2){ xr + offx + wr *  sprite.flip_x, yr - offh + hr * !sprite.flip_y }; | ||||||
|                     uv2 = (t_fvec2){ xr - offw + wr * !sprite.flip_x, yr - offh + hr * !sprite.flip_y }; |                     uv2 = (Vec2){ xr - offw + wr * !sprite.flip_x, yr - offh + hr * !sprite.flip_y }; | ||||||
|                     uv3 = (t_fvec2){ xr - offw + wr * !sprite.flip_x, yr + offy + hr *  sprite.flip_y }; |                     uv3 = (Vec2){ xr - offw + wr * !sprite.flip_x, yr + offy + hr *  sprite.flip_y }; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 /* try fitting texture into supplied destination rectangle */ |                 /* try fitting texture into supplied destination rectangle */ | ||||||
| @@ -149,10 +149,10 @@ void render_sprites(const struct primitive_2d primitives[], | |||||||
|                 const float rx = sprite.rect.w / srcrect.w; |                 const float rx = sprite.rect.w / srcrect.w; | ||||||
|                 const float ry = sprite.rect.h / srcrect.h; |                 const float ry = sprite.rect.h / srcrect.h; | ||||||
|  |  | ||||||
|                 uv0 = (t_fvec2){ rx *  sprite.flip_x, ry *  sprite.flip_y }; |                 uv0 = (Vec2){ rx *  sprite.flip_x, ry *  sprite.flip_y }; | ||||||
|                 uv1 = (t_fvec2){ rx *  sprite.flip_x, ry * !sprite.flip_y }; |                 uv1 = (Vec2){ rx *  sprite.flip_x, ry * !sprite.flip_y }; | ||||||
|                 uv2 = (t_fvec2){ rx * !sprite.flip_x, ry * !sprite.flip_y }; |                 uv2 = (Vec2){ rx * !sprite.flip_x, ry * !sprite.flip_y }; | ||||||
|                 uv3 = (t_fvec2){ rx * !sprite.flip_x, ry *  sprite.flip_y }; |                 uv3 = (Vec2){ rx * !sprite.flip_x, ry *  sprite.flip_y }; | ||||||
|  |  | ||||||
|                 if (m_is_set(sprite, texture_region)) { |                 if (m_is_set(sprite, texture_region)) { | ||||||
|                     /* displace origin */ |                     /* displace origin */ | ||||||
| @@ -165,44 +165,44 @@ void render_sprites(const struct primitive_2d primitives[], | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             t_fvec2 v0, v1, v2, v3; |             Vec2 v0, v1, v2, v3; | ||||||
|  |  | ||||||
|             /* todo: fast PI/2 degree divisible rotations? */ |             /* todo: fast PI/2 degree divisible rotations? */ | ||||||
|             if (sprite.rotation == 0.0f) { |             if (sprite.rotation == 0.0f) { | ||||||
|                 /* non-rotated case */ |                 /* non-rotated case */ | ||||||
|  |  | ||||||
|                 v0 = (t_fvec2){ sprite.rect.x,                 sprite.rect.y }; |                 v0 = (Vec2){ sprite.rect.x,                 sprite.rect.y }; | ||||||
|                 v1 = (t_fvec2){ sprite.rect.x,                 sprite.rect.y + sprite.rect.h }; |                 v1 = (Vec2){ sprite.rect.x,                 sprite.rect.y + sprite.rect.h }; | ||||||
|                 v2 = (t_fvec2){ sprite.rect.x + sprite.rect.w, sprite.rect.y + sprite.rect.h }; |                 v2 = (Vec2){ sprite.rect.x + sprite.rect.w, sprite.rect.y + sprite.rect.h }; | ||||||
|                 v3 = (t_fvec2){ sprite.rect.x + sprite.rect.w, sprite.rect.y }; |                 v3 = (Vec2){ sprite.rect.x + sprite.rect.w, sprite.rect.y }; | ||||||
|  |  | ||||||
|             } else if (sprite.rect.w == sprite.rect.h) { |             } else if (sprite.rect.w == sprite.rect.h) { | ||||||
|                 /* rotated square case */ |                 /* rotated square case */ | ||||||
|  |  | ||||||
|                 const t_fvec2 c = frect_center(sprite.rect); |                 const Vec2 c = frect_center(sprite.rect); | ||||||
|                 const t_fvec2 t = fast_cossine(sprite.rotation + (float)M_PI_4); |                 const Vec2 t = fast_cossine(sprite.rotation + (float)M_PI_4); | ||||||
|                 const t_fvec2 d = { |                 const Vec2 d = { | ||||||
|                     .x = t.x * sprite.rect.w * (float)M_SQRT1_2, |                     .x = t.x * sprite.rect.w * (float)M_SQRT1_2, | ||||||
|                     .y = t.y * sprite.rect.h * (float)M_SQRT1_2, |                     .y = t.y * sprite.rect.h * (float)M_SQRT1_2, | ||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 v0 = (t_fvec2){ c.x - d.x, c.y - d.y }; |                 v0 = (Vec2){ c.x - d.x, c.y - d.y }; | ||||||
|                 v1 = (t_fvec2){ c.x - d.y, c.y + d.x }; |                 v1 = (Vec2){ c.x - d.y, c.y + d.x }; | ||||||
|                 v2 = (t_fvec2){ c.x + d.x, c.y + d.y }; |                 v2 = (Vec2){ c.x + d.x, c.y + d.y }; | ||||||
|                 v3 = (t_fvec2){ c.x + d.y, c.y - d.x }; |                 v3 = (Vec2){ c.x + d.y, c.y - d.x }; | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
|                 /* rotated non-square case*/ |                 /* rotated non-square case*/ | ||||||
|  |  | ||||||
|                 const t_fvec2 c = frect_center(sprite.rect); |                 const Vec2 c = frect_center(sprite.rect); | ||||||
|                 const t_fvec2 t = fast_cossine(sprite.rotation); |                 const Vec2 t = fast_cossine(sprite.rotation); | ||||||
|  |  | ||||||
|                 const t_fvec2 h = { sprite.rect.w / 2, sprite.rect.h / 2 }; |                 const Vec2 h = { sprite.rect.w / 2, sprite.rect.h / 2 }; | ||||||
|  |  | ||||||
|                 v0 = (t_fvec2){ c.x + t.x * -h.x - t.y * -h.y, c.y + t.y * -h.x + t.x * -h.y }; |                 v0 = (Vec2){ c.x + t.x * -h.x - t.y * -h.y, c.y + t.y * -h.x + t.x * -h.y }; | ||||||
|                 v1 = (t_fvec2){ c.x + t.x * -h.x - t.y * +h.y, c.y + t.y * -h.x + t.x * +h.y }; |                 v1 = (Vec2){ c.x + t.x * -h.x - t.y * +h.y, c.y + t.y * -h.x + t.x * +h.y }; | ||||||
|                 v2 = (t_fvec2){ c.x + t.x * +h.x - t.y * +h.y, c.y + t.y * +h.x + t.x * +h.y }; |                 v2 = (Vec2){ c.x + t.x * +h.x - t.y * +h.y, c.y + t.y * +h.x + t.x * +h.y }; | ||||||
|                 v3 = (t_fvec2){ c.x + t.x * +h.x - t.y * -h.y, c.y + t.y * +h.x + t.x * -h.y }; |                 v3 = (Vec2){ c.x + t.x * +h.x - t.y * -h.y, c.y + t.y * +h.x + t.x * -h.y }; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             push_sprite_payload_to_vertex_buffer_builder(batch, &payload, v0, v1, v2, v3, uv0, uv1, uv2, uv3, sprite.color); |             push_sprite_payload_to_vertex_buffer_builder(batch, &payload, v0, v1, v2, v3, uv0, uv1, uv2, uv3, sprite.color); | ||||||
|   | |||||||
| @@ -12,26 +12,8 @@ | |||||||
| #define NUM_DISPLAY_ASCII ((ASCII_END - ASCII_START) + 1) | #define NUM_DISPLAY_ASCII ((ASCII_END - ASCII_START) + 1) | ||||||
|  |  | ||||||
|  |  | ||||||
| struct font_data { | static FontData *text_load_font_data(const char *path, int height_px) { | ||||||
|     stbtt_packedchar char_data[NUM_DISPLAY_ASCII]; |     FontData *font_data = ccalloc(1, sizeof *font_data); | ||||||
|     stbtt_fontinfo info; |  | ||||||
|  |  | ||||||
|     const char *file_path; |  | ||||||
|     unsigned char *file_bytes; |  | ||||||
|     size_t file_bytes_len; |  | ||||||
|  |  | ||||||
|     gpu_texture texture; |  | ||||||
|  |  | ||||||
|     int height_px; |  | ||||||
|     float scale_factor; |  | ||||||
|     int ascent; |  | ||||||
|     int descent; |  | ||||||
|     int line_gap; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static struct font_data *text_load_font_data(const char *path, int height_px) { |  | ||||||
|     struct font_data *font_data = ccalloc(1, sizeof *font_data); |  | ||||||
|     font_data->file_path = path; |     font_data->file_path = path; | ||||||
|     font_data->height_px = height_px; |     font_data->height_px = height_px; | ||||||
|  |  | ||||||
| @@ -77,21 +59,21 @@ static struct font_data *text_load_font_data(const char *path, int height_px) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void text_destroy_font_data(struct font_data *font_data) { | static void text_destroy_font_data(FontData *font_data) { | ||||||
|     free(font_data->file_bytes); |     free(font_data->file_bytes); | ||||||
|     delete_gpu_texture(font_data->texture); |     delete_gpu_texture(font_data->texture); | ||||||
|     free(font_data); |     free(font_data); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void text_draw_with(struct font_data* font_data, char* text, t_fvec2 position, t_color color) { | static void text_draw_with(FontData* font_data, char* text, Vec2 position, Color color) { | ||||||
|     static vertex_buffer vertex_array = 0; |     VertexBuffer vertex_array = 0; | ||||||
|     if (vertex_array == 0) |     if (vertex_array == 0) | ||||||
|         vertex_array = create_vertex_buffer(); |         vertex_array = create_vertex_buffer(); | ||||||
|  |  | ||||||
|     const size_t len = SDL_strlen(text); |     const size_t len = SDL_strlen(text); | ||||||
|  |  | ||||||
|     vertex_buffer_builder payload = build_vertex_buffer(vertex_array, get_text_payload_size() * len); |     VertexBufferBuilder payload = build_vertex_buffer(vertex_array, get_text_payload_size() * len); | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < len; ++i) { |     for (size_t i = 0; i < len; ++i) { | ||||||
|         const char c = text[i]; |         const char c = text[i]; | ||||||
| @@ -131,21 +113,21 @@ static void ensure_font_cache(const char *font_path, int height_px) { | |||||||
|     /* HACK: stupid, bad, don't do this */ |     /* HACK: stupid, bad, don't do this */ | ||||||
|     bool is_cached = false; |     bool is_cached = false; | ||||||
|     for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) { |     for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) { | ||||||
|         struct font_data *font_data = ctx.text_cache.data[i]; |         FontData *font_data = ctx.text_cache.data[i]; | ||||||
|         if ((strcmp(font_path, font_data->file_path) == 0) && height_px == font_data->height_px) { |         if ((strcmp(font_path, font_data->file_path) == 0) && height_px == font_data->height_px) { | ||||||
|             is_cached = true; |             is_cached = true; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if (!is_cached) { |     if (!is_cached) { | ||||||
|         struct font_data *new_font_data = text_load_font_data(font_path, height_px); |         FontData *new_font_data = text_load_font_data(font_path, height_px); | ||||||
|         arrput(ctx.text_cache.data, new_font_data); |         arrput(ctx.text_cache.data, new_font_data); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static struct font_data *get_font_data(const char *font_path, int height_px) { | static FontData *get_font_data(const char *font_path, int height_px) { | ||||||
|     struct font_data *font_data = NULL; |     FontData *font_data = NULL; | ||||||
|     for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) { |     for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) { | ||||||
|         font_data = ctx.text_cache.data[i]; |         font_data = ctx.text_cache.data[i]; | ||||||
|         if ((strcmp(font_path, font_data->file_path) == 0) && height_px == font_data->height_px) { |         if ((strcmp(font_path, font_data->file_path) == 0) && height_px == font_data->height_px) { | ||||||
| @@ -156,18 +138,18 @@ static struct font_data *get_font_data(const char *font_path, int height_px) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void render_text(const struct text_primitive *text) { | void render_text(const TextPrimitive *text) { | ||||||
|     struct font_data *font_data = get_font_data(text->font, text->height_px); |     FontData *font_data = get_font_data(text->font, text->height_px); | ||||||
|     text_draw_with(font_data, text->text, text->position, text->color); |     text_draw_with(font_data, text->text, text->position, text->color); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void text_cache_init(struct text_cache *cache) { | void text_cache_init(TextCache *cache) { | ||||||
|     arrsetlen(cache->data, 0); |     arrsetlen(cache->data, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void text_cache_deinit(struct text_cache *cache) { | void text_cache_deinit(TextCache *cache) { | ||||||
|     for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) { |     for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) { | ||||||
|         text_destroy_font_data(ctx.text_cache.data[i]); |         text_destroy_font_data(ctx.text_cache.data[i]); | ||||||
|     } |     } | ||||||
| @@ -176,7 +158,7 @@ void text_cache_deinit(struct text_cache *cache) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void push_text(char *string, t_fvec2 position, int height_px, t_color color, const char *font_path) { | void push_text(char *string, Vec2 position, int height_px, Color color, const char *font_path) { | ||||||
|     ensure_font_cache(font_path, height_px); |     ensure_font_cache(font_path, height_px); | ||||||
|  |  | ||||||
|     /* the string might not be around by the time it's used, so copy it */ |     /* the string might not be around by the time it's used, so copy it */ | ||||||
| @@ -185,7 +167,7 @@ void push_text(char *string, t_fvec2 position, int height_px, t_color color, con | |||||||
|     char *dup_string = cmalloc(strlen(string) + 1); |     char *dup_string = cmalloc(strlen(string) + 1); | ||||||
|     strcpy(dup_string, string); |     strcpy(dup_string, string); | ||||||
|  |  | ||||||
|     struct text_primitive text = { |     TextPrimitive text = { | ||||||
|         .color = color, |         .color = color, | ||||||
|         .position = position, |         .position = position, | ||||||
|         .text = dup_string, |         .text = dup_string, | ||||||
| @@ -193,7 +175,7 @@ void push_text(char *string, t_fvec2 position, int height_px, t_color color, con | |||||||
|         .height_px = height_px, |         .height_px = height_px, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     struct primitive_2d primitive = { |     Primitive2D primitive = { | ||||||
|         .type = PRIMITIVE_2D_TEXT, |         .type = PRIMITIVE_2D_TEXT, | ||||||
|         .text = text, |         .text = text, | ||||||
|     }; |     }; | ||||||
| @@ -204,7 +186,7 @@ void push_text(char *string, t_fvec2 position, int height_px, t_color color, con | |||||||
|  |  | ||||||
| int get_text_width(char *string, int height_px, const char *font_path) { | int get_text_width(char *string, int height_px, const char *font_path) { | ||||||
|     ensure_font_cache(font_path, height_px); |     ensure_font_cache(font_path, height_px); | ||||||
|     struct font_data *font_data = get_font_data(font_path, height_px); |     FontData *font_data = get_font_data(font_path, height_px); | ||||||
|  |  | ||||||
|     int length = 0; |     int length = 0; | ||||||
|     for (const char *p = string; *p != '\0'; ++p) { |     for (const char *p = string; *p != '\0'; ++p) { | ||||||
|   | |||||||
| @@ -1,3 +1,10 @@ | |||||||
|  | #ifndef TWN_TEXT_C_H | ||||||
|  | #define TWN_TEXT_C_H | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include "twn_gpu_texture_c.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stb_truetype.h> | #include <stb_truetype.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -6,7 +13,7 @@ | |||||||
| #define NUM_DISPLAY_ASCII ((ASCII_END - ASCII_START) + 1) | #define NUM_DISPLAY_ASCII ((ASCII_END - ASCII_START) + 1) | ||||||
|  |  | ||||||
|  |  | ||||||
| struct font_data { | typedef struct FontData { | ||||||
|     stbtt_packedchar char_data[NUM_DISPLAY_ASCII]; |     stbtt_packedchar char_data[NUM_DISPLAY_ASCII]; | ||||||
|     stbtt_fontinfo info; |     stbtt_fontinfo info; | ||||||
|  |  | ||||||
| @@ -14,11 +21,14 @@ struct font_data { | |||||||
|     unsigned char *file_bytes; |     unsigned char *file_bytes; | ||||||
|     size_t file_bytes_len; |     size_t file_bytes_len; | ||||||
|  |  | ||||||
|     gpu_texture texture; |     GPUTexture texture; | ||||||
|  |  | ||||||
|     int height_px; |     int height_px; | ||||||
|     float scale_factor; |     float scale_factor; | ||||||
|     int ascent; |     int ascent; | ||||||
|     int descent; |     int descent; | ||||||
|     int line_gap; |     int line_gap; | ||||||
| }; | } FontData; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif | ||||||
|   | |||||||
| @@ -9,42 +9,42 @@ | |||||||
| /* TODO: automatic handling of repeating textures */ | /* TODO: automatic handling of repeating textures */ | ||||||
| /*       for that we could allocate a loner texture */ | /*       for that we could allocate a loner texture */ | ||||||
| void unfurl_triangle(const char *path, | void unfurl_triangle(const char *path, | ||||||
|                      t_fvec3 v0, |                      Vec3 v0, | ||||||
|                      t_fvec3 v1, |                      Vec3 v1, | ||||||
|                      t_fvec3 v2, |                      Vec3 v2, | ||||||
|                      t_shvec2 uv0, |                      Vec2sh uv0, | ||||||
|                      t_shvec2 uv1, |                      Vec2sh uv1, | ||||||
|                      t_shvec2 uv2) |                      Vec2sh uv2) | ||||||
| { | { | ||||||
|     const t_texture_key texture_key = textures_get_key(&ctx.texture_cache, path); |     const TextureKey texture_key = textures_get_key(&ctx.texture_cache, path); | ||||||
|  |  | ||||||
|     struct mesh_batch_item *batch_p = hmgetp_null(ctx.uncolored_mesh_batches, texture_key); |     struct MeshBatchItem *batch_p = hmgetp_null(ctx.uncolored_mesh_batches, texture_key); | ||||||
|     if (!batch_p) { |     if (!batch_p) { | ||||||
|         struct mesh_batch item = {0}; |         struct MeshBatch item = {0}; | ||||||
|         hmput(ctx.uncolored_mesh_batches, texture_key, item); |         hmput(ctx.uncolored_mesh_batches, texture_key, item); | ||||||
|         batch_p = &ctx.uncolored_mesh_batches[hmlenu(ctx.uncolored_mesh_batches) - 1]; /* TODO: can last index be used? */ |         batch_p = &ctx.uncolored_mesh_batches[hmlenu(ctx.uncolored_mesh_batches) - 1]; /* TODO: can last index be used? */ | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     union uncolored_space_triangle triangle = { .primitive = { |     union UncoloredSpaceTriangle triangle = { .primitive = { | ||||||
|         .v0 = v0, |         .v0 = v0, | ||||||
|         .v1 = v1, |         .v1 = v1, | ||||||
|         .v2 = v2, |         .v2 = v2, | ||||||
|         .uv1 = m_to_fvec2(uv1), |         .uv1 = m_vec2_from(uv1), | ||||||
|         .uv0 = m_to_fvec2(uv0), |         .uv0 = m_vec2_from(uv0), | ||||||
|         .uv2 = m_to_fvec2(uv2), |         .uv2 = m_vec2_from(uv2), | ||||||
|     }}; |     }}; | ||||||
|  |  | ||||||
|     union uncolored_space_triangle *triangles = (union uncolored_space_triangle *)batch_p->value.primitives; |     union UncoloredSpaceTriangle *triangles = (union UncoloredSpaceTriangle *)batch_p->value.primitives; | ||||||
|  |  | ||||||
|     arrpush(triangles, triangle); |     arrpush(triangles, triangle); | ||||||
|     batch_p->value.primitives = (uint8_t *)triangles; |     batch_p->value.primitives = (uint8_t *)triangles; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, | void draw_uncolored_space_traingle_batch(struct MeshBatch *batch, | ||||||
|                                          t_texture_key texture_key) |                                          TextureKey texture_key) | ||||||
| { | { | ||||||
|     static vertex_buffer vertex_array = 0; |     static VertexBuffer vertex_array = 0; | ||||||
|     if (vertex_array == 0) |     if (vertex_array == 0) | ||||||
|         vertex_array = create_vertex_buffer(); |         vertex_array = create_vertex_buffer(); | ||||||
|  |  | ||||||
| @@ -54,8 +54,8 @@ void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, | |||||||
|     if (primitives_len == 0) |     if (primitives_len == 0) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|     const t_frect srcrect = textures_get_srcrect(&ctx.texture_cache, texture_key); |     const Rect srcrect = textures_get_srcrect(&ctx.texture_cache, texture_key); | ||||||
|     const t_frect dims    = textures_get_dims(&ctx.texture_cache, texture_key); |     const Rect dims    = textures_get_dims(&ctx.texture_cache, texture_key); | ||||||
|  |  | ||||||
|     const float wr = srcrect.w / dims.w; |     const float wr = srcrect.w / dims.w; | ||||||
|     const float hr = srcrect.h / dims.h; |     const float hr = srcrect.h / dims.h; | ||||||
| @@ -64,8 +64,8 @@ void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, | |||||||
|  |  | ||||||
|     /* update pixel-based uvs to correspond with texture atlases */ |     /* update pixel-based uvs to correspond with texture atlases */ | ||||||
|     for (size_t i = 0; i < primitives_len; ++i) { |     for (size_t i = 0; i < primitives_len; ++i) { | ||||||
|         struct uncolored_space_triangle_payload *payload = |         struct UncoloredSpaceTrianglePayload *payload = | ||||||
|             &((union uncolored_space_triangle *)batch->primitives)[i].payload; |             &((union UncoloredSpaceTriangle *)batch->primitives)[i].payload; | ||||||
|  |  | ||||||
|         payload->uv0.x = xr + ((float)payload->uv0.x / srcrect.w) * wr; |         payload->uv0.x = xr + ((float)payload->uv0.x / srcrect.w) * wr; | ||||||
|         payload->uv0.y = yr + ((float)payload->uv0.y / srcrect.h) * hr; |         payload->uv0.y = yr + ((float)payload->uv0.y / srcrect.h) * hr; | ||||||
| @@ -75,7 +75,7 @@ void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, | |||||||
|         payload->uv2.y = yr + ((float)payload->uv2.y / srcrect.h) * hr; |         payload->uv2.y = yr + ((float)payload->uv2.y / srcrect.h) * hr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     specify_vertex_buffer(vertex_array, batch->primitives, primitives_len * sizeof (struct uncolored_space_triangle_payload)); |     specify_vertex_buffer(vertex_array, batch->primitives, primitives_len * sizeof (struct UncoloredSpaceTrianglePayload)); | ||||||
|  |  | ||||||
|     finally_draw_uncolored_space_traingle_batch(batch, texture_key, vertex_array); |     finally_draw_uncolored_space_traingle_batch(batch, texture_key, vertex_array); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,9 +24,9 @@ static const char *audio_exts[audio_file_type_count] = { | |||||||
| /* TODO: count frames without use, free the memory when threshold is met */ | /* TODO: count frames without use, free the memory when threshold is met */ | ||||||
| /* TODO: count repeated usages for sound effect cases with rendering to ram? */ | /* TODO: count repeated usages for sound effect cases with rendering to ram? */ | ||||||
| /* stores path to data hash, useful for sound effects */ | /* stores path to data hash, useful for sound effects */ | ||||||
| static struct audio_file_cache { | static struct AudioFileCache { | ||||||
|     char *key; |     char *key; | ||||||
|     struct audio_file_cache_value { |     struct AudioFileCacheValue { | ||||||
|         unsigned char *data; |         unsigned char *data; | ||||||
|         size_t len; |         size_t len; | ||||||
|     } value; |     } value; | ||||||
| @@ -34,7 +34,7 @@ static struct audio_file_cache { | |||||||
|  |  | ||||||
|  |  | ||||||
| static int64_t get_audio_data(const char *path, unsigned char **data) { | static int64_t get_audio_data(const char *path, unsigned char **data) { | ||||||
|     const struct audio_file_cache *cache = shgetp_null(audio_file_cache, path); |     const struct AudioFileCache *cache = shgetp_null(audio_file_cache, path); | ||||||
|     if (!cache) { |     if (!cache) { | ||||||
|         unsigned char *file; |         unsigned char *file; | ||||||
|         int64_t len = file_to_bytes(path, &file); |         int64_t len = file_to_bytes(path, &file); | ||||||
| @@ -43,7 +43,7 @@ static int64_t get_audio_data(const char *path, unsigned char **data) { | |||||||
|             return -1; |             return -1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const struct audio_file_cache_value value = { file, (size_t)len }; |         const struct AudioFileCacheValue value = { file, (size_t)len }; | ||||||
|         shput(audio_file_cache, path, value); |         shput(audio_file_cache, path, value); | ||||||
|  |  | ||||||
|         *data = file; |         *data = file; | ||||||
| @@ -55,16 +55,16 @@ static int64_t get_audio_data(const char *path, unsigned char **data) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void play_audio(const char *path, const char *channel) { | void audio_play(const char *path, const char *channel) { | ||||||
|     const struct audio_channel_item *pair = shgetp_null(ctx.audio_channels, channel); |     const AudioChannelItem *pair = shgetp_null(ctx.audio_channels, channel); | ||||||
|     if (!pair) |     if (!pair) | ||||||
|         play_audio_ex(path, channel, get_default_audio_args()); |         audio_play_ex(path, channel, audio_get_default_args()); | ||||||
|     else |     else | ||||||
|         play_audio_ex(path, channel, pair->value.args); |         audio_play_ex(path, channel, pair->value.args); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static t_audio_file_type infer_audio_file_type(const char *path) { | static AudioFileType infer_audio_file_type(const char *path) { | ||||||
|     size_t path_len = strlen(path); |     size_t path_len = strlen(path); | ||||||
|  |  | ||||||
|     for (int i = 0; i < audio_file_type_count; ++i) { |     for (int i = 0; i < audio_file_type_count; ++i) { | ||||||
| @@ -73,7 +73,7 @@ static t_audio_file_type infer_audio_file_type(const char *path) { | |||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|         if (strcmp(&path[path_len - ext_length], audio_exts[i]) == 0) |         if (strcmp(&path[path_len - ext_length], audio_exts[i]) == 0) | ||||||
|             return (t_audio_file_type)i; |             return (AudioFileType)i; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return audio_file_type_unknown; |     return audio_file_type_unknown; | ||||||
| @@ -82,7 +82,7 @@ static t_audio_file_type infer_audio_file_type(const char *path) { | |||||||
|  |  | ||||||
| /* TODO: error propagation and clearing of resources on partial success? */ | /* TODO: error propagation and clearing of resources on partial success? */ | ||||||
| /*       or should we expect things to simply fail? */ | /*       or should we expect things to simply fail? */ | ||||||
| static union audio_context init_audio_context(const char *path, t_audio_file_type type) { | static union AudioContext init_audio_context(const char *path, AudioFileType type) { | ||||||
|     switch (type) { |     switch (type) { | ||||||
|     case audio_file_type_ogg: { |     case audio_file_type_ogg: { | ||||||
|         unsigned char *data; |         unsigned char *data; | ||||||
| @@ -101,7 +101,7 @@ static union audio_context init_audio_context(const char *path, t_audio_file_typ | |||||||
|  |  | ||||||
|         stb_vorbis_info info = stb_vorbis_get_info(handle); |         stb_vorbis_info info = stb_vorbis_get_info(handle); | ||||||
|  |  | ||||||
|         return (union audio_context) { |         return (union AudioContext) { | ||||||
|             .vorbis = { |             .vorbis = { | ||||||
|                 .data = data, |                 .data = data, | ||||||
|                 .handle = handle, |                 .handle = handle, | ||||||
| @@ -131,21 +131,21 @@ static union audio_context init_audio_context(const char *path, t_audio_file_typ | |||||||
|  |  | ||||||
|         xm_set_max_loop_count(handle, 1); |         xm_set_max_loop_count(handle, 1); | ||||||
|  |  | ||||||
|         return (union audio_context) { |         return (union AudioContext) { | ||||||
|             .xm = { .handle = handle } |             .xm = { .handle = handle } | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     default: |     default: | ||||||
|         CRY("Audio error", "Unhandled audio format (in init)"); |         CRY("Audio error", "Unhandled audio format (in init)"); | ||||||
|         return (union audio_context){0}; |         return (union AudioContext){0}; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return (union audio_context){0}; |     return (union AudioContext){0}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void repeat_audio(struct audio_channel *channel) { | static void repeat_audio(AudioChannel *channel) { | ||||||
|     switch (channel->file_type) { |     switch (channel->file_type) { | ||||||
|     case audio_file_type_ogg: { |     case audio_file_type_ogg: { | ||||||
|         stb_vorbis_seek_start(channel->context.vorbis.handle); |         stb_vorbis_seek_start(channel->context.vorbis.handle); | ||||||
| @@ -164,13 +164,13 @@ static void repeat_audio(struct audio_channel *channel) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void play_audio_ex(const char *path, const char *channel, t_play_audio_args args) { | void audio_play_ex(const char *path, const char *channel, PlayAudioArgs args) { | ||||||
|     struct audio_channel_item *pair = shgetp_null(ctx.audio_channels, channel); |     AudioChannelItem *pair = shgetp_null(ctx.audio_channels, channel); | ||||||
|  |  | ||||||
|     /* create a channel if it doesn't exist */ |     /* create a channel if it doesn't exist */ | ||||||
|     if (!pair) { |     if (!pair) { | ||||||
|         t_audio_file_type file_type = infer_audio_file_type(path); |         AudioFileType file_type = infer_audio_file_type(path); | ||||||
|         struct audio_channel new_channel = { |         AudioChannel new_channel = { | ||||||
|             .args = args, |             .args = args, | ||||||
|             .file_type = file_type, |             .file_type = file_type, | ||||||
|             .context = init_audio_context(path, file_type), |             .context = init_audio_context(path, file_type), | ||||||
| @@ -189,8 +189,8 @@ void play_audio_ex(const char *path, const char *channel, t_play_audio_args args | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| t_play_audio_args *get_audio_args(const char *channel) { | PlayAudioArgs *audio_get_args(const char *channel) { | ||||||
|     struct audio_channel_item *pair = shgetp_null(ctx.audio_channels, channel); |     AudioChannelItem *pair = shgetp_null(ctx.audio_channels, channel); | ||||||
|     if (!pair) |     if (!pair) | ||||||
|         return NULL; |         return NULL; | ||||||
|  |  | ||||||
| @@ -198,8 +198,8 @@ t_play_audio_args *get_audio_args(const char *channel) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| t_play_audio_args get_default_audio_args(void) { | PlayAudioArgs audio_get_default_args(void) { | ||||||
|     return (t_play_audio_args){ |     return (PlayAudioArgs){ | ||||||
|         .repeat = false, |         .repeat = false, | ||||||
|         .crossfade = false, |         .crossfade = false, | ||||||
|         .volume = 1.0f, |         .volume = 1.0f, | ||||||
| @@ -209,7 +209,7 @@ t_play_audio_args get_default_audio_args(void) { | |||||||
|  |  | ||||||
|  |  | ||||||
| /* this assumes int16_t based streams */ | /* this assumes int16_t based streams */ | ||||||
| static void audio_mixin_streams(const struct audio_channel *channel, | static void audio_mixin_streams(const AudioChannel *channel, | ||||||
|                                 uint8_t *restrict a, |                                 uint8_t *restrict a, | ||||||
|                                 uint8_t *restrict b, |                                 uint8_t *restrict b, | ||||||
|                                 size_t frames) |                                 size_t frames) | ||||||
| @@ -236,7 +236,7 @@ static void audio_mixin_streams(const struct audio_channel *channel, | |||||||
|  |  | ||||||
|  |  | ||||||
| /* remember: sample is data for all channels where frame is a part of it */ | /* remember: sample is data for all channels where frame is a part of it */ | ||||||
| static void audio_sample_and_mixin_channel(const struct audio_channel *channel, | static void audio_sample_and_mixin_channel(const AudioChannel *channel, | ||||||
|                                            uint8_t *stream, |                                            uint8_t *stream, | ||||||
|                                            int len) |                                            int len) | ||||||
| { | { | ||||||
| @@ -323,7 +323,7 @@ static void audio_sample_and_mixin_channel(const struct audio_channel *channel, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void sanity_check_channel(const struct audio_channel *channel) { | static void sanity_check_channel(const AudioChannel *channel) { | ||||||
|     if (channel->args.volume < 0.0f || channel->args.volume > 1.0f) |     if (channel->args.volume < 0.0f || channel->args.volume > 1.0f) | ||||||
|         log_warn("Volume argument is out of range for channel (%s)", channel->name); |         log_warn("Volume argument is out of range for channel (%s)", channel->name); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,15 +13,15 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef enum audio_file_type { | typedef enum AudioFileType { | ||||||
|     audio_file_type_ogg, |     audio_file_type_ogg, | ||||||
|     audio_file_type_xm, |     audio_file_type_xm, | ||||||
|     audio_file_type_count, |     audio_file_type_count, | ||||||
|     audio_file_type_unknown, |     audio_file_type_unknown, | ||||||
| } t_audio_file_type; | } AudioFileType; | ||||||
|  |  | ||||||
|  |  | ||||||
| union audio_context { | union AudioContext { | ||||||
|     struct { |     struct { | ||||||
|         stb_vorbis *handle; |         stb_vorbis *handle; | ||||||
|         unsigned char *data; |         unsigned char *data; | ||||||
| @@ -35,19 +35,19 @@ union audio_context { | |||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct audio_channel { | typedef struct AudioChannel { | ||||||
|     t_play_audio_args args; |     PlayAudioArgs args; | ||||||
|     enum audio_file_type file_type; |     AudioFileType file_type; | ||||||
|     union audio_context context; /* interpreted by `file_type` value */ |     union AudioContext context; /* interpreted by `file_type` value */ | ||||||
|     const char *path; |     const char *path; | ||||||
|     const char *name; |     const char *name; | ||||||
| }; | } AudioChannel; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct audio_channel_item { | typedef struct AudioChannelItem { | ||||||
|     char *key; |     char *key; | ||||||
|     struct audio_channel value; |     struct AudioChannel value; | ||||||
| }; | } AudioChannelItem; | ||||||
|  |  | ||||||
|  |  | ||||||
| void audio_callback(void *userdata, uint8_t *stream, int len); | void audio_callback(void *userdata, uint8_t *stream, int len); | ||||||
|   | |||||||
| @@ -8,12 +8,12 @@ | |||||||
| #define CAMERA_FAR_Z 100.0f | #define CAMERA_FAR_Z 100.0f | ||||||
|  |  | ||||||
|  |  | ||||||
| t_matrix4 camera_look_at(const t_camera *const camera) { | Matrix4 camera_look_at(const Camera *const camera) { | ||||||
|     /* from cglm */ |     /* from cglm */ | ||||||
|     const t_fvec3 r = m_vec_norm(m_vec_cross(camera->target, camera->up)); |     const Vec3 r = m_vec_norm(m_vec_cross(camera->target, camera->up)); | ||||||
|     const t_fvec3 u = m_vec_cross(r, camera->target); |     const Vec3 u = m_vec_cross(r, camera->target); | ||||||
|  |  | ||||||
|     t_matrix4 result; |     Matrix4 result; | ||||||
|  |  | ||||||
|     result.row[0].x =  r.x; |     result.row[0].x =  r.x; | ||||||
|     result.row[0].y =  u.x; |     result.row[0].y =  u.x; | ||||||
| @@ -33,9 +33,9 @@ t_matrix4 camera_look_at(const t_camera *const camera) { | |||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| t_matrix4 camera_perspective(const t_camera *const camera) { | Matrix4 camera_perspective(const Camera *const camera) { | ||||||
|     /* from cglm */ |     /* from cglm */ | ||||||
|     t_matrix4 result = {0}; |     Matrix4 result = {0}; | ||||||
|  |  | ||||||
|     const float aspect = RENDER_BASE_RATIO; |     const float aspect = RENDER_BASE_RATIO; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,4 +2,4 @@ | |||||||
|  |  | ||||||
| /* internally there's only one context, but it gets type casted to game and engine variants based on which header is included */ | /* internally there's only one context, but it gets type casted to game and engine variants based on which header is included */ | ||||||
| /* engine parts should never mix twn_engine_context_c.h with twn_context.h */ | /* engine parts should never mix twn_engine_context_c.h with twn_context.h */ | ||||||
| t_engine_ctx ctx = {0}; | EngineContext ctx = {0}; | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
|  |  | ||||||
| #include "twn_context.h" | #include "twn_context.h" | ||||||
| #include "twn_textures_c.h" | #include "twn_textures_c.h" | ||||||
|  | #include "twn_audio_c.h" | ||||||
| #include "twn_engine_api.h" | #include "twn_engine_api.h" | ||||||
| #include "twn_input.h" | #include "twn_input.h" | ||||||
| #include "rendering/twn_rendering_c.h" | #include "rendering/twn_rendering_c.h" | ||||||
| @@ -13,20 +14,20 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct engine_context { | typedef struct EngineContext { | ||||||
|     /* user code facing context */ |     /* user code facing context */ | ||||||
|     t_ctx game; |     Context game; | ||||||
|  |  | ||||||
|     /* the program's actual argc and argv */ |     /* the program's actual argc and argv */ | ||||||
|     int argc; |     int argc; | ||||||
|     char **argv; |     char **argv; | ||||||
|  |  | ||||||
|     struct primitive_2d *render_queue_2d; |     struct Primitive2D *render_queue_2d; | ||||||
|     struct mesh_batch_item *uncolored_mesh_batches; |     MeshBatchItem *uncolored_mesh_batches; | ||||||
|     struct text_cache text_cache; |     struct TextCache text_cache; | ||||||
|     struct texture_cache texture_cache; |     TextureCache texture_cache; | ||||||
|  |  | ||||||
|     struct audio_channel_item *audio_channels; |     AudioChannelItem *audio_channels; | ||||||
|     SDL_AudioDeviceID audio_device; |     SDL_AudioDeviceID audio_device; | ||||||
|     int audio_stream_frequency; |     int audio_stream_frequency; | ||||||
|     SDL_AudioFormat audio_stream_format; |     SDL_AudioFormat audio_stream_format; | ||||||
| @@ -46,8 +47,8 @@ typedef struct engine_context { | |||||||
|  |  | ||||||
|     bool resync_flag; |     bool resync_flag; | ||||||
|     bool was_successful; |     bool was_successful; | ||||||
| } t_engine_ctx; | } EngineContext; | ||||||
|  |  | ||||||
| TWN_API extern t_engine_ctx ctx; | TWN_API extern EngineContext ctx; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ | |||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| static void update_action_pressed_state(struct input_state *input, struct action *action) { | static void update_action_pressed_state(InputState *input, Action *action) { | ||||||
|     for (size_t i = 0; i < SDL_arraysize(action->bindings); ++i) { |     for (size_t i = 0; i < SDL_arraysize(action->bindings); ++i) { | ||||||
|         switch (action->bindings[i].source) { |         switch (action->bindings[i].source) { | ||||||
|         case BUTTON_SOURCE_NOT_SET: |         case BUTTON_SOURCE_NOT_SET: | ||||||
| @@ -61,21 +61,21 @@ static void update_action_pressed_state(struct input_state *input, struct action | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void input_bind_code_to_action(struct input_state *input, | static void input_bind_code_to_action(InputState *input, | ||||||
|                                       char *action_name, |                                       char *action_name, | ||||||
|                                       enum button_source source, |                                       ButtonSource source, | ||||||
|                                       union button_code code) |                                       union ButtonCode code) | ||||||
| { | { | ||||||
|     struct action_hash_item *action_item = shgetp_null(input->action_hash, action_name); |     ActionHashItem *action_item = shgetp_null(input->action_hash, action_name); | ||||||
|     if (action_item == NULL) { |     if (action_item == NULL) { | ||||||
|         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); |         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     struct action *action = &action_item->value; |     Action *action = &action_item->value; | ||||||
|  |  | ||||||
|     /* check every binding to make sure this code isn't already bound */ |     /* check every binding to make sure this code isn't already bound */ | ||||||
|     for (size_t i = 0; i < SDL_arraysize(action->bindings); ++i) { |     for (size_t i = 0; i < SDL_arraysize(action->bindings); ++i) { | ||||||
|         struct button *binding = &action->bindings[i]; |         Button *binding = &action->bindings[i]; | ||||||
|  |  | ||||||
|         if (binding->source != source) |         if (binding->source != source) | ||||||
|             break; |             break; | ||||||
| @@ -111,30 +111,30 @@ static void input_bind_code_to_action(struct input_state *input, | |||||||
|         memmove(action->bindings, action->bindings + 1, shifted_size); |         memmove(action->bindings, action->bindings + 1, shifted_size); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     action->bindings[action->num_bindings++] = (struct button) { |     action->bindings[action->num_bindings++] = (Button) { | ||||||
|         .source = source, |         .source = source, | ||||||
|         .code = code, |         .code = code, | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void input_unbind_code_from_action(struct input_state *input, | static void input_unbind_code_from_action(InputState *input, | ||||||
|                                           char *action_name, |                                           char *action_name, | ||||||
|                                           enum button_source source, |                                           ButtonSource source, | ||||||
|                                           union button_code code) |                                           union ButtonCode code) | ||||||
| { | { | ||||||
|     struct action_hash_item *action_item = shgetp_null(input->action_hash, action_name); |     ActionHashItem *action_item = shgetp_null(input->action_hash, action_name); | ||||||
|     if (action_item == NULL) { |     if (action_item == NULL) { | ||||||
|         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); |         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     struct action *action = &action_item->value; |     Action *action = &action_item->value; | ||||||
|  |  | ||||||
|     /* check every binding to make sure this code is bound */ |     /* check every binding to make sure this code is bound */ | ||||||
|     size_t index = 0; |     size_t index = 0; | ||||||
|     bool is_bound = false; |     bool is_bound = false; | ||||||
|     for (index = 0; index < SDL_arraysize(action->bindings); ++index) { |     for (index = 0; index < SDL_arraysize(action->bindings); ++index) { | ||||||
|         struct button *binding = &action->bindings[index]; |         Button *binding = &action->bindings[index]; | ||||||
|  |  | ||||||
|         if (binding->source != source) |         if (binding->source != source) | ||||||
|             continue; |             continue; | ||||||
| @@ -174,17 +174,17 @@ static void input_unbind_code_from_action(struct input_state *input, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_state_init(struct input_state *input) { | void input_state_init(InputState *input) { | ||||||
|     sh_new_strdup(input->action_hash); |     sh_new_strdup(input->action_hash); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_state_deinit(struct input_state *input) { | void input_state_deinit(InputState *input) { | ||||||
|     shfree(input->action_hash); |     shfree(input->action_hash); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_state_update(struct input_state *input) { | void input_state_update(InputState *input) { | ||||||
|     input->keyboard_state = SDL_GetKeyboardState(NULL); |     input->keyboard_state = SDL_GetKeyboardState(NULL); | ||||||
|     input->mouse_state = SDL_GetMouseState(&input->mouse_window_position.x, |     input->mouse_state = SDL_GetMouseState(&input->mouse_window_position.x, | ||||||
|                                            &input->mouse_window_position.y); |                                            &input->mouse_window_position.y); | ||||||
| @@ -193,74 +193,74 @@ void input_state_update(struct input_state *input) { | |||||||
|                               &input->mouse_relative_position.y); |                               &input->mouse_relative_position.y); | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < shlenu(input->action_hash); ++i) { |     for (size_t i = 0; i < shlenu(input->action_hash); ++i) { | ||||||
|         struct action *action = &input->action_hash[i].value; |         Action *action = &input->action_hash[i].value; | ||||||
|         update_action_pressed_state(input, action); |         update_action_pressed_state(input, action); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_bind_action_scancode(struct input_state *input, | void input_bind_action_scancode(InputState *input, | ||||||
|                                 char *action_name, |                                 char *action_name, | ||||||
|                                 SDL_Scancode scancode) |                                 SDL_Scancode scancode) | ||||||
| { | { | ||||||
|     input_bind_code_to_action(input, |     input_bind_code_to_action(input, | ||||||
|                               action_name, |                               action_name, | ||||||
|                               BUTTON_SOURCE_KEYBOARD_PHYSICAL, |                               BUTTON_SOURCE_KEYBOARD_PHYSICAL, | ||||||
|                               (union button_code) { .scancode = scancode }); |                               (union ButtonCode) { .scancode = scancode }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_unbind_action_scancode(struct input_state *input, | void input_unbind_action_scancode(InputState *input, | ||||||
|                                   char *action_name, |                                   char *action_name, | ||||||
|                                   SDL_Scancode scancode) |                                   SDL_Scancode scancode) | ||||||
| { | { | ||||||
|     input_unbind_code_from_action(input, |     input_unbind_code_from_action(input, | ||||||
|                                   action_name, |                                   action_name, | ||||||
|                                   BUTTON_SOURCE_KEYBOARD_PHYSICAL, |                                   BUTTON_SOURCE_KEYBOARD_PHYSICAL, | ||||||
|                                   (union button_code) { .scancode = scancode }); |                                   (union ButtonCode) { .scancode = scancode }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_bind_action_mouse(struct input_state *input, | void input_bind_action_mouse(InputState *input, | ||||||
|                              char *action_name, |                              char *action_name, | ||||||
|                              uint8_t mouse_button) |                              uint8_t mouse_button) | ||||||
| { | { | ||||||
|     input_bind_code_to_action(input, |     input_bind_code_to_action(input, | ||||||
|                               action_name, |                               action_name, | ||||||
|                               BUTTON_SOURCE_MOUSE, |                               BUTTON_SOURCE_MOUSE, | ||||||
|                               (union button_code) { .mouse_button = mouse_button}); |                               (union ButtonCode) { .mouse_button = mouse_button}); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_unbind_action_mouse(struct input_state *input, | void input_unbind_action_mouse(InputState *input, | ||||||
|                                char *action_name, |                                char *action_name, | ||||||
|                                uint8_t mouse_button) |                                uint8_t mouse_button) | ||||||
| { | { | ||||||
|     input_unbind_code_from_action(input, |     input_unbind_code_from_action(input, | ||||||
|                                   action_name, |                                   action_name, | ||||||
|                                   BUTTON_SOURCE_MOUSE, |                                   BUTTON_SOURCE_MOUSE, | ||||||
|                                   (union button_code) { .mouse_button = mouse_button}); |                                   (union ButtonCode) { .mouse_button = mouse_button}); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_add_action(struct input_state *input, char *action_name) { | void input_add_action(InputState *input, char *action_name) { | ||||||
|     if (shgeti(input->action_hash, action_name) >= 0) { |     if (shgeti(input->action_hash, action_name) >= 0) { | ||||||
|         log_warn("(%s) Action \"%s\" is already registered.", __func__, action_name); |         log_warn("(%s) Action \"%s\" is already registered.", __func__, action_name); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     shput(input->action_hash, action_name, (struct action) { 0 }); |     shput(input->action_hash, action_name, (Action) { 0 }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_delete_action(struct input_state *input, char *action_name) { | void input_delete_action(InputState *input, char *action_name) { | ||||||
|     if (shdel(input->action_hash, action_name) == 0) |     if (shdel(input->action_hash, action_name) == 0) | ||||||
|         log_warn("(%s) Action \"%s\" is not registered.", __func__, action_name); |         log_warn("(%s) Action \"%s\" is not registered.", __func__, action_name); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool input_is_action_pressed(struct input_state *input, char *action_name) { | bool input_is_action_pressed(InputState *input, char *action_name) { | ||||||
|     struct action_hash_item *action = shgetp_null(input->action_hash, action_name); |     ActionHashItem *action = shgetp_null(input->action_hash, action_name); | ||||||
|     if (action == NULL) { |     if (action == NULL) { | ||||||
|         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); |         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); | ||||||
|         return false; |         return false; | ||||||
| @@ -269,8 +269,8 @@ bool input_is_action_pressed(struct input_state *input, char *action_name) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool input_is_action_just_pressed(struct input_state *input, char *action_name) { | bool input_is_action_just_pressed(InputState *input, char *action_name) { | ||||||
|     struct action_hash_item *action = shgetp_null(input->action_hash, action_name); |     ActionHashItem *action = shgetp_null(input->action_hash, action_name); | ||||||
|     if (action == NULL) { |     if (action == NULL) { | ||||||
|         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); |         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); | ||||||
|         return false; |         return false; | ||||||
| @@ -279,8 +279,8 @@ bool input_is_action_just_pressed(struct input_state *input, char *action_name) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool input_is_action_just_released(struct input_state *input, char *action_name) { | bool input_is_action_just_released(InputState *input, char *action_name) { | ||||||
|     struct action_hash_item *action = shgetp_null(input->action_hash, action_name); |     ActionHashItem *action = shgetp_null(input->action_hash, action_name); | ||||||
|     if (action == NULL) { |     if (action == NULL) { | ||||||
|         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); |         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); | ||||||
|         return false; |         return false; | ||||||
| @@ -289,30 +289,30 @@ bool input_is_action_just_released(struct input_state *input, char *action_name) | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| t_fvec2 input_get_action_position(struct input_state *input, char *action_name) { | Vec2 input_get_action_position(InputState *input, char *action_name) { | ||||||
|     struct action_hash_item *action = shgetp_null(input->action_hash, action_name); |     ActionHashItem *action = shgetp_null(input->action_hash, action_name); | ||||||
|     if (action == NULL) { |     if (action == NULL) { | ||||||
|         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); |         log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name); | ||||||
|         return (t_fvec2) { 0 }; |         return (Vec2) { 0 }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return action->value.position; |     return action->value.position; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_set_mouse_captured(struct input_state *input, bool enabled) { | void input_set_mouse_captured(InputState *input, bool enabled) { | ||||||
|     (void)input; |     (void)input; | ||||||
|     /* TODO: returns -1 if not supported, but like... do we care? */ |     /* TODO: returns -1 if not supported, but like... do we care? */ | ||||||
|     SDL_SetRelativeMouseMode(enabled); |     SDL_SetRelativeMouseMode(enabled); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool input_is_mouse_captured(struct input_state *input) { | bool input_is_mouse_captured(InputState *input) { | ||||||
|     (void)input; |     (void)input; | ||||||
|     return SDL_GetRelativeMouseMode(); |     return SDL_GetRelativeMouseMode(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_reset_state(struct input_state *input) { | void input_reset_state(InputState *input) { | ||||||
|     stbds_shfree(input->action_hash); |     stbds_shfree(input->action_hash); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,6 +3,6 @@ | |||||||
|  |  | ||||||
| #include "twn_input.h" | #include "twn_input.h" | ||||||
|  |  | ||||||
| void input_reset_state(struct input_state *input); | void input_reset_state(InputState *input); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -167,7 +167,7 @@ static void main_loop(void) { | |||||||
|             poll_events(); |             poll_events(); | ||||||
|  |  | ||||||
|             if (ctx.game.window_size_has_changed) { |             if (ctx.game.window_size_has_changed) { | ||||||
|                 t_vec2 size; |                 Vec2i size; | ||||||
|                 SDL_GetWindowSize(ctx.window, &size.x, &size.y); |                 SDL_GetWindowSize(ctx.window, &size.x, &size.y); | ||||||
|                 ctx.game.window_w = size.x; |                 ctx.game.window_w = size.x; | ||||||
|                 ctx.game.window_h = size.y; |                 ctx.game.window_h = size.y; | ||||||
|   | |||||||
| @@ -113,14 +113,14 @@ static SDL_Surface *create_surface(int width, int height) { | |||||||
|  |  | ||||||
|  |  | ||||||
| /* adds a new, blank atlas surface to the cache */ | /* adds a new, blank atlas surface to the cache */ | ||||||
| static void add_new_atlas(struct texture_cache *cache) { | static void add_new_atlas(TextureCache *cache) { | ||||||
|     SDL_Surface *new_atlas = create_surface(TEXTURE_ATLAS_SIZE, TEXTURE_ATLAS_SIZE); |     SDL_Surface *new_atlas = create_surface(TEXTURE_ATLAS_SIZE, TEXTURE_ATLAS_SIZE); | ||||||
|     arrput(cache->atlas_surfaces, new_atlas); |     arrput(cache->atlas_surfaces, new_atlas); | ||||||
|     arrput(cache->atlas_textures, create_gpu_texture(TEXTURE_FILTER_NEAREAST, true)); |     arrput(cache->atlas_textures, create_gpu_texture(TEXTURE_FILTER_NEAREAST, true)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void upload_texture_from_surface(gpu_texture texture, SDL_Surface *surface) { | static void upload_texture_from_surface(GPUTexture texture, SDL_Surface *surface) { | ||||||
|     SDL_LockSurface(surface); |     SDL_LockSurface(surface); | ||||||
|  |  | ||||||
|     upload_gpu_texture(texture, surface->pixels, surface->format->BytesPerPixel, surface->w, surface->h); |     upload_gpu_texture(texture, surface->pixels, surface->format->BytesPerPixel, surface->w, surface->h); | ||||||
| @@ -129,7 +129,7 @@ static void upload_texture_from_surface(gpu_texture texture, SDL_Surface *surfac | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void recreate_current_atlas_texture(struct texture_cache *cache) { | static void recreate_current_atlas_texture(TextureCache *cache) { | ||||||
|     /* TODO: should surfaces be freed after they cannot be referenced in atlas builing? */ |     /* TODO: should surfaces be freed after they cannot be referenced in atlas builing? */ | ||||||
|     /*       for example, if full page of 64x64 tiles was already filled, there's no real reason to process them further */ |     /*       for example, if full page of 64x64 tiles was already filled, there's no real reason to process them further */ | ||||||
|     SDL_Surface *atlas_surface = cache->atlas_surfaces[cache->atlas_index]; |     SDL_Surface *atlas_surface = cache->atlas_surfaces[cache->atlas_index]; | ||||||
| @@ -164,7 +164,7 @@ static void recreate_current_atlas_texture(struct texture_cache *cache) { | |||||||
|  |  | ||||||
|  |  | ||||||
| /* uses the textures currently in the cache to create an array of stbrp_rects */ | /* uses the textures currently in the cache to create an array of stbrp_rects */ | ||||||
| static stbrp_rect *create_rects_from_cache(struct texture_cache *cache) { | static stbrp_rect *create_rects_from_cache(TextureCache *cache) { | ||||||
|     stbrp_rect *rects = NULL; |     stbrp_rect *rects = NULL; | ||||||
|     for (size_t i = 0; i < shlenu(cache->hash); ++i) { |     for (size_t i = 0; i < shlenu(cache->hash); ++i) { | ||||||
|         if (cache->hash[i].value.loner_texture != 0) |         if (cache->hash[i].value.loner_texture != 0) | ||||||
| @@ -203,7 +203,7 @@ static stbrp_rect *filter_unpacked_rects(stbrp_rect *rects) { | |||||||
|  |  | ||||||
| /* updates the original rects array with the data from packed_rects */ | /* updates the original rects array with the data from packed_rects */ | ||||||
| /* returns true if all rects were packed successfully */ | /* returns true if all rects were packed successfully */ | ||||||
| static bool update_rects(struct texture_cache *cache, stbrp_rect *rects, stbrp_rect *packed_rects) { | static bool update_rects(TextureCache *cache, stbrp_rect *rects, stbrp_rect *packed_rects) { | ||||||
|     /* !!! do not grow either of the arrays !!! */ |     /* !!! do not grow either of the arrays !!! */ | ||||||
|     /* the reallocation will try to reassign the array pointer, to no effect. */ |     /* the reallocation will try to reassign the array pointer, to no effect. */ | ||||||
|     /* see stb_ds.h */ |     /* see stb_ds.h */ | ||||||
| @@ -229,13 +229,13 @@ static bool update_rects(struct texture_cache *cache, stbrp_rect *rects, stbrp_r | |||||||
|  |  | ||||||
|  |  | ||||||
| /* updates the atlas location of every rect in the cache */ | /* updates the atlas location of every rect in the cache */ | ||||||
| static void update_texture_rects_in_atlas(struct texture_cache *cache, stbrp_rect *rects) { | static void update_texture_rects_in_atlas(TextureCache *cache, stbrp_rect *rects) { | ||||||
|     int r = 0; |     int r = 0; | ||||||
|     for (size_t i = 0; i < shlenu(cache->hash); ++i) { |     for (size_t i = 0; i < shlenu(cache->hash); ++i) { | ||||||
|         if (cache->hash[i].value.loner_texture != 0) |         if (cache->hash[i].value.loner_texture != 0) | ||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|         cache->hash[i].value.srcrect = (t_frect) { |         cache->hash[i].value.srcrect = (Rect) { | ||||||
|             .x = (float)rects[r].x, |             .x = (float)rects[r].x, | ||||||
|             .y = (float)rects[r].y, |             .y = (float)rects[r].y, | ||||||
|             .w = (float)rects[r].w, |             .w = (float)rects[r].w, | ||||||
| @@ -247,7 +247,7 @@ static void update_texture_rects_in_atlas(struct texture_cache *cache, stbrp_rec | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void textures_cache_init(struct texture_cache *cache, SDL_Window *window) { | void textures_cache_init(TextureCache *cache, SDL_Window *window) { | ||||||
|     cache->window = window; |     cache->window = window; | ||||||
|     sh_new_arena(cache->hash); |     sh_new_arena(cache->hash); | ||||||
|  |  | ||||||
| @@ -258,7 +258,7 @@ void textures_cache_init(struct texture_cache *cache, SDL_Window *window) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void textures_cache_deinit(struct texture_cache *cache) { | void textures_cache_deinit(TextureCache *cache) { | ||||||
|     /* free atlas textures */ |     /* free atlas textures */ | ||||||
|     for (size_t i = 0; i < arrlenu(cache->atlas_textures); ++i) { |     for (size_t i = 0; i < arrlenu(cache->atlas_textures); ++i) { | ||||||
|         delete_gpu_texture(cache->atlas_textures[i]); |         delete_gpu_texture(cache->atlas_textures[i]); | ||||||
| @@ -282,7 +282,7 @@ void textures_cache_deinit(struct texture_cache *cache) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void textures_dump_atlases(struct texture_cache *cache) { | void textures_dump_atlases(TextureCache *cache) { | ||||||
|     PHYSFS_mkdir("/dump"); |     PHYSFS_mkdir("/dump"); | ||||||
|  |  | ||||||
|     const char string_template[] = "/dump/atlas%zd.png"; |     const char string_template[] = "/dump/atlas%zd.png"; | ||||||
| @@ -307,18 +307,18 @@ void textures_dump_atlases(struct texture_cache *cache) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static enum texture_mode infer_texture_mode(SDL_Surface *surface) { | static enum TextureMode infer_texture_mode(SDL_Surface *surface) { | ||||||
|     const uint32_t amask = surface->format->Amask; |     const uint32_t amask = surface->format->Amask; | ||||||
|     if (amask == 0) |     if (amask == 0) | ||||||
|         return TEXTURE_MODE_OPAQUE; |         return TEXTURE_MODE_OPAQUE; | ||||||
|  |  | ||||||
|     enum texture_mode result = TEXTURE_MODE_OPAQUE; |     enum TextureMode result = TEXTURE_MODE_OPAQUE; | ||||||
|  |  | ||||||
|     SDL_LockSurface(surface); |     SDL_LockSurface(surface); | ||||||
|  |  | ||||||
|     for (int i = 0; i < surface->w * surface->h; ++i) { |     for (int i = 0; i < surface->w * surface->h; ++i) { | ||||||
|         /* TODO: don't assume 32 bit depth ? */ |         /* TODO: don't assume 32 bit depth ? */ | ||||||
|         t_color color; |         Color color; | ||||||
|         SDL_GetRGBA(((uint32_t *)surface->pixels)[i], surface->format, &color.r, &color.g, &color.b, &color.a); |         SDL_GetRGBA(((uint32_t *)surface->pixels)[i], surface->format, &color.r, &color.g, &color.b, &color.a); | ||||||
|  |  | ||||||
|         if (color.a == 0) |         if (color.a == 0) | ||||||
| @@ -335,14 +335,14 @@ static enum texture_mode infer_texture_mode(SDL_Surface *surface) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static t_texture_key textures_load(struct texture_cache *cache, const char *path) { | static TextureKey textures_load(TextureCache *cache, const char *path) { | ||||||
|     /* no need to do anything if it was loaded already */ |     /* no need to do anything if it was loaded already */ | ||||||
|     const ptrdiff_t i = shgeti(cache->hash, path); |     const ptrdiff_t i = shgeti(cache->hash, path); | ||||||
|     if (i >= 0) |     if (i >= 0) | ||||||
|         return (t_texture_key){ (uint16_t)i }; |         return (TextureKey){ (uint16_t)i }; | ||||||
|  |  | ||||||
|     SDL_Surface *surface = image_to_surface(path); |     SDL_Surface *surface = image_to_surface(path); | ||||||
|     struct texture new_texture = { |     Texture new_texture = { | ||||||
|         .data = surface, |         .data = surface, | ||||||
|         .mode = infer_texture_mode(surface), |         .mode = infer_texture_mode(surface), | ||||||
|     }; |     }; | ||||||
| @@ -357,18 +357,18 @@ static t_texture_key textures_load(struct texture_cache *cache, const char *path | |||||||
|         } |         } | ||||||
|         new_texture.loner_texture = create_gpu_texture(TEXTURE_FILTER_NEAREAST, true); |         new_texture.loner_texture = create_gpu_texture(TEXTURE_FILTER_NEAREAST, true); | ||||||
|         upload_texture_from_surface(new_texture.loner_texture, surface);  |         upload_texture_from_surface(new_texture.loner_texture, surface);  | ||||||
|         new_texture.srcrect = (t_frect) { .w = (float)surface->w, .h = (float)surface->h }; |         new_texture.srcrect = (Rect) { .w = (float)surface->w, .h = (float)surface->h }; | ||||||
|     } else { |     } else { | ||||||
|         /* will be fully populated as the atlas updates */ |         /* will be fully populated as the atlas updates */ | ||||||
|         new_texture.atlas_index = cache->atlas_index; |         new_texture.atlas_index = cache->atlas_index; | ||||||
|         cache->is_dirty = true; |         cache->is_dirty = true; | ||||||
|     } |     } | ||||||
|     shput(cache->hash, path, new_texture); |     shput(cache->hash, path, new_texture); | ||||||
|     return (t_texture_key){ (uint16_t)shgeti(cache->hash, path) }; |     return (TextureKey){ (uint16_t)shgeti(cache->hash, path) }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void textures_update_atlas(struct texture_cache *cache) { | void textures_update_atlas(TextureCache *cache) { | ||||||
|     if (!cache->is_dirty) |     if (!cache->is_dirty) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
| @@ -421,14 +421,14 @@ static const char *rodata_start; | |||||||
| static const char *rodata_stop; | static const char *rodata_stop; | ||||||
|  |  | ||||||
| static const char *last_path = NULL; | static const char *last_path = NULL; | ||||||
| static t_texture_key last_texture; | static TextureKey last_texture; | ||||||
| static struct ptr_to_texture { | static struct PtrToTexture { | ||||||
|     const void *key; |     const void *key; | ||||||
|     t_texture_key value; |     TextureKey value; | ||||||
| } *ptr_to_texture; | } *ptr_to_texture; | ||||||
|  |  | ||||||
| /* TODO: separate and reuse */ | /* TODO: separate and reuse */ | ||||||
| t_texture_key textures_get_key(struct texture_cache *cache, const char *path) { | TextureKey textures_get_key(TextureCache *cache, const char *path) { | ||||||
|     if (rodata_stop == NULL) |     if (rodata_stop == NULL) | ||||||
|         if (!infer_elf_section_bounds(".rodata", &rodata_start, &rodata_stop)) |         if (!infer_elf_section_bounds(".rodata", &rodata_start, &rodata_stop)) | ||||||
|             CRY("Section inference", ".rodata section lookup failed"); |             CRY("Section inference", ".rodata section lookup failed"); | ||||||
| @@ -458,7 +458,7 @@ t_texture_key textures_get_key(struct texture_cache *cache, const char *path) { | |||||||
| } | } | ||||||
|  |  | ||||||
| #else | #else | ||||||
| t_texture_key textures_get_key(struct texture_cache *cache, const char *path) { | TextureKey textures_get_key(TextureCache *cache, const char *path) { | ||||||
|     /* hash tables are assumed to be stable, so we just return indices */ |     /* hash tables are assumed to be stable, so we just return indices */ | ||||||
|     const ptrdiff_t texture = shgeti(cache->hash, path); |     const ptrdiff_t texture = shgeti(cache->hash, path); | ||||||
|  |  | ||||||
| @@ -466,12 +466,12 @@ t_texture_key textures_get_key(struct texture_cache *cache, const char *path) { | |||||||
|     if (texture == -1) { |     if (texture == -1) { | ||||||
|         return textures_load(cache, path); |         return textures_load(cache, path); | ||||||
|     } else |     } else | ||||||
|         return (t_texture_key){ (uint16_t)texture }; |         return (TextureKey){ (uint16_t)texture }; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif /* generic implementation of textures_get_key() */ | #endif /* generic implementation of textures_get_key() */ | ||||||
|  |  | ||||||
| int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key key) { | int32_t textures_get_atlas_id(const TextureCache *cache, TextureKey key) { | ||||||
|     if (m_texture_key_is_valid(key)) { |     if (m_texture_key_is_valid(key)) { | ||||||
|         if (cache->hash[key.id].value.loner_texture != 0) |         if (cache->hash[key.id].value.loner_texture != 0) | ||||||
|             return -cache->hash[key.id].value.loner_texture; |             return -cache->hash[key.id].value.loner_texture; | ||||||
| @@ -484,32 +484,32 @@ int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key k | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| t_frect textures_get_srcrect(const struct texture_cache *cache, t_texture_key key) { | Rect textures_get_srcrect(const TextureCache *cache, TextureKey key) { | ||||||
|     if (m_texture_key_is_valid(key)) { |     if (m_texture_key_is_valid(key)) { | ||||||
|         return cache->hash[key.id].value.srcrect; |         return cache->hash[key.id].value.srcrect; | ||||||
|     } else { |     } else { | ||||||
|         CRY("Texture lookup failed.", |         CRY("Texture lookup failed.", | ||||||
|             "Tried to get texture that isn't loaded."); |             "Tried to get texture that isn't loaded."); | ||||||
|         return (t_frect){ 0, 0, 0, 0 }; |         return (Rect){ 0, 0, 0, 0 }; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| t_frect textures_get_dims(const struct texture_cache *cache, t_texture_key key) { | Rect textures_get_dims(const TextureCache *cache, TextureKey key) { | ||||||
|     if (m_texture_key_is_valid(key)) { |     if (m_texture_key_is_valid(key)) { | ||||||
|         if (cache->hash[key.id].value.loner_texture != 0) |         if (cache->hash[key.id].value.loner_texture != 0) | ||||||
|             return cache->hash[key.id].value.srcrect; |             return cache->hash[key.id].value.srcrect; | ||||||
|         else |         else | ||||||
|             return (t_frect){ .w = TEXTURE_ATLAS_SIZE, .h = TEXTURE_ATLAS_SIZE }; |             return (Rect){ .w = TEXTURE_ATLAS_SIZE, .h = TEXTURE_ATLAS_SIZE }; | ||||||
|     } else { |     } else { | ||||||
|         CRY("Texture lookup failed.", |         CRY("Texture lookup failed.", | ||||||
|             "Tried to get texture that isn't loaded."); |             "Tried to get texture that isn't loaded."); | ||||||
|         return (t_frect){ 0, 0, 0, 0 }; |         return (Rect){ 0, 0, 0, 0 }; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void textures_bind(const struct texture_cache *cache, t_texture_key key) { | void textures_bind(const TextureCache *cache, TextureKey key) { | ||||||
|     if (m_texture_key_is_valid(key)) { |     if (m_texture_key_is_valid(key)) { | ||||||
|         if (cache->hash[key.id].value.loner_texture == 0) |         if (cache->hash[key.id].value.loner_texture == 0) | ||||||
|             bind_gpu_texture(cache->atlas_textures[cache->hash[key.id].value.atlas_index]); |             bind_gpu_texture(cache->atlas_textures[cache->hash[key.id].value.atlas_index]); | ||||||
| @@ -523,7 +523,7 @@ void textures_bind(const struct texture_cache *cache, t_texture_key key) { | |||||||
|  |  | ||||||
|  |  | ||||||
| /* TODO: alternative schemes, such as: array texture, fragment shader and geometry division */ | /* TODO: alternative schemes, such as: array texture, fragment shader and geometry division */ | ||||||
| void textures_bind_repeating(const struct texture_cache *cache, t_texture_key key) { | void textures_bind_repeating(const TextureCache *cache, TextureKey key) { | ||||||
|     if (m_texture_key_is_valid(key)) { |     if (m_texture_key_is_valid(key)) { | ||||||
|         if (cache->hash[key.id].value.loner_texture == 0) { |         if (cache->hash[key.id].value.loner_texture == 0) { | ||||||
|  |  | ||||||
| @@ -533,9 +533,9 @@ void textures_bind_repeating(const struct texture_cache *cache, t_texture_key ke | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             const struct texture texture = cache->hash[key.id].value; |             const Texture texture = cache->hash[key.id].value; | ||||||
|  |  | ||||||
|             const gpu_texture repeating_texture = create_gpu_texture(TEXTURE_FILTER_NEAREAST, false); |             const GPUTexture repeating_texture = create_gpu_texture(TEXTURE_FILTER_NEAREAST, false); | ||||||
|  |  | ||||||
|             SDL_LockSurface(texture.data); |             SDL_LockSurface(texture.data); | ||||||
|  |  | ||||||
| @@ -561,7 +561,7 @@ void textures_bind_repeating(const struct texture_cache *cache, t_texture_key ke | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| enum texture_mode textures_get_mode(const struct texture_cache *cache, t_texture_key key) { | TextureMode textures_get_mode(const TextureCache *cache, TextureKey key) { | ||||||
|     if (m_texture_key_is_valid(key)) { |     if (m_texture_key_is_valid(key)) { | ||||||
|         return cache->hash[key.id].value.mode; |         return cache->hash[key.id].value.mode; | ||||||
|     } else { |     } else { | ||||||
| @@ -572,14 +572,14 @@ enum texture_mode textures_get_mode(const struct texture_cache *cache, t_texture | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| size_t textures_get_num_atlases(const struct texture_cache *cache) { | size_t textures_get_num_atlases(const TextureCache *cache) { | ||||||
|     return cache->atlas_index + 1;     |     return cache->atlas_index + 1;     | ||||||
| } | } | ||||||
|  |  | ||||||
| void textures_reset_state(void) { | void textures_reset_state(void) { | ||||||
| #if defined(__linux__) && !defined(HOT_RELOAD_SUPPORT) | #if defined(__linux__) && !defined(HOT_RELOAD_SUPPORT) | ||||||
|     last_path = NULL; |     last_path = NULL; | ||||||
|     last_texture = (t_texture_key){0}; |     last_texture = (TextureKey){0}; | ||||||
|     shfree(ptr_to_texture); |     shfree(ptr_to_texture); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -11,47 +11,47 @@ | |||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| struct texture { | typedef struct Texture { | ||||||
|     t_frect srcrect;            /* position in atlas */ |     Rect srcrect;            /* position in atlas */ | ||||||
|     SDL_Surface *data;          /* original image data */ |     SDL_Surface *data;          /* original image data */ | ||||||
|     int atlas_index; |     int atlas_index; | ||||||
|     gpu_texture loner_texture;       /* stored directly for loners, == 0 means atlas_index should be used */ |     GPUTexture loner_texture;       /* stored directly for loners, == 0 means atlas_index should be used */ | ||||||
|     gpu_texture repeating_texture;   /* separately allocated texture, for loners == loner_texture */ |     GPUTexture repeating_texture;   /* separately allocated Texture, for loners == loner_texture */ | ||||||
|     enum texture_mode mode; |     enum TextureMode mode; | ||||||
| }; | } Texture; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct texture_cache_item { | typedef struct TextureCacheItem { | ||||||
|     char *key; |     char *key; | ||||||
|     struct texture value; |     struct Texture value; | ||||||
| }; | } TextureCacheItem; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct texture_cache { | typedef struct TextureCache { | ||||||
|     SDL_Window *window;          /* from context */ |     SDL_Window *window;          /* from context */ | ||||||
|  |  | ||||||
|     struct texture_cache_item *hash; |     struct TextureCacheItem *hash; | ||||||
|  |  | ||||||
|     stbrp_node *node_buffer;     /* used internally by stb_rect_pack */ |     stbrp_node *node_buffer;     /* used internally by stb_rect_pack */ | ||||||
|  |  | ||||||
|     SDL_Surface **atlas_surfaces; |     SDL_Surface **atlas_surfaces; | ||||||
|     gpu_texture *atlas_textures;      /* shared by atlas textures */ |     GPUTexture *atlas_textures;      /* shared by atlas textures */ | ||||||
|     int atlas_index;             /* atlas that is currently being built */ |     int atlas_index;             /* atlas that is currently being built */ | ||||||
|  |  | ||||||
|     bool is_dirty;               /* current atlas needs to be recreated */ |     bool is_dirty;               /* current atlas needs to be recreated */ | ||||||
| }; | } TextureCache; | ||||||
|  |  | ||||||
| /* type safe structure for persistent texture handles */ | /* type safe structure for persistent texture handles */ | ||||||
| typedef struct { uint16_t id; } t_texture_key; | typedef struct TextureKey { uint16_t id; } TextureKey; | ||||||
|  |  | ||||||
| /* tests whether given key structure corresponds to any texture */ | /* tests whether given key structure corresponds to any texture */ | ||||||
| #define m_texture_key_is_valid(p_key) ((p_key).id != (uint16_t)-1) | #define m_texture_key_is_valid(p_key) ((p_key).id != (uint16_t)-1) | ||||||
|  |  | ||||||
| void textures_cache_init(struct texture_cache *cache, SDL_Window *window); | void textures_cache_init(struct TextureCache *cache, SDL_Window *window); | ||||||
| void textures_cache_deinit(struct texture_cache *cache); | void textures_cache_deinit(struct TextureCache *cache); | ||||||
|  |  | ||||||
| /* for debugging */ | /* for debugging */ | ||||||
| void textures_dump_atlases(struct texture_cache *cache); | void textures_dump_atlases(struct TextureCache *cache); | ||||||
|  |  | ||||||
| /* loads an image if it isn't in the cache, otherwise a no-op. */ | /* loads an image if it isn't in the cache, otherwise a no-op. */ | ||||||
| /* can be called from anywhere at any time after init, useful if you want to */ | /* can be called from anywhere at any time after init, useful if you want to */ | ||||||
| @@ -61,30 +61,30 @@ void textures_dump_atlases(struct texture_cache *cache); | |||||||
| /* repacks the current texture atlas based on the texture cache if needed */ | /* repacks the current texture atlas based on the texture cache if needed */ | ||||||
| /* any previously returned srcrect results are invalidated after that */ | /* any previously returned srcrect results are invalidated after that */ | ||||||
| /* call it every time before rendering */ | /* call it every time before rendering */ | ||||||
| void textures_update_atlas(struct texture_cache *cache); | void textures_update_atlas(TextureCache *cache); | ||||||
|  |  | ||||||
| /* returns a persistent handle to some texture in cache, loading it if needed */ | /* returns a persistent handle to some texture in cache, loading it if needed */ | ||||||
| /* check the result with m_texture_key_is_valid() */ | /* check the result with m_texture_key_is_valid() */ | ||||||
| t_texture_key textures_get_key(struct texture_cache *cache, const char *path); | TextureKey textures_get_key(TextureCache *cache, const char *path); | ||||||
|  |  | ||||||
| /* returns a rect in a texture cache of the given key */ | /* returns a rect in a texture cache of the given key */ | ||||||
| t_frect textures_get_srcrect(const struct texture_cache *cache, t_texture_key key); | Rect textures_get_srcrect(const TextureCache *cache, TextureKey key); | ||||||
|  |  | ||||||
| /* returns a rect of dimensions of the whole texture (whole atlas) */ | /* returns a rect of dimensions of the whole texture (whole atlas) */ | ||||||
| t_frect textures_get_dims(const struct texture_cache *cache, t_texture_key key); | Rect textures_get_dims(const TextureCache *cache, TextureKey key); | ||||||
|  |  | ||||||
| /* returns an identifier that is equal for all textures placed in the same atlas */ | /* returns an identifier that is equal for all textures placed in the same atlas */ | ||||||
| int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key key); | int32_t textures_get_atlas_id(const TextureCache *cache, TextureKey key); | ||||||
|  |  | ||||||
| void textures_bind(const struct texture_cache *cache, t_texture_key key); | void textures_bind(const TextureCache *cache, TextureKey key); | ||||||
|  |  | ||||||
| void textures_bind_repeating(const struct texture_cache *cache, t_texture_key key); | void textures_bind_repeating(const TextureCache *cache, TextureKey key); | ||||||
|  |  | ||||||
| /* returns helpful information about contents of alpha channel in given texture */ | /* returns helpful information about contents of alpha channel in given texture */ | ||||||
| enum texture_mode textures_get_mode(const struct texture_cache *cache, t_texture_key key); | TextureMode textures_get_mode(const TextureCache *cache, TextureKey key); | ||||||
|  |  | ||||||
| /* returns the number of atlases in the cache */ | /* returns the number of atlases in the cache */ | ||||||
| size_t textures_get_num_atlases(const struct texture_cache *cache); | size_t textures_get_num_atlases(const TextureCache *cache); | ||||||
|  |  | ||||||
| /* TODO: should recieve texture_cache, get_key optimization cache should be cleared some other way */ | /* TODO: should recieve texture_cache, get_key optimization cache should be cleared some other way */ | ||||||
| void textures_reset_state(void); | void textures_reset_state(void); | ||||||
|   | |||||||
| @@ -171,7 +171,7 @@ bool strends(const char *str, const char *suffix) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool overlap_rect(const t_rect *a, const t_rect *b, t_rect *result) { | bool overlap_rect(const Recti *a, const Recti *b, Recti *result) { | ||||||
|     SDL_Rect a_sdl = { a->x, a->y, a->w, a->h }; |     SDL_Rect a_sdl = { a->x, a->y, a->w, a->h }; | ||||||
|     SDL_Rect b_sdl = { b->x, b->y, b->w, b->h }; |     SDL_Rect b_sdl = { b->x, b->y, b->w, b->h }; | ||||||
|     SDL_Rect result_sdl = { 0 }; |     SDL_Rect result_sdl = { 0 }; | ||||||
| @@ -179,13 +179,13 @@ bool overlap_rect(const t_rect *a, const t_rect *b, t_rect *result) { | |||||||
|     bool intersection = SDL_IntersectRect(&a_sdl, &b_sdl, &result_sdl); |     bool intersection = SDL_IntersectRect(&a_sdl, &b_sdl, &result_sdl); | ||||||
|  |  | ||||||
|     if (result != NULL) |     if (result != NULL) | ||||||
|         *result = (t_rect){ result_sdl.x, result_sdl.y, result_sdl.w, result_sdl.h }; |         *result = (Recti){ result_sdl.x, result_sdl.y, result_sdl.w, result_sdl.h }; | ||||||
|  |  | ||||||
|     return intersection; |     return intersection; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool overlap_frect(const t_frect *a, const t_frect *b, t_frect *result) { | bool overlap_frect(const Rect *a, const Rect *b, Rect *result) { | ||||||
|     SDL_FRect a_sdl = { a->x, a->y, a->w, a->h }; |     SDL_FRect a_sdl = { a->x, a->y, a->w, a->h }; | ||||||
|     SDL_FRect b_sdl = { b->x, b->y, b->w, b->h }; |     SDL_FRect b_sdl = { b->x, b->y, b->w, b->h }; | ||||||
|     SDL_FRect result_sdl = { 0 }; |     SDL_FRect result_sdl = { 0 }; | ||||||
| @@ -193,28 +193,28 @@ bool overlap_frect(const t_frect *a, const t_frect *b, t_frect *result) { | |||||||
|     bool intersection = SDL_IntersectFRect(&a_sdl, &b_sdl, &result_sdl); |     bool intersection = SDL_IntersectFRect(&a_sdl, &b_sdl, &result_sdl); | ||||||
|  |  | ||||||
|     if (result != NULL) |     if (result != NULL) | ||||||
|         *result = (t_frect){ result_sdl.x, result_sdl.y, result_sdl.w, result_sdl.h }; |         *result = (Rect){ result_sdl.x, result_sdl.y, result_sdl.w, result_sdl.h }; | ||||||
|  |  | ||||||
|     return intersection; |     return intersection; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool intersect_rect(const t_rect *a, const t_rect *b) { | bool intersect_rect(const Recti *a, const Recti *b) { | ||||||
|     SDL_Rect a_sdl = { a->x, a->y, a->w, a->h }; |     SDL_Rect a_sdl = { a->x, a->y, a->w, a->h }; | ||||||
|     SDL_Rect b_sdl = { b->x, b->y, b->w, b->h }; |     SDL_Rect b_sdl = { b->x, b->y, b->w, b->h }; | ||||||
|     return SDL_HasIntersection(&a_sdl, &b_sdl); |     return SDL_HasIntersection(&a_sdl, &b_sdl); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| bool intersect_frect(const t_frect *a, const t_frect *b) { | bool intersect_frect(const Rect *a, const Rect *b) { | ||||||
|     SDL_FRect a_sdl = { a->x, a->y, a->w, a->h }; |     SDL_FRect a_sdl = { a->x, a->y, a->w, a->h }; | ||||||
|     SDL_FRect b_sdl = { b->x, b->y, b->w, b->h }; |     SDL_FRect b_sdl = { b->x, b->y, b->w, b->h }; | ||||||
|     return SDL_HasIntersectionF(&a_sdl, &b_sdl); |     return SDL_HasIntersectionF(&a_sdl, &b_sdl); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| t_frect to_frect(t_rect rect) { | Rect to_frect(Recti rect) { | ||||||
|     return (t_frect) { |     return (Rect) { | ||||||
|         .h = (float)rect.h, |         .h = (float)rect.h, | ||||||
|         .w = (float)rect.w, |         .w = (float)rect.w, | ||||||
|         .x = (float)rect.x, |         .x = (float)rect.x, | ||||||
| @@ -223,8 +223,8 @@ t_frect to_frect(t_rect rect) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| t_fvec2 frect_center(t_frect rect) { | Vec2 frect_center(Rect rect) { | ||||||
|     return (t_fvec2){ |     return (Vec2){ | ||||||
|         .x = rect.x + rect.w / 2, |         .x = rect.x + rect.w / 2, | ||||||
|         .y = rect.y + rect.h / 2, |         .y = rect.y + rect.h / 2, | ||||||
|     }; |     }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user