use crate::__gl;
use crate::{Device, Filter, Framebuffer, Pipeline, Region};
use std::{mem, ops::Range};
#[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),
Vec2([f32; 2]),
Vec3([f32; 3]),
Vec4([f32; 4]),
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 unsafe 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) => {
self.0.ProgramUniform1ui(pipeline.0, location, *val as _);
}
Constant::F32(val) => {
self.0.ProgramUniform1f(pipeline.0, location, *val as _);
}
Constant::Vec2(v) => {
self.0.ProgramUniform2f(pipeline.0, location, v[0], v[1]);
}
Constant::Vec3(v) => {
self.0
.ProgramUniform3f(pipeline.0, location, v[0], v[1], v[2]);
}
Constant::Vec4(v) => {
self.0
.ProgramUniform4f(pipeline.0, location, v[0], v[1], v[2], v[3]);
}
Constant::Mat3x3(mat) => {
self.0.ProgramUniformMatrix3fv(
pipeline.0,
location,
1,
__gl::FALSE,
mat.as_ptr() as *const _,
);
}
Constant::Mat4x4(mat) => {
self.0.ProgramUniformMatrix4fv(
pipeline.0,
location,
1,
__gl::FALSE,
mat.as_ptr() as *const _,
);
}
}
}
}
pub unsafe 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<_>>();
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<_>>();
self.0
.DepthRangeArrayv(first, viewports.len() as _, depth_ranges.as_ptr());
}
pub unsafe 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<_>>();
self.0
.ScissorArrayv(first, scissors.len() as _, scissors_raw.as_ptr());
}
pub unsafe fn set_depth_bias(&self, constant_factor: f32, slope_factor: f32) {
self.0.PolygonOffset(slope_factor, constant_factor);
}
pub unsafe fn draw(&self, primitive: Primitive, vertices: Range<u32>, instance: Range<u32>) {
self.0.DrawArraysInstancedBaseInstance(
primitive as _,
vertices.start as _,
(vertices.end - vertices.start) as _,
(instance.end - instance.start) as _,
instance.start as _,
);
}
pub unsafe fn draw_indexed(
&self,
primitive: Primitive,
index_ty: IndexTy,
indices: Range<u32>,
instance: Range<u32>,
base_vertex: i32,
) {
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 unsafe fn draw_indirect(&self, primitive: Primitive, offset: u64, count: u32, stride: u32) {
self.0
.MultiDrawArraysIndirect(primitive as _, offset as _, count as _, stride as _);
}
pub unsafe fn draw_indirect_from_host(&self, primitive: Primitive, data: &[DrawIndirectCmd]) {
self.0.MultiDrawArraysIndirect(
primitive as _,
data.as_ptr() as *const _,
data.len() as _,
mem::size_of::<DrawIndirectCmd>() as _,
);
}
pub unsafe fn draw_indexed_indirect(
&self,
primitive: Primitive,
index_ty: IndexTy,
offset: u64,
count: u32,
stride: u32,
) {
self.0.MultiDrawElementsIndirect(
primitive as _,
index_ty as _,
offset as _,
count as _,
stride as _,
);
}
pub unsafe fn draw_indexed_indirect_from_host(
&self,
primitive: Primitive,
index_ty: IndexTy,
data: &[DrawIndexedIndirectCmd],
) {
self.0.MultiDrawElementsIndirect(
primitive as _,
index_ty as _,
data.as_ptr() as *const _,
data.len() as _,
mem::size_of::<DrawIndexedIndirectCmd>() as _,
);
}
pub unsafe fn dispatch(&self, x: u32, y: u32, z: u32) {
self.0.DispatchCompute(x, y, z);
}
pub unsafe fn dispatch_indirect(&self, offset: u64) {
self.0.DispatchComputeIndirect(offset as _);
}
pub unsafe fn blit(
&self,
src: Framebuffer,
src_region: Region,
dst: Framebuffer,
dst_region: Region,
filter: Filter,
) {
self.0.BlitNamedFramebuffer(
src.0,
dst.0,
src_region.x,
src_region.x,
src_region.w,
src_region.h,
dst_region.x,
dst_region.x,
dst_region.w,
dst_region.h,
__gl::COLOR_BUFFER_BIT,
filter as _,
);
}
pub unsafe fn draw_mesh_tasks_nv(&self, task_count: u32, first_task: u32) {
self.0.DrawMeshTasksNV(first_task, task_count);
}
pub unsafe fn draw_mesh_tasks_indirect_nv(&self, offset: u64, draw_count: u32, stride: u32) {
self.0
.MultiDrawMeshTasksIndirectNV(offset as _, draw_count as _, stride as _);
}
pub unsafe fn draw_mesh_tasks_indirect_count_nv(
&self,
offset: u64,
count_buffer_offset: u64,
max_draw_count: u32,
stride: u32,
) {
self.0.MultiDrawMeshTasksIndirectCountNV(
offset as _,
count_buffer_offset as _,
max_draw_count as _,
stride as _,
);
}
}