Introduce a new type for representing map coordinates.

To resolve the ambiguity introduced when the introduction of isometric maps meant that cell and map coordinates were no longer equivalent, a new type has been introduced so they can each be represented separately.
This commit is contained in:
RoosterDragon
2014-12-22 19:07:20 +00:00
parent 40c9d0a47d
commit 7cfece6dc0
21 changed files with 257 additions and 232 deletions

View File

@@ -273,7 +273,8 @@ namespace OpenRA.Editor
{
var ui = u * ChunkSize + i;
var vj = v * ChunkSize + j;
var tr = Map.MapTiles.Value[ui, vj];
var uv = new MPos(ui, vj);
var tr = Map.MapTiles.Value[uv];
var tile = TileSetRenderer.Data(tr.Type);
if (tile == null)
continue;
@@ -284,9 +285,9 @@ namespace OpenRA.Editor
for (var y = 0; y < TileSetRenderer.TileSize; y++)
p[(j * TileSetRenderer.TileSize + y) * stride + i * TileSetRenderer.TileSize + x] = Palette.GetColor(rawImage[x + TileSetRenderer.TileSize * y]).ToArgb();
if (Map.MapResources.Value[ui, vj].Type != 0)
if (Map.MapResources.Value[uv].Type != 0)
{
var resourceImage = ResourceTemplates[Map.MapResources.Value[ui, vj].Type].Bitmap;
var resourceImage = ResourceTemplates[Map.MapResources.Value[uv].Type].Bitmap;
var srcdata = resourceImage.LockBits(resourceImage.Bounds(),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

View File

@@ -9,7 +9,6 @@
#endregion
using System;
using System.Drawing;
using Eluant;
using Eluant.ObjectBinding;
using OpenRA.Scripting;
@@ -28,7 +27,6 @@ namespace OpenRA
public static CPos operator +(CVec a, CPos b) { return new CPos(a.X + b.X, a.Y + b.Y); }
public static CPos operator +(CPos a, CVec b) { return new CPos(a.X + b.X, a.Y + b.Y); }
public static CPos operator -(CPos a, CVec b) { return new CPos(a.X - b.X, a.Y - b.Y); }
public static CVec operator -(CPos a, CPos b) { return new CVec(a.X - b.X, a.Y - b.Y); }
public static bool operator ==(CPos me, CPos other) { return me.X == other.X && me.Y == other.Y; }
@@ -37,12 +35,6 @@ namespace OpenRA
public static CPos Max(CPos a, CPos b) { return new CPos(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
public static CPos Min(CPos a, CPos b) { return new CPos(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
public CPos Clamp(Rectangle r)
{
return new CPos(Math.Min(r.Right, Math.Max(X, r.Left)),
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
}
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
public bool Equals(CPos other) { return other == this; }
@@ -50,6 +42,31 @@ namespace OpenRA
public override string ToString() { return X + "," + Y; }
public MPos ToMPos(Map map)
{
return ToMPos(map.TileShape);
}
public MPos ToMPos(TileShape shape)
{
if (shape == TileShape.Rectangle)
return new MPos(X, Y);
// Convert from diamond cell (x, y) position to rectangular map position (u, v)
// - The staggered rows make this fiddly (hint: draw a diagram!)
// (a) Consider the relationships:
// - +1x (even -> odd) adds (0, 1) to (u, v)
// - +1x (odd -> even) adds (1, 1) to (u, v)
// - +1y (even -> odd) adds (-1, 1) to (u, v)
// - +1y (odd -> even) adds (0, 1) to (u, v)
// (b) Therefore:
// - ax + by adds (a - b)/2 to u (only even increments count)
// - ax + by adds a + b to v
var u = (X - Y) / 2;
var v = X + Y;
return new MPos(u, v);
}
#region Scripting interface
public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right)

View File

@@ -44,7 +44,7 @@ namespace OpenRA.Graphics
{
var mapX = x + b.Left;
var mapY = y + b.Top;
var type = tileset[tileset.GetTerrainIndex(mapTiles[mapX, mapY])];
var type = tileset[tileset.GetTerrainIndex(mapTiles[new MPos(mapX, mapY)])];
colors[y * stride + x] = type.Color.ToArgb();
}
}
@@ -74,11 +74,11 @@ namespace OpenRA.Graphics
{
var mapX = x + b.Left;
var mapY = y + b.Top;
if (map.MapResources.Value[mapX, mapY].Type == 0)
if (map.MapResources.Value[new MPos(mapX, mapY)].Type == 0)
continue;
var res = resourceRules.Actors["world"].Traits.WithInterface<ResourceTypeInfo>()
.Where(t => t.ResourceType == map.MapResources.Value[mapX, mapY].Type)
.Where(t => t.ResourceType == map.MapResources.Value[new MPos(mapX, mapY)].Type)
.Select(t => t.TerrainType).FirstOrDefault();
if (res == null)
@@ -114,7 +114,7 @@ namespace OpenRA.Graphics
{
var mapX = x + b.Left;
var mapY = y + b.Top;
var custom = map.CustomTerrain[mapX, mapY];
var custom = map.CustomTerrain[new MPos(mapX, mapY)];
if (custom == byte.MaxValue)
continue;
colors[y * stride + x] = world.TileSet[custom].Color.ToArgb();
@@ -148,9 +148,9 @@ namespace OpenRA.Graphics
var color = t.Trait.RadarSignatureColor(t.Actor);
foreach (var cell in t.Trait.RadarSignatureCells(t.Actor))
{
var uv = Map.CellToMap(map.TileShape, cell);
if (b.Contains(uv.X, uv.Y))
colors[(uv.Y - b.Top) * stride + uv.X - b.Left] = color.ToArgb();
var uv = cell.ToMPos(map);
if (b.Contains(uv.U, uv.V))
colors[(uv.V - b.Top) * stride + uv.U - b.Left] = color.ToArgb();
}
}
}
@@ -174,7 +174,6 @@ namespace OpenRA.Graphics
var shroud = Color.Black.ToArgb();
var fog = Color.FromArgb(128, Color.Black).ToArgb();
var offset = new CVec(b.Left, b.Top);
unsafe
{
@@ -184,11 +183,11 @@ namespace OpenRA.Graphics
var fogObscured = world.FogObscuresTest(map.Cells);
foreach (var uv in map.Cells.MapCoords)
{
var bitmapUv = uv - offset;
if (shroudObscured(uv.X, uv.Y))
colors[bitmapUv.Y * stride + bitmapUv.X] = shroud;
else if (fogObscured(uv.X, uv.Y))
colors[bitmapUv.Y * stride + bitmapUv.X] = fog;
var bitmapXy = new int2(uv.U - b.Left, uv.V - b.Top);
if (shroudObscured(uv))
colors[bitmapXy.Y * stride + bitmapXy.X] = shroud;
else if (fogObscured(uv))
colors[bitmapXy.Y * stride + bitmapXy.X] = fog;
}
}

View File

@@ -44,12 +44,11 @@ namespace OpenRA.Graphics
{
var verticesPerRow = 4 * map.Bounds.Width;
var cells = viewport.VisibleCells;
var shape = wr.World.Map.TileShape;
// Only draw the rows that are visible.
// VisibleCells is clamped to the map, so additional checks are unnecessary
var firstRow = Map.CellToMap(shape, cells.TopLeft).Y - map.Bounds.Top;
var lastRow = Map.CellToMap(shape, cells.BottomRight).Y - map.Bounds.Top + 1;
var firstRow = cells.TopLeft.ToMPos(map).V - map.Bounds.Top;
var lastRow = cells.BottomRight.ToMPos(map).V - map.Bounds.Top + 1;
Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer(
vertexBuffer, verticesPerRow * firstRow, verticesPerRow * (lastRow - firstRow),

View File

@@ -94,8 +94,8 @@ namespace OpenRA.Graphics
var b = map.Bounds;
// Expand to corners of cells
var tl = wr.ScreenPxPosition(map.CenterOfCell(Map.MapToCell(map.TileShape, new CPos(b.Left, b.Top))) - new WVec(512, 512, 0));
var br = wr.ScreenPxPosition(map.CenterOfCell(Map.MapToCell(map.TileShape, new CPos(b.Right, b.Bottom))) + new WVec(511, 511, 0));
var tl = wr.ScreenPxPosition(map.CenterOfCell(new MPos(b.Left, b.Top).ToCPos(map)) - new WVec(512, 512, 0));
var br = wr.ScreenPxPosition(map.CenterOfCell(new MPos(b.Right, b.Bottom).ToCPos(map)) + new WVec(511, 511, 0));
mapBounds = Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
maxGroundHeight = wr.World.TileSet.MaxGroundHeight;
@@ -164,15 +164,15 @@ namespace OpenRA.Graphics
var wbr = worldRenderer.Position(BottomRight);
// Visible rectangle in map coordinates
var ctl = new CPos(wtl.X / 1024, wtl.Y / 1024);
var ctl = new MPos(wtl.X / 1024, wtl.Y / 1024);
var dy = map.TileShape == TileShape.Diamond ? 512 : 1024;
var cbr = new CPos((wbr.X + 1023) / 1024, (wbr.Y + dy - 1) / dy);
var cbr = new MPos((wbr.X + 1023) / 1024, (wbr.Y + dy - 1) / dy);
// Add a 1 cell cordon to prevent holes, then convert back to cell coordinates
var tl = map.Clamp(Map.MapToCell(map.TileShape, ctl - new CVec(1, 1)));
var tl = map.Clamp(new MPos(ctl.U - 1, ctl.V - 1).ToCPos(map));
// Also need to account for height of cells in rows below the bottom
var br = map.Clamp(Map.MapToCell(map.TileShape, cbr + new CVec(1, 2 + maxGroundHeight / 2)));
var br = map.Clamp(new MPos(cbr.U + 1, cbr.V + 2 + maxGroundHeight / 2).ToCPos(map));
cells = new CellRegion(map.TileShape, tl, br);
cellsDirty = false;

64
OpenRA.Game/MPos.cs Normal file
View File

@@ -0,0 +1,64 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
namespace OpenRA
{
public struct MPos : IEquatable<MPos>
{
public readonly int U, V;
public MPos(int u, int v) { U = u; V = v; }
public static readonly MPos Zero = new MPos(0, 0);
public static bool operator ==(MPos me, MPos other) { return me.U == other.U && me.V == other.V; }
public static bool operator !=(MPos me, MPos other) { return !(me == other); }
public override int GetHashCode() { return U.GetHashCode() ^ V.GetHashCode(); }
public bool Equals(MPos other) { return other == this; }
public override bool Equals(object obj) { return obj is MPos && Equals((MPos)obj); }
public MPos Clamp(Rectangle r)
{
return new MPos(Math.Min(r.Right, Math.Max(U, r.Left)),
Math.Min(r.Bottom, Math.Max(V, r.Top)));
}
public override string ToString() { return U + "," + V; }
public CPos ToCPos(Map map)
{
return ToCPos(map.TileShape);
}
public CPos ToCPos(TileShape shape)
{
if (shape == TileShape.Rectangle)
return new CPos(U, V);
// Convert from rectangular map position to diamond cell position
// - The staggered rows make this fiddly (hint: draw a diagram!)
// (a) Consider the relationships:
// - +1u (even -> odd) adds (1, -1) to (x, y)
// - +1v (even -> odd) adds (1, 0) to (x, y)
// - +1v (odd -> even) adds (0, 1) to (x, y)
// (b) Therefore:
// - au + 2bv adds (a + b) to (x, y)
// - a correction factor is added if v is odd
var offset = (V & 1) == 1 ? 1 : 0;
var y = (V - offset) / 2 - U;
var x = V - y;
return new CPos(x, y);
}
}
}

View File

@@ -48,14 +48,13 @@ namespace OpenRA
// Resolve an array index from cell coordinates
int Index(CPos cell)
{
var uv = Map.CellToMap(Shape, cell);
return Index(uv.X, uv.Y);
return Index(cell.ToMPos(Shape));
}
// Resolve an array index from map coordinates
int Index(int u, int v)
int Index(MPos uv)
{
return v * Size.Width + u;
return uv.V * Size.Width + uv.U;
}
/// <summary>Gets or sets the <see cref="OpenRA.CellLayer"/> using cell coordinates</summary>
@@ -76,19 +75,19 @@ namespace OpenRA
}
/// <summary>Gets or sets the layer contents using raw map coordinates (not CPos!)</summary>
public T this[int u, int v]
public T this[MPos uv]
{
get
{
return entries[Index(u, v)];
return entries[Index(uv)];
}
set
{
entries[Index(u, v)] = value;
entries[Index(uv)] = value;
if (CellEntryChanged != null)
CellEntryChanged(Map.MapToCell(Shape, new CPos(u, v)));
CellEntryChanged(uv.ToCPos(Shape));
}
}
@@ -123,7 +122,7 @@ namespace OpenRA
result.Clear(defaultValue);
for (var j = 0; j < height; j++)
for (var i = 0; i < width; i++)
result[i, j] = layer[i, j];
result[new MPos(i, j)] = layer[new MPos(i, j)];
return result;
}

View File

@@ -26,8 +26,8 @@ namespace OpenRA
// Corners in map coordinates
// These will only equal TopLeft and BottomRight for TileShape.Rectangular
readonly CPos mapTopLeft;
readonly CPos mapBottomRight;
readonly MPos mapTopLeft;
readonly MPos mapBottomRight;
public CellRegion(TileShape shape, CPos topLeft, CPos bottomRight)
{
@@ -35,17 +35,15 @@ namespace OpenRA
TopLeft = topLeft;
BottomRight = bottomRight;
mapTopLeft = Map.CellToMap(shape, TopLeft);
mapBottomRight = Map.CellToMap(shape, BottomRight);
mapTopLeft = TopLeft.ToMPos(shape);
mapBottomRight = BottomRight.ToMPos(shape);
}
/// <summary>Expand the specified region with an additional cordon. This may expand the region outside the map borders.</summary>
public static CellRegion Expand(CellRegion region, int cordon)
{
var offset = new CVec(cordon, cordon);
var tl = Map.MapToCell(region.shape, Map.CellToMap(region.shape, region.TopLeft) - offset);
var br = Map.MapToCell(region.shape, Map.CellToMap(region.shape, region.BottomRight) + offset);
var tl = new MPos(region.mapTopLeft.U - cordon, region.mapTopLeft.V - cordon).ToCPos(region.shape);
var br = new MPos(region.mapBottomRight.U + cordon, region.mapBottomRight.V + cordon).ToCPos(region.shape);
return new CellRegion(region.shape, tl, br);
}
@@ -83,8 +81,8 @@ namespace OpenRA
public bool Contains(CPos cell)
{
var uv = Map.CellToMap(shape, cell);
return uv.X >= mapTopLeft.X && uv.X <= mapBottomRight.X && uv.Y >= mapTopLeft.Y && uv.Y <= mapBottomRight.Y;
var uv = cell.ToMPos(shape);
return uv.U >= mapTopLeft.U && uv.U <= mapBottomRight.U && uv.V >= mapTopLeft.V && uv.V <= mapBottomRight.V;
}
public MapCoordsRegion MapCoords
@@ -128,25 +126,25 @@ namespace OpenRA
u += 1;
// Check for column overflow
if (u > r.mapBottomRight.X)
if (u > r.mapBottomRight.U)
{
v += 1;
u = r.mapTopLeft.X;
u = r.mapTopLeft.U;
// Check for row overflow
if (v > r.mapBottomRight.Y)
if (v > r.mapBottomRight.V)
return false;
}
current = Map.MapToCell(r.shape, new CPos(u, v));
current = new MPos(u, v).ToCPos(r.shape);
return true;
}
public void Reset()
{
// Enumerator starts *before* the first element in the sequence.
u = r.mapTopLeft.X - 1;
v = r.mapTopLeft.Y;
u = r.mapTopLeft.U - 1;
v = r.mapTopLeft.V;
}
public CPos Current { get { return current; } }
@@ -154,12 +152,12 @@ namespace OpenRA
public void Dispose() { }
}
public struct MapCoordsRegion : IEnumerable<CPos>
public struct MapCoordsRegion : IEnumerable<MPos>
{
public struct MapCoordsEnumerator : IEnumerator<CPos>
public struct MapCoordsEnumerator : IEnumerator<MPos>
{
readonly CellRegion r;
CPos current;
MPos current;
public MapCoordsEnumerator(CellRegion region)
: this()
@@ -170,30 +168,30 @@ namespace OpenRA
public bool MoveNext()
{
var u = current.X + 1;
var v = current.Y;
var u = current.U + 1;
var v = current.V;
// Check for column overflow
if (u > r.mapBottomRight.X)
if (u > r.mapBottomRight.U)
{
v += 1;
u = r.mapTopLeft.X;
u = r.mapTopLeft.U;
// Check for row overflow
if (v > r.mapBottomRight.Y)
if (v > r.mapBottomRight.V)
return false;
}
current = new CPos(u, v);
current = new MPos(u, v);
return true;
}
public void Reset()
{
current = new CPos(r.mapTopLeft.X - 1, r.mapTopLeft.Y);
current = new MPos(r.mapTopLeft.U - 1, r.mapTopLeft.V);
}
public CPos Current { get { return current; } }
public MPos Current { get { return current; } }
object IEnumerator.Current { get { return Current; } }
public void Dispose() { }
}
@@ -210,7 +208,7 @@ namespace OpenRA
return new MapCoordsEnumerator(r);
}
IEnumerator<CPos> IEnumerable<CPos>.GetEnumerator()
IEnumerator<MPos> IEnumerable<MPos>.GetEnumerator()
{
return GetEnumerator();
}

View File

@@ -367,13 +367,13 @@ namespace OpenRA
cachedTileSet = Exts.Lazy(() => Rules.TileSets[Tileset]);
var tl = Map.MapToCell(TileShape, new CPos(Bounds.Left, Bounds.Top));
var br = Map.MapToCell(TileShape, new CPos(Bounds.Right - 1, Bounds.Bottom - 1));
var tl = new MPos(Bounds.Left, Bounds.Top).ToCPos(this);
var br = new MPos(Bounds.Right - 1, Bounds.Bottom - 1).ToCPos(this);
Cells = new CellRegion(TileShape, tl, br);
CustomTerrain = new CellLayer<byte>(this);
foreach (var uv in Cells.MapCoords)
CustomTerrain[uv.X, uv.Y] = byte.MaxValue;
CustomTerrain[uv] = byte.MaxValue;
}
public Ruleset PreloadRules()
@@ -485,7 +485,7 @@ namespace OpenRA
if (index == byte.MaxValue)
index = (byte)(i % 4 + (j % 4) * 4);
tiles[i, j] = new TerrainTile(tile, index);
tiles[new MPos(i, j)] = new TerrainTile(tile, index);
}
}
}
@@ -506,7 +506,7 @@ namespace OpenRA
s.Position = header.HeightsOffset;
for (var i = 0; i < MapSize.X; i++)
for (var j = 0; j < MapSize.Y; j++)
tiles[i, j] = s.ReadUInt8().Clamp((byte)0, maxHeight);
tiles[new MPos(i, j)] = s.ReadUInt8().Clamp((byte)0, maxHeight);
}
}
@@ -529,7 +529,7 @@ namespace OpenRA
{
var type = s.ReadUInt8();
var density = s.ReadUInt8();
resources[i, j] = new ResourceTile(type, density);
resources[new MPos(i, j)] = new ResourceTile(type, density);
}
}
}
@@ -566,7 +566,7 @@ namespace OpenRA
{
for (var j = 0; j < MapSize.Y; j++)
{
var tile = MapTiles.Value[i, j];
var tile = MapTiles.Value[new MPos(i, j)];
writer.Write(tile.Type);
writer.Write(tile.Index);
}
@@ -577,7 +577,7 @@ namespace OpenRA
if (heightsOffset != 0)
for (var i = 0; i < MapSize.X; i++)
for (var j = 0; j < MapSize.Y; j++)
writer.Write(MapHeight.Value[i, j]);
writer.Write(MapHeight.Value[new MPos(i, j)]);
// Resource data
if (resourcesOffset != 0)
@@ -586,7 +586,7 @@ namespace OpenRA
{
for (var j = 0; j < MapSize.Y; j++)
{
var tile = MapResources.Value[i, j];
var tile = MapResources.Value[new MPos(i, j)];
writer.Write(tile.Type);
writer.Write(tile.Index);
}
@@ -599,13 +599,12 @@ namespace OpenRA
public bool Contains(CPos cell)
{
var uv = CellToMap(TileShape, cell);
return Contains(uv.X, uv.Y);
return Contains(cell.ToMPos(this));
}
public bool Contains(int u, int v)
public bool Contains(MPos uv)
{
return Bounds.Contains(u, v);
return Bounds.Contains(uv.U, uv.V);
}
public WPos CenterOfCell(CPos cell)
@@ -648,46 +647,6 @@ namespace OpenRA
return new CPos(u, v);
}
public static CPos MapToCell(TileShape shape, CPos map)
{
if (shape == TileShape.Rectangle)
return map;
// Convert from rectangular map position to diamond cell position
// - The staggered rows make this fiddly (hint: draw a diagram!)
// (a) Consider the relationships:
// - +1u (even -> odd) adds (1, -1) to (x, y)
// - +1v (even -> odd) adds (1, 0) to (x, y)
// - +1v (odd -> even) adds (0, 1) to (x, y)
// (b) Therefore:
// - au + 2bv adds (a + b) to (x, y)
// - a correction factor is added if v is odd
var offset = (map.Y & 1) == 1 ? 1 : 0;
var y = (map.Y - offset) / 2 - map.X;
var x = map.Y - y;
return new CPos(x, y);
}
public static CPos CellToMap(TileShape shape, CPos cell)
{
if (shape == TileShape.Rectangle)
return cell;
// Convert from diamond cell (x, y) position to rectangular map position (u, v)
// - The staggered rows make this fiddly (hint: draw a diagram!)
// (a) Consider the relationships:
// - +1x (even -> odd) adds (0, 1) to (u, v)
// - +1x (odd -> even) adds (1, 1) to (u, v)
// - +1y (even -> odd) adds (-1, 1) to (u, v)
// - +1y (odd -> even) adds (0, 1) to (u, v)
// (b) Therefore:
// - ax + by adds (a - b)/2 to u (only even increments count)
// - ax + by adds a + b to v
var u = (cell.X - cell.Y) / 2;
var v = cell.X + cell.Y;
return new CPos(u, v);
}
public int FacingBetween(CPos cell, CPos towards, int fallbackfacing)
{
return Traits.Util.GetFacing(CenterOfCell(towards) - CenterOfCell(cell), fallbackfacing);
@@ -700,9 +659,9 @@ namespace OpenRA
var oldMapHeight = MapHeight.Value;
var newSize = new Size(width, height);
MapTiles = Exts.Lazy(() => CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[0, 0]));
MapResources = Exts.Lazy(() => CellLayer.Resize(oldMapResources, newSize, oldMapResources[0, 0]));
MapHeight = Exts.Lazy(() => CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[0, 0]));
MapTiles = Exts.Lazy(() => CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[MPos.Zero]));
MapResources = Exts.Lazy(() => CellLayer.Resize(oldMapResources, newSize, oldMapResources[MPos.Zero]));
MapHeight = Exts.Lazy(() => CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[MPos.Zero]));
MapSize = new int2(newSize);
}
@@ -710,8 +669,8 @@ namespace OpenRA
{
Bounds = Rectangle.FromLTRB(left, top, right, bottom);
var tl = Map.MapToCell(TileShape, new CPos(Bounds.Left, Bounds.Top));
var br = Map.MapToCell(TileShape, new CPos(Bounds.Right - 1, Bounds.Bottom - 1));
var tl = new MPos(Bounds.Left, Bounds.Top).ToCPos(this);
var br = new MPos(Bounds.Right - 1, Bounds.Bottom - 1).ToCPos(this);
Cells = new CellRegion(TileShape, tl, br);
}
@@ -781,8 +740,8 @@ namespace OpenRA
{
for (var i = Bounds.Left; i < Bounds.Right; i++)
{
var type = MapTiles.Value[i, j].Type;
var index = MapTiles.Value[i, j].Index;
var type = MapTiles.Value[new MPos(i, j)].Type;
var index = MapTiles.Value[new MPos(i, j)].Index;
if (!tileset.Templates.ContainsKey(type))
{
Console.WriteLine("Unknown Tile ID {0}".F(type));
@@ -794,18 +753,16 @@ namespace OpenRA
continue;
index = (byte)r.Next(0, template.TilesCount);
MapTiles.Value[i, j] = new TerrainTile(type, index);
MapTiles.Value[new MPos(i, j)] = new TerrainTile(type, index);
}
}
}
public byte GetTerrainIndex(CPos cell)
{
var uv = Map.CellToMap(TileShape, cell);
var u = uv.X;
var v = uv.Y;
var custom = CustomTerrain[u, v];
return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[u, v]);
var uv = cell.ToMPos(this);
var custom = CustomTerrain[uv];
return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[uv]);
}
public TerrainTypeInfo GetTerrainInfo(CPos cell)
@@ -816,7 +773,7 @@ namespace OpenRA
public CPos Clamp(CPos cell)
{
var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1);
return MapToCell(TileShape, CellToMap(TileShape, cell).Clamp(bounds));
return cell.ToMPos(this).Clamp(bounds).ToCPos(this);
}
public CPos ChooseRandomCell(MersenneTwister rand)
@@ -824,7 +781,7 @@ namespace OpenRA
var x = rand.Next(Bounds.Left, Bounds.Right);
var y = rand.Next(Bounds.Top, Bounds.Bottom);
return MapToCell(TileShape, new CPos(x, y));
return new MPos(x, y).ToCPos(this);
}
public CPos ChooseRandomEdgeCell(MersenneTwister rand)
@@ -835,7 +792,7 @@ namespace OpenRA
var x = isX ? rand.Next(Bounds.Left, Bounds.Right) : (edge ? Bounds.Left : Bounds.Right);
var y = !isX ? rand.Next(Bounds.Top, Bounds.Bottom) : (edge ? Bounds.Top : Bounds.Bottom);
return MapToCell(TileShape, new CPos(x, y));
return new MPos(x, y).ToCPos(this);
}
public WRange DistanceToEdge(WPos pos, WVec dir)

