use crate::gfx;
use gfx::Buffer;
use gfx::CmdBuf;
use maths_rs::prelude::*;
struct DynamicBuffer<D: gfx::Device> {
cpu_data: Vec<f32>,
gpu_data: Vec<D::Buffer>,
gpu_data_size: Vec<usize>,
vertex_count: u32
}
#[repr(C)]
struct ImDrawVertex2d {
_position: [f32; 2],
_color: [f32; 4],
}
#[repr(C)]
struct ImDrawVertex3d {
_position: [f32; 3],
_color: [f32; 4],
}
pub struct ImDrawInfo {
pub initial_buffer_size_2d: usize,
pub initial_buffer_size_3d: usize
}
pub struct ImDraw<D: gfx::Device> {
vertices_2d: DynamicBuffer<D>,
vertices_3d: DynamicBuffer<D>
}
impl<D> ImDraw<D> where D: gfx::Device {
fn new_buffer_2d_info(num_elements: usize) -> gfx::BufferInfo {
gfx::BufferInfo {
usage: gfx::BufferUsage::VERTEX,
cpu_access: gfx::CpuAccessFlags::WRITE,
format: gfx::Format::Unknown,
stride: std::mem::size_of::<ImDrawVertex2d>(),
num_elements,
initial_state: gfx::ResourceState::VertexConstantBuffer
}
}
fn new_buffer_3d_info(num_elements: usize) -> gfx::BufferInfo {
gfx::BufferInfo {
usage: gfx::BufferUsage::VERTEX,
cpu_access: gfx::CpuAccessFlags::WRITE,
format: gfx::Format::Unknown,
stride: std::mem::size_of::<ImDrawVertex3d>(),
num_elements,
initial_state: gfx::ResourceState::VertexConstantBuffer
}
}
pub fn create(info: &ImDrawInfo) -> Result<Self, super::Error> {
Ok(ImDraw {
vertices_2d: DynamicBuffer {
cpu_data: Vec::with_capacity(info.initial_buffer_size_2d),
gpu_data: Vec::new(),
gpu_data_size: Vec::new(),
vertex_count: 0
},
vertices_3d: DynamicBuffer {
cpu_data: Vec::with_capacity(info.initial_buffer_size_3d),
gpu_data: Vec::new(),
gpu_data_size: Vec::new(),
vertex_count: 0
},
})
}
pub fn add_vertex_2d(&mut self, v: Vec2f, col: Vec4f) {
for i in 0..2 {
self.vertices_2d.cpu_data.push(v[i])
}
for i in 0..4 {
self.vertices_2d.cpu_data.push(col[i])
}
}
pub fn add_line_2d(&mut self, start: Vec2f, end: Vec2f, col: Vec4f) {
self.add_vertex_2d(start, col);
self.add_vertex_2d(end, col);
}
pub fn add_tri_2d(&mut self, p1: Vec2f, p2: Vec2f, p3: Vec2f, col: Vec4f) {
self.add_vertex_2d(p1, col);
self.add_vertex_2d(p2, col);
self.add_vertex_2d(p2, col);
self.add_vertex_2d(p3, col);
self.add_vertex_2d(p3, col);
self.add_vertex_2d(p1, col);
}
pub fn add_rect_2d(&mut self, p: Vec2f, size: Vec2f, col: Vec4f) {
let p1 = p + Vec2f::new(size.x, 0.0);
let p2 = p + size;
let p3 = p + Vec2f::new(0.0, size.y);
self.add_vertex_2d(p, col);
self.add_vertex_2d(p1, col);
self.add_vertex_2d(p1, col);
self.add_vertex_2d(p2, col);
self.add_vertex_2d(p2, col);
self.add_vertex_2d(p3, col);
self.add_vertex_2d(p3, col);
self.add_vertex_2d(p, col);
}
pub fn add_vertex_3d(&mut self, v: Vec3f, col: Vec4f) {
for i in 0..3 {
self.vertices_3d.cpu_data.push(v[i])
}
for i in 0..4 {
self.vertices_3d.cpu_data.push(col[i])
}
}
pub fn add_line_3d(&mut self, start: Vec3f, end: Vec3f, col: Vec4f) {
self.add_vertex_3d(start, col);
self.add_vertex_3d(end, col);
}
pub fn add_point_3d(&mut self, pos: Vec3f, size: f32, col: Vec4f) {
self.add_line_3d(pos - Vec3f::unit_x() * size, pos + Vec3f::unit_x() * size, col);
self.add_line_3d(pos - Vec3f::unit_y() * size, pos + Vec3f::unit_y() * size, col);
self.add_line_3d(pos - Vec3f::unit_z() * size, pos + Vec3f::unit_z() * size, col);
}
pub fn add_circle_3d_xz(&mut self, pos: Vec3f, radius: f32, col: Vec4f) {
let segs = 16;
let step = (f32::pi() * 2.0) / segs as f32;
for i in 0..16 {
let ix = i as f32 * step;
let iy = (i + 1) as f32 * step;
self.add_line_3d(pos + Vec3f::new(f32::sin(ix), 0.0, f32::cos(ix)) * radius,
pos + Vec3f::new(f32::sin(iy), 0.0, f32::cos(iy)) * radius, col);
}
}
pub fn add_aabb_3d(&mut self, aabb_min: Vec3f, aabb_max: Vec3f, col: Vec4f) {
self.add_line_3d(vec3f(aabb_min.x, aabb_min.y, aabb_min.z), vec3f(aabb_max.x, aabb_min.y, aabb_min.z), col);
self.add_line_3d(vec3f(aabb_min.x, aabb_min.y, aabb_min.z), vec3f(aabb_min.x, aabb_min.y, aabb_max.z), col);
self.add_line_3d(vec3f(aabb_min.x, aabb_min.y, aabb_max.z), vec3f(aabb_max.x, aabb_min.y, aabb_max.z), col);
self.add_line_3d(vec3f(aabb_max.x, aabb_min.y, aabb_max.z), vec3f(aabb_max.x, aabb_min.y, aabb_min.z), col);
self.add_line_3d(vec3f(aabb_min.x, aabb_max.y, aabb_min.z), vec3f(aabb_max.x, aabb_max.y, aabb_min.z), col);
self.add_line_3d(vec3f(aabb_min.x, aabb_max.y, aabb_min.z), vec3f(aabb_min.x, aabb_max.y, aabb_max.z), col);
self.add_line_3d(vec3f(aabb_min.x, aabb_max.y, aabb_max.z), vec3f(aabb_max.x, aabb_max.y, aabb_max.z), col);
self.add_line_3d(vec3f(aabb_max.x, aabb_max.y, aabb_max.z), vec3f(aabb_max.x, aabb_max.y, aabb_min.z), col);
self.add_line_3d(vec3f(aabb_min.x, aabb_min.y, aabb_min.z), vec3f(aabb_min.x, aabb_max.y, aabb_min.z), col);
self.add_line_3d(vec3f(aabb_max.x, aabb_min.y, aabb_min.z), vec3f(aabb_max.x, aabb_max.y, aabb_min.z), col);
self.add_line_3d(vec3f(aabb_max.x, aabb_min.y, aabb_max.z), vec3f(aabb_max.x, aabb_max.y, aabb_max.z), col);
self.add_line_3d(vec3f(aabb_min.x, aabb_min.y, aabb_max.z), vec3f(aabb_min.x, aabb_max.y, aabb_max.z), col);
}
pub fn add_obb_3d(&mut self, obb: Vec<Vec3f>, col: Vec4f) {
self.add_line_3d(vec3f(obb[0].x, obb[0].y, obb[0].z), vec3f(obb[1].x, obb[1].y, obb[1].z), col);
self.add_line_3d(vec3f(obb[1].x, obb[1].y, obb[1].z), vec3f(obb[2].x, obb[2].y, obb[2].z), col);
self.add_line_3d(vec3f(obb[2].x, obb[2].y, obb[2].z), vec3f(obb[3].x, obb[3].y, obb[3].z), col);
self.add_line_3d(vec3f(obb[3].x, obb[3].y, obb[3].z), vec3f(obb[0].x, obb[0].y, obb[0].z), col);
self.add_line_3d(vec3f(obb[4].x, obb[4].y, obb[4].z), vec3f(obb[5].x, obb[5].y, obb[5].z), col);
self.add_line_3d(vec3f(obb[5].x, obb[5].y, obb[5].z), vec3f(obb[6].x, obb[6].y, obb[6].z), col);
self.add_line_3d(vec3f(obb[6].x, obb[6].y, obb[6].z), vec3f(obb[7].x, obb[7].y, obb[7].z), col);
self.add_line_3d(vec3f(obb[7].x, obb[7].y, obb[7].z), vec3f(obb[4].x, obb[4].y, obb[4].z), col);
self.add_line_3d(vec3f(obb[4].x, obb[4].y, obb[4].z), vec3f(obb[0].x, obb[0].y, obb[0].z), col);
self.add_line_3d(vec3f(obb[5].x, obb[5].y, obb[5].z), vec3f(obb[1].x, obb[1].y, obb[1].z), col);
self.add_line_3d(vec3f(obb[6].x, obb[6].y, obb[6].z), vec3f(obb[2].x, obb[2].y, obb[2].z), col);
self.add_line_3d(vec3f(obb[7].x, obb[7].y, obb[7].z), vec3f(obb[3].x, obb[3].y, obb[3].z), col);
}
pub fn add_frustum(&mut self, view_proj: Mat4f, col: Vec4f) {
let corners = view_proj.get_frustum_corners();
let mut obb = Vec::new();
for c in corners {
obb.push(c);
}
self.add_line_3d(obb[0], obb[1], col);
self.add_line_3d(obb[1], obb[3], col);
self.add_line_3d(obb[3], obb[2], col);
self.add_line_3d(obb[2], obb[0], col);
self.add_line_3d(obb[4], obb[5], col);
self.add_line_3d(obb[5], obb[7], col);
self.add_line_3d(obb[7], obb[6], col);
self.add_line_3d(obb[6], obb[4], col);
self.add_line_3d(obb[0], obb[4], col);
self.add_line_3d(obb[1], obb[5], col);
self.add_line_3d(obb[2], obb[6], col);
self.add_line_3d(obb[3], obb[7], col);
}
pub fn submit(&mut self, device: &mut D, buffer_index: usize) -> Result<(), super::Error> {
if !self.vertices_2d.cpu_data.is_empty() {
let num_elems = self.vertices_2d.cpu_data.len() / 6;
while buffer_index >= self.vertices_2d.gpu_data.len() {
self.vertices_2d.gpu_data.push(
device.create_buffer::<u8>(&Self::new_buffer_2d_info(num_elems), None)?
);
self.vertices_2d.gpu_data_size.push(num_elems);
}
if num_elems > self.vertices_2d.gpu_data_size[buffer_index] {
self.vertices_2d.gpu_data[buffer_index] = device.create_buffer::<u8>(
&Self::new_buffer_2d_info(num_elems), None)?;
}
self.vertices_2d.gpu_data[buffer_index].update(0, self.vertices_2d.cpu_data.as_slice())?;
self.vertices_2d.gpu_data_size[buffer_index] = num_elems;
self.vertices_2d.vertex_count = num_elems as u32;
self.vertices_2d.cpu_data.clear();
}
if !self.vertices_3d.cpu_data.is_empty() {
let num_elems = self.vertices_3d.cpu_data.len() / 7;
while buffer_index >= self.vertices_3d.gpu_data.len() {
self.vertices_3d.gpu_data.push(
device.create_buffer::<u8>(&Self::new_buffer_3d_info(num_elems), None)?
);
self.vertices_3d.gpu_data_size.push(num_elems);
}
if num_elems > self.vertices_3d.gpu_data_size[buffer_index] {
self.vertices_3d.gpu_data[buffer_index] = device.create_buffer::<u8>(
&Self::new_buffer_3d_info(num_elems), None)?;
}
self.vertices_3d.gpu_data[buffer_index].update(0, self.vertices_3d.cpu_data.as_slice())?;
self.vertices_3d.gpu_data_size[buffer_index] = num_elems;
self.vertices_3d.vertex_count = num_elems as u32;
self.vertices_3d.cpu_data.clear();
}
Ok(())
}
pub fn draw_2d(&mut self, cmd: &D::CmdBuf, buffer_index: usize) {
if buffer_index < self.vertices_2d.gpu_data.len() {
cmd.set_vertex_buffer(&self.vertices_2d.gpu_data[buffer_index], 0);
cmd.draw_instanced(self.vertices_2d.vertex_count, 1, 0, 0);
}
}
pub fn draw_3d(&mut self, cmd: &D::CmdBuf, buffer_index: usize) {
if buffer_index < self.vertices_3d.gpu_data.len() {
cmd.set_vertex_buffer(&self.vertices_3d.gpu_data[buffer_index], 0);
cmd.draw_instanced(self.vertices_3d.vertex_count, 1, 0, 0);
}
}
}