use anyhow::Result;
use glam::f32::{vec2, Mat4, Vec2, Vec4};
use vulkano::{buffer::BufferContents, pipeline::graphics::vertex_input::Vertex as VTX};
use super::{Loader, ModelData};
use parking_lot::Mutex;
use std::sync::Arc;
#[repr(C)]
#[derive(BufferContents, VTX, Debug, Clone, Copy, PartialEq)]
pub struct Vertex {
#[format(R32G32_SFLOAT)]
pub position: Vec2,
#[format(R32G32_SFLOAT)]
pub tex_position: Vec2,
}
#[inline]
pub const fn vert(x: f32, y: f32) -> Vertex {
Vertex {
position: vec2(x, y),
tex_position: vec2(x, y),
}
}
#[inline]
pub const fn tvert(x: f32, y: f32, tx: f32, ty: f32) -> Vertex {
Vertex {
position: vec2(x, y),
tex_position: vec2(tx, ty),
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, BufferContents)]
pub(crate) struct ModelViewProj {
pub model: Mat4,
pub view: Mat4,
pub proj: Mat4,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, BufferContents, VTX)]
pub(crate) struct InstanceData {
#[format(R32G32B32A32_SFLOAT)]
pub color: Vec4,
#[format(R32_UINT)]
pub layer: u32,
#[format(R32G32B32A32_SFLOAT)]
pub model: Mat4,
#[format(R32G32B32A32_SFLOAT)]
pub view: Mat4,
#[format(R32G32B32A32_SFLOAT)]
pub proj: Mat4,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, BufferContents)]
pub(crate) struct ObjectFrag {
pub color: Vec4,
pub texture_id: u32,
}
impl Default for ObjectFrag {
fn default() -> Self {
Self {
color: Vec4::splat(0.0),
texture_id: 0,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Data {
Fixed {
vertices: &'static [Vertex],
indices: &'static [u32],
},
Dynamic {
vertices: Vec<Vertex>,
indices: Vec<u32>,
},
}
impl Data {
pub const fn new_dynamic(vertices: Vec<Vertex>, indices: Vec<u32>) -> Self {
Self::Dynamic { vertices, indices }
}
pub const fn new_fixed(vertices: &'static [Vertex], indices: &'static [u32]) -> Self {
Self::Fixed { vertices, indices }
}
pub fn square() -> Self {
Data::Fixed {
vertices: &SQUARE,
indices: &SQUARE_ID,
}
}
pub fn triangle() -> Self {
Data::Fixed {
vertices: &TRIANGLE,
indices: &TRIANGLE_ID,
}
}
pub fn is_empty(&self) -> bool {
match self {
Self::Fixed { vertices, indices } => vertices.is_empty() || indices.is_empty(),
Self::Dynamic { vertices, indices } => vertices.is_empty() || indices.is_empty(),
}
}
pub fn vertices(&self) -> &[Vertex] {
match self {
Self::Fixed { vertices, .. } => vertices,
Self::Dynamic { vertices, .. } => vertices,
}
}
pub fn indices(&self) -> &[u32] {
match self {
Self::Fixed { indices, .. } => indices,
Self::Dynamic { indices, .. } => indices,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct BasicShapes {
pub square: ModelData,
pub triangle: ModelData,
}
impl BasicShapes {
pub fn new(loader: &Arc<Mutex<Loader>>) -> Result<Self> {
Ok(Self {
square: ModelData::new_from_loader(Data::square(), loader)?,
triangle: ModelData::new_from_loader(Data::triangle(), loader)?,
})
}
}
#[allow(dead_code)]
const TRIANGLE: [Vertex; 3] = [vert(0.0, -1.0), vert(-1.0, 1.0), vert(1.0, 1.0)];
#[allow(dead_code)]
const TRIANGLE_ID: [u32; 3] = [0, 1, 2];
#[allow(dead_code)]
const SQUARE: [Vertex; 4] = [
vert(-1.0, -1.0),
vert(1.0, -1.0),
vert(-1.0, 1.0),
vert(1.0, 1.0),
];
#[allow(dead_code)]
const SQUARE_ID: [u32; 6] = [0, 1, 2, 1, 2, 3];
#[macro_export]
macro_rules! make_circle {
($corners:expr) => {{ use let_engine::prelude::{vec2, Vertex};
let corners = $corners;
let mut vertices: Vec<Vertex> = vec![];
let mut indices: Vec<u32> = vec![];
use core::f64::consts::TAU;
vertices.push(Vertex {
position: vec2(0.0, 0.0),
tex_position: vec2(0.0, 0.0),
});
for i in 0..corners {
vertices.push(vert(
(TAU * ((i as f64) / corners as f64)).cos() as f32,
(TAU * ((i as f64) / corners as f64)).sin() as f32,
));
}
for i in 0..corners - 1 { indices.extend([0, i + 1, i + 2]);
}
indices.extend([0, corners, 1]);
Data::Dynamic { vertices, indices }
}};
($corners:expr, $percent:expr) => {{ use core::f64::consts::TAU;
use let_engine::prelude::{vec2, Vertex};
let corners = $corners;
let percent = $percent as f64;
let percent: f64 = percent.clamp(0.0, 1.0);
let mut vertices: Vec<Vertex> = vec![];
let mut indices: Vec<u32> = vec![];
let count = TAU * percent;
vertices.push(vert(0.0, 0.0));
for i in 0..corners + 1 {
vertices.push(vert(
(count * ((i as f64) / corners as f64)).cos() as f32,
(count * ((i as f64) / corners as f64)).sin() as f32,
));
}
for i in 0..corners {
indices.extend([0, i + 1, i + 2]);
}
Data::Dynamic { vertices, indices }
}};
}