View File

@@ -84,6 +84,7 @@
<Compile Include="Activities\Activity.cs" />
<Compile Include="Activities\CallFunc.cs" />
<Compile Include="Actor.cs" />
<Compile Include="MPos.cs" />
<Compile Include="GameRules\Warhead.cs" />
<Compile Include="Graphics\QuadRenderer.cs" />
<Compile Include="Download.cs" />

View File

@@ -29,7 +29,7 @@ namespace OpenRA.Orders
else
{
var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, mi)
.Where(a => a.Info.Traits.Contains<ITargetableInfo>() && !a.FootprintInMapCoords.All(uv => world.ShroudObscures(uv.X, uv.Y)))
.Where(a => a.Info.Traits.Contains<ITargetableInfo>() && !a.Footprint.All(world.ShroudObscures))
.WithHighestSelectionPriority();
target = frozen != null ? Target.FromFrozenActor(frozen) : Target.FromCell(world, xy);
}
@@ -74,7 +74,7 @@ namespace OpenRA.Orders
else
{
var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, mi)
.Where(a => a.Info.Traits.Contains<ITargetableInfo>() && !a.FootprintInMapCoords.All(uv => world.ShroudObscures(uv.X, uv.Y)))
.Where(a => a.Info.Traits.Contains<ITargetableInfo>() && !a.Footprint.All(world.ShroudObscures))
.WithHighestSelectionPriority();
target = frozen != null ? Target.FromFrozenActor(frozen) : Target.FromCell(world, xy);
}

