2024-10-25 12:10:59 +02:00
|
|
|
pub mod render;
|
2024-10-25 15:00:57 +02:00
|
|
|
pub mod shapes;
|
2024-11-12 11:09:50 +01:00
|
|
|
pub mod state;
|
|
|
|
pub mod utils;
|
|
|
|
|
2024-10-21 16:24:40 +02:00
|
|
|
use skia_safe as skia;
|
2024-11-12 11:09:50 +01:00
|
|
|
|
|
|
|
use crate::state::State;
|
|
|
|
use crate::utils::uuid_from_u32_quartet;
|
2024-10-21 16:24:40 +02:00
|
|
|
|
2024-11-12 11:09:50 +01:00
|
|
|
static mut STATE: Option<Box<State>> = None;
|
2024-11-14 12:08:50 +01:00
|
|
|
|
2024-11-14 11:47:10 +01:00
|
|
|
extern "C" {
|
|
|
|
fn emscripten_GetProcAddress(
|
|
|
|
name: *const ::std::os::raw::c_char,
|
|
|
|
) -> *const ::std::os::raw::c_void;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init_gl() {
|
|
|
|
unsafe {
|
|
|
|
gl::load_with(|addr| {
|
|
|
|
let addr = std::ffi::CString::new(addr).unwrap();
|
|
|
|
emscripten_GetProcAddress(addr.into_raw() as *const _) as *const _
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2024-10-21 16:24:40 +02:00
|
|
|
|
|
|
|
/// This is called from JS after the WebGL context has been created.
|
|
|
|
#[no_mangle]
|
2024-11-12 11:09:50 +01:00
|
|
|
pub extern "C" fn init(width: i32, height: i32) {
|
|
|
|
let state_box = Box::new(State::with_capacity(width, height, 2048));
|
|
|
|
unsafe {
|
|
|
|
STATE = Some(state_box);
|
|
|
|
}
|
2024-10-21 16:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This is called from JS when the window is resized.
|
|
|
|
/// # Safety
|
|
|
|
#[no_mangle]
|
2024-11-12 11:09:50 +01:00
|
|
|
pub unsafe extern "C" fn resize_surface(width: i32, height: i32) {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-14 11:47:10 +01:00
|
|
|
state.render_state.resize(width, height);
|
2024-10-21 16:24:40 +02:00
|
|
|
}
|
|
|
|
|
2024-10-25 15:00:57 +02:00
|
|
|
#[no_mangle]
|
2024-11-12 11:09:50 +01:00
|
|
|
pub unsafe extern "C" fn draw_all_shapes(zoom: f32, pan_x: f32, pan_y: f32) {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-14 12:08:50 +01:00
|
|
|
state.draw_all_shapes(zoom, pan_x, pan_y);
|
2024-11-12 11:09:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern "C" fn reset_canvas() {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-14 12:08:50 +01:00
|
|
|
state.render_state().reset_canvas();
|
2024-11-12 11:09:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
|
|
|
let id = uuid_from_u32_quartet(a, b, c, d);
|
2024-11-13 15:00:20 +01:00
|
|
|
state.use_shape(id);
|
2024-11-12 11:09:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn set_shape_selrect(x1: f32, y1: f32, x2: f32, y2: f32) {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
|
|
|
|
2024-11-13 15:00:20 +01:00
|
|
|
if let Some(shape) = state.current_shape() {
|
2024-11-12 11:09:50 +01:00
|
|
|
shape.selrect.x1 = x1;
|
|
|
|
shape.selrect.y1 = y1;
|
|
|
|
shape.selrect.x2 = x2;
|
|
|
|
shape.selrect.y2 = y2;
|
|
|
|
}
|
2024-10-21 16:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2024-11-12 11:09:50 +01:00
|
|
|
pub unsafe extern "C" fn set_shape_rotation(rotation: f32) {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-13 15:00:20 +01:00
|
|
|
if let Some(shape) = state.current_shape() {
|
2024-11-12 11:09:50 +01:00
|
|
|
shape.rotation = rotation;
|
|
|
|
}
|
2024-10-21 16:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2024-11-12 15:56:33 +01:00
|
|
|
pub unsafe extern "C" fn set_shape_transform(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) {
|
2024-11-12 11:09:50 +01:00
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-13 15:00:20 +01:00
|
|
|
if let Some(shape) = state.current_shape() {
|
2024-11-12 15:56:33 +01:00
|
|
|
shape.transform.a = a;
|
|
|
|
shape.transform.b = b;
|
|
|
|
shape.transform.c = c;
|
|
|
|
shape.transform.d = d;
|
|
|
|
shape.transform.e = e;
|
|
|
|
shape.transform.f = f;
|
2024-11-12 11:09:50 +01:00
|
|
|
}
|
2024-10-21 16:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2024-11-13 11:48:29 +01:00
|
|
|
pub extern "C" fn add_shape_child(a: u32, b: u32, c: u32, d: u32) {
|
2024-11-12 11:09:50 +01:00
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-12 15:56:33 +01:00
|
|
|
let id = uuid_from_u32_quartet(a, b, c, d);
|
2024-11-13 15:00:20 +01:00
|
|
|
if let Some(shape) = state.current_shape() {
|
2024-11-13 11:48:29 +01:00
|
|
|
shape.children.push(id);
|
2024-11-13 10:56:00 +01:00
|
|
|
}
|
2024-10-21 16:24:40 +02:00
|
|
|
}
|
|
|
|
|
2024-10-25 15:00:57 +02:00
|
|
|
#[no_mangle]
|
2024-11-13 11:48:29 +01:00
|
|
|
pub extern "C" fn clear_shape_children() {
|
2024-11-12 11:09:50 +01:00
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-13 15:00:20 +01:00
|
|
|
if let Some(shape) = state.current_shape() {
|
2024-11-13 11:48:29 +01:00
|
|
|
shape.children.clear();
|
2024-11-13 10:56:00 +01:00
|
|
|
}
|
2024-10-25 15:00:57 +02:00
|
|
|
}
|
|
|
|
|
2024-11-13 12:12:14 +01:00
|
|
|
#[no_mangle]
|
|
|
|
pub extern "C" fn add_shape_solid_fill(r: u8, g: u8, b: u8, a: f32) {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-13 15:00:20 +01:00
|
|
|
if let Some(shape) = state.current_shape() {
|
2024-11-13 12:12:14 +01:00
|
|
|
let alpha: u8 = (a * 0xff as f32).floor() as u8;
|
|
|
|
let color = skia::Color::from_argb(alpha, r, g, b);
|
|
|
|
shape.add_fill(shapes::Fill::from(color));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern "C" fn clear_shape_fills() {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
2024-11-13 15:00:20 +01:00
|
|
|
if let Some(shape) = state.current_shape() {
|
2024-11-13 12:12:14 +01:00
|
|
|
shape.clear_fills();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-13 16:39:26 +01:00
|
|
|
#[no_mangle]
|
|
|
|
pub extern "C" fn set_shape_blend_mode(mode: i32) {
|
|
|
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
|
|
|
if let Some(shape) = state.current_shape() {
|
|
|
|
shape.set_blend_mode(shapes::BlendMode::from(mode));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-21 16:24:40 +02:00
|
|
|
fn main() {
|
2024-11-14 11:47:10 +01:00
|
|
|
init_gl();
|
2024-10-21 16:24:40 +02:00
|
|
|
}
|