use crate::math::prelude::Aabb2;
use crate::utils::prelude::{DataBuffer, HashValue};
use super::assets::prelude::*;
use super::backends::frame::Command;
use super::errors::*;
use super::MAX_UNIFORM_VARIABLES;
#[derive(Default)]
pub struct CommandBuffer {
cmds: Vec<Command>,
bufs: DataBuffer,
}
impl CommandBuffer {
#[inline]
pub fn new() -> Self {
CommandBuffer {
cmds: Vec::with_capacity(32),
bufs: DataBuffer::with_capacity(512),
}
}
#[inline]
pub fn draw(&mut self, dc: Draw) {
let len = dc.uniforms_len;
let ptr = self.bufs.extend_from_slice(&dc.uniforms[0..len]);
let cmd = Command::Draw(dc.shader, dc.mesh, dc.mesh_index, ptr);
self.cmds.push(cmd);
}
#[inline]
pub fn update_scissor(&mut self, scissor: SurfaceScissor) {
self.cmds.push(Command::UpdateScissor(scissor));
}
#[inline]
pub fn update_viewport(&mut self, viewport: SurfaceViewport) {
self.cmds.push(Command::UpdateViewport(viewport));
}
#[inline]
pub fn update_texture(&mut self, id: TextureHandle, area: Aabb2<u32>, bytes: &[u8]) {
let bufs = &mut self.bufs;
let ptr = bufs.extend_from_slice(bytes);
self.cmds.push(Command::UpdateTexture(id, area, ptr));
}
#[inline]
pub fn update_vertex_buffer(&mut self, id: MeshHandle, offset: usize, bytes: &[u8]) {
let bufs = &mut self.bufs;
let ptr = bufs.extend_from_slice(bytes);
self.cmds.push(Command::UpdateVertexBuffer(id, offset, ptr));
}
#[inline]
pub fn update_index_buffer(&mut self, id: MeshHandle, offset: usize, bytes: &[u8]) {
let bufs = &mut self.bufs;
let ptr = bufs.extend_from_slice(bytes);
self.cmds.push(Command::UpdateIndexBuffer(id, offset, ptr));
}
pub fn submit(&mut self, surface: SurfaceHandle) -> Result<()> {
let doubele_frame = unsafe { super::frames() };
let mut frame = doubele_frame.write();
frame.cmds.push(Command::Bind(surface));
for v in self.cmds.drain(..) {
match v {
Command::Draw(shader, mesh, mesh_index, ptr) => {
let vars = self.bufs.as_slice(ptr);
let ptr = frame.bufs.extend_from_slice(vars);
let cmd = Command::Draw(shader, mesh, mesh_index, ptr);
frame.cmds.push(cmd);
}
Command::UpdateTexture(id, area, ptr) => {
let ptr = frame.bufs.extend_from_slice(self.bufs.as_slice(ptr));
frame.cmds.push(Command::UpdateTexture(id, area, ptr));
}
Command::UpdateVertexBuffer(id, offset, ptr) => {
let ptr = frame.bufs.extend_from_slice(self.bufs.as_slice(ptr));
let cmd = Command::UpdateVertexBuffer(id, offset, ptr);
frame.cmds.push(cmd);
}
Command::UpdateIndexBuffer(id, offset, ptr) => {
let ptr = frame.bufs.extend_from_slice(self.bufs.as_slice(ptr));
frame.cmds.push(Command::UpdateIndexBuffer(id, offset, ptr));
}
other => frame.cmds.push(other),
}
}
self.bufs.clear();
Ok(())
}
}
pub struct DrawCommandBuffer<T: Ord + Copy> {
cmds: Vec<(T, Command)>,
bufs: DataBuffer,
}
impl<T: Ord + Copy> Default for DrawCommandBuffer<T> {
fn default() -> Self {
DrawCommandBuffer {
cmds: Vec::with_capacity(32),
bufs: DataBuffer::with_capacity(512),
}
}
}
impl<T: Ord + Copy> DrawCommandBuffer<T> {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn draw(&mut self, order: T, dc: Draw) {
let len = dc.uniforms_len;
let ptr = self.bufs.extend_from_slice(&dc.uniforms[0..len]);
let cmd = Command::Draw(dc.shader, dc.mesh, dc.mesh_index, ptr);
self.cmds.push((order, cmd));
}
pub fn submit(&mut self, surface: SurfaceHandle) -> Result<()> {
let doubele_frame = unsafe { super::frames() };
let mut frame = doubele_frame.write();
frame.cmds.push(Command::Bind(surface));
self.cmds.as_mut_slice().sort_by_key(|v| v.0);
for v in self.cmds.drain(..) {
if let (_, Command::Draw(shader, mesh, mesh_index, ptr)) = v {
let vars = self.bufs.as_slice(ptr);
let ptr = frame.bufs.extend_from_slice(vars);
let cmd = Command::Draw(shader, mesh, mesh_index, ptr);
frame.cmds.push(cmd);
}
}
self.bufs.clear();
Ok(())
}
}
#[derive(Debug, Copy, Clone)]
pub struct Draw {
pub(crate) uniforms: [(HashValue<str>, UniformVariable); MAX_UNIFORM_VARIABLES],
pub(crate) uniforms_len: usize,
pub shader: ShaderHandle,
pub mesh: MeshHandle,
pub mesh_index: MeshIndex,
}
impl Draw {
pub fn new(shader: ShaderHandle, mesh: MeshHandle) -> Self {
let nil = (HashValue::zero(), UniformVariable::I32(0));
Draw {
shader,
mesh,
uniforms: [nil; MAX_UNIFORM_VARIABLES],
uniforms_len: 0,
mesh_index: MeshIndex::All,
}
}
pub fn set_uniform_variable<F, V>(&mut self, field: F, variable: V)
where
F: Into<HashValue<str>>,
V: Into<UniformVariable>,
{
assert!(self.uniforms_len < MAX_UNIFORM_VARIABLES);
let field = field.into();
let variable = variable.into();
for i in 0..self.uniforms_len {
if self.uniforms[i].0 == field {
self.uniforms[i] = (field, variable);
return;
}
}
self.uniforms[self.uniforms_len] = (field, variable);
self.uniforms_len += 1;
}
}