mirror of
				https://github.com/MaddyThorson/StrawberryBF.git
				synced 2025-11-04 01:41:33 +08:00 
			
		
		
		
	Cleaned up entity tracking. Scene.Camera. Matrix struct.
This commit is contained in:
		@ -25,7 +25,10 @@ namespace Strawberry
 | 
			
		||||
		private Scene scene;
 | 
			
		||||
		private Scene switchToScene;
 | 
			
		||||
		private bool updating;
 | 
			
		||||
		private Dictionary<Type, List<Type>> entityAssignableLists;
 | 
			
		||||
		private Dictionary<Type, List<Type>> componentAssignableLists;
 | 
			
		||||
 | 
			
		||||
		//SDL Vars
 | 
			
		||||
		public SDL.Renderer* Renderer { get; private set; }
 | 
			
		||||
		public Color ClearColor = .Black;
 | 
			
		||||
 | 
			
		||||
@ -78,7 +81,7 @@ namespace Strawberry
 | 
			
		||||
			SDLMixer.OpenAudio(44100, SDLMixer.MIX_DEFAULT_FORMAT, 2, 4096);
 | 
			
		||||
			SDLTTF.Init();
 | 
			
		||||
 | 
			
		||||
			TypeTree.[Friend]Build();
 | 
			
		||||
			BuildTypeLists();
 | 
			
		||||
			Input.[Friend]Init(gamepadLimit);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -99,7 +102,7 @@ namespace Strawberry
 | 
			
		||||
				delete VirtualInputs;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			TypeTree.[Friend]Dispose();
 | 
			
		||||
			DisposeTypeLists();
 | 
			
		||||
			Input.[Friend]Dispose();
 | 
			
		||||
			Game = null;
 | 
			
		||||
		}
 | 
			
		||||
