1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-07-04 15:26:00 +02:00

Additional 3d support

This commit is contained in:
Brian Fiete 2021-05-25 10:57:22 -04:00
parent 369bb0640c
commit 39c140f44a
27 changed files with 4063 additions and 126 deletions

View file

@ -0,0 +1,14 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
namespace Beefy.geom
{
class BoundingBox
{
public Vector3 Min;
public Vector3 Max;
public const int CornerCount = 8;
}
}

View file

@ -55,6 +55,19 @@ namespace Beefy.geom
this.m33 = m33;
}
public static Matrix4 CreateFromColumnMajor(
float m00, float m10, float m20, float m30,
float m01, float m11, float m21, float m31,
float m02, float m12, float m22, float m32,
float m03, float m13, float m23, float m33)
{
return .(
m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33);
}
public static Matrix4 CreatePerspective(float width, float height, float nearPlaneDistance, float farPlaneDistance)
{
Matrix4 matrix;
@ -190,25 +203,23 @@ namespace Beefy.geom
public static Matrix4 Multiply(Matrix4 m1, Matrix4 m2)
{
Matrix4 r;
r.m00 = m1.m00 * m2.m00 + m1.m01 * m2.m10 + m1.m02 * m2.m20 + m1.m03 * m2.m30;
r.m01 = m1.m00 * m2.m01 + m1.m01 * m2.m11 + m1.m02 * m2.m21 + m1.m03 * m2.m31;
r.m02 = m1.m00 * m2.m02 + m1.m01 * m2.m12 + m1.m02 * m2.m22 + m1.m03 * m2.m32;
r.m03 = m1.m00 * m2.m03 + m1.m01 * m2.m13 + m1.m02 * m2.m23 + m1.m03 * m2.m33;
r.m10 = m1.m10 * m2.m00 + m1.m11 * m2.m10 + m1.m12 * m2.m20 + m1.m13 * m2.m30;
r.m11 = m1.m10 * m2.m01 + m1.m11 * m2.m11 + m1.m12 * m2.m21 + m1.m13 * m2.m31;
r.m12 = m1.m10 * m2.m02 + m1.m11 * m2.m12 + m1.m12 * m2.m22 + m1.m13 * m2.m32;
r.m13 = m1.m10 * m2.m03 + m1.m11 * m2.m13 + m1.m12 * m2.m23 + m1.m13 * m2.m33;
r.m20 = m1.m20 * m2.m00 + m1.m21 * m2.m10 + m1.m22 * m2.m20 + m1.m23 * m2.m30;
r.m21 = m1.m20 * m2.m01 + m1.m21 * m2.m11 + m1.m22 * m2.m21 + m1.m23 * m2.m31;
r.m22 = m1.m20 * m2.m02 + m1.m21 * m2.m12 + m1.m22 * m2.m22 + m1.m23 * m2.m32;
r.m23 = m1.m20 * m2.m03 + m1.m21 * m2.m13 + m1.m22 * m2.m23 + m1.m23 * m2.m33;
r.m30 = m1.m30 * m2.m00 + m1.m31 * m2.m10 + m1.m32 * m2.m20 + m1.m33 * m2.m30;
r.m31 = m1.m30 * m2.m01 + m1.m31 * m2.m11 + m1.m32 * m2.m21 + m1.m33 * m2.m31;
r.m32 = m1.m30 * m2.m02 + m1.m31 * m2.m12 + m1.m32 * m2.m22 + m1.m33 * m2.m32;
r.m33 = m1.m30 * m2.m03 + m1.m31 * m2.m13 + m1.m32 * m2.m23 + m1.m33 * m2.m33;
r.m00 = (((m1.m00 * m2.m00) + (m1.m10 * m2.m01)) + (m1.m20 * m2.m02)) + (m1.m30 * m2.m03);
r.m10 = (((m1.m00 * m2.m10) + (m1.m10 * m2.m11)) + (m1.m20 * m2.m12)) + (m1.m30 * m2.m13);
r.m20 = (((m1.m00 * m2.m20) + (m1.m10 * m2.m21)) + (m1.m20 * m2.m22)) + (m1.m30 * m2.m23);
r.m30 = (((m1.m00 * m2.m30) + (m1.m10 * m2.m31)) + (m1.m20 * m2.m32)) + (m1.m30 * m2.m33);
r.m01 = (((m1.m01 * m2.m00) + (m1.m11 * m2.m01)) + (m1.m21 * m2.m02)) + (m1.m31 * m2.m03);
r.m11 = (((m1.m01 * m2.m10) + (m1.m11 * m2.m11)) + (m1.m21 * m2.m12)) + (m1.m31 * m2.m13);
r.m21 = (((m1.m01 * m2.m20) + (m1.m11 * m2.m21)) + (m1.m21 * m2.m22)) + (m1.m31 * m2.m23);
r.m31 = (((m1.m01 * m2.m30) + (m1.m11 * m2.m31)) + (m1.m21 * m2.m32)) + (m1.m31 * m2.m33);
r.m02 = (((m1.m02 * m2.m00) + (m1.m12 * m2.m01)) + (m1.m22 * m2.m02)) + (m1.m32 * m2.m03);
r.m12 = (((m1.m02 * m2.m10) + (m1.m12 * m2.m11)) + (m1.m22 * m2.m12)) + (m1.m32 * m2.m13);
r.m22 = (((m1.m02 * m2.m20) + (m1.m12 * m2.m21)) + (m1.m22 * m2.m22)) + (m1.m32 * m2.m23);
r.m32 = (((m1.m02 * m2.m30) + (m1.m12 * m2.m31)) + (m1.m22 * m2.m32)) + (m1.m32 * m2.m33);
r.m03 = (((m1.m03 * m2.m00) + (m1.m13 * m2.m01)) + (m1.m23 * m2.m02)) + (m1.m33 * m2.m03);
r.m13 = (((m1.m03 * m2.m10) + (m1.m13 * m2.m11)) + (m1.m23 * m2.m12)) + (m1.m33 * m2.m13);
r.m23 = (((m1.m03 * m2.m20) + (m1.m13 * m2.m21)) + (m1.m23 * m2.m22)) + (m1.m33 * m2.m23);
r.m33 = (((m1.m03 * m2.m30) + (m1.m13 * m2.m31)) + (m1.m23 * m2.m32)) + (m1.m33 * m2.m33);
return r;
}
@ -489,5 +500,730 @@ namespace Beefy.geom
r20, r21, r22, r23,
0, 0, 0, 1);
}
public static void Invert(Matrix4 matrix, out Matrix4 result)
{
float num1 = matrix.m00;
float num2 = matrix.m10;
float num3 = matrix.m20;
float num4 = matrix.m30;
float num5 = matrix.m01;
float num6 = matrix.m11;
float num7 = matrix.m21;
float num8 = matrix.m31;
float num9 = matrix.m02;
float num10 = matrix.m12;
float num11 = matrix.m22;
float num12 = matrix.m32;
float num13 = matrix.m03;
float num14 = matrix.m13;
float num15 = matrix.m23;
float num16 = matrix.m33;
float num17 = (float) ((double) num11 * (double) num16 - (double) num12 * (double) num15);
float num18 = (float) ((double) num10 * (double) num16 - (double) num12 * (double) num14);
float num19 = (float) ((double) num10 * (double) num15 - (double) num11 * (double) num14);
float num20 = (float) ((double) num9 * (double) num16 - (double) num12 * (double) num13);
float num21 = (float) ((double) num9 * (double) num15 - (double) num11 * (double) num13);
float num22 = (float) ((double) num9 * (double) num14 - (double) num10 * (double) num13);
float num23 = (float) ((double) num6 * (double) num17 - (double) num7 * (double) num18 + (double) num8 * (double) num19);
float num24 = (float) -((double) num5 * (double) num17 - (double) num7 * (double) num20 + (double) num8 * (double) num21);
float num25 = (float) ((double) num5 * (double) num18 - (double) num6 * (double) num20 + (double) num8 * (double) num22);
float num26 = (float) -((double) num5 * (double) num19 - (double) num6 * (double) num21 + (double) num7 * (double) num22);
float num27 = (float) (1.0 / ((double) num1 * (double) num23 + (double) num2 * (double) num24 + (double) num3 * (double) num25 + (double) num4 * (double) num26));
result.m00 = num23 * num27;
result.m01 = num24 * num27;
result.m02 = num25 * num27;
result.m03 = num26 * num27;
result.m10 = (float)(-((double) num2 * (double) num17 - (double) num3 * (double) num18 + (double) num4 * (double) num19) * num27);
result.m11 = (float) ((double) num1 * (double) num17 - (double) num3 * (double) num20 + (double) num4 * (double) num21) * num27;
result.m12 = (float)(-((double) num1 * (double) num18 - (double) num2 * (double) num20 + (double) num4 * (double) num22) * num27);
result.m13 = (float) ((double) num1 * (double) num19 - (double) num2 * (double) num21 + (double) num3 * (double) num22) * num27;
float num28 = (float) ((double) num7 * (double) num16 - (double) num8 * (double) num15);
float num29 = (float) ((double) num6 * (double) num16 - (double) num8 * (double) num14);
float num30 = (float) ((double) num6 * (double) num15 - (double) num7 * (double) num14);
float num31 = (float) ((double) num5 * (double) num16 - (double) num8 * (double) num13);
float num32 = (float) ((double) num5 * (double) num15 - (double) num7 * (double) num13);
float num33 = (float) ((double) num5 * (double) num14 - (double) num6 * (double) num13);
result.m20 = (float) ((double) num2 * (double) num28 - (double) num3 * (double) num29 + (double) num4 * (double) num30) * num27;
result.m21 = (float)(-((double) num1 * (double) num28 - (double) num3 * (double) num31 + (double) num4 * (double) num32) * num27);
result.m22 = (float) ((double) num1 * (double) num29 - (double) num2 * (double) num31 + (double) num4 * (double) num33) * num27;
result.m23 = (float)(-((double) num1 * (double) num30 - (double) num2 * (double) num32 + (double) num3 * (double) num33) * num27);
float num34 = (float) ((double) num7 * (double) num12 - (double) num8 * (double) num11);
float num35 = (float) ((double) num6 * (double) num12 - (double) num8 * (double) num10);
float num36 = (float) ((double) num6 * (double) num11 - (double) num7 * (double) num10);
float num37 = (float) ((double) num5 * (double) num12 - (double) num8 * (double) num9);
float num38 = (float) ((double) num5 * (double) num11 - (double) num7 * (double) num9);
float num39 = (float) ((double) num5 * (double) num10 - (double) num6 * (double) num9);
result.m30 = (float)(-((double) num2 * (double) num34 - (double) num3 * (double) num35 + (double) num4 * (double) num36) * num27);
result.m31 = (float) ((double) num1 * (double) num34 - (double) num3 * (double) num37 + (double) num4 * (double) num38) * num27;
result.m32 = (float)(-((double) num1 * (double) num35 - (double) num2 * (double) num37 + (double) num4 * (double) num39) * num27);
result.m33 = (float) ((double) num1 * (double) num36 - (double) num2 * (double) num38 + (double) num3 * (double) num39) * num27;
/*
///
// Use Laplace expansion theorem to calculate the inverse of a 4x4 matrix
//
// 1. Calculate the 2x2 determinants needed the 4x4 determinant based on the 2x2 determinants
// 3. Create the adjugate matrix, which satisfies: A * adj(A) = det(A) * I
// 4. Divide adjugate matrix with the determinant to find the inverse
float det1, det2, det3, det4, det5, det6, det7, det8, det9, det10, det11, det12;
float detMatrix;
FindDeterminants(ref matrix, out detMatrix, out det1, out det2, out det3, out det4, out det5, out det6,
out det7, out det8, out det9, out det10, out det11, out det12);
float invDetMatrix = 1f / detMatrix;
Matrix ret; // Allow for matrix and result to point to the same structure
ret.M11 = (matrix.M22*det12 - matrix.M23*det11 + matrix.M24*det10) * invDetMatrix;
ret.M12 = (-matrix.M12*det12 + matrix.M13*det11 - matrix.M14*det10) * invDetMatrix;
ret.M13 = (matrix.M42*det6 - matrix.M43*det5 + matrix.M44*det4) * invDetMatrix;
ret.M14 = (-matrix.M32*det6 + matrix.M33*det5 - matrix.M34*det4) * invDetMatrix;
ret.M21 = (-matrix.M21*det12 + matrix.M23*det9 - matrix.M24*det8) * invDetMatrix;
ret.M22 = (matrix.M11*det12 - matrix.M13*det9 + matrix.M14*det8) * invDetMatrix;
ret.M23 = (-matrix.M41*det6 + matrix.M43*det3 - matrix.M44*det2) * invDetMatrix;
ret.M24 = (matrix.M31*det6 - matrix.M33*det3 + matrix.M34*det2) * invDetMatrix;
ret.M31 = (matrix.M21*det11 - matrix.M22*det9 + matrix.M24*det7) * invDetMatrix;
ret.M32 = (-matrix.M11*det11 + matrix.M12*det9 - matrix.M14*det7) * invDetMatrix;
ret.M33 = (matrix.M41*det5 - matrix.M42*det3 + matrix.M44*det1) * invDetMatrix;
ret.M34 = (-matrix.M31*det5 + matrix.M32*det3 - matrix.M34*det1) * invDetMatrix;
ret.M41 = (-matrix.M21*det10 + matrix.M22*det8 - matrix.M23*det7) * invDetMatrix;
ret.M42 = (matrix.M11*det10 - matrix.M12*det8 + matrix.M13*det7) * invDetMatrix;
ret.M43 = (-matrix.M41*det4 + matrix.M42*det2 - matrix.M43*det1) * invDetMatrix;
ret.M44 = (matrix.M31*det4 - matrix.M32*det2 + matrix.M33*det1) * invDetMatrix;
result = ret;
*/
}
public static Matrix4 Invert(Matrix4 matrix)
{
Invert(matrix, var outMatrix);
return outMatrix;
}
/// <summary>
/// Decomposes this matrix to translation, rotation and scale elements. Returns <c>true</c> if matrix can be decomposed; <c>false</c> otherwise.
/// </summary>
/// <param name="scale">Scale vector as an output parameter.
/// <param name="rotation">Rotation quaternion as an output parameter.
/// <param name="translation">Translation vector as an output parameter.
/// <returns><c>true</c> if matrix can be decomposed; <c>false</c> otherwise.</returns>
public bool Decompose(
out Vector3 scale,
out Quaternion rotation,
out Vector3 translation
) {
translation.mX = m03;
translation.mY = m13;
translation.mZ = m23;
float xs = (Math.Sign(m00 * m10 * m20 * m30) < 0) ? -1 : 1;
float ys = (Math.Sign(m01 * m11 * m21 * m31) < 0) ? -1 : 1;
float zs = (Math.Sign(m02 * m12 * m22 * m32) < 0) ? -1 : 1;
scale.mX = xs * (float) Math.Sqrt(m00 * m00 + m10 * m10 + m20 * m20);
scale.mY = ys * (float) Math.Sqrt(m01 * m01 + m11 * m11 + m21 * m21);
scale.mZ = zs * (float) Math.Sqrt(m02 * m02 + m12 * m12 + m22 * m22);
if (Math.WithinEpsilon(scale.mX, 0.0f) ||
Math.WithinEpsilon(scale.mY, 0.0f) ||
Math.WithinEpsilon(scale.mZ, 0.0f) )
{
rotation = Quaternion.Identity;
return false;
}
Matrix4 m1 = Matrix4.CreateFromColumnMajor(
m00 / scale.mX, m10 / scale.mX, m20 / scale.mX, 0,
m01 / scale.mY, m11 / scale.mY, m21 / scale.mY, 0,
m02 / scale.mZ, m12 / scale.mZ, m22 / scale.mZ, 0,
0, 0, 0, 1
);
rotation = Quaternion.CreateFromRotationMatrix(m1);
return true;
}
/// <summary>
/// Returns a determinant of this matrix.
/// </summary>
/// <returns>Determinant of this matrix</returns>
/// <remarks>See more about determinant here - http://en.wikipedia.org/wiki/Determinant.
/// </remarks>
public float Determinant()
{
float num18 = (m22 * m33) - (m32 * m23);
float num17 = (m12 * m33) - (m32 * m13);
float num16 = (m12 * m23) - (m22 * m13);
float num15 = (m02 * m33) - (m32 * m03);
float num14 = (m02 * m23) - (m22 * m03);
float num13 = (m02 * m13) - (m12 * m03);
return (
(
(
(m00 * (((m11 * num18) - (m21 * num17)) + (m31 * num16))) -
(m10 * (((m01 * num18) - (m21 * num15)) + (m31 * num14)))
) + (m20 * (((m01 * num17) - (m11 * num15)) + (m31 * num13)))
) - (m30 * (((m01 * num16) - (m11 * num14)) + (m21 * num13)))
);
}
/// <summary>
/// Creates a new matrix for spherical billboarding that rotates around specified object position.
/// </summary>
/// <param name="objectPosition">Position of billboard object. It will rotate around that vector.
/// <param name="cameraPosition">The camera position.
/// <param name="cameraUpVector">The camera up vector.
/// <param name="cameraForwardVector">Optional camera forward vector.
/// <returns>The matrix for spherical billboarding.</returns>
public static Matrix4 CreateBillboard(
Vector3 objectPosition,
Vector3 cameraPosition,
Vector3 cameraUpVector,
Nullable<Vector3> cameraForwardVector
) {
Matrix4 result;
// Delegate to the other overload of the function to do the work
CreateBillboard(
objectPosition,
cameraPosition,
cameraUpVector,
cameraForwardVector,
out result
);
return result;
}
/// <summary>
/// Creates a new matrix for spherical billboarding that rotates around specified object position.
/// </summary>
/// <param name="objectPosition">Position of billboard object. It will rotate around that vector.
/// <param name="cameraPosition">The camera position.
/// <param name="cameraUpVector">The camera up vector.
/// <param name="cameraForwardVector">Optional camera forward vector.
/// <param name="result">The matrix for spherical billboarding as an output parameter.
public static void CreateBillboard(
Vector3 objectPosition,
Vector3 cameraPosition,
Vector3 cameraUpVector,
Vector3? cameraForwardVector,
out Matrix4 result
) {
Vector3 vector;
Vector3 vector2;
Vector3 vector3;
vector.mX = objectPosition.mX - cameraPosition.mX;
vector.mY = objectPosition.mY - cameraPosition.mY;
vector.mZ = objectPosition.mZ - cameraPosition.mZ;
float num = vector.LengthSquared;
if (num < 0.0001f)
{
vector = cameraForwardVector.HasValue ?
-cameraForwardVector.Value :
Vector3.Forward;
}
else
{
vector *= (float) (1f / ((float) Math.Sqrt((double) num)));
}
vector3 = Vector3.Cross(cameraUpVector, vector);
vector3.Normalize();
vector2 = Vector3.Cross(vector, vector3);
result.m00 = vector3.mX;
result.m10 = vector3.mY;
result.m20 = vector3.mZ;
result.m30 = 0;
result.m01 = vector2.mX;
result.m11 = vector2.mY;
result.m21 = vector2.mZ;
result.m31 = 0;
result.m02 = vector.mX;
result.m12 = vector.mY;
result.m22 = vector.mZ;
result.m32 = 0;
result.m03 = objectPosition.mX;
result.m13 = objectPosition.mY;
result.m23 = objectPosition.mZ;
result.m33 = 1;
}
/// <summary>
/// Creates a new matrix for cylindrical billboarding that rotates around specified axis.
/// </summary>
/// <param name="objectPosition">Object position the billboard will rotate around.
/// <param name="cameraPosition">Camera position.
/// <param name="rotateAxis">Axis of billboard for rotation.
/// <param name="cameraForwardVector">Optional camera forward vector.
/// <param name="objectForwardVector">Optional object forward vector.
/// <returns>The matrix for cylindrical billboarding.</returns>
public static Matrix4 CreateConstrainedBillboard(
Vector3 objectPosition,
Vector3 cameraPosition,
Vector3 rotateAxis,
Nullable<Vector3> cameraForwardVector,
Nullable<Vector3> objectForwardVector
) {
Matrix4 result;
CreateConstrainedBillboard(
objectPosition,
cameraPosition,
rotateAxis,
cameraForwardVector,
objectForwardVector,
out result
);
return result;
}
/// <summary>
/// Creates a new matrix for cylindrical billboarding that rotates around specified axis.
/// </summary>
/// <param name="objectPosition">Object position the billboard will rotate around.
/// <param name="cameraPosition">Camera position.
/// <param name="rotateAxis">Axis of billboard for rotation.
/// <param name="cameraForwardVector">Optional camera forward vector.
/// <param name="objectForwardVector">Optional object forward vector.
/// <param name="result">The matrix for cylindrical billboarding as an output parameter.
public static void CreateConstrainedBillboard(
Vector3 objectPosition,
Vector3 cameraPosition,
Vector3 rotateAxis,
Vector3? cameraForwardVector,
Vector3? objectForwardVector,
out Matrix4 result
) {
float num;
Vector3 vector;
Vector3 vector2;
Vector3 vector3;
vector2.mX = objectPosition.mX - cameraPosition.mX;
vector2.mY = objectPosition.mY - cameraPosition.mY;
vector2.mZ = objectPosition.mZ - cameraPosition.mZ;
float num2 = vector2.LengthSquared;
if (num2 < 0.0001f)
{
vector2 = cameraForwardVector.HasValue ?
-cameraForwardVector.Value :
Vector3.Forward;
}
else
{
vector2 *= (float) (1f / ((float) Math.Sqrt((double) num2)));
}
Vector3 vector4 = rotateAxis;
num = Vector3.Dot(rotateAxis, vector2);
if (Math.Abs(num) > 0.9982547f)
{
if (objectForwardVector.HasValue)
{
vector = objectForwardVector.Value;
num = Vector3.Dot(rotateAxis, vector);
if (Math.Abs(num) > 0.9982547f)
{
num = (
(rotateAxis.mX * Vector3.Forward.mX) +
(rotateAxis.mY * Vector3.Forward.mY)
) + (rotateAxis.mZ * Vector3.Forward.mZ);
vector = (Math.Abs(num) > 0.9982547f) ?
Vector3.Right :
Vector3.Forward;
}
}
else
{
num = (
(rotateAxis.mX * Vector3.Forward.mX) +
(rotateAxis.mY * Vector3.Forward.mY)
) + (rotateAxis.mZ * Vector3.Forward.mZ);
vector = (Math.Abs(num) > 0.9982547f) ?
Vector3.Right :
Vector3.Forward;
}
vector3 = Vector3.Cross(rotateAxis, vector);
vector3.Normalize();
vector = Vector3.Cross(vector3, rotateAxis);
vector.Normalize();
}
else
{
vector3 = Vector3.Cross(rotateAxis, vector2);
vector3.Normalize();
vector = Vector3.Cross(vector3, vector4);
vector.Normalize();
}
result.m00 = vector3.mX;
result.m10 = vector3.mY;
result.m20 = vector3.mZ;
result.m30 = 0;
result.m01 = vector4.mX;
result.m11 = vector4.mY;
result.m21 = vector4.mZ;
result.m31 = 0;
result.m02 = vector.mX;
result.m12 = vector.mY;
result.m22 = vector.mZ;
result.m32 = 0;
result.m03 = objectPosition.mX;
result.m13 = objectPosition.mY;
result.m23 = objectPosition.mZ;
result.m33 = 1;
}
/// <summary>
/// Creates a new matrix which contains the rotation moment around specified axis.
/// </summary>
/// <param name="axis">The axis of rotation.
/// <param name="angle">The angle of rotation in radians.
/// <returns>The rotation matrix.</returns>
public static Matrix4 CreateFromAxisAngle(Vector3 axis, float angle)
{
Matrix4 result;
CreateFromAxisAngle(axis, angle, out result);
return result;
}
/// <summary>
/// Creates a new matrix which contains the rotation moment around specified axis.
/// </summary>
/// <param name="axis">The axis of rotation.
/// <param name="angle">The angle of rotation in radians.
/// <param name="result">The rotation matrix as an output parameter.
public static void CreateFromAxisAngle(
Vector3 axis,
float angle,
out Matrix4 result
) {
float x = axis.mX;
float y = axis.mY;
float z = axis.mZ;
float num2 = (float) Math.Sin((double) angle);
float num = (float) Math.Cos((double) angle);
float num11 = x * x;
float num10 = y * y;
float num9 = z * z;
float num8 = x * y;
float num7 = x * z;
float num6 = y * z;
result.m00 = num11 + (num * (1f - num11));
result.m10 = (num8 - (num * num8)) + (num2 * z);
result.m20 = (num7 - (num * num7)) - (num2 * y);
result.m30 = 0;
result.m01 = (num8 - (num * num8)) - (num2 * z);
result.m11 = num10 + (num * (1f - num10));
result.m21 = (num6 - (num * num6)) + (num2 * x);
result.m31 = 0;
result.m02 = (num7 - (num * num7)) + (num2 * y);
result.m12 = (num6 - (num * num6)) - (num2 * x);
result.m22 = num9 + (num * (1f - num9));
result.m32 = 0;
result.m03 = 0;
result.m13 = 0;
result.m23 = 0;
result.m33 = 1;
}
/// <summary>
/// Creates a new rotation matrix from a <see cref="Quaternion"/>.
/// </summary>
/// <param name="quaternion"><see cref="Quaternion"/> of rotation moment.
/// <returns>The rotation matrix.</returns>
public static Matrix4 CreateFromQuaternion(Quaternion quaternion)
{
Matrix4 result;
CreateFromQuaternion(quaternion, out result);
return result;
}
/// <summary>
/// Creates a new rotation matrix from a <see cref="Quaternion"/>.
/// </summary>
/// <param name="quaternion"><see cref="Quaternion"/> of rotation moment.
/// <param name="result">The rotation matrix as an output parameter.
public static void CreateFromQuaternion(Quaternion quaternion, out Matrix4 result)
{
float num9 = quaternion.mX * quaternion.mX;
float num8 = quaternion.mY * quaternion.mY;
float num7 = quaternion.mZ * quaternion.mZ;
float num6 = quaternion.mX * quaternion.mY;
float num5 = quaternion.mZ * quaternion.mW;
float num4 = quaternion.mZ * quaternion.mX;
float num3 = quaternion.mY * quaternion.mW;
float num2 = quaternion.mY * quaternion.mZ;
float num = quaternion.mX * quaternion.mW;
result.m00 = 1f - (2f * (num8 + num7));
result.m10 = 2f * (num6 + num5);
result.m20 = 2f * (num4 - num3);
result.m30 = 0f;
result.m01 = 2f * (num6 - num5);
result.m11 = 1f - (2f * (num7 + num9));
result.m21 = 2f * (num2 + num);
result.m31 = 0f;
result.m02 = 2f * (num4 + num3);
result.m12 = 2f * (num2 - num);
result.m22 = 1f - (2f * (num8 + num9));
result.m32 = 0f;
result.m03 = 0f;
result.m13 = 0f;
result.m23 = 0f;
result.m33 = 1f;
}
/// Creates a new rotation matrix from the specified yaw, pitch and roll values.
/// @param yaw The yaw rotation value in radians.
/// @param pitch The pitch rotation value in radians.
/// @param roll The roll rotation value in radians.
/// @returns The rotation matrix
/// @remarks For more information about yaw, pitch and roll visit http://en.wikipedia.org/wiki/Euler_angles.
public static Matrix4 CreateFromYawPitchRoll(float yaw, float pitch, float roll)
{
Matrix4 matrix;
CreateFromYawPitchRoll(yaw, pitch, roll, out matrix);
return matrix;
}
/// Creates a new rotation matrix from the specified yaw, pitch and roll values.
/// @param yaw The yaw rotation value in radians.
/// @param pitch The pitch rotation value in radians.
/// @param roll The roll rotation value in radians.
/// @param result The rotation matrix as an output parameter.
/// @remarks>For more information about yaw, pitch and roll visit http://en.wikipedia.org/wiki/Euler_angles.
public static void CreateFromYawPitchRoll(
float yaw,
float pitch,
float roll,
out Matrix4 result
) {
Quaternion quaternion;
Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll, out quaternion);
CreateFromQuaternion(quaternion, out result);
}
/// Creates a new viewing matrix.
/// @param cameraPosition Position of the camera.
/// @param cameraTarget Lookup vector of the camera.
/// @param cameraUpVector The direction of the upper edge of the camera.
/// @returns The viewing matrix.
public static Matrix4 CreateLookAt(
Vector3 cameraPosition,
Vector3 cameraTarget,
Vector3 cameraUpVector
) {
Matrix4 matrix;
CreateLookAt(cameraPosition, cameraTarget, cameraUpVector, out matrix);
return matrix;
}
/// Creates a new viewing matrix.
/// @param cameraPosition Position of the camera.
/// @param cameraTarget Lookup vector of the camera.
/// @param cameraUpVector The direction of the upper edge of the camera.
/// @param result The viewing matrix as an output parameter.
public static void CreateLookAt(
Vector3 cameraPosition,
Vector3 cameraTarget,
Vector3 cameraUpVector,
out Matrix4 result
) {
Vector3 vectorA = Vector3.Normalize(cameraPosition - cameraTarget);
Vector3 vectorB = Vector3.Normalize(Vector3.Cross(cameraUpVector, vectorA));
Vector3 vectorC = Vector3.Cross(vectorA, vectorB);
result.m00 = vectorB.mX;
result.m10 = vectorC.mX;
result.m20 = vectorA.mX;
result.m30 = 0f;
result.m01 = vectorB.mY;
result.m11 = vectorC.mY;
result.m21 = vectorA.mY;
result.m31 = 0f;
result.m02 = vectorB.mZ;
result.m12 = vectorC.mZ;
result.m22 = vectorA.mZ;
result.m32 = 0f;
result.m03 = -Vector3.Dot(vectorB, cameraPosition);
result.m13 = -Vector3.Dot(vectorC, cameraPosition);
result.m23 = -Vector3.Dot(vectorA, cameraPosition);
result.m33 = 1f;
}
/// Creates a new projection matrix for orthographic view.
/// @param width Width of the viewing volume.
/// @param height Height of the viewing volume.
/// @param zNearPlane Depth of the near plane.
/// @param zFarPlane Depth of the far plane.
/// @returns The new projection matrix for orthographic view.</returns>
public static Matrix4 CreateOrthographic(
float width,
float height,
float zNearPlane,
float zFarPlane
) {
Matrix4 matrix;
CreateOrthographic(width, height, zNearPlane, zFarPlane, out matrix);
return matrix;
}
/// Creates a new projection matrix for orthographic view.
/// @param width Width of the viewing volume.
/// @param height Height of the viewing volume.
/// @param zNearPlane Depth of the near plane.
/// @param zFarPlane Depth of the far plane.
/// @param result The new projection matrix for orthographic view as an output parameter.
public static void CreateOrthographic(
float width,
float height,
float zNearPlane,
float zFarPlane,
out Matrix4 result
) {
result.m00 = 2f / width;
result.m10 = result.m20 = result.m30 = 0f;
result.m11 = 2f / height;
result.m01 = result.m21 = result.m31 = 0f;
result.m22 = 1f / (zNearPlane - zFarPlane);
result.m02 = result.m12 = result.m32 = 0f;
result.m03 = result.m13 = 0f;
result.m23 = zNearPlane / (zNearPlane - zFarPlane);
result.m33 = 1f;
}
/// Creates a new projection matrix for customized orthographic view.
/// @param left Lower x-value at the near plane.
/// @param right Upper x-value at the near plane.
/// @param bottom Lower y-coordinate at the near plane.
/// @param top Upper y-value at the near plane.
/// @param zNearPlane Depth of the near plane.
/// @param zFarPlane Depth of the far plane.
/// @returns The new projection matrix for customized orthographic view.</returns>
public static Matrix4 CreateOrthographicOffCenter(
float left,
float right,
float bottom,
float top,
float zNearPlane,
float zFarPlane
) {
Matrix4 matrix;
CreateOrthographicOffCenter(
left,
right,
bottom,
top,
zNearPlane,
zFarPlane,
out matrix
);
return matrix;
}
/// Creates a new projection matrix for customized orthographic view.
/// @param left Lower x-value at the near plane.
/// @param right Upper x-value at the near plane.
/// @param bottom Lower y-coordinate at the near plane.
/// @param top Upper y-value at the near plane.
/// @param zNearPlane Depth of the near plane.
/// @param zFarPlane Depth of the far plane.
/// @param result The new projection matrix for customized orthographic view as an output parameter.
public static void CreateOrthographicOffCenter(
float left,
float right,
float bottom,
float top,
float zNearPlane,
float zFarPlane,
out Matrix4 result
)
{
result.m00 = (float) (2.0 / ((double) right - (double) left));
result.m10 = 0.0f;
result.m20 = 0.0f;
result.m30 = 0.0f;
result.m01 = 0.0f;
result.m11 = (float) (2.0 / ((double) top - (double) bottom));
result.m21 = 0.0f;
result.m31 = 0.0f;
result.m02 = 0.0f;
result.m12 = 0.0f;
result.m22 = (float) (1.0 / ((double) zNearPlane - (double) zFarPlane));
result.m32 = 0.0f;
result.m03 = (float) (
((double) left + (double) right) /
((double) left - (double) right)
);
result.m13 = (float) (
((double) top + (double) bottom) /
((double) bottom - (double) top)
);
result.m23 = (float) (
(double) zNearPlane /
((double) zNearPlane - (double) zFarPlane)
);
result.m33 = 1.0f;
}
/// Creates a new matrix that flattens geometry into a specified <see cref="Plane"/> as if casting a shadow from a specified light source.
/// @param lightDirection A vector specifying the direction from which the light that will cast the shadow is coming.
/// @param plane The plane onto which the new matrix should flatten geometry so as to cast a shadow.
/// @returns>A matrix that can be used to flatten geometry onto the specified plane from the specified direction.
public static Matrix4 CreateShadow(Vector3 lightDirection, Plane plane)
{
Matrix4 result;
result = CreateShadow(lightDirection, plane);
return result;
}
/// Creates a new matrix that flattens geometry into a specified <see cref="Plane"/> as if casting a shadow from a specified light source.
/// @param lightDirection A vector specifying the direction from which the light that will cast the shadow is coming.
/// @param plane The plane onto which the new matrix should flatten geometry so as to cast a shadow.
/// @param result A matrix that can be used to flatten geometry onto the specified plane from the specified direction as an output parameter.
public static void CreateShadow(
Vector3 lightDirection,
Plane plane,
out Matrix4 result)
{
float dot = (
(plane.Normal.mX * lightDirection.mX) +
(plane.Normal.mY * lightDirection.mY) +
(plane.Normal.mZ * lightDirection.mZ)
);
float x = -plane.Normal.mX;
float y = -plane.Normal.mY;
float z = -plane.Normal.mZ;
float d = -plane.D;
result.m00 = (x * lightDirection.mX) + dot;
result.m10 = x * lightDirection.mY;
result.m20 = x * lightDirection.mZ;
result.m30 = 0;
result.m01 = y * lightDirection.mX;
result.m11 = (y * lightDirection.mY) + dot;
result.m21 = y * lightDirection.mZ;
result.m31 = 0;
result.m02 = z * lightDirection.mX;
result.m12 = z * lightDirection.mY;
result.m22 = (z * lightDirection.mZ) + dot;
result.m32 = 0;
result.m03 = d * lightDirection.mX;
result.m13 = d * lightDirection.mY;
result.m23 = d * lightDirection.mZ;
result.m33 = dot;
}
public override void ToString(System.String strBuffer)
{
for (int row < 4)
for (int col < 4)
{
#unwarn
strBuffer.AppendF($"M{row+1}{col+1}:{((float*)&this)[row+col*4]}\n");
}
}
}
}

