reworked rendering to transform sprites to pixel coordinates correctly

This commit is contained in:
Sara 2023-10-01 21:58:48 +02:00
parent 4fcb637bbb
commit a841fa7c92
9 changed files with 45 additions and 40 deletions

View file

@ -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);
}

View file

@ -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
};
}

View file

@ -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

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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

View file

@ -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