canary-rs/crates/script/src/lib.rs

207 lines
5.4 KiB
Rust

// Copyright (c) 2022 Marceline Cramer
// SPDX-License-Identifier: Apache-2.0
pub use canary_types::*;
pub mod draw;
#[macro_export]
macro_rules! export_abi {
($panel_impl: ident) => {
#[no_mangle]
pub extern "C" fn bind_panel(panel: u32, msg: u32) -> u32 {
::canary_script::abi::bind_panel::<$panel_impl>(panel, msg)
}
#[no_mangle]
pub extern "C" fn update(panel_data: u32, dt: f32) {
::canary_script::abi::update(panel_data, dt)
}
#[no_mangle]
pub extern "C" fn draw(panel_data: u32) {
::canary_script::abi::draw(panel_data)
}
#[no_mangle]
pub extern "C" fn on_cursor_event(panel_data: u32, kind: u32, x: f32, y: f32) {
::canary_script::abi::on_cursor_event(panel_data, kind, x, y)
}
#[no_mangle]
pub extern "C" fn on_message(panel_data: u32, msg: u32) {
::canary_script::abi::on_message(panel_data, msg)
}
};
}
pub mod abi {
use super::*;
use num_traits::FromPrimitive;
static mut PANEL_IMPLS: Vec<Box<dyn PanelImpl>> = Vec::new();
pub fn bind_panel<T: BindPanel>(panel: u32, msg: u32) -> u32 {
unsafe {
let panel = Panel(panel);
let msg = Message(msg);
let panel_impl = T::bind(panel, msg);
let id = PANEL_IMPLS.len() as u32;
PANEL_IMPLS.push(panel_impl);
id
}
}
pub fn update(panel_data: u32, dt: f32) {
let panel = unsafe { &mut PANEL_IMPLS[panel_data as usize] };
panel.update(dt);
}
pub fn draw(panel_data: u32) {
let panel = unsafe { &mut PANEL_IMPLS[panel_data as usize] };
panel.draw();
}
pub fn on_cursor_event(panel_data: u32, kind: u32, x: f32, y: f32) {
let panel = unsafe { &mut PANEL_IMPLS[panel_data as usize] };
let at = canary_types::Vec2 { x, y };
let kind = CursorEventKind::from_u32(kind).unwrap();
panel.on_cursor_event(kind, at);
}
pub fn on_message(panel_data: u32, msg: u32) {
let panel = unsafe { &mut PANEL_IMPLS[panel_data as usize] };
let msg = Message(msg);
panel.on_message(msg)
}
}
pub trait BindPanel {
fn bind(panel: Panel, msg: Message) -> Box<dyn PanelImpl>;
}
pub trait PanelImpl {
fn update(&mut self, dt: f32);
fn draw(&mut self);
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2);
fn on_message(&mut self, msg: Message);
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct Panel(u32);
impl Panel {
pub unsafe fn bind(id: u32) -> Self {
Self(id)
}
pub fn draw_indexed(&self, vertices: &[MeshVertex], indices: &[MeshIndex]) {
unsafe {
draw_indexed(
vertices.as_ptr() as u32,
vertices.len() as u32,
indices.as_ptr() as u32,
indices.len() as u32,
)
}
}
pub fn draw_text_layout(&self, layout: &TextLayout, offset: Vec2, scale: f32, color: Color) {
unsafe {
draw_text_layout(
layout.0, offset.x, offset.y, scale, color.r, color.g, color.b, color.a,
)
}
}
pub fn draw_triangle(&self, v1: Vec2, v2: Vec2, v3: Vec2, color: Color) {
let vertices = [
MeshVertex {
position: v1,
color,
},
MeshVertex {
position: v2,
color,
},
MeshVertex {
position: v3,
color,
},
];
let indices = [0, 1, 2];
self.draw_indexed(&vertices, &indices);
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct Font(u32);
impl Font {
pub fn new(family: &str) -> Self {
unsafe { Self(font_load(family.as_ptr() as u32, family.len() as u32)) }
}
}
#[repr(transparent)]
pub struct TextLayout(u32);
impl TextLayout {
pub fn new(font: &Font, text: &str) -> Self {
unsafe {
Self(text_layout_new(
font.0,
text.as_ptr() as u32,
text.len() as u32,
))
}
}
pub fn get_bounds(&self) -> Rect {
unsafe {
let mut bounds = Rect::default();
let bounds_ptr: *mut Rect = &mut bounds;
text_layout_get_bounds(self.0, bounds_ptr as u32);
bounds
}
}
}
impl Drop for TextLayout {
fn drop(&mut self) {
unsafe { text_layout_delete(self.0) }
}
}
#[repr(transparent)]
pub struct Message(u32);
impl Message {
pub fn to_vec(self) -> Vec<u8> {
unsafe {
let len = message_get_len(self.0) as usize;
let mut vec = Vec::with_capacity(len);
vec.set_len(len);
message_get_data(self.0, vec.as_ptr() as u32);
vec
}
}
}
extern "C" {
fn draw_indexed(vertices_ptr: u32, vertices_num: u32, indices_ptr: u32, indices_num: u32);
fn draw_text_layout(id: u32, xoff: f32, yoff: f32, scale: f32, r: f32, g: f32, b: f32, a: f32);
fn font_load(family_ptr: u32, family_len: u32) -> u32;
fn text_layout_new(font_id: u32, text_ptr: u32, text_len: u32) -> u32;
fn text_layout_delete(id: u32);
fn text_layout_get_bounds(id: u32, rect_ptr: u32);
fn message_get_len(id: u32) -> u32;
fn message_get_data(id: u32, ptr: u32);
}