View File

@@ -23,7 +23,7 @@ namespace OpenRA.Traits
public class FrozenActor
{
public readonly CPos[] FootprintInMapCoords;
public readonly MPos[] Footprint;
public readonly CellRegion FootprintRegion;
public readonly WPos CenterPosition;
public readonly Rectangle Bounds;
@@ -40,10 +40,10 @@ namespace OpenRA.Traits
public bool Visible;
public FrozenActor(Actor self, CPos[] footprintInMapCoords, CellRegion footprintRegion)
public FrozenActor(Actor self, MPos[] footprint, CellRegion footprintRegion)
{
actor = self;
FootprintInMapCoords = footprintInMapCoords;
Footprint = footprint;
FootprintRegion = footprintRegion;
CenterPosition = self.CenterPosition;
@@ -59,11 +59,11 @@ namespace OpenRA.Traits
public void Tick(World world, Shroud shroud)
{
// We are doing the following LINQ manually to avoid allocating an extra delegate since this is a hot path.
// Visible = !FootprintInMapCoords.Any(mapCoord => shroud.IsVisibleTest(FootprintRegion)(mapCoord.X, mapCoord.Y));
// Visible = !Footprint.Any(shroud.IsVisibleTest(FootprintRegion));
var isVisibleTest = shroud.IsVisibleTest(FootprintRegion);
Visible = true;
foreach (var mapCoord in FootprintInMapCoords)
if (isVisibleTest(mapCoord.X, mapCoord.Y))
foreach (var uv in Footprint)
if (isVisibleTest(uv))
{
Visible = false;
break;

View File

@@ -57,12 +57,12 @@ namespace OpenRA.Traits
public int Hash { get; private set; }
static readonly Func<int, int, bool> TruthPredicate = (u, v) => true;
readonly Func<int, int, bool> shroudEdgeTest;
readonly Func<int, int, bool> fastExploredTest;
readonly Func<int, int, bool> slowExploredTest;
readonly Func<int, int, bool> fastVisibleTest;
readonly Func<int, int, bool> slowVisibleTest;
static readonly Func<MPos, bool> TruthPredicate = _ => true;
readonly Func<MPos, bool> shroudEdgeTest;
readonly Func<MPos, bool> fastExploredTest;
readonly Func<MPos, bool> slowExploredTest;
readonly Func<MPos, bool> fastVisibleTest;
readonly Func<MPos, bool> slowVisibleTest;
public Shroud(Actor self)
{
@@ -81,7 +81,7 @@ namespace OpenRA.Traits
fogVisibilities = Exts.Lazy(() => self.TraitsImplementing<IFogVisibilityModifier>().ToArray());
shroudEdgeTest = (u, v) => map.Contains(u, v);
shroudEdgeTest = map.Contains;
fastExploredTest = IsExploredCore;
slowExploredTest = IsExplored;
fastVisibleTest = IsVisibleCore;
@@ -233,8 +233,8 @@ namespace OpenRA.Traits
throw new ArgumentException("The map bounds of these shrouds do not match.", "s");
foreach (var uv in map.Cells.MapCoords)
if (s.explored[uv.X, uv.Y])
explored[uv.X, uv.Y] = true;
if (s.explored[uv])
explored[uv] = true;
Invalidate();
}
@@ -242,7 +242,7 @@ namespace OpenRA.Traits
public void ExploreAll(World world)
{
foreach (var uv in map.Cells.MapCoords)
explored[uv.X, uv.Y] = true;
explored[uv] = true;
Invalidate();
}
@@ -250,36 +250,35 @@ namespace OpenRA.Traits
public void ResetExploration()
{
foreach (var uv in map.Cells.MapCoords)
explored[uv.X, uv.Y] = visibleCount[uv.X, uv.Y] > 0;
explored[uv] = visibleCount[uv] > 0;
Invalidate();
}
public bool IsExplored(CPos cell)
{
var uv = Map.CellToMap(map.TileShape, cell);
return IsExplored(uv.X, uv.Y);
return IsExplored(cell.ToMPos(map));
}
public bool IsExplored(int u, int v)
public bool IsExplored(MPos uv)
{
if (!map.Contains(u, v))
if (!map.Contains(uv))
return false;
if (!ShroudEnabled)
return true;
return IsExploredCore(u, v);
return IsExploredCore(uv);
}
bool ShroudEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Shroud; } }
bool IsExploredCore(int u, int v)
bool IsExploredCore(MPos uv)
{
return explored[u, v] && (generatedShroudCount[u, v] == 0 || visibleCount[u, v] > 0);
return explored[uv] && (generatedShroudCount[uv] == 0 || visibleCount[uv] > 0);
}
public Func<int, int, bool> IsExploredTest(CellRegion region)
public Func<MPos, bool> IsExploredTest(CellRegion region)
{
// If the region to test extends outside the map we must use the slow test that checks the map boundary every time.
if (!map.Cells.Contains(region))
@@ -300,29 +299,29 @@ namespace OpenRA.Traits
public bool IsVisible(CPos cell)
{
var uv = Map.CellToMap(map.TileShape, cell);
return IsVisible(uv.X, uv.Y);
var uv = cell.ToMPos(map);
return IsVisible(uv);
}
bool IsVisible(int u, int v)
bool IsVisible(MPos uv)
{
if (!map.Contains(u, v))
if (!map.Contains(uv))
return false;
if (!FogEnabled)
return true;
return IsVisibleCore(u, v);
return IsVisibleCore(uv);
}
bool FogEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Fog; } }
bool IsVisibleCore(int u, int v)
bool IsVisibleCore(MPos uv)
{
return visibleCount[u, v] > 0;
return visibleCount[uv] > 0;
}
public Func<int, int, bool> IsVisibleTest(CellRegion region)
public Func<MPos, bool> IsVisibleTest(CellRegion region)
{
// If the region to test extends outside the map we must use the slow test that checks the map boundary every time.
if (!map.Cells.Contains(region))

View File

@@ -133,9 +133,9 @@ namespace OpenRA.Widgets
{
var preview = Preview();
var tileShape = Game.ModData.Manifest.TileShape;
var point = Map.CellToMap(tileShape, cell);
var dx = (int)(previewScale * (point.X - preview.Bounds.Left));
var dy = (int)(previewScale * (point.Y - preview.Bounds.Top));
var point = cell.ToMPos(tileShape);
var dx = (int)(previewScale * (point.U - preview.Bounds.Left));
var dy = (int)(previewScale * (point.V - preview.Bounds.Top));
return new int2(mapRect.X + dx, mapRect.Y + dy);
}

View File

@@ -24,7 +24,7 @@ namespace OpenRA
{
public class World
{
static readonly Func<int, int, bool> FalsePredicate = (u, v) => false;
static readonly Func<MPos, bool> FalsePredicate = _ => false;
internal readonly TraitDictionary TraitDict = new TraitDictionary();
readonly HashSet<Actor> actors = new HashSet<Actor>();
readonly List<IEffect> effects = new List<IEffect>();
@@ -65,24 +65,24 @@ namespace OpenRA
public bool FogObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(p); }
public bool ShroudObscures(Actor a) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(a); }
public bool ShroudObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(p); }
public bool ShroudObscures(int u, int v) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(u, v); }
public bool ShroudObscures(MPos uv) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(uv); }
public Func<int, int, bool> FogObscuresTest(CellRegion region)
public Func<MPos, bool> FogObscuresTest(CellRegion region)
{
var rp = RenderPlayer;
if (rp == null)
return FalsePredicate;
var predicate = rp.Shroud.IsVisibleTest(region);
return (u, v) => !predicate(u, v);
return uv => !predicate(uv);
}
public Func<int, int, bool> ShroudObscuresTest(CellRegion region)
public Func<MPos, bool> ShroudObscuresTest(CellRegion region)
{
var rp = RenderPlayer;
if (rp == null)
return FalsePredicate;
var predicate = rp.Shroud.IsExploredTest(region);
return (u, v) => !predicate(u, v);
return uv => !predicate(uv);
}
public bool IsReplay

