implement luanti and irrlicht transformations

This commit is contained in:
FatalErr42O 2024-11-30 21:02:40 -08:00
parent 5eba698c90
commit 2c7a244aa2
20 changed files with 1045 additions and 226 deletions

View File

@ -130,7 +130,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -662,7 +662,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -662,7 +662,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -77,7 +77,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -730,7 +730,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -118,7 +118,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -77,7 +77,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -89,6 +89,10 @@
<td class="summary">Create a matrix from a quaternion.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_rot_from_quaternion">set_rot_from_quaternion (q)</a></td>
<td class="summary">set the rotation of a matrix from a quaternion.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#from_direction">from_direction (direction, up)</a></td>
<td class="summary">Create a matrix from a direction/up pair.</td>
</tr>
@ -97,6 +101,38 @@
<td class="summary">Create a matrix from a transform.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_rot_zxy">set_rot_zxy (pitch, yaw, roll)</a></td>
<td class="summary">set the rotation of a given matrix in euler in the ZXY application order.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_rot_luanti_entity">set_rot_luanti_entity (pitch, yaw, roll)</a></td>
<td class="summary">alias of <code>set_rot_zxy</code>.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_rot_zxy">get_rot_zxy (the)</a></td>
<td class="summary">get the ZXY euler rotation of the given matrix.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_rot_luanti_entity">get_rot_luanti_entity (the)</a></td>
<td class="summary">Alias of <code>get_rot_zxy</code>.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_rot_xyz">set_rot_xyz (pitch, yaw, roll)</a></td>
<td class="summary">set the rotation of a given matrix in euler in the XYZ application order.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_rot_irrlicht_bone">set_rot_irrlicht_bone (pitch, yaw, roll)</a></td>
<td class="summary">alias of <code>set_rot_xyz</code>.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_rot_xyz">get_rot_xyz (the)</a></td>
<td class="summary">Get the XYZ euler rotation of the given matrix.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_rot_irrlicht_bone">get_rot_irrlicht_bone (the)</a></td>
<td class="summary">Alias of <code>get_rot_zxy</code>.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#from_ortho">from_ortho (left, right, top, bottom, near, far)</a></td>
<td class="summary">Create matrix from orthogonal.</td>
</tr>
@ -307,6 +343,29 @@
</dd>
<dt>
<a name = "set_rot_from_quaternion"></a>
<strong>set_rot_from_quaternion (q)</strong>
</dt>
<dd>
set the rotation of a matrix from a quaternion. Not sure at all where i got this code from, but it works...
i refactored so it works with https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.html
I think I got it from https://github.com/minetest/irrlicht/blob/7173c2c62997b6416f17b90f9a50bff11fef1c4c/include/quaternion.h#L367
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">q</span>
<span class="types"><span class="type">quat</span></span>
rotation quaternion. only supports normal quaternion rotation (will normalize)
</li>
</ul>
</dd>
<dt>
<a name = "from_direction"></a>
@ -373,6 +432,286 @@
</dd>
<dt>
<a name = "set_rot_zxy"></a>
<strong>set_rot_zxy (pitch, yaw, roll)</strong>
</dt>
<dd>
set the rotation of a given matrix in euler in the ZXY application order. This is the order that minetest entities are rotated in.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">pitch</span>
<span class="types"><span class="type">float</span></span>
the clockwise pitch in radians
</li>
<li><span class="parameter">yaw</span>
<span class="types"><span class="type">float</span></span>
the clockwise yaw in radians
</li>
<li><span class="parameter">roll</span>
<span class="types"><span class="type">float</span></span>
the clockwise yaw in roll
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">matrix</span></span>
</ol>
</dd>
<dt>
<a name = "set_rot_luanti_entity"></a>
<strong>set_rot_luanti_entity (pitch, yaw, roll)</strong>
</dt>
<dd>
alias of <code>set_rot_zxy</code>. Sets the rotation of a given matrix in euler in the ZXY application order. This is the order that minetest entities are rotated in.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">pitch</span>
<span class="types"><span class="type">float</span></span>
the clockwise pitch in radians
</li>
<li><span class="parameter">yaw</span>
<span class="types"><span class="type">float</span></span>
the clockwise yaw in radians
</li>
<li><span class="parameter">roll</span>
<span class="types"><span class="type">float</span></span>
the clockwise yaw in roll
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">matrix</span></span>
</ol>
</dd>
<dt>
<a name = "get_rot_zxy"></a>
<strong>get_rot_zxy (the)</strong>
</dt>
<dd>
get the ZXY euler rotation of the given matrix. This is the order that minetest entities are rotated in.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">the</span>
<span class="types"><span class="type">matrix</span></span>
matrix to get the rotation of
</li>
</ul>
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">float</span></span>
pitch</li>
<li>
<span class="types"><span class="type">float</span></span>
yaw</li>
<li>
<span class="types"><span class="type">float</span></span>
roll</li>
</ol>
</dd>
<dt>
<a name = "get_rot_luanti_entity"></a>
<strong>get_rot_luanti_entity (the)</strong>
</dt>
<dd>
Alias of <code>get_rot_zxy</code>. Gets the ZXY euler rotation of the given matrix. This is the order that minetest entities are rotated in.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">the</span>
<span class="types"><span class="type">matrix</span></span>
matrix to get the rotation of
</li>
</ul>
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">float</span></span>
pitch</li>
<li>
<span class="types"><span class="type">float</span></span>
yaw</li>
<li>
<span class="types"><span class="type">float</span></span>
roll</li>
</ol>
</dd>
<dt>
<a name = "set_rot_xyz"></a>
<strong>set_rot_xyz (pitch, yaw, roll)</strong>
</dt>
<dd>
set the rotation of a given matrix in euler in the XYZ application order. This is the rotation order irrlicht uses (i.e. for bones in Luanti)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">pitch</span>
<span class="types"><span class="type">float</span></span>
the clockwise pitch in radians
</li>
<li><span class="parameter">yaw</span>
<span class="types"><span class="type">float</span></span>
the clockwise yaw in radians
</li>
<li><span class="parameter">roll</span>
<span class="types"><span class="type">float</span></span>
the clockwise yaw in roll
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">matrix</span></span>
</ol>
</dd>
<dt>
<a name = "set_rot_irrlicht_bone"></a>
<strong>set_rot_irrlicht_bone (pitch, yaw, roll)</strong>
</dt>
<dd>
alias of <code>set_rot_xyz</code>. Sets the rotation of a given matrix in euler in the XYZ application order. This is the rotation order irrlicht uses (i.e. for bones in Luanti)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">pitch</span>
<span class="types"><span class="type">float</span></span>
the clockwise pitch in radians
</li>
<li><span class="parameter">yaw</span>
<span class="types"><span class="type">float</span></span>
the clockwise yaw in radians
</li>
<li><span class="parameter">roll</span>
<span class="types"><span class="type">float</span></span>
the clockwise yaw in roll
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">matrix</span></span>
</ol>
</dd>
<dt>
<a name = "get_rot_xyz"></a>
<strong>get_rot_xyz (the)</strong>
</dt>
<dd>
Get the XYZ euler rotation of the given matrix. This is the rotation order irrlicht uses (i.e. for bones in Luanti)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">the</span>
<span class="types"><span class="type">matrix</span></span>
matrix to get the rotation of
</li>
</ul>
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">float</span></span>
pitch</li>
<li>
<span class="types"><span class="type">float</span></span>
yaw</li>
<li>
<span class="types"><span class="type">float</span></span>
roll</li>
</ol>
</dd>
<dt>
<a name = "get_rot_irrlicht_bone"></a>
<strong>get_rot_irrlicht_bone (the)</strong>
</dt>
<dd>
Alias of <code>get_rot_zxy</code>. Gets the XYZ euler rotation of the given matrix. This is the rotation order irrlicht uses (i.e. for bones in Luanti).
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">the</span>
<span class="types"><span class="type">matrix</span></span>
matrix to get the rotation of
</li>
</ul>
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">float</span></span>
pitch</li>
<li>
<span class="types"><span class="type">float</span></span>
yaw</li>
<li>
<span class="types"><span class="type">float</span></span>
roll</li>
</ol>
</dd>
<dt>
<a name = "from_ortho"></a>
@ -1166,7 +1505,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -77,7 +77,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -703,7 +703,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -98,11 +98,7 @@
<td class="summary">Subtract a quaternion from another.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#mul">mul (a, b)</a></td>
<td class="summary">Multiply two quaternions.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#mul_vec3">mul_vec3 (a, b)</a></td>
<td class="name" nowrap><a href="#mul_vec3">mul_vec3 (a, v)</a></td>
<td class="summary">Multiply a quaternion and a vec3.</td>
</tr>
<tr>
@ -131,7 +127,7 @@
</tr>
<tr>
<td class="name" nowrap><a href="#rotate">rotate (angle, axis, y, z)</a></td>
<td class="summary">Alias of from<em>angle</em>axis.</td>
<td class="summary">Alias of <code>from_angle_axis.</code></td>
</tr>
<tr>
<td class="name" nowrap><a href="#conjugate">conjugate (a)</a></td>
@ -186,12 +182,40 @@
<td class="summary">Convert a quaternion into an angle/axis pair.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#to_euler_angles_unpack">to_euler_angles_unpack (a)</a></td>
<td class="summary">Convert a quaternion into euler angle components</td>
<td class="name" nowrap><a href="#set_matrix_rot">set_matrix_rot (quaternion, the)</a></td>
<td class="summary">set a matrix's rotation fields from a quaternion.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#to_euler_angles">to_euler_angles (a)</a></td>
<td class="summary">Convert a quaternion into euler angles</td>
<td class="name" nowrap><a href="#from_matrix">from_matrix (the)</a></td>
<td class="summary">create a new quaternion from a matrix.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_rot_luanti_entity">get_rot_luanti_entity ()</a></td>
<td class="summary">alias of <code>get_euler_zxy</code></td>
</tr>
<tr>
<td class="name" nowrap><a href="#from_euler_zxy">from_euler_zxy (X, Y, Z)</a></td>
<td class="summary">create a quaternion from euler angles in the ZXY rotation order.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_rot_luanti_entity">get_rot_luanti_entity ()</a></td>
<td class="summary">alias of <code>from_euler_zxy</code></td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_euler_xyz">get_euler_xyz (quaternion)</a></td>
<td class="summary">convert a quaternion to an xyz euler angles.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_rot_irrlicht_bone">get_rot_irrlicht_bone ()</a></td>
<td class="summary">alias of <code>get_euler_xyz</code></td>
</tr>
<tr>
<td class="name" nowrap><a href="#from_euler_xyz">from_euler_xyz (X, Y, Z)</a></td>
<td class="summary">create a quaternion from euler angles in the xyz rotation order.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_rot_irrlicht_bone">get_rot_irrlicht_bone ()</a></td>
<td class="summary">alias of <code>quat.from_euler_zxy</code></td>
</tr>
<tr>
<td class="name" nowrap><a href="#to_vec3">to_vec3 (a)</a></td>
@ -298,7 +322,7 @@
<strong>from_direction (normal, up)</strong>
</dt>
<dd>
Create a quaternion from a normal/up vector pair.
Create a quaternion from a normal/up vector pair. (accepts minetest vectors)
<h3>Parameters:</h3>
@ -414,44 +438,13 @@
</dd>
<dt>
<a name = "mul"></a>
<strong>mul (a, b)</strong>
</dt>
<dd>
Multiply two quaternions.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">a</span>
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
Left hand operand
</li>
<li><span class="parameter">b</span>
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
Right hand operand
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
quaternion equivalent to "apply b, then a"
</ol>
</dd>
<dt>
<a name = "mul_vec3"></a>
<strong>mul_vec3 (a, b)</strong>
<strong>mul_vec3 (a, v)</strong>
</dt>
<dd>
Multiply a quaternion and a vec3.
Multiply a quaternion and a vec3. Equivalent to rotating the vector (a) by the quaternion (v)
<h3>Parameters:</h3>
@ -460,7 +453,7 @@
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
Left hand operand
</li>
<li><span class="parameter">b</span>
<li><span class="parameter">v</span>
<span class="types"><span class="type">vec3</span></span>
Right hand operand
</li>
@ -656,7 +649,7 @@
<strong>rotate (angle, axis, y, z)</strong>
</dt>
<dd>
Alias of from<em>angle</em>axis.
Alias of <code>from_angle_axis.</code>
<h3>Parameters:</h3>
@ -1084,36 +1077,32 @@
</dd>
<dt>
<a name = "to_euler_angles_unpack"></a>
<strong>to_euler_angles_unpack (a)</strong>
<a name = "set_matrix_rot"></a>
<strong>set_matrix_rot (quaternion, the)</strong>
</dt>
<dd>
Convert a quaternion into euler angle components
set a matrix's rotation fields from a quaternion. Uses mat4.set<em>rot</em>from_quaternion
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">a</span>
<li><span class="parameter">quaternion</span>
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
Quaternion to convert
to convert
</li>
<li><span class="parameter">the</span>
<span class="types"><span class="type">mat4</span></span>
mat4 to apply to.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">roll</span></span>
<span class="types"><span class="type">mat4</span></span>
</li>
<li>
<span class="types"><span class="type">pitch</span></span>
</li>
<li>
<span class="types"><span class="type">yaw</span></span>
no idea if this shit really works, very well could not...</li>
</ol>
@ -1121,31 +1110,210 @@
</dd>
<dt>
<a name = "to_euler_angles"></a>
<strong>to_euler_angles (a)</strong>
<a name = "from_matrix"></a>
<strong>from_matrix (the)</strong>
</dt>
<dd>
Convert a quaternion into euler angles
create a new quaternion from a matrix. Uses mat4.to_quaternion
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">a</span>
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
Quaternion to convert
<li><span class="parameter">the</span>
<span class="types"><span class="type">mat4</span></span>
matrix to use
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">result</span></span>
a {roll, pitch, yaw} table
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
</ol>
</dd>
<dt>
<a name = "get_rot_luanti_entity"></a>
<strong>get_rot_luanti_entity ()</strong>
</dt>
<dd>
alias of <code>get_euler_zxy</code>
</dd>
<dt>
<a name = "from_euler_zxy"></a>
<strong>from_euler_zxy (X, Y, Z)</strong>
</dt>
<dd>
create a quaternion from euler angles in the ZXY rotation order. This is the rotation order Luanti Entities use
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">X</span>
<span class="types"><span class="type">float</span></span>
</li>
<li><span class="parameter">Y</span>
<span class="types"><span class="type">float</span></span>
</li>
<li><span class="parameter">Z</span>
<span class="types"><span class="type">float</span></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
q
</ol>
</dd>
<dt>
<a name = "get_rot_luanti_entity"></a>
<strong>get_rot_luanti_entity ()</strong>
</dt>
<dd>
alias of <code>from_euler_zxy</code>
</dd>
<dt>
<a name = "get_euler_xyz"></a>
<strong>get_euler_xyz (quaternion)</strong>
</dt>
<dd>
convert a quaternion to an xyz euler angles. This is the rotation order used by irrlicht bones.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">quaternion</span>
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
to convert
</li>
</ul>
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">X</span></span>
</li>
<li>
<span class="types"><span class="type">Y</span></span>
</li>
<li>
<span class="types"><span class="type">Z</span></span>
</li>
</ol>
</dd>
<dt>
<a name = "get_rot_irrlicht_bone"></a>
<strong>get_rot_irrlicht_bone ()</strong>
</dt>
<dd>
alias of <code>get_euler_xyz</code>
</dd>
<dt>
<a name = "from_euler_xyz"></a>
<strong>from_euler_xyz (X, Y, Z)</strong>
</dt>
<dd>
create a quaternion from euler angles in the xyz rotation order. This is the rotation order irrlicht bones use
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">X</span>
<span class="types"><span class="type">float</span></span>
</li>
<li><span class="parameter">Y</span>
<span class="types"><span class="type">float</span></span>
</li>
<li><span class="parameter">Z</span>
<span class="types"><span class="type">float</span></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../modules/quat.html#quat">quat</a></span>
q
</ol>
</dd>
<dt>
<a name = "get_rot_irrlicht_bone"></a>
<strong>get_rot_irrlicht_bone ()</strong>
</dt>
<dd>
alias of <code>quat.from_euler_zxy</code>
</dd>
<dt>
<a name = "to_vec3"></a>
@ -1235,7 +1403,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -77,7 +77,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -550,7 +550,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -1117,7 +1117,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -1025,7 +1025,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@ -61,7 +61,7 @@
<h1>Cirno's Perfect Math Library</h1>
<h3>Adapated for Minetest</h3>
<h3>Adapted for Minetest</h3>
<p>For best memory performance: have luaJIT &amp; it's FFI library (this should be built into luaJIT), and add MTUL-CPML to your trusted list (so it can <code>require()</code> call the FFI library).</p>
<p>Various useful bits of game math. 3D line intersections, ray casting, 2d/3d vectors, 4x4 matrices, quaternions, etc.</p>
@ -80,7 +80,7 @@ Documentation can be found here: <a href="https://minetest-unification-library.g
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/lunarmodules/ldoc">LDoc 1.5.0</a></i>
<i style="float:right;">Last updated 2024-01-06 19:06:14 </i>
<i style="float:right;">Last updated 2024-11-30 20:09:10 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

