Replace MapGrid.CellCorners with a new CellRamp struct.

This commit is contained in:
Paul Chote
2020-04-28 00:52:40 +01:00
committed by atlimit8
parent 4614f6febe
commit 5af12440ba
3 changed files with 126 additions and 73 deletions

View File

@@ -263,7 +263,7 @@ namespace OpenRA.Graphics
if (Math.Abs(s.X - world.X) <= tileSize.Width && Math.Abs(s.Y - world.Y) <= tileSize.Height)
{
var ramp = map.Ramp.Contains(uv) ? map.Ramp[uv] : 0;
var corners = map.Grid.CellCorners[ramp];
var corners = map.Grid.Ramps[ramp].Corners;
var pos = map.CenterOfCell(uv.ToCPos(map));
var screen = corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToArray();

View File

@@ -9,7 +9,6 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -20,6 +19,81 @@ namespace OpenRA
{
public enum MapGridType { Rectangular, RectangularIsometric }
public enum RampSplit { Flat, X, Y }
public enum RampCornerHeight { Low = 0, Half = 1, Full = 2 }
public struct CellRamp
{
public readonly WVec[] Corners;
public readonly WVec[][] Polygons;
public CellRamp(MapGridType type, RampCornerHeight tl = RampCornerHeight.Low, RampCornerHeight tr = RampCornerHeight.Low, RampCornerHeight br = RampCornerHeight.Low, RampCornerHeight bl = RampCornerHeight.Low, RampSplit split = RampSplit.Flat)
{
if (type == MapGridType.RectangularIsometric)
{
Corners = new[]
{
new WVec(0, -724, 724 * (int)tl),
new WVec(724, 0, 724 * (int)tr),
new WVec(0, 724, 724 * (int)br),
new WVec(-724, 0, 724 * (int)bl),
};
}
else
{
Corners = new[]
{
new WVec(-512, -512, 512 * (int)tl),
new WVec(512, -512, 512 * (int)tr),
new WVec(512, 512, 512 * (int)br),
new WVec(-512, 512, 512 * (int)bl)
};
}
if (split == RampSplit.X)
{
Polygons = new[]
{
new[] { Corners[0], Corners[1], Corners[3] },
new[] { Corners[1], Corners[2], Corners[3] }
};
}
else if (split == RampSplit.Y)
{
Polygons = new[]
{
new[] { Corners[0], Corners[1], Corners[2] },
new[] { Corners[0], Corners[2], Corners[3] }
};
}
else
Polygons = new[] { Corners };
}
public WDist DistanceAboveTerrain(WVec delta)
{
// Enumerate over the polygons, assuming that they are triangles
// If the ramp is not split we will take the first three vertices of the corners as a valid triangle
WVec[] p = null;
var u = 0;
var v = 0;
for (var i = 0; i < Polygons.Length; i++)
{
p = Polygons[i];
u = ((p[1].Y - p[2].Y) * (delta.X - p[2].X) - (p[1].X - p[2].X) * (delta.Y - p[2].Y)) / 1024;
v = ((p[0].X - p[2].X) * (delta.Y - p[2].Y) - (p[0].Y - p[2].Y) * (delta.X - p[2].X)) / 1024;
// Point is within the triangle if 0 <= u,v <= 1024
if (u >= 0 && u <= 1024 && v >= 0 && v <= 1024)
break;
}
// Calculate w from u,v and interpolate height
var dz = (u * p[0].Z + v * p[1].Z + (1024 - u - v) * p[2].Z) / 1024;
return new WDist(delta.Z - dz);
}
}
public class MapGrid : IGlobalModData
{
public readonly MapGridType Type = MapGridType.Rectangular;
@@ -41,43 +115,7 @@ namespace OpenRA
new WVec(256, 256, 0), // bottom right - index 5
};
public WVec[][] CellCorners { get; private set; }
readonly int[][] cellCornerHalfHeights = new int[][]
{
// Flat
new[] { 0, 0, 0, 0 },
// Slopes (two corners high)
new[] { 0, 0, 1, 1 },
new[] { 1, 0, 0, 1 },
new[] { 1, 1, 0, 0 },
new[] { 0, 1, 1, 0 },
// Slopes (one corner high)
new[] { 0, 0, 0, 1 },
new[] { 1, 0, 0, 0 },
new[] { 0, 1, 0, 0 },
new[] { 0, 0, 1, 0 },
// Slopes (three corners high)
new[] { 1, 0, 1, 1 },
new[] { 1, 1, 0, 1 },
new[] { 1, 1, 1, 0 },
new[] { 0, 1, 1, 1 },
// Slopes (two corners high, one corner double high)
new[] { 1, 0, 1, 2 },
new[] { 2, 1, 0, 1 },
new[] { 1, 2, 1, 0 },
new[] { 0, 1, 2, 1 },
// Slopes (two corners high, alternating)
new[] { 1, 0, 1, 0 },
new[] { 0, 1, 0, 1 },
new[] { 1, 0, 1, 0 },
new[] { 0, 1, 0, 1 }
};
public CellRamp[] Ramps { get; private set; }
internal readonly CVec[][] TilesByDistance;
@@ -96,34 +134,46 @@ namespace OpenRA
throw new InvalidDataException("Subcell default index must be a valid index into the offset triples and must be greater than 0 for mods with subcells");
}
var makeCorners = Type == MapGridType.RectangularIsometric ?
(Func<int[], WVec[]>)IsometricCellCorners : RectangularCellCorners;
CellCorners = cellCornerHalfHeights.Select(makeCorners).ToArray();
// Slope types are hardcoded following the convention from the TS and RA2 map format
Ramps = new[]
{
// Flat
new CellRamp(Type),
// Two adjacent corners raised by half a cell
new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Half),
new CellRamp(Type, br: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, tl: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half),
// One corner raised by half a cell
new CellRamp(Type, br: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, tl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, tr: RampCornerHeight.Half, split: RampSplit.Y),
// Three corners raised by half a cell
new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),
// Full tile sloped (mid corners raised by half cell, far corner by full cell)
new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Full, bl: RampCornerHeight.Half),
new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Full),
new CellRamp(Type, tl: RampCornerHeight.Full, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Full, br: RampCornerHeight.Half),
// Two opposite corners raised by half a cell
new CellRamp(Type, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.X),
};
TilesByDistance = CreateTilesByDistance();
}
static WVec[] IsometricCellCorners(int[] cornerHeight)
{
return new WVec[]
{
new WVec(-724, 0, 724 * cornerHeight[0]),
new WVec(0, -724, 724 * cornerHeight[1]),
new WVec(724, 0, 724 * cornerHeight[2]),
new WVec(0, 724, 724 * cornerHeight[3])
};
}
static WVec[] RectangularCellCorners(int[] cornerHeight)
{
return new WVec[]
{
new WVec(-512, -512, 512 * cornerHeight[0]),
new WVec(512, -512, 512 * cornerHeight[1]),
new WVec(512, 512, 512 * cornerHeight[2]),
new WVec(-512, 512, 512 * cornerHeight[3])
};
}
CVec[][] CreateTilesByDistance()
{
var ts = new List<CVec>[MaximumTileSearchRange + 1];

View File

@@ -63,24 +63,27 @@ namespace OpenRA.Mods.Common.Traits
continue;
var height = (int)map.Height[uv];
var corners = map.Grid.CellCorners[map.Ramp[uv]];
var r = map.Grid.Ramps[map.Ramp[uv]];
var pos = map.CenterOfCell(uv.ToCPos(map));
var width = uv == mouseCell ? 3 : 1;
// Colors change between points, so render separately
for (var i = 0; i < 4; i++)
foreach (var p in r.Polygons)
{
var j = (i + 1) % 4;
var start = pos + corners[i];
var end = pos + corners[j];
var startColor = colors[height + corners[i].Z / 512];
var endColor = colors[height + corners[j].Z / 512];
yield return new LineAnnotationRenderable(start, end, width, startColor, endColor);
for (var i = 0; i < p.Length; i++)
{
var j = (i + 1) % p.Length;
var start = pos + p[i];
var end = pos + p[j];
var startColor = colors[height + p[i].Z / 512];
var endColor = colors[height + p[j].Z / 512];
yield return new LineAnnotationRenderable(start, end, width, startColor, endColor);
}
}
}
// Projected cell coordinates for the current cell
var projectedCorners = map.Grid.CellCorners[0];
var projectedCorners = map.Grid.Ramps[0].Corners;
foreach (var puv in map.ProjectedCellsCovering(mouseCell))
{
var pos = map.CenterOfCell(((MPos)puv).ToCPos(map));