use crate::{
StereoKitError,
material::{Material, MaterialT},
maths::{Matrix, Rect},
mesh::{Mesh, MeshT},
model::{Model, ModelT},
system::{IAsset, RenderClear, RenderLayer, assets_releaseref_threadsafe},
tex::{Tex, TexT},
util::Color128,
};
use std::{
self,
ffi::{CStr, CString, c_char, c_void},
ptr::NonNull,
};
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct RenderList(pub NonNull<_RenderListT>);
impl Drop for RenderList {
fn drop(&mut self) {
unsafe { assets_releaseref_threadsafe(self.0.as_ptr() as *mut c_void) };
}
}
impl AsRef<RenderList> for RenderList {
fn as_ref(&self) -> &RenderList {
self
}
}
#[repr(C)]
#[derive(Debug)]
pub struct _RenderListT {
_unused: [u8; 0],
}
pub type RenderListT = *mut _RenderListT;
unsafe extern "C" {
pub fn render_list_find(id: *const c_char) -> RenderListT;
pub fn render_list_set_id(render_list: RenderListT, id: *const c_char);
pub fn render_list_get_id(render_list: RenderListT) -> *const c_char;
pub fn render_get_primary_list() -> RenderListT;
pub fn render_list_create() -> RenderListT;
pub fn render_list_addref(list: RenderListT);
pub fn render_list_release(list: RenderListT);
pub fn render_list_clear(list: RenderListT);
pub fn render_list_item_count(list: RenderListT) -> i32;
pub fn render_list_prev_count(list: RenderListT) -> i32;
pub fn render_list_add_mesh(
list: RenderListT,
mesh: MeshT,
material: MaterialT,
transform: Matrix,
color_linear: Color128,
render_layer: RenderLayer,
);
pub fn render_list_add_model(
list: RenderListT,
model: ModelT,
transform: Matrix,
color_linear: Color128,
render_layer: RenderLayer,
);
pub fn render_list_add_model_mat(
list: RenderListT,
model: ModelT,
material_override: MaterialT,
transform: Matrix,
color_linear: Color128,
render_layer: RenderLayer,
);
pub fn render_list_draw_now(
list: RenderListT,
to_rendertarget: TexT,
camera: Matrix,
projection: Matrix,
clear_color: Color128,
clear: RenderClear,
viewport_pct: Rect,
layer_filter: RenderLayer,
material_variant: i32,
);
pub fn render_list_push(list: RenderListT);
pub fn render_list_pop();
}
impl Default for RenderList {
fn default() -> Self {
Self::new()
}
}
impl IAsset for RenderList {
fn get_id(&self) -> &str {
self.get_id()
}
}
impl RenderList {
pub fn new() -> Self {
RenderList(NonNull::new(unsafe { render_list_create() }).unwrap())
}
pub fn find<S: AsRef<str>>(id: S) -> Result<RenderList, StereoKitError> {
let c_str = CString::new(id.as_ref())?;
let render_list = NonNull::new(unsafe { render_list_find(c_str.as_ptr()) });
match render_list {
Some(render_list) => Ok(RenderList(render_list)),
None => Err(StereoKitError::RenderListFind(id.as_ref().to_owned(), "not found".to_owned())),
}
}
pub fn clone_ref(&self) -> RenderList {
RenderList(
NonNull::new(unsafe { render_list_find(render_list_get_id(self.0.as_ptr())) })
.expect("<asset>::clone_ref failed!"),
)
}
pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
let cstr_id = CString::new(id.as_ref()).unwrap();
unsafe { render_list_set_id(self.0.as_ptr(), cstr_id.as_ptr()) };
self
}
pub fn clear(&mut self) -> &mut Self {
unsafe { render_list_clear(self.0.as_ptr()) }
self
}
pub fn add_mesh(
&mut self,
mesh: impl AsRef<Mesh>,
material: impl AsRef<Material>,
transform: impl Into<Matrix>,
color_linear: impl Into<Color128>,
layer: Option<RenderLayer>,
) -> &mut Self {
let layer = layer.unwrap_or(RenderLayer::Layer0);
unsafe {
render_list_add_mesh(
self.0.as_ptr(),
mesh.as_ref().0.as_ptr(),
material.as_ref().0.as_ptr(),
transform.into(),
color_linear.into(),
layer,
)
}
self
}
pub fn add_model(
&mut self,
model: impl AsRef<Model>,
material_override: Option<Material>,
transform: impl Into<Matrix>,
color_linear: impl Into<Color128>,
layer: Option<RenderLayer>,
) -> &mut Self {
let layer = layer.unwrap_or(RenderLayer::Layer0);
match material_override {
Some(material) => unsafe {
render_list_add_model_mat(
self.0.as_ptr(),
model.as_ref().0.as_ptr(),
material.as_ref().0.as_ptr(),
transform.into(),
color_linear.into(),
layer,
)
},
None => unsafe {
render_list_add_model(
self.0.as_ptr(),
model.as_ref().0.as_ptr(),
transform.into(),
color_linear.into(),
layer,
)
},
}
self
}
#[allow(clippy::too_many_arguments)]
pub fn draw_now(
&mut self,
to_rendertarget: impl AsRef<Tex>,
camera: impl Into<Matrix>,
projection: impl Into<Matrix>,
clear_color: Option<Color128>,
clear: Option<RenderClear>,
viewport_pct: Rect,
layer_filter: Option<RenderLayer>,
material_variant: Option<i32>,
) {
let layer_filter = layer_filter.unwrap_or(RenderLayer::all());
let clear = clear.unwrap_or(RenderClear::All);
let clear_color = clear_color.unwrap_or_default();
let material_variant = material_variant.unwrap_or(0);
unsafe {
render_list_draw_now(
self.0.as_ptr(),
to_rendertarget.as_ref().0.as_ptr(),
camera.into(),
projection.into(),
clear_color,
clear,
viewport_pct,
layer_filter,
material_variant,
)
}
}
pub fn primary() -> Self {
RenderList(NonNull::new(unsafe { render_get_primary_list() }).unwrap())
}
pub fn push(&mut self) {
unsafe { render_list_push(self.0.as_ptr()) }
}
pub fn pop() {
unsafe { render_list_pop() }
}
pub fn get_id(&self) -> &str {
unsafe { CStr::from_ptr(render_list_get_id(self.0.as_ptr())) }.to_str().unwrap()
}
pub fn get_count(&self) -> i32 {
unsafe { render_list_item_count(self.0.as_ptr()) }
}
pub fn get_prev_count(&self) -> i32 {
unsafe { render_list_prev_count(self.0.as_ptr()) }
}
}