diff --git a/Cargo.toml b/Cargo.toml index 3d04ea3..fe2e0dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ "apps/music-player", "apps/sandbox", "crates/script", - "crates/types", "scripts/music-player", "scripts/sao-ui", ] @@ -19,7 +18,7 @@ license = "LGPL-3.0-or-later" allsorts = "0.10" anyhow = "1" bytemuck = "1" -canary_types = { path = "crates/types" } +canary-script = { path = "crates/script" } lyon = "1" ouroboros = "^0.15" parking_lot = "0.12" diff --git a/crates/script/Cargo.toml b/crates/script/Cargo.toml index 55a5eee..f7d45b6 100644 --- a/crates/script/Cargo.toml +++ b/crates/script/Cargo.toml @@ -1,10 +1,12 @@ [package] -name = "canary_script" +name = "canary-script" version = "0.1.0" edition = "2021" license = "Apache-2.0" [dependencies] bitflags = "^1" -canary_types = { path = "../types", features = ["glam"] } -glam = "^0.21" +bytemuck = { version = "1", features = ["derive"] } +glam = { version = "^0.21", features = ["bytemuck"] } +num-derive = "0.3" +num-traits = "0.2" diff --git a/crates/script/src/api/abi.rs b/crates/script/src/api/abi.rs new file mode 100644 index 0000000..737e6da --- /dev/null +++ b/crates/script/src/api/abi.rs @@ -0,0 +1,42 @@ +// Copyright (c) 2022 Marceline Cramer +// SPDX-License-Identifier: Apache-2.0 + +#![allow(dead_code)] + +use super::*; + +static mut PANEL_IMPLS: Vec> = Vec::new(); + +pub fn bind_panel(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 = Vec2::new(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) +} diff --git a/crates/script/src/draw.rs b/crates/script/src/api/mod.rs similarity index 67% rename from crates/script/src/draw.rs rename to crates/script/src/api/mod.rs index 570bef0..ae6f6cd 100644 --- a/crates/script/src/draw.rs +++ b/crates/script/src/api/mod.rs @@ -1,154 +1,148 @@ // Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: Apache-2.0 -use super::{Color, Panel, TextLayout}; -use bitflags::bitflags; -use glam::Vec2; +use super::*; -pub enum Corner { - TopRight, - BottomRight, - BottomLeft, - TopLeft, +pub mod abi; + +#[macro_export] +macro_rules! export_abi { + ($panel_impl: ident) => { + #[no_mangle] + pub extern "C" fn bind_panel(panel: u32, msg: u32) -> u32 { + ::canary_script::api::abi::bind_panel::<$panel_impl>(panel, msg) + } + + #[no_mangle] + pub extern "C" fn update(panel_data: u32, dt: f32) { + ::canary_script::api::abi::update(panel_data, dt) + } + + #[no_mangle] + pub extern "C" fn draw(panel_data: u32) { + ::canary_script::api::abi::draw(panel_data) + } + + #[no_mangle] + pub extern "C" fn on_cursor_event(panel_data: u32, kind: u32, x: f32, y: f32) { + ::canary_script::api::abi::on_cursor_event(panel_data, kind, x, y) + } + + #[no_mangle] + pub extern "C" fn on_message(panel_data: u32, msg: u32) { + ::canary_script::api::abi::on_message(panel_data, msg) + } + }; } -bitflags! { - pub struct CornerFlags: u8 { - const TOP_RIGHT = 0x01; - const BOTTOM_RIGHT = 0x02; - const BOTTOM_LEFT = 0x04; - const TOP_LEFT = 0x08; - const TOP = 0x09; - const RIGHT = 0x03; - const BOTTOM = 0x06; - const LEFT = 0x0C; - const ALL = 0x0F; - } +pub trait BindPanel { + fn bind(panel: Panel, msg: Message) -> Box; } -#[derive(Copy, Clone, Debug)] -pub enum Side { - Top, - Right, - Bottom, - Left, +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 ColoredTriangle { - pub v1: Vec2, - pub v2: Vec2, - pub v3: Vec2, - pub color: Color, +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.0) } + } + + 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 Rect { - pub bl: Vec2, - pub tr: Vec2, -} +pub struct Font(u32); -impl Rect { - pub fn from_xy_size(xy: Vec2, size: Vec2) -> Self { - Self { - bl: xy, - tr: xy + size, - } - } - - pub fn from_circle_bounds(center: Vec2, radius: f32) -> Self { - Self { - bl: center - radius, - tr: center + radius, - } - } - - pub fn from_triangle_bounds(tri: &ColoredTriangle) -> Self { - Self { - bl: tri.v1.min(tri.v2).min(tri.v3), - tr: tri.v1.max(tri.v2).max(tri.v3), - } - } - - pub fn inset(&self, d: f32) -> Self { - Self { - bl: self.bl + d, - tr: self.tr - d, - } - } - - pub fn tl(&self) -> Vec2 { - Vec2::new(self.bl.x, self.tr.y) - } - - pub fn br(&self) -> Vec2 { - Vec2::new(self.tr.x, self.bl.y) - } - - pub fn offset(&self, offset: Vec2) -> Self { - Self { - bl: self.bl + offset, - tr: self.tr + offset, - } - } - - pub fn scale(&self, scale: f32) -> Self { - Self { - bl: self.bl * scale, - tr: self.tr * scale, - } - } - - pub fn is_valid(&self) -> bool { - self.bl.cmplt(self.tr).all() - } - - pub fn intersects_rect(&self, other: &Self) -> bool { - self.bl.cmple(other.tr).all() && self.tr.cmpge(other.bl).all() - } - - pub fn intersection(&self, other: &Self) -> Option { - let clipped = Self { - bl: self.bl.max(other.bl), - tr: self.tr.min(other.tr), - }; - - if clipped.is_valid() { - Some(clipped) - } else { - None - } - } - - pub fn contains_rect(&self, other: &Self) -> bool { - self.bl.x < other.bl.x - && self.bl.y < other.bl.y - && self.tr.x > other.tr.x - && self.tr.y > other.tr.y - } - - pub fn contains_point(&self, xy: Vec2) -> bool { - self.bl.x < xy.x && self.bl.y < xy.y && self.tr.x > xy.x && self.tr.y > xy.y - } - - pub fn size(&self) -> Vec2 { - self.tr - self.bl - } - - pub fn width(&self) -> f32 { - self.tr.x - self.bl.x - } - - pub fn height(&self) -> f32 { - self.tr.y - self.bl.y +impl Font { + pub fn new(family: &str) -> Self { + unsafe { Self(font_load(family.as_ptr() as u32, family.len() as u32)) } } } -impl From for Rect { - fn from(other: canary_types::Rect) -> Self { - Self { - bl: other.bl.into(), - tr: other.tr.into(), +#[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 { + 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 } } } @@ -415,3 +409,16 @@ impl DrawContext { } } } + +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, color: u32); + 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); +} diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index 78843e9..544790b 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -1,202 +1,227 @@ // Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: Apache-2.0 -pub use canary_types::*; +use bitflags::bitflags; +use bytemuck::{Pod, Zeroable}; +pub use glam::Vec2; +use num_derive::{FromPrimitive, ToPrimitive}; +use num_traits::FromPrimitive; -pub mod draw; +pub mod api; -#[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) - } +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)] +pub struct Rect { + pub bl: Vec2, + pub tr: Vec2, +} - #[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) - } +impl Rect { + pub const NEG_INFINITY: Self = Self { + bl: Vec2::splat(f32::INFINITY), + tr: Vec2::splat(f32::NEG_INFINITY), }; -} -pub mod abi { - use super::*; - use num_traits::FromPrimitive; - - static mut PANEL_IMPLS: Vec> = Vec::new(); - - pub fn bind_panel(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 from_xy_size(xy: Vec2, size: Vec2) -> Self { + Self { + bl: xy, + tr: xy + size, } } - pub fn update(panel_data: u32, dt: f32) { - let panel = unsafe { &mut PANEL_IMPLS[panel_data as usize] }; - panel.update(dt); + pub fn from_circle_bounds(center: Vec2, radius: f32) -> Self { + Self { + bl: center - radius, + tr: center + radius, + } } - pub fn draw(panel_data: u32) { - let panel = unsafe { &mut PANEL_IMPLS[panel_data as usize] }; - panel.draw(); + pub fn from_triangle_bounds(tri: &ColoredTriangle) -> Self { + Self { + bl: tri.v1.min(tri.v2).min(tri.v3), + tr: tri.v1.max(tri.v2).max(tri.v3), + } } - 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 inset(&self, d: f32) -> Self { + Self { + bl: self.bl + d, + tr: self.tr - d, + } } - 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 fn tl(&self) -> Vec2 { + Vec2::new(self.bl.x, self.tr.y) + } + + pub fn br(&self) -> Vec2 { + Vec2::new(self.tr.x, self.bl.y) + } + + pub fn offset(&self, offset: Vec2) -> Self { + Self { + bl: self.bl + offset, + tr: self.tr + offset, + } + } + + pub fn scale(&self, scale: f32) -> Self { + Self { + bl: self.bl * scale, + tr: self.tr * scale, + } + } + + pub fn is_valid(&self) -> bool { + self.bl.cmplt(self.tr).all() + } + + pub fn intersects_rect(&self, other: &Self) -> bool { + self.bl.cmple(other.tr).all() && self.tr.cmpge(other.bl).all() + } + + pub fn intersection(&self, other: &Self) -> Option { + let clipped = Self { + bl: self.bl.max(other.bl), + tr: self.tr.min(other.tr), + }; + + if clipped.is_valid() { + Some(clipped) + } else { + None + } + } + + pub fn contains_rect(&self, other: &Self) -> bool { + self.bl.x < other.bl.x + && self.bl.y < other.bl.y + && self.tr.x > other.tr.x + && self.tr.y > other.tr.y + } + + pub fn contains_point(&self, xy: Vec2) -> bool { + self.bl.x < xy.x && self.bl.y < xy.y && self.tr.x > xy.x && self.tr.y > xy.y + } + + pub fn size(&self) -> Vec2 { + self.tr - self.bl + } + + pub fn width(&self) -> f32 { + self.tr.x - self.bl.x + } + + pub fn height(&self) -> f32 { + self.tr.y - self.bl.y } } -pub trait BindPanel { - fn bind(panel: Panel, msg: Message) -> Box; +#[repr(C)] +#[derive(Copy, Clone, Debug, Pod, Zeroable)] +pub struct Color(pub u32); + +impl From for Color { + fn from(other: glam::Vec4) -> Self { + let map = |v: f32| (v * 255.0).floor() as u8; + Self::new(map(other.x), map(other.y), map(other.z), map(other.w)) + } } -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); +impl From for glam::Vec4 { + fn from(other: Color) -> Self { + let (r, g, b, a) = other.to_rgba_unmultiplied(); + let map = |v: u8| (v as f32) / 255.0; + Self::new(map(r), map(g), map(b), map(a)) + } +} + +impl Color { + pub const WHITE: Self = Self(0xffffffff); + pub const BLACK: Self = Self(0x000000ff); + pub const TRANSPARENT: Self = Self(0); + pub const RED: Self = Self(0xff0000ff); + pub const GREEN: Self = Self(0x00ff00ff); + pub const BLUE: Self = Self(0x0000ffff); + pub const YELLOW: Self = Self(0xffff00ff); + pub const MAGENTA: Self = Self(0xff00ffff); + pub const CYAN: Self = Self(0x00ffffff); + + pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self { + Color(((r as u32) << 24) | ((g as u32) << 16) | ((b as u32) << 8) | (a as u32)) + } + + pub fn to_rgba_unmultiplied(&self) -> (u8, u8, u8, u8) { + ( + (self.0 >> 24) as u8, + (self.0 >> 16) as u8, + (self.0 >> 8) as u8, + self.0 as u8, + ) + } + + pub fn alpha_multiply(&self, mul: u8) -> Self { + let a = self.0 as u8 as u16; + let multiplied = ((a * (mul as u16)) >> 8) as u8; + self.with_alpha(multiplied) + } + + pub fn with_alpha(&self, alpha: u8) -> Self { + Self(self.0 & 0xffffff00 | alpha as u32) + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Pod, Zeroable)] +pub struct MeshVertex { + pub position: Vec2, + pub color: Color, +} + +pub type MeshIndex = u32; + +#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)] +pub enum CursorEventKind { + Hover = 0, + Select = 1, + Drag = 2, + Deselect = 3, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)] +pub enum Corner { + TopRight = 0, + BottomRight = 1, + BottomLeft = 2, + TopLeft = 3, +} + +bitflags! { + pub struct CornerFlags: u8 { + const TOP_RIGHT = 0x01; + const BOTTOM_RIGHT = 0x02; + const BOTTOM_LEFT = 0x04; + const TOP_LEFT = 0x08; + const TOP = 0x09; + const RIGHT = 0x03; + const BOTTOM = 0x06; + const LEFT = 0x0C; + const ALL = 0x0F; + } +} + +#[derive(Copy, Clone, Debug)] +pub enum Side { + Top, + Right, + Bottom, + Left, } -#[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.0) } - } - - 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 { - 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, color: u32); - 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); +pub struct ColoredTriangle { + pub v1: Vec2, + pub v2: Vec2, + pub v3: Vec2, + pub color: Color, } diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml deleted file mode 100644 index 16b648a..0000000 --- a/crates/types/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "canary_types" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -bytemuck = { version = "1", features = ["derive"] } -glam = { version = "^0.21", optional = true } -num-derive = "0.3" -num-traits = "0.2" diff --git a/crates/types/LICENSE b/crates/types/LICENSE deleted file mode 100644 index d645695..0000000 --- a/crates/types/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs deleted file mode 100644 index c3e6b7c..0000000 --- a/crates/types/src/lib.rs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2022 Marceline Cramer -// SPDX-License-Identifier: Apache-2.0 - -#[macro_use] -extern crate num_derive; - -use bytemuck::{Pod, Zeroable}; -pub use num_traits; - -#[repr(C)] -#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)] -pub struct Vec2 { - pub x: f32, - pub y: f32, -} - -impl Vec2 { - pub const INFINITY: Self = Self { - x: f32::INFINITY, - y: f32::INFINITY, - }; - - pub const NEG_INFINITY: Self = Self { - x: f32::NEG_INFINITY, - y: f32::NEG_INFINITY, - }; -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, Pod, Zeroable)] -pub struct Color(pub u32); - -impl Color { - pub const WHITE: Self = Self(0xffffffff); - pub const BLACK: Self = Self(0x000000ff); - pub const TRANSPARENT: Self = Self(0); - pub const RED: Self = Self(0xff0000ff); - pub const GREEN: Self = Self(0x00ff00ff); - pub const BLUE: Self = Self(0x0000ffff); - pub const YELLOW: Self = Self(0xffff00ff); - pub const MAGENTA: Self = Self(0xff00ffff); - pub const CYAN: Self = Self(0x00ffffff); - - pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self { - Color(((r as u32) << 24) | ((g as u32) << 16) | ((b as u32) << 8) | (a as u32)) - } - - pub fn to_rgba_unmultiplied(&self) -> (u8, u8, u8, u8) { - ( - (self.0 >> 24) as u8, - (self.0 >> 16) as u8, - (self.0 >> 8) as u8, - self.0 as u8, - ) - } - - pub fn alpha_multiply(&self, mul: u8) -> Self { - let a = self.0 as u8 as u16; - let multiplied = ((a * (mul as u16)) >> 8) as u8; - self.with_alpha(multiplied) - } - - pub fn with_alpha(&self, alpha: u8) -> Self { - Self(self.0 & 0xffffff00 | alpha as u32) - } -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, Pod, Zeroable)] -pub struct MeshVertex { - pub position: Vec2, - pub color: Color, -} - -pub type MeshIndex = u32; - -#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)] -pub enum CursorEventKind { - Hover = 0, - Select = 1, - Drag = 2, - Deselect = 3, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)] -pub struct Rect { - pub bl: Vec2, - pub tr: Vec2, -} - -impl Rect { - pub const NEG_INFINITY: Self = Self { - bl: Vec2::INFINITY, - tr: Vec2::NEG_INFINITY, - }; -} - -#[cfg(feature = "glam")] -mod glam_interop { - use super::*; - - impl From for Vec2 { - fn from(other: glam::Vec2) -> Self { - Self { - x: other.x, - y: other.y, - } - } - } - - impl From for glam::Vec2 { - fn from(other: Vec2) -> Self { - Self::new(other.x, other.y) - } - } - - impl From for Color { - fn from(other: glam::Vec4) -> Self { - let map = |v: f32| (v * 255.0).floor() as u8; - Self::new(map(other.x), map(other.y), map(other.z), map(other.w)) - } - } - - impl From for glam::Vec4 { - fn from(other: Color) -> Self { - let (r, g, b, a) = other.to_rgba_unmultiplied(); - let map = |v: u8| (v as f32) / 255.0; - Self::new(map(r), map(g), map(b), map(a)) - } - } -} diff --git a/scripts/music-player/Cargo.toml b/scripts/music-player/Cargo.toml index 14105da..8a0e3b8 100644 --- a/scripts/music-player/Cargo.toml +++ b/scripts/music-player/Cargo.toml @@ -7,6 +7,6 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -canary_script = { path = "../../crates/script" } +canary-script = { path = "../../crates/script" } canary-music-player = { path = "../../apps/music-player" } wee_alloc = "^0.4" diff --git a/scripts/music-player/src/lib.rs b/scripts/music-player/src/lib.rs index e0b367f..998aaf1 100644 --- a/scripts/music-player/src/lib.rs +++ b/scripts/music-player/src/lib.rs @@ -1,10 +1,8 @@ #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; -use canary_script::{ - draw::DrawContext, BindPanel, Color, CursorEventKind, Font, Message, Panel, PanelImpl, - TextLayout, Vec2, -}; +use canary_script::*; +use api::*; canary_script::export_abi!(MusicPlayerPanel); diff --git a/scripts/sao-ui/Cargo.toml b/scripts/sao-ui/Cargo.toml index 947ba8b..6c6862e 100644 --- a/scripts/sao-ui/Cargo.toml +++ b/scripts/sao-ui/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] glam = "^0.21" keyframe = "1" -canary_script = { path = "../../crates/script" } +canary-script = { path = "../../crates/script" } serde = { version = "1", features = ["derive"] } serde_json = "1" wee_alloc = "^0.4" diff --git a/scripts/sao-ui/src/lib.rs b/scripts/sao-ui/src/lib.rs index 8b68cf7..15daa23 100644 --- a/scripts/sao-ui/src/lib.rs +++ b/scripts/sao-ui/src/lib.rs @@ -8,7 +8,7 @@ pub mod panel; pub mod widgets; use canary_script::*; -use glam::Vec2; +use api::*; use widgets::Widget; use main_menu::MainMenuPanel; @@ -41,7 +41,7 @@ impl PanelImpl for ConfirmationDialogPanel { } fn draw(&mut self) { - let ctx = canary_script::draw::DrawContext::new(self.panel); + let ctx = DrawContext::new(self.panel); self.dialog.draw(&ctx); } diff --git a/scripts/sao-ui/src/main_menu.rs b/scripts/sao-ui/src/main_menu.rs index 39abb27..1f6ce7c 100644 --- a/scripts/sao-ui/src/main_menu.rs +++ b/scripts/sao-ui/src/main_menu.rs @@ -1,9 +1,8 @@ -use crate::widgets::*; +use crate::widgets::prelude::*; +use crate::{DrawContext, Rect}; + use button::{RectButton, RoundButton, RoundButtonStyle}; -use canary_script::draw::{DrawContext, Rect}; -use canary_script::{BindPanel, Color, CursorEventKind, Font, Message, Panel, PanelImpl}; use dialog::{Dialog, DialogInfo, DialogResponse, DialogStyle}; -use glam::Vec2; use menu::{SlotMenu, SlotMenuEvent, TabMenu}; use shell::{Offset, OffsetAlignment, Popup, Reveal}; use text::LabelText; @@ -28,7 +27,7 @@ impl PanelImpl for MainMenuPanel { } fn draw(&mut self) { - let ctx = canary_script::draw::DrawContext::new(self.panel); + let ctx = DrawContext::new(self.panel); Widget::draw(&mut self.menu, &ctx); } diff --git a/scripts/sao-ui/src/widgets/mod.rs b/scripts/sao-ui/src/widgets/mod.rs index 6844fdd..a9968df 100644 --- a/scripts/sao-ui/src/widgets/mod.rs +++ b/scripts/sao-ui/src/widgets/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later use crate::{CursorEventKind, Vec2}; -use canary_script::draw::{DrawContext, Rect}; +use canary_script::{api::DrawContext, Rect}; pub mod button; pub mod dialog; @@ -74,8 +74,7 @@ impl Widget for T { pub mod prelude { pub use super::*; - pub use canary_script::{CursorEventKind, Color, Font, TextLayout}; - pub use canary_script::draw::{CornerFlags, Rect, DrawContext}; pub use crate::anim::Animation; + pub use canary_script::{*, api::*}; pub use keyframe::functions::*; } diff --git a/src/lib.rs b/src/lib.rs index fb9e465..6e89aa5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ // Copyright (c) 2022 Marceline Cramer // SDPX-License-Identifier: LGPL-3.0-or-later -pub use canary_types::*; +pub use canary_script::*; use parking_lot::{Mutex, RwLock}; use slab::Slab; use std::collections::HashMap; diff --git a/src/text/glyph.rs b/src/text/glyph.rs index b025c3d..cf862e8 100644 --- a/src/text/glyph.rs +++ b/src/text/glyph.rs @@ -1,7 +1,8 @@ // Copyright (c) 2022 Marceline Cramer // SDPX-License-Identifier: LGPL-3.0-or-later -use super::AllsortsFont; +use super::{AllsortsFont, Rect, Vec2}; + use allsorts::binary::read::ReadScope; use allsorts::cff::CFF; use allsorts::font::GlyphTableFlags; @@ -10,7 +11,6 @@ use allsorts::outline::OutlineBuilder; use allsorts::pathfinder_geometry::{line_segment::LineSegment2F, vector::Vector2F}; use allsorts::tables::{glyf::GlyfTable, loca::LocaTable, FontTableProvider, SfntVersion}; use allsorts::tag; -use canary_types::{Rect, Vec2}; use lyon::path::Path; use parking_lot::RwLock; @@ -93,10 +93,7 @@ impl CachedGlyph { &fill_options, &mut BuffersBuilder::new(&mut geometry, |vertex: FillVertex| { let position = vertex.position(); - Vec2 { - x: position.x, - y: position.y, - } + Vec2::new(position.x, position.y) }), ) .unwrap(); diff --git a/src/text/mod.rs b/src/text/mod.rs index bdc5816..1032742 100644 --- a/src/text/mod.rs +++ b/src/text/mod.rs @@ -1,14 +1,13 @@ // Copyright (c) 2022 Marceline Cramer // SDPX-License-Identifier: LGPL-3.0-or-later -use super::{DrawCommand, MeshIndex, MeshVertex}; +use super::{Color, DrawCommand, MeshIndex, MeshVertex, Rect, Vec2}; use allsorts::binary::read::ReadScope; use allsorts::font::MatchingPresentation; use allsorts::font_data::{DynamicFontTableProvider, FontData as AllsortsFontData}; use allsorts::glyph_position::{GlyphLayout, TextDirection}; use allsorts::{tag, Font as AllsortsFont}; -use canary_types::{Color, Rect, Vec2}; use ouroboros::self_referencing; use parking_lot::Mutex; use std::collections::HashMap; @@ -140,7 +139,7 @@ impl Font { let x = v.x * scale + xpos; let y = v.y * scale + ypos; vertices.push(MeshVertex { - position: canary_types::Vec2 { x, y }, + position: Vec2::new(x, y), color, }); }