summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/Cargo.toml8
-rw-r--r--sys/build.rs8
-rw-r--r--sys/src/lib.rs98
-rw-r--r--sys/src/renderer.rs49
-rw-r--r--sys/src/window.rs116
5 files changed, 279 insertions, 0 deletions
diff --git a/sys/Cargo.toml b/sys/Cargo.toml
new file mode 100644
index 0000000..bb1a70d
--- /dev/null
+++ b/sys/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "alligator_sys"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/sys/build.rs b/sys/build.rs
new file mode 100644
index 0000000..c33a20f
--- /dev/null
+++ b/sys/build.rs
@@ -0,0 +1,8 @@
+fn main() {
+ let out_dir = std::env::var("OUT_DIR").unwrap();
+ eprintln!("{out_dir}");
+ println!("cargo:rustc-link-lib=d3d11");
+ println!("cargo:rustc-link-search=native=./");
+ println!("cargo:rustc-link-lib-static=alligator_backend");
+ println!("cargo:rerun-if-changed=alligator_backend.lib");
+}
diff --git a/sys/src/lib.rs b/sys/src/lib.rs
new file mode 100644
index 0000000..f3fae9c
--- /dev/null
+++ b/sys/src/lib.rs
@@ -0,0 +1,98 @@
+use std::ffi::{c_uchar, c_uint, c_void};
+use std::os::raw::c_char;
+
+mod renderer;
+mod window;
+
+pub use renderer::Renderer;
+pub use window::{Window, WindowConfig, WindowEvent};
+
+type CRenderer = *mut ();
+type CWindow = *mut ();
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[repr(C)]
+pub struct RendererConfig {
+ pub width: c_uint,
+ pub height: c_uint,
+ pub instance_capacity: c_uint,
+ pub fullscreen: bool,
+ pub vsync: bool,
+}
+
+#[repr(C)]
+pub struct Vertex {
+ x: f32,
+ y: f32,
+ z: f32,
+ curve_a: f32,
+ curve_b: f32,
+ color1_r: f32,
+ color1_g: f32,
+ color1_b: f32,
+ color1_a: f32,
+ normal_x: f32,
+ normal_y: f32,
+ normal_z: f32,
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+struct CWindowConfig {
+ default_width: c_uint,
+ default_height: c_uint,
+ default_x: c_uint,
+ default_y: c_uint,
+ title: *const c_char,
+ visible: bool,
+ borderless_fullscreen: bool,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[repr(C)]
+pub enum CWindowEvent {
+ AboutToWait,
+ Other,
+ CloseRequest,
+ ScaleFactorChange,
+ Resume,
+ RedrawRequest,
+}
+
+#[link(name = "alligator_backend", kind = "static")]
+extern "C" {
+ fn new_renderer(config: RendererConfig, window: CWindow) -> CRenderer;
+ fn resize_renderer(renderer: CRenderer, width: c_uint, height: c_uint);
+ fn set_vsync(renderer: CRenderer, vsync: bool);
+ fn create_vertex_buffer(renderer: CRenderer, count: c_uint, instances: *const Vertex);
+ fn set_camera(
+ renderer: CRenderer,
+ x: f32,
+ y: f32,
+ zoom: f32,
+ rotation: f32,
+ width: f32,
+ height: f32,
+ );
+ fn render_frame(renderer: CRenderer);
+ fn destroy_renderer(renderer: CRenderer);
+
+ fn create_window(config: CWindowConfig) -> CWindow;
+ fn set_visible(window: CWindow, visible: bool);
+ fn resize_window(window: CWindow, width: c_uint, height: c_uint);
+ fn set_fullscreen(window: CWindow, fullscreen: bool);
+ fn set_title(window: CWindow, title: *const c_char);
+ fn wait_for_event(window: CWindow);
+ fn pop_event(window: CWindow) -> bool;
+ fn wait_for_resume(window: CWindow);
+ fn set_event_handler(window: CWindow, closure: *mut c_void);
+ fn run_event_handler(window: CWindow, event: CWindowEvent);
+ fn request_redraw(window: CWindow);
+ fn destroy_window(window: CWindow);
+}
+
+#[no_mangle]
+unsafe extern "C" fn alligator_run_closure(closure: *mut c_void, event: CWindowEvent) {
+ let closure: &mut &mut dyn FnMut(CWindowEvent) = unsafe { &mut *closure.cast() };
+ closure(event)
+}
diff --git a/sys/src/renderer.rs b/sys/src/renderer.rs
new file mode 100644
index 0000000..05d111b
--- /dev/null
+++ b/sys/src/renderer.rs
@@ -0,0 +1,49 @@
+use crate::{RendererConfig, Vertex, Window};
+
+pub struct Renderer {
+ ptr: *mut (),
+}
+
+impl Drop for Renderer {
+ fn drop(&mut self) {
+ unsafe { crate::destroy_renderer(self.ptr) }
+ }
+}
+
+impl Renderer {
+ pub fn new(window: &Window, config: RendererConfig) -> Self {
+ let ptr = unsafe { crate::new_renderer(config, window.ptr) };
+ Self { ptr }
+ }
+
+ pub fn resize(&mut self, width: u32, height: u32) {
+ unsafe { crate::resize_renderer(self.ptr, width, height) }
+ }
+
+ pub fn set_vsync(&mut self, vsync: bool) {
+ unsafe { crate::set_vsync(self.ptr, vsync) }
+ }
+
+ pub fn create_vertex_buffer(&mut self, vertices: &[Vertex]) {
+ assert!(vertices.len() < (u32::MAX as usize), "Too many triangles!");
+ let ptr = vertices.as_ptr();
+ let len = vertices.len();
+ unsafe { crate::create_vertex_buffer(self.ptr, len as u32, ptr) }
+ }
+
+ pub fn set_camera(
+ &mut self,
+ x: f32,
+ y: f32,
+ zoom: f32,
+ rotation: f32,
+ width: f32,
+ height: f32,
+ ) {
+ unsafe { crate::set_camera(self.ptr, x, y, zoom, rotation, width, height) }
+ }
+
+ pub fn render_frame(&mut self) {
+ unsafe { crate::render_frame(self.ptr) }
+ }
+}
diff --git a/sys/src/window.rs b/sys/src/window.rs
new file mode 100644
index 0000000..19de5e7
--- /dev/null
+++ b/sys/src/window.rs
@@ -0,0 +1,116 @@
+use std::ffi::{c_void, CString};
+use std::ops::ControlFlow;
+
+use crate::{CWindowConfig, CWindowEvent};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct WindowConfig {
+ pub title: String,
+ pub default_width: u32,
+ pub default_height: u32,
+ pub default_x: u32,
+ pub default_y: u32,
+ pub visible: bool,
+ pub borderless_fullscreen: bool,
+}
+
+pub struct Window {
+ pub(crate) ptr: *mut (),
+}
+
+pub enum WindowEvent {
+ Other = 1,
+ CloseRequest,
+ ScaleFactorChange,
+ Resume,
+ RedrawRequest,
+}
+
+impl Drop for Window {
+ fn drop(&mut self) {
+ unsafe { crate::destroy_window(self.ptr) }
+ }
+}
+
+impl Window {
+ pub fn new(config: WindowConfig) -> Self {
+ let title = CString::new(config.title.as_bytes()).unwrap();
+ let config = CWindowConfig {
+ default_width: config.default_width,
+ default_height: config.default_height,
+ default_x: config.default_x,
+ default_y: config.default_y,
+ visible: config.visible,
+ borderless_fullscreen: config.borderless_fullscreen,
+ title: title.as_ptr(),
+ };
+
+ let window = unsafe { crate::create_window(config) };
+
+ Self { ptr: window }
+ }
+
+ pub fn set_visible(&mut self, visible: bool) {
+ unsafe { crate::set_visible(self.ptr, visible) }
+ }
+
+ pub fn set_title(&mut self, title: &str) {
+ let string = CString::new(title.to_string().as_bytes()).unwrap();
+ let bytes = string.as_ptr();
+ unsafe { crate::set_title(self.ptr, bytes) }
+ }
+
+ pub fn resize(&mut self, width: u32, height: u32) {
+ unsafe { crate::resize_window(self.ptr, width, height) }
+ }
+
+ pub fn set_fullscreen(&mut self, fullscreen: bool) {
+ unsafe { crate::set_fullscreen(self.ptr, fullscreen) }
+ }
+
+ fn translate_event(event: CWindowEvent) -> Option<WindowEvent> {
+ let event = match event {
+ CWindowEvent::AboutToWait => return None,
+ CWindowEvent::Other => WindowEvent::Other,
+ CWindowEvent::CloseRequest => WindowEvent::CloseRequest,
+ CWindowEvent::ScaleFactorChange => WindowEvent::ScaleFactorChange,
+ CWindowEvent::Resume => WindowEvent::Resume,
+ CWindowEvent::RedrawRequest => WindowEvent::RedrawRequest,
+ };
+ Some(event)
+ }
+
+ pub fn wait_for_event(&self) {
+ unsafe { crate::wait_for_event(self.ptr) }
+ }
+
+ pub fn pop_event(&self) -> bool {
+ unsafe { crate::pop_event(self.ptr) }
+ }
+
+ pub fn wait_for_resume(&mut self) {
+ unsafe { crate::wait_for_resume(self.ptr) }
+ }
+
+ pub fn run(&mut self, mut handler: impl FnMut(&mut Window, Option<WindowEvent>)) -> ! {
+ let window_ptr = self.ptr;
+
+ unsafe {
+ let closure = |c_event: CWindowEvent| {
+ handler(self, Self::translate_event(c_event));
+ };
+ let closure_data: Box<Box<dyn FnMut(CWindowEvent)>> = Box::new(Box::new(closure));
+ crate::set_event_handler(window_ptr, Box::into_raw(closure_data) as *mut _);
+ }
+
+ loop {
+ if !self.pop_event() {
+ unsafe { crate::run_event_handler(window_ptr, CWindowEvent::AboutToWait) };
+ }
+ }
+ }
+
+ pub fn request_redraw(&mut self) {
+ unsafe { crate::request_redraw(self.ptr) }
+ }
+}