@ -210,5 +213,57 @@ namespace Strawberry
 | 
			
		||||
				switchToScene = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Type assignable caching
 | 
			
		||||
 | 
			
		||||
		private void BuildTypeLists()
 | 
			
		||||
		{
 | 
			
		||||
			/*
 | 
			
		||||
				For each Type that extends Entity, we build a list of all the other Entity Types that it is assignable to.
 | 
			
		||||
				We cache these lists, and use them later to bucket Entities as they are added to the Scene.
 | 
			
		||||
				This allows us to retrieve Entities by type very easily.
 | 
			
		||||
			*/
 | 
			
		||||
 | 
			
		||||
			entityAssignableLists = new Dictionary<Type, List<Type>>();
 | 
			
		||||
			for (let type in Type.Enumerator())
 | 
			
		||||
			{	
 | 
			
		||||
				if (type != typeof(Entity) && type.IsSubtypeOf(typeof(Entity)))
 | 
			
		||||
				{
 | 
			
		||||
					let list = new List<Type>();
 | 
			
		||||
					for (let check in Type.Enumerator())
 | 
			
		||||
						if (check != typeof(Entity) && check.IsSubtypeOf(typeof(Entity)) && type.IsSubtypeOf(check))
 | 
			
		||||
							list.Add(check);
 | 
			
		||||
					entityAssignableLists.Add(type, list);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
				And then we also do this for components
 | 
			
		||||
			*/
 | 
			
		||||
 | 
			
		||||
			componentAssignableLists = new Dictionary<Type, List<Type>>();
 | 
			
		||||
			for (let type in Type.Enumerator())
 | 
			
		||||
			{	
 | 
			
		||||
				if (type != typeof(Component) && type.IsSubtypeOf(typeof(Component)))
 | 
			
		||||
				{
 | 
			
		||||
					let list = new List<Type>();
 | 
			
		||||
					for (let check in Type.Enumerator())
 | 
			
		||||
						if (check != typeof(Component) && check.IsSubtypeOf(typeof(Component)) && type.IsSubtypeOf(check))
 | 
			
		||||
							list.Add(check);
 | 
			
		||||
					componentAssignableLists.Add(type, list);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void DisposeTypeLists()
 | 
			
		||||
		{
 | 
			
		||||
			for (let list in entityAssignableLists.Values)
 | 
			
		||||
				delete list;
 | 
			
		||||
			delete entityAssignableLists;
 | 
			
		||||
 | 
			
		||||
			for (let list in componentAssignableLists.Values)
 | 
			
		||||
				delete list;
 | 
			
		||||
			delete componentAssignableLists;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ namespace Strawberry
 | 
			
		||||
		public float TimeStarted { get; private set; }
 | 
			
		||||
		public Grid SolidGrid;
 | 
			
		||||
		public Rect Bounds;
 | 
			
		||||
		public Vector Camera;
 | 
			
		||||
 | 
			
		||||
		private List<Entity> entities;
 | 
			
		||||
		private HashSet<Entity> toRemove;
 | 
			
		||||
@ -22,11 +23,11 @@ namespace Strawberry
 | 
			
		||||
			toRemove = new HashSet<Entity>();
 | 
			
		||||
 | 
			
		||||
			entityTracker = new Dictionary<Type, List<Entity>>();
 | 
			
		||||
			for (let type in TypeTree.[Friend]EntityAssignableLists.Keys)
 | 
			
		||||
			for (let type in Game.[Friend]entityAssignableLists.Keys)
 | 
			
		||||
				entityTracker.Add(type, new List<Entity>());
 | 
			
		||||
 | 
			
		||||
			componentTracker = new Dictionary<Type, List<Component>>();
 | 
			
		||||
			for (let type in TypeTree.[Friend]ComponentAssignableLists.Keys)
 | 
			
		||||
			for (let type in Game.[Friend]componentAssignableLists.Keys)
 | 
			
		||||
				componentTracker.Add(type, new List<Component>());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -63,6 +64,8 @@ namespace Strawberry
 | 
			
		||||
 | 
			
		||||
		public virtual void Update()
 | 
			
		||||
		{
 | 
			
		||||
			Camera.X += 20 * Time.Delta;
 | 
			
		||||
 | 
			
		||||
			UpdateLists();
 | 
			
		||||
			for (var e in entities)
 | 
			
		||||
				if (e.Active)
 | 
			
		||||
@ -132,7 +135,7 @@ namespace Strawberry
 | 
			
		||||
 | 
			
		||||
		private void TrackEntity(Entity e)
 | 
			
		||||
		{
 | 
			
		||||
			for (let t in TypeTree.[Friend]EntityAssignableLists[e.GetType()])
 | 
			
		||||
			for (let t in Game.[Friend]entityAssignableLists[e.GetType()])
 | 
			
		||||
				entityTracker[t].Add(e);
 | 
			
		||||
 | 
			
		||||
			for (let c in e.[Friend]components)
 | 
			
		||||
@ -141,7 +144,7 @@ namespace Strawberry
 | 
			
		||||
 | 
			
		||||
		private void UntrackEntity(Entity e)
 | 
			
		||||
		{
 | 
			
		||||
			for (let t in TypeTree.[Friend]EntityAssignableLists[e.GetType()])
 | 
			
		||||
			for (let t in Game.[Friend]entityAssignableLists[e.GetType()])
 | 
			
		||||
				entityTracker[t].Remove(e);
 | 
			
		||||
 | 
			
		||||
			for (let c in e.[Friend]components)
 | 
			
		||||
@ -150,13 +153,13 @@ namespace Strawberry
 | 
			
		||||
 | 
			
		||||
		private void TrackComponent(Component c)
 | 
			
		||||
		{
 | 
			
		||||
			for (let t in TypeTree.[Friend]ComponentAssignableLists[c.GetType()])
 | 
			
		||||
			for (let t in Game.[Friend]componentAssignableLists[c.GetType()])
 | 
			
		||||
				componentTracker[t].Add(c);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void UntrackComponent(Component c)
 | 
			
		||||
		{
 | 
			
		||||
			for (let t in TypeTree.[Friend]ComponentAssignableLists[c.GetType()])
 | 
			
		||||
			for (let t in Game.[Friend]componentAssignableLists[c.GetType()])
 | 
			
		||||
				componentTracker[t].Remove(c);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,12 @@ namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	static public class Draw
 | 
			
		||||
	{
 | 
			
		||||
		static public Point Camera => Game.Scene != null ? Game.Scene.Camera.Round() : Point.Zero;
 | 
			
		||||
 | 
			
		||||
		static public void Rect(int x, int y, int w, int h, Color color)
 | 
			
		||||
		{
 | 
			
		||||
			SDL.SetRenderDrawColor(Game.Renderer, color.R, color.G, color.B, color.A);
 | 
			
		||||
			SDL.RenderFillRect(Game.Renderer, &SDL.Rect((int32)x, (int32)y, (int32)w, (int32)h));
 | 
			
		||||
			SDL.RenderFillRect(Game.Renderer, &SDL.Rect((int32)(x - Camera.X), (int32)(y - Camera.Y), (int32)w, (int32)h));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static public void Rect(Rect rect, Color color)
 | 
			
		||||
@ -18,7 +20,7 @@ namespace Strawberry
 | 
			
		||||
		static public void HollowRect(int x, int y, int w, int h, Color color)
 | 
			
		||||
		{
 | 
			
		||||
			SDL.SetRenderDrawColor(Game.Renderer, color.R, color.G, color.B, color.A);
 | 
			
		||||
			SDL.RenderDrawRect(Game.Renderer, &SDL.Rect((int32)x, (int32)y, (int32)w, (int32)h));
 | 
			
		||||
			SDL.RenderDrawRect(Game.Renderer, &SDL.Rect((int32)(x - Camera.X), (int32)(y - Camera.Y), (int32)w, (int32)h));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static public void HollowRect(Rect rect, Color color)
 | 
			
		||||
@ -28,8 +30,11 @@ namespace Strawberry
 | 
			
		||||
 | 
			
		||||
		static public void Line(Point from, Point to, Color color)
 | 
			
		||||
		{
 | 
			
		||||
			let fromn = (Point)(from - Camera);
 | 
			
		||||
			let ton = (Point)(to - Camera);
 | 
			
		||||
 | 
			
		||||
			SDL.SetRenderDrawColor(Game.Renderer, color.R, color.G, color.B, color.A);
 | 
			
		||||
			SDL.RenderDrawLine(Game.Renderer, (int32)from.X, (int32)from.Y, (int32)to.X, (int32)to.Y);
 | 
			
		||||
			SDL.RenderDrawLine(Game.Renderer, (int32)fromn.X, (int32)fromn.Y, (int32)ton.X, (int32)ton.Y);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,61 +0,0 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	static public class TypeTree
 | 
			
		||||
	{
 | 
			
		||||
		static private Dictionary<Type, List<Type>> EntityAssignableLists;
 | 
			
		||||
		static private Dictionary<Type, List<Type>> ComponentAssignableLists;
 | 
			
		||||
 | 
			
		||||
		static private void Build()
 | 
			
		||||
		{
 | 
			
		||||
			/*
 | 
			
		||||
				For each Type that extends Entity, we build a list of all the other Entity Types that it is assignable to.
 | 
			
		||||
				We cache these lists, and use them later to bucket Entities as they are added to the Scene.
 | 
			
		||||
				This allows us to retrieve Entities by type very easily.
 | 
			
		||||
			*/
 | 
			
		||||
 | 
			
		||||
			EntityAssignableLists = new Dictionary<Type, List<Type>>();
 | 
			
		||||
			for (let type in Type.Enumerator())
 | 
			
		||||
			{	
 | 
			
		||||
				if (type != typeof(Entity) && type.IsSubtypeOf(typeof(Entity)))
 | 
			
		||||
				{
 | 
			
		||||
					let list = new List<Type>();
 | 
			
		||||
					for (let check in Type.Enumerator())
 | 
			
		||||
						if (check != typeof(Entity) && check.IsSubtypeOf(typeof(Entity)) && type.IsSubtypeOf(check))
 | 
			
		||||
							list.Add(check);
 | 
			
		||||
					EntityAssignableLists.Add(type, list);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
				And then we also do this for components
 | 
			
		||||
			*/
 | 
			
		||||
 | 
			
		||||
			ComponentAssignableLists = new Dictionary<Type, List<Type>>();
 | 
			
		||||
			for (let type in Type.Enumerator())
 | 
			
		||||
			{	
 | 
			
		||||
				if (type != typeof(Component) && type.IsSubtypeOf(typeof(Component)))
 | 
			
		||||
				{
 | 
			
		||||
					let list = new List<Type>();
 | 
			
		||||
					for (let check in Type.Enumerator())
 | 
			
		||||
						if (check != typeof(Component) && check.IsSubtypeOf(typeof(Component)) && type.IsSubtypeOf(check))
 | 
			
		||||
							list.Add(check);
 | 
			
		||||
					ComponentAssignableLists.Add(type, list);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static private void Dispose()
 | 
			
		||||
		{
 | 
			
		||||
			for (let list in EntityAssignableLists.Values)
 | 
			
		||||
				delete list;
 | 
			
		||||
			delete EntityAssignableLists;
 | 
			
		||||
 | 
			
		||||
			for (let list in ComponentAssignableLists.Values)
 | 
			
		||||
				delete list;
 | 
			
		||||
			delete ComponentAssignableLists;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										508
									
								
								src/Struct/Matrix.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										508
									
								
								src/Struct/Matrix.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,508 @@
 | 
			
		||||
using System;
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
		Based on Matrix3x2.cs by Microsoft, under MIT license
 | 
			
		||||
		Source: https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Matrix3x2.cs
 | 
			
		||||
 | 
			
		||||
		Copyright (c) Microsoft. All rights reserved.
 | 
			
		||||
		Licensed under the MIT license.
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	public struct Matrix
 | 
			
		||||
	{
 | 
			
		||||
		static public readonly Matrix Identity = Matrix(1, 0, 0, 1, 0, 0);
 | 
			
		||||
 | 
			
		||||
		//       Row--vv--Column
 | 
			
		||||
		public float M11;
 | 
			
		||||
		public float M12;
 | 
			
		||||
		public float M21;
 | 
			
		||||
		public float M22;
 | 
			
		||||
		public float M31;
 | 
			
		||||
		public float M32;
 | 
			
		||||
 | 
			
		||||
		public this(float m11, float m12, float m21, float m22, float m31, float m32)
 | 
			
		||||
		{
 | 
			
		||||
			M11 = m11;
 | 
			
		||||
			M12 = m12;
 | 
			
		||||
			M21 = m21;
 | 
			
		||||
			M22 = m22;
 | 
			
		||||
			M31 = m31;
 | 
			
		||||
			M32 = m32;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool IsIdentity
 | 
			
		||||
		{
 | 
			
		||||
		    get
 | 
			
		||||
		    {
 | 
			
		||||
		        return M11 == 1f && M22 == 1f && // Check diagonal element first for early out.
 | 
			
		||||
		                            M12 == 0f &&
 | 
			
		||||
		               M21 == 0f &&
 | 
			
		||||
		               M31 == 0f && M32 == 0f;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Vector Translation
 | 
			
		||||
		{
 | 
			
		||||
		    get
 | 
			
		||||
		    {
 | 
			
		||||
		        return .(M31, M32);
 | 
			
		||||
		    }
 | 
			
		||||
 | 
			
		||||
		    set mut
 | 
			
		||||
		    {
 | 
			
		||||
		        M31 = value.X;
 | 
			
		||||
		        M32 = value.Y;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Vector Scale
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return .(M11, M22);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			set mut
 | 
			
		||||
			{
 | 
			
		||||
				M11 = value.X;
 | 
			
		||||
				M22 = value.Y;
 | 
			
		||||
			}	
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Vector Up
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return .(M21, -M22);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			set mut
 | 
			
		||||
			{
 | 
			
		||||
				M21 = value.X;
 | 
			
		||||
				M22 = -value.Y;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Vector Down
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return .(M21, M22);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			set mut
 | 
			
		||||
			{
 | 
			
		||||
				M21 = -value.X;
 | 
			
		||||
				M22 = value.Y;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Vector Right
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return .(M11, -M12);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			set mut
 | 
			
		||||
			{
 | 
			
		||||
				M11 = value.X;
 | 
			
		||||
				M12 = -value.Y;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Vector Left
 | 
			
		||||
		{
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return .(-M11, M12);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			set mut
 | 
			
		||||
			{
 | 
			
		||||
				M11 = -value.X;
 | 
			
		||||
				M12 = value.Y;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Result<Matrix> Inverse
 | 
			
		||||
		{
 | 
			
		||||
			get => Invert(this);
 | 
			
		||||
 | 
			
		||||
			set mut
 | 
			
		||||
			{
 | 
			
		||||
				this = Invert(value);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//Static Helpers
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateTranslation(Vector position)
 | 
			
		||||
		{
 | 
			
		||||
		    return Matrix(
 | 
			
		||||
				1, 0,
 | 
			
		||||
				0, 1,
 | 
			
		||||
				position.X, position.Y
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateScale(Vector scale)
 | 
			
		||||
		{
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				scale.X, 0,
 | 
			
		||||
				0, scale.Y,
 | 
			
		||||
				0, 0
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateScale(Vector scale, Vector origin)
 | 
			
		||||
		{
 | 
			
		||||
			float tx = origin.X * (1 - scale.X);
 | 
			
		||||
			float ty = origin.Y * (1 - scale.Y);
 | 
			
		||||
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				scale.X, 0,
 | 
			
		||||
				0, scale.Y,
 | 
			
		||||
				tx, ty
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateScale(float scale)
 | 
			
		||||
		{
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				scale, 0,
 | 
			
		||||
				0, scale,
 | 
			
		||||
				0, 0
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateScale(float scale, Vector origin)
 | 
			
		||||
		{
 | 
			
		||||
			float tx = origin.X * (1 - scale);
 | 
			
		||||
			float ty = origin.Y * (1 - scale);
 | 
			
		||||
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				scale, 0,
 | 
			
		||||
				0, scale,
 | 
			
		||||
				tx, ty
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateSkew(float radiansX, float radiansY)
 | 
			
		||||
		{
 | 
			
		||||
			float xTan = (float)Math.Tan(radiansX);
 | 
			
		||||
			float yTan = (float)Math.Tan(radiansY);
 | 
			
		||||
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				1, yTan,
 | 
			
		||||
				xTan, 1,
 | 
			
		||||
				0, 0
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateSkew(float radiansX, float radiansY, Vector origin)
 | 
			
		||||
		{
 | 
			
		||||
		    float xTan = (float)Math.Tan(radiansX);
 | 
			
		||||
		    float yTan = (float)Math.Tan(radiansY);
 | 
			
		||||
 | 
			
		||||
		    float tx = -origin.Y * xTan;
 | 
			
		||||
		    float ty = -origin.X * yTan;
 | 
			
		||||
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				1, yTan,
 | 
			
		||||
				xTan, 1,
 | 
			
		||||
				tx, ty
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateRotation(float radians)
 | 
			
		||||
		{
 | 
			
		||||
			let rad = (float)Math.IEEERemainder(radians, Math.PI_f * 2);
 | 
			
		||||
 | 
			
		||||
		    float c, s;
 | 
			
		||||
 | 
			
		||||
		    const float epsilon = 0.001f * (float)Math.PI_f / 180f;     // 0.1% of a degree
 | 
			
		||||
 | 
			
		||||
		    if (rad > -epsilon && rad < epsilon)
 | 
			
		||||
		    {
 | 
			
		||||
		        // Exact case for zero rotation.
 | 
			
		||||
		        c = 1;
 | 
			
		||||
		        s = 0;
 | 
			
		||||
		    }
 | 
			
		||||
		    else if (rad > Math.PI_f / 2 - epsilon && rad < Math.PI_f / 2 + epsilon)
 | 
			
		||||
		    {
 | 
			
		||||
		        // Exact case for 90 degree rotation.
 | 
			
		||||
		        c = 0;
 | 
			
		||||
		        s = 1;
 | 
			
		||||
		    }
 | 
			
		||||
		    else if (rad < -Math.PI_f + epsilon || rad > Math.PI_f - epsilon)
 | 
			
		||||
		    {
 | 
			
		||||
		        // Exact case for 180 degree rotation.
 | 
			
		||||
		        c = -1;
 | 
			
		||||
		        s = 0;
 | 
			
		||||
		    }
 | 
			
		||||
		    else if (rad > -Math.PI_f / 2 - epsilon && rad < -Math.PI_f / 2 + epsilon)
 | 
			
		||||
		    {
 | 
			
		||||
		        // Exact case for 270 degree rotation.
 | 
			
		||||
		        c = 0;
 | 
			
		||||
		        s = -1;
 | 
			
		||||
		    }
 | 
			
		||||
		    else
 | 
			
		||||
		    {
 | 
			
		||||
		        // Arbitrary rotation.
 | 
			
		||||
		        c = (float)Math.Cos(rad);
 | 
			
		||||
		        s = (float)Math.Sin(rad);
 | 
			
		||||
		    }
 | 
			
		||||
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				c, s,
 | 
			
		||||
				-s, c,
 | 
			
		||||
				0, 0
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix CreateRotation(float radians, Vector origin)
 | 
			
		||||
		{
 | 
			
		||||
		    let rad = (float)Math.IEEERemainder(radians, Math.PI_f * 2);
 | 
			
		||||
 | 
			
		||||
		    float c, s;
 | 
			
		||||
 | 
			
		||||
		    const float epsilon = 0.001f * (float)Math.PI_f / 180f;     // 0.1% of a degree
 | 
			
		||||
 | 
			
		||||
		    if (rad > -epsilon && rad < epsilon)
 | 
			
		||||
		    {
 | 
			
		||||
		        // Exact case for zero rotation.
 | 
			
		||||
		        c = 1;
 | 
			
		||||
		        s = 0;
 | 
			
		||||
		    }
 | 
			
		||||
		    else if (rad > Math.PI_f / 2 - epsilon && rad < Math.PI_f / 2 + epsilon)
 | 
			
		||||
		    {
 | 
			
		||||
		        // Exact case for 90 degree rotation.
 | 
			
		||||
		        c = 0;
 | 
			
		||||
		        s = 1;
 | 
			
		||||
		    }
 | 
			
		||||
		    else if (rad < -Math.PI_f + epsilon || rad > Math.PI_f - epsilon)
 | 
			
		||||
		    {
 | 
			
		||||
		        // Exact case for 180 degree rotation.
 | 
			
		||||
		        c = -1;
 | 
			
		||||
		        s = 0;
 | 
			
		||||
		    }
 | 
			
		||||
		    else if (rad > -Math.PI_f / 2 - epsilon && rad < -Math.PI_f / 2 + epsilon)
 | 
			
		||||
		    {
 | 
			
		||||
		        // Exact case for 270 degree rotation.
 | 
			
		||||
		        c = 0;
 | 
			
		||||
		        s = -1;
 | 
			
		||||
		    }
 | 
			
		||||
		    else
 | 
			
		||||
		    {
 | 
			
		||||
		        // Arbitrary rotation.
 | 
			
		||||
		        c = (float)Math.Cos(rad);
 | 
			
		||||
		        s = (float)Math.Sin(rad);
 | 
			
		||||
		    }
 | 
			
		||||
 | 
			
		||||
		    float x = origin.X * (1 - c) + origin.Y * s;
 | 
			
		||||
		    float y = origin.Y * (1 - c) - origin.X * s;
 | 
			
		||||
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				c, s,
 | 
			
		||||
				-s, c,
 | 
			
		||||
				x, y
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// Calculates the determinant for this matrix. 
 | 
			
		||||
		/// The determinant is calculated by expanding the matrix with a third column whose values are (0,0,1).
 | 
			
		||||
		public float GetDeterminant()
 | 
			
		||||
		{
 | 
			
		||||
		    // There isn't actually any such thing as a determinant for a non-square matrix,
 | 
			
		||||
		    // but this 3x2 type is really just an optimization of a 3x3 where we happen to
 | 
			
		||||
		    // know the rightmost column is always (0, 0, 1). So we expand to 3x3 format:
 | 
			
		||||
		    //
 | 
			
		||||
		    //  [ M11, M12, 0 ]
 | 
			
		||||
		    //  [ M21, M22, 0 ]
 | 
			
		||||
		    //  [ M31, M32, 1 ]
 | 
			
		||||
		    //
 | 
			
		||||
		    // Sum the diagonal products:
 | 
			
		||||
		    //  (M11 * M22 * 1) + (M12 * 0 * M31) + (0 * M21 * M32)
 | 
			
		||||
		    //
 | 
			
		||||
		    // Subtract the opposite diagonal products:
 | 
			
		||||
		    //  (M31 * M22 * 0) + (M32 * 0 * M11) + (1 * M21 * M12)
 | 
			
		||||
		    //
 | 
			
		||||
		    // Collapse out the constants and oh look, this is just a 2x2 determinant!
 | 
			
		||||
 | 
			
		||||
		    return (M11 * M22) - (M21 * M12);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Result<Matrix> Invert(Matrix matrix)
 | 
			
		||||
		{
 | 
			
		||||
		    let det = (matrix.M11 * matrix.M22) - (matrix.M21 * matrix.M12);
 | 
			
		||||
 | 
			
		||||
		    if (Math.Abs(det) < float.Epsilon)
 | 
			
		||||
				return .Err;
 | 
			
		||||
 | 
			
		||||
		    let invDet = 1.0f / det;
 | 
			
		||||
 | 
			
		||||
		    return Matrix(
 | 
			
		||||
				matrix.M22 * invDet,
 | 
			
		||||
				-matrix.M12 * invDet,
 | 
			
		||||
 | 
			
		||||
				-matrix.M21 * invDet,
 | 
			
		||||
				matrix.M11 * invDet,
 | 
			
		||||
 | 
			
		||||
				(matrix.M21 * matrix.M32 - matrix.M31 * matrix.M22) * invDet,
 | 
			
		||||
				(matrix.M31 * matrix.M12 - matrix.M11 * matrix.M32) * invDet
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix Lerp(Matrix a, Matrix b, float t)
 | 
			
		||||
		{
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				a.M11 + (b.M11 - a.M11) * t,
 | 
			
		||||
				a.M12 + (b.M12 - a.M12) * t,
 | 
			
		||||
 | 
			
		||||
				a.M21 + (b.M21 - a.M21) * t,
 | 
			
		||||
				a.M22 + (b.M22 - a.M22) * t,
 | 
			
		||||
 | 
			
		||||
				a.M31 + (b.M31 - a.M31) * t,
 | 
			
		||||
				a.M32 + (b.M32 - a.M32) * t
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix Negate(Matrix mat)
 | 
			
		||||
		{
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				-mat.M11, -mat.M12,
 | 
			
		||||
				-mat.M21, -mat.M22,
 | 
			
		||||
				-mat.M31, -mat.M32
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix Add(Matrix a, Matrix b)
 | 
			
		||||
		{
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				a.M11 + b.M11, a.M12 + b.M12,
 | 
			
		||||
				a.M21 + b.M21, a.M22 + b.M22,
 | 
			
		||||
				a.M31 + b.M31, a.M32 + b.M32
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix Subtract(Matrix a, Matrix b)
 | 
			
		||||
		{
 | 
			
		||||
		    return Matrix(
 | 
			
		||||
				a.M11 - b.M11, a.M12 - b.M12,
 | 
			
		||||
				a.M21 - b.M21, a.M22 - b.M22,
 | 
			
		||||
				a.M31 - b.M31, a.M32 - b.M32
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix Multiply(Matrix a, Matrix b)
 | 
			
		||||
		{
 | 
			
		||||
		    return Matrix(
 | 
			
		||||
				a.M11 * b.M11 + a.M12 * b.M21,
 | 
			
		||||
				a.M11 * b.M12 + a.M12 * b.M22,
 | 
			
		||||
 | 
			
		||||
				a.M21 * b.M11 + a.M22 * b.M21,
 | 
			
		||||
				a.M21 * b.M12 + a.M22 * b.M22,
 | 
			
		||||
 | 
			
		||||
				a.M31 * b.M11 + a.M32 * b.M21 + b.M31,
 | 
			
		||||
				a.M31 * b.M12 + a.M32 * b.M22 + b.M32
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix Multiply(Matrix a, float scale)
 | 
			
		||||
		{
 | 
			
		||||
		    return Matrix(
 | 
			
		||||
				a.M11 * scale, a.M12 * scale,
 | 
			
		||||
				a.M21 * scale, a.M22 * scale,
 | 
			
		||||
				a.M31 * scale, a.M32 * scale
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Operators
 | 
			
		||||
 | 
			
		||||
		public static Matrix operator -(Matrix mat)
 | 
			
		||||
		{
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				-mat.M11, -mat.M12,
 | 
			
		||||
				-mat.M21, -mat.M22,
 | 
			
		||||
				-mat.M31, -mat.M32
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix operator +(Matrix a, Matrix b)
 | 
			
		||||
		{
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				a.M11 + b.M11, a.M12 + b.M12,
 | 
			
		||||
				a.M21 + b.M21, a.M22 + b.M22,
 | 
			
		||||
				a.M31 + b.M31, a.M32 + b.M32
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix operator -(Matrix a, Matrix b)
 | 
			
		||||
		{
 | 
			
		||||
		    return Matrix(
 | 
			
		||||
				a.M11 - b.M11, a.M12 - b.M12,
 | 
			
		||||
				a.M21 - b.M21, a.M22 - b.M22,
 | 
			
		||||
				a.M31 - b.M31, a.M32 - b.M32
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix operator *(Matrix a, Matrix b)
 | 
			
		||||
		{
 | 
			
		||||
		    return Matrix(
 | 
			
		||||
				a.M11 * b.M11 + a.M12 * b.M21,
 | 
			
		||||
				a.M11 * b.M12 + a.M12 * b.M22,
 | 
			
		||||
 | 
			
		||||
				a.M21 * b.M11 + a.M22 * b.M21,
 | 
			
		||||
				a.M21 * b.M12 + a.M22 * b.M22,
 | 
			
		||||
 | 
			
		||||
				a.M31 * b.M11 + a.M32 * b.M21 + b.M31,
 | 
			
		||||
				a.M31 * b.M12 + a.M32 * b.M22 + b.M32
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Matrix operator *(Matrix mat, float scale)
 | 
			
		||||
		{
 | 
			
		||||
			return Matrix(
 | 
			
		||||
				mat.M11 * scale, mat.M12 * scale,
 | 
			
		||||
				mat.M21 * scale, mat.M22 * scale,
 | 
			
		||||
				mat.M31 * scale, mat.M32 * scale
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool operator ==(Matrix a, Matrix b)
 | 
			
		||||
		{
 | 
			
		||||
		    return (a.M11 == b.M11 && a.M22 == b.M22 && // Check diagonal element first for early out.
 | 
			
		||||
		                                        a.M12 == b.M12 &&
 | 
			
		||||
		            a.M21 == b.M21 &&
 | 
			
		||||
		            a.M31 == b.M31 && a.M32 == b.M32);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool operator !=(Matrix a, Matrix b)
 | 
			
		||||
		{
 | 
			
		||||
		    return (a.M11 != b.M11 || a.M12 != b.M12 ||
 | 
			
		||||
		            a.M21 != b.M21 || a.M22 != b.M22 ||
 | 
			
		||||
		            a.M31 != b.M31 || a.M32 != b.M32);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void ToString(String strBuffer)
 | 
			
		||||
		{
 | 
			
		||||
			let str = scope String();
 | 
			
		||||
 | 
			
		||||
			str.Append("[ ");
 | 
			
		||||
			M11.ToString(str);
 | 
			
		||||
			str.Append(", ");
 | 
			
		||||
			M12.ToString(str);
 | 
			
		||||
			str.Append(",\n");
 | 
			
		||||
			M21.ToString(str);
 | 
			
		||||
			str.Append(", ");
 | 
			
		||||
			M22.ToString(str);
 | 
			
		||||
			str.Append(",\n");
 | 
			
		||||
			M31.ToString(str);
 | 
			
		||||
			str.Append(", ");
 | 
			
		||||
			M32.ToString(str);
 | 
			
		||||
			str.Append(" ]");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user