1use geng::prelude::*;
2
3use crate::conversions::Vec2RealConversions;
4
5pub fn pixel_perfect_pos(
7 pos: vec2<f32>,
8 camera: &impl geng::AbstractCamera2d,
9 framebuffer_size: vec2<f32>,
10) -> vec2<f32> {
11 let pos = camera_world_to_screen(pos, camera, framebuffer_size);
13 let pos = pos.map(f32::floor);
14 camera.screen_to_world(framebuffer_size, pos)
16}
17
18pub fn pixel_perfect_aabb(
20 pos: vec2<f32>,
21 align: vec2<f32>,
22 size: vec2<usize>,
23 camera: &impl geng::AbstractCamera2d,
24 framebuffer_size: vec2<f32>,
25) -> Aabb2<f32> {
26 let pos = camera_world_to_screen(pos, camera, framebuffer_size);
28 let align_size = (size.as_f32() * align).map(f32::fract);
29 let pos = pos.map(f32::floor) + align_size;
30 let screen_aabb = Aabb2::point(pos).extend_symmetric(size.as_f32() / 2.0);
31 screen_aabb.map_bounds(|pos| camera.screen_to_world(framebuffer_size, pos))
33}
34
35fn camera_world_to_screen(
36 pos: vec2<f32>,
37 camera: &impl geng::AbstractCamera2d,
38 framebuffer_size: vec2<f32>,
39) -> vec2<f32> {
40 let pos = (camera.projection_matrix(framebuffer_size) * camera.view_matrix()) * pos.extend(1.0);
41 let pos = pos.xy() / pos.z;
42 vec2(
46 (pos.x + 1.0) / 2.0 * framebuffer_size.x,
47 (pos.y + 1.0) / 2.0 * framebuffer_size.y,
48 )
49}