From a841fa7c92003809718e0a3eb1b64d922f28458f Mon Sep 17 00:00:00 2001
From: Sara <sara@saragerretsen.nl>
Date: Sun, 1 Oct 2023 21:58:48 +0200
Subject: [PATCH] reworked rendering to transform sprites to pixel coordinates
 correctly

---
 src/assets.c    |  1 +
 src/camera.c    | 32 ++++++++++++++++++--------------
 src/camera.h    |  7 ++++---
 src/fencer.c    | 18 +++++++++---------
 src/level.c     |  8 ++++----
 src/sprite.c    |  9 ++++-----
 src/tilemap.c   |  4 ++--
 src/tilemap.h   |  2 +-
 src/transform.h |  4 ++--
 9 files changed, 45 insertions(+), 40 deletions(-)

diff --git a/src/assets.c b/src/assets.c
index 4169b2b..5eabd3e 100644
--- a/src/assets.c
+++ b/src/assets.c
@@ -64,6 +64,7 @@ static
 void _empty_assets() {
     AssetData* start = _assets;
     AssetData* end = _assets + _assets_len;
+
     for(AssetData* asset = start; asset < end; ++asset) {
         asset->destructor(asset->asset);
     }
diff --git a/src/camera.c b/src/camera.c
index 1cb3a71..7502dfe 100644
--- a/src/camera.c
+++ b/src/camera.c
@@ -6,26 +6,30 @@ Camera g_camera;
 
 void camera_init() {
     LOG_INFO("camera_init");
-    g_camera.centre = ZeroVector;
-    g_camera.width = 10;
+    g_camera.transform = IdentityTransform;
+    g_camera.fov = 10;
 }
 
 static inline
 float _camera_height(Camera* self) {
-    return self->width * ((float)g_render_resolution.y / (float)g_render_resolution.x);
+    return self->fov * ((float)g_render_resolution.y / (float)g_render_resolution.x);
 }
 
-static inline
-float _cam_to_world_conversion() {
-    return g_render_resolution.x / g_camera.width;
-}
+SDL_FRect camera_world_to_pixel_rect(Camera* self, SDL_FRect* world_space) {
+    Transform t = self->transform;
+    t.rotation = 0;
+    t.scale = OneVector;
+    t = transform_invert(t);
 
-SDL_FRect camera_world_to_screen_space(Camera* self, SDL_FRect* world_space) {
-    float unit = _cam_to_world_conversion();
-    return (SDL_FRect) {
-        .x = (g_camera.centre.x - world_space->x + g_camera.width/2.0) * unit,
-        .y = (g_camera.centre.y - world_space->y + _camera_height(&g_camera)/2.0) * unit,
-        .w = world_space->w * unit,
-        .h = world_space->h * unit
+    Vector tl = {world_space->x + (self->fov / 2.0), world_space->y + (_camera_height(self) / 2.0)};
+    Vector size = {world_space->w, world_space->h};
+
+    tl = vmulff(transform_point(&t, tl), g_render_resolution.x / self->fov);
+    size = vmulff(vmulf(t.scale, size), g_render_resolution.x / self->fov);
+
+
+    return (SDL_FRect){
+        tl.x, tl.y,
+        size.x, size.y
     };
 }
diff --git a/src/camera.h b/src/camera.h
index 9098e0b..c2ab7fa 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -2,11 +2,12 @@
 #define _fencer_camera_h
 
 #include "vmath.h"
+#include "transform.h"
 #include <SDL2/SDL_rect.h>
 
 struct Camera {
-    Vector centre;
-    float width;
+    float fov;
+    Transform transform;
 };
 
 typedef struct Camera Camera;
@@ -16,6 +17,6 @@ extern Camera g_camera;
 
 extern void camera_init();
 extern SDL_FRect camera_screen_to_world_space(Camera* self, SDL_FRect* camera_space);
-extern SDL_FRect camera_world_to_screen_space(Camera* self, SDL_FRect* world_space);
+extern SDL_FRect camera_world_to_pixel_rect(Camera* self, SDL_FRect* world_space);
 
 #endif // !_fencer_camera_h
diff --git a/src/fencer.c b/src/fencer.c
index c2a0bf8..12cba63 100644
--- a/src/fencer.c
+++ b/src/fencer.c
@@ -16,32 +16,32 @@ static Vector cam_speed = ZeroVector;
 
 static
 void cam_move_h(int val) {
-    cam_speed.x = -val * 0.01f;
+    cam_speed.x = val * 0.1f;
 }
 static
 void cam_move_v(int val) {
-    cam_speed.y = val * 0.01f;
+    cam_speed.y = -val * 0.1f;
 }
 
 static
 void play() {
+    g_camera.fov = 40;
     spr_player_standing = spritesheet_load("assets/sprites/player.png", (IVector){128, 128});
     player = sprite_from_spritesheet(spr_player_standing, 0);
-    sprite_set_origin(player, (Vector){0.5f, 1.0f});
-    player_trans.scale = OneVector;
-    assert(player != NULL && "Player failed to load");
+    player_trans.scale = (Vector){4.f, 4.f};
+    sprite_set_origin(player, (Vector){0.25f, 1.f});
 
     level = level_load("level_0");
-    assert(level != NULL && "Level failed to load");
 
     input_add_axis_action(SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, &cam_move_h);
     input_add_axis_action(SDL_SCANCODE_DOWN, SDL_SCANCODE_UP, &cam_move_v);
-    g_camera.width = 20;
+
 }
 
 static
 void tick() {
-    g_camera.centre = vaddf(g_camera.centre, cam_speed);
+    g_camera.transform.position = vaddf(g_camera.transform.position, cam_speed);
+    player_trans.position = g_camera.transform.position;
 }
 
 static
@@ -52,7 +52,7 @@ void draw() {
 
 int main(int argc, char* argv[]) {
     struct ProgramSettings config = {
-        .target_fps = 0, // unbounded speed
+        .target_fps = 120,
         .title = "fencer",
         .view_resolution = {1920, 1080},
         .on_play = &play,
diff --git a/src/level.c b/src/level.c
index b39023a..3e0b0bf 100644
--- a/src/level.c
+++ b/src/level.c
@@ -13,10 +13,9 @@ struct Level {
     asset_id asset_id;
     size_t level_iid;
 
+    Transform transform;
     Tilemap** tilemaps;
-
     size_t tilemaps_len;
-
     Vector player_start;
 };
 
@@ -62,7 +61,8 @@ Level* level_from_json(cJSON* json) {
         return NULL;
     }
     *self = (Level) {
-        .asset_id = store_asset(self, &_deallocate_level)
+        .asset_id = store_asset(self, &_deallocate_level),
+        .transform = IdentityTransform
     };
 
     // fetch the instance id
@@ -125,6 +125,6 @@ void level_destroy(Level* self) {
 void level_draw(Level* self) {
     Tilemap** end = self->tilemaps + self->tilemaps_len;
     for(Tilemap** map = self->tilemaps; map != end; ++map) {
-        tilemap_draw(*map);
+        tilemap_draw(*map, self->transform);
     }
 }
diff --git a/src/sprite.c b/src/sprite.c
index d74df8a..76e2370 100644
--- a/src/sprite.c
+++ b/src/sprite.c
@@ -44,19 +44,18 @@ void sprite_draw(Sprite* self, Transform transform) {
     SDL_Texture* texture = spritesheet_get_texture(self->spritesheet);
     SDL_Rect source = spritesheet_get_frame_rect(self->spritesheet, self->current_frame);
 
-    Vector left_top = vinvf(transform_point(&transform, self->origin));
+    Vector left_top = transform_point(&transform, vinvf(self->origin));
 
     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 = vmulff(vmulf(self->origin, transform.scale), 0.5f);
+    destination = camera_world_to_pixel_rect(&g_camera, &destination);
+    Vector origin = vmulf(self->origin, transform.scale);
 
     SDL_RenderCopyExF(g_renderer, texture, &source, &destination,
                       transform.rotation * 57.2958, &origin, SDL_FLIP_NONE);
+    SDL_SetRenderDrawColor(g_renderer, 255, 255, 255, 255);
 }
 
 Vector sprite_get_origin(Sprite* self) {
diff --git a/src/tilemap.c b/src/tilemap.c
index db5bba3..d5fc6a8 100644
--- a/src/tilemap.c
+++ b/src/tilemap.c
@@ -95,8 +95,8 @@ Tilemap* tilemap_from_autolayer(cJSON* json) {
     return self;
 }
 
-void tilemap_draw(Tilemap* self) {
-    Transform tiletrans = self->transform;
+void tilemap_draw(Tilemap* self, Transform transform) {
+    Transform tiletrans = transform_apply(transform, self->transform);
     TileInstance* tile;
 
     for(int i = 0; i < self->map_num; ++i) {
diff --git a/src/tilemap.h b/src/tilemap.h
index 8be86ef..1956f33 100644
--- a/src/tilemap.h
+++ b/src/tilemap.h
@@ -14,6 +14,6 @@ extern void tilemap_destroy(Tilemap* self);
 
 extern void tilemap_set_tileset(Tilemap* self, Tileset* set);
 
-extern void tilemap_draw(Tilemap* tilemap);
+extern void tilemap_draw(Tilemap* tilemap, Transform transform);
 
 #endif // !_fencer_tilemap_h
diff --git a/src/transform.h b/src/transform.h
index 9687f28..9627601 100644
--- a/src/transform.h
+++ b/src/transform.h
@@ -37,12 +37,12 @@ Transform transform_invert(Transform a) {
 
 static inline
 Vector transform_direction(Transform* self, Vector direction) {
-    return vmulf(vrotatef(direction, self->rotation), self->scale);
+    return vrotatef(direction, self->rotation);
 }
 
 static inline
 Vector transform_point(Transform* self, Vector position) {
-    return vaddf(transform_direction(self, position), self->position);
+    return vaddf(vmulf(transform_direction(self, position), self->scale), self->position);
 }
 
 #endif // !_fencer_transform_h