use crate::buffer::{GpuBuffer, GpuDeviceExt};
use vek::{Aabr, Vec2};
use wgpu::{BufferUsages, Device};
const LABEL: Option<&str> = Some("Camera");
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(C)]
pub struct Camera {
pub position: Vec2<f32>,
pub base_dimensions: Vec2<f32>,
pub zoom: Vec2<f32>,
_padding: [f32; 2],
_more_padding: [f32; 24 + 32],
}
pub type GpuCamera = GpuBuffer<Camera>;
unsafe impl bytemuck::Zeroable for Camera {}
unsafe impl bytemuck::Pod for Camera {}
pub const AMOUNT: u32 = 1150 * 1000;
pub const MAX_WIDTH: u32 = 1500;
pub const MAX_HEIGHT: u32 = 1150;
fn aspect_ratio_to_dimensions(aspect_ratio: f32) -> Vec2<f32> {
let mut width = (AMOUNT as f32 * aspect_ratio).sqrt();
let mut height = width / aspect_ratio;
if width > MAX_WIDTH as f32 {
width = MAX_WIDTH as f32;
height = width / aspect_ratio;
}
if height > MAX_HEIGHT as f32 {
height = MAX_HEIGHT as f32;
width = height * aspect_ratio;
}
Vec2::new(width / 32., height / 32.)
}
impl GpuCamera {
pub fn upload(camera: &Camera, device: &Device) -> Self {
device.buffer(camera, LABEL, BufferUsages::UNIFORM | BufferUsages::VERTEX)
}
}
impl Camera {
pub fn new_with_dimensions(base_dimensions: Vec2<f32>) -> Self {
Self {
position: Vec2::new(0., 0.),
base_dimensions,
zoom: Vec2::new(1., 1.),
_padding: [21.; 2],
_more_padding: [21.; 24 + 32],
}
}
pub fn new(aspect_ratio: f32) -> Self {
Self::new_with_dimensions(aspect_ratio_to_dimensions(aspect_ratio))
}
pub fn switch_aspect_ratio(&mut self, aspect_ratio: f32) {
self.base_dimensions = aspect_ratio_to_dimensions(aspect_ratio);
}
pub fn relative_map_position(&self, position: Vec2<f32>) -> Vec2<f32> {
let adjusted_position = position - Vec2::new(0.5, 0.5);
adjusted_position * self.base_dimensions * self.zoom
}
pub fn map_position(&self, position: Vec2<f32>) -> Vec2<f32> {
let relative_position = self.relative_map_position(position);
self.position + relative_position
}
pub fn move_to(&mut self, map_position: Vec2<f32>, logical_position: Vec2<f32>) {
let relative_position = self.relative_map_position(logical_position);
self.position = map_position - relative_position;
}
pub fn world_perspective_size(&self, parallax: Vec2<f32>) -> Vec2<f32> {
let parallax_zoom = parallax.x.max(parallax.y);
let parallax_zoom_factor = Vec2::lerp(Vec2::one(), self.zoom, parallax_zoom);
self.base_dimensions * parallax_zoom_factor
}
pub fn world_perspective(&self, parallax: Vec2<f32>) -> Aabr<f32> {
let tile_counts = self.world_perspective_size(parallax);
let camera_position = self.position * parallax;
Aabr {
min: camera_position - tile_counts / 2.,
max: camera_position + tile_counts / 2.,
}
}
}