diff --git a/OpenRA.Game/Graphics/QuadRenderer.cs b/OpenRA.Game/Graphics/QuadRenderer.cs new file mode 100644 index 0000000000..26ab90664d --- /dev/null +++ b/OpenRA.Game/Graphics/QuadRenderer.cs @@ -0,0 +1,60 @@ +#region Copyright & License Information +/* + * Copyright 2007-2011 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.Drawing; +using OpenRA.FileFormats.Graphics; + +namespace OpenRA.Graphics +{ + public class QuadRenderer : Renderer.IBatchRenderer + { + Renderer renderer; + IShader shader; + + Vertex[] vertices = new Vertex[Renderer.TempBufferSize]; + int nv = 0; + + public QuadRenderer(Renderer renderer, IShader shader) + { + this.renderer = renderer; + this.shader = shader; + } + + public void Flush() + { + if (nv > 0) + { + shader.Render(() => + { + var vb = renderer.GetTempVertexBuffer(); + vb.SetData(vertices, nv); + renderer.DrawBatch(vb, 0, nv, PrimitiveType.QuadList); + }); + + nv = 0; + } + } + + public void FillRect(RectangleF r, Color color) + { + Renderer.CurrentBatchRenderer = this; + + if (nv + 4 > Renderer.TempBufferSize) + Flush(); + + vertices[nv] = new Vertex(new float2(r.Left, r.Top), new float2(color.R / 255.0f, color.G / 255.0f), new float2(color.B / 255.0f, color.A / 255.0f)); + vertices[nv + 1] = new Vertex(new float2(r.Right, r.Top), new float2(color.R / 255.0f, color.G / 255.0f), new float2(color.B / 255.0f, color.A / 255.0f)); + vertices[nv + 2] = new Vertex(new float2(r.Right, r.Bottom), new float2(color.R / 255.0f, color.G / 255.0f), new float2(color.B / 255.0f, color.A / 255.0f)); + vertices[nv + 3] = new Vertex(new float2(r.Left, r.Bottom), new float2(color.R / 255.0f, color.G / 255.0f), new float2(color.B / 255.0f, color.A / 255.0f)); + + nv += 4; + } + } +} diff --git a/OpenRA.Game/Graphics/Renderer.cs b/OpenRA.Game/Graphics/Renderer.cs index 8be5040802..d98ddecd9d 100644 --- a/OpenRA.Game/Graphics/Renderer.cs +++ b/OpenRA.Game/Graphics/Renderer.cs @@ -28,6 +28,7 @@ namespace OpenRA.Graphics internal static int TempBufferCount; public SpriteRenderer WorldSpriteRenderer { get; private set; } + public QuadRenderer WorldQuadRenderer { get; private set; } public LineRenderer WorldLineRenderer { get; private set; } public LineRenderer LineRenderer { get; private set; } public SpriteRenderer RgbaSpriteRenderer { get; private set; } @@ -48,6 +49,7 @@ namespace OpenRA.Graphics WorldSpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp")); WorldLineRenderer = new LineRenderer(this, device.CreateShader("line")); LineRenderer = new LineRenderer(this, device.CreateShader("line")); + WorldQuadRenderer = new QuadRenderer(this, device.CreateShader("line")); RgbaSpriteRenderer = new SpriteRenderer(this, device.CreateShader("rgba")); SpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp")); diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 890b04c2ca..e1d4cc465c 100755 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -80,6 +80,7 @@ + diff --git a/OpenRA.Mods.RA/Move/PathFinder.cs b/OpenRA.Mods.RA/Move/PathFinder.cs index 8705463283..2ef3f8f452 100755 --- a/OpenRA.Mods.RA/Move/PathFinder.cs +++ b/OpenRA.Mods.RA/Move/PathFinder.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using OpenRA.FileFormats; using OpenRA.Support; using OpenRA.Traits; @@ -125,21 +126,43 @@ namespace OpenRA.Mods.RA.Move { using (fromSrc) using (fromDest) + { + List path = null; + while (!fromSrc.queue.Empty && !fromDest.queue.Empty) { /* make some progress on the first search */ var p = fromSrc.Expand(world); - if (fromDest.cellInfo[p.X, p.Y].Seen && fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity) - return MakeBidiPath(fromSrc, fromDest, p); + if (fromDest.cellInfo[p.X, p.Y].Seen && + fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity) + { + path = MakeBidiPath(fromSrc, fromDest, p); + break; + } /* make some progress on the second search */ var q = fromDest.Expand(world); - if (fromSrc.cellInfo[q.X, q.Y].Seen && fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity) - return MakeBidiPath(fromSrc, fromDest, q); + if (fromSrc.cellInfo[q.X, q.Y].Seen && + fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity) + { + path = MakeBidiPath(fromSrc, fromDest, q); + break; + } } + var dbg = world.WorldActor.TraitOrDefault(); + if (dbg != null) + { + dbg.AddLayer(fromSrc.considered.Select(p => new Pair(p, fromSrc.cellInfo[p.X, p.Y].MinCost)), fromSrc.maxCost); + dbg.AddLayer(fromDest.considered.Select(p => new Pair(p, fromDest.cellInfo[p.X, p.Y].MinCost)), fromDest.maxCost); + } + + if (path != null) + return path; + } + return new List(0); } } diff --git a/OpenRA.Mods.RA/Move/PathSearch.cs b/OpenRA.Mods.RA/Move/PathSearch.cs index 8261f807b7..be8b3d6d45 100755 --- a/OpenRA.Mods.RA/Move/PathSearch.cs +++ b/OpenRA.Mods.RA/Move/PathSearch.cs @@ -26,7 +26,8 @@ namespace OpenRA.Mods.RA.Move public bool checkForBlocked; public Actor ignoreBuilding; public bool inReverse; - + public HashSet considered; + public int maxCost; MobileInfo mobileInfo; Actor self; public Player owner { get { return self.Owner; } } @@ -39,6 +40,8 @@ namespace OpenRA.Mods.RA.Move this.self = self; customCost = null; queue = new PriorityQueue(); + considered = new HashSet(); + maxCost = 0; } public PathSearch InReverse() @@ -108,14 +111,20 @@ namespace OpenRA.Mods.RA.Move return p.Location; } + // This current cell is ok; check all immediate directions: + considered.Add(p.Location); + foreach( CVec d in directions ) { CPos newHere = p.Location + d; - if (!world.Map.IsInMap(newHere.X, newHere.Y)) continue; + // Is this direction flat-out unusable or already seen? + if (!world.Map.IsInMap(newHere.X, newHere.Y)) + continue; if (cellInfo[newHere.X, newHere.Y].Seen) continue; + // Now we may seriously consider this direction using heuristics: var costHere = mobileInfo.MovementCostForCell(world, newHere); if (costHere == int.MaxValue) @@ -134,8 +143,12 @@ namespace OpenRA.Mods.RA.Move int cellCost = costHere; if (d.X * d.Y != 0) cellCost = (cellCost * 34) / 24; + int userCost = 0; if (customCost != null) - cellCost += customCost(newHere); + { + userCost = customCost(newHere); + cellCost += userCost; + } // directional bonuses for smoother flow! if (LaneBias != 0) @@ -151,6 +164,7 @@ namespace OpenRA.Mods.RA.Move int newCost = cellInfo[p.Location.X, p.Location.Y].MinCost + cellCost; + // Cost is even higher; next direction: if (newCost >= cellInfo[newHere.X, newHere.Y].MinCost) continue; @@ -158,7 +172,11 @@ namespace OpenRA.Mods.RA.Move cellInfo[newHere.X, newHere.Y].MinCost = newCost; queue.Add(new PathDistance(newCost + est, newHere)); + + if (newCost > maxCost) maxCost = newCost; + considered.Add(newHere); } + return p.Location; } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 00c0d47f48..735cae25ae 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -403,6 +403,7 @@ + diff --git a/OpenRA.Mods.RA/World/DebugOverlay.cs b/OpenRA.Mods.RA/World/DebugOverlay.cs new file mode 100644 index 0000000000..4d1f1b8af0 --- /dev/null +++ b/OpenRA.Mods.RA/World/DebugOverlay.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class DebugOverlayInfo : Traits.TraitInfo + { + } + + class DebugOverlay : IRenderOverlay, IWorldLoaded + { + int[,] layer; + int refreshTick; + World world; + + public void WorldLoaded(World w) + { + this.world = w; + this.layer = new int[w.Map.MapSize.X, w.Map.MapSize.Y]; + this.refreshTick = 0; + } + + public void AddLayer(IEnumerable> cellWeights, int maxWeight) + { + if (maxWeight == 0) return; + + foreach (var p in cellWeights) + layer[p.First.X, p.First.Y] = layer[p.First.X, p.First.Y] / 2 + (p.Second * 128 / maxWeight); + } + + public void Render(WorldRenderer wr) + { + var qr = Game.Renderer.WorldQuadRenderer; + bool doSwap = refreshTick - world.FrameNumber <= 0; + if (doSwap) refreshTick = world.FrameNumber + 20; + + for (int j = world.Map.Bounds.Top; j <= world.Map.Bounds.Bottom; ++j) + for (int i = world.Map.Bounds.Left; i <= world.Map.Bounds.Right; ++i) + { + if (!world.Map.IsInMap(i, j)) continue; + + var cell = new CPos(i, j); + var pix = cell.ToPPos(); + + var w = Math.Max(0, Math.Min(layer[i, j], 224)); + if (doSwap) + { + layer[i, j] = layer[i, j] * 4 / 5; + } + qr.FillRect(new RectangleF(pix.X, pix.Y, Game.CellSize, Game.CellSize), Color.FromArgb(w, Color.White)); + } + } + } +} diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml index 0999f4ce4e..6b2f3ae00b 100644 --- a/mods/ra/rules/system.yaml +++ b/mods/ra/rules/system.yaml @@ -455,7 +455,7 @@ Player: BaseAttackNotifier: PlayerStatistics: -World: +World: OpenWidgetAtGameStart: Widget: INGAME_ROOT ObserverWidget: OBSERVER_ROOT @@ -562,6 +562,7 @@ World: Type:Crater Types:cr1,cr2,cr3,cr4,cr5,cr6 Depths:5,5,5,5,5,5 + DebugOverlay: SpawnMapActors: CreateMPPlayers: MPStartLocations: