JacksEscape/camera.c

89 lines
2.3 KiB
C

#include "camera.h"
#include "types.h"
#include "entity.h"
#include "util/assert.h"
static inline double dabs(double x) { return x < 0.0 ? -x : x; }
static inline double dmin(double x, double y) { return x < y ? x : y; }
System_Camera *camera_NewSystem(App *super) {
System_Camera *sys = zero_malloc(sizeof(System_Camera));
sys->super = super;
Box2 default_screen = {
.lefttop = {.x = 0.0, .y = 0.0},
.size = {.x = 1280, .y = 720}};
sys->cam = sys->screen = default_screen;
return sys;
}
void camera_DeleteSystem(System_Camera *sys) {
free(sys);
}
void camera_AddEntity(System_Camera *sys, Entity *e) {
if (e->player) {
ASSERT(!sys->player && "Two player entities are added! Did you forget to DeleteEntity for player?");
sys->player = e->player;
}
}
void camera_DeleteEntity(System_Camera *sys, uintptr_t id) {
if (sys->player && sys->player->super->id == id)
sys->player = NULL;
}
void camera_Advance(System_Camera *sys, Duration deltaTime) {
Vec2 tocenter;
if (sys->target.size.x > EPS)
tocenter = box2_Center(sys->target);
else if (sys->player)
tocenter = vec2_Add(
sys->player->super->position->position,
vec2(0, -sys->player->super->hitbox->box.size.y));
else
return;
double speed;
if (dabs(sys->speed) < EPS)
speed = 4.0;
else
speed = sys->speed;
Vec2 oldcenter = box2_Center(sys->cam), oldsize = sys->cam.size;
Vec2 newcenter, newsize;
Vec2 diff = vec2_Minus(tocenter, oldcenter);
if (dabs(diff.x) < EPS && dabs(diff.y) < EPS)
newcenter = tocenter;
else {
Vec2 xdiff = vec2_Scale(diff, dmin(speed * duration_Seconds(deltaTime), 1.0));
newcenter = vec2_Add(oldcenter, xdiff);
}
// TODO size scaling
newsize = oldsize;
sys->cam = box2_FromCenter(newcenter, newsize);
}
inline static Vec2 _camera_TransformSize(System_Camera *sys, Vec2 worldSize) {
Vec2 result = {
.x = worldSize.x / sys->cam.size.x * sys->screen.size.x,
.y = worldSize.y / sys->cam.size.y * sys->screen.size.y};
return result;
}
Vec2 camera_TransformVec2(System_Camera *sys, Vec2 world) {
Vec2 relative = vec2_Minus(world, sys->cam.lefttop);
return vec2_Add(sys->screen.lefttop, _camera_TransformSize(sys, relative));
}
Box2 camera_TransformBox2(System_Camera *sys, Box2 world) {
Box2 result = {
.lefttop = camera_TransformVec2(sys, world.lefttop),
.size = _camera_TransformSize(sys, world.size)};
return result;
}