From e354528942b5863645f4ef67180abd5638b26200 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Mon, 19 Feb 2024 23:14:38 -0500 Subject: [PATCH] scripting: Implement LuaVec3:move_by, and add more methods for Lua on math types --- examples/testbed/scripts/test.lua | 5 + lyra-scripting/elua | 2 +- .../lyra-scripting-derive/src/lib.rs | 33 +++- .../lyra-scripting-derive/src/mat_wrapper.rs | 34 ++-- lyra-scripting/src/lua/wrappers/math.rs | 174 ++++++++++++------ 5 files changed, 170 insertions(+), 78 deletions(-) diff --git a/examples/testbed/scripts/test.lua b/examples/testbed/scripts/test.lua index 0294bac..7c2af70 100644 --- a/examples/testbed/scripts/test.lua +++ b/examples/testbed/scripts/test.lua @@ -14,6 +14,11 @@ function on_update() ---@type number local dt = world:resource(DeltaTime) + local v = Vec3.new(10, 10, 10) + v:move_by(50, 50, 50) + v:move_by(Vec3.new(50, 50, 50)) + print("v = " .. tostring(v)) + world:view(function (t) t:translate(0, 0.5 * dt, 0) diff --git a/lyra-scripting/elua b/lyra-scripting/elua index d32c138..22b6d21 160000 --- a/lyra-scripting/elua +++ b/lyra-scripting/elua @@ -1 +1 @@ -Subproject commit d32c138e996ec2fe17b7a5f7c0d3ff1562e446f0 +Subproject commit 22b6d218bdb6a5aafc0efd4fb80a67d2c796d0e7 diff --git a/lyra-scripting/lyra-scripting-derive/src/lib.rs b/lyra-scripting/lyra-scripting-derive/src/lib.rs index 21367b1..5f90c92 100644 --- a/lyra-scripting/lyra-scripting-derive/src/lib.rs +++ b/lyra-scripting/lyra-scripting-derive/src/lib.rs @@ -38,6 +38,22 @@ impl MetaMethod { s.starts_with("Lua") } + /// Returns a boolean indiciating if the metamethod has takes in any arguments + fn does_metamethod_have_arg(metamethod: &Ident) -> bool { + let mm_str = metamethod.to_string(); + let mm_str = mm_str.as_str(); + match mm_str { + "Add" | "Sub" | "Div" | "Mul" | "Mod" | "Eq" | "Shl" | "Shr" | "BAnd" | "BOr" + | "BXor" => { + true + }, + "Unm" | "BNot" | "ToString" => { + false + }, + _ => todo!(), + } + } + /// returns the tokens of the body of the metamethod /// /// Parameters @@ -139,11 +155,20 @@ impl MetaMethod { }; let body = Self::get_method_body(&self.ident, other); - quote! { - builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, (v,): (#wrapper_ident,)| { - #body - }); + if Self::does_metamethod_have_arg(&self.ident) { + quote! { + builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, (v,): (#wrapper_ident,)| { + #body + }); + } + } else { + quote! { + builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, ()| { + #body + }); + } } + } else if self.mods.len() == 1 { let first = self.mods.iter().next().unwrap(); let body = Self::get_body_for_arg(&self.ident, first, quote!(v)); diff --git a/lyra-scripting/lyra-scripting-derive/src/mat_wrapper.rs b/lyra-scripting/lyra-scripting-derive/src/mat_wrapper.rs index fdb0e39..770451f 100644 --- a/lyra-scripting/lyra-scripting-derive/src/mat_wrapper.rs +++ b/lyra-scripting/lyra-scripting-derive/src/mat_wrapper.rs @@ -9,9 +9,9 @@ pub(crate) struct MatWrapper { 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)); + builder.field("ZERO", #wrapper_ident(#wrapped_path::ZERO)); + builder.field("IDENTITY", #wrapper_ident(#wrapped_path::IDENTITY)); + builder.field("NAN", #wrapper_ident(#wrapped_path::NAN)); } } @@ -28,37 +28,37 @@ impl MatWrapper { let element_ty = quote!(f32); quote! { - methods.add_function("from_cols", + builder.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", + builder.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", + builder.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", + builder.function("from_diagonal", |_, (diag,): (#column_type,)| { Ok(#wrapper_ident(#wrapped_path::from_diagonal(diag.0))) }); - methods.add_method("col", + builder.method("col", |_, this, (idx,): (usize,)| { Ok(#column_type(this.col(idx))) }); - methods.add_method("row", + builder.method("row", |_, this, (idx,): (usize,)| { Ok(#column_type(this.row(idx))) }); - methods.add_method_mut("set_col", + builder.method_mut("set_col", |_, this, (idx, newc): (usize, #column_type)| { let col = this.col_mut(idx); *col = newc.0; @@ -66,38 +66,38 @@ impl MatWrapper { Ok(()) }); - methods.add_method("is_finite", + builder.method("is_finite", |_, this, (): ()| { Ok(this.is_finite()) }); - methods.add_method("is_nan", + builder.method("is_nan", |_, this, (): ()| { Ok(this.is_nan()) }); - methods.add_method("transpose", + builder.method("transpose", |_, this, (): ()| { Ok(#wrapper_ident(this.0.transpose())) }); - methods.add_method("determinant", + builder.method("determinant", |_, this, (): ()| { Ok(this.determinant()) }); - methods.add_method("inverse", + builder.method("inverse", |_, this, (): ()| { Ok(#wrapper_ident(this.inverse())) }); - methods.add_method("abs_diff_eq", + builder.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", + /* builder.method("as_dmat", |_, this, (rhs, max_abs_diff): (#wrapper_ident, f32)| { Ok(D#wrapper_ident(this.as_dmat)) }); */ diff --git a/lyra-scripting/src/lua/wrappers/math.rs b/lyra-scripting/src/lua/wrappers/math.rs index 7030619..38cd41a 100644 --- a/lyra-scripting/src/lua/wrappers/math.rs +++ b/lyra-scripting/src/lua/wrappers/math.rs @@ -7,7 +7,7 @@ use lyra_scripting_derive::wrap_math_vec_copy; use crate as lyra_scripting; // f32 types -/* wrap_math_vec_copy!( +wrap_math_vec_copy!( math::Vec2, derives(PartialEq), fields(x, y), @@ -18,8 +18,21 @@ use crate as lyra_scripting; Mul(LuaVec2, f32), Mod(LuaVec2, f32), Eq, Unm, ToString - ) -); */ + ), + custom_methods { + builder.method_mut("move_by", |lua, this, vals: elua::ValueVec| { + let vals_clone = vals.clone(); + if let Some((x, y)) = vals.try_into_vals::<(f32, f32)>(lua)? { + this.x += x; + this.y += y; + } else if let Some(v) = vals_clone.try_into_vals::(lua)? { + this.0 += v.0; + } + + Ok(()) + }); + } +); wrap_math_vec_copy!( math::Vec3, derives(PartialEq), @@ -31,9 +44,36 @@ wrap_math_vec_copy!( Mul(LuaVec3, f32), Mod(LuaVec3, f32), Eq, Unm, ToString - ) + ), + custom_methods { + builder.method_mut("move_by", |lua, this, vals: elua::ValueVec| { + let vals_clone = vals.clone(); + if let Some((x, y, z)) = vals.try_into_vals::<(f32, f32, f32)>(lua)? { + this.x += x; + this.y += y; + this.z += z; + } else if let Some(v) = vals_clone.try_into_vals::(lua)? { + this.0 += v.0; + } + + Ok(()) + }); + } ); +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 + ) +); // ================================================= @@ -51,19 +91,7 @@ wrap_math_vec_copy!( 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!( @@ -328,30 +356,30 @@ wrap_math_vec_copy!( BXor(LuaU64Vec4, u64), Eq, BNot ) -); +);*/ // bool types -wrap_math_vec_copy!( +/* wrap_math_vec_copy!( math::BVec2, derives(PartialEq, Eq, Hash), fields(x, y), - metamethods(Eq, BAnd, BOr, BXor, BNot) + 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) + 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) -); + metamethods(Eq, BAnd, BOr, BXOr, BNot) +); */ // mat2 -wrap_math_vec_copy!( +/* wrap_math_vec_copy!( math::Mat2, derives(PartialEq), no_new, @@ -367,6 +395,7 @@ wrap_math_vec_copy!( ) ); */ +// TODO /* wrap_math_vec_copy!( math::Mat4, derives(PartialEq), @@ -392,8 +421,31 @@ wrap_math_vec_copy!( +/// A macro that generates field getters and setters for lua wrapped types. +macro_rules! wrapped_field_getsetters { + ($builder: ident, $name: literal, $field: ident, $type: ident) => { + $builder.field_getter($name, |_, this| { + Ok($type(this.$field)) + }); + $builder.field_setter($name, |_, this, v: $type| { + this.$field = *v; + Ok(()) + }); + }; +} - +/// A macro that generates field getters and setters for types that already implement As/FromLua. +macro_rules! field_getsetters { + ($builder: ident, $name: literal, $field: ident, $type: ty) => { + $builder.field_getter($name, |_, this| { + Ok(this.$field) + }); + $builder.field_setter($name, |_, this, v: $type| { + this.$field = v; + Ok(()) + }); + }; +} wrap_math_vec_copy!( @@ -403,12 +455,19 @@ wrap_math_vec_copy!( metamethods( Eq, // __mul for LuaVec3 is manually implemented below since it doesn't return Self - Mul(LuaQuat, f32), + //Mul(LuaQuat, f32), Add, Sub, Div(f32), ), + custom_fields { + field_getsetters!(builder, "x", x, f32); + field_getsetters!(builder, "y", y, f32); + field_getsetters!(builder, "z", z, f32); + field_getsetters!(builder, "w", w, f32); + }, custom_methods { + // manually implemented since Quat doesn't have a `new` function builder.function("new", |_, (x, y, z, w)| { Ok(Self(math::Quat::from_xyzw(x, y, z, w))) }); @@ -440,21 +499,44 @@ wrap_math_vec_copy!( Ok(this.length_squared()) }); - builder.method("normalize", |_, this, ()| { - Ok(Self(this.normalize())) + builder.method_mut("normalize", |_, this, ()| { + this.0 = this.normalize(); + Ok(()) }); - builder.method("mult_quat", |_, this, (rhs,): (Self,)| { - Ok(Self(this.0 * rhs.0)) + builder.method_mut("mult_quat", |_, this, (rhs,): (Self,)| { + this.0 *= rhs.0; + Ok(()) }); builder.method("mult_vec3", |_, this, (rhs,): (LuaVec3,)| { Ok(LuaVec3(this.0 * rhs.0)) }); - // manually implemented here since it doesn't return `Self` - builder.meta_method(elua::MetaMethod::Mul, |_, this, (rhs,): (LuaVec3,)| { - Ok(LuaVec3(this.0 * rhs.0)) + // manually implemented here since multiplying may not return `Self`. + builder.meta_method(elua::MetaMethod::Mul, |lua, this, (val,): (elua::Value,)| { + use elua::AsLua; + + match val { + elua::Value::Userdata(ud) => { + if ud.is::()? { + let v3 = ud.as_ref::()?; + LuaVec3(this.0 * v3.0) + .as_lua(lua) + } else { + let quat = ud.as_ref::()?; + LuaQuat(this.0 * quat.0) + .as_lua(lua) + } + }, + elua::Value::Number(n) => { + LuaQuat(this.0 * (n as f32)) + .as_lua(lua) + }, + _ => { + todo!() + } + } }); builder.method("lerp", |_, this, (rhs, alpha): (Self, f32)| { @@ -469,29 +551,9 @@ wrap_math_vec_copy!( no_new, metamethods(ToString, Eq), custom_fields { - builder.field_getter("translation", |_, this| { - Ok(LuaVec3(this.translation)) - }); - builder.field_setter("translation", |_, this, v: LuaVec3| { - this.translation = *v; - Ok(()) - }); - - builder.field_getter("rotation", |_, this| { - Ok(LuaQuat(this.rotation)) - }); - builder.field_setter("rotation", |_, this, v: LuaQuat| { - this.rotation = *v; - Ok(()) - }); - - builder.field_getter("scale", |_, this| { - Ok(LuaVec3(this.scale)) - }); - builder.field_setter("scale", |_, this, v: LuaVec3| { - this.scale = *v; - Ok(()) - }); + wrapped_field_getsetters!(builder, "translation", translation, LuaVec3); + wrapped_field_getsetters!(builder, "rotation", rotation, LuaQuat); + wrapped_field_getsetters!(builder, "scale", scale, LuaVec3); }, custom_methods { builder.function("default", |_, ()| {