View file

@ -0,0 +1,291 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
using System;
namespace Beefy.geom
{
/// <summary>
/// Defines the intersection between a <see cref="Plane"/> and a bounding volume.
/// </summary>
public enum PlaneIntersectionType
{
/// <summary>
/// There is no intersection, the bounding volume is in the negative half space of the plane.
/// </summary>
Front,
/// <summary>
/// There is no intersection, the bounding volume is in the positive half space of the plane.
/// </summary>
Back,
/// <summary>
/// The plane is intersected.
/// </summary>
Intersecting
}
public struct Plane
{
public Vector3 Normal;
public float D;
public this(Vector4 value)
: this(Vector3(value.mX, value.mY, value.mZ), value.mW)
{
}
public this(Vector3 normal, float d)
{
Normal = normal;
D = d;
}
public this(Vector3 a, Vector3 b, Vector3 c)
{
Vector3 ab = b - a;
Vector3 ac = c - a;
Vector3 cross = Vector3.Cross(ab, ac);
Vector3.Normalize(cross, out Normal);
D = -(Vector3.Dot(Normal, a));
}
public this(float a, float b, float c, float d)
: this(Vector3(a, b, c), d)
{
}
public float Dot(Vector4 value)
{
return (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ) +
(this.D * value.mW)
);
}
public void Dot(ref Vector4 value, out float result)
{
result = (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ) +
(this.D * value.mW)
);
}
public float DotCoordinate(Vector3 value)
{
return (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ) +
this.D
);
}
public void DotCoordinate(ref Vector3 value, out float result)
{
result = (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ) +
this.D
);
}
public float DotNormal(Vector3 value)
{
return (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ)
);
}
public void DotNormal(Vector3 value, out float result)
{
result = (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ)
);
}
public void Normalize() mut
{
float length = Normal.Length;
float factor = 1.0f / length;
Normal = Vector3.Multiply(Normal, factor);
D = D * factor;
}
/*public PlaneIntersectionType Intersects(BoundingBox box)
{
return box.Intersects(this);
}
public void Intersects(ref BoundingBox box, out PlaneIntersectionType result)
{
box.Intersects(ref this, out result);
}
public PlaneIntersectionType Intersects(BoundingSphere sphere)
{
return sphere.Intersects(this);
}
public void Intersects(ref BoundingSphere sphere, out PlaneIntersectionType result)
{
sphere.Intersects(ref this, out result);
}
public PlaneIntersectionType Intersects(BoundingFrustum frustum)
{
return frustum.Intersects(this);
}*/
#endregion
#region Internal Methods
internal PlaneIntersectionType Intersects(ref Vector3 point)
{
float distance;
DotCoordinate(ref point, out distance);
if (distance > 0)
{
return PlaneIntersectionType.Front;
}
if (distance < 0)
{
return PlaneIntersectionType.Back;
}
return PlaneIntersectionType.Intersecting;
}
#endregion
#region Public Static Methods
public static Plane Normalize(Plane value)
{
Plane ret;
Normalize(value, out ret);
return ret;
}
public static void Normalize(Plane value, out Plane result)
{
float length = value.Normal.Length;
float factor = 1.0f / length;
result.Normal = Vector3.Multiply(value.Normal, factor);
result.D = value.D * factor;
}
/// <summary>
/// Transforms a normalized plane by a matrix.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed plane.</returns>
public static Plane Transform(Plane plane, Matrix4 matrix)
{
Plane result;
Transform(plane, matrix, out result);
return result;
}
/// <summary>
/// Transforms a normalized plane by a matrix.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <param name="result">The transformed plane.</param>
public static void Transform(
Plane plane,
Matrix4 matrix,
out Plane result
) {
/* See "Transforming Normals" in
* http://www.glprogramming.com/red/appendixf.html
* for an explanation of how this works.
*/
Matrix4 transformedMatrix;
transformedMatrix = Matrix4.Invert(matrix);
transformedMatrix = Matrix4.Transpose(transformedMatrix);
Vector4 vector = Vector4(plane.Normal, plane.D);
Vector4 transformedVector;
Vector4.Transform(
vector,
transformedMatrix,
out transformedVector
);
result = Plane(transformedVector);
}
/// <summary>
/// Transforms a normalized plane by a quaternion rotation.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="rotation">The quaternion rotation.</param>
/// <returns>The transformed plane.</returns>
public static Plane Transform(Plane plane, Quaternion rotation)
{
Plane result;
Transform(plane, rotation, out result);
return result;
}
/// <summary>
/// Transforms a normalized plane by a quaternion rotation.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="rotation">The quaternion rotation.</param>
/// <param name="result">The transformed plane.</param>
public static void Transform(
Plane plane,
Quaternion rotation,
out Plane result
) {
result.Normal = Vector3.Transform(
plane.Normal,
rotation
);
result.D = plane.D;
}
#endregion
#region Public Static Operators and Override Methods
public static bool operator !=(Plane plane1, Plane plane2)
{
return !plane1.Equals(plane2);
}
public static bool operator ==(Plane plane1, Plane plane2)
{
return plane1.Equals(plane2);
}
public bool Equals(Plane other)
{
return (Normal == other.Normal && D == other.D);
}
public int GetHashCode()
{
return Normal.GetHashCode() ^ D.GetHashCode();
}
public override void ToString(String str)
{
str.AppendF($"{Normal:{Normal} D:{D}}");
}
#endregion
}
}