111
init.lua
View File

@ -56,75 +56,82 @@ local files = {
"bound3",
}
--you will now witness the lua equivelant of a schizo rant. Have fun with this bullshit.
--initialize some variables
mtul = mtul or {
loaded_modules = {}
}
mtul.math = mtul.math or {} --other modules (probably) have not initialized this.
mtul.math = mtul.math or {}
mtul.loaded_modules.cpml = true
local modpath = minetest.get_modpath("mtul_cpml")
local loaded_modules = {}
local old_require = require --just in case require is present (aka it's an insecure environment)
local ie = minetest.request_insecure_environment()
--if require isn't present, allow us to load the modules through hackish means
--there's like 100s of require calls, it'd be insane to replace them. If you're farmiliar with require, the goal should be obvious.
modules = "" --this is just for Busted support, as it'll bitch about "attempt to concat a nil value" otherwise.
--modules is the path to modules
local old_package_path
if not ie then
--if an insecure environment cannot be loaded, then we basically change how require works temporarily, so modules (which is referenced in all CPML files on require() has to be changed)
modules = modpath.."/modules/"
else
old_package_path = package.path
--get the real modpath and add it to the package.path string so we can find our modules in require()
ie.package.path = ie.package.path .. ";"..string.gsub(modpath, "\\bin\\%.%.", "").."?.lua" --add our path
modules = ".modules."
end
local modpath
--check that it's minetest and not a lua script running it. If it's not minetest we dont have to do all of this, but otherwise we dont know if
if minetest or (core and core.register_globalstep) then
modpath = minetest.get_modpath("mtul_cpml")
local ie = minetest.request_insecure_environment()
if not ie then
function require(path)
if loaded_modules[path] then return loaded_modules[path] end
local ending = string.gsub(path:sub(#modules+1), "%.", "/")..".lua"
--[[if ending[1] ~= "/" then
ending = "/"..ending
end]]
path = modules..ending
loaded_modules[path] = dofile(path)
return loaded_modules[path]
end
else
require = ie.require
end
--print(require, ie.require)
if type(jit) == "table" and jit.status() then
if ie then
if pcall(require, "ffi") then
minetest.log("verbose", "MTUL-CPML: loaded JIT FFI library. Memory efficiency with FFI enabled.")
print("mtul-cpml: JIT FFI loaded successfully.")
--since we can't use require, what we do instead is override require by some utterly offensive means.
modules = "" --path to modules.
if not ie then
--if an insecure environment cannot be loaded, then we basically change how require works temporarily, so modules (which is referenced in all CPML files on require() has to be changed)
modules = modpath.."/modules/"
function require(path)
local ending = string.gsub(path:sub(#modules+1), "%.", "/")..".lua"
path = modules..ending
return dofile(path)
end
else
minetest.log("error", "MTUL-CPML: Failure to load JIT FFI library.")
old_package_path = package.path
--get the real modpath and add it to the package.path string so we can find our modules in require()
ie.package.path = ie.package.path .. ";"..string.gsub(modpath, "\\bin\\%.%.", "").."?.lua" --add our path
modules = ".modules."
require = ie.require
end
else
minetest.log("error", "MTUL-CPML: insecure environment denied for MTUL-CPML. Add mtul-cpml to your trusted mods for JIT FFI support (memory efficiency & speed boost)")
end
else
minetest.log("verbose", "MTUL-CPML: JIT not present, skipped attempt to load JIT FFI library for acceleration and memory efficiency")
end
--load the files
if type(jit) == "table" and jit.status() then
if ie then
if pcall(require, "ffi") then
minetest.log("verbose", "MTUL-CPML: loaded JIT FFI library. Memory efficiency with FFI enabled.")
print("mtul-cpml: JIT FFI loaded successfully.")
else
minetest.log("error", "MTUL-CPML: Failure to load JIT FFI library.")
end
else
minetest.log("error", "MTUL-CPML: insecure environment denied for MTUL-CPML. Add mtul-cpml to your trusted mods for better performance")
end
else
minetest.log("verbose", "MTUL-CPML: JIT not present, skipped attempt to load JIT FFI library for acceleration and memory efficiency")
end
end
--load the files
for _, file in ipairs(files) do
mtul.math[file] = require(modules .. file)
end
--unset all the global shit we had to change for CPML to work properly.
if old_package_path then
ie.package.path = old_package_path
if modpath then
if ie then
ie.package.path = old_package_path
end
modules = nil
require = old_require
end
modules = nil
require = old_require
--dofile(modpath.."/unit_tests/quat_unit_test.lua")
if modpath then
print("MTUL CPML: BEGINNING UNIT TESTING FOR COMPLEX TYPES")
dofile(modpath.."/unit_tests/irrlicht_luanti_tests.lua")
dofile(modpath.."/unit_tests/matrix_unit_test.lua")
dofile(modpath.."/unit_tests/quat_unit_test.lua")
else
print("MTUL CPML: BEGINNING UNIT TESTING FOR COMPLEX TYPES")
require("/unit_tests/irrlicht_luanti_tests.lua")
require("/unit_tests/matrix_unit_test.lua")
require("/unit_tests/quat_unit_test.lua")
end

View File

@ -1,3 +1 @@
# literally just so I dont have to open powershell every time.
@echo off
ldoc .

View File

@ -3,10 +3,11 @@
local constants = require(modules .. "constants")
local vec2 = require(modules .. "vec2")
local vec3 = require(modules .. "vec3")
local quat = require(modules .. "quat")
--local quat = require(modules .. "quat")
local utils = require(modules .. "utils")
local precond = require(modules .. "_private_precond")
local private = require(modules .. "_private_utils")
local DBL_EPSILON = constants.DBL_EPSILON
local sqrt = math.sqrt
local cos = math.cos
local sin = math.sin
@ -58,7 +59,8 @@ local tv4 = { 0, 0, 0, 0 }
-- table Length 4 (4 vec4s)
-- nil
-- @treturn mat4 out
function mat4.new(a)
function mat4.new(a, ...)
local out = new()
-- 4x4 matrix
@ -128,7 +130,33 @@ end
-- @tparam quat q Rotation quaternion
-- @treturn mat4 out
function mat4.from_quaternion(q)
return mat4.from_angle_axis(q:to_angle_axis())
--q=q:normalize()
return mat4.set_rot_from_quaternion(identity(new()), q)
end
--- set the rotation of a matrix from a quaternion. Not sure at all where i got this code from, but it works...
-- i refactored so it works with https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.html
-- I think I got it from https://github.com/minetest/irrlicht/blob/7173c2c62997b6416f17b90f9a50bff11fef1c4c/include/quaternion.h#L367
-- @tparam quat q rotation quaternion. only supports normal quaternion rotation (will normalize)
function mat4.set_rot_from_quaternion(m, q)
local qx,qy,qz,qw = q.x,q.y,q.z,q.w
--normalize the quaternion
--local s = 1/sqrt(qx * qx + qy * qy + qz * qz + qw * qw)
local s = 1/sqrt(qx * qx + qz * qz + qy * qy + qw * qw)
qx,qy,qz,qw = qx*s,qy*s,qz*s,qw*s
m[1] = 1-2*(qy^2 + qz^2)
m[2] = 2*(qx*qy + qz*qw)
m[3] = 2*(qx*qz - qy*qw)
m[5] = 2*(qx*qy - qz*qw)
m[6] = 1-2*(qx^2 + qz^2)
m[7] = 2*(qy*qz + qx*qw)
m[9] = 2*(qx*qz + qy*qw)
m[10]= 2*(qy*qz - qx*qw)
m[11]= 1-2*(qx^2 + qy^2)
return m
end
--- Create a matrix from a direction/up pair.
@ -186,6 +214,151 @@ function mat4.from_transform(trans, rot, scale)
return rsm
end
local tau = 2*math.pi
local atan2 = math.atan2
--- set the rotation of a given matrix in euler in the ZXY application order. This is the order that minetest entities are rotated in.
-- @tparam float pitch the clockwise pitch in radians
-- @tparam float yaw the clockwise yaw in radians
-- @tparam float roll the clockwise yaw in roll
-- @treturn matrix
function mat4.set_rot_zxy(M, pitch,yaw,roll)
--minetest numeric.h
local cr = cos(roll)
local sr = sin(roll)
local cp = cos(pitch)
local sp = sin(pitch);
local cy = cos(yaw)
local sy = sin(yaw);
M[1] = sr * sp * sy + cr * cy
M[2] = sr * cp
M[3] = sr * sp * cy - cr * sy
M[5] = cr * sp * sy - sr * cy
M[6] = cr * cp
M[7] = cr * sp * cy + sr * sy
M[9] = cp * sy
M[10] = -sp
M[11] = cp * cy
return M
end
local asin = math.asin
local abs = math.abs
--- alias of `set_rot_zxy`. Sets the rotation of a given matrix in euler in the ZXY application order. This is the order that minetest entities are rotated in.
-- @tparam float pitch the clockwise pitch in radians
-- @tparam float yaw the clockwise yaw in radians
-- @tparam float roll the clockwise yaw in roll
-- @treturn matrix
-- @function set_rot_luanti_entity
mat4.set_rot_luanti_entity = mat4.set_rot_zxy
--- get the ZXY euler rotation of the given matrix. This is the order that minetest entities are rotated in.
-- @tparam matrix the matrix to get the rotation of
-- @treturn float pitch
-- @treturn float yaw
-- @treturn float roll
function mat4.get_rot_zxy(M)
local X,Y,Z
if abs(M[10])-1 < DBL_EPSILON then --check if x is 90 or -90. If it is yaw will experience gimbal lock and there will therefore be infinite solutions.
Z = atan2(M[2], M[6]) --(cz*cx / sz*cx) = cz/cx = tz.
Y = atan2(M[9], M[11])
X = atan2(-M[10], M[6]/cos(Z))
else
Z = atan2(M[7], M[5])
Y = 0 --pitch and roll are the same given x=90 or -90.
X = asin(-M[10])
end
return X,Y,Z
end
--- Alias of `get_rot_zxy`. Gets the ZXY euler rotation of the given matrix. This is the order that minetest entities are rotated in.
-- @tparam matrix the matrix to get the rotation of
-- @treturn float pitch
-- @treturn float yaw
-- @treturn float roll
-- @function get_rot_luanti_entity
mat4.get_rot_luanti_entity = mat4.get_rot_zxy
--- set the rotation of a given matrix in euler in the XYZ application order. This is the rotation order irrlicht uses (i.e. for bones in Luanti)
-- @tparam float pitch the clockwise pitch in radians
-- @tparam float yaw the clockwise yaw in radians
-- @tparam float roll the clockwise yaw in roll
-- @treturn matrix
function mat4.set_rot_xyz(M, pitch,yaw,roll)
--standard euler rotation matrices applied in XYZ order (matrix transformations are applied in inverse)
local cp = cos(pitch)
local sp = sin(pitch)
local cy = cos(yaw)
local sy = sin(yaw)
local cr = cos(roll)
local sr = sin(roll)
M[1] = (cy * cr)
M[2] = (cy * sr)
M[3] = (-sy)
M[5] = (sp * sy * cr - cp * sr)
M[6] = (sp * sy * sr + cp * cr)
M[7] = (sp * cy)
M[9] = (cp * sy * cr + sp * sr)
M[10] = (cp * sy * sr - sp * cr)
M[11] = (cp * cy)
return M
end
--- alias of `set_rot_xyz`. Sets the rotation of a given matrix in euler in the XYZ application order. This is the rotation order irrlicht uses (i.e. for bones in Luanti)
-- @tparam float pitch the clockwise pitch in radians
-- @tparam float yaw the clockwise yaw in radians
-- @tparam float roll the clockwise yaw in roll
-- @treturn matrix
-- @function set_rot_irrlicht_bone
mat4.set_rot_irrlicht_bone = mat4.set_rot_xyz
--- Get the XYZ euler rotation of the given matrix. This is the rotation order irrlicht uses (i.e. for bones in Luanti)
-- @tparam matrix the matrix to get the rotation of
-- @treturn float pitch
-- @treturn float yaw
-- @treturn float roll
function mat4.get_rot_xyz(M)
local X,Y,Z
if abs(M[3])-1 < DBL_EPSILON then --check if x is 90 or -90. If they are yaw will experience gimbal lock and there will therefore be infinite solutions.
Z = atan2(M[2], M[1])
Y = atan2(-M[3], M[1]/cos(Z))
X = atan2(M[7], M[11])
else
--Z = atan2(M[], M[])
Y = asin(M[3])
X = atan2(M[5], M[7])
Z = 0
end
return X,Y,Z
end
--- Alias of `get_rot_zxy`. Gets the XYZ euler rotation of the given matrix. This is the rotation order irrlicht uses (i.e. for bones in Luanti).
-- @tparam matrix the matrix to get the rotation of
-- @treturn float pitch
-- @treturn float yaw
-- @treturn float roll
-- @function get_rot_irrlicht_bone
mat4.get_rot_irrlicht_bone = mat4.get_rot_xyz
--- Create matrix from orthogonal.
-- @tparam number left
-- @tparam number right
@ -773,19 +946,18 @@ end
--- Convert a matrix to a quaternion.
-- @tparam mat4 a Matrix to be converted
-- @treturn quat out
function mat4.to_quat(a)
identity(tmp):transpose(a)
local w = sqrt(1 + tmp[1] + tmp[6] + tmp[11]) / 2
local scale = w * 4
local q = quat.new(
tmp[10] - tmp[7] / scale,
tmp[3] - tmp[9] / scale,
tmp[5] - tmp[2] / scale,
local quat_new
function mat4.to_quaternion(m)
--I want to note that for no apparent reason at all the original matrix was transposed here
if not quat_new then quat_new = mtul.math.quat.new end
local w = math.sqrt(1 + m[1] + m[6] + m[11]) / 2
local q=quat_new(
(m[7] - m[10]) /(4 * w),
(m[9] - m[3]) /(4 * w),
(m[2] - m[5]) /(4 * w),
w
)
return q:normalize(q)
return q
end
-- http://www.crownandcutlass.com/features/technicaldetails/frustum.html

View File

@ -5,6 +5,8 @@ local constants = require(modules .. "constants")
local vec3 = require(modules .. "vec3")
local precond = require(modules .. "_private_precond")
local private = require(modules .. "_private_utils")
local utils = require(modules .. "utils")
local mat4 = require(modules .. "mat4")
local DOT_THRESHOLD = constants.DOT_THRESHOLD
local DBL_EPSILON = constants.DBL_EPSILON
local acos = math.acos
@ -36,10 +38,6 @@ if type(jit) == "table" and jit.status() then
end
end
-- Statically allocate a temporary variable used in some of our functions.
local tmp = new()
local qv, uv, uuv = vec3(), vec3(), vec3()
--- Constants
-- @table quat
-- @field unit Unit quaternion
@ -79,6 +77,10 @@ function quat.new(x, y, z, w)
return new(0, 0, 0, 1)
end
--[[returns the required delta rotation to make a quaternion aim at a point
function quat.aim_at_point(quat)
end]]
--- Create a quaternion from an angle/axis pair.
-- @tparam number angle Angle (in radians)
-- @param axis/x -- Can be of two types, a vec3 axis, or the x component of that axis
@ -96,28 +98,6 @@ function quat.from_angle_axis(angle, axis, a3, a4)
end
end
--works in theory... probably.
--- Create a quaternion from an euler angle
-- @tparam Vec3 (or xyz table)
-- @treturn quat out
function quat.from_euler_rotation(rot)
local cr = cos(rot.z*.5)
local sr = sin(rot.z*.5)
local cp = cos(rot.x*.5)
local sp = sin(rot.x*.5)
local cy = cos(rot.y*.5)
local sy = sin(rot.y*.5)
return quat.new({
w = cr * cp * cy + sr * sp * sy,
x = sr * cp * cy - cr * sp * sy,
y = cr * sp * cy + sr * cp * sy,
z = cr * cp * sy - sr * sp * cy
})
end
--- Create a quaternion from a normal/up vector pair. (accepts minetest vectors)
-- @tparam vec3 normal
-- @tparam vec3 up (optional)
@ -167,28 +147,48 @@ end
-- @tparam quat a Left hand operand
-- @tparam quat b Right hand operand
-- @treturn quat quaternion equivalent to "apply b, then a"
local out = {}
function quat.mul(a, b)
return new(
a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y,
a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z,
a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x,
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
(a.x * b.w) + (a.w * b.x) + (a.y * b.z) - (a.z * b.y),
(a.y * b.w) + (a.w * b.y) + (a.z * b.x) - (a.x * b.z),
(b.w * a.z) + (b.z * a.w) + (b.y * a.x) - (b.x * a.y),
(a.w * b.w) - (a.x * b.x) - (a.y * b.y) - (a.z * b.z)
)
end
--- Multiply a quaternion and a vec3.
-- Statically allocate a temporary variable used in some of our functions.
local tmp = new()
local u, uv, uuv = vec3(), vec3(), vec3()
--- Multiply a quaternion and a vec3. Equivalent to rotating the vector (a) by the quaternion (v)
-- @tparam quat a Left hand operand
-- @tparam vec3 b Right hand operand
-- @tparam vec3 v Right hand operand
-- @treturn vec3 out
function quat.mul_vec3(a, b)
qv.x = a.x
qv.y = a.y
qv.z = a.z
uv = qv:cross(b)
uuv = qv:cross(uv)
return b + ((uv * a.w) + uuv) * 2
function quat.mul_vec3(a, v)
u.x = a.x
u.y = a.y
u.z = a.z
uv = u:cross(v)
uuv = u:cross(uv)
return v + ((uv * a.w) + uuv) * 2
end
--[[ does the same thing as above, which I did not know when i reimplemented it to check.
function quat.rotate_vec3(a, v)
u.x = a.x
u.y = a.y
u.z = a.z
local s = a.w
return
(u*u:dot(v)*2) +
(v*(s*s - u:dot(u))) +
(u:cross(v)*s*2)
end]]
--- Raise a normalized quaternion to a scalar power.
-- @tparam quat a Left hand operand (should be a unit quaternion)
-- @tparam number s Right hand operand
@ -253,7 +253,7 @@ function quat.scale(a, s)
)
end
--- Alias of from_angle_axis.
--- Alias of `from_angle_axis.`
-- @tparam number angle Angle (in radians)
-- @param axis/x -- Can be of two types, a vec3 axis, or the x component of that axis
-- @param y axis -- y component of axis (optional, only if x component param used)
@ -445,42 +445,177 @@ function quat.to_angle_axis(a, identityAxis)
return angle, vec3(x, y, z)
end
--- Convert a quaternion into euler angle components
-- @tparam quat a Quaternion to convert
-- @treturn roll
-- @treturn pitch
-- @treturn yaw
--no idea if this shit really works, very well could not...
function quat.to_euler_angles_unpack(q)
-- roll (x-axis rotation)
local sinr_cosp = 2 * (q.w * q.x + q.y * q.z)
local cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y)
local pitch = math.atan2(sinr_cosp, cosr_cosp)
-- pitch (y-axis rotation)
local sinp = 2 * (q.w * q.y - q.z * q.x)
local yaw
if math.abs(sinp) >= 1 then
yaw = math.pi / 2 * ((sinp > 0) and 1 or -1) -- Use 90 degrees if out of range
else
yaw = math.asin(sinp)
end
-- yaw (z-axis rotation)
local siny_cosp = 2 * (q.w * q.z + q.x * q.y)
local cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z)
local roll = math.atan2(siny_cosp, cosy_cosp)
return pitch, yaw, roll
--- set a matrix's rotation fields from a quaternion. Uses mat4.set_rot_from_quaternion
-- @tparam quat quaternion to convert
-- @tparam mat4 the mat4 to apply to.
-- @treturn mat4
function quat.set_matrix_rot(q, m)
m:set_rot_from_quaternion(q)
return m
end
--- Convert a quaternion into euler angles
-- @tparam quat a Quaternion to convert
-- @treturn result a {roll, pitch, yaw} table
function quat.to_euler_angles(a)
return {quat.to_euler_angles_unpack(a)}
--- create a new quaternion from a matrix. Uses mat4.to_quaternion
-- @tparam mat4 the matrix to use
-- @treturn quat
function quat.from_matrix(m)
return m:to_quaternion()
end
--- convert a quaternion to an ZXY euler angles. This is the rotation order used by Minetest/Luanti Entities.
-- @tparam quat quaternion to convert
-- @treturn float X
-- @treturn float Y
-- @treturn float Z
local atan2 = math.atan2
local abs = math.abs
local asin = math.asin
function quat.get_euler_zxy(q)
local qx, qy, qz, qw = q.x, q.y, q.z, q.w
local s = 1/sqrt(qx * qx + qz * qz + qy * qy + qw * qw)
qx,qz,qy,qw = qx*s, qz*s, qy*s, qw*s
--convert to matrix but only grab the matrix indices we need. Basically this violently smashes together the matrix to zxy and quat to matrix code.
local m2 = 2*(qx*qy + qz*qw)
local m5 = 2*(qx*qy - qz*qw)
local m6 = 1-2*(qx^2 + qz^2)
local m7 = 2*(qy*qz + qx*qw)
local m9 = 2*(qx*qz + qy*qw)
local m10 = 2*(qy*qz - qx*qw)
local m11 = 1-2*(qx^2 + qy^2)
local X,Y,Z
if abs(m10)-1 < DBL_EPSILON then --check if x is 90 or -90. If it is yaw will experience gimbal lock and there will therefore be infinite solutions.
Z = atan2(m2, m6) --(cz*cx / sz*cx) = cz/cx = tz.
Y = atan2(m9, m11)
X = atan2(-m10, m6/cos(Z))
else
Z = atan2(m7, m5)
Y = 0 --pitch and roll are the same given x=90 or -90.
X = asin(-m10)
end
return X,Y,Z
end
--- alias of `get_euler_zxy`
-- @function quat.get_rot_luanti_entity
quat.get_euler_luanti_entity = quat.get_euler_zxy
--- create a quaternion from euler angles in the ZXY rotation order. This is the rotation order Luanti Entities use
-- @tparam float X
-- @tparam float Y
-- @tparam float Z
-- @treturn quat q
function quat.from_euler_zxy(X,Y,Z)
--I want to note that for no apparent reason at all the original matrix was transposed here
local cr = cos(Z)
local sr = sin(Z)
local cp = cos(X)
local sp = sin(X);
local cy = cos(Y)
local sy = sin(Y);
local m1 = sr * sp * sy + cr * cy
local m2 = sr * cp
local m3 = sr * sp * cy - cr * sy
local m5 = cr * sp * sy - sr * cy
local m6 = cr * cp
local m7 = cr * sp * cy + sr * sy
local m9 = cp * sy
local m10 = -sp
local m11 = cp * cy
local w = math.sqrt(1 + m1 + m6 + m11) / 2
return new(
(m7 - m10) /(4 * w),
(m9 - m3) /(4 * w),
(m2 - m5) /(4 * w),
w
)
end
--- alias of `from_euler_zxy`
-- @function quat.get_rot_luanti_entity
quat.from_euler_luanti_entity = quat.from_euler_zxy
--- convert a quaternion to an xyz euler angles. This is the rotation order used by irrlicht bones.
-- @tparam quat quaternion to convert
-- @treturn X
-- @treturn Y
-- @treturn Z
function quat.get_euler_xyz(q)
local qx, qy, qz, qw = q.x, q.y, q.z, q.w
local s = 1/sqrt(qx * qx + qz * qz + qy * qy + qw * qw)
qx,qz,qy,qw = qx*s, qz*s, qy*s, qw*s
--convert to matrix but only grab the matrix indices we need. Basically this violently smashes together the matrix to zxy and quat to matrix code.
local m1 = 1-2*(qy^2 + qz^2)
local m2 = 2*(qx*qy + qz*qw)
local m3 = 2*(qx*qz - qy*qw)
local m5 = 2*(qx*qy - qz*qw)
local m7 = 2*(qy*qz + qx*qw)
local m11 = 1-2*(qx^2 + qy^2)
local X,Y,Z
if abs(m3)-1 < DBL_EPSILON then --check if x is 90 or -90. If they are yaw will experience gimbal lock and there will therefore be infinite solutions.
Z = atan2(m2, m1)
Y = atan2(-m3, m1/cos(Z))
X = atan2(m7, m11)
else
--Z = atan2(M[], M[])
Y = asin[m3]
X = atan2(m5, m7)
Z = 0
end
return X,Y,Z
end
--- alias of `get_euler_xyz`
-- @function quat.get_rot_irrlicht_bone
quat.get_euler_irrlicht_bone = quat.get_euler_xyz
--- create a quaternion from euler angles in the xyz rotation order. This is the rotation order irrlicht bones use
-- @tparam float X
-- @tparam float Y
-- @tparam float Z
-- @treturn quat q
function quat.from_euler_xyz(X,Y,Z)
local cp = cos(X)
local sp = sin(X)
local cy = cos(Y)
local sy = sin(Y)
local cr = cos(Z)
local sr = sin(Z)
local m1 = (cy * cr)
local m2 = (cy * sr)
local m3 = (-sy)
local m5 = (sp * sy * cr - cp * sr)
local m6 = (sp * sy * sr + cp * cr)
local m7 = (sp * cy)
local m9 = (cp * sy * cr + sp * sr)
local m10 = (cp * sy * sr - sp * cr)
local m11 = (cp * cy)
local w = math.sqrt(1 + m1 + m6 + m11) / 2
return new(
(m7 - m10) /(4 * w),
(m9 - m3) /(4 * w),
(m2 - m5) /(4 * w),
w
)
end
--- alias of `quat.from_euler_zxy`
--@function quat.get_rot_irrlicht_bone
quat.from_euler_irrlicht_bone = quat.from_euler_xyz
--- Convert a quaternion into a vec3.
-- @tparam quat a Quaternion to convert
-- @treturn vec3 out