scripting: Implement LuaVec3:move_by, and add more methods for Lua on math types

This commit is contained in:
SeanOMik 2024-02-19 23:14:38 -05:00
parent e6b4e83dee
commit e354528942
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
5 changed files with 170 additions and 78 deletions

View File

@ -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)

@ -1 +1 @@
Subproject commit d32c138e996ec2fe17b7a5f7c0d3ff1562e446f0
Subproject commit 22b6d218bdb6a5aafc0efd4fb80a67d2c796d0e7

View File

@ -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));

View File

@ -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))
}); */

View File

@ -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::<Self>(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::<Self>(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::<LuaVec3>()? {
let v3 = ud.as_ref::<LuaVec3>()?;
LuaVec3(this.0 * v3.0)
.as_lua(lua)
} else {
let quat = ud.as_ref::<LuaQuat>()?;
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", |_, ()| {