extern crate self as nsi;
use crate::{argument::*, *};
#[allow(unused_imports)]
use std::{
ffi::{CStr, CString},
marker::PhantomData,
ops::Drop,
os::raw::{c_int, c_void},
slice,
vec::Vec,
};
#[derive(Debug, Hash, PartialEq)]
pub struct Context<'a> {
context: NSIContext_t,
_marker: PhantomData<*mut &'a ()>,
}
impl<'a> From<Context<'a>> for NSIContext_t {
#[inline]
fn from(context: Context<'a>) -> Self {
context.context
}
}
impl<'a> Context<'a> {
#[inline]
pub fn new(args: &ArgSlice<'_, 'a>) -> Option<Self> {
let (args_len, args_ptr, _args_out) = get_c_param_vec(args);
let context = NSI_API.NSIBegin(args_len, args_ptr);
if 0 == context {
None
} else {
Some(Self {
context,
_marker: PhantomData,
})
}
}
#[inline]
pub fn create(
&self,
handle: impl Into<Vec<u8>>,
node_type: impl Into<Vec<u8>>,
args: &ArgSlice<'_, 'a>,
) {
let handle = CString::new(handle).unwrap();
let node_type = CString::new(node_type).unwrap();
let (args_len, args_ptr, _args_out) = get_c_param_vec(args);
NSI_API.NSICreate(
self.context,
handle.as_ptr(),
node_type.as_ptr(),
args_len,
args_ptr,
);
}
#[inline]
pub fn delete(&self, handle: impl Into<Vec<u8>>, args: &ArgSlice<'_, 'a>) {
let handle = CString::new(handle).unwrap();
let (args_len, args_ptr, _args_out) = get_c_param_vec(args);
NSI_API.NSIDelete(self.context, handle.as_ptr(), args_len, args_ptr);
}
#[inline]
pub fn set_attribute(&self, handle: impl Into<Vec<u8>>, args: &ArgSlice<'_, 'a>) {
let handle = CString::new(handle).unwrap();
let (args_len, args_ptr, _args_out) = get_c_param_vec(args);
NSI_API.NSISetAttribute(self.context, handle.as_ptr(), args_len, args_ptr);
}
#[inline]
pub fn set_attribute_at_time(
&self,
handle: impl Into<Vec<u8>>,
time: f64,
args: &ArgSlice<'_, 'a>,
) {
let handle = CString::new(handle).unwrap();
let (args_len, args_ptr, _args_out) = get_c_param_vec(args);
NSI_API.NSISetAttributeAtTime(self.context, handle.as_ptr(), time, args_len, args_ptr);
}
#[inline]
pub fn delete_attribute(&self, handle: impl Into<Vec<u8>>, name: impl Into<Vec<u8>>) {
let handle = CString::new(handle).unwrap();
let name = CString::new(name).unwrap();
NSI_API.NSIDeleteAttribute(self.context, handle.as_ptr(), name.as_ptr());
}
#[inline]
pub fn connect(
&self,
from: impl Into<Vec<u8>>,
from_attr: impl Into<Vec<u8>>,
to: impl Into<Vec<u8>>,
to_attr: impl Into<Vec<u8>>,
args: &ArgSlice<'_, 'a>,
) {
let from = CString::new(from).unwrap();
let from_attr = CString::new(from_attr).unwrap();
let to = CString::new(to).unwrap();
let to_attr = CString::new(to_attr).unwrap();
let (args_len, args_ptr, _args_out) = get_c_param_vec(args);
NSI_API.NSIConnect(
self.context,
from.as_ptr(),
from_attr.as_ptr(),
to.as_ptr(),
to_attr.as_ptr(),
args_len,
args_ptr,
);
}
#[inline]
pub fn disconnect(
&self,
from: impl Into<Vec<u8>>,
from_attr: impl Into<Vec<u8>>,
to: impl Into<Vec<u8>>,
to_attr: impl Into<Vec<u8>>,
) {
let from = CString::new(from).unwrap();
let from_attr = CString::new(from_attr).unwrap();
let to = CString::new(to).unwrap();
let to_attr = CString::new(to_attr).unwrap();
NSI_API.NSIDisconnect(
self.context,
from.as_ptr(),
from_attr.as_ptr(),
to.as_ptr(),
to_attr.as_ptr(),
);
}
#[inline]
pub fn evaluate(&self, args: &ArgSlice<'_, 'a>) {
let (args_len, args_ptr, _args_out) = get_c_param_vec(args);
NSI_API.NSIEvaluate(self.context, args_len, args_ptr);
}
#[inline]
pub fn render_control(&self, args: &ArgSlice<'_, 'a>) {
let (_, _, mut args_out) = get_c_param_vec(args);
let fn_pointer: nsi_sys::NSIRenderStopped_t =
Some(render_status as extern "C" fn(*mut c_void, i32, i32));
if let Some(arg) = args.iter().find_map(|arg| {
if unsafe { CStr::from_bytes_with_nul_unchecked(b"callback\0") } == arg.name.as_c_str()
{
Some(arg)
} else {
None
}
}) {
args_out.push(nsi_sys::NSIParam_t {
name: b"stoppedcallback\0" as *const _ as _,
data: &fn_pointer as *const _ as _,
type_: NSIType_t_NSITypePointer as _,
arraylength: 0,
count: 1,
flags: 0,
});
args_out.push(nsi_sys::NSIParam_t {
name: b"stoppedcallbackdata\0" as *const _ as _,
data: &arg.data.as_c_ptr() as *const _ as _,
type_: NSIType_t_NSITypePointer as _,
arraylength: 1,
count: 1,
flags: 0,
});
}
NSI_API.NSIRenderControl(self.context, args_out.len() as _, args_out.as_ptr());
}
}
impl<'a> Drop for Context<'a> {
#[inline]
fn drop(&mut self) {
NSI_API.NSIEnd(self.context);
}
}
pub enum NodeType {
All,
Root, Global,
Set,
Shader,
Attributes,
Transform,
Instances,
Plane,
Mesh,
FaceSet,
Curves,
Particles,
Procedural,
Volume,
Environment,
Camera,
OrthographicCamera,
PerspectiveCamera,
FisheyeCamera,
CylindricalCamera,
SphericalCamera,
OutputDriver,
OutputLayer,
Screen,
}
impl From<NodeType> for Vec<u8> {
#[inline]
fn from(node_type: NodeType) -> Self {
match node_type {
NodeType::All => b".all".to_vec(),
NodeType::Root => b".root".to_vec(),
NodeType::Global => b".global".to_vec(),
NodeType::Set => b"set".to_vec(),
NodeType::Plane => b"plane".to_vec(),
NodeType::Shader => b"shader".to_vec(),
NodeType::Attributes => b"attributes".to_vec(),
NodeType::Transform => b"transform".to_vec(),
NodeType::Instances => b"instances".to_vec(),
NodeType::Mesh => b"mesh".to_vec(),
NodeType::FaceSet => b"faceset".to_vec(),
NodeType::Curves => b"curves".to_vec(),
NodeType::Particles => b"particles".to_vec(),
NodeType::Procedural => b"procedural".to_vec(),
NodeType::Volume => b"volume".to_vec(),
NodeType::Environment => b"environment".to_vec(),
NodeType::Camera => b"camera".to_vec(),
NodeType::OrthographicCamera => b"orthographiccamera".to_vec(),
NodeType::PerspectiveCamera => b"perspectivecamera".to_vec(),
NodeType::FisheyeCamera => b"fisheyecamera".to_vec(),
NodeType::CylindricalCamera => b"cylindricalcamera".to_vec(),
NodeType::SphericalCamera => b"sphericalcamera".to_vec(),
NodeType::OutputDriver => b"outputdriver".to_vec(),
NodeType::OutputLayer => b"outputlayer".to_vec(),
NodeType::Screen => b"screen".to_vec(),
}
}
}
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, num_enum::FromPrimitive)]
pub enum RenderStatus {
#[num_enum(default)]
Completed = nsi_sys::NSIStoppingStatus_NSIRenderCompleted as _,
Aborted = nsi_sys::NSIStoppingStatus_NSIRenderAborted as _,
Synchronized = nsi_sys::NSIStoppingStatus_NSIRenderSynchronized as _,
Restarted = nsi_sys::NSIStoppingStatus_NSIRenderRestarted as _,
}
pub trait FnStatus<'a>: Fn(
&Context,
RenderStatus,
)
+ 'a {}
#[doc(hidden)]
impl<
'a,
T: Fn(&Context, RenderStatus) + 'a + for<'r, 's> Fn(&'r context::Context<'s>, RenderStatus),
> FnStatus<'a> for T
{
}
pub struct StatusCallback<'a>(Box<Box<dyn FnStatus<'a>>>);
impl<'a> StatusCallback<'a> {
pub fn new<F>(fn_status: F) -> Self
where
F: FnStatus<'a>,
{
StatusCallback(Box::new(Box::new(fn_status)))
}
}
impl CallbackPtr for StatusCallback<'_> {
#[doc(hidden)]
fn to_ptr(self) -> *const core::ffi::c_void {
Box::into_raw(self.0) as *const _ as _
}
}
#[no_mangle]
pub(crate) extern "C" fn render_status(
payload: *mut c_void,
context: nsi_sys::NSIContext_t,
status: c_int,
) {
if !payload.is_null() {
let fn_status = unsafe { Box::from_raw(payload as *mut Box<dyn FnStatus>) };
let ctx = Context {
context,
_marker: PhantomData,
};
fn_status(&ctx, status.into());
std::mem::forget(ctx);
}
}