View file

@ -1,3 +1,6 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
using System;
using Beefy.gfx;
@ -189,43 +192,50 @@ namespace Beefy.geom
public static void CreateFromRotationMatrix(ref Matrix4 matrix, out Quaternion result)
{
float num8 = (matrix.m11 + matrix.m22) + matrix.m33;
if (num8 > 0f)
{
float num = (float)Math.Sqrt((double)(num8 + 1f));
result.mW = num * 0.5f;
num = 0.5f / num;
result.mX = (matrix.m23 - matrix.m32) * num;
result.mY = (matrix.m31 - matrix.m13) * num;
result.mZ = (matrix.m12 - matrix.m21) * num;
}
else if ((matrix.m11 >= matrix.m22) && (matrix.m11 >= matrix.m33))
{
float num7 = (float)Math.Sqrt((double)(((1f + matrix.m11) - matrix.m22) - matrix.m33));
float num4 = 0.5f / num7;
result.mX = 0.5f * num7;
result.mY = (matrix.m12 + matrix.m21) * num4;
result.mZ = (matrix.m13 + matrix.m31) * num4;
result.mW = (matrix.m23 - matrix.m32) * num4;
}
else if (matrix.m22 > matrix.m33)
{
float num6 = (float)Math.Sqrt((double)(((1f + matrix.m22) - matrix.m11) - matrix.m33));
float num3 = 0.5f / num6;
result.mX = (matrix.m21 + matrix.m12) * num3;
result.mY = 0.5f * num6;
result.mZ = (matrix.m32 + matrix.m23) * num3;
result.mW = (matrix.m31 - matrix.m13) * num3;
}
else
{
float num5 = (float)Math.Sqrt((double)(((1f + matrix.m33) - matrix.m11) - matrix.m22));
float num2 = 0.5f / num5;
result.mX = (matrix.m31 + matrix.m13) * num2;
result.mY = (matrix.m32 + matrix.m23) * num2;
result.mZ = 0.5f * num5;
result.mW = (matrix.m12 - matrix.m21) * num2;
}
float sqrt;
float half;
float scale = matrix.m00 + matrix.m11 + matrix.m22;
if (scale > 0.0f)
{
sqrt = (float) Math.Sqrt(scale + 1.0f);
result.mW = sqrt * 0.5f;
sqrt = 0.5f / sqrt;
result.mX = (matrix.m21 - matrix.m12) * sqrt;
result.mY = (matrix.m02 - matrix.m20) * sqrt;
result.mZ = (matrix.m10 - matrix.m01) * sqrt;
}
else if ((matrix.m00 >= matrix.m11) && (matrix.m00 >= matrix.m22))
{
sqrt = (float) Math.Sqrt(1.0f + matrix.m00 - matrix.m11 - matrix.m22);
half = 0.5f / sqrt;
result.mX = 0.5f * sqrt;
result.mY = (matrix.m10 + matrix.m01) * half;
result.mZ = (matrix.m20 + matrix.m02) * half;
result.mW = (matrix.m21 - matrix.m12) * half;
}
else if (matrix.m11 > matrix.m22)
{
sqrt = (float) Math.Sqrt(1.0f + matrix.m11 - matrix.m00 - matrix.m22);
half = 0.5f/sqrt;
result.mX = (matrix.m01 + matrix.m10)*half;
result.mY = 0.5f*sqrt;
result.mZ = (matrix.m12 + matrix.m21)*half;
result.mW = (matrix.m02 - matrix.m20)*half;
}
else
{
sqrt = (float) Math.Sqrt(1.0f + matrix.m22 - matrix.m00 - matrix.m11);
half = 0.5f / sqrt;
result.mX = (matrix.m02 + matrix.m20) * half;
result.mY = (matrix.m12 + matrix.m21) * half;
result.mZ = 0.5f * sqrt;
result.mW = (matrix.m10 - matrix.m01) * half;
}
}
public static Quaternion CreateFromYawPitchRoll(float yaw, float pitch, float roll)

