8 Commits

11 changed files with 203 additions and 98 deletions

View File

@@ -1,12 +1,11 @@
using System; using System;
using System.Numerics;
namespace Engine.Core; namespace Engine.Core;
// TODO Comments // TODO Comments
/// <summary> /// <summary>
/// Represents a 4D left handed space matrix. /// Represents a 4D left handed space matrix in a Column Major convention.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Initializes a new instance of the <see cref="Matrix4x4"/> struct with the specified values. /// Initializes a new instance of the <see cref="Matrix4x4"/> struct with the specified values.
@@ -67,6 +66,11 @@ public readonly struct Matrix4x4(
/// </summary> /// </summary>
public Matrix4x4 Inverse => Invert(this); public Matrix4x4 Inverse => Invert(this);
/// <summary>
/// Represents the transposed version of this <see cref="Matrix4x4"/>.
/// </summary>
public Matrix4x4 Transposed => Transpose(this);
public static Matrix4x4 operator *(Matrix4x4 a, Matrix4x4 b) => new( public static Matrix4x4 operator *(Matrix4x4 a, Matrix4x4 b) => new(
a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31 + a.M14 * b.M41, a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31 + a.M14 * b.M41,
a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32 + a.M14 * b.M42, a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32 + a.M14 * b.M42,
@@ -89,6 +93,13 @@ public readonly struct Matrix4x4(
a.M41 * b.M14 + a.M42 * b.M24 + a.M43 * b.M34 + a.M44 * b.M44 a.M41 * b.M14 + a.M42 * b.M24 + a.M43 * b.M34 + a.M44 * b.M44
); );
public static Vector4D operator *(Matrix4x4 m, Vector4D v) => new(
m.M11 * v.X + m.M12 * v.Y + m.M13 * v.Z + m.M14 * v.W,
m.M21 * v.X + m.M22 * v.Y + m.M23 * v.Z + m.M24 * v.W,
m.M31 * v.X + m.M32 * v.Y + m.M33 * v.Z + m.M34 * v.W,
m.M41 * v.X + m.M42 * v.Y + m.M43 * v.Z + m.M44 * v.W
);
public static bool operator ==(Matrix4x4 left, Matrix4x4 right) => public static bool operator ==(Matrix4x4 left, Matrix4x4 right) =>
left.M11 == right.M11 && left.M12 == right.M12 && left.M13 == right.M13 && left.M14 == right.M14 && left.M11 == right.M11 && left.M12 == right.M12 && left.M13 == right.M13 && left.M14 == right.M14 &&
left.M21 == right.M21 && left.M22 == right.M22 && left.M23 == right.M23 && left.M24 == right.M24 && left.M21 == right.M21 && left.M22 == right.M22 && left.M23 == right.M23 && left.M24 == right.M24 &&
@@ -202,11 +213,23 @@ public readonly struct Matrix4x4(
); );
} }
/// <summary>
/// Transposes the given <see cref="Matrix4x4"/>.
/// </summary>
/// <param name="m">The <see cref="Matrix4x4"/>.</param>
/// <returns>The transposed <see cref="Matrix4x4"/> of the given <see cref="Matrix4x4"/>.</returns>
public static Matrix4x4 Transpose(Matrix4x4 m) => new(
m.M11, m.M21, m.M31, m.M41,
m.M12, m.M22, m.M32, m.M42,
m.M13, m.M23, m.M33, m.M43,
m.M14, m.M24, m.M34, m.M44
);
public static Matrix4x4 CreateTranslation(Vector3D position) => new( public static Matrix4x4 CreateTranslation(Vector3D position) => new(
1f, 0f, 0f, 0f, 1f, 0f, 0f, position.X,
0f, 1f, 0f, 0f, 0f, 1f, 0f, position.Y,
0f, 0f, 1f, 0f, 0f, 0f, 1f, position.Z,
position.X, position.Y, position.Z, 1 0f, 0f, 0f, 1f
); );
public static Matrix4x4 CreateScale(float scale) => new( public static Matrix4x4 CreateScale(float scale) => new(
@@ -228,10 +251,10 @@ public readonly struct Matrix4x4(
float c = Math.Cos(radians); float c = Math.Cos(radians);
float s = Math.Sin(radians); float s = Math.Sin(radians);
return new Matrix4x4( return new(
1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f,
0f, c, s, 0f, 0f, c, -s, 0f,
0f, -s, c, 0f, 0f, s, c, 0f,
0f, 0f, 0f, 1f 0f, 0f, 0f, 1f
); );
} }
@@ -241,10 +264,10 @@ public readonly struct Matrix4x4(
float c = Math.Cos(radians); float c = Math.Cos(radians);
float s = Math.Sin(radians); float s = Math.Sin(radians);
return new Matrix4x4( return new(
c, 0f, -s, 0f, c, 0f, s, 0f,
0f, 1f, 0f, 0f, 0f, 1f, 0f, 0f,
s, 0f, c, 0f, -s, 0f, c, 0f,
0f, 0f, 0f, 1f 0f, 0f, 0f, 1f
); );
} }
@@ -254,9 +277,9 @@ public readonly struct Matrix4x4(
float c = Math.Cos(radians); float c = Math.Cos(radians);
float s = Math.Sin(radians); float s = Math.Sin(radians);
return new Matrix4x4( return new(
c, s, 0f, 0f, c, -s, 0f, 0f,
-s, c, 0f, 0f, s, c, 0f, 0f,
0f, 0f, 1f, 0f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f 0f, 0f, 0f, 1f
); );
@@ -275,7 +298,7 @@ public readonly struct Matrix4x4(
Vector3D x = up.Cross(z).Normalized; Vector3D x = up.Cross(z).Normalized;
Vector3D y = z.Cross(x); Vector3D y = z.Cross(x);
return new Matrix4x4( return new(
x.X, y.X, z.X, 0f, x.X, y.X, z.X, 0f,
x.Y, y.Y, z.Y, 0f, x.Y, y.Y, z.Y, 0f,
x.Z, y.Z, z.Z, 0f, x.Z, y.Z, z.Z, 0f,
@@ -285,28 +308,53 @@ public readonly struct Matrix4x4(
public static Matrix4x4 CreateLookMatrix(Vector3D position, Vector3D target, Vector3D up) public static Matrix4x4 CreateLookMatrix(Vector3D position, Vector3D target, Vector3D up)
{ {
Vector3D z = position.FromTo(target).Normalized; Vector3D f = (target - position).Normalized;
Vector3D x = up.Cross(z).Normalized; Vector3D s = f.Cross(up).Normalized;
Vector3D y = z.Cross(x); Vector3D u = s.Cross(f);
return new Matrix4x4( return new(
x.X, y.X, z.X, 0f, s.X, u.X, -f.X, 0f,
x.Y, y.Y, z.Y, 0f, s.Y, u.Y, -f.Y, 0f,
x.Z, y.Z, z.Z, 0f, s.Z, u.Z, -f.Z, 0f,
-x.Dot(position), -y.Dot(position), -z.Dot(position), 1f -s.Dot(position), -u.Dot(position), f.Dot(position), 1f
); );
} }
public static Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfViewInRadians, float aspectRatio, float nearPlane, float farPlane) public static Matrix4x4 CreateOrthographicView(float width, float height, float nearPlane = -1f, float farPlane = 1f)
{ {
float yScale = 1f / Math.Tan(fieldOfViewInRadians / 2f); float invDepth = 1f / (farPlane - nearPlane);
float xScale = yScale / aspectRatio;
return new Matrix4x4( return new(
2f / width, 0f, 0f, 0f,
0f, -2f / height, 0f, 0f,
0f, 0f, 1f * invDepth, 0f,
-1f, 1f, -nearPlane * invDepth, 1f
);
}
public static Matrix4x4 CreateOrthographicViewCentered(float width, float height, float nearPlane = -1f, float farPlane = 1f)
{
float invDepth = 1f / (farPlane - nearPlane);
return new(
2f / width, 0f, 0f, 0f,
0f, 2f / height, 0f, 0f,
0f, 0f, 1f * invDepth, 0f,
0f, 0f, -nearPlane * invDepth, 1f
);
}
public static Matrix4x4 CreatePerspectiveFieldOfView(float fovRadians, float aspectRatio, float nearPlane, float farPlane)
{
float yScale = 1f / Math.Tan(fovRadians / 2f);
float xScale = yScale / aspectRatio;
float zRange = farPlane - nearPlane;
return new(
xScale, 0f, 0f, 0f, xScale, 0f, 0f, 0f,
0f, yScale, 0f, 0f, 0f, yScale, 0f, 0f,
0f, 0f, farPlane / (farPlane - nearPlane), 1f, 0f, 0f, -(farPlane + nearPlane) / zRange, -1f,
0f, 0f, -nearPlane * farPlane / (farPlane - nearPlane), 0f 0f, 0f, -(2f * nearPlane * farPlane) / zRange, 0f
); );
} }
@@ -344,11 +392,14 @@ public static class Matrix4x4Extensions
/// <inheritdoc cref="Matrix4x4.Invert(Matrix4x4)" /> /// <inheritdoc cref="Matrix4x4.Invert(Matrix4x4)" />
public static Matrix4x4 Invert(this Matrix4x4 matrix) => Matrix4x4.Invert(matrix); public static Matrix4x4 Invert(this Matrix4x4 matrix) => Matrix4x4.Invert(matrix);
/// <inheritdoc cref="Matrix4x4.Transpose(Matrix4x4)" />
public static Matrix4x4 Transpose(this Matrix4x4 matrix) => Matrix4x4.Transpose(matrix);
/// <inheritdoc cref="Matrix4x4.CreateTranslation(Vector3D)" /> /// <inheritdoc cref="Matrix4x4.CreateTranslation(Vector3D)" />
public static Matrix4x4 ApplyTranslation(this Matrix4x4 matrix, Vector3D translation) => matrix * Matrix4x4.CreateTranslation(translation); public static Matrix4x4 ApplyTranslation(this Matrix4x4 matrix, Vector3D translation) => matrix * Matrix4x4.CreateTranslation(translation);
/// <inheritdoc cref="Matrix4x4.CreateScale(Vector3D)" /> /// <inheritdoc cref="Matrix4x4.CreateScale(Vector3D)" />
public static Matrix4x4 ApplyScale(this Matrix4x4 matrix, Vector3 scale) => matrix * Matrix4x4.CreateScale(scale); public static Matrix4x4 ApplyScale(this Matrix4x4 matrix, Vector3D scale) => matrix * Matrix4x4.CreateScale(scale);
/// <inheritdoc cref="Matrix4x4.CreateScale(float)" /> /// <inheritdoc cref="Matrix4x4.CreateScale(float)" />
public static Matrix4x4 ApplyScale(this Matrix4x4 matrix, float scale) => matrix * Matrix4x4.CreateScale(scale); public static Matrix4x4 ApplyScale(this Matrix4x4 matrix, float scale) => matrix * Matrix4x4.CreateScale(scale);
@@ -366,15 +417,23 @@ public static class Matrix4x4Extensions
public static Matrix4x4 ApplyRotation(this Matrix4x4 matrix, Quaternion quaternion) => matrix * Matrix4x4.CreateRotation(quaternion); public static Matrix4x4 ApplyRotation(this Matrix4x4 matrix, Quaternion quaternion) => matrix * Matrix4x4.CreateRotation(quaternion);
/// <inheritdoc cref="Matrix4x4.CreateLookMatrix( Vector3D, Vector3D)" /> /// <inheritdoc cref="Matrix4x4.CreateLookMatrix( Vector3D, Vector3D)" />
public static Matrix4x4 ApplyLookRotationTo(this Matrix4x4 matrix, Vector3D forward, Vector3 up) => matrix * Matrix4x4.CreateLookMatrix(forward, up); public static Matrix4x4 ApplyLookRotationTo(this Matrix4x4 matrix, Vector3D forward, Vector3D up) => matrix * Matrix4x4.CreateLookMatrix(forward, up);
/// <inheritdoc cref="Matrix4x4.CreateLookMatrix(Vector3D, Vector3D, Vector3D)" /> /// <inheritdoc cref="Matrix4x4.CreateLookMatrix(Vector3D, Vector3D, Vector3D)" />
public static Matrix4x4 CreateLookMatrixTo(this Vector3D from, Vector3D to, Vector3 up) => Matrix4x4.CreateLookMatrix(from, to, up); public static Matrix4x4 CreateLookMatrixTo(this Vector3D from, Vector3D to, Vector3D up) => Matrix4x4.CreateLookMatrix(from, to, up);
/// <inheritdoc cref="Matrix4x4.CreatePerspectiveFieldOfView(float, float, float, float)" /> /// <inheritdoc cref="Matrix4x4.CreatePerspectiveFieldOfView(float, float, float, float)" />
public static Matrix4x4 ApplyPerspectiveFieldOfView(this Matrix4x4 matrix, float fieldOfViewInRadians, float aspectRatio, float nearPlane, float farPlane) public static Matrix4x4 ApplyPerspectiveFieldOfView(this Matrix4x4 matrix, float fieldOfViewInRadians, float aspectRatio, float nearPlane, float farPlane)
=> matrix * Matrix4x4.CreatePerspectiveFieldOfView(fieldOfViewInRadians, aspectRatio, nearPlane, farPlane); => matrix * Matrix4x4.CreatePerspectiveFieldOfView(fieldOfViewInRadians, aspectRatio, nearPlane, farPlane);
/// <inheritdoc cref="Matrix4x4.CreateOrthographicView(float, float, float, float)" />
public static Matrix4x4 ApplyOrthographicView(this Matrix4x4 matrix, float width, float height, float nearPlane = -1f, float farPlane = 1f)
=> matrix * Matrix4x4.CreateOrthographicView(width, height, nearPlane, farPlane);
/// <inheritdoc cref="Matrix4x4.CreateOrthographicViewCentered(float, float, float, float)" />
public static Matrix4x4 ApplyOrthographicViewCentered(this Matrix4x4 matrix, float width, float height, float nearPlane = -1f, float farPlane = 1f)
=> matrix * Matrix4x4.CreateOrthographicViewCentered(width, height, nearPlane, farPlane);
/// <inheritdoc cref="Matrix4x4.ToRightHanded(Matrix4x4) /> /// <inheritdoc cref="Matrix4x4.ToRightHanded(Matrix4x4) />
public static Matrix4x4 ToRightHanded(this Matrix4x4 matrix) => Matrix4x4.ToRightHanded(matrix); public static Matrix4x4 ToRightHanded(this Matrix4x4 matrix) => Matrix4x4.ToRightHanded(matrix);
} }

View File

@@ -82,11 +82,19 @@ public readonly struct Vector2D(float x, float y) : IEquatable<Vector2D>
public static bool operator ==(Vector2D left, Vector2D right) => left.X == right.X && left.Y == right.Y; public static bool operator ==(Vector2D left, Vector2D right) => left.X == right.X && left.Y == right.Y;
public static bool operator !=(Vector2D left, Vector2D right) => left.X != right.X || left.Y != right.Y; public static bool operator !=(Vector2D left, Vector2D right) => left.X != right.X || left.Y != right.Y;
public static implicit operator System.Numerics.Vector2(Vector2D vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(Vector2DInt vector) => new(vector.X, vector.Y); public static implicit operator Vector2D(Vector2DInt vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(Vector3D vector) => new(vector.X, vector.Y); public static implicit operator Vector2D(Vector3DInt vector) => new(vector.X, vector.Y);
public static implicit operator System.Numerics.Vector2(Vector2D vector) => new(vector.X, vector.Y);
public static implicit operator System.Numerics.Vector3(Vector2D vector) => new(vector.X, vector.Y, 0f);
public static implicit operator System.Numerics.Vector4(Vector2D vector) => new(vector.X, vector.Y, 0f, 0f);
public static implicit operator Vector2D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y); public static implicit operator Vector2D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(System.Numerics.Vector4 vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(Vector3D vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(Vector4D vector) => new(vector.X, vector.Y);
/// <summary> /// <summary>
/// Calculates the length of the <see cref="Vector2D"/>. /// Calculates the length of the <see cref="Vector2D"/>.

View File

@@ -74,9 +74,12 @@ public readonly struct Vector2DInt(int x, int y) : IEquatable<Vector2DInt>
public static bool operator ==(Vector2DInt left, Vector2DInt right) => left.X == right.X && left.Y == right.Y; public static bool operator ==(Vector2DInt left, Vector2DInt right) => left.X == right.X && left.Y == right.Y;
public static bool operator !=(Vector2DInt left, Vector2DInt right) => left.X != right.X || left.Y != right.Y; public static bool operator !=(Vector2DInt left, Vector2DInt right) => left.X != right.X || left.Y != right.Y;
public static implicit operator Vector2DInt(Vector2D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt());
public static implicit operator Vector2DInt(Vector3DInt vector) => new(vector.X, vector.Y); public static implicit operator Vector2DInt(Vector3DInt vector) => new(vector.X, vector.Y);
public static implicit operator Vector2DInt(Vector2D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt());
public static implicit operator Vector2DInt(Vector3D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt());
public static implicit operator Vector2DInt(Vector4D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt());
/// <summary> /// <summary>
/// Calculates the length of the <see cref="Vector2DInt"/>. /// Calculates the length of the <see cref="Vector2DInt"/>.
/// </summary> /// </summary>

View File

@@ -92,11 +92,19 @@ public readonly struct Vector3D(float x, float y, float z) : IEquatable<Vector3D
public static bool operator ==(Vector3D left, Vector3D right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z; public static bool operator ==(Vector3D left, Vector3D right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
public static bool operator !=(Vector3D left, Vector3D right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z; public static bool operator !=(Vector3D left, Vector3D right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
public static implicit operator System.Numerics.Vector3(Vector3D vector) => new(vector.X, vector.Y, vector.Z); public static implicit operator Vector3D(Vector2DInt vector) => new(vector.X, vector.Y, 0f);
public static implicit operator Vector3D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator Vector3D(Vector3DInt vector) => new(vector.X, vector.Y, vector.Z); public static implicit operator Vector3D(Vector3DInt vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator Vector3D(Vector2D vector) => new(vector.X, vector.Y, 0f);
public static implicit operator System.Numerics.Vector2(Vector3D vector) => new(vector.X, vector.Y);
public static implicit operator System.Numerics.Vector3(Vector3D vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator System.Numerics.Vector4(Vector3D vector) => new(vector.X, vector.Y, vector.Z, 0f);
public static implicit operator Vector3D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y, 0f); public static implicit operator Vector3D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y, 0f);
public static implicit operator Vector3D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator Vector3D(System.Numerics.Vector4 vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator Vector3D(Vector2D vector) => new(vector.X, vector.Y, 0f);
public static implicit operator Vector3D(Vector4D vector) => new(vector.X, vector.Y, vector.Z);
/// <summary> /// <summary>
/// Calculates the length of the <see cref="Vector3D"/>. /// Calculates the length of the <see cref="Vector3D"/>.

View File

@@ -84,9 +84,12 @@ public readonly struct Vector3DInt(int x, int y, int z) : IEquatable<Vector3DInt
public static bool operator ==(Vector3DInt left, Vector3DInt right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z; public static bool operator ==(Vector3DInt left, Vector3DInt right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
public static bool operator !=(Vector3DInt left, Vector3DInt right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z; public static bool operator !=(Vector3DInt left, Vector3DInt right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
public static implicit operator Vector3DInt(Vector3D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt(), vector.Z.RoundToInt());
public static implicit operator Vector3DInt(Vector2DInt vector) => new(vector.X, vector.Y, 0); public static implicit operator Vector3DInt(Vector2DInt vector) => new(vector.X, vector.Y, 0);
public static implicit operator Vector3DInt(Vector2D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt(), 0);
public static implicit operator Vector3DInt(Vector3D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt(), vector.Z.RoundToInt());
public static implicit operator Vector3DInt(Vector4D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt(), vector.Z.RoundToInt());
/// <summary> /// <summary>
/// Calculates the length of the <see cref="Vector3DInt"/>. /// Calculates the length of the <see cref="Vector3DInt"/>.
/// </summary> /// </summary>

View File

@@ -90,9 +90,20 @@ public readonly struct Vector4D(float x, float y, float z, float w) : IEquatable
public static bool operator ==(Vector4D left, Vector4D right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W; public static bool operator ==(Vector4D left, Vector4D right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W;
public static bool operator !=(Vector4D left, Vector4D right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W; public static bool operator !=(Vector4D left, Vector4D right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W;
public static implicit operator Vector4D(Vector2DInt vector) => new(vector.X, vector.Y, 0f, 0f);
public static implicit operator Vector4D(Vector3DInt vector) => new(vector.X, vector.Y, vector.Z, 0f);
public static implicit operator System.Numerics.Vector2(Vector4D vector) => new(vector.X, vector.Y);
public static implicit operator System.Numerics.Vector3(Vector4D vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator System.Numerics.Vector4(Vector4D vector) => new(vector.X, vector.Y, vector.Z, vector.W); public static implicit operator System.Numerics.Vector4(Vector4D vector) => new(vector.X, vector.Y, vector.Z, vector.W);
public static implicit operator Vector4D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y, 0f, 0f);
public static implicit operator Vector4D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y, vector.Z, 0f);
public static implicit operator Vector4D(System.Numerics.Vector4 vector) => new(vector.X, vector.Y, vector.Z, vector.W); public static implicit operator Vector4D(System.Numerics.Vector4 vector) => new(vector.X, vector.Y, vector.Z, vector.W);
public static implicit operator Vector4D(Vector2D vector) => new(vector.X, vector.Y, 0f, 0f);
public static implicit operator Vector4D(Vector3D vector) => new(vector.X, vector.Y, vector.Z, 0f);
/// <summary> /// <summary>
/// Calculates the length of the <see cref="Vector4D"/>. /// Calculates the length of the <see cref="Vector4D"/>.
/// </summary> /// </summary>

View File

@@ -72,13 +72,34 @@ public class MonoGameCamera2D : Behaviour, ICamera2D, IFirstFrameUpdate, ILastFr
// TODO This causes delay since OnPreDraw calls assuming this is called in in Update // TODO This causes delay since OnPreDraw calls assuming this is called in in Update
public Vector2D ScreenToWorldPosition(Vector2D screenPosition) public Vector2D ScreenToWorldPosition(Vector2D screenPosition)
{ {
Vector2D worldPosition = Vector2.Transform(screenPosition.ToVector2(), ViewMatrix.Inverse.ToXnaMatrix()).ToVector2D(); float x = 2f * screenPosition.X / Viewport.Width - 1f;
return worldPosition.Scale(EngineConverterExtensions.screenScale); float y = 1f - 2f * screenPosition.Y / Viewport.Height;
Vector4D normalizedCoordinates = new(x, y, 0f, 1f);
Matrix4x4 invertedViewProjectionMatrix = (ProjectionMatrix * ViewMatrix).Inverse;
Vector4D worldPosition = invertedViewProjectionMatrix * normalizedCoordinates;
if (worldPosition.W != 0f)
worldPosition /= worldPosition.W;
return new(worldPosition.X, worldPosition.Y);
} }
public Vector2D WorldToScreenPosition(Vector2D worldPosition) public Vector2D WorldToScreenPosition(Vector2D worldPosition)
{ {
Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), ViewMatrix.ToXnaMatrix()).ToVector2D(); Vector4D worldPosition4D = new(worldPosition.X, worldPosition.Y, 0f, 1f);
return screenPosition.Scale(EngineConverterExtensions.screenScale);
Matrix4x4 viewProjection = ProjectionMatrix * ViewMatrix;
Vector4D clip = viewProjection * worldPosition4D;
if (clip.W != 0f)
clip /= clip.W;
float screenX = (clip.X + 1f) * .5f * Viewport.Width;
float screenY = (1f - clip.Y) * .5f * Viewport.Height;
return new(screenX, screenY);
} }
public void LastActiveFrame() => Transform = null!; public void LastActiveFrame() => Transform = null!;
@@ -91,12 +112,11 @@ public class MonoGameCamera2D : Behaviour, ICamera2D, IFirstFrameUpdate, ILastFr
public void PreDraw() public void PreDraw()
{ {
ProjectionMatrix = Matrix.CreateOrthographicOffCenter(Viewport.X, Viewport.Width, Viewport.Height, Viewport.Y, 0, 1).FromXnaMatrix(); ProjectionMatrix = Matrix4x4.CreateOrthographicViewCentered(Viewport.Width, Viewport.Height);
ViewMatrix = ViewMatrix =
Matrix4x4.CreateTranslation(new Vector3D(-Transform.Position.X, Transform.Position.Y, 0f)) * Matrix4x4.CreateTranslation(new Vector3D(-Transform.Position.X, -Transform.Position.Y, 0f))
Matrix4x4.CreateRotationZ(Transform.Rotation * Math.DegreeToRadian) * .ApplyRotationZ(Transform.Rotation * Math.DegreeToRadian)
Matrix4x4.CreateScale(Transform.Scale.X.Max(Transform.Scale.Y)) * .ApplyScale(Transform.Scale.X.Max(Transform.Scale.Y))
Matrix4x4.CreateScale(Zoom) * .ApplyScale(Zoom);
Matrix4x4.CreateTranslation(new Vector3D(Viewport.Width * .5f, Viewport.Height * .5f, 0f));
} }
} }

View File

@@ -15,49 +15,49 @@ public class SpriteBatchWrapper(GraphicsDevice graphicsDevice) : ISpriteBatch
=> spriteBatch.Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState, effect, transformMatrix); => spriteBatch.Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState, effect, transformMatrix);
public void Draw(Texture2D texture, Vector2D position, AABB2D? sourceAABB, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth) public void Draw(Texture2D texture, Vector2D position, AABB2D? sourceAABB, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth)
=> spriteBatch.Draw(texture, position.ToDisplayVector2(), sourceAABB?.ToRectangle(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth); => spriteBatch.Draw(texture, position.ToVector2(), sourceAABB?.ToRectangle(), color, rotation, origin.ToVector2(), scale.ToVector2(), effects, layerDepth);
public void Draw(Texture2D texture, Vector2D position, AABB2D? sourceAABB, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth) public void Draw(Texture2D texture, Vector2D position, AABB2D? sourceAABB, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth)
=> spriteBatch.Draw(texture, position.ToDisplayVector2(), sourceAABB?.ToRectangle(), color, rotation, origin.ToDisplayVector2(), scale, effects, layerDepth); => spriteBatch.Draw(texture, position.ToVector2(), sourceAABB?.ToRectangle(), color, rotation, origin.ToVector2(), scale, effects, layerDepth);
public void Draw(Texture2D texture, AABB2D destinationAABB, AABB2D? sourceAABB, Color color, float rotation, Vector2D origin, SpriteEffects effects, float layerDepth) public void Draw(Texture2D texture, AABB2D destinationAABB, AABB2D? sourceAABB, Color color, float rotation, Vector2D origin, SpriteEffects effects, float layerDepth)
=> spriteBatch.Draw(texture, destinationAABB.ToRectangle(), sourceAABB?.ToRectangle(), color, rotation, origin.ToDisplayVector2(), effects, layerDepth); => spriteBatch.Draw(texture, destinationAABB.ToRectangle(), sourceAABB?.ToRectangle(), color, rotation, origin.ToVector2(), effects, layerDepth);
public void Draw(Texture2D texture, Vector2D position, AABB2D? sourceAABB, Color color) public void Draw(Texture2D texture, Vector2D position, AABB2D? sourceAABB, Color color)
=> spriteBatch.Draw(texture, position.ToDisplayVector2(), sourceAABB?.ToRectangle(), color); => spriteBatch.Draw(texture, position.ToVector2(), sourceAABB?.ToRectangle(), color);
public void Draw(Texture2D texture, AABB2D destinationAABB, AABB2D? sourceAABB, Color color) public void Draw(Texture2D texture, AABB2D destinationAABB, AABB2D? sourceAABB, Color color)
=> spriteBatch.Draw(texture, destinationAABB.ToRectangle(), sourceAABB?.ToRectangle(), color); => spriteBatch.Draw(texture, destinationAABB.ToRectangle(), sourceAABB?.ToRectangle(), color);
public void Draw(Texture2D texture, Vector2D position, Color color) public void Draw(Texture2D texture, Vector2D position, Color color)
=> spriteBatch.Draw(texture, position.ToDisplayVector2(), color); => spriteBatch.Draw(texture, position.ToVector2(), color);
public void Draw(Texture2D texture, AABB2D destinationAABB, Color color) public void Draw(Texture2D texture, AABB2D destinationAABB, Color color)
=> spriteBatch.Draw(texture, destinationAABB.ToRectangle(), color); => spriteBatch.Draw(texture, destinationAABB.ToRectangle(), color);
public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color) public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color)
=> spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color); => spriteBatch.DrawString(spriteFont, text, position.ToVector2(), color);
public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth) public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth)
=> spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale, effects, layerDepth); => spriteBatch.DrawString(spriteFont, text, position.ToVector2(), color, rotation, origin.ToVector2(), scale, effects, layerDepth);
public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth) public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth)
=> spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth); => spriteBatch.DrawString(spriteFont, text, position.ToVector2(), color, rotation, origin.ToVector2(), scale.ToVector2(), effects, layerDepth);
public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth, bool rtl) public void DrawString(SpriteFont spriteFont, string text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth, bool rtl)
=> spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth, rtl); => spriteBatch.DrawString(spriteFont, text, position.ToVector2(), color, rotation, origin.ToVector2(), scale.ToVector2(), effects, layerDepth, rtl);
public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color) public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color)
=> spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color); => spriteBatch.DrawString(spriteFont, text, position.ToVector2(), color);
public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth) public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, float scale, SpriteEffects effects, float layerDepth)
=> spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale, effects, layerDepth); => spriteBatch.DrawString(spriteFont, text, position.ToVector2(), color, rotation, origin.ToVector2(), scale, effects, layerDepth);
public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth) public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth)
=> spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth); => spriteBatch.DrawString(spriteFont, text, position.ToVector2(), color, rotation, origin.ToVector2(), scale.ToVector2(), effects, layerDepth);
public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth, bool rtl) public void DrawString(SpriteFont spriteFont, StringBuilder text, Vector2D position, Color color, float rotation, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth, bool rtl)
=> spriteBatch.DrawString(spriteFont, text, position.ToDisplayVector2(), color, rotation, origin.ToDisplayVector2(), scale.ToDisplayVector2(), effects, layerDepth, rtl); => spriteBatch.DrawString(spriteFont, text, position.ToVector2(), color, rotation, origin.ToVector2(), scale.ToVector2(), effects, layerDepth, rtl);
public void End() public void End()
=> spriteBatch.End(); => spriteBatch.End();

View File

@@ -9,8 +9,6 @@ namespace Engine.Integration.MonoGame;
public static class EngineConverterExtensions public static class EngineConverterExtensions
{ {
public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UniverseTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); public static UniverseTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime);
@@ -60,12 +58,6 @@ public static class EngineConverterExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Microsoft.Xna.Framework.Quaternion ToXnaQuaternion(this Core.Quaternion quaternion) => new(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W); public static Microsoft.Xna.Framework.Quaternion ToXnaQuaternion(this Core.Quaternion quaternion) => new(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2D ApplyDisplayScale(this Vector2D vector) => vector.Scale(screenScale);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rectangle ToDisplayRectangle(this Rectangle rectangle, DisplayMode displayMode) => new() public static Rectangle ToDisplayRectangle(this Rectangle rectangle, DisplayMode displayMode) => new()
{ {
@@ -78,8 +70,8 @@ public static class EngineConverterExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rectangle ToRectangle(this AABB2D aabb) => new() public static Rectangle ToRectangle(this AABB2D aabb) => new()
{ {
X = (int)(aabb.LowerBoundary.X * screenScale.X), X = (int)aabb.LowerBoundary.X,
Y = (int)(aabb.LowerBoundary.Y * screenScale.Y), Y = (int)aabb.LowerBoundary.Y,
Width = (int)(aabb.UpperBoundary.X - aabb.LowerBoundary.X), Width = (int)(aabb.UpperBoundary.X - aabb.LowerBoundary.X),
Height = (int)(aabb.UpperBoundary.Y - aabb.LowerBoundary.Y) Height = (int)(aabb.UpperBoundary.Y - aabb.LowerBoundary.Y)
}; };

View File

@@ -33,9 +33,9 @@ public class MonoGameTriangleBatch : Behaviour, ITriangleBatch, IFirstFrameUpdat
if (verticesIndex + 3 >= vertices.Length) if (verticesIndex + 3 >= vertices.Length)
Flush(); Flush();
Vector2 A = triangle.A.ToDisplayVector2(); Vector2 A = triangle.A.ToVector2();
Vector2 B = triangle.B.ToDisplayVector2(); Vector2 B = triangle.B.ToVector2();
Vector2 C = triangle.C.ToDisplayVector2(); Vector2 C = triangle.C.ToVector2();
Color color = colorRGBA.ToColor(); Color color = colorRGBA.ToColor();
vertices[verticesIndex++] = new(new(A.X, A.Y, 0f), color); vertices[verticesIndex++] = new(new(A.X, A.Y, 0f), color);
@@ -44,19 +44,11 @@ public class MonoGameTriangleBatch : Behaviour, ITriangleBatch, IFirstFrameUpdat
} }
public void Begin(Matrix4x4? view = null, Matrix4x4? projection = null) public void Begin(Matrix4x4? view = null, Matrix4x4? projection = null)
{
if (view != null)
this.view = view.Value.ToXnaMatrix();
else
this.view = Matrix.Identity;
if (projection != null)
this.projection = projection.Value.ToXnaMatrix();
else
{ {
Viewport viewport = graphicsDevice.Viewport; Viewport viewport = graphicsDevice.Viewport;
this.projection = Matrix.CreateOrthographicOffCenter(viewport.X, viewport.Width, viewport.Height, viewport.Y, 0, 1);
} this.view = (view ?? Matrix4x4.Identity).Transposed.ToXnaMatrix();
this.projection = (projection ?? Matrix4x4.CreateOrthographicViewCentered(viewport.Width, viewport.Height)).Transposed.ToXnaMatrix();
} }
public void End() => Flush(); public void End() => Flush();

View File

@@ -4,12 +4,12 @@ using Engine.Core;
namespace Engine.Systems.Graphics; namespace Engine.Systems.Graphics;
public class TriangleBatcher : Behaviour, IFirstFrameUpdate, IDraw public class TriangleBatcher : Behaviour, IFirstFrameUpdate, ILastFrameUpdate, IDraw
{ {
private static Comparer<int> SortByAscendingPriority() => Comparer<int>.Create((x, y) => x.CompareTo(y)); private static Comparer<int> SortByAscendingPriority() => Comparer<int>.Create((x, y) => x.CompareTo(y));
private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority; private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority;
private ITriangleBatch triangleBatch = null!; private readonly BehaviourCollector<ITriangleBatch> triangleBatches = new();
private ICamera camera = null!; private ICamera camera = null!;
private readonly ActiveBehaviourCollectorOrdered<int, IDrawableTriangle> drawableShapes = new(GetPriority(), SortByAscendingPriority()); private readonly ActiveBehaviourCollectorOrdered<int, IDrawableTriangle> drawableShapes = new(GetPriority(), SortByAscendingPriority());
@@ -18,16 +18,25 @@ public class TriangleBatcher : Behaviour, IFirstFrameUpdate, IDraw
{ {
camera = Universe.FindRequiredBehaviour<ICamera>(); camera = Universe.FindRequiredBehaviour<ICamera>();
triangleBatch = Universe.FindRequiredBehaviour<ITriangleBatch>();
drawableShapes.Unassign();
drawableShapes.Assign(Universe); drawableShapes.Assign(Universe);
triangleBatches.Assign(Universe);
} }
public void Draw() public void Draw()
{ {
for (int i = 0; i < triangleBatches.Count; i++)
{
ITriangleBatch triangleBatch = triangleBatches[i];
triangleBatch.Begin(camera.ViewMatrix, camera.ProjectionMatrix); triangleBatch.Begin(camera.ViewMatrix, camera.ProjectionMatrix);
for (int i = 0; i < drawableShapes.Count; i++) for (int j = 0; j < drawableShapes.Count; j++)
drawableShapes[i].Draw(triangleBatch); drawableShapes[j].Draw(triangleBatch);
triangleBatch.End(); triangleBatch.End();
} }
}
public void LastActiveFrame()
{
triangleBatches.Unassign();
drawableShapes.Unassign();
}
} }