use __gl;
use std::mem;
use std::ops::Range;
use device::Device;
use {Pipeline, Region};
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum Primitive {
Points = __gl::POINTS,
Lines = __gl::LINES,
LineStrip = __gl::LINE_STRIP,
Triangles = __gl::TRIANGLES,
TriangleStrip = __gl::TRIANGLE_STRIP,
LinesAdjacency = __gl::LINES_ADJACENCY,
LinesStripAdjacency = __gl::LINE_STRIP_ADJACENCY,
TrianglesAdjacency = __gl::TRIANGLES_ADJACENCY,
TrianglesStripAdjacency = __gl::TRIANGLE_STRIP_ADJACENCY,
Patches = __gl::PATCHES,
}
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum IndexTy {
U8 = __gl::UNSIGNED_BYTE,
U16 = __gl::UNSIGNED_SHORT,
U32 = __gl::UNSIGNED_INT,
}
impl IndexTy {
fn size(&self) -> u32 {
match *self {
IndexTy::U8 => 1,
IndexTy::U16 => 2,
IndexTy::U32 => 4,
}
}
}
pub struct Viewport {
pub x: f32,
pub y: f32,
pub w: f32,
pub h: f32,
pub n: f64,
pub f: f64,
}
pub enum Constant {
U32(u32),
F32(f32),
Vec3([f32; 3]),
Mat3x3([[f32; 3]; 3]),
Mat4x4([[f32; 4]; 4]),
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct DrawIndirectCmd {
pub vertex_count: u32,
pub instance_count: u32,
pub first_vertex: u32,
pub first_instance: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct DrawIndexedIndirectCmd {
pub index_count: u32,
pub instance_count: u32,
pub first_index: u32,
pub base_vertex: i32,
pub first_instance: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct DispatchIndirectCmd {
pub x: u32,
pub y: u32,
pub z: u32,
}
impl Device {
pub fn bind_uniform_constants(&self, pipeline: &Pipeline, first: u32, constants: &[Constant]) {
for (i, constant) in constants.iter().enumerate() {
let location = first as i32 + i as i32;
match constant {
Constant::U32(val) => unsafe {
self.0.ProgramUniform1ui(pipeline.0, location, *val as _);
},
Constant::F32(val) => unsafe {
self.0.ProgramUniform1f(pipeline.0, location, *val as _);
},
Constant::Vec3(v) => unsafe {
self.0
.ProgramUniform3f(pipeline.0, location, v[0], v[1], v[2]);
},
Constant::Mat3x3(mat) => unsafe {
self.0.ProgramUniformMatrix3fv(
pipeline.0,
location,
1,
__gl::FALSE,
mat.as_ptr() as *const _,
);
},
Constant::Mat4x4(mat) => unsafe {
self.0.ProgramUniformMatrix4fv(
pipeline.0,
location,
1,
__gl::FALSE,
mat.as_ptr() as *const _,
);
},
}
}
}
pub fn set_viewport(&self, first: u32, viewports: &[Viewport]) {
let rects = viewports
.iter()
.flat_map(|viewport| vec![viewport.x, viewport.y, viewport.w, viewport.h])
.collect::<Vec<_>>();
unsafe {
self.0
.ViewportArrayv(first, viewports.len() as _, rects.as_ptr());
}
let depth_ranges = viewports
.iter()
.flat_map(|viewport| vec![viewport.n, viewport.f])
.collect::<Vec<_>>();
unsafe {
self.0
.DepthRangeArrayv(first, viewports.len() as _, depth_ranges.as_ptr());
}
}
pub fn set_scissor(&self, first: u32, scissors: &[Region]) {
let scissors_raw = scissors
.iter()
.flat_map(|scissor| vec![scissor.x, scissor.y, scissor.w, scissor.h])
.collect::<Vec<_>>();
unsafe {
self.0
.ScissorArrayv(first, scissors.len() as _, scissors_raw.as_ptr());
}
}
pub fn draw(&self, primitive: Primitive, vertices: Range<u32>, instance: Range<u32>) {
unsafe {
self.0.DrawArraysInstancedBaseInstance(
primitive as _,
vertices.start as _,
(vertices.end - vertices.start) as _,
(instance.end - instance.start) as _,
instance.start as _,
)
}
}
pub fn draw_indexed(
&self,
primitive: Primitive,
index_ty: IndexTy,
indices: Range<u32>,
instance: Range<u32>,
base_vertex: i32,
) {
unsafe {
self.0.DrawElementsInstancedBaseVertexBaseInstance(
primitive as _,
(indices.end - indices.start) as _,
index_ty as _,
(index_ty.size() * indices.start) as _,
(instance.end - instance.start) as _,
base_vertex,
instance.start as _,
)
}
}
pub fn draw_indirect(&self, primitive: Primitive, offset: u64, count: u32, stride: u32) {
unsafe {
self.0
.MultiDrawArraysIndirect(primitive as _, offset as _, count as _, stride as _);
}
}
pub fn draw_indirect_from_host(&self, primitive: Primitive, data: &[DrawIndirectCmd]) {
unsafe {
self.0.MultiDrawArraysIndirect(
primitive as _,
data.as_ptr() as *const _,
data.len() as _,
mem::size_of::<DrawIndirectCmd>() as _,
);
}
}
pub fn draw_indexed_indirect(
&self,
primitive: Primitive,
index_ty: IndexTy,
offset: u64,
count: u32,
stride: u32,
) {
unsafe {
self.0.MultiDrawElementsIndirect(
primitive as _,
index_ty as _,
offset as _,
count as _,
stride as _,
);
}
}
pub fn draw_indexed_indirect_from_host(
&self,
primitive: Primitive,
index_ty: IndexTy,
data: &[DrawIndexedIndirectCmd],
) {
unsafe {
self.0.MultiDrawElementsIndirect(
primitive as _,
index_ty as _,
data.as_ptr() as *const _,
data.len() as _,
mem::size_of::<DrawIndirectCmd>() as _,
);
}
}
pub fn dispatch(&self, x: u32, y: u32, z: u32) {
unsafe {
self.0.DispatchCompute(x, y, z);
}
}
pub fn dispatch_indirect(&self, offset: u64) {
unsafe {
self.0.DispatchComputeIndirect(offset as _);
}
}
}