1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00
luanti/src/script/lua_api/l_rotation.cpp
2025-05-10 20:38:44 +02:00

239 lines
4.9 KiB
C++

// Luanti
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2025 Lars Müller
#include "lua_api/l_rotation.h"
#include "common/c_packer.h"
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "irr_v3d.h"
#include "quaternion.h"
#include <cmath>
#include <cstring>
#include <lauxlib.h>
#include <lua.h>
core::quaternion &LuaRotation::check(lua_State *L, int index)
{
return static_cast<LuaRotation *>(luaL_checkudata(L, index, className))->quaternion;
}
void LuaRotation::create(lua_State *L, const core::quaternion &quaternion)
{
auto *rot = static_cast<LuaRotation *>(lua_newuserdata(L, sizeof(LuaRotation)));
rot->quaternion = quaternion;
luaL_getmetatable(L, LuaRotation::className);
lua_setmetatable(L, -2);
}
// Constructors
int LuaRotation::l_identity(lua_State *L)
{
create(L, core::quaternion());
return 1;
}
int LuaRotation::l_quaternion(lua_State *L)
{
// TODO be more strict.
f64 x = luaL_checknumber(L, 1);
f64 y = luaL_checknumber(L, 2);
f64 z = luaL_checknumber(L, 3);
f64 w = luaL_checknumber(L, 4);
// Note: Converted to f32
core::quaternion q(x, y, z, w);
q.normalize();
create(L, q);
return 1;
}
int LuaRotation::l_axis_angle(lua_State *L)
{
v3f axis = readParam<v3f>(L, 1);
f64 angle = luaL_checknumber(L, 2);
core::quaternion quaternion;
// Note: Axis converted to f32
axis.normalize();
quaternion.fromAngleAxis(angle, axis);
create(L, quaternion);
return 1;
}
template<float v3f::* C>
int LuaRotation::l_fixed_axis_angle(lua_State *L)
{
f64 angle = luaL_checknumber(L, 1);
// Note: Angle converted to f32
v3f axis;
axis.*C = 1.0f;
create(L, core::quaternion().fromAngleAxis(angle, axis));
return 1;
}
int LuaRotation::l_euler_angles(lua_State *L)
{
v3f euler = readParam<v3f>(L, 1);
core::quaternion quaternion;
// Note: Euler angles converted to f32
quaternion.set(euler.X, euler.Y, euler.Z);
create(L, quaternion);
return 1;
}
int LuaRotation::l_to_quaternion(lua_State *L)
{
const auto &q = check(L, 1);
lua_pushnumber(L, q.X);
lua_pushnumber(L, q.Y);
lua_pushnumber(L, q.Z);
lua_pushnumber(L, q.W);
return 4;
}
int LuaRotation::l_to_axis_angle(lua_State *L)
{
const auto q = check(L, 1);
core::vector3df axis;
f32 angle;
q.toAngleAxis(angle, axis);
push_v3f(L, axis);
lua_pushnumber(L, angle);
return 2;
}
int LuaRotation::l_to_euler_angles(lua_State *L)
{
const auto &q = check(L, 1);
core::vector3df euler;
q.toEuler(euler);
lua_pushnumber(L, euler.X);
lua_pushnumber(L, euler.Y);
lua_pushnumber(L, euler.Z);
return 3;
}
// Math
int LuaRotation::l_apply(lua_State *L)
{
const auto &q = check(L, 1);
v3f vec = readParam<v3f>(L, 2);
push_v3f(L, q * vec);
return 1;
}
int LuaRotation::l_compose(lua_State *L)
{
int n_args = lua_gettop(L);
if (n_args == 0)
return LuaRotation::l_identity(L);
auto product = check(L, 1);
for (int i = 2; i <= n_args; ++i) {
product *= check(L, i);
}
create(L, product);
return 1;
}
int LuaRotation::l_invert(lua_State *L)
{
create(L, check(L, 1).makeInverse());
return 1;
}
int LuaRotation::l_slerp(lua_State *L)
{
const auto &from = check(L, 1);
const auto &to = check(L, 2);
f32 time = readParam<Finite<f32>>(L, 3).value;
core::quaternion result;
result.slerp(from, to, time);
create(L, result);
return 1;
}
int LuaRotation::l_angle_to(lua_State *L)
{
const auto &from = check(L, 1);
const auto &to = check(L, 2);
f32 angle = from.angleTo(to);
lua_pushnumber(L, angle);
return 1;
}
// Serialization
int LuaRotation::mt_tostring(lua_State *L)
{
const auto &q = check(L, 1);
lua_pushfstring(L, "(%f\t%f\t%f\t%f)", q.X, q.Y, q.Z, q.W);
return 1;
}
void *LuaRotation::packIn(lua_State *L, int idx)
{
return new core::quaternion(check(L, idx));
}
void LuaRotation::packOut(lua_State *L, void *ptr)
{
auto *quat = static_cast<core::quaternion *>(ptr);
if (L)
create(L, *quat);
delete quat;
}
void LuaRotation::Register(lua_State *L)
{
static const luaL_Reg metamethods[] = {
{"__tostring", mt_tostring},
{0, 0}
};
registerClass<LuaRotation>(L, methods, metamethods);
lua_createtable(L, 0, 0);
int Matrix4 = lua_gettop(L);
#define SET_CONSTRUCTOR(name, method) \
lua_pushcfunction(L, method); \
lua_setfield(L, Matrix4, name); \
#define CONSTRUCTOR(name) SET_CONSTRUCTOR(#name, l_##name)
CONSTRUCTOR(identity)
CONSTRUCTOR(quaternion)
CONSTRUCTOR(axis_angle)
CONSTRUCTOR(euler_angles)
CONSTRUCTOR(compose)
#undef CONSTRUCTOR
SET_CONSTRUCTOR("x", l_fixed_axis_angle<&v3f::X>)
SET_CONSTRUCTOR("y", l_fixed_axis_angle<&v3f::Y>)
SET_CONSTRUCTOR("z", l_fixed_axis_angle<&v3f::Z>)
#undef SET_CONSTRUCTOR
lua_setglobal(L, className);
script_register_packer(L, className, packIn, packOut);
}
const char LuaRotation::className[] = "Rotation";
#define METHOD(name) luamethod(LuaRotation, name)
const luaL_Reg LuaRotation::methods[] = {
METHOD(to_quaternion),
METHOD(to_axis_angle),
METHOD(to_euler_angles),
METHOD(apply),
METHOD(compose),
METHOD(invert),
METHOD(slerp),
METHOD(angle_to),
{0,0}
};
#undef METHOD