use {
anyhow::{Error, Result},
fna3d::Color,
std::mem,
};
use super::embedded;
#[derive(Debug, Clone)]
pub struct Texture2dDrop {
device: fna3d::Device,
pub raw: *mut fna3d::Texture,
pub w: u32,
pub h: u32,
}
impl Drop for Texture2dDrop {
fn drop(&mut self) {
self.device.add_dispose_texture(self.raw);
}
}
impl Texture2dDrop {
pub fn from_encoded_bytes(device: &fna3d::Device, bytes: &[u8]) -> Self {
let (ptr, len, [w, h]) = fna3d::img::from_encoded_bytes(bytes);
if ptr == std::ptr::null_mut() {
panic!("Unable to read the encoded bytes as an image!");
}
let pixels: &[u8] = unsafe { std::slice::from_raw_parts(ptr, len as usize) };
let tex = Self::from_decoded_bytes(device, w, h, pixels);
fna3d::img::free(ptr);
tex
}
pub fn from_decoded_bytes(device: &fna3d::Device, w: u32, h: u32, pixels: &[u8]) -> Self {
let raw = device.create_texture_2d(fna3d::SurfaceFormat::Color, w, h, 1, false);
device.set_texture_data_2d(raw, 0, 0, w, h, 0, pixels);
Self {
device: device.clone(),
raw,
w,
h,
}
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct Vertex {
pub dst: [f32; 3],
pub color: Color,
pub uv: [f32; 2],
}
impl Default for Vertex {
fn default() -> Self {
Self {
dst: [0.0, 0.0, 0.0],
color: Color::rgba(255, 255, 255, 255),
uv: [0.0, 0.0],
}
}
}
impl Vertex {
pub fn new(dst: [f32; 3], uv: [f32; 2], color: Color) -> Self {
Self { dst, uv, color }
}
const ELEMS: &'static [fna3d::VertexElement; 3] = &[
fna3d::VertexElement {
offset: 0,
vertexElementFormat: fna3d::VertexElementFormat::Vector3 as u32,
vertexElementUsage: fna3d::VertexElementUsage::Position as u32,
usageIndex: 0,
},
fna3d::VertexElement {
offset: 12,
vertexElementFormat: fna3d::VertexElementFormat::Color as u32,
vertexElementUsage: fna3d::VertexElementUsage::Color as u32,
usageIndex: 0,
},
fna3d::VertexElement {
offset: 16,
vertexElementFormat: fna3d::VertexElementFormat::Vector2 as u32,
vertexElementUsage: fna3d::VertexElementUsage::TextureCoordinate as u32,
usageIndex: 0,
},
];
pub const DECLARATION: fna3d::VertexDeclaration = fna3d::VertexDeclaration {
vertexStride: mem::size_of::<Vertex>() as i32,
elementCount: 3,
elements: Self::ELEMS as *const _ as *mut _,
};
}
#[derive(Debug)]
pub struct Shader2d {
device: fna3d::Device,
effect: *mut fna3d::Effect,
effect_data: *mut fna3d::mojo::Effect,
}
impl Drop for Shader2d {
fn drop(&mut self) {
self.device.add_dispose_effect(self.effect);
}
}
impl Shader2d {
pub fn new(device: &fna3d::Device, w: u32, h: u32) -> Result<Self> {
let (effect, effect_data) =
fna3d::mojo::from_bytes(&device, embedded::SHADER).map_err(Error::msg)?;
Self::set_mat(effect_data, w as f32, h as f32)?;
Ok(Self {
device: device.clone(),
effect,
effect_data,
})
}
fn set_mat(
data: *mut fna3d::mojo::Effect,
w: f32,
h: f32,
) -> std::result::Result<(), std::ffi::NulError> {
let mat = fna3d::mojo::orthographic_off_center(0.0, w as f32, h as f32, 0.0, 1.0, 0.0);
let name = "MatrixTransform";
unsafe {
let name = std::ffi::CString::new(name)?;
if !fna3d::mojo::set_param(data, &name, &mat) {
eprintln!("Failed to set MatrixTransform shader paramter. Probablly we're not using `SpriteEffect.fxb`");
}
};
Ok(())
}
pub fn apply_to_device(&self) {
let pass = 0;
self.device
.apply_effect(self.effect, pass, &fna3d::utils::no_change_effect());
}
}