Compare commits

..

No commits in common. "d14abcc3e592cff1b7d3f6f046a57ab4c8f615c2" and "e49d69dbc1d73c4331529f22e6a2abd9efb798fc" have entirely different histories.

37 changed files with 155 additions and 2393 deletions

View File

@ -5,14 +5,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
math = ["dep:glam"]
[dependencies] [dependencies]
lyra-ecs-derive = { path = "./lyra-ecs-derive" } lyra-ecs-derive = { path = "./lyra-ecs-derive" }
anyhow = "1.0.75" anyhow = "1.0.75"
thiserror = "1.0.50" thiserror = "1.0.50"
glam = { version = "0.24.0", optional = true }
[dev-dependencies] [dev-dependencies]
rand = "0.8.5" # used for tests rand = "0.8.5" # used for tests

View File

@ -34,10 +34,6 @@ pub mod system;
pub mod tick; pub mod tick;
pub use tick::*; pub use tick::*;
/// Implements Component for glam math types
#[cfg(feature = "math")]
pub mod math;
pub use lyra_ecs_derive::*; pub use lyra_ecs_derive::*;
#[cfg(test)] #[cfg(test)]

View File

@ -1,19 +0,0 @@
use crate::Component;
use glam::{Vec3, Quat, Vec2, Vec4, Mat4};
macro_rules! impl_component_math {
($type: ident) => {
impl Component for $type {
fn name() -> &'static str {
stringify!($type)
}
}
};
}
impl_component_math!(Vec2);
impl_component_math!(Vec3);
impl_component_math!(Vec4);
impl_component_math!(Mat4);
impl_component_math!(Quat);

View File

@ -5,8 +5,8 @@ edition = "2021"
[dependencies] [dependencies]
lyra-resource = { path = "../lyra-resource" } lyra-resource = { path = "../lyra-resource" }
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] } lyra-ecs = { path = "../lyra-ecs" }
lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] } lyra-reflect = { path = "../lyra-reflect" }
winit = "0.28.1" winit = "0.28.1"
tracing = "0.1.37" tracing = "0.1.37"

View File

