Get some math types and some ecs stuff exposed to lua
This commit is contained in:
parent
acfd238274
commit
d14abcc3e5
|
@ -5,8 +5,8 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
lyra-resource = { path = "../lyra-resource" }
|
||||
lyra-ecs = { path = "../lyra-ecs" }
|
||||
lyra-reflect = { path = "../lyra-reflect" }
|
||||
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
|
||||
lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] }
|
||||
|
||||
winit = "0.28.1"
|
||||
tracing = "0.1.37"
|
||||
|
|
|
@ -342,7 +342,7 @@ impl Game {
|
|||
.with(fmt::layer().with_writer(stdout_layer))
|
||||
.with(filter::Targets::new()
|
||||
// done by prefix, so it includes all lyra subpackages
|
||||
.with_target("lyra", Level::TRACE)
|
||||
.with_target("lyra", Level::DEBUG)
|
||||
.with_target("wgpu", Level::WARN)
|
||||
.with_default(Level::INFO))
|
||||
.init();
|
||||
|
|
|
@ -89,8 +89,7 @@ impl Transform {
|
|||
/// Performs a linear interpolation between `self` and `rhs` based on the value `alpha`.
|
||||
///
|
||||
/// When `alpha` is `0.0`, the result will be equal to `self`. When `alpha` is `1.0`, the result
|
||||
/// will be equal to `rhs`. When `alpha` is outside of range `[0, 1]`, the result is linearly
|
||||
/// extrapolated.
|
||||
/// will be equal to `rhs`.
|
||||
pub fn lerp(&self, rhs: Transform, alpha: f32) -> Self {
|
||||
|
||||
if alpha.is_finite() {
|
||||
|
|
|
@ -10,8 +10,9 @@ default = ["lua"]
|
|||
lua = ["dep:mlua"]
|
||||
|
||||
[dependencies]
|
||||
lyra-ecs = { path = "../lyra-ecs" }
|
||||
lyra-reflect = { path = "../lyra-reflect" }
|
||||
lyra-scripting-derive = { path = "lyra-scripting-derive" }
|
||||
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
|
||||
lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] }
|
||||
lyra-resource = { path = "../lyra-resource" }
|
||||
lyra-game = { path = "../lyra-game" }
|
||||
thiserror = "1.0.50"
|
||||
|
@ -23,4 +24,4 @@ mlua = { version = "0.9.2", features = ["lua54"], optional = true } # luajit may
|
|||
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = { version = "0.3.16", features = [ "tracing-log" ] }
|
||||
tracing-subscriber = { version = "0.3.16", features = [ "tracing-log" ] }
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "lyra-scripting-derive"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.70"
|
||||
quote = "1.0.33"
|
||||
syn = "2.0.41"
|
|
@ -0,0 +1,606 @@
|
|||
use proc_macro2::{Ident, Span};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, Path, Token, token, parenthesized, punctuated::Punctuated, braced, bracketed};
|
||||
|
||||
mod mat_wrapper;
|
||||
use mat_wrapper::MatWrapper;
|
||||
|
||||
const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type";
|
||||
const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
|
||||
|
||||
pub(crate) struct MetaMethod {
|
||||
pub ident: Ident,
|
||||
pub mods: Vec<Ident>,
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for MetaMethod {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let ident: Ident = input.parse()?;
|
||||
|
||||
let mods = if input.peek(token::Paren) {
|
||||
let content;
|
||||
let _parens: token::Paren = parenthesized!(content in input);
|
||||
content.parse_terminated(Ident::parse, Token![,])?
|
||||
.into_iter().collect()
|
||||
} else { vec![] };
|
||||
|
||||
Ok(Self {
|
||||
ident,
|
||||
mods,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct VecWrapper {
|
||||
|
||||
}
|
||||
|
||||
impl VecWrapper {
|
||||
fn vec_size(&self, wrapper_ident: &Ident) -> usize {
|
||||
let name = wrapper_ident.to_string();
|
||||
name[name.len() - 1..].parse::<usize>()
|
||||
.or_else(|_| name[name.len() - 2.. name.len() - 1].parse::<usize>())
|
||||
.expect("Failure to grab Vec size from ident name")
|
||||
}
|
||||
|
||||
/// Returns the token stream of the type of the axis of the vec (Vec2 vs IVec2 vs I64Vec2, etc.)
|
||||
fn vec_axis_type(&self, wrapper_ident: &Ident) -> &'static str {
|
||||
let name = wrapper_ident.to_string();
|
||||
let start = name.find("Vec").unwrap();
|
||||
|
||||
let before = &name[start - 1.. start];
|
||||
match before {
|
||||
"D" => return "f64",
|
||||
"I" => return "i32",
|
||||
"U" => return "u32",
|
||||
"B" => return "bool",
|
||||
_ => {},
|
||||
}
|
||||
//println!("before is {before}");
|
||||
|
||||
let three_before = &name[start - 3.. start];
|
||||
match three_before {
|
||||
"I64" => return "i64",
|
||||
"U64" => return "u64",
|
||||
_ => {},
|
||||
}
|
||||
//println!("three before is {three_before}");
|
||||
|
||||
"f32"
|
||||
}
|
||||
|
||||
pub fn to_field_tokens(&self, wrapped_path: &Path, wrapper_ident: &Ident) -> proc_macro2::TokenStream {
|
||||
let mut consts = vec![quote!(ZERO), quote!(ONE), quote!(X),
|
||||
quote!(Y), ]; // , quote!(AXES)
|
||||
|
||||
let vec_size = self.vec_size(wrapper_ident);
|
||||
let axis_type_name = self.vec_axis_type(wrapper_ident);
|
||||
|
||||
if axis_type_name.contains("b") {
|
||||
return quote! {
|
||||
fields.add_field("FALSE", #wrapper_ident(#wrapped_path::FALSE));
|
||||
fields.add_field("TRUE", #wrapper_ident(#wrapped_path::TRUE));
|
||||
};
|
||||
}
|
||||
|
||||
if vec_size >= 3 {
|
||||
consts.push(quote!(Z));
|
||||
|
||||
// no negative numbers for unsigned vecs
|
||||
if !axis_type_name.contains("u") {
|
||||
consts.push(quote!(NEG_Z));
|
||||
}
|
||||
}
|
||||
|
||||
if vec_size == 4 {
|
||||
consts.push(quote!(W));
|
||||
|
||||
// no negative numbers for unsigned vecs
|
||||
if !axis_type_name.contains("u") {
|
||||
consts.push(quote!(NEG_W));
|
||||
}
|
||||
}
|
||||
|
||||
// no negative numbers for unsigned vecs
|
||||
if !axis_type_name.contains("u") {
|
||||
consts.push(quote!(NEG_X));
|
||||
consts.push(quote!(NEG_Y));
|
||||
consts.push(quote!(NEG_ONE));
|
||||
}
|
||||
|
||||
if axis_type_name.contains("f") {
|
||||
consts.push(quote!(NAN))
|
||||
}
|
||||
|
||||
let const_tokens = consts.iter().map(|cnst| {
|
||||
let const_name = cnst.to_string();
|
||||
|
||||
quote! {
|
||||
fields.add_field(#const_name, #wrapper_ident(#wrapped_path::#cnst));
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#const_tokens)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_method_tokens(&self, wrapped_path: &Path, wrapper_ident: &Ident) -> proc_macro2::TokenStream {
|
||||
let vec_size = self.vec_size(wrapper_ident);
|
||||
let axis_type_name = self.vec_axis_type(wrapper_ident);
|
||||
// methods that only some vecs have
|
||||
let mut optional_methods = vec![];
|
||||
|
||||
// boolean vectors dont have much :(
|
||||
if axis_type_name.contains("b") {
|
||||
return quote!(); // TODO: all, any, bitmask, splat
|
||||
}
|
||||
|
||||
if axis_type_name.contains("f") {
|
||||
let type_id = Ident::new(axis_type_name, Span::call_site());
|
||||
|
||||
optional_methods.push(
|
||||
quote! {
|
||||
methods.add_method("clamp_length",
|
||||
|_, this, (min, max): (#type_id, #type_id)| {
|
||||
Ok(#wrapper_ident(this.clamp_length(min, max)))
|
||||
});
|
||||
|
||||
methods.add_method("abs_diff_eq",
|
||||
|_, this, (rhs, max_abs_diff): (#wrapper_ident, #type_id)| {
|
||||
Ok(this.abs_diff_eq(rhs.0, max_abs_diff))
|
||||
});
|
||||
|
||||
methods.add_method("ceil",
|
||||
|_, this, (): ()| {
|
||||
Ok(#wrapper_ident(this.ceil()))
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
if vec_size != 4 {
|
||||
optional_methods.push(
|
||||
quote! {
|
||||
methods.add_method("angle_between",
|
||||
|_, this, (rhs,): (#wrapper_ident,)| {
|
||||
Ok(this.angle_between(rhs.0))
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if !axis_type_name.contains("u") {
|
||||
optional_methods.push(
|
||||
quote! {
|
||||
methods.add_method("abs",
|
||||
|_, this, (): ()| {
|
||||
Ok(#wrapper_ident(this.abs()))
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let optional_methods_iter = optional_methods.iter();
|
||||
quote! {
|
||||
|
||||
|
||||
methods.add_method("clamp",
|
||||
|_, this, (min, max): (#wrapper_ident, #wrapper_ident)| {
|
||||
Ok(#wrapper_ident(this.clamp(min.0, max.0)))
|
||||
});
|
||||
|
||||
// TODO: Not all Vecs have this
|
||||
/* methods.add_method("clamp_length",
|
||||
|_, this, (min, max): (f32, f32)| {
|
||||
Ok(#wrapper_ident(this.clamp_length(min, max)))
|
||||
}); */
|
||||
|
||||
|
||||
methods.add_method("to_array",
|
||||
|_, this, (): ()| {
|
||||
Ok(this.to_array())
|
||||
});
|
||||
|
||||
#(#optional_methods_iter)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WrapUsage {
|
||||
pub type_path: Path,
|
||||
/// The extra derives of the type.
|
||||
pub derive_idents: Punctuated<Ident, Token![,]>,
|
||||
/// The field idents of the type that will be exposed with gets and sets
|
||||
pub field_idents: Punctuated<Ident, Token![,]>,
|
||||
pub skip_new_fn: bool,
|
||||
/// The identifiers that are taken as parameters in the types 'new' function
|
||||
pub new_fn_idents: Punctuated<Ident, Token![,]>,
|
||||
pub meta_method_idents: Punctuated<MetaMethod, Token![,]>,
|
||||
|
||||
pub matrix: Option<MatWrapper>,
|
||||
pub vec: Option<VecWrapper>,
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for WrapUsage {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let type_path: Path = input.parse()?;
|
||||
let mut s = Self {
|
||||
type_path,
|
||||
derive_idents: Punctuated::default(),
|
||||
field_idents: Punctuated::default(),
|
||||
skip_new_fn: false,
|
||||
new_fn_idents: Punctuated::default(),
|
||||
meta_method_idents: Punctuated::default(),
|
||||
matrix: None,
|
||||
vec: None,
|
||||
};
|
||||
/* let mut derive_idents = None;
|
||||
let mut field_idents = None;
|
||||
let mut new_fn_idents = None; */
|
||||
|
||||
while input.peek(Token![,]) {
|
||||
let _: Token![,] = input.parse()?;
|
||||
//println!("Peeked a , ({:?})", input);
|
||||
|
||||
if input.peek(syn::Ident) {
|
||||
let ident: Ident = input.parse()?;
|
||||
let ident_str = ident.to_string();
|
||||
let ident_str = ident_str.as_str();
|
||||
|
||||
match ident_str {
|
||||
"derives" => {
|
||||
if input.peek(token::Paren) {
|
||||
let content;
|
||||
let _parens: token::Paren = parenthesized!(content in input);
|
||||
|
||||
let derives: Punctuated<Ident, Token![,]> = content.parse_terminated(Ident::parse, Token![,])?;
|
||||
s.derive_idents = derives;
|
||||
//println!("read derives: {:?}", s.derive_idents);
|
||||
}
|
||||
},
|
||||
"fields" => {
|
||||
if input.peek(token::Paren) {
|
||||
let content;
|
||||
let _parens: token::Paren = parenthesized!(content in input);
|
||||
|
||||
let fields: Punctuated<Ident, Token![,]> = content.parse_terminated(Ident::parse, Token![,])?;
|
||||
s.field_idents = fields;
|
||||
//println!("read fields: {:?}", s.field_idents);
|
||||
}
|
||||
},
|
||||
"new" => {
|
||||
if input.peek(token::Paren) {
|
||||
let content;
|
||||
let _parens: token::Paren = parenthesized!(content in input);
|
||||
|
||||
let fields: Punctuated<Ident, Token![,]> = content.parse_terminated(Ident::parse, Token![,])?;
|
||||
s.new_fn_idents = fields;
|
||||
//println!("read fields: {:?}", s.new_fn_idents);
|
||||
}
|
||||
},
|
||||
"no_new" => {
|
||||
s.skip_new_fn = true;
|
||||
},
|
||||
"matrix" => {
|
||||
if input.peek(token::Brace) {
|
||||
let content;
|
||||
let _braces = braced!(content in input);
|
||||
s.matrix = Some(content.parse()?);
|
||||
}
|
||||
},
|
||||
"metamethods" => {
|
||||
if input.peek(token::Paren) {
|
||||
let content;
|
||||
let _bracket: token::Paren = parenthesized!(content in input);
|
||||
|
||||
let meta_methods: Punctuated<MetaMethod, Token![,]> = content.parse_terminated(MetaMethod::parse, Token![,])?;
|
||||
s.meta_method_idents = meta_methods;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(syn::Error::new_spanned(ident, "unknown wrapper command"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a wrapper type for a VecN from the engine math library.
|
||||
#[proc_macro]
|
||||
pub fn wrap_math_vec_copy(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as WrapUsage);
|
||||
|
||||
let path: Path = input.type_path;
|
||||
let type_name = &path.segments.last()
|
||||
.expect("Failure to find typename in macro usage!")
|
||||
.ident;
|
||||
let wrapper_typename = Ident::new(&format!("Lua{}", type_name), Span::call_site());
|
||||
|
||||
let vec_wrapper = {
|
||||
let name_str = type_name.to_string();
|
||||
if name_str.contains("Vec") {
|
||||
Some(VecWrapper {})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
/* let vec_wrapper_fields = vec_wrapper.as_ref().map(|vec|
|
||||
vec.to_field_tokens(&path, &wrapper_typename)); */
|
||||
let vec_wrapper_fields: Option<proc_macro2::TokenStream> = None;
|
||||
let vec_wrapper_methods = vec_wrapper.as_ref().map(|vec|
|
||||
vec.to_method_tokens(&path, &wrapper_typename));
|
||||
|
||||
let derive_idents_iter = input.derive_idents.iter();
|
||||
|
||||
let field_get_set_pairs = input.field_idents.iter().map(|i| {
|
||||
let is = i.to_string();
|
||||
quote! {
|
||||
fields.add_field_method_get(#is, |_, this| {
|
||||
Ok(this.#i)
|
||||
});
|
||||
fields.add_field_method_set(#is, |_, this, #i| {
|
||||
this.#i = #i;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let new_fn_idents = {
|
||||
let idents = if input.new_fn_idents.is_empty() {
|
||||
input.field_idents.iter()
|
||||
} else {
|
||||
input.new_fn_idents.iter()
|
||||
};
|
||||
|
||||
let idents_c = idents.clone();
|
||||
|
||||
if !input.skip_new_fn {
|
||||
quote! {
|
||||
methods.add_function("new", |_, ( #(#idents_c),* )| {
|
||||
Ok(#wrapper_typename(#path::new( #(#idents),* )))
|
||||
});
|
||||
}
|
||||
} else { quote!() }
|
||||
};
|
||||
|
||||
let matrix_wrapper_methods = input.matrix.as_ref().map(|m|
|
||||
m.to_method_tokens(&path, &wrapper_typename));
|
||||
let matrix_wrapper_fields = input.matrix.as_ref().map(|m|
|
||||
m.to_field_tokens(&path, &wrapper_typename));
|
||||
|
||||
let meta_method_idents = {
|
||||
let idents = input.meta_method_idents.iter().map(|metamethod| {
|
||||
let metamethod_ident = &metamethod.ident;
|
||||
let mm_str = metamethod.ident.to_string();
|
||||
let mm_str = mm_str.as_str();
|
||||
match mm_str {
|
||||
"Add" | "Sub" | "Div" | "Mul" | "Mod" => {
|
||||
let symbol = match mm_str {
|
||||
"Add" => quote!(+),
|
||||
"Sub" => quote!(-),
|
||||
"Div" => quote!(/),
|
||||
"Mul" => quote!(*),
|
||||
"Mod" => quote!(%),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// create a temporary vec to chain with metamethod.mods. If no parameters
|
||||
// were provided, add the wrapper to the list of parameters.
|
||||
let t = if metamethod.mods.is_empty() {
|
||||
vec![wrapper_typename.clone()]
|
||||
} else { vec![] };
|
||||
|
||||
let mods = metamethod.mods.iter().chain(t.iter()).map(|param| {
|
||||
let other = if param.to_string().starts_with("Lua") {
|
||||
quote!(other.0)
|
||||
} else {
|
||||
quote!(other)
|
||||
};
|
||||
|
||||
quote! {
|
||||
methods.add_meta_method(mlua::MetaMethod::#metamethod_ident,
|
||||
|_, this, (other,): (#param,)| {
|
||||
Ok(#wrapper_typename(this.0 #symbol #other))
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#mods)*
|
||||
}
|
||||
},
|
||||
"Unm" => {
|
||||
quote! {
|
||||
methods.add_meta_method(mlua::MetaMethod::#metamethod_ident, |_, this, ()| {
|
||||
Ok(#wrapper_typename(-this.0))
|
||||
});
|
||||
}
|
||||
},
|
||||
// Eq meta method has a different implementation than the above methods.
|
||||
"Eq" => {
|
||||
quote! {
|
||||
methods.add_meta_method(mlua::MetaMethod::#metamethod_ident,
|
||||
|_, this, (other,): (#wrapper_typename,)| {
|
||||
Ok(this.0 == other.0)
|
||||
});
|
||||
}
|
||||
},
|
||||
"Shl" => {
|
||||
// create a temporary vec to chain with metamethod.mods. If no parameters
|
||||
// were provided, add the wrapper to the list of parameters.
|
||||
let t = if metamethod.mods.is_empty() {
|
||||
vec![wrapper_typename.clone()]
|
||||
} else { vec![] };
|
||||
|
||||
let mods = metamethod.mods.iter().chain(t.iter()).map(|param| {
|
||||
let other = if param.to_string().starts_with("Lua") {
|
||||
quote!(other.0)
|
||||
} else {
|
||||
quote!(other)
|
||||
};
|
||||
|
||||
quote! {
|
||||
methods.add_meta_method(mlua::MetaMethod::#metamethod_ident,
|
||||
|_, this, (other,): (#param,)| {
|
||||
Ok(#wrapper_typename(this.0 << #other))
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#mods)*
|
||||
}
|
||||
}
|
||||
"Shr" => {
|
||||
// create a temporary vec to chain with metamethod.mods. If no parameters
|
||||
// were provided, add the wrapper to the list of parameters.
|
||||
let t = if metamethod.mods.is_empty() {
|
||||
vec![wrapper_typename.clone()]
|
||||
} else { vec![] };
|
||||
|
||||
let mods = metamethod.mods.iter().chain(t.iter()).map(|param| {
|
||||
let other = if param.to_string().starts_with("Lua") {
|
||||
quote!(other.0)
|
||||
} else {
|
||||
quote!(other)
|
||||
};
|
||||
|
||||
quote! {
|
||||
methods.add_meta_method(mlua::MetaMethod::#metamethod_ident,
|
||||
|_, this, (other,): (#param,)| {
|
||||
Ok(#wrapper_typename(this.0 >> #other))
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#mods)*
|
||||
}
|
||||
},
|
||||
"BAnd" | "BOr" | "BXor" => {
|
||||
let symbol = match mm_str {
|
||||
"BAnd" => {
|
||||
quote!(&)
|
||||
},
|
||||
"BOr" => {
|
||||
quote!(|)
|
||||
},
|
||||
"BXor" => {
|
||||
quote!(^)
|
||||
},
|
||||
_ => unreachable!() // the string was just checked to be one of these
|
||||
};
|
||||
|
||||
// create a temporary vec to chain with metamethod.mods. If no parameters
|
||||
// were provided, add the wrapper to the list of parameters.
|
||||
let t = if metamethod.mods.is_empty() {
|
||||
vec![wrapper_typename.clone()]
|
||||
} else { vec![] };
|
||||
|
||||
let mods = metamethod.mods.iter().chain(t.iter()).map(|param| {
|
||||
let other = if param.to_string().starts_with("Lua") {
|
||||
quote!(other.0)
|
||||
} else {
|
||||
quote!(other)
|
||||
};
|
||||
|
||||
quote! {
|
||||
methods.add_meta_method(mlua::MetaMethod::#metamethod_ident,
|
||||
|_, this, (other,): (#param,)| {
|
||||
Ok(#wrapper_typename(this.0 #symbol #other))
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#mods)*
|
||||
}
|
||||
},
|
||||
"BNot" => {
|
||||
quote! {
|
||||
methods.add_meta_method(mlua::MetaMethod::#metamethod_ident, |_, this, ()| {
|
||||
Ok(#wrapper_typename(!this.0))
|
||||
});
|
||||
}
|
||||
},
|
||||
"ToString" => {
|
||||
quote! {
|
||||
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| {
|
||||
Ok(format!("{:?}", this.0))
|
||||
});
|
||||
}
|
||||
},
|
||||
_ => syn::Error::new_spanned(metamethod_ident,
|
||||
"unsupported auto implementation of metamethod").to_compile_error(),
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#idents)*
|
||||
}
|
||||
};
|
||||
|
||||
proc_macro::TokenStream::from(quote! {
|
||||
#[derive(Clone, Copy, lyra_reflect::Reflect, #(#derive_idents_iter),*)]
|
||||
pub struct #wrapper_typename(#[reflect(skip)] pub(crate) #path);
|
||||
|
||||
impl std::ops::Deref for #wrapper_typename {
|
||||
type Target = #path;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for #wrapper_typename {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> mlua::FromLua<'lua> for #wrapper_typename {
|
||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
mlua::Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl mlua::UserData for #wrapper_typename {
|
||||
fn add_fields<'lua, F: mlua::prelude::LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
#(#field_get_set_pairs)*
|
||||
|
||||
#matrix_wrapper_fields
|
||||
#vec_wrapper_fields
|
||||
}
|
||||
|
||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
#new_fn_idents
|
||||
|
||||
methods.add_method(#FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
||||
Ok(crate::ScriptBorrow::from_component::<#path>(Some(this.0.clone())))
|
||||
});
|
||||
|
||||
methods.add_function(#FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||
Ok(crate::ScriptBorrow::from_component::<#path>(None))
|
||||
});
|
||||
|
||||
#meta_method_idents
|
||||
|
||||
#matrix_wrapper_methods
|
||||
#vec_wrapper_methods
|
||||
}
|
||||
}
|
||||
|
||||
impl lyra_scripting::lua::LuaWrapper for #wrapper_typename {
|
||||
fn wrapped_type_id() -> std::any::TypeId {
|
||||
std::any::TypeId::of::<#path>()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
use proc_macro2::Ident;
|
||||
use quote::quote;
|
||||
use syn::{Path, Token};
|
||||
|
||||
pub(crate) struct MatWrapper {
|
||||
pub column_type: Ident,
|
||||
}
|
||||
|
||||
impl MatWrapper {
|
||||
pub fn to_field_tokens(&self, wrapped_path: &Path, wrapper_ident: &Ident) -> proc_macro2::TokenStream {
|
||||
quote! {
|
||||
fields.add_field("ZERO", #wrapper_ident(#wrapped_path::ZERO));
|
||||
fields.add_field("IDENTITY", #wrapper_ident(#wrapped_path::IDENTITY));
|
||||
fields.add_field("NAN", #wrapper_ident(#wrapped_path::NAN));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_method_tokens(&self, wrapped_path: &Path, wrapper_ident: &Ident) -> proc_macro2::TokenStream {
|
||||
let column_type = &self.column_type;
|
||||
|
||||
let column_size = {
|
||||
let ty_str = column_type.to_string();
|
||||
ty_str[ty_str.len() - 1..].parse::<usize>()
|
||||
.expect("Failure to parse number from token type")
|
||||
};
|
||||
let column_size_xtwo = column_size * 2;
|
||||
|
||||
let element_ty = quote!(f32);
|
||||
|
||||
quote! {
|
||||
methods.add_function("from_cols",
|
||||
|_, (x_axis, y_axis): (#column_type, #column_type)| {
|
||||
Ok(#wrapper_ident(#wrapped_path::from_cols(x_axis.0, y_axis.0)))
|
||||
});
|
||||
|
||||
methods.add_function("from_cols_array",
|
||||
|_, (arr,): ([#element_ty; #column_size_xtwo],)| {
|
||||
Ok(#wrapper_ident(#wrapped_path::from_cols_array(&arr)))
|
||||
});
|
||||
|
||||
methods.add_function("from_cols_array_2d",
|
||||
|_, (arr,): ([[#element_ty; #column_size]; #column_size],)| {
|
||||
Ok(#wrapper_ident(#wrapped_path::from_cols_array_2d(&arr)))
|
||||
});
|
||||
|
||||
methods.add_function("from_diagonal",
|
||||
|_, (diag,): (#column_type,)| {
|
||||
Ok(#wrapper_ident(#wrapped_path::from_diagonal(diag.0)))
|
||||
});
|
||||
|
||||
methods.add_method("col",
|
||||
|_, this, (idx,): (usize,)| {
|
||||
Ok(#column_type(this.col(idx)))
|
||||
});
|
||||
|
||||
methods.add_method("row",
|
||||
|_, this, (idx,): (usize,)| {
|
||||
Ok(#column_type(this.row(idx)))
|
||||
});
|
||||
|
||||
methods.add_method_mut("set_col",
|
||||
|_, this, (idx, newc): (usize, #column_type)| {
|
||||
let col = this.col_mut(idx);
|
||||
*col = newc.0;
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("is_finite",
|
||||
|_, this, (): ()| {
|
||||
Ok(this.is_finite())
|
||||
});
|
||||
|
||||
methods.add_method("is_nan",
|
||||
|_, this, (): ()| {
|
||||
Ok(this.is_nan())
|
||||
});
|
||||
|
||||
methods.add_method("transpose",
|
||||
|_, this, (): ()| {
|
||||
Ok(#wrapper_ident(this.0.transpose()))
|
||||
});
|
||||
|
||||
methods.add_method("determinant",
|
||||
|_, this, (): ()| {
|
||||
Ok(this.determinant())
|
||||
});
|
||||
|
||||
methods.add_method("inverse",
|
||||
|_, this, (): ()| {
|
||||
Ok(#wrapper_ident(this.inverse()))
|
||||
});
|
||||
|
||||
methods.add_method("abs_diff_eq",
|
||||
|_, this, (rhs, max_abs_diff): (#wrapper_ident, f32)| {
|
||||
Ok(this.abs_diff_eq(rhs.0, max_abs_diff))
|
||||
});
|
||||
|
||||
// TODO: After all DMat's are implemented
|
||||
/* methods.add_method("as_dmat",
|
||||
|_, this, (rhs, max_abs_diff): (#wrapper_ident, f32)| {
|
||||
Ok(D#wrapper_ident(this.as_dmat))
|
||||
}); */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for MatWrapper {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let mut column_type = None;
|
||||
|
||||
// cba to remove the use of this bool
|
||||
let mut first = true;
|
||||
|
||||
while input.peek(Token![,]) || first {
|
||||
if !first {
|
||||
let _: Token![,] = input.parse()?;
|
||||
}
|
||||
|
||||
if input.peek(syn::Ident) {
|
||||
let ident: Ident = input.parse()?;
|
||||
let ident_str = ident.to_string();
|
||||
let ident_str = ident_str.as_str();
|
||||
|
||||
match ident_str {
|
||||
"col_type" => {
|
||||
let _eq: Token![=] = input.parse()?;
|
||||
column_type = Some(input.parse()?);
|
||||
},
|
||||
_ => return Err(syn::Error::new_spanned(ident, "unknown matrix wrapper command")),
|
||||
}
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
column_type: column_type.ok_or_else(|| syn::Error::new(input.span(),
|
||||
"expected `col_type`"))?,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
Quat = { x = 0.0, y = 0.0, z = 0.0, w = 0.0 }
|
||||
Quat.__index = Quat
|
||||
Quat.__name = "Quat"
|
||||
|
||||
--- Constructs a new Quaternion from x, y, z, and w.
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param z number
|
||||
---@param w number
|
||||
---@return Quat
|
||||
function Quat:new(x, y, z, w)
|
||||
local q = {}
|
||||
setmetatable(q, Quat)
|
||||
|
||||
q.x = x
|
||||
q.y = y
|
||||
q.z = z
|
||||
q.w = w
|
||||
|
||||
return q
|
||||
end
|
||||
|
||||
Quat.IDENTITY = Quat:new(0, 0, 0, 1)
|
||||
|
||||
function Quat:copy()
|
||||
return Quat:new(self.x, self.y, self.z, self.w)
|
||||
end
|
||||
|
||||
--- Creates a quaternion from the angle, in radians, around the x axis.
|
||||
--- @param rad number
|
||||
--- @return Quat
|
||||
function Quat:from_rotation_x(rad)
|
||||
local sin = math.sin(rad * 0.5)
|
||||
local cos = math.cos(rad * 0.5)
|
||||
return Quat:new(sin, 0, 0, cos)
|
||||
end
|
||||
|
||||
--- Creates a quaternion from the angle, in radians, around the y axis.
|
||||
--- @param rad number
|
||||
--- @return Quat
|
||||
function Quat:from_rotation_y(rad)
|
||||
local sin = math.sin(rad * 0.5)
|
||||
local cos = math.cos(rad * 0.5)
|
||||
return Quat:new(0, sin, 0, cos)
|
||||
end
|
||||
|
||||
--- Creates a quaternion from the angle, in radians, around the z axis.
|
||||
--- @param rad number
|
||||
--- @return Quat
|
||||
function Quat:from_rotation_z(rad)
|
||||
local sin = math.sin(rad * 0.5)
|
||||
local cos = math.cos(rad * 0.5)
|
||||
return Quat:new(0, 0, sin, cos)
|
||||
end
|
||||
|
||||
--- Computes the dot product of `self`.
|
||||
---@param rhs Quat
|
||||
---@return number
|
||||
function Quat:dot(rhs)
|
||||
return (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + (self.w * rhs.w)
|
||||
end
|
||||
|
||||
--- Computes the length of `self`.
|
||||
---@return number
|
||||
function Quat:length()
|
||||
return math.sqrt(self:dot(self))
|
||||
end
|
||||
|
||||
--- Compute the length of `self` squared.
|
||||
---@return number
|
||||
function Quat:length_squared()
|
||||
return self:length() ^ 2
|
||||
end
|
||||
|
||||
--- Normalizes `self` and returns the new Quat
|
||||
---@return unknown
|
||||
function Quat:normalize()
|
||||
local length = self:length()
|
||||
return self / length
|
||||
end
|
||||
|
||||
--- Multiplies two Quaternions together. Keep in mind that Quaternion multiplication is NOT
|
||||
--- commutative so the order in which you multiply the quaternions matters.
|
||||
---@param rhs Quat
|
||||
---@return Quat
|
||||
function Quat:mult_quat(rhs)
|
||||
local x1, y1, z1, w1 = self.x, self.y, self.z, self.w
|
||||
local x2, y2, z2, w2 = rhs.x, rhs.y, rhs.z, rhs.w
|
||||
|
||||
local x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
|
||||
local y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2
|
||||
local z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2
|
||||
local w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * x2
|
||||
|
||||
return Quat:new(x, y, z, w)
|
||||
end
|
||||
|
||||
--- Multiplies `self` by a Vec3, returning the rotated Vec3
|
||||
---@param vec Vec3
|
||||
---@return Vec3
|
||||
function Quat:mult_vec3(vec)
|
||||
local vec_quat = Quat:new(vec.x, vec.y, vec.z, 0)
|
||||
local quat = self:mult_quat(vec_quat)
|
||||
return Vec3:new(quat.x, quat.y, quat.z)
|
||||
end
|
||||
|
||||
--- Calculates the linear iterpolation between `self` and `rhs` based on the `alpha`.
|
||||
--- When `alpha` is `0`, the result will be equal to `self`. When `s` is `1`, the result
|
||||
--- will be equal to `rhs`
|
||||
--- @param rhs Quat
|
||||
--- @param alpha number
|
||||
--- @return Quat
|
||||
function Quat:lerp(rhs, alpha)
|
||||
-- ensure alpha is [0, 1]
|
||||
local alpha = math.max(0, math.min(1, alpha))
|
||||
|
||||
local x1, y1, z1, w1 = self.x, self.y, self.z, self.w
|
||||
local x2, y2, z2, w2 = rhs.x, rhs.y, rhs.z, rhs.w
|
||||
|
||||
local x = (1 - alpha) * x1 + alpha * x2
|
||||
local y = (1 - alpha) * y1 + alpha * y2
|
||||
local z = (1 - alpha) * z1 + alpha * z2
|
||||
local w = (1 - alpha) * w1 + alpha * w2
|
||||
|
||||
return Quat:new(x, y, z, w):normalize()
|
||||
end
|
||||
|
||||
function Quat:__add(rhs)
|
||||
return Quat:new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z, self.w + rhs.w)
|
||||
end
|
||||
|
||||
function Quat:__sub(rhs)
|
||||
return Quat:new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z, self.w - rhs.w)
|
||||
end
|
||||
|
||||
function Quat:__mul(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Quat:new(self.x * rhs, self.y * rhs, self.z * rhs, self.w * rhs)
|
||||
elseif type(rhs) == "table" then
|
||||
local name = rhs.__name
|
||||
|
||||
if name == "Vec3" then
|
||||
return self:mult_vec3(rhs)
|
||||
elseif name == "Quat" then
|
||||
return self:mult_quat(rhs)
|
||||
else
|
||||
assert(false, "Unknown usertype of rhs" .. name)
|
||||
end
|
||||
else
|
||||
assert(false, "Unknown type of rhs" .. type(rhs))
|
||||
end
|
||||
end
|
||||
|
||||
function Quat:__div(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Quat:new(self.x / rhs, self.y / rhs, self.z / rhs, self.w / rhs)
|
||||
else
|
||||
assert(rhs.__name == "Quat", "Attempted to divide Quat by unknown type " .. rhs.__name)
|
||||
return Quat:new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z, self.w / rhs.w)
|
||||
end
|
||||
end
|
||||
|
||||
function Quat:__eq(rhs)
|
||||
return self.x == rhs.x and self.y == rhs.y and self.z == rhs.z and self.w == rhs.w
|
||||
end
|
||||
|
||||
function Quat:__lt(rhs)
|
||||
return self.x < rhs.x and self.y < rhs.y and self.z < rhs.z and self.w < rhs.w
|
||||
end
|
||||
|
||||
function Quat:__le(rhs)
|
||||
return self.x <= rhs.x and self.y <= rhs.y and self.z <= rhs.z and self.w <= rhs.w
|
||||
end
|
||||
|
||||
function Quat:__tostring()
|
||||
return "Quat(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ", " .. self.w .. ")"
|
||||
end
|
|
@ -0,0 +1,94 @@
|
|||
--require("math.quat")
|
||||
--require("math.vec3")
|
||||
|
||||
Transform = { translation = Vec3.ZERO, rotation = Quat.IDENTITY, scale = Vec3.ONE }
|
||||
Transform.__index = Transform
|
||||
Transform.__name = "Transform"
|
||||
|
||||
function Transform:new(translation, rotation, scale)
|
||||
local t = {}
|
||||
setmetatable(t, Transform)
|
||||
|
||||
t.translation = translation
|
||||
t.rotation = rotation
|
||||
t.scale = scale
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
function Transform:copy()
|
||||
return Transform:new(self.translation:copy(), self.rotation:copy(), self.scale:copy())
|
||||
end
|
||||
|
||||
--- Creates a new Transform with the translation at the vec3
|
||||
--- @param pos Vec3
|
||||
function Transform:from_vec3(pos)
|
||||
local t = Transform:copy() -- copy of default transform
|
||||
t.translation = pos
|
||||
return t
|
||||
end
|
||||
|
||||
function Transform:from_xyz(x, y, z)
|
||||
Transform:from_vec3(Vec3:new(x, y, z))
|
||||
end
|
||||
|
||||
--- Calculates the forward vector of the Transform.
|
||||
--- @return Vec3
|
||||
function Transform:forward()
|
||||
return (self.rotation * Vec3.NEG_Z):normalize()
|
||||
end
|
||||
|
||||
--- Calculates the left vector of the Transform.
|
||||
--- @return Vec3
|
||||
function Transform:left()
|
||||
return (self.rotation * Vec3.X):normalize()
|
||||
end
|
||||
|
||||
--- Calculates the up vector of the Transform.
|
||||
--- @return Vec3
|
||||
function Transform:up()
|
||||
return (self.rotation * Vec3.Y):normalize()
|
||||
end
|
||||
|
||||
--- Rotates `self` using a Quaternion
|
||||
--- @param quat Quat
|
||||
function Transform:rotate(quat)
|
||||
self.rotation = (quat * self.rotation):normalize()
|
||||
end
|
||||
|
||||
--- Rotates `self` around the x-axis
|
||||
--- @param rad number
|
||||
function Transform:rotate_x(rad)
|
||||
self:rotate(Quat:from_rotation_x(rad))
|
||||
end
|
||||
|
||||
--- Rotates `self` around the y-axis
|
||||
--- @param rad number
|
||||
function Transform:rotate_y(rad)
|
||||
self:rotate(Quat:from_rotation_y(rad))
|
||||
end
|
||||
|
||||
--- Rotates `self` around the z-axis
|
||||
--- @param rad number
|
||||
function Transform:rotate_z(rad)
|
||||
self:rotate(Quat:from_rotation_z(rad))
|
||||
end
|
||||
|
||||
--- Calculates the linear iterpolation between `self` and `rhs` based on the `alpha`.
|
||||
--- When `alpha` is `0`, the result will be equal to `self`. When `s` is `1`, the result
|
||||
--- will be equal to `rhs`
|
||||
--- @param rhs Transform
|
||||
--- @param alpha number
|
||||
--- @return Transform
|
||||
function Transform:lerp(rhs, alpha)
|
||||
local res = self:copy()
|
||||
res.translation = self.translation:lerp(rhs.translation, alpha)
|
||||
res.rotation = self.rotation:lerp(rhs.rotation, alpha)
|
||||
res.scale = self.scale:lerp(rhs.scale, alpha)
|
||||
return res
|
||||
end
|
||||
|
||||
function Transform:__tostring()
|
||||
return "Transform(pos=" .. tostring(self.translation) .. ", rot="
|
||||
.. tostring(self.rotation) .. ", scale=" .. tostring(self.scale) .. ")"
|
||||
end
|
|
@ -0,0 +1,161 @@
|
|||
Vec3 = { x = 0.0, y = 0.0, z = 0.0 }
|
||||
Vec3.__index = Vec3
|
||||
Vec3.__name = "Vec3"
|
||||
|
||||
--- Constructs a new vector
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param z number
|
||||
---@return Vec3
|
||||
function Vec3:new(x, y, z)
|
||||
local v = {}
|
||||
setmetatable(v, Vec3)
|
||||
|
||||
v.x = x
|
||||
v.y = y
|
||||
v.z = z
|
||||
|
||||
return v
|
||||
end
|
||||
|
||||
function Vec3:copy()
|
||||
return Vec3:new(self.x, self.y, self.z)
|
||||
end
|
||||
|
||||
--- Constructs a vector with all elements as parameter `x`.
|
||||
---@param x number
|
||||
---@return Vec3
|
||||
function Vec3:all(x)
|
||||
return Vec3:new(x, x, x)
|
||||
end
|
||||
|
||||
--- A unit-length vector pointing alongside the positive X axis.
|
||||
Vec3.X = Vec3:new(1, 0, 0)
|
||||
--- A unit-length vector pointing alongside the positive Y axis.
|
||||
Vec3.Y = Vec3:new(0, 1, 0)
|
||||
--- A unit-length vector pointing alongside the positive Z axis.
|
||||
Vec3.Z = Vec3:new(0, 0, 1)
|
||||
|
||||
--- A unit-length vector pointing alongside the negative X axis.
|
||||
Vec3.NEG_X = Vec3:new(-1, 0, 0)
|
||||
--- A unit-length vector pointing alongside the negative Y axis.
|
||||
Vec3.NEG_Y = Vec3:new(0, -1, 0)
|
||||
--- A unit-length vector pointing alongside the negative Z axis.
|
||||
Vec3.NEG_Z = Vec3:new(0, 0, -1)
|
||||
|
||||
--- A vector of all zeros
|
||||
Vec3.ZERO = Vec3:new(0, 0, 0)
|
||||
--- A vector of all ones
|
||||
Vec3.ONE = Vec3:new(1, 1, 1)
|
||||
|
||||
--- Computes the absolute value of `self`.
|
||||
---@return Vec3
|
||||
function Vec3:abs()
|
||||
return Vec3:new(math.abs(self.x), math.abs(self.y), math.abs(self.z))
|
||||
end
|
||||
|
||||
--- Computes the length of `self`.
|
||||
---@return number
|
||||
function Vec3:length()
|
||||
return math.sqrt(self:dot(self))
|
||||
end
|
||||
|
||||
--- Computes the dot product of `self` and `rhs`.
|
||||
---@param rhs Vec3
|
||||
---@return number
|
||||
function Vec3:dot(rhs)
|
||||
assert(rhs.__name == "Vec3")
|
||||
|
||||
return (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z)
|
||||
end
|
||||
|
||||
--- Returns a vector that has the minimum value of each element of `self` and `rhs`
|
||||
---@param rhs Vec3
|
||||
---@return Vec3
|
||||
function Vec3:min(rhs)
|
||||
local x = math.min(self.x, rhs.x)
|
||||
local y = math.min(self.y, rhs.y)
|
||||
local z = math.min(self.z, rhs.z)
|
||||
|
||||
return Vec3:new(x, y, z)
|
||||
end
|
||||
|
||||
--- Returns `self` normalized to a length 1.
|
||||
---@return unknown
|
||||
function Vec3:normalize()
|
||||
local len_recip = 1.0 / self:length()
|
||||
return self * len_recip
|
||||
end
|
||||
|
||||
--- Calculates the linear iterpolation between `self` and `rhs` based on the `alpha`.
|
||||
--- When `alpha` is `0`, the result will be equal to `self`. When `s` is `1`, the result
|
||||
--- will be equal to `rhs`
|
||||
--- @param rhs Vec3
|
||||
--- @param alpha number
|
||||
--- @return Vec3
|
||||
function Vec3:lerp(rhs, alpha)
|
||||
-- ensure alpha is [0, 1]
|
||||
local alpha = math.max(0, math.min(1, alpha))
|
||||
|
||||
local res = self:copy()
|
||||
res = res + ((rhs - res) * alpha)
|
||||
return res
|
||||
end
|
||||
|
||||
function Vec3:__add(rhs)
|
||||
return Vec3:new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
|
||||
end
|
||||
|
||||
function Vec3:__sub(rhs)
|
||||
return Vec3:new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
|
||||
end
|
||||
|
||||
function Vec3:__mul(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Vec3:new(self.x * rhs, self.y * rhs, self.z * rhs)
|
||||
else
|
||||
return Vec3:new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z)
|
||||
end
|
||||
end
|
||||
|
||||
function Vec3:__div(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Vec3:new(self.x / rhs, self.y / rhs, self.z / rhs)
|
||||
else
|
||||
return Vec3:new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z)
|
||||
end
|
||||
end
|
||||
|
||||
function Vec3:__idiv(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Vec3:new(self.x // rhs, self.y // rhs, self.z // rhs)
|
||||
else
|
||||
return Vec3:new(self.x // rhs.x, self.y // rhs.y, self.z // rhs.z)
|
||||
end
|
||||
end
|
||||
|
||||
function Vec3:__unm()
|
||||
return Vec3:new(-self.x, -self.y, -self.z)
|
||||
end
|
||||
|
||||
function Vec3:__pow(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Vec3:new(self.x ^ rhs, self.y ^ rhs, self.z ^ rhs)
|
||||
end
|
||||
end
|
||||
|
||||
function Vec3:__eq(rhs)
|
||||
return self.x == rhs.x and self.y == rhs.y and self.z == rhs.z
|
||||
end
|
||||
|
||||
function Vec3:__lt(rhs)
|
||||
return self.x < rhs.x and self.y < rhs.y and self.z < rhs.z
|
||||
end
|
||||
|
||||
function Vec3:__le(rhs)
|
||||
return self.x <= rhs.x and self.y <= rhs.y and self.z <= rhs.z
|
||||
end
|
||||
|
||||
function Vec3:__tostring()
|
||||
return "Vec3(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")"
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use lyra_ecs::{ResourceObject, Entity};
|
||||
use lyra_ecs::{ResourceObject, Entity, World};
|
||||
|
||||
use crate::ScriptWorldPtr;
|
||||
|
||||
|
@ -42,6 +42,9 @@ pub trait ScriptApiProvider {
|
|||
/// The type used as the script's context.
|
||||
type ScriptContext;
|
||||
|
||||
/// Prepare the ECS world for this api. Things like registering types with the type registry happen here.
|
||||
fn prepare_world(&mut self, world: &mut World) {}
|
||||
|
||||
/// Exposes an API in the provided script context.
|
||||
fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), ScriptError>;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
pub mod lua;
|
||||
|
||||
pub mod world;
|
||||
use lyra_ecs::Component;
|
||||
pub use world::*;
|
||||
|
||||
pub mod wrap;
|
||||
|
@ -18,9 +19,10 @@ use lyra_game::game::Game;
|
|||
#[allow(unused_imports)]
|
||||
pub(crate) mod lyra_engine {
|
||||
pub use lyra_ecs as ecs;
|
||||
pub use lyra_reflect as reflect;
|
||||
}
|
||||
|
||||
use lyra_reflect::{ReflectedComponent, Reflect};
|
||||
use lyra_reflect::{ReflectedComponent, Reflect, FromType};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ReflectBranch {
|
||||
|
@ -60,6 +62,20 @@ impl Clone for ScriptBorrow {
|
|||
}
|
||||
}
|
||||
|
||||
impl ScriptBorrow {
|
||||
pub fn from_component<T>(data: Option<T>) -> Self
|
||||
where
|
||||
T: Reflect + Component + Default + 'static
|
||||
{
|
||||
let data = data.map(|d| Box::new(d) as Box<(dyn Reflect + 'static)>);
|
||||
|
||||
Self {
|
||||
reflect_branch: ReflectBranch::Component(<ReflectedComponent as FromType<T>>::from_type()),
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An extension trait that adds some helpful methods that makes it easier to do scripting things
|
||||
pub trait GameScriptExt {
|
||||
fn add_script_api_provider<T, P>(&mut self, provider: P)
|
||||
|
@ -69,12 +85,13 @@ pub trait GameScriptExt {
|
|||
}
|
||||
|
||||
impl GameScriptExt for Game {
|
||||
fn add_script_api_provider<T, P>(&mut self, provider: P)
|
||||
fn add_script_api_provider<T, P>(&mut self, mut provider: P)
|
||||
where
|
||||
T: ScriptHost,
|
||||
P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static
|
||||
{
|
||||
let world = self.world();
|
||||
provider.prepare_world(world);
|
||||
let mut providers = world.get_resource_mut::<ScriptApiProviders<T>>();
|
||||
providers.add_provider(provider);
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ impl ReflectedIterator {
|
|||
unsafe { self.reflected_components.as_ref().unwrap().as_ref() };
|
||||
|
||||
let reg_type = reflected_components.get_type(id)
|
||||
.expect("Could not find type for dynamic view!");
|
||||
.expect("Requested type was not found in TypeRegistry");
|
||||
let proxy = reg_type.get_data::<ReflectLuaProxy>()
|
||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ pub use dynamic_iter::*;
|
|||
pub mod world;
|
||||
use lyra_game::{plugin::Plugin, game::GameStages};
|
||||
use lyra_resource::ResourceManager;
|
||||
use tracing::{debug, error};
|
||||
use tracing::{debug, error, trace};
|
||||
pub use world::*;
|
||||
|
||||
pub mod script;
|
||||
|
@ -13,16 +13,16 @@ pub use script::*;
|
|||
pub mod loader;
|
||||
pub use loader::*;
|
||||
|
||||
pub mod modules;
|
||||
pub use modules::*;
|
||||
pub mod providers;
|
||||
pub mod wrappers;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
use std::{ptr::NonNull, sync::Mutex};
|
||||
use std::{ptr::NonNull, sync::Mutex, any::TypeId};
|
||||
|
||||
use lyra_ecs::{DynamicBundle, World, query::{ResMut, View, Entities}};
|
||||
use lyra_reflect::{Reflect, FromType};
|
||||
use lyra_reflect::{Reflect, FromType, RegisteredType, TypeRegistry};
|
||||
|
||||
use mlua::{Lua, AnyUserDataExt};
|
||||
|
||||
|
@ -33,6 +33,35 @@ pub const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
|
|||
|
||||
use crate::{ScriptBorrow, ScriptDynamicBundle, ScriptApiProviders, ScriptContexts, ScriptWorldPtr, ScriptList, ScriptData, ScriptHost, ScriptError, GameScriptExt};
|
||||
|
||||
use self::providers::{UtilityApiProvider, LyraMathApiProvider, LyraEcsApiProvider};
|
||||
|
||||
pub trait RegisterLuaType {
|
||||
/// Register a lua type that **is not wrapped**.
|
||||
fn register_lua_type<'a, T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData>(&mut self);
|
||||
/// Registers a wrapped lua type.
|
||||
/// You provide the wrapper as `W`, and the type that the wrapper wraps, as `T`.
|
||||
fn register_lua_wrapper<'a, W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData>(&mut self);
|
||||
}
|
||||
|
||||
impl RegisterLuaType for World {
|
||||
fn register_lua_type<'a, T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData>(&mut self) {
|
||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
||||
|
||||
let type_id = TypeId::of::<T>();
|
||||
|
||||
let reg_type = registry.get_type_or_default(type_id);
|
||||
reg_type.add_data(<ReflectLuaProxy as FromType<T>>::from_type());
|
||||
//reg_type.add_data(<ReflectedComponent as FromType<T>>::from_type());
|
||||
}
|
||||
|
||||
fn register_lua_wrapper<'a, W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData>(&mut self) {
|
||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
||||
|
||||
let reg_type = registry.get_type_or_default(W::wrapped_type_id());
|
||||
reg_type.add_data(<ReflectLuaProxy as FromType<W>>::from_type());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> mlua::FromLua<'lua> for ScriptBorrow {
|
||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
|
@ -49,6 +78,11 @@ pub fn reflect_user_data(ud: &mlua::AnyUserData) -> ScriptBorrow {
|
|||
.expect("Type does not implement '__internal_reflect' properly")
|
||||
}
|
||||
|
||||
pub trait LuaWrapper {
|
||||
/// The type id of the wrapped type.
|
||||
fn wrapped_type_id() -> TypeId;
|
||||
}
|
||||
|
||||
pub trait LuaProxy {
|
||||
fn as_lua_value<'lua>(lua: &'lua mlua::Lua, this: &dyn Reflect) -> mlua::Result<mlua::AnyUserData<'lua>>;
|
||||
fn apply(lua: &mlua::Lua, this: &mut dyn Reflect, apply: &mlua::AnyUserData) -> mlua::Result<()>;
|
||||
|
@ -176,7 +210,7 @@ fn lua_call_script_function(world: &mut World, stage_name: &str) -> anyhow::Resu
|
|||
};
|
||||
|
||||
if let Some(ctx) = contexts.get_context_mut(script.id()) {
|
||||
debug!("Running '{}' function in script '{}'", stage_name, script.name());
|
||||
trace!("Running '{}' function in script '{}'", stage_name, script.name());
|
||||
match host.call_script(world_ptr.clone(), &script_data, ctx, &mut providers, stage_name) {
|
||||
Ok(()) => {},
|
||||
Err(e) => match e {
|
||||
|
@ -230,6 +264,8 @@ impl Plugin for LuaScriptingPlugin {
|
|||
fn setup(&self, game: &mut lyra_game::game::Game) {
|
||||
let world = game.world();
|
||||
|
||||
world.add_resource_default::<TypeRegistry>();
|
||||
|
||||
world.add_resource_default::<LuaHost>();
|
||||
world.add_resource_default::<ScriptApiProviders<LuaHost>>();
|
||||
world.add_resource_default::<ScriptContexts<LuaContext>>();
|
||||
|
@ -240,6 +276,8 @@ impl Plugin for LuaScriptingPlugin {
|
|||
drop(loader);
|
||||
|
||||
game.add_script_api_provider::<LuaHost, _>(UtilityApiProvider);
|
||||
game.add_script_api_provider::<LuaHost, _>(LyraEcsApiProvider);
|
||||
game.add_script_api_provider::<LuaHost, _>(LyraMathApiProvider);
|
||||
|
||||
game
|
||||
.add_system_to_stage(GameStages::First, "lua_create_contexts", lua_scripts_create_contexts, &[])
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
use crate::{lua::LuaContext, ScriptApiProvider, ScriptWorldPtr, ScriptDynamicBundle};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LyraEcsApiProvider;
|
||||
|
||||
impl ScriptApiProvider for LyraEcsApiProvider {
|
||||
type ScriptContext = LuaContext;
|
||||
|
||||
fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
let ctx = ctx.lock().unwrap();
|
||||
|
||||
let globals = ctx.globals();
|
||||
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
|
||||
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_script(&mut self, data: &crate::ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_script_environment(&mut self, world: crate::ScriptWorldPtr, data: &crate::ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
use lyra_ecs::World;
|
||||
use lyra_game::math;
|
||||
use crate::lua::RegisterLuaType;
|
||||
use crate::lua::wrappers::LuaVec3;
|
||||
|
||||
use crate::{ScriptApiProvider, lua::LuaContext};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LyraMathApiProvider;
|
||||
|
||||
impl ScriptApiProvider for LyraMathApiProvider {
|
||||
type ScriptContext = LuaContext;
|
||||
|
||||
fn prepare_world(&mut self, world: &mut World) {
|
||||
world.register_lua_wrapper::<LuaVec3>();
|
||||
}
|
||||
|
||||
fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
let ctx = ctx.lock().unwrap();
|
||||
|
||||
/* let bytes = include_bytes!("../../../scripts/lua/math/vec3.lua");
|
||||
ctx.load(bytes.to_vec()).exec()?;
|
||||
|
||||
let bytes = include_bytes!("../../../scripts/lua/math/quat.lua");
|
||||
ctx.load(bytes.to_vec()).exec()?;
|
||||
|
||||
let bytes = include_bytes!("../../../scripts/lua/math/transform.lua");
|
||||
ctx.load(bytes.to_vec()).exec()?; */
|
||||
|
||||
let globals = ctx.globals();
|
||||
globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?;
|
||||
//globals.set("Vec3", LuaVec3(math::Vec3::ZERO).into_lua(&ctx)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_script(&mut self, data: &crate::ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_script_environment(&mut self, world: crate::ScriptWorldPtr, data: &crate::ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/* #[derive(Clone, Copy, PartialEq, Debug, lyra_reflect::Reflect)]
|
||||
pub struct LuaVec3(#[reflect(skip)] math::Vec3);
|
||||
|
||||
impl From<math::Vec3> for LuaVec3 {
|
||||
fn from(value: math::Vec3) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> mlua::IntoLua<'lua> for LuaVec3 {
|
||||
fn into_lua(self, lua: &'lua mlua::prelude::Lua) -> mlua::prelude::LuaResult<mlua::prelude::LuaValue<'lua>> {
|
||||
let globals = lua.globals();
|
||||
|
||||
let v3 = globals.get::<_, mlua::Table>("Vec3")?;
|
||||
let v3_new = v3.get::<_, mlua::Function>("new")?;
|
||||
v3_new.call::<_, mlua::Table>((v3, self.0.x, self.0.y, self.0.z))
|
||||
.and_then(|t| t.into_lua(lua))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug, lyra_reflect::Reflect)]
|
||||
pub struct LuaQuat(#[reflect(skip)] math::Quat);
|
||||
|
||||
impl From<math::Quat> for LuaQuat {
|
||||
fn from(value: math::Quat) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> mlua::IntoLua<'lua> for LuaQuat {
|
||||
fn into_lua(self, lua: &'lua mlua::prelude::Lua) -> mlua::prelude::LuaResult<mlua::prelude::LuaValue<'lua>> {
|
||||
let globals = lua.globals();
|
||||
|
||||
let q = globals.get::<_, mlua::Table>("Quat")?;
|
||||
let q_new = q.get::<_, mlua::Function>("new")?;
|
||||
q_new.call::<_, mlua::Table>((q, self.0.x, self.0.y, self.0.z, self.0.w))
|
||||
.and_then(|t| t.into_lua(lua))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, lyra_reflect::Reflect)]
|
||||
pub struct LuaTransform(#[reflect(skip)] math::Transform);
|
||||
|
||||
impl From<math::Transform> for LuaTransform {
|
||||
fn from(value: math::Transform) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> mlua::IntoLua<'lua> for LuaTransform {
|
||||
fn into_lua(self, lua: &'lua mlua::prelude::Lua) -> mlua::prelude::LuaResult<mlua::prelude::LuaValue<'lua>> {
|
||||
let globals = lua.globals();
|
||||
|
||||
let translation = LuaVec3(self.0.translation).into_lua(lua)?;
|
||||
let rot = LuaQuat(self.0.rotation).into_lua(lua)?;
|
||||
let scale = LuaVec3(self.0.scale).into_lua(lua)?;
|
||||
|
||||
let transf = globals.get::<_, mlua::Table>("Transform")?;
|
||||
let transf_new = transf.get::<_, mlua::Function>("new")?;
|
||||
transf_new.call::<_, mlua::Table>((transf, translation, rot, scale))
|
||||
.and_then(|t| t.into_lua(lua))
|
||||
}
|
||||
} */
|
|
@ -0,0 +1,8 @@
|
|||
pub mod util;
|
||||
pub use util::*;
|
||||
|
||||
pub mod math;
|
||||
pub use math::*;
|
||||
|
||||
pub mod ecs;
|
||||
pub use ecs::*;
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::Mutex;
|
||||
|
||||
use mlua::IntoLua;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
|
||||
|
||||
|
@ -17,7 +17,7 @@ fn try_call_lua_function(lua: &mlua::Lua, fn_name: &str) -> Result<(), ScriptErr
|
|||
.map_err(ScriptError::MluaError)?;
|
||||
},
|
||||
Err(mlua::Error::FromLuaConversionError { from: "nil", to: "function", message: None }) => {
|
||||
debug!("Function '{}' was not found, ignoring...", fn_name)
|
||||
trace!("Function '{}' was not found, ignoring...", fn_name)
|
||||
// ignore
|
||||
},
|
||||
Err(e) => {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use lyra_ecs::query::dynamic::QueryDynamicType;
|
||||
use lyra_reflect::TypeRegistry;
|
||||
use mlua::{AnyUserDataExt, IntoLua, IntoLuaMulti};
|
||||
|
@ -73,7 +75,9 @@ impl mlua::UserData for ScriptWorldPtr {
|
|||
|
||||
methods.add_method("view", |lua, this, (system, queries): (mlua::Function, mlua::Variadic<mlua::AnyUserData>)| {
|
||||
if queries.is_empty() {
|
||||
panic!("No components were provided!");
|
||||
return Err(mlua::Error::BadArgument { to: Some("world:view".to_string()), pos: 2, name: Some("...".to_string()), cause:
|
||||
Arc::new(mlua::Error::external(WorldError::LuaInvalidUsage("no component types provided".to_string())))
|
||||
});
|
||||
}
|
||||
|
||||
let world = unsafe { this.inner.as_ref() };
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
use lyra_game::math;
|
||||
use lyra_scripting_derive::wrap_math_vec_copy;
|
||||
use crate::lyra_engine;
|
||||
|
||||
use crate as lyra_scripting;
|
||||
|
||||
// f32 types
|
||||
/* wrap_math_vec_copy!(
|
||||
math::Vec2,
|
||||
derives(PartialEq),
|
||||
fields(x, y),
|
||||
metamethods(
|
||||
Add(LuaVec2, f32),
|
||||
Sub(LuaVec2, f32),
|
||||
Div(LuaVec2, f32),
|
||||
Mul(LuaVec2, f32),
|
||||
Mod(LuaVec2, f32),
|
||||
Eq, Unm
|
||||
)
|
||||
); */
|
||||
wrap_math_vec_copy!(
|
||||
math::Vec3,
|
||||
derives(PartialEq),
|
||||
fields(x, y, z),
|
||||
metamethods(
|
||||
ToString,
|
||||
Eq, Unm
|
||||
)
|
||||
/* metamethods(
|
||||
Add(LuaVec3, f32),
|
||||
Sub(LuaVec3, f32),
|
||||
Div(LuaVec3, f32),
|
||||
Mul(LuaVec3, f32),
|
||||
Mod(LuaVec3, f32),
|
||||
Eq, Unm
|
||||
) */
|
||||
);
|
||||
/* wrap_math_vec_copy!(
|
||||
math::Vec3A,
|
||||
derives(PartialEq),
|
||||
fields(x, y, z),
|
||||
metamethods(
|
||||
Add(LuaVec3A, f32),
|
||||
Sub(LuaVec3A, f32),
|
||||
Div(LuaVec3A, f32),
|
||||
Mul(LuaVec3A, f32),
|
||||
Mod(LuaVec3A, f32),
|
||||
Eq, Unm
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::Vec4,
|
||||
derives(PartialEq),
|
||||
fields(w, x, y, z),
|
||||
metamethods(
|
||||
Add(LuaVec4, f32),
|
||||
Sub(LuaVec4, f32),
|
||||
Div(LuaVec4, f32),
|
||||
Mul(LuaVec4, f32),
|
||||
Mod(LuaVec4, f32),
|
||||
Eq, Unm
|
||||
)
|
||||
);
|
||||
|
||||
// f64 types
|
||||
wrap_math_vec_copy!(
|
||||
math::DVec2,
|
||||
derives(PartialEq),
|
||||
fields(x, y),
|
||||
metamethods(
|
||||
Add(LuaDVec2, f64),
|
||||
Sub(LuaDVec2, f64),
|
||||
Div(LuaDVec2, f64),
|
||||
Mul(LuaDVec2, f64),
|
||||
Mod(LuaDVec2, f64),
|
||||
Eq, Unm
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::DVec3,
|
||||
derives(PartialEq),
|
||||
fields(x, y, z),
|
||||
metamethods(
|
||||
Add(LuaDVec3, f64),
|
||||
Sub(LuaDVec3, f64),
|
||||
Div(LuaDVec3, f64),
|
||||
Mul(LuaDVec3, f64),
|
||||
Mod(LuaDVec3, f64),
|
||||
Eq, Unm
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::DVec4,
|
||||
derives(PartialEq),
|
||||
fields(w, x, y, z),
|
||||
metamethods(
|
||||
Add(LuaDVec4, f64),
|
||||
Sub(LuaDVec4, f64),
|
||||
Div(LuaDVec4, f64),
|
||||
Mul(LuaDVec4, f64),
|
||||
Mod(LuaDVec4, f64),
|
||||
Eq, Unm
|
||||
)
|
||||
);
|
||||
|
||||
// i32 types
|
||||
wrap_math_vec_copy!(
|
||||
math::IVec2,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y),
|
||||
metamethods(
|
||||
Add(LuaIVec2, i32),
|
||||
Sub(LuaIVec2, i32),
|
||||
Div(LuaIVec2, i32),
|
||||
Mul(LuaIVec2, i32),
|
||||
Mod(LuaIVec2, i32),
|
||||
Shl(LuaIVec2, LuaUVec2, i32),
|
||||
Shr(LuaIVec2, LuaUVec2, i32),
|
||||
BAnd(LuaIVec2, i32),
|
||||
BOr(LuaIVec2, i32),
|
||||
BXor(LuaIVec2, i32),
|
||||
Eq, Unm, BNot
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::IVec3,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y, z),
|
||||
metamethods(
|
||||
Add(LuaIVec3, i32),
|
||||
Sub(LuaIVec3, i32),
|
||||
Div(LuaIVec3, i32),
|
||||
Mul(LuaIVec3, i32),
|
||||
Mod(LuaIVec3, i32),
|
||||
Shl(LuaIVec3, LuaUVec3, i32),
|
||||
Shr(LuaIVec3, LuaUVec3, i32),
|
||||
BAnd(LuaIVec3, i32),
|
||||
BOr(LuaIVec3, i32),
|
||||
BXor(LuaIVec3, i32),
|
||||
Eq, Unm, BNot
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::IVec4,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(w, x, y, z),
|
||||
metamethods(
|
||||
Add(LuaIVec4, i32),
|
||||
Sub(LuaIVec4, i32),
|
||||
Div(LuaIVec4, i32),
|
||||
Mul(LuaIVec4, i32),
|
||||
Mod(LuaIVec4, i32),
|
||||
Shl(LuaIVec4, LuaUVec4, i32),
|
||||
Shr(LuaIVec4, LuaUVec4, i32),
|
||||
BAnd(LuaIVec4, i32),
|
||||
BOr(LuaIVec4, i32),
|
||||
BXor(LuaIVec4, i32),
|
||||
Eq, Unm, BNot
|
||||
)
|
||||
);
|
||||
|
||||
// u32 types
|
||||
wrap_math_vec_copy!(
|
||||
math::UVec2,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y),
|
||||
metamethods(
|
||||
Add(LuaUVec2, u32),
|
||||
Sub(LuaUVec2, u32),
|
||||
Div(LuaUVec2, u32),
|
||||
Mul(LuaUVec2, u32),
|
||||
Mod(LuaUVec2, u32),
|
||||
Shl(LuaUVec2, LuaIVec2, i32),
|
||||
Shr(LuaUVec2, LuaIVec2, i32),
|
||||
BAnd(LuaUVec2, u32),
|
||||
BOr(LuaUVec2, u32),
|
||||
BXor(LuaUVec2, u32),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::UVec3,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y, z),
|
||||
metamethods(
|
||||
Add(LuaUVec3, u32),
|
||||
Sub(LuaUVec3, u32),
|
||||
Div(LuaUVec3, u32),
|
||||
Mul(LuaUVec3, u32),
|
||||
Mod(LuaUVec3, u32),
|
||||
Shl(LuaUVec3, LuaIVec3, i32),
|
||||
Shr(LuaUVec3, LuaIVec3, i32),
|
||||
BAnd(LuaUVec3, u32),
|
||||
BOr(LuaUVec3, u32),
|
||||
BXor(LuaUVec3, u32),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::UVec4,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(w, x, y, z),
|
||||
metamethods(
|
||||
Add(LuaUVec4, u32),
|
||||
Sub(LuaUVec4, u32),
|
||||
Div(LuaUVec4, u32),
|
||||
Mul(LuaUVec4, u32),
|
||||
Mod(LuaUVec4, u32),
|
||||
Shl(LuaUVec4, LuaIVec4, i32),
|
||||
Shr(LuaUVec4, LuaIVec4, i32),
|
||||
BAnd(LuaUVec4, u32),
|
||||
BOr(LuaUVec4, u32),
|
||||
BXor(LuaUVec4, u32),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
|
||||
// i64 types
|
||||
wrap_math_vec_copy!(
|
||||
math::I64Vec2,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y),
|
||||
metamethods(
|
||||
Add(LuaI64Vec2, i64),
|
||||
Sub(LuaI64Vec2, i64),
|
||||
Div(LuaI64Vec2, i64),
|
||||
Mul(LuaI64Vec2, i64),
|
||||
Mod(LuaI64Vec2, i64),
|
||||
Shl(i64),
|
||||
Shr(i64),
|
||||
BAnd(LuaI64Vec2, i64),
|
||||
BOr(LuaI64Vec2, i64),
|
||||
BXor(LuaI64Vec2, i64),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::I64Vec3,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y, z),
|
||||
metamethods(
|
||||
Add(LuaI64Vec3, i64),
|
||||
Sub(LuaI64Vec3, i64),
|
||||
Div(LuaI64Vec3, i64),
|
||||
Mul(LuaI64Vec3, i64),
|
||||
Mod(LuaI64Vec3, i64),
|
||||
Shl(i64),
|
||||
Shr(i64),
|
||||
BAnd(LuaI64Vec3, i64),
|
||||
BOr(LuaI64Vec3, i64),
|
||||
BXor(LuaI64Vec3, i64),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::I64Vec4,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(w, x, y, z),
|
||||
metamethods(
|
||||
Add(LuaI64Vec4, i64),
|
||||
Sub(LuaI64Vec4, i64),
|
||||
Div(LuaI64Vec4, i64),
|
||||
Mul(LuaI64Vec4, i64),
|
||||
Mod(LuaI64Vec4, i64),
|
||||
Shl(i64),
|
||||
Shr(i64),
|
||||
BAnd(LuaI64Vec4, i64),
|
||||
BOr(LuaI64Vec4, i64),
|
||||
BXor(LuaI64Vec4, i64),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
|
||||
// u64 types
|
||||
wrap_math_vec_copy!(
|
||||
math::U64Vec2,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y),
|
||||
metamethods(
|
||||
Add(LuaU64Vec2, u64),
|
||||
Sub(LuaU64Vec2, u64),
|
||||
Div(LuaU64Vec2, u64),
|
||||
Mul(LuaU64Vec2, u64),
|
||||
Mod(LuaU64Vec2, u64),
|
||||
Shl(i64),
|
||||
Shr(i64),
|
||||
BAnd(LuaU64Vec2, u64),
|
||||
BOr(LuaU64Vec2, u64),
|
||||
BXor(LuaU64Vec2, u64),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::U64Vec3,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y, z),
|
||||
metamethods(
|
||||
Add(LuaU64Vec3, u64),
|
||||
Sub(LuaU64Vec3, u64),
|
||||
Div(LuaU64Vec3, u64),
|
||||
Mul(LuaU64Vec3, u64),
|
||||
Mod(LuaU64Vec3, u64),
|
||||
Shl(i64),
|
||||
Shr(i64),
|
||||
BAnd(LuaU64Vec3, u64),
|
||||
BOr(LuaU64Vec3, u64),
|
||||
BXor(LuaU64Vec3, u64),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::U64Vec4,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(w, x, y, z),
|
||||
metamethods(
|
||||
Add(LuaU64Vec4, u64),
|
||||
Sub(LuaU64Vec4, u64),
|
||||
Div(LuaU64Vec4, u64),
|
||||
Mul(LuaU64Vec4, u64),
|
||||
Mod(LuaU64Vec4, u64),
|
||||
Shl(i64),
|
||||
Shr(i64),
|
||||
BAnd(LuaU64Vec4, u64),
|
||||
BOr(LuaU64Vec4, u64),
|
||||
BXor(LuaU64Vec4, u64),
|
||||
Eq, BNot
|
||||
)
|
||||
);
|
||||
|
||||
// bool types
|
||||
wrap_math_vec_copy!(
|
||||
math::BVec2,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y),
|
||||
metamethods(Eq, BAnd, BOr, BXor, BNot)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::BVec3,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(x, y, z),
|
||||
metamethods(Eq, BAnd, BOr, BXor, BNot)
|
||||
);
|
||||
wrap_math_vec_copy!(
|
||||
math::BVec4,
|
||||
derives(PartialEq, Eq, Hash),
|
||||
fields(w, x, y, z),
|
||||
metamethods(Eq, BAnd, BOr, BXor, BNot)
|
||||
);
|
||||
|
||||
// mat2
|
||||
wrap_math_vec_copy!(
|
||||
math::Mat2,
|
||||
derives(PartialEq),
|
||||
no_new,
|
||||
matrix {
|
||||
col_type = LuaVec2
|
||||
},
|
||||
metamethods(
|
||||
Eq,
|
||||
Add,
|
||||
Sub,
|
||||
Mul(LuaMat2, f32),
|
||||
Unm
|
||||
)
|
||||
); */
|
Loading…
Reference in New Issue