Add Int32Matrix4x4 struct.

This allows matrices to be represented as a value type, and additionally allows avoiding array allocations when calculating rotations.
This commit is contained in:
RoosterDragon
2018-03-17 16:44:41 +00:00
committed by abcdefg30
parent 5bd5a384b7
commit e17ede34ef
6 changed files with 148 additions and 52 deletions

View File

@@ -323,12 +323,31 @@ namespace OpenRA.Graphics
return mtx;
}
public static float[] MakeFloatMatrix(int[] imtx)
public static float[] MakeFloatMatrix(Int32Matrix4x4 imtx)
{
var fmtx = new float[16];
for (var i = 0; i < 16; i++)
fmtx[i] = imtx[i] * 1f / imtx[15];
return fmtx;
var multipler = 1f / imtx.M44;
return new float[]
{
imtx.M11 * multipler,
imtx.M12 * multipler,
imtx.M13 * multipler,
imtx.M14 * multipler,
imtx.M21 * multipler,
imtx.M22 * multipler,
imtx.M23 * multipler,
imtx.M24 * multipler,
imtx.M31 * multipler,
imtx.M32 * multipler,
imtx.M33 * multipler,
imtx.M34 * multipler,
imtx.M41 * multipler,
imtx.M42 * multipler,
imtx.M43 * multipler,
imtx.M44 * multipler,
};
}
public static float[] MatrixAABBMultiply(float[] mtx, float[] bounds)

View File

@@ -106,6 +106,7 @@
<Compile Include="Actor.cs" />
<Compile Include="CacheStorage.cs" />
<Compile Include="FileSystem\IPackage.cs" />
<Compile Include="Primitives\Int32Matrix4x4.cs" />
<Compile Include="LogProxy.cs" />
<Compile Include="Map\MapGrid.cs" />
<Compile Include="Map\MapPlayers.cs" />

View File

