mod common;
use {
anyhow::{Error, Result},
fna3d::Color,
sdl2::{event::Event, EventPump},
std::{mem, time::Duration},
};
use self::common::{
embedded,
gfx::{Shader2d, Texture2dDrop, Vertex},
};
const W: u32 = 1280;
const H: u32 = 720;
pub fn main() -> Result<()> {
env_logger::init();
let title = "Rust-FNA3D texture example";
let init = common::init(title, (W, H))?;
let pump = init.sdl.event_pump().map_err(Error::msg)?;
self::run(pump, init)
}
fn run(mut pump: EventPump, init: common::Init) -> Result<()> {
let mut game = self::GameData::new(init)?;
'running: loop {
for ev in pump.poll_iter() {
match ev {
Event::Quit { .. } => break 'running,
_ => {}
}
}
std::thread::sleep(Duration::from_nanos(1_000_000_000 / 30));
game.tick()?;
}
Ok(())
}
pub struct GameData {
init: common::Init,
draw: DrawData,
verts: Vec<Vertex>,
tex: Texture2dDrop,
}
impl GameData {
pub fn new(init: common::Init) -> Result<Self> {
let tex = Texture2dDrop::from_encoded_bytes(&init.device, embedded::ICON);
let color = Color::rgb(255, 255, 255);
let verts = {
let pos = (100.0, 100.0);
let size = (tex.w as f32 / 2.0, tex.h as f32 / 2.0);
vec![
Vertex::new([pos.0, pos.1, 0.0], [0.0, 0.0], color),
Vertex::new([pos.0 + size.0, pos.1, 0.0], [1.0, 0.0], color),
Vertex::new([pos.0, pos.1 + size.1, 0.0], [0.0, 1.0], color),
Vertex::new([pos.0 + size.0, pos.1 + size.1, 0.0], [1.0, 1.0], color),
]
};
let draw = DrawData::new(init.device.clone(), verts.len() as u32)?;
Ok(Self {
init,
draw,
verts,
tex,
})
}
pub fn tick(&mut self) -> Result<()> {
self.init.device.clear(
fna3d::ClearOptions::TARGET,
Color::rgb(120, 180, 140).to_vec4(),
0.0, 0, );
self.draw.draw_quads(&self.verts, self.tex.raw)?;
self.init
.device
.swap_buffers(None, None, self.init.raw_window() as *mut _);
Ok(())
}
}
#[derive(Debug)]
pub struct DrawData {
device: fna3d::Device,
shader: Shader2d,
vbuf: *mut fna3d::Buffer,
vbind: fna3d::VertexBufferBinding,
ibuf: *mut fna3d::Buffer,
}
impl Drop for DrawData {
fn drop(&mut self) {
self.device.add_dispose_vertex_buffer(self.vbuf);
self.device.add_dispose_index_buffer(self.ibuf);
}
}
impl DrawData {
pub fn new(device: fna3d::Device, n_verts: u32) -> Result<Self> {
let shader = Shader2d::new(&device, W, H)?;
let vbuf = device.gen_vertex_buffer(
true,
fna3d::BufferUsage::None,
n_verts * mem::size_of::<Vertex>() as u32,
);
let ibuf = device.gen_index_buffer(false, fna3d::BufferUsage::None, 16 * n_verts);
{
let data = [0 as i16, 1, 2, 3, 2, 1];
device.set_index_buffer_data(ibuf, 0, &data, fna3d::SetDataOptions::None);
}
let vbind = fna3d::VertexBufferBinding {
vertexBuffer: vbuf,
vertexDeclaration: Vertex::DECLARATION,
vertexOffset: 0,
instanceFrequency: 0,
};
Ok(Self {
device,
shader,
vbuf,
vbind,
ibuf,
})
}
pub fn draw_quads(&mut self, verts: &[Vertex], tex: *mut fna3d::Texture) -> Result<()> {
self.shader.apply_to_device();
{
let offset = 0;
self.device.set_vertex_buffer_data(
self.vbuf,
offset,
&verts,
fna3d::SetDataOptions::None,
);
}
{
let sampler = fna3d::SamplerState::default();
let slot = 0;
self.device.verify_sampler(slot, tex, &sampler);
}
{
let base_vtx = 0;
let base_vtx_idx = 0;
let n_verts = verts.len() as u32;
let base_idx = 0;
let n_triangles = n_verts / 2;
self.device
.apply_vertex_buffer_bindings(&[self.vbind], true, base_vtx);
self.device.draw_indexed_primitives(
fna3d::PrimitiveType::TriangleList,
base_vtx,
base_vtx_idx,
n_verts,
base_idx,
n_triangles,
self.ibuf,
fna3d::IndexElementSize::Bits16,
);
}
Ok(())
}
}