diff --git a/.gitignore b/.gitignore index 546259f..3f72f7d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,6 @@ Thumbs.db .project .cproject builtins +_codeql_detected_source_root /xmath/include/dmsdk/* diff --git a/xmath/api/xMath.script_api b/xmath/api/xMath.script_api index bb88954..1bef8af 100644 --- a/xmath/api/xMath.script_api +++ b/xmath/api/xMath.script_api @@ -347,3 +347,55 @@ type: matrix4 - name: position type: [vector3, vector4] + + - name: quat_matrix4 + type: function + desc: "Set the value of a quaternion from a matrix4." + parameters: + - name: q_in_place + type: quaternion + - name: m + type: matrix4 + + - name: matrix4_compose + type: function + desc: "Set the value of a matrix from translation, rotation and scale." + parameters: + - name: m_in_place + type: matrix4 + - name: translation + type: [vector3, vector4] + - name: rotation + type: quaternion + - name: scale + type: vector3 + + - name: matrix4_scale + type: function + desc: "Set the value of a matrix from scale. Can take a vector3, a single number for uniform scale, or 3 numbers for x, y, z scale." + parameters: + - name: m_in_place + type: matrix4 + - name: scale + type: [vector3, number] + + - name: clamp + type: function + desc: "Clamp input value in range [min, max]. For numbers, pass (value, min, max) and returns the clamped number. For vectors, pass (v_in_place, value, min, max) to modify v_in_place. min and max can be numbers or matching vector types." + parameters: + - name: value_or_out + type: [number, vector3, vector4] + desc: "For numbers, the value to clamp. For vectors, the output vector to store the result." + - name: value_or_min + type: [number, vector3, vector4] + desc: "For numbers, the minimum value. For vectors, the value to clamp." + - name: min_or_max + type: [number, vector3, vector4] + desc: "For numbers, the maximum value. For vectors, the minimum value." + - name: max + type: [number, vector3, vector4] + desc: "For vectors only, the maximum value." + returns: + - name: result + type: number + desc: "For number inputs, returns the clamped number. For vector inputs, modifies v_in_place and returns nothing." diff --git a/xmath/src/xMath.cpp b/xmath/src/xMath.cpp index 41bdbfc..dab3219 100644 --- a/xmath/src/xMath.cpp +++ b/xmath/src/xMath.cpp @@ -535,6 +535,182 @@ static int xMath_matrix_translation(lua_State* L) return 0; } +static int xMath_quat_matrix4(lua_State* L) +{ + if (dmScript::IsQuat(L, 1)) + { + Vectormath::Aos::Quat *out = dmScript::CheckQuat(L, 1); + Vectormath::Aos::Matrix4 *m = dmScript::CheckMatrix4(L, 2); + Vectormath::Aos::Matrix3 m3(m->getCol0().getXYZ(), m->getCol1().getXYZ(), m->getCol2().getXYZ()); + *out = Vectormath::Aos::Quat(m3); + } + + return 0; +} + +static int xMath_matrix4_compose(lua_State* L) +{ + if (dmScript::IsMatrix4(L, 1)) + { + Vectormath::Aos::Matrix4 *out = dmScript::CheckMatrix4(L, 1); + Vectormath::Aos::Vector3 translation(0, 0, 0); + if (dmScript::IsVector3(L, 2)) + { + translation = *dmScript::CheckVector3(L, 2); + } + else if (dmScript::IsVector4(L, 2)) + { + translation = dmScript::CheckVector4(L, 2)->getXYZ(); + } + Vectormath::Aos::Quat *rotation = dmScript::CheckQuat(L, 3); + Vectormath::Aos::Vector3 *scale = dmScript::CheckVector3(L, 4); + + Vectormath::Aos::Matrix3 rotationMatrix = Vectormath::Aos::Matrix3(*rotation); + Vectormath::Aos::Matrix3 scaleMatrix = Vectormath::Aos::Matrix3::scale(*scale); + Vectormath::Aos::Matrix3 rs = rotationMatrix * scaleMatrix; + + *out = Vectormath::Aos::Matrix4(rs, translation); + } + + return 0; +} + +static int xMath_matrix4_scale(lua_State* L) +{ + if (dmScript::IsMatrix4(L, 1)) + { + Vectormath::Aos::Matrix4 *out = dmScript::CheckMatrix4(L, 1); + int nargs = lua_gettop(L); + + if (nargs == 2) + { + if (dmScript::IsVector3(L, 2)) + { + Vectormath::Aos::Vector3 *scale = dmScript::CheckVector3(L, 2); + *out = Vectormath::Aos::Matrix4::scale(*scale); + } + else if (lua_isnumber(L, 2)) + { + float s = (float) luaL_checknumber(L, 2); + *out = Vectormath::Aos::Matrix4::scale(Vectormath::Aos::Vector3(s, s, s)); + } + } + else if (nargs == 4) + { + float x = (float) luaL_checknumber(L, 2); + float y = (float) luaL_checknumber(L, 3); + float z = (float) luaL_checknumber(L, 4); + *out = Vectormath::Aos::Matrix4::scale(Vectormath::Aos::Vector3(x, y, z)); + } + } + + return 0; +} + +static inline float clamp_value(float value, float min_val, float max_val) +{ + if (value < min_val) return min_val; + if (value > max_val) return max_val; + return value; +} + +static int xMath_clamp(lua_State* L) +{ + int nargs = lua_gettop(L); + + if (nargs >= 3 && lua_isnumber(L, 1)) + { + // clamp(value, min, max) for numbers - returns clamped number + float value = (float) luaL_checknumber(L, 1); + float min_val = (float) luaL_checknumber(L, 2); + float max_val = (float) luaL_checknumber(L, 3); + lua_pushnumber(L, clamp_value(value, min_val, max_val)); + return 1; + } + else if (dmScript::IsVector3(L, 1)) + { + // clamp(out, value, min, max) for vectors - modifies out in place + Vectormath::Aos::Vector3 *out = dmScript::CheckVector3(L, 1); + Vectormath::Aos::Vector3 *value = dmScript::CheckVector3(L, 2); + + float min_x, min_y, min_z; + float max_x, max_y, max_z; + + if (dmScript::IsVector3(L, 3)) + { + Vectormath::Aos::Vector3 *min_v = dmScript::CheckVector3(L, 3); + min_x = min_v->getX(); + min_y = min_v->getY(); + min_z = min_v->getZ(); + } + else + { + float min_val = (float) luaL_checknumber(L, 3); + min_x = min_y = min_z = min_val; + } + + if (dmScript::IsVector3(L, 4)) + { + Vectormath::Aos::Vector3 *max_v = dmScript::CheckVector3(L, 4); + max_x = max_v->getX(); + max_y = max_v->getY(); + max_z = max_v->getZ(); + } + else + { + float max_val = (float) luaL_checknumber(L, 4); + max_x = max_y = max_z = max_val; + } + + out->setX(clamp_value(value->getX(), min_x, max_x)); + out->setY(clamp_value(value->getY(), min_y, max_y)); + out->setZ(clamp_value(value->getZ(), min_z, max_z)); + } + else if (dmScript::IsVector4(L, 1)) + { + Vectormath::Aos::Vector4 *out = dmScript::CheckVector4(L, 1); + Vectormath::Aos::Vector4 *value = dmScript::CheckVector4(L, 2); + + float min_x, min_y, min_z, min_w; + float max_x, max_y, max_z, max_w; + + if (dmScript::IsVector4(L, 3)) + { + Vectormath::Aos::Vector4 *min_v = dmScript::CheckVector4(L, 3); + min_x = min_v->getX(); + min_y = min_v->getY(); + min_z = min_v->getZ(); + min_w = min_v->getW(); + } + else + { + float min_val = (float) luaL_checknumber(L, 3); + min_x = min_y = min_z = min_w = min_val; + } + + if (dmScript::IsVector4(L, 4)) + { + Vectormath::Aos::Vector4 *max_v = dmScript::CheckVector4(L, 4); + max_x = max_v->getX(); + max_y = max_v->getY(); + max_z = max_v->getZ(); + max_w = max_v->getW(); + } + else + { + float max_val = (float) luaL_checknumber(L, 4); + max_x = max_y = max_z = max_w = max_val; + } + + out->setX(clamp_value(value->getX(), min_x, max_x)); + out->setY(clamp_value(value->getY(), min_y, max_y)); + out->setZ(clamp_value(value->getZ(), min_z, max_z)); + out->setW(clamp_value(value->getW(), min_w, max_w)); + } + + return 0; +} + //* Native Extension Bindings //* ---------------------------------------------------------------------------- @@ -561,6 +737,7 @@ static const luaL_reg xMathModule_methods[] = {"quat_rotation_y", xMath_quat_rotation_y}, {"quat_rotation_z", xMath_quat_rotation_z}, {"quat", xMath_quat}, + {"quat_matrix4", xMath_quat_matrix4}, //* Vector + Quat {"lerp", xMath_lerp}, {"slerp", xMath_slerp}, @@ -578,6 +755,10 @@ static const luaL_reg xMathModule_methods[] = {"matrix_rotation_y", xMath_matrix_rotation_y}, {"matrix_rotation_z", xMath_matrix_rotation_z}, {"matrix_translation", xMath_matrix_translation}, + {"matrix4_compose", xMath_matrix4_compose}, + {"matrix4_scale", xMath_matrix4_scale}, + //* Utility + {"clamp", xMath_clamp}, {0, 0} };