From 9180c6d06ff4791c02eec50856f80b1aa5666ba9 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 24 Sep 2023 23:40:14 +0200 Subject: [PATCH] added sprite and spritesheet --- src/sprite.c | 59 ++++++++++++++++++++++++++++++++++++++ src/sprite.h | 25 ++++++++++++++++ src/spritesheet.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++ src/spritesheet.h | 21 ++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 src/sprite.c create mode 100644 src/sprite.h create mode 100644 src/spritesheet.c create mode 100644 src/spritesheet.h diff --git a/src/sprite.c b/src/sprite.c new file mode 100644 index 0000000..c5c9882 --- /dev/null +++ b/src/sprite.c @@ -0,0 +1,59 @@ +#include "sprite.h" +#include "camera.h" +#include "render.h" +#include "spritesheet.h" +#include +#include + +struct Sprite { + // The animation sheet to sample sprites from. + Spritesheet* sheet; + + // The current frame of animation. + size_t current_frame; + // Time at the start of the current frame of animation. + float current_frame_time; + + // The local transformation of this sprite. + Transform transform; + Vector origin; +}; + +Sprite* sprite_from_spritesheet(Spritesheet* sheet) { + Sprite* self = malloc(sizeof(Sprite)); + + self->sheet = sheet; + self->transform = IdentityTransform; + self->origin = (Vector){0.5f, 1.0f}; + self->current_frame = 0; + // TODO: replace with a getter for the current game time. + self->current_frame_time = 0; + + return self; +} + +void sprite_destroy(Sprite* self) { + free(self); +} + +void sprite_draw(Sprite* self, Transform transform) { + SDL_Texture* texture = spritesheet_get_texture(self->sheet); + SDL_Rect source = spritesheet_get_frame_rect(self->sheet, self->current_frame); + transform = transform_apply(transform, self->transform); + Vector left_top = vinvf(transform_point(&transform, self->origin)); + printf("lt: %f %f\n", left_top.x, left_top.y); + printf("or: %f %f\n", self->origin.x, self->origin.y); + + SDL_FRect destination = (SDL_FRect) { + left_top.x, left_top.y, + transform.scale.x, transform.scale.y + }; + + destination = camera_world_to_screen_space(&g_camera, &destination); + + Vector origin = vmulf(self->origin, vmulff(transform.scale, 0.5f)); + self->transform.rotation += 0.01f; + + SDL_RenderCopyExF(g_renderer, texture, &source, &destination, + transform.rotation * 57.2958, &origin, SDL_FLIP_NONE); +} diff --git a/src/sprite.h b/src/sprite.h new file mode 100644 index 0000000..3e98bb3 --- /dev/null +++ b/src/sprite.h @@ -0,0 +1,25 @@ +#ifndef _fencer_sprite_h +#define _fencer_sprite_h + +#include "vmath.h" +#include "transform.h" +#include "spritesheet.h" +#include +#include + +// Forward declaration of the private sprite struct +typedef struct Sprite Sprite; + +extern Sprite* sprite_from_spritesheet(Spritesheet* sheet); +extern void sprite_destroy(Sprite* sprite); +extern void sprite_draw(Sprite* self, Transform transform); + +extern void sprite_set_position(Sprite* self, Vector position); +extern void sprite_translate(Sprite* self, Vector delta_position); +extern void sprite_set_scale(Sprite* self, Vector scale); +extern void sprite_scale(Sprite* self, Vector scale); +extern void sprite_set_rotation(Sprite* self, float rotation); +extern void sprite_rotate(Sprite* self, float delta_rotation); +extern void sprite_set_origin(Sprite* self, Vector origin); + +#endif // !_fencer_sprite_h diff --git a/src/spritesheet.c b/src/spritesheet.c new file mode 100644 index 0000000..4f0a1b4 --- /dev/null +++ b/src/spritesheet.c @@ -0,0 +1,72 @@ +#include "spritesheet.h" +#include "assets.h" +#include "render.h" +#include +#include + +struct Spritesheet { + // The texture to sample. + SDL_Texture* texture; + // The resolution of the texture. + IVector resolution; + // The number of frames in the sheet. + size_t frame_count; + // The number of frames contained in the width of the texture. + size_t frame_shear; + // Rules for how to play the sheet's animation. + AnimationType animation_type; + // The resolution of a single frame of the sheet. + IVector frame_size; + // The time to wait before switching frames. + float frame_interval; +}; + +static +void _spritesheet_destroy_asset(void* self_void) { + Spritesheet* self = self_void; + SDL_DestroyTexture(self->texture); + free(self_void); +} + +Spritesheet* spritesheet_from_texture(const char* texture_name, IVector frame_resolution) { + Spritesheet* self = malloc(sizeof(Spritesheet)); + + if(self == NULL) { + return NULL; + } + + store_asset(self, _spritesheet_destroy_asset); + + // Load the texture image and query it's size + self->texture = IMG_LoadTexture(g_renderer, texture_name); + SDL_QueryTexture(self->texture, NULL, NULL, &self->resolution.x, &self->resolution.y); + + self->animation_type = ANIMTYPE_ONCE; + self->frame_size = frame_resolution; + self->frame_shear = self->resolution.x / self->frame_size.x; + self->frame_count = self->resolution.x / self->frame_size.x + self->resolution.y / self->frame_size.y; + self->frame_interval = 0.016f; + + return self; +} + +void spritesheet_destroy(Spritesheet* self) { + asset_id id = get_asset_id(self); + if(id != 0) { + free_asset(id); + } +} + +SDL_Texture* spritesheet_get_texture(const Spritesheet* self) { + return self->texture; +} + +SDL_Rect spritesheet_get_frame_rect(const Spritesheet* self, size_t index) { + IVector tile_coord = {index % self->frame_shear, index / self->frame_shear}; + tile_coord = vmuli(tile_coord, self->frame_size); + + return (SDL_Rect) { + tile_coord.x, tile_coord.y, + self->frame_size.x, self->frame_size.y + }; +} \ No newline at end of file diff --git a/src/spritesheet.h b/src/spritesheet.h new file mode 100644 index 0000000..6346d01 --- /dev/null +++ b/src/spritesheet.h @@ -0,0 +1,21 @@ +#ifndef _fencer_spritesheet_h +#define _fencer_spritesheet_h + +#include "vmath.h" +#include + +typedef enum AnimationType AnimationType; +enum AnimationType { + ANIMTYPE_ONCE, + ANIMTYPE_LOOP, +}; + +typedef struct Spritesheet Spritesheet; + +extern Spritesheet* spritesheet_from_texture(const char* texture_name, IVector frame_resolution); +extern void spritesheet_destroy(Spritesheet* self); + +extern SDL_Texture* spritesheet_get_texture(const Spritesheet* self); +extern SDL_Rect spritesheet_get_frame_rect(const Spritesheet* self, size_t index); + +#endif // !_fencer_spritesheet_h