@@ -0,0 +1,72 @@
#region Copyright & License Information
/*
* Copyright 2007-2018 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
namespace OpenRA
{
public struct Int32Matrix4x4 : IEquatable<Int32Matrix4x4>
{
public readonly int M11, M12, M13, M14, M21, M22, M23, M24, M31, M32, M33, M34, M41, M42, M43, M44;
public Int32Matrix4x4(
int m11, int m12, int m13, int m14,
int m21, int m22, int m23, int m24,
int m31, int m32, int m33, int m34,
int m41, int m42, int m43, int m44)
{
M11 = m11;
M12 = m12;
M13 = m13;
M14 = m14;
M21 = m21;
M22 = m22;
M23 = m23;
M24 = m24;
M31 = m31;
M32 = m32;
M33 = m33;
M34 = m34;
M41 = m41;
M42 = m42;
M43 = m43;
M44 = m44;
}
public static bool operator ==(Int32Matrix4x4 me, Int32Matrix4x4 other)
{
return
me.M11 == other.M11 && me.M12 == other.M12 && me.M13 == other.M13 && me.M14 == other.M14 &&
me.M21 == other.M21 && me.M22 == other.M22 && me.M23 == other.M23 && me.M24 == other.M24 &&
me.M31 == other.M31 && me.M32 == other.M32 && me.M33 == other.M33 && me.M34 == other.M34 &&
me.M41 == other.M41 && me.M42 == other.M42 && me.M43 == other.M43 && me.M44 == other.M44;
}
public static bool operator !=(Int32Matrix4x4 me, Int32Matrix4x4 other) { return !(me == other); }
public override int GetHashCode() { return M11 ^ M22 ^ M33 ^ M44; }
public bool Equals(Int32Matrix4x4 other) { return other == this; }
public override bool Equals(object obj) { return obj is Int32Matrix4x4 && Equals((Int32Matrix4x4)obj); }
public override string ToString()
{
return
"[" + M11 + " " + M12 + " " + M13 + " " + M14 + "],[" +
"[" + M21 + " " + M22 + " " + M23 + " " + M24 + "],[" +
"[" + M31 + " " + M32 + " " + M33 + " " + M34 + "],[" +
"[" + M41 + " " + M42 + " " + M43 + " " + M44 + "]";
}
}
}

View File

@@ -41,58 +41,61 @@ namespace OpenRA
return new WRot(Roll, Pitch, yaw);
}
public int[] AsQuarternion()
void AsQuarternion(out int x, out int y, out int z, out int w)
{
// Angles increase clockwise
var r = new WAngle(-Roll.Angle / 2);
var p = new WAngle(-Pitch.Angle / 2);
var y = new WAngle(-Yaw.Angle / 2);
var cr = (long)r.Cos();
var sr = (long)r.Sin();
var cp = (long)p.Cos();
var sp = (long)p.Sin();
var cy = (long)y.Cos();
var sy = (long)y.Sin();
var roll = new WAngle(-Roll.Angle / 2);
var pitch = new WAngle(-Pitch.Angle / 2);
var yaw = new WAngle(-Yaw.Angle / 2);
var cr = (long)roll.Cos();
var sr = (long)roll.Sin();
var cp = (long)pitch.Cos();
var sp = (long)pitch.Sin();
var cy = (long)yaw.Cos();
var sy = (long)yaw.Sin();
// Normalized to 1024 == 1.0
return new int[4]
{
(int)((sr * cp * cy - cr * sp * sy) / 1048576), // x
(int)((cr * sp * cy + sr * cp * sy) / 1048576), // y
(int)((cr * cp * sy - sr * sp * cy) / 1048576), // z
(int)((cr * cp * cy + sr * sp * sy) / 1048576) // w
};
x = (int)((sr * cp * cy - cr * sp * sy) / 1048576);
y = (int)((cr * sp * cy + sr * cp * sy) / 1048576);
z = (int)((cr * cp * sy - sr * sp * cy) / 1048576);
w = (int)((cr * cp * cy + sr * sp * sy) / 1048576);
}
public int[] AsMatrix()
public void AsMatrix(out Int32Matrix4x4 mtx)
{
var q = AsQuarternion();
int x, y, z, w;
AsQuarternion(out x, out y, out z, out w);
// Theoretically 1024 * * 2, but may differ slightly due to rounding
var lsq = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
var lsq = x * x + y * y + z * z + w * w;
// Quaternion components use 10 bits, so there's no risk of overflow
var mtx = new int[16];
mtx[0] = lsq - 2 * (q[1] * q[1] + q[2] * q[2]);
mtx[1] = 2 * (q[0] * q[1] + q[2] * q[3]);
mtx[2] = 2 * (q[0] * q[2] - q[1] * q[3]);
mtx[3] = 0;
mtx = new Int32Matrix4x4(
lsq - 2 * (y * y + z * z),
2 * (x * y + z * w),
2 * (x * z - y * w),
0,
mtx[4] = 2 * (q[0] * q[1] - q[2] * q[3]);
mtx[5] = lsq - 2 * (q[0] * q[0] + q[2] * q[2]);
mtx[6] = 2 * (q[1] * q[2] + q[0] * q[3]);
mtx[7] = 0;
2 * (x * y - z * w),
lsq - 2 * (x * x + z * z),
2 * (y * z + x * w),
0,
mtx[8] = 2 * (q[0] * q[2] + q[1] * q[3]);
mtx[9] = 2 * (q[1] * q[2] - q[0] * q[3]);
mtx[10] = lsq - 2 * (q[0] * q[0] + q[1] * q[1]);
mtx[11] = 0;
2 * (x * z + y * w),
2 * (y * z - x * w),
lsq - 2 * (x * x + y * y),
0,
mtx[12] = 0;
mtx[13] = 0;
mtx[14] = 0;
mtx[15] = lsq;
0,
0,
0,
lsq);
}
public Int32Matrix4x4 AsMatrix()
{
Int32Matrix4x4 mtx;
AsMatrix(out mtx);
return mtx;
}

View File

@@ -46,19 +46,20 @@ namespace OpenRA
public WVec Rotate(WRot rot)
{
return Rotate(rot.AsMatrix());
Int32Matrix4x4 mtx;
rot.AsMatrix(out mtx);
return Rotate(ref mtx);
}
public WVec Rotate(int[] rotationMatrix)
public WVec Rotate(ref Int32Matrix4x4 mtx)
{
var mtx = rotationMatrix;
var lx = (long)X;
var ly = (long)Y;
var lz = (long)Z;
return new WVec(
(int)((lx * mtx[0] + ly * mtx[4] + lz * mtx[8]) / mtx[15]),
(int)((lx * mtx[1] + ly * mtx[5] + lz * mtx[9]) / mtx[15]),
(int)((lx * mtx[2] + ly * mtx[6] + lz * mtx[10]) / mtx[15]));
(int)((lx * mtx.M11 + ly * mtx.M21 + lz * mtx.M31) / mtx.M44),
(int)((lx * mtx.M12 + ly * mtx.M22 + lz * mtx.M32) / mtx.M44),
(int)((lx * mtx.M13 + ly * mtx.M23 + lz * mtx.M33) / mtx.M44));
}
public WAngle Yaw

View File

@@ -17,8 +17,8 @@ namespace OpenRA.Mods.Common.Graphics
public struct RangeCircleRenderable : IRenderable, IFinalizedRenderable
{
const int RangeCircleSegments = 32;
static readonly int[][] RangeCircleStartRotations = Exts.MakeArray(RangeCircleSegments, i => WRot.FromFacing(8 * i).AsMatrix());
static readonly int[][] RangeCircleEndRotations = Exts.MakeArray(RangeCircleSegments, i => WRot.FromFacing(8 * i + 6).AsMatrix());
static readonly Int32Matrix4x4[] RangeCircleStartRotations = Exts.MakeArray(RangeCircleSegments, i => WRot.FromFacing(8 * i).AsMatrix());
static readonly Int32Matrix4x4[] RangeCircleEndRotations = Exts.MakeArray(RangeCircleSegments, i => WRot.FromFacing(8 * i + 6).AsMatrix());
readonly WPos centerPosition;
readonly WDist radius;
@@ -58,8 +58,8 @@ namespace OpenRA.Mods.Common.Graphics
var offset = new WVec(radius.Length, 0, 0);
for (var i = 0; i < RangeCircleSegments; i++)
{
var a = wr.Screen3DPosition(centerPosition + offset.Rotate(RangeCircleStartRotations[i]));
var b = wr.Screen3DPosition(centerPosition + offset.Rotate(RangeCircleEndRotations[i]));
var a = wr.Screen3DPosition(centerPosition + offset.Rotate(ref RangeCircleStartRotations[i]));
var b = wr.Screen3DPosition(centerPosition + offset.Rotate(ref RangeCircleEndRotations[i]));
if (contrastWidth > 0)
wcr.DrawLine(a, b, contrastWidth / wr.Viewport.Zoom, contrastColor);