use rogalik_math::vectors::Vector2f;
use crate::structs::Vertex;
use rogalik_common::SpriteParams;
#[derive(Clone, Copy, Debug, Default)]
pub struct SpriteAtlas {
cols: usize,
pub u_step: f32,
pub v_step: f32,
u_size: f32,
v_size: f32,
sprite_w: f32,
sprite_h: f32,
}
impl SpriteAtlas {
pub fn new(
texture_size: (u32, u32),
rows: usize,
cols: usize,
padding: Option<(f32, f32)>,
) -> Self {
let (sp_w, sp_h) = sprite_pixel_size(texture_size.0, texture_size.1, rows, cols, padding);
Self {
cols,
u_step: 1.0 / cols as f32,
v_step: 1.0 / rows as f32,
u_size: sp_w / texture_size.0 as f32,
v_size: sp_h / texture_size.1 as f32,
sprite_w: sp_w,
sprite_h: sp_h,
}
}
pub fn get_sprite_size(&self) -> (f32, f32) {
(self.sprite_w, self.sprite_h)
}
pub fn get_sprite(
&self,
index: usize,
position: Vector2f,
size: Vector2f,
params: SpriteParams,
) -> ([Vertex; 4], [u16; 6]) {
let row = index / self.cols;
let col = index % self.cols;
let u = self.u_step * col as f32;
let v = self.v_step * row as f32;
let color = params.color.as_srgb();
let l = u;
let r = u + self.u_size;
let b = v + self.v_size;
let t = v;
let mut uvs = [[l, b], [r, b], [r, t], [l, t]];
if params.flip_x {
for uv in uvs.iter_mut() {
if uv[0] == l {
uv[0] = r
} else {
uv[0] = l
}
}
}
if params.flip_y {
for uv in uvs.iter_mut() {
if uv[1] == b {
uv[1] = t
} else {
uv[1] = b
}
}
}
let mut vertices = [
Vertex {
position: [position.x, position.y, 0.0],
color,
tex_coords: uvs[0],
},
Vertex {
position: [position.x + size.x, position.y, 0.0],
color,
tex_coords: uvs[1],
},
Vertex {
position: [position.x + size.x, position.y + size.y, 0.0],
color,
tex_coords: uvs[2],
},
Vertex {
position: [position.x, position.y + size.y, 0.0],
color,
tex_coords: uvs[3],
},
];
if let Some(rotate) = params.rotate {
let cx = position.x + 0.5 * size.x;
let cy = position.y + 0.5 * size.y;
rotate_verts(&mut vertices, rotate, cx, cy);
}
let indices = [0, 1, 2, 0, 2, 3];
(vertices, indices)
}
pub fn get_sliced_sprite(
&self,
index: usize,
position: Vector2f,
size: Vector2f,
params: SpriteParams,
) -> ([Vertex; 16], [u16; 54]) {
let row = index / self.cols;
let col = index % self.cols;
let u = self.u_step * col as f32;
let v = self.v_step * row as f32;
let color = params.color.as_srgb();
let (slice_dim, base_size) = params.slice.unwrap();
let ratio_w = slice_dim as f32 / self.sprite_w;
let ratio_h = slice_dim as f32 / self.sprite_h;
let u_slice = ratio_w * self.u_size;
let v_slice = ratio_h * self.v_size;
let w_slice = ratio_w * base_size.x;
let h_slice = ratio_h * base_size.y;
let mut us = [u, u + u_slice, u + self.u_size - u_slice, u + self.u_size];
let mut vs = [v + self.v_size, v + self.v_size - v_slice, v + v_slice, v];
let xs = [
position.x,
position.x + w_slice,
position.x + size.x - w_slice,
position.x + size.x,
];
let ys = [
position.y,
position.y + h_slice,
position.y + size.y - h_slice,
position.y + size.y,
];
if params.flip_x {
us.reverse();
}
if params.flip_y {
vs.reverse();
}
let mut vertices = [Vertex::default(); 16];
let mut idx = 0;
for (y, v) in ys.iter().zip(vs) {
for (x, u) in xs.iter().zip(us) {
vertices[idx] = Vertex {
position: [*x, *y, 0.0],
color,
tex_coords: [u, v],
};
idx += 1;
}
}
let indices = [
12, 8, 13, 8, 9, 13, 13, 9, 14, 9, 10, 14, 14, 10, 15, 10, 11, 15, 8, 4, 9, 4, 5, 9, 9,
5, 10, 5, 6, 10, 10, 6, 11, 6, 7, 11, 4, 0, 5, 0, 1, 5, 5, 1, 6, 1, 2, 6, 6, 2, 7, 2,
3, 7,
];
if let Some(rotate) = params.rotate {
let cx = position.x + 0.5 * size.x;
let cy = position.y + 0.5 * size.y;
rotate_verts(&mut vertices, rotate, cx, cy);
}
(vertices, indices)
}
}
pub fn sprite_pixel_size(
texture_w: u32,
texture_h: u32,
rows: usize,
cols: usize,
padding: Option<(f32, f32)>,
) -> (f32, f32) {
let grid_width = (texture_w as f32) / (cols as f32);
let grid_height = (texture_h as f32) / (rows as f32);
match padding {
None => (grid_width, grid_height),
Some((x, y)) => (grid_width - x, grid_height - y),
}
}
fn rotate_verts(vertices: &mut [Vertex], angle: f32, cx: f32, cy: f32) {
let c = angle.cos();
let s = angle.sin();
for v in vertices {
v.position[0] -= cx;
v.position[1] -= cy;
let x = v.position[0];
v.position[0] = x * c - v.position[1] * s;
v.position[1] = x * s + v.position[1] * c;
v.position[0] += cx;
v.position[1] += cy;
}
}