#include #include #include "view.h" #define ZOOM_MAX 100.0 #define ZOOM_MIN 0.02 #define PAN_BOUNDS 35.0 #define X_IN_BOUNDS(view, w, x) \ ((x + PAN_BOUNDS <= w) && (PAN_BOUNDS - x <= view->width * view->zoom / view->stretch)) #define Y_IN_BOUNDS(view, h, y) \ ((y + PAN_BOUNDS <= h) && (PAN_BOUNDS - y <= view->height * view->zoom * view->stretch)) #define FOV_MIN AL_TO_RADIANS(10.0) #define FOV_MAX AL_TO_RADIANS(160.0) #define VIEW_ON_ITS_SIDE(view) \ (view->rotation % CAMU_VIEW_ROTATION_180 == CAMU_VIEW_ROTATION_90) void camu_view_init(struct camu_view *view, u32 width, u32 height, u8 rotation) { view->mode = CAMU_DEFAULT_VIEW; view->rotation = rotation; view->width = width; view->height = height; view->zindex = 0; view->stretch = 1.0; view->fov = AL_TO_RADIANS(CAMU_DEFAULT_FOV); } void camu_view_calculate(struct camu_view *view, u32 window_width, u32 window_height) { u32 width, height; if (VIEW_ON_ITS_SIDE(view)) { width = view->height; height = view->width; view->stretch = height / (f64)width; } else { width = view->width; height = view->height; view->stretch = 1.0; } f64 frame_ratio = width / (f64)height; f64 ratio = window_width / (f64)window_height; switch (view->mode) { case CAMU_VIEW_AUTOFIT: if (frame_ratio > ratio) { view->zoom = window_width / (f64)width; } else { view->zoom = window_height / (f64)height; } break; case CAMU_VIEW_ZOOM: if (frame_ratio < ratio) { view->zoom = window_width / (f64)width; } else { view->zoom = window_height / (f64)height; } break; default: return; } view->x_offset = (window_width - (width * view->zoom)) / 2.0; view->y_offset = (window_height - (height * view->zoom)) / 2.0; } bool camu_view_pan_simple(struct camu_view *view, u32 window_width, u32 window_height, f64 dx, f64 dy) { f64 nx = view->x_offset + dx; f64 ny = view->y_offset + dy; bool view_changed = false; if (X_IN_BOUNDS(view, window_width, nx)) { view->x_offset = nx; view_changed = true; } if (Y_IN_BOUNDS(view, window_height, ny)) { view->y_offset = ny; view_changed = true; } return view_changed; } bool camu_view_zoom_simple(struct camu_view *view, u32 window_width, u32 window_height, f64 x, f64 y, f64 v) { x -= view->x_offset; y -= view->y_offset; x /= view->zoom; y /= view->zoom; f64 prev_width = window_width * view->zoom; f64 prev_height = window_height * view->zoom; f64 x_ratio = x / (f64)window_width; f64 y_ratio = y / (f64)window_height; f64 zoom = view->zoom + (v * view->zoom); if (zoom > ZOOM_MAX || zoom < ZOOM_MIN) return false; x = view->x_offset - x_ratio * ((window_width * zoom) - prev_width); y = view->y_offset - y_ratio * ((window_height * zoom) - prev_height); if (!(X_IN_BOUNDS(view, window_width, x) && Y_IN_BOUNDS(view, window_height, y))) { return false; } view->x_offset = x; view->y_offset = y; view->zoom = zoom; return true; } bool camu_view_zoom_fov(struct camu_view *view, f64 v) { f64 fov = view->fov - v; if (fov > FOV_MAX || fov < FOV_MIN) return false; view->fov = fov; return true; }