mirror of
https://github.com/MaddyThorson/StrawberryBF.git
synced 2025-02-18 11:38:28 +08:00
Cleaned up entity tracking. Scene.Camera. Matrix struct.
This commit is contained in:
parent
292213dae5
commit
fe3672f30c
@ -25,7 +25,10 @@ namespace Strawberry
|
|||||||
private Scene scene;
|
private Scene scene;
|
||||||
private Scene switchToScene;
|
private Scene switchToScene;
|
||||||
private bool updating;
|
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 SDL.Renderer* Renderer { get; private set; }
|
||||||
public Color ClearColor = .Black;
|
public Color ClearColor = .Black;
|
||||||
|
|
||||||
@ -78,7 +81,7 @@ namespace Strawberry
|
|||||||
SDLMixer.OpenAudio(44100, SDLMixer.MIX_DEFAULT_FORMAT, 2, 4096);
|
SDLMixer.OpenAudio(44100, SDLMixer.MIX_DEFAULT_FORMAT, 2, 4096);
|
||||||
SDLTTF.Init();
|
SDLTTF.Init();
|
||||||
|
|
||||||
TypeTree.[Friend]Build();
|
BuildTypeLists();
|
||||||
Input.[Friend]Init(gamepadLimit);
|
Input.[Friend]Init(gamepadLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +102,7 @@ namespace Strawberry
|
|||||||
delete VirtualInputs;
|
delete VirtualInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeTree.[Friend]Dispose();
|
DisposeTypeLists();
|
||||||
Input.[Friend]Dispose();
|
Input.[Friend]Dispose();
|
||||||
Game = null;
|
Game = null;
|
||||||
}
|
}
|
||||||
@ -210,5 +213,57 @@ namespace Strawberry
|
|||||||
switchToScene = value;
|
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 float TimeStarted { get; private set; }
|
||||||
public Grid SolidGrid;
|
public Grid SolidGrid;
|
||||||
public Rect Bounds;
|
public Rect Bounds;
|
||||||
|
public Vector Camera;
|
||||||
|
|
||||||
private List<Entity> entities;
|
private List<Entity> entities;
|
||||||
private HashSet<Entity> toRemove;
|
private HashSet<Entity> toRemove;
|
||||||
@ -22,11 +23,11 @@ namespace Strawberry
|
|||||||
toRemove = new HashSet<Entity>();
|
toRemove = new HashSet<Entity>();
|
||||||
|
|
||||||
entityTracker = new Dictionary<Type, List<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>());
|
entityTracker.Add(type, new List<Entity>());
|
||||||
|
|
||||||
componentTracker = new Dictionary<Type, List<Component>>();
|
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>());
|
componentTracker.Add(type, new List<Component>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +64,8 @@ namespace Strawberry
|
|||||||
|
|
||||||
public virtual void Update()
|
public virtual void Update()
|
||||||
{
|
{
|
||||||
|
Camera.X += 20 * Time.Delta;
|
||||||
|
|
||||||
UpdateLists();
|
UpdateLists();
|
||||||
for (var e in entities)
|
for (var e in entities)
|
||||||
if (e.Active)
|
if (e.Active)
|
||||||
@ -132,7 +135,7 @@ namespace Strawberry
|
|||||||
|
|
||||||
private void TrackEntity(Entity e)
|
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);
|
entityTracker[t].Add(e);
|
||||||
|
|
||||||
for (let c in e.[Friend]components)
|
for (let c in e.[Friend]components)
|
||||||
@ -141,7 +144,7 @@ namespace Strawberry
|
|||||||
|
|
||||||
private void UntrackEntity(Entity e)
|
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);
|
entityTracker[t].Remove(e);
|
||||||
|
|
||||||
for (let c in e.[Friend]components)
|
for (let c in e.[Friend]components)
|
||||||
@ -150,13 +153,13 @@ namespace Strawberry
|
|||||||
|
|
||||||
private void TrackComponent(Component c)
|
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);
|
componentTracker[t].Add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UntrackComponent(Component 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);
|
componentTracker[t].Remove(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,12 @@ namespace Strawberry
|
|||||||
{
|
{
|
||||||
static public class Draw
|
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)
|
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.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)
|
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)
|
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.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)
|
static public void HollowRect(Rect rect, Color color)
|
||||||
@ -28,8 +30,11 @@ namespace Strawberry
|
|||||||
|
|
||||||
static public void Line(Point from, Point to, Color color)
|
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.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(" ]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user