View File

@@ -29,7 +29,7 @@ namespace OpenRA.Mods.Common.Traits
[Sync] public int VisibilityHash;
readonly bool startsRevealed;
readonly CPos[] footprintInMapsCoords;
readonly MPos[] footprint;
readonly CellRegion footprintRegion;
readonly Lazy<IToolTip> tooltip;
@@ -44,9 +44,9 @@ namespace OpenRA.Mods.Common.Traits
{
// Spawned actors (e.g. building husks) shouldn't be revealed
startsRevealed = info.StartsRevealed && !init.Contains<ParentActorInit>();
var footprint = FootprintUtils.Tiles(init.Self).ToList();
footprintInMapsCoords = footprint.Select(cell => Map.CellToMap(init.World.Map.TileShape, cell)).ToArray();
footprintRegion = CellRegion.BoundingRegion(init.World.Map.TileShape, footprint);
var footprintCells = FootprintUtils.Tiles(init.Self).ToList();
footprint = footprintCells.Select(cell => cell.ToMPos(init.World.Map)).ToArray();
footprintRegion = CellRegion.BoundingRegion(init.World.Map.TileShape, footprintCells);
tooltip = Exts.Lazy(() => init.Self.TraitsImplementing<IToolTip>().FirstOrDefault());
tooltip = Exts.Lazy(() => init.Self.TraitsImplementing<IToolTip>().FirstOrDefault());
health = Exts.Lazy(() => init.Self.TraitOrDefault<Health>());
@@ -69,11 +69,11 @@ namespace OpenRA.Mods.Common.Traits
foreach (var p in self.World.Players)
{
// We are doing the following LINQ manually to avoid allocating an extra delegate since this is a hot path.
// var isVisible = footprintInMapsCoords.Any(mapCoord => p.Shroud.IsVisibleTest(footprintRegion)(mapCoord.X, mapCoord.Y));
// var isVisible = footprint.Any(p.Shroud.IsVisibleTest(footprintRegion));
var isVisibleTest = p.Shroud.IsVisibleTest(footprintRegion);
var isVisible = false;
foreach (var mapCoord in footprintInMapsCoords)
if (isVisibleTest(mapCoord.X, mapCoord.Y))
foreach (var uv in footprint)
if (isVisibleTest(uv))
{
isVisible = true;
break;
@@ -89,7 +89,7 @@ namespace OpenRA.Mods.Common.Traits
foreach (var p in self.World.Players)
{
visible[p] |= startsRevealed;
p.PlayerActor.Trait<FrozenActorLayer>().Add(frozen[p] = new FrozenActor(self, footprintInMapsCoords, footprintRegion));
p.PlayerActor.Trait<FrozenActorLayer>().Add(frozen[p] = new FrozenActor(self, footprint, footprintRegion));
}
initialized = true;

View File

@@ -334,7 +334,7 @@ namespace OpenRA.Mods.Common.Traits
defaultCellInfoLayer = new CellLayer<CellInfo>(map);
for (var v = 0; v < mapSize.Height; v++)
for (var u = 0; u < mapSize.Width; u++)
defaultCellInfoLayer[u, v] = new CellInfo(int.MaxValue, Map.MapToCell(map.TileShape, new CPos(u, v)), false);
defaultCellInfoLayer[new MPos(u, v)] = new CellInfo(int.MaxValue, new MPos(u, v).ToCPos(map), false);
}
result.CopyValuesFrom(defaultCellInfoLayer);

View File

@@ -36,12 +36,12 @@ namespace OpenRA.Mods.Common.Traits
var shroudObscured = world.ShroudObscuresTest(wr.Viewport.VisibleCells);
foreach (var uv in wr.Viewport.VisibleCells.MapCoords)
{
if (shroudObscured(uv.X, uv.Y))
if (shroudObscured(uv))
continue;
var c = render[uv.X, uv.Y];
var c = render[uv];
if (c.Sprite != null)
new SpriteRenderable(c.Sprite, wr.World.Map.CenterOfCell(Map.MapToCell(world.Map.TileShape, uv)),
new SpriteRenderable(c.Sprite, wr.World.Map.CenterOfCell(uv.ToCPos(world.Map)),
WVec.Zero, -511, c.Type.Palette, 1f, true).Render(wr); // TODO ZOffset is ignored
}
}

View File

@@ -151,17 +151,13 @@ namespace OpenRA.Mods.Common.Traits
notVisibleEdges = info.UseExtendedIndex ? Edges.AllSides : Edges.AllCorners;
}
Edges GetEdges(int u, int v, Func<int, int, bool> isVisible)
Edges GetEdges(MPos uv, Func<MPos, bool> isVisible)
{
if (!isVisible(u, v))
if (!isVisible(uv))
return notVisibleEdges;
var cell = Map.MapToCell(map.TileShape, new CPos(u, v));
Func<CPos, bool> isCellVisible = c =>
{
var uv = Map.CellToMap(map.TileShape, c);
return isVisible(uv.X, uv.Y);
};
var cell = uv.ToCPos(map);
Func<CPos, bool> isCellVisible = c => isVisible(c.ToMPos(map));
// If a side is shrouded then we also count the corners
var edge = Edges.None;
@@ -208,18 +204,16 @@ namespace OpenRA.Mods.Common.Traits
// Adds a 1-cell border around the border to cover any sprites peeking outside the map
foreach (var uv in CellRegion.Expand(w.Map.Cells, 1).MapCoords)
{
var u = uv.X;
var v = uv.Y;
var screen = wr.ScreenPosition(w.Map.CenterOfCell(Map.MapToCell(map.TileShape, uv)));
var screen = wr.ScreenPosition(w.Map.CenterOfCell(uv.ToCPos(map)));
var variant = (byte)Game.CosmeticRandom.Next(info.ShroudVariants.Length);
tiles[u, v] = new ShroudTile(screen, variant);
tiles[uv] = new ShroudTile(screen, variant);
// Set the cells outside the border so they don't need to be touched again
if (!map.Contains(u, v))
if (!map.Contains(uv))
{
var shroudTile = tiles[u, v];
var shroudTile = tiles[uv];
shroudTile.Shroud = GetTile(shroudSprites, notVisibleEdges, variant);
tiles[u, v] = shroudTile;
tiles[uv] = shroudTile;
}
}
@@ -263,15 +257,13 @@ namespace OpenRA.Mods.Common.Traits
var visibleUnderFog = shroud.IsVisibleTest(updatedRegion);
foreach (var uv in updatedRegion.MapCoords)
{
var u = uv.X;
var v = uv.Y;
var shrouded = GetEdges(u, v, visibleUnderShroud);
var fogged = GetEdges(u, v, visibleUnderFog);
var shroudTile = tiles[u, v];
var shrouded = GetEdges(uv, visibleUnderShroud);
var fogged = GetEdges(uv, visibleUnderFog);
var shroudTile = tiles[uv];
var variant = shroudTile.Variant;
shroudTile.Shroud = GetTile(shroudSprites, shrouded, variant);
shroudTile.Fog = GetTile(fogSprites, fogged, variant);
tiles[u, v] = shroudTile;
tiles[uv] = shroudTile;
}
}
@@ -294,7 +286,7 @@ namespace OpenRA.Mods.Common.Traits
foreach (var uv in CellRegion.Expand(wr.Viewport.VisibleCells, 1).MapCoords)
{
var t = tiles[uv.X, uv.Y];
var t = tiles[uv];
if (t.Shroud != null)
{

View File

@@ -84,10 +84,10 @@ namespace OpenRA.Mods.Common.Traits
foreach (var uv in wr.Viewport.VisibleCells.MapCoords)
{
var lr = Game.Renderer.WorldLineRenderer;
var pos = wr.World.Map.CenterOfCell(Map.MapToCell(wr.World.Map.TileShape, uv));
var pos = wr.World.Map.CenterOfCell(uv.ToCPos(wr.World.Map));
var height = (int)wr.World.Map.MapHeight.Value[uv.X, uv.Y];
var tile = wr.World.Map.MapTiles.Value[uv.X, uv.Y];
var height = (int)wr.World.Map.MapHeight.Value[uv];
var tile = wr.World.Map.MapTiles.Value[uv];
TerrainTileInfo tileInfo = null;

View File

@@ -91,7 +91,7 @@ namespace OpenRA.Mods.Common.Widgets
void UpdateTerrainCell(CPos cell)
{
var stride = radarSheet.Size.Width;
var uv = Map.CellToMap(world.Map.TileShape, cell);
var uv = cell.ToMPos(world.Map);
var terrain = world.Map.GetTerrainInfo(cell);
var dx = terrainSprite.Bounds.Left - world.Map.Bounds.Left;
@@ -102,7 +102,7 @@ namespace OpenRA.Mods.Common.Widgets
fixed (byte* colorBytes = &radarData[0])
{
var colors = (int*)colorBytes;
colors[(uv.Y + dy) * stride + uv.X + dx] = terrain.Color.ToArgb();
colors[(uv.V + dy) * stride + uv.U + dx] = terrain.Color.ToArgb();
}
}
}
@@ -110,7 +110,7 @@ namespace OpenRA.Mods.Common.Widgets
void UpdateShroudCell(CPos cell)
{
var stride = radarSheet.Size.Width;
var uv = Map.CellToMap(world.Map.TileShape, cell);
var uv = cell.ToMPos(world.Map);
var dx = shroudSprite.Bounds.Left - world.Map.Bounds.Left;
var dy = shroudSprite.Bounds.Top - world.Map.Bounds.Top;
@@ -125,7 +125,7 @@ namespace OpenRA.Mods.Common.Widgets
fixed (byte* colorBytes = &radarData[0])
{
var colors = (int*)colorBytes;
colors[(uv.Y + dy) * stride + uv.X + dx] = color;
colors[(uv.V + dy) * stride + uv.U + dx] = color;
}
}
}
@@ -291,10 +291,10 @@ namespace OpenRA.Mods.Common.Widgets
var color = t.Trait.RadarSignatureColor(t.Actor);
foreach (var cell in t.Trait.RadarSignatureCells(t.Actor))
{
var uv = Map.CellToMap(world.Map.TileShape, cell);
var uv = cell.ToMPos(world.Map);
if (world.Map.Bounds.Contains(uv.X, uv.Y))
colors[(uv.Y + dy) * stride + uv.X + dx] = color.ToArgb();
if (world.Map.Bounds.Contains(uv.U, uv.V))
colors[(uv.V + dy) * stride + uv.U + dx] = color.ToArgb();
}
}
}
@@ -329,10 +329,9 @@ namespace OpenRA.Mods.Common.Widgets
int2 CellToMinimapPixel(CPos p)
{
var mapOrigin = new CVec(world.Map.Bounds.Left, world.Map.Bounds.Top);
var mapOffset = Map.CellToMap(world.Map.TileShape, p) - mapOrigin;
return new int2(mapRect.X, mapRect.Y) + (previewScale * new float2(mapOffset.X, mapOffset.Y)).ToInt2();
var uv = p.ToMPos(world.Map);
var mapOffset = new float2(uv.U - world.Map.Bounds.Left, uv.V - world.Map.Bounds.Top);
return new int2(mapRect.X, mapRect.Y) + (previewScale * mapOffset).ToInt2();
}
CPos MinimapPixelToCell(int2 p)
@@ -340,7 +339,7 @@ namespace OpenRA.Mods.Common.Widgets
var viewOrigin = new float2(mapRect.X, mapRect.Y);
var mapOrigin = new float2(world.Map.Bounds.Left, world.Map.Bounds.Top);
var fcell = mapOrigin + (1f / previewScale) * (p - viewOrigin);
return Map.MapToCell(world.Map.TileShape, new CPos((int)fcell.X, (int)fcell.Y));
return new MPos((int)fcell.X, (int)fcell.Y).ToCPos(world.Map);
}
}
}