@ -342,7 +342,7 @@ impl Game {
.with(fmt::layer().with_writer(stdout_layer)) .with(fmt::layer().with_writer(stdout_layer))
.with(filter::Targets::new() .with(filter::Targets::new()
// done by prefix, so it includes all lyra subpackages // done by prefix, so it includes all lyra subpackages
.with_target("lyra", Level::DEBUG) .with_target("lyra", Level::TRACE)
.with_target("wgpu", Level::WARN) .with_target("wgpu", Level::WARN)
.with_default(Level::INFO)) .with_default(Level::INFO))
.init(); .init();

View File

@ -89,7 +89,8 @@ impl Transform {
/// Performs a linear interpolation between `self` and `rhs` based on the value `alpha`. /// 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 /// When `alpha` is `0.0`, the result will be equal to `self`. When `alpha` is `1.0`, the result
/// will be equal to `rhs`. /// will be equal to `rhs`. When `alpha` is outside of range `[0, 1]`, the result is linearly
/// extrapolated.
pub fn lerp(&self, rhs: Transform, alpha: f32) -> Self { pub fn lerp(&self, rhs: Transform, alpha: f32) -> Self {
if alpha.is_finite() { if alpha.is_finite() {

View File

@ -5,10 +5,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
math = ["dep:glam"]
[dependencies] [dependencies]
lyra-reflect-derive = { path = "lyra-reflect-derive" } lyra-reflect-derive = { path = "lyra-reflect-derive" }
lyra-ecs = { path = "../lyra-ecs" } lyra-ecs = { path = "../lyra-ecs" }
glam = { version = "0.24.0", optional = true }

View File

@ -32,7 +32,7 @@ impl From<&Variant> for VariantType {
/// Generates the following different outputs: /// Generates the following different outputs:
/// ///
/// ```compile_fail /// ```rust
/// // for struct variants /// // for struct variants
/// TestEnum::Error { msg, code } /// TestEnum::Error { msg, code }
/// ///
@ -98,7 +98,7 @@ fn gen_variant_if(enum_id: &proc_macro2::Ident, variant: &Variant, if_body: proc
/// Generates the following: /// Generates the following:
/// ///
/// ```compile_fail /// ```rust
/// /// generated one field here /// /// generated one field here
/// if name == "msg" { /// if name == "msg" {
/// return Some(msg); /// return Some(msg);
@ -113,7 +113,7 @@ fn gen_variant_if(enum_id: &proc_macro2::Ident, variant: &Variant, if_body: proc
fn gen_if_field_names(variant: &Variant) -> proc_macro2::TokenStream { fn gen_if_field_names(variant: &Variant) -> proc_macro2::TokenStream {
let field_ifs = variant.fields.iter().map(|field| { let field_ifs = variant.fields.iter().map(|field| {
let id = field.ident.as_ref().unwrap(); let id = field.ident.as_ref().unwrap();
let id_str = id.to_string(); let id_str = id.span().source_text().unwrap();
quote! { quote! {
if name == #id_str { if name == #id_str {
@ -129,7 +129,7 @@ fn gen_if_field_names(variant: &Variant) -> proc_macro2::TokenStream {
/// Generates the following rust code: /// Generates the following rust code:
/// ///
/// ```compile_fail /// ```rust
/// match name { /// match name {
/// "msg" | "code" => true, /// "msg" | "code" => true,
/// _ => false, /// _ => false,
@ -140,7 +140,7 @@ fn gen_match_names(variant: &Variant) -> proc_macro2::TokenStream {
let field_name_strs = variant.fields.iter().map(|field| { let field_name_strs = variant.fields.iter().map(|field| {
let id = field.ident.as_ref() let id = field.ident.as_ref()
.expect("Could not find identifier for enum field!"); .expect("Could not find identifier for enum field!");
id.to_string() id.span().source_text().unwrap()
}); });
quote! { quote! {
@ -153,7 +153,7 @@ fn gen_match_names(variant: &Variant) -> proc_macro2::TokenStream {
/// Generates the following: /// Generates the following:
/// ///
/// ```compile_fail /// ```rust
/// /// generated one field here /// /// generated one field here
/// if idx == 0 { /// if idx == 0 {
/// return Some(a); /// return Some(a);
@ -190,7 +190,7 @@ fn gen_if_field_indices(variant: &Variant) -> proc_macro2::TokenStream {
/// Generates the following: /// Generates the following:
/// ///
/// ```compile_fail /// ```rust
/// /// generated one field here /// /// generated one field here
/// if idx == 0 { /// if idx == 0 {
/// return Some("a"); /// return Some("a");
@ -226,7 +226,7 @@ fn gen_if_field_indices_names(variant: &Variant) -> proc_macro2::TokenStream {
} }
/// Generates the following: /// Generates the following:
/// ```compile_fail /// ```rust
/// /// when `by_index` is false: /// /// when `by_index` is false:
/// ///
/// if let TestEnum::Error{ msg, code} = self { /// if let TestEnum::Error{ msg, code} = self {
@ -292,6 +292,7 @@ fn gen_enum_if_stmts(enum_id: &proc_macro2::Ident, data: &DataEnum, by_index: bo
_ => quote! { }, _ => quote! { },
} }
}); });
println!("====");
quote! { quote! {
#( #struct_vars )* #( #struct_vars )*
@ -300,7 +301,7 @@ fn gen_enum_if_stmts(enum_id: &proc_macro2::Ident, data: &DataEnum, by_index: bo
/// Generates the following rust code: /// Generates the following rust code:
/// ///
/// ```compile_fail /// ```rust
/// if let TestEnum::Error { msg, code } = self { /// if let TestEnum::Error { msg, code } = self {
/// return match name { /// return match name {
/// // expands for continuing struct fields /// // expands for continuing struct fields
@ -331,7 +332,7 @@ fn gen_enum_has_field(enum_id: &proc_macro2::Ident, data: &DataEnum) -> proc_mac
/// Generates the following code: /// Generates the following code:
/// ///
/// ```compile_fail /// ```rust
/// match self { /// match self {
/// TestEnum::Start => 0, /// TestEnum::Start => 0,
/// TestEnum::Middle(a, b) => 2, /// TestEnum::Middle(a, b) => 2,
@ -358,7 +359,7 @@ fn gen_enum_fields_len(enum_id: &proc_macro2::Ident, data: &DataEnum) -> proc_ma
/// Generates the following code: /// Generates the following code:
/// ///
/// ```compile_fail /// ```rust
/// if let TestEnum::Error { msg, code } = self { /// if let TestEnum::Error { msg, code } = self {
/// if idx == 0 { /// if idx == 0 {
/// return Some("msg"); /// return Some("msg");
@ -389,7 +390,7 @@ fn gen_enum_field_name_at(enum_id: &proc_macro2::Ident, data: &DataEnum) -> proc
} }
/// Generates the following code: /// Generates the following code:
/// ```compile_fail /// ```rust
/// match self { /// match self {
/// TestEnum::Start => 0, /// TestEnum::Start => 0,
/// TestEnum::Middle(a, b) => 1, /// TestEnum::Middle(a, b) => 1,
@ -427,7 +428,7 @@ fn gen_enum_variant_name(enum_id: &proc_macro2::Ident, data: &DataEnum, gen_inde
/// Generates a match statement that returns the types of the variants of the enum. /// Generates a match statement that returns the types of the variants of the enum.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```rust
/// match self { /// match self {
/// TestEnum::Start => EnumType::Unit, /// TestEnum::Start => EnumType::Unit,
/// TestEnum::Middle(a, b) => EnumType::Tuple, /// TestEnum::Middle(a, b) => EnumType::Tuple,
@ -457,35 +458,41 @@ fn gen_enum_variant_type(enum_id: &proc_macro2::Ident, data: &DataEnum) -> proc_
/// Create a reflect implementation for an enum /// Create a reflect implementation for an enum
pub fn derive_reflect_enum(input: &DeriveInput, data_enum: &DataEnum) -> proc_macro2::TokenStream { pub fn derive_reflect_enum(input: &DeriveInput, data_enum: &DataEnum) -> proc_macro2::TokenStream {
let input_ident = &input.ident; let type_path = &input.ident;
let ident_str = input.ident.to_string(); let name = type_path.span().source_text().unwrap();
//println!("Got type path: {}", type_path);
let variant_count = data_enum.variants.len(); let variant_count = data_enum.variants.len();
let field_ifs = gen_enum_if_stmts(input_ident, data_enum, false); /* let mut variants_iter = data_enum.variants.iter();
let field_mut_ifs = gen_enum_if_stmts(input_ident, data_enum, false);
let field_at_ifs = gen_enum_if_stmts(input_ident, data_enum, true); let variant = variants_iter.next().unwrap();
let field_at_mut_ifs = gen_enum_if_stmts(input_ident, data_enum, true); let variant_name = &variant.ident; */
let has_field = gen_enum_has_field(input_ident, data_enum); let field_ifs = gen_enum_if_stmts(type_path, data_enum, false);
let field_len = gen_enum_fields_len(input_ident, data_enum); let field_mut_ifs = gen_enum_if_stmts(type_path, data_enum, false);
let field_name_at = gen_enum_field_name_at(input_ident, data_enum);
let variant_name_match = gen_enum_variant_name(input_ident, data_enum, false); let field_at_ifs = gen_enum_if_stmts(type_path, data_enum, true);
let variant_idx_match = gen_enum_variant_name(input_ident, data_enum, true); let field_at_mut_ifs = gen_enum_if_stmts(type_path, data_enum, true);
let variant_type = gen_enum_variant_type(input_ident, data_enum);
let has_field = gen_enum_has_field(type_path, data_enum);
let field_len = gen_enum_fields_len(type_path, data_enum);
let field_name_at = gen_enum_field_name_at(type_path, data_enum);
let variant_name_match = gen_enum_variant_name(type_path, data_enum, false);
let variant_idx_match = gen_enum_variant_name(type_path, data_enum, true);
let variant_type = gen_enum_variant_type(type_path, data_enum);
let generics = add_trait_bounds(input.generics.clone(), vec![parse_quote!(Reflect), parse_quote!(Clone)]); let generics = add_trait_bounds(input.generics.clone(), vec![parse_quote!(Reflect), parse_quote!(Clone)]);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
return proc_macro2::TokenStream::from(quote! { return proc_macro2::TokenStream::from(quote! {
impl #impl_generics lyra_engine::reflect::Reflect for #input_ident #ty_generics #where_clause { impl #impl_generics lyra_engine::reflect::Reflect for #type_path #ty_generics #where_clause {
fn name(&self) -> ::std::string::String { fn name(&self) -> ::std::string::String {
#ident_str.to_string() #name.to_string()
} }
fn type_id(&self) -> std::any::TypeId { fn type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<#input_ident #ty_generics>() std::any::TypeId::of::<#type_path #ty_generics>()
} }
fn as_any(&self) -> &dyn std::any::Any { fn as_any(&self) -> &dyn std::any::Any {
@ -523,7 +530,7 @@ pub fn derive_reflect_enum(input: &DeriveInput, data_enum: &DataEnum) -> proc_ma
} }
} }
impl #impl_generics lyra_engine::reflect::Enum for #input_ident #ty_generics #where_clause { impl #impl_generics lyra_engine::reflect::Enum for #type_path #ty_generics #where_clause {
fn field(&self, name: &str) -> Option<&dyn lyra_engine::reflect::Reflect> { fn field(&self, name: &str) -> Option<&dyn lyra_engine::reflect::Reflect> {
let name = name.to_lowercase(); let name = name.to_lowercase();
let name = name.as_str(); let name = name.as_str();

View File

@ -1,5 +1,4 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::Ident;
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use syn::{Generics, Path, Attribute, GenericParam, parse_macro_input, DeriveInput, TypeParamBound}; use syn::{Generics, Path, Attribute, GenericParam, parse_macro_input, DeriveInput, TypeParamBound};
@ -11,55 +10,8 @@ mod struct_derive;
#[allow(unused_imports)] #[allow(unused_imports)]
use struct_derive::*; use struct_derive::*;
mod struct_macro;
/* #[proc_macro_attribute(attributes(reflect))]
pub fn reflect(_attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
item
} */
pub(crate) struct FieldAttributes(Vec<ReflectAttribute>);
impl FieldAttributes {
/// Searches for a usage of the 'reflect' attribute and returns a list of the
/// things used in the usage.
pub fn from_vec(v: &Vec<syn::Attribute>) -> Result<Self, syn::Error> {
let s: Result<Vec<ReflectAttribute>, _> = v.iter().filter_map(|att| match &att.meta {
syn::Meta::Path(_) => None,
syn::Meta::List(l) => {
Some(syn::parse::<ReflectAttribute>(l.tokens.clone().into()))
}
syn::Meta::NameValue(_) => None
}).collect();
Ok(Self(s?))
}
pub fn has_skip(&self) -> bool {
self.0.iter().any(|a| *a == ReflectAttribute::Skip)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ReflectAttribute {
Skip
}
impl syn::parse::Parse for ReflectAttribute {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let ident: Ident = input.parse()?;
let ident_str = ident.to_string().to_lowercase();
match ident_str.as_str() {
"skip" => Ok(Self::Skip),
_ => Err(syn::Error::new(ident.span(), "Unknown reflect attribute flag"))
}
}
}
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) struct ReflectDef { pub(crate) struct ReflectDef {
//pub ident: Ident,
pub type_path: Path, pub type_path: Path,
pub generics: Generics, pub generics: Generics,
pub attributes: Vec<Attribute> pub attributes: Vec<Attribute>
@ -69,12 +21,10 @@ impl syn::parse::Parse for ReflectDef {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let attributes = input.call(Attribute::parse_outer)?; let attributes = input.call(Attribute::parse_outer)?;
let type_path = Path::parse_mod_style(input)?; let type_path = Path::parse_mod_style(input)?;
//let ident = type_path. //type_path.require_ident()?;
let mut generics = input.parse::<Generics>()?; let mut generics = input.parse::<Generics>()?;
generics.where_clause = input.parse()?; generics.where_clause = input.parse()?;
Ok(Self { Ok(Self {
//ident: ident.clone(),
type_path, type_path,
generics, generics,
attributes, attributes,
@ -82,7 +32,7 @@ impl syn::parse::Parse for ReflectDef {
} }
} }
#[proc_macro_derive(Reflect, attributes(reflect))] #[proc_macro_derive(Reflect)]
pub fn derive_reflect(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn derive_reflect(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput); let input = parse_macro_input!(input as DeriveInput);
@ -106,21 +56,17 @@ pub fn derive_reflect(input: proc_macro::TokenStream) -> proc_macro::TokenStream
pub fn impl_reflect_trait_value(input: TokenStream) -> TokenStream { pub fn impl_reflect_trait_value(input: TokenStream) -> TokenStream {
let reflect = syn::parse_macro_input!(input as ReflectDef); let reflect = syn::parse_macro_input!(input as ReflectDef);
let type_path = reflect.type_path; let type_path = reflect.type_path.clone().into_token_stream();
// convert the type path to a string. This would not create a leading separator
let type_path_str = { let name_id = &reflect.type_path.segments.last().unwrap().ident;
let idents: Vec<String> = type_path.segments.iter() let name = name_id.span().source_text().unwrap();
.map(|segment| segment.ident.to_string())
.collect();
idents.join("::")
};
let (impl_generics, ty_generics, where_clause) = reflect.generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = reflect.generics.split_for_impl();
TokenStream::from(quote! { TokenStream::from(quote! {
impl #impl_generics lyra_engine::reflect::Reflect for #type_path #ty_generics #where_clause { impl #impl_generics lyra_engine::reflect::Reflect for #type_path #ty_generics #where_clause {
fn name(&self) -> ::std::string::String { fn name(&self) -> ::std::string::String {
#type_path_str.to_string() #name.to_string()
} }
fn type_id(&self) -> std::any::TypeId { fn type_id(&self) -> std::any::TypeId {
@ -174,8 +120,3 @@ pub(crate) fn add_trait_bounds(mut generics: Generics, add_bounds: Vec<TypeParam
} }
generics generics
} }
#[proc_macro]
pub fn impl_reflect_simple_struct(input: TokenStream) -> TokenStream {
struct_macro::impl_reflect_simple_struct(input)
}

View File

@ -1,34 +1,13 @@
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use syn::{DeriveInput, parse_quote, DataStruct}; use syn::{DeriveInput, parse_quote, DataStruct};
use crate::{add_trait_bounds, FieldAttributes}; use crate::add_trait_bounds;
#[derive(Debug, PartialEq, Eq)]
enum StructType {
Unit,
Named,
Tuple,
}
impl StructType {
pub fn new(data: &DataStruct) -> Self {
if let Some(first) = data.fields.iter().next() {
if first.ident.is_some() {
Self::Named
} else {
Self::Tuple
}
} else {
Self::Unit
}
}
}
/// Generates code that matches a string with a struct's field name, and returns an Option that /// Generates code that matches a string with a struct's field name, and returns an Option that
/// contains a borrow (mutable borrow if `is_mut` is true) to the matching struct field. /// contains a borrow (mutable borrow if `is_mut` is true) to the matching struct field.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```rust
/// // when `is_mut` = false /// // when `is_mut` = false
/// match name { /// match name {
/// "x" => Some(&self.x), /// "x" => Some(&self.x),
@ -43,49 +22,35 @@ impl StructType {
/// _ => None, /// _ => None,
/// } /// }
/// ``` /// ```
///
/// If the struct is a unit or tuple struct, None will always be returned
fn gen_struct_field_match(data: &DataStruct, is_mut: bool) -> proc_macro2::TokenStream { fn gen_struct_field_match(data: &DataStruct, is_mut: bool) -> proc_macro2::TokenStream {
let ty = StructType::new(data); let mut_tkn = if is_mut {
quote! {
mut
}
} else { quote!{} };
if ty == StructType::Named { let field_arms = data.fields.iter().map(|field| {
let mut_tkn = if is_mut { let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
quote! { let field_name_str = field_ident.to_string();
mut
}
} else { quote!{} };
let field_arms = data.fields.iter().map(|field| {
let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
let field_name_str = field_ident.to_string();
let attrs = FieldAttributes::from_vec(&field.attrs)
.expect("Failure to parse reflect attributes");
if attrs.has_skip() {
quote! {
#field_name_str => None
}
} else {
quote! {
#field_name_str => Some(&#mut_tkn self.#field_ident)
}
}
});
quote! { quote! {
match name { #field_name_str => Some(&#mut_tkn self.#field_ident)
#(#field_arms,)*
_ => None,
}
} }
} else { quote!(None) } });
quote! {
match name {
#(#field_arms,)*
_ => None,
}
}
} }
/// Generates code that matches a string with a struct's field name, and sets that field value /// Generates code that matches a string with a struct's field name, and sets that field value
/// with the provided `val`. /// with the provided `val`.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```rust
/// match name { /// match name {
/// "x" => self.x = any_val.downcast_ref::<f32>() /// "x" => self.x = any_val.downcast_ref::<f32>()
/// .expect(&format!("Cannot set struct's field of {} type to the provided type of {}", "f32", val.name())) /// .expect(&format!("Cannot set struct's field of {} type to the provided type of {}", "f32", val.name()))
@ -99,48 +64,34 @@ fn gen_struct_field_match(data: &DataStruct, is_mut: bool) -> proc_macro2::Token
/// } /// }
/// ``` /// ```
fn gen_struct_set_field_match(data: &DataStruct) -> proc_macro2::TokenStream { fn gen_struct_set_field_match(data: &DataStruct) -> proc_macro2::TokenStream {
let ty = StructType::new(data); let field_arms = data.fields.iter().map(|field| {
let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
if ty == StructType::Named { let field_name_str = field_ident.to_string();
let field_arms = data.fields.iter().map(|field| { let field_ty = &field.ty;
let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
let field_name_str = field_ident.to_string();
let field_ty = &field.ty;
let attrs = FieldAttributes::from_vec(&field.attrs)
.expect("Failure to parse reflect attributes");
if attrs.has_skip() {
quote! {
#field_name_str => {}
}
} else {
quote! {
#field_name_str => self.#field_ident = any_val.downcast_ref::<#field_ty>()
.expect(&format!("Cannot set struct's field of {} type to the provided type of {}", #field_name_str, val.name()))
.clone() //Some(&#mut_tkn self.#field_ident)
}
}
});
quote! { quote! {
let any_val = val.as_any(); #field_name_str => self.#field_ident = any_val.downcast_ref::<#field_ty>()
match name { .expect(&format!("Cannot set struct's field of {} type to the provided type of {}", #field_name_str, val.name()))
#(#field_arms,)* .clone() //Some(&#mut_tkn self.#field_ident)
_ => {
return false;
},
}
true
} }
} else { quote!(return false;) } });
quote! {
let any_val = val.as_any();
match name {
#(#field_arms,)*
_ => {
return false;
},
}
}
} }
/// Generates code that matches a string with a struct's field name, and returns a string that is /// Generates code that matches a string with a struct's field name, and returns a string that is
/// the type of the field. /// the type of the field.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```rust
/// match name { /// match name {
/// "x" => Some("f32"), /// "x" => Some("f32"),
/// "y" => Some("f32"), /// "y" => Some("f32"),
@ -148,36 +99,32 @@ fn gen_struct_set_field_match(data: &DataStruct) -> proc_macro2::TokenStream {
/// } /// }
/// ``` /// ```
fn gen_struct_field_name_match(data: &DataStruct) -> proc_macro2::TokenStream { fn gen_struct_field_name_match(data: &DataStruct) -> proc_macro2::TokenStream {
let ty = StructType::new(data); let field_arms = data.fields.iter().map(|field| {
let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
let field_name_str = field_ident.to_string();
if ty == StructType::Named { let mut field_ty_stream = proc_macro2::TokenStream::new();
let field_arms = data.fields.iter().map(|field| { field.ty.to_tokens(&mut field_ty_stream);
let field_ident = field.ident.as_ref().expect("Struct is missing field ident!"); let s = field_ty_stream.to_string();
let field_name_str = field_ident.to_string();
let mut field_ty_stream = proc_macro2::TokenStream::new();
field.ty.to_tokens(&mut field_ty_stream);
let s = field_ty_stream.to_string();
quote! {
#field_name_str => Some(#s)
}
});
quote! { quote! {
match name { #field_name_str => Some(#s)
#(#field_arms,)*
_ => None,
}
} }
} else { quote!(None) } });
quote! {
match name {
#(#field_arms,)*
_ => None,
}
}
} }
/// Generates code that matches a string with a struct's field name, and sets that field value /// Generates code that matches a string with a struct's field name, and sets that field value
/// with the provided `val`. /// with the provided `val`.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```rust
/// match name { /// match name {
/// 0 => self.x = any_val.downcast_ref::<f32>() /// 0 => self.x = any_val.downcast_ref::<f32>()
/// .expect(&format!("Cannot set struct's field of {} type to the provided type of {}", "f32", val.name())) /// .expect(&format!("Cannot set struct's field of {} type to the provided type of {}", "f32", val.name()))
@ -191,38 +138,15 @@ fn gen_struct_field_name_match(data: &DataStruct) -> proc_macro2::TokenStream {
/// } /// }
/// ``` /// ```
fn gen_struct_set_field_match_idx(data: &DataStruct) -> proc_macro2::TokenStream { fn gen_struct_set_field_match_idx(data: &DataStruct) -> proc_macro2::TokenStream {
let ty = StructType::new(data);
if ty == StructType::Unit {
return quote!( return false; );
}
let field_arms = data.fields.iter().enumerate().map(|(idx, field)| { let field_arms = data.fields.iter().enumerate().map(|(idx, field)| {
let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
let field_name_str = field_ident.to_string();
let field_ty = &field.ty; let field_ty = &field.ty;
let attrs = FieldAttributes::from_vec(&field.attrs) quote! {
.expect("Failure to parse reflect attributes"); #idx => self.#field_ident = any_val.downcast_ref::<#field_ty>()
if attrs.has_skip() { .expect(&format!("Cannot set struct's field of {} type to the provided type of {}", #field_name_str, val.name()))
return quote! { .clone()
#idx => {}
};
}
if let Some(field_ident) = &field.ident {
let field_name_str = field_ident.to_string();
quote! {
#idx => self.#field_ident = any_val.downcast_ref::<#field_ty>()
.expect(&format!("Cannot set struct's field of {} to the provided type of {}", #field_name_str, val.name()))
.clone()
}
} else {
let sidx = syn::Index::from(idx);
quote! {
#idx => self.#sidx = any_val.downcast_ref::<#field_ty>()
.expect(&format!("Cannot set struct's field at {} to the provided type of {}", #idx, val.name()))
.clone()
}
} }
}); });
@ -234,8 +158,6 @@ fn gen_struct_set_field_match_idx(data: &DataStruct) -> proc_macro2::TokenStream
return false; return false;
}, },
} }
true
} }
} }
@ -243,7 +165,7 @@ fn gen_struct_set_field_match_idx(data: &DataStruct) -> proc_macro2::TokenStream
/// type of the field. /// type of the field.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```rust
/// match name { /// match name {
/// 0 => Some("f32"), /// 0 => Some("f32"),
/// 1 => Some("f32"), /// 1 => Some("f32"),
@ -274,7 +196,7 @@ fn gen_struct_field_name_match_idx(data: &DataStruct) -> proc_macro2::TokenStrea
/// to the matching struct field. /// to the matching struct field.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```rust
/// // when `is_mut` = false /// // when `is_mut` = false
/// match idx { /// match idx {
/// 0 => Some(&self.x), /// 0 => Some(&self.x),
@ -290,12 +212,6 @@ fn gen_struct_field_name_match_idx(data: &DataStruct) -> proc_macro2::TokenStrea
/// } /// }
/// ``` /// ```
fn gen_struct_field_match_idx(data: &DataStruct, is_mut: bool) -> proc_macro2::TokenStream { fn gen_struct_field_match_idx(data: &DataStruct, is_mut: bool) -> proc_macro2::TokenStream {
let ty = StructType::new(data);
if ty == StructType::Unit {
return quote!(None);
}
let mut_tkn = if is_mut { let mut_tkn = if is_mut {
quote! { quote! {
mut mut
@ -303,23 +219,10 @@ fn gen_struct_field_match_idx(data: &DataStruct, is_mut: bool) -> proc_macro2::T
} else { quote!{} }; } else { quote!{} };
let field_arms = data.fields.iter().enumerate().map(|(idx, field)| { let field_arms = data.fields.iter().enumerate().map(|(idx, field)| {
let attrs = FieldAttributes::from_vec(&field.attrs) let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
.expect("Failure to parse reflect attributes");
if attrs.has_skip() {
return quote! {
#idx => None
};
}
if let Some(field_ident) = &field.ident { quote! {
quote! { #idx => Some(&#mut_tkn self.#field_ident)
#idx => Some(&#mut_tkn self.#field_ident)
}
} else {
let sidx = syn::Index::from(idx);
quote! {
#idx => Some(&#mut_tkn self.#sidx)
}
} }
}); });
@ -335,7 +238,7 @@ fn gen_struct_field_match_idx(data: &DataStruct, is_mut: bool) -> proc_macro2::T
/// and returns an Option that contains the name of the field. /// and returns an Option that contains the name of the field.
/// ///
/// Example: /// Example:
/// ```compile_fail /// ```rust
/// match idx { /// match idx {
/// 0 => Some("x"), /// 0 => Some("x"),
/// 1 => Some("y"), /// 1 => Some("y"),
@ -343,34 +246,27 @@ fn gen_struct_field_match_idx(data: &DataStruct, is_mut: bool) -> proc_macro2::T
/// } /// }
/// ``` /// ```
fn gen_struct_field_name_idx(data: &DataStruct) -> proc_macro2::TokenStream { fn gen_struct_field_name_idx(data: &DataStruct) -> proc_macro2::TokenStream {
let ty = StructType::new(data); let field_arms = data.fields.iter().enumerate().map(|(idx, field)| {
let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
if ty == StructType::Named { let field_name_str = field_ident.to_string();
let field_arms = data.fields.iter().enumerate().map(|(idx, field)| {
let field_ident = field.ident.as_ref().expect("Struct is missing field ident!");
let field_name_str = field_ident.to_string();
quote! {
#idx => Some(#field_name_str)
}
});
quote! { quote! {
match idx { #idx => Some(#field_name_str)
#(#field_arms,)* }
_ => None, });
}
quote! {
match idx {
#(#field_arms,)*
_ => None,
} }
} else {
quote!(None)
} }
} }
/// Generates a token stream that implements Reflect and Struct for the provided struct /// Generates a token stream that implements Reflect and Struct for the provided struct
pub fn derive_reflect_struct(input: &DeriveInput, data_struct: &DataStruct) -> proc_macro2::TokenStream { pub fn derive_reflect_struct(input: &DeriveInput, data_struct: &DataStruct) -> proc_macro2::TokenStream {
let type_path = &input.ident; let type_path = &input.ident;
let name = type_path.to_string(); let name = type_path.span().source_text().unwrap();
//let name = type_path.span().source_text().unwrap();
let field_len = data_struct.fields.len(); let field_len = data_struct.fields.len();
let get_field_match = gen_struct_field_match(data_struct, false); let get_field_match = gen_struct_field_match(data_struct, false);
@ -464,10 +360,12 @@ pub fn derive_reflect_struct(input: &DeriveInput, data_struct: &DataStruct) -> p
fn set_field(&mut self, name: &str, val: &dyn lyra_engine::reflect::Reflect) -> bool { fn set_field(&mut self, name: &str, val: &dyn lyra_engine::reflect::Reflect) -> bool {
#set_field_named #set_field_named
true
} }
fn set_field_at(&mut self, idx: usize, val: &dyn lyra_engine::reflect::Reflect) -> bool { fn set_field_at(&mut self, idx: usize, val: &dyn lyra_engine::reflect::Reflect) -> bool {
#set_field_idx #set_field_idx
true
} }
fn field_type(&self, name: &str) -> Option<&'static str> { fn field_type(&self, name: &str) -> Option<&'static str> {

View File

@ -1,270 +0,0 @@
use quote::quote;
use syn::{Token, parenthesized, punctuated::Punctuated};
struct Field {
name: syn::Ident,
_eq: Token![=],
ty: syn::Ident,
}
impl syn::parse::Parse for Field {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(Self {
name: input.parse()?,
_eq: input.parse()?,
ty: input.parse()?,
})
}
}
struct SimpleStruct {
type_path: syn::Path,
pub generics: syn::Generics,
fields: Vec<Field>,
}
impl syn::parse::Parse for SimpleStruct {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
//let type_path = syn::Path::parse_mod_style(input)?;
let type_path: syn::Path = input.parse()?;
/* let mut generics = input.parse::<syn::Generics>()?;
generics.where_clause = input.parse()?; */
let mut fields = vec![];
// parse fields if a comma is found
if input.peek(Token![,]) {
let _: Token![,] = input.parse()?;
let ident: syn::Ident = input.parse()?;
let ident_str = ident.to_string();
match ident_str.as_str() {
"fields" => {
let content;
let _parens: syn::token::Paren = parenthesized!(content in input);
let f: Punctuated<Field, Token![,]> = content.parse_terminated(Field::parse, Token![,])?;
fields = f.into_iter().collect();
},
_ => return Err(syn::Error::new(ident.span(), "Unknown macro command, expected `fields`")),
}
}
Ok(Self {
type_path,
generics: syn::Generics::default(),
fields,
})
}
}
fn gen_match_field_name_arm(simple: &SimpleStruct, default: &proc_macro2::TokenStream, arm_gen: fn(field: &Field) -> proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let field_arms_iter = simple.fields.iter().map(|f| {
let fname = &f.name;
let arm = arm_gen(f);
quote! {
stringify!(#fname) => #arm
}
});
quote! {
match name {
#(#field_arms_iter,)*
_ => #default,
}
}
}
fn gen_match_field_index_arm(simple: &SimpleStruct, default: &proc_macro2::TokenStream, arm_gen: fn(field: &Field) -> proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let field_arms_iter = simple.fields.iter().enumerate().map(|(idx, f)| {
let arm = arm_gen(f);
quote! {
#idx => #arm
}
});
quote! {
match idx {
#(#field_arms_iter,)*
_ => #default,
}
}
}
pub(crate) fn impl_reflect_simple_struct(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let simple = syn::parse_macro_input!(input as SimpleStruct);
let type_path = &simple.type_path;
let (impl_generics, ty_generics, where_clause) = simple.generics.split_for_impl();
// convert the type path to a string. This would not create a leading separator
/* let type_path_str = {
let idents: Vec<String> = type_path.segments.iter()
.map(|segment| segment.ident.to_string())
.collect();
idents.join("::")
}; */
let borrow_fn = |field: &Field| {
let name = &field.name;
quote! {
Some(&self.#name)
}
};
let borrow_mut_fn = |field: &Field| {
let name = &field.name;
quote! {
Some(&mut self.#name)
}
};
let none_default = quote!(None);
let false_return_default = quote!( { return false; });
let field_count = simple.fields.len();
let field_fn = gen_match_field_name_arm(&simple, &none_default, borrow_fn);
let field_mut_fn = gen_match_field_name_arm(&simple, &none_default, borrow_mut_fn);
let field_at_fn = gen_match_field_index_arm(&simple, &none_default, borrow_fn);
let field_at_mut_fn = gen_match_field_index_arm(&simple, &none_default, borrow_mut_fn);
let field_name_at_fn = gen_match_field_index_arm(&simple, &none_default, |f| {
let name = &f.name;
quote! {
Some(stringify!(#name))
}
});
let set_field_arm = |f: &Field| {
let name = &f.name;
let ty = &f.ty;
quote! {
self.#name = any_val.downcast_ref::<#ty>()
.expect(&format!("Cannot set struct's field of {} type to the provided type of {}", stringify!(#name), val.name()))
.clone() //Some(&#mut_tkn self.#field_ident)
}
};
let set_field_fn = gen_match_field_name_arm(&simple, &false_return_default, set_field_arm);
let set_field_at_fn = gen_match_field_index_arm(&simple, &false_return_default, set_field_arm);
let get_field_ty_arm = |f: &Field| {
let fty = &f.ty;
quote! {
Some(stringify!(#fty))
}
};
let field_type_fn = gen_match_field_name_arm(&simple, &none_default, get_field_ty_arm);
let field_type_at_fn = gen_match_field_index_arm(&simple, &none_default, get_field_ty_arm);
proc_macro::TokenStream::from(quote! {
impl #impl_generics lyra_engine::reflect::Reflect for #type_path #ty_generics #where_clause {
fn name(&self) -> ::std::string::String {
stringify!(#type_path).to_string()
}
fn type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<#type_path #ty_generics>()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn apply(&mut self, val: &dyn lyra_engine::reflect::Reflect) {
let val = val.as_any().downcast_ref::<Self>()
.expect("The type of `val` is not the same as `self`");
*self = val.clone();
}
fn clone_inner(&self) -> Box<dyn lyra_engine::reflect::Reflect> {
Box::new(self.clone())
}
fn reflect_ref(&self) -> lyra_engine::reflect::ReflectRef {
lyra_engine::reflect::ReflectRef::Value(self)
}
fn reflect_mut(&mut self) -> lyra_engine::reflect::ReflectMut {
lyra_engine::reflect::ReflectMut::Value(self)
}
fn reflect_val(&self) -> &dyn lyra_engine::reflect::Reflect {
self
}
fn reflect_val_mut(&mut self) -> &mut dyn lyra_engine::reflect::Reflect {
self
}
}
impl #impl_generics lyra_engine::reflect::Struct for #type_path #ty_generics #where_clause {
fn field(&self, name: &str) -> Option<&dyn Reflect> {
#field_fn
}
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> {
#field_mut_fn
}
fn fields_len(&self) -> usize {
#field_count
}
fn field_at(&self, idx: usize) -> Option<&dyn Reflect> {
#field_at_fn
}
fn field_at_mut(&mut self, idx: usize) -> Option<&mut dyn Reflect> {
#field_at_mut_fn
}
fn field_name_at(&self, idx: usize) -> Option<&str> {
#field_name_at_fn
}
fn set_field(&mut self, name: &str, val: &dyn Reflect) -> bool {
let any_val = val.as_any();
#set_field_fn
true
}
fn set_field_at(&mut self, idx: usize, val: &dyn Reflect) -> bool {
let any_val = val.as_any();
#set_field_at_fn
true
}
fn field_type(&self, name: &str) -> Option<&'static str> {
#field_type_fn
}
fn field_type_at(&self, idx: usize) -> Option<&'static str> {
#field_type_at_fn
}
fn method(&self, name: &str) -> Option<&Method> {
unimplemented!()
}
fn method_at(&self, idx: usize) -> Option<&Method> {
unimplemented!()
}
fn methods_len(&self) -> usize {
unimplemented!()
}
}
})
}

View File

@ -4,7 +4,7 @@ use crate::List;
use crate::lyra_engine; use crate::lyra_engine;
use crate::{Reflect, ReflectRef, ReflectMut, util}; use super::{Reflect, ReflectRef, ReflectMut, util};
impl_reflect_trait_value!(bool); impl_reflect_trait_value!(bool);
impl_reflect_trait_value!(char); impl_reflect_trait_value!(char);

View File

@ -1,10 +0,0 @@
use lyra_reflect_derive::{impl_reflect_simple_struct, impl_reflect_trait_value};
use crate::{lyra_engine, Reflect, Method};
impl_reflect_simple_struct!(glam::Vec2, fields(x=f32, y=f32));
impl_reflect_simple_struct!(glam::Vec3, fields(x=f32, y=f32, z=f32));
impl_reflect_simple_struct!(glam::Vec4, fields(x=f32, y=f32, z=f32, w=f32));
impl_reflect_simple_struct!(glam::Quat, fields(x=f32, y=f32, z=f32, w=f32));
impl_reflect_trait_value!(glam::Mat4);

View File

@ -1,4 +0,0 @@
pub mod impl_std;
#[cfg(feature="math")]
pub mod impl_math;

View File

@ -6,8 +6,6 @@ use lyra_ecs::{world::World, DynamicBundle, Component, Entity, ComponentInfo};
extern crate self as lyra_reflect; extern crate self as lyra_reflect;
pub use lyra_reflect_derive::*;
#[allow(unused_imports)] #[allow(unused_imports)]
pub(crate) mod lyra_engine { pub(crate) mod lyra_engine {
pub(crate) mod reflect { pub(crate) mod reflect {
@ -44,7 +42,7 @@ pub use method::*;
pub mod registry; pub mod registry;
pub use registry::*; pub use registry::*;
pub mod impls; pub mod impl_std;
pub trait Reflect: Any { pub trait Reflect: Any {
fn name(&self) -> String; fn name(&self) -> String;

View File

@ -52,6 +52,7 @@ pub trait Enum: Reflect {
#[allow(unused_variables)] #[allow(unused_variables)]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use lyra_reflect_derive::Reflect;
use super::EnumType; use super::EnumType;
use crate::{lyra_engine, Reflect, ReflectRef}; use crate::{lyra_engine, Reflect, ReflectRef};

View File

@ -41,6 +41,7 @@ pub trait Struct: Reflect {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use lyra_reflect_derive::Reflect;
use crate::{Reflect, ReflectRef, ReflectMut}; use crate::{Reflect, ReflectRef, ReflectMut};
use crate::lyra_engine; use crate::lyra_engine;

View File

@ -21,12 +21,6 @@ impl TypeRegistry {
self.inner.get_mut(&type_id) self.inner.get_mut(&type_id)
} }
/// Get a registered type, or register a new type and return it.
pub fn get_type_or_default(&mut self, type_id: TypeId) -> &mut RegisteredType {
self.inner.entry(type_id)
.or_insert(RegisteredType::default())
}
pub fn register_type<T>(&mut self) pub fn register_type<T>(&mut self)
where where
T: AsRegisteredType + 'static T: AsRegisteredType + 'static

View File

@ -10,9 +10,8 @@ default = ["lua"]
lua = ["dep:mlua"] lua = ["dep:mlua"]
[dependencies] [dependencies]
lyra-scripting-derive = { path = "lyra-scripting-derive" } lyra-ecs = { path = "../lyra-ecs" }
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] } lyra-reflect = { path = "../lyra-reflect" }
lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] }
lyra-resource = { path = "../lyra-resource" } lyra-resource = { path = "../lyra-resource" }
lyra-game = { path = "../lyra-game" } lyra-game = { path = "../lyra-game" }
thiserror = "1.0.50" thiserror = "1.0.50"

View File

@ -1,14 +0,0 @@
[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"

View File

@ -1,606 +0,0 @@
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>()
}
}
})
}

View File

@ -1,142 +0,0 @@
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`"))?,
})
}
}

View File

@ -1,177 +0,0 @@
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

View File

@ -1,94 +0,0 @@
--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

View File

@ -1,161 +0,0 @@
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

View File

@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use lyra_ecs::{ResourceObject, Entity, World}; use lyra_ecs::{ResourceObject, Entity};
use crate::ScriptWorldPtr; use crate::ScriptWorldPtr;
@ -42,9 +42,6 @@ pub trait ScriptApiProvider {
/// The type used as the script's context. /// The type used as the script's context.
type ScriptContext; 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. /// Exposes an API in the provided script context.
fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), ScriptError>; fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), ScriptError>;

View File

@ -2,7 +2,6 @@
pub mod lua; pub mod lua;
pub mod world; pub mod world;
use lyra_ecs::Component;
pub use world::*; pub use world::*;
pub mod wrap; pub mod wrap;
@ -19,10 +18,9 @@ use lyra_game::game::Game;
#[allow(unused_imports)] #[allow(unused_imports)]
pub(crate) mod lyra_engine { pub(crate) mod lyra_engine {
pub use lyra_ecs as ecs; pub use lyra_ecs as ecs;
pub use lyra_reflect as reflect;
} }
use lyra_reflect::{ReflectedComponent, Reflect, FromType}; use lyra_reflect::{ReflectedComponent, Reflect};
#[derive(Clone)] #[derive(Clone)]
pub enum ReflectBranch { pub enum ReflectBranch {
@ -62,20 +60,6 @@ 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 /// An extension trait that adds some helpful methods that makes it easier to do scripting things
pub trait GameScriptExt { pub trait GameScriptExt {
fn add_script_api_provider<T, P>(&mut self, provider: P) fn add_script_api_provider<T, P>(&mut self, provider: P)
@ -85,13 +69,12 @@ pub trait GameScriptExt {
} }
impl GameScriptExt for Game { impl GameScriptExt for Game {
fn add_script_api_provider<T, P>(&mut self, mut provider: P) fn add_script_api_provider<T, P>(&mut self, provider: P)
where where
T: ScriptHost, T: ScriptHost,
P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static
{ {
let world = self.world(); let world = self.world();
provider.prepare_world(world);
let mut providers = world.get_resource_mut::<ScriptApiProviders<T>>(); let mut providers = world.get_resource_mut::<ScriptApiProviders<T>>();
providers.add_provider(provider); providers.add_provider(provider);
} }

View File

@ -149,7 +149,7 @@ impl ReflectedIterator {
unsafe { self.reflected_components.as_ref().unwrap().as_ref() }; unsafe { self.reflected_components.as_ref().unwrap().as_ref() };
let reg_type = reflected_components.get_type(id) let reg_type = reflected_components.get_type(id)
.expect("Requested type was not found in TypeRegistry"); .expect("Could not find type for dynamic view!");
let proxy = reg_type.get_data::<ReflectLuaProxy>() let proxy = reg_type.get_data::<ReflectLuaProxy>()
.expect("Type does not have ReflectLuaProxy as a TypeData"); .expect("Type does not have ReflectLuaProxy as a TypeData");

View File

@ -4,7 +4,7 @@ pub use dynamic_iter::*;
pub mod world; pub mod world;
use lyra_game::{plugin::Plugin, game::GameStages}; use lyra_game::{plugin::Plugin, game::GameStages};
use lyra_resource::ResourceManager; use lyra_resource::ResourceManager;
use tracing::{debug, error, trace}; use tracing::{debug, error};
pub use world::*; pub use world::*;
pub mod script; pub mod script;
@ -13,16 +13,16 @@ pub use script::*;
pub mod loader; pub mod loader;
pub use loader::*; pub use loader::*;
pub mod providers; pub mod modules;
pub mod wrappers; pub use modules::*;
#[cfg(test)] #[cfg(test)]
mod test; mod test;
use std::{ptr::NonNull, sync::Mutex, any::TypeId}; use std::{ptr::NonNull, sync::Mutex};
use lyra_ecs::{DynamicBundle, World, query::{ResMut, View, Entities}}; use lyra_ecs::{DynamicBundle, World, query::{ResMut, View, Entities}};
use lyra_reflect::{Reflect, FromType, RegisteredType, TypeRegistry}; use lyra_reflect::{Reflect, FromType};
use mlua::{Lua, AnyUserDataExt}; use mlua::{Lua, AnyUserDataExt};
@ -33,35 +33,6 @@ pub const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
use crate::{ScriptBorrow, ScriptDynamicBundle, ScriptApiProviders, ScriptContexts, ScriptWorldPtr, ScriptList, ScriptData, ScriptHost, ScriptError, GameScriptExt}; 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 { impl<'lua> mlua::FromLua<'lua> for ScriptBorrow {
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua Lua) -> mlua::Result<Self> { fn from_lua(value: mlua::Value<'lua>, _lua: &'lua Lua) -> mlua::Result<Self> {
match value { match value {
@ -78,11 +49,6 @@ pub fn reflect_user_data(ud: &mlua::AnyUserData) -> ScriptBorrow {
.expect("Type does not implement '__internal_reflect' properly") .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 { pub trait LuaProxy {
fn as_lua_value<'lua>(lua: &'lua mlua::Lua, this: &dyn Reflect) -> mlua::Result<mlua::AnyUserData<'lua>>; 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<()>; fn apply(lua: &mlua::Lua, this: &mut dyn Reflect, apply: &mlua::AnyUserData) -> mlua::Result<()>;
@ -210,7 +176,7 @@ fn lua_call_script_function(world: &mut World, stage_name: &str) -> anyhow::Resu
}; };
if let Some(ctx) = contexts.get_context_mut(script.id()) { if let Some(ctx) = contexts.get_context_mut(script.id()) {
trace!("Running '{}' function in script '{}'", stage_name, script.name()); debug!("Running '{}' function in script '{}'", stage_name, script.name());
match host.call_script(world_ptr.clone(), &script_data, ctx, &mut providers, stage_name) { match host.call_script(world_ptr.clone(), &script_data, ctx, &mut providers, stage_name) {
Ok(()) => {}, Ok(()) => {},
Err(e) => match e { Err(e) => match e {
@ -264,8 +230,6 @@ impl Plugin for LuaScriptingPlugin {
fn setup(&self, game: &mut lyra_game::game::Game) { fn setup(&self, game: &mut lyra_game::game::Game) {
let world = game.world(); let world = game.world();
world.add_resource_default::<TypeRegistry>();
world.add_resource_default::<LuaHost>(); world.add_resource_default::<LuaHost>();
world.add_resource_default::<ScriptApiProviders<LuaHost>>(); world.add_resource_default::<ScriptApiProviders<LuaHost>>();
world.add_resource_default::<ScriptContexts<LuaContext>>(); world.add_resource_default::<ScriptContexts<LuaContext>>();
@ -276,8 +240,6 @@ impl Plugin for LuaScriptingPlugin {
drop(loader); drop(loader);
game.add_script_api_provider::<LuaHost, _>(UtilityApiProvider); game.add_script_api_provider::<LuaHost, _>(UtilityApiProvider);
game.add_script_api_provider::<LuaHost, _>(LyraEcsApiProvider);
game.add_script_api_provider::<LuaHost, _>(LyraMathApiProvider);
game game
.add_system_to_stage(GameStages::First, "lua_create_contexts", lua_scripts_create_contexts, &[]) .add_system_to_stage(GameStages::First, "lua_create_contexts", lua_scripts_create_contexts, &[])

View File

@ -1,26 +0,0 @@
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(())
}
}

View File

@ -1,108 +0,0 @@
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))
}
} */

View File

@ -1,8 +0,0 @@
pub mod util;
pub use util::*;
pub mod math;
pub use math::*;
pub mod ecs;
pub use ecs::*;

View File

@ -1,7 +1,7 @@
use std::sync::Mutex; use std::sync::Mutex;
use mlua::IntoLua; use mlua::IntoLua;
use tracing::{debug, trace}; use tracing::debug;
use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity}; 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)?; .map_err(ScriptError::MluaError)?;
}, },
Err(mlua::Error::FromLuaConversionError { from: "nil", to: "function", message: None }) => { Err(mlua::Error::FromLuaConversionError { from: "nil", to: "function", message: None }) => {
trace!("Function '{}' was not found, ignoring...", fn_name) debug!("Function '{}' was not found, ignoring...", fn_name)
// ignore // ignore
}, },
Err(e) => { Err(e) => {

View File

@ -1,5 +1,3 @@
use std::sync::Arc;
use lyra_ecs::query::dynamic::QueryDynamicType; use lyra_ecs::query::dynamic::QueryDynamicType;
use lyra_reflect::TypeRegistry; use lyra_reflect::TypeRegistry;
use mlua::{AnyUserDataExt, IntoLua, IntoLuaMulti}; use mlua::{AnyUserDataExt, IntoLua, IntoLuaMulti};
@ -75,9 +73,7 @@ impl mlua::UserData for ScriptWorldPtr {
methods.add_method("view", |lua, this, (system, queries): (mlua::Function, mlua::Variadic<mlua::AnyUserData>)| { methods.add_method("view", |lua, this, (system, queries): (mlua::Function, mlua::Variadic<mlua::AnyUserData>)| {
if queries.is_empty() { if queries.is_empty() {
return Err(mlua::Error::BadArgument { to: Some("world:view".to_string()), pos: 2, name: Some("...".to_string()), cause: panic!("No components were provided!");
Arc::new(mlua::Error::external(WorldError::LuaInvalidUsage("no component types provided".to_string())))
});
} }
let world = unsafe { this.inner.as_ref() }; let world = unsafe { this.inner.as_ref() };

View File

@ -1,365 +0,0 @@
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
)
); */