use crate::buffer::Buffer;
use crate::ffi::*;
use crate::render::pipeline::{CullMode, DepthStencilState, RenderPipeline, Winding};
use crate::texture::Texture;
use std::ffi::c_void;
#[derive(Debug, Clone, Copy)]
#[repr(usize)]
pub enum PrimitiveType {
Point = MTLPrimitiveTypePoint,
Line = MTLPrimitiveTypeLine,
LineStrip = MTLPrimitiveTypeLineStrip,
Triangle = MTLPrimitiveTypeTriangle,
TriangleStrip = MTLPrimitiveTypeTriangleStrip,
}
#[derive(Debug, Clone, Copy)]
#[repr(usize)]
pub enum IndexType {
UInt16 = MTLIndexTypeUInt16,
UInt32 = MTLIndexTypeUInt32,
}
impl IndexType {
pub fn size(self) -> usize {
match self {
IndexType::UInt16 => 2,
IndexType::UInt32 => 4,
}
}
}
pub struct RenderEncoder {
raw: ObjcId,
owned: bool,
ended: std::cell::Cell<bool>,
}
impl RenderEncoder {
pub(crate) fn from_raw(raw: ObjcId, owned: bool) -> Self {
RenderEncoder {
raw,
owned,
ended: std::cell::Cell::new(false),
}
}
#[inline(always)]
pub fn bind(&self, pipeline: &RenderPipeline) {
unsafe { msg1_void(self.raw, SEL_setRenderPipelineState(), pipeline.as_raw()) };
}
#[inline(always)]
pub fn set_vertex_buffer(&self, index: u32, buffer: &Buffer, offset: usize) {
unsafe {
msg3_void(
self.raw,
SEL_setVertexBuffer_offset_atIndex(),
buffer.as_raw(),
offset,
index as NSUInteger,
)
};
}
#[inline(always)]
pub fn set_fragment_buffer(&self, index: u32, buffer: &Buffer, offset: usize) {
unsafe {
msg3_void(
self.raw,
SEL_setFragmentBuffer_offset_atIndex(),
buffer.as_raw(),
offset,
index as NSUInteger,
)
};
}
#[inline(always)]
pub fn push_vertex(&self, data: &[u8], index: u32) {
unsafe {
msg_bytes_void(
self.raw,
SEL_setVertexBytes_length_atIndex(),
data.as_ptr() as *const c_void,
data.len(),
index as NSUInteger,
)
};
}
#[inline(always)]
pub fn push_fragment(&self, data: &[u8], index: u32) {
unsafe {
msg_bytes_void(
self.raw,
SEL_setFragmentBytes_length_atIndex(),
data.as_ptr() as *const c_void,
data.len(),
index as NSUInteger,
)
};
}
#[inline(always)]
pub fn set_vertex_texture(&self, index: u32, texture: &Texture) {
unsafe {
type F = unsafe extern "C" fn(ObjcId, ObjcSel, ObjcId, NSUInteger);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(
self.raw,
SEL_setVertexTexture_atIndex(),
texture.as_raw(),
index as NSUInteger,
);
}
}
#[inline(always)]
pub fn set_fragment_texture(&self, index: u32, texture: &Texture) {
unsafe {
type F = unsafe extern "C" fn(ObjcId, ObjcSel, ObjcId, NSUInteger);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(
self.raw,
SEL_setFragmentTexture_atIndex(),
texture.as_raw(),
index as NSUInteger,
);
}
}
#[inline]
pub fn set_viewport(&self, x: f64, y: f64, w: f64, h: f64, near: f64, far: f64) {
unsafe {
let v = MTLViewport {
origin_x: x,
origin_y: y,
width: w,
height: h,
znear: near,
zfar: far,
};
type F = unsafe extern "C" fn(ObjcId, ObjcSel, MTLViewport);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(self.raw, SEL_setViewport(), v);
}
}
#[inline]
pub fn set_scissor(&self, x: u32, y: u32, w: u32, h: u32) {
unsafe {
let r = MTLScissorRect {
x: x as NSUInteger,
y: y as NSUInteger,
width: w as NSUInteger,
height: h as NSUInteger,
};
type F = unsafe extern "C" fn(ObjcId, ObjcSel, MTLScissorRect);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(self.raw, SEL_setScissorRect(), r);
}
}
#[inline]
pub fn set_cull_mode(&self, mode: CullMode) {
unsafe { msg1_uint_void(self.raw, SEL_setCullMode(), mode as NSUInteger) };
}
#[inline]
pub fn set_front_facing_winding(&self, winding: Winding) {
unsafe { msg1_uint_void(self.raw, SEL_setFrontFacingWinding(), winding as NSUInteger) };
}
#[inline]
pub fn set_depth_stencil_state(&self, state: &DepthStencilState) {
unsafe { msg1_void(self.raw, SEL_setDepthStencilState(), state.as_raw()) };
}
#[inline]
pub fn set_depth_bias(&self, bias: f32, slope_scale: f32, clamp: f32) {
unsafe {
type F = unsafe extern "C" fn(ObjcId, ObjcSel, f32, f32, f32);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(self.raw, SEL_setDepthBias(), bias, slope_scale, clamp);
}
}
#[inline(always)]
pub fn draw(&self, primitive: PrimitiveType, start: u32, count: u32) {
unsafe {
type F = unsafe extern "C" fn(ObjcId, ObjcSel, NSUInteger, NSUInteger, NSUInteger);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(
self.raw,
SEL_drawPrimitives_vertexStart_vertexCount(),
primitive as NSUInteger,
start as NSUInteger,
count as NSUInteger,
);
}
}
#[inline(always)]
pub fn draw_instanced(&self, primitive: PrimitiveType, start: u32, count: u32, instances: u32) {
unsafe {
type F = unsafe extern "C" fn(
ObjcId,
ObjcSel,
NSUInteger,
NSUInteger,
NSUInteger,
NSUInteger,
);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(
self.raw,
SEL_drawPrimitives_vertexStart_vertexCount_instanceCount(),
primitive as NSUInteger,
start as NSUInteger,
count as NSUInteger,
instances as NSUInteger,
);
}
}
#[inline(always)]
pub fn draw_indexed(
&self,
primitive: PrimitiveType,
index_count: u32,
index_type: IndexType,
index_buffer: &Buffer,
index_buffer_offset: usize,
) {
unsafe {
type F = unsafe extern "C" fn(
ObjcId,
ObjcSel,
NSUInteger,
NSUInteger,
NSUInteger,
ObjcId,
NSUInteger,
);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(
self.raw,
SEL_drawIndexedPrimitives(),
primitive as NSUInteger,
index_count as NSUInteger,
index_type as NSUInteger,
index_buffer.as_raw(),
index_buffer_offset,
);
}
}
#[inline(always)]
pub fn draw_indexed_instanced(
&self,
primitive: PrimitiveType,
index_count: u32,
index_type: IndexType,
index_buffer: &Buffer,
index_buffer_offset: usize,
instances: u32,
) {
unsafe {
type F = unsafe extern "C" fn(
ObjcId,
ObjcSel,
NSUInteger,
NSUInteger,
NSUInteger,
ObjcId,
NSUInteger,
NSUInteger,
);
let f: F = std::mem::transmute(objc_msgSend as *const c_void);
f(
self.raw,
SEL_drawIndexedPrimitives_instanced(),
primitive as NSUInteger,
index_count as NSUInteger,
index_type as NSUInteger,
index_buffer.as_raw(),
index_buffer_offset,
instances as NSUInteger,
);
}
}
#[inline(always)]
pub fn end(self) {
self.ended.set(true);
unsafe { msg0_void(self.raw, SEL_endEncoding()) };
}
pub fn as_raw(&self) -> ObjcId {
self.raw
}
}
impl Drop for RenderEncoder {
#[mutants::skip] fn drop(&mut self) {
if !self.ended.get() {
unsafe { msg0_void(self.raw, SEL_endEncoding()) };
}
if self.owned {
unsafe { release_nonnull(self.raw) };
}
}
}