View file

@ -1,3 +1,6 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
using System;
using System.Collections;
using System.Text;
@ -131,7 +134,7 @@ namespace Beefy.geom
{
Vector3 newVec;
Normalize(vector, out newVec);
return vector;
return newVec;
}
public static void Normalize(Vector3 value, out Vector3 result)
@ -173,7 +176,7 @@ namespace Beefy.geom
return new Vector2D((float)Math.Cos(angle) * length, (float)Math.Sin(angle) * length);
}*/
public static Vector3 Transform(Vector3 vec, Matrix4 matrix)
public static Vector3 TransformW(Vector3 vec, Matrix4 matrix)
{
Vector3 result;
float fInvW = 1.0f / (matrix.m30 * vec.mX + matrix.m31 * vec.mY + matrix.m32 * vec.mZ + matrix.m33);
@ -181,9 +184,19 @@ namespace Beefy.geom
result.mX = (matrix.m00 * vec.mX + matrix.m01 * vec.mY + matrix.m02 * vec.mZ + matrix.m03) * fInvW;
result.mY = (matrix.m10 * vec.mX + matrix.m11 * vec.mY + matrix.m12 * vec.mZ + matrix.m13) * fInvW;
result.mZ = (matrix.m20 * vec.mX + matrix.m21 * vec.mY + matrix.m22 * vec.mZ + matrix.m23) * fInvW;
return result;
}
public static Vector3 Transform(Vector3 vec, Matrix4 matrix)
{
Vector3 result;
result.mX = (vec.mX * matrix.m00) + (vec.mY * matrix.m01) + (vec.mZ * matrix.m02) + matrix.m03;
result.mY = (vec.mX * matrix.m10) + (vec.mY * matrix.m11) + (vec.mZ * matrix.m12) + matrix.m13;
result.mZ = (vec.mX * matrix.m20) + (vec.mY * matrix.m21) + (vec.mZ * matrix.m22) + matrix.m23;
return result;
}
/*public static void Transform(Vector3[] sourceArray, ref Matrix4 matrix, Vector3[] destinationArray)
{
//Debug.Assert(destinationArray.Length >= sourceArray.Length, "The destination array is smaller than the source array.");
@ -199,6 +212,51 @@ namespace Beefy.geom
}
}*/
/// <summary>
/// Returns a <see>Vector3</see> pointing in the opposite
/// direction of <paramref name="value"/>.
/// </summary>
/// <param name="value">The vector to negate.</param>
/// <returns>The vector negation of <paramref name="value"/>.</returns>
public static Vector3 Negate(Vector3 value)
{
return .(-value.mX, -value.mY, -value.mZ);
}
/// <summary>
/// Stores a <see>Vector3</see> pointing in the opposite
/// direction of <paramref name="value"/> in <paramref name="result"/>.
/// </summary>
/// <param name="value">The vector to negate.</param>
/// <param name="result">The vector that the negation of <paramref name="value"/> will be stored in.</param>
public static void Negate(Vector3 value, out Vector3 result)
{
result.mX = -value.mX;
result.mY = -value.mY;
result.mZ = -value.mZ;
}
/// <summary>
/// Creates a new <see cref="Vector3"/> that contains a multiplication of two vectors.
/// </summary>
/// <param name="value1">Source <see cref="Vector3"/>.</param>
/// <param name="value2">Source <see cref="Vector3"/>.</param>
/// <returns>The result of the vector multiplication.</returns>
public static Vector3 Multiply(Vector3 value1, Vector3 value2)
{
return .(value1.mX * value2.mX, value1.mY * value2.mY, value1.mZ * value2.mZ);
}
public static Vector3 Multiply(Vector3 value1, float value2)
{
return .(value1.mX * value2, value1.mY * value2, value1.mZ * value2);
}
public void Normalize() mut
{
Normalize(this, out this);
}
public static Vector3 Transform(Vector3 vec, Quaternion quat)
{
Matrix4 matrix = quat.ToMatrix();
@ -234,6 +292,11 @@ namespace Beefy.geom
return Vector3(vec1.mX - vec2.mX, vec1.mY - vec2.mY, vec1.mZ - vec2.mZ);
}
public static Vector3 operator -(Vector3 vec1)
{
return Vector3(-vec1.mX, -vec1.mY, -vec1.mZ);
}
public static Vector3 operator *(Vector3 vec, float scale)
{
return Vector3(vec.mX * scale, vec.mY * scale, vec.mZ * scale);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,59 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
using Beefy.geom;
using System.Diagnostics;
namespace Beefy.geom
{
struct Viewport
{
private int mX;
private int mY;
private int mWidth;
private int mHeight;
private float mMinDepth;
private float mMaxDepth;
public this(int x, int y, int width, int height,float minDepth,float maxDepth)
{
this.mX = x;
this.mY = y;
this.mWidth = width;
this.mHeight = height;
this.mMinDepth = minDepth;
this.mMaxDepth = maxDepth;
}
/// Unprojects a Vector3 from screen space into world space.
/// @param source The Vector3 to unproject.
/// @param projection The projection
/// @param view The view
/// @param world The world
public Vector3 Unproject(Vector3 source, Matrix4 projection, Matrix4 view, Matrix4 world)
{
var source;
Matrix4 matrix = Matrix4.Invert(Matrix4.Multiply(Matrix4.Multiply(world, view), projection));
source.mX = (((source.mX - this.mX) / ((float) this.mWidth)) * 2f) - 1f;
source.mY = -((((source.mY - this.mY) / ((float) this.mHeight)) * 2f) - 1f);
source.mZ = (source.mZ - this.mMinDepth) / (this.mMaxDepth - this.mMinDepth);
Vector3 vector = Vector3.Transform(source, matrix);
float a = (((source.mX * matrix.m30) + (source.mY * matrix.m31)) + (source.mZ * matrix.m32)) + matrix.m33;
if (!WithinEpsilon(a, 1f))
{
vector.mX = vector.mX / a;
vector.mY = vector.mY / a;
vector.mZ = vector.mZ / a;
}
return vector;
}
private static bool WithinEpsilon(float a, float b)
{
float num = a - b;
return ((-1.401298E-45f <= num) && (num <= float.Epsilon));
}
}
}

View file

@ -442,7 +442,10 @@ namespace Beefy.gfx
//static unsafe extern void Gfx_DrawIndexedVertices2D(void* vtxData, int vtxCount, int* idxData, int idxCount, float a, float b, float c, float d, float tx, float ty, float z);
[CallingConvention(.Stdcall), CLink]
static extern void Gfx_DrawIndexedVertices2D(int32 vertexSize, void* vtxData, int32 vtxCount, uint16* idxData, int32 idxCount, float a, float b, float c, float d, float tx, float ty, float z);
static extern void Gfx_DrawIndexedVertices(int32 vertexSize, void* vtxData, int32 vtxCount, uint16* idxData, int32 idxCount);
[CallingConvention(.Stdcall), CLink]
static extern void Gfx_DrawIndexedVertices2D(int32 vertexSize, void* vtxData, int32 vtxCount, uint16* idxData, int32 idxCount, float a, float b, float c, float d, float tx, float ty, float z);
[CallingConvention(.Stdcall), CLink]
static extern void Gfx_SetShaderConstantData(int32 usageIdx, int32 slotIdx, void* data, int32 size);
@ -794,14 +797,28 @@ namespace Beefy.gfx
public void DrawIndexedVertices(VertexDefinition vertexDef, void* vertices, int vtxCount, uint16[] indices)
{
Gfx_DrawIndexedVertices2D(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices.CArray(), (int32)indices.Count,
mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth);
if (vertexDef.mPosition2DOffset != -1)
{
Gfx_DrawIndexedVertices2D(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices.CArray(), (int32)indices.Count,
mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth);
}
else
{
Gfx_DrawIndexedVertices(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices.CArray(), (int32)indices.Count);
}
}
public void DrawIndexedVertices(VertexDefinition vertexDef, void* vertices, int vtxCount, uint16* indices, int idxCount)
{
Gfx_DrawIndexedVertices2D(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices, (int32)idxCount,
mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth);
if (vertexDef.mPosition2DOffset != -1)
{
Gfx_DrawIndexedVertices2D(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices, (int32)idxCount,
mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth);
}
else
{
Gfx_DrawIndexedVertices(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices, (int32)idxCount);
}
}
public void SetVertexShaderConstantData(int slotIdx, void* data, int size)

View file

@ -48,7 +48,13 @@ namespace Beefy.gfx
#if !STUDIO_CLIENT
extension ModelDef
{
{
public enum ModelCreateFlags
{
None = 0,
NoSetRenderState = 1
}
public class Animation
{
public void* mNativeModelDefAnimation;
@ -103,11 +109,20 @@ namespace Beefy.gfx
extern static void* Res_OpenModel(char8* fileName, char8* baseDir, void* nativeVertexDef);
[CallingConvention(.Stdcall), CLink]
extern static void* ModelDef_CreateModelInstance(void* nativeModel);
extern static void* ModelDef_CreateModelInstance(void* nativeModel, ModelCreateFlags flags);
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_Compact(void* nativeModel);
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_SetBaseDir(void* nativeModel, char8* baseDir);
[CallingConvention(.Stdcall), CLink]
extern static char8* ModelDef_GetInfo(void* nativeModel);
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_GetBounds(void* nativeModel, out Vector3 min, out Vector3 max);
[CallingConvention(.Stdcall), CLink]
extern static float ModelDef_GetFrameRate(void* nativeModel);
@ -123,6 +138,9 @@ namespace Beefy.gfx
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_SetTextures(void* nativeModel, int32 meshIdx, int32 primitivesIdx, char8** paths, int32 pathCount);
[CallingConvention(.Stdcall), CLink]
extern static bool ModelDef_RayIntersect(void* nativeModel, Matrix4 worldMtx, Vector3 origin, Vector3 vec, out Vector3 outIntersect, out float outDistance);
[CallingConvention(.Stdcall), CLink]
extern static Span<uint8> Res_SerializeModel(void* nativeModel);
@ -147,20 +165,20 @@ namespace Beefy.gfx
public static ModelDef LoadModel(String fileName, String baseDir)
{
void* nativeModelDef = null;
if (fileName.EndsWith(".bfm", .OrdinalIgnoreCase))
nativeModelDef = Res_OpenModel(fileName, baseDir, VertexDef.sVertexDefinition.mNativeVertexDefinition);
if (fileName.EndsWith(".gltf", .OrdinalIgnoreCase))
nativeModelDef = Res_OpenGLTF(fileName, baseDir, VertexDef.sVertexDefinition.mNativeVertexDefinition);
else if (fileName.EndsWith(".fbx", .OrdinalIgnoreCase))
nativeModelDef = Res_OpenFBX(fileName, VertexDef.sVertexDefinition.mNativeVertexDefinition);
else
nativeModelDef = Res_OpenGLTF(fileName, baseDir, VertexDef.sVertexDefinition.mNativeVertexDefinition);
nativeModelDef = Res_OpenModel(fileName, baseDir, VertexDef.sVertexDefinition.mNativeVertexDefinition);
if (nativeModelDef == null)
return null;
return new ModelDef(nativeModelDef);
}
public ModelInstance CreateInstance()
public ModelInstance CreateInstance(ModelCreateFlags flags = .None)
{
void* nativeModelInstance = ModelDef_CreateModelInstance(mNativeModelDef);
void* nativeModelInstance = ModelDef_CreateModelInstance(mNativeModelDef, flags);
if (nativeModelInstance == null)
return null;
var modelInstance = new ModelInstance(nativeModelInstance, this);
@ -177,6 +195,21 @@ namespace Beefy.gfx
str.Append(ModelDef_GetInfo(mNativeModelDef));
}
public void GetBounds(out Vector3 min, out Vector3 max)
{
ModelDef_GetBounds(mNativeModelDef, out min, out max);
}
public void Compact()
{
ModelDef_Compact(mNativeModelDef);
}
public void SetBaseDir(StringView baseDir)
{
ModelDef_SetBaseDir(mNativeModelDef, baseDir.ToScopeCStr!());
}
public void SetTextures(int meshIdx, int primitivesIdx, Span<char8*> paths)
{
ModelDef_SetTextures(mNativeModelDef, (.)meshIdx, (.)primitivesIdx, paths.Ptr, (.)paths.Length);
@ -187,6 +220,11 @@ namespace Beefy.gfx
var span = Res_SerializeModel(mNativeModelDef);
data.AddRange(span);
}
public bool RayIntersect(Matrix4 worldMtx, Vector3 origin, Vector3 vec, out Vector3 outIntersect, out float outDistance)
{
return ModelDef_RayIntersect(mNativeModelDef, worldMtx, origin, vec, out outIntersect, out outDistance);
}
}
public class ModelInstance : RenderCmd

View file

@ -19,6 +19,12 @@ namespace Beefy.gfx
Always
}
public enum Topology
{
TriangleList,
LineList
}
#if !STUDIO_CLIENT
public class RenderState
{
@ -34,6 +40,9 @@ namespace Beefy.gfx
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetTexWrap(void* renderState, bool texWrap);
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetWireframe(void* renderState, bool wireframe);
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_DisableClip(void* renderState);
@ -46,6 +55,9 @@ namespace Beefy.gfx
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetDepthWrite(void* nativeRenderState, int32 depthWrite);
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetTopology(void* nativeRenderState, int32 topology);
public void* mNativeRenderState;
public bool mIsFromDefaultRenderState;
@ -115,6 +127,22 @@ namespace Beefy.gfx
RenderState_SetTexWrap(mNativeRenderState, value);
}
}
public bool Wireframe
{
set
{
RenderState_SetWireframe(mNativeRenderState, value);
}
}
public Topology Topology
{
set
{
RenderState_SetTopology(mNativeRenderState, (.)value);
}
}
}
#else
public class RenderState