From 7d0de5645f64990c721147cbb848277912792e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Sun, 10 Mar 2013 07:32:35 +0100 Subject: [PATCH 1/6] Added QuadRenderer to render shaded/colored quads. Added DebugOverlay to World to show A* bidi search cost per cell. --- OpenRA.Game/Graphics/QuadRenderer.cs | 60 ++++++++++++++++++++++++++++ OpenRA.Game/Graphics/Renderer.cs | 2 + OpenRA.Game/OpenRA.Game.csproj | 1 + OpenRA.Mods.RA/Move/PathFinder.cs | 31 ++++++++++++-- OpenRA.Mods.RA/Move/PathSearch.cs | 24 +++++++++-- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 + OpenRA.Mods.RA/World/DebugOverlay.cs | 60 ++++++++++++++++++++++++++++ mods/ra/rules/system.yaml | 3 +- 8 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 OpenRA.Game/Graphics/QuadRenderer.cs create mode 100644 OpenRA.Mods.RA/World/DebugOverlay.cs 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: From 493eb10b965e9ebfb9d3ab5501da08459b2b2e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Sun, 10 Mar 2013 07:33:25 +0100 Subject: [PATCH 2/6] Now coloring A* cells by owning player color. Added checkbox to cheats menu. --- OpenRA.Mods.RA/Move/PathFinder.cs | 7 +-- OpenRA.Mods.RA/Widgets/Logic/CheatsLogic.cs | 5 ++ OpenRA.Mods.RA/World/DebugOverlay.cs | 51 +++++++++++++-------- mods/ra/chrome/cheats.yaml | 8 +++- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/OpenRA.Mods.RA/Move/PathFinder.cs b/OpenRA.Mods.RA/Move/PathFinder.cs index 2ef3f8f452..d2eb745c0f 100755 --- a/OpenRA.Mods.RA/Move/PathFinder.cs +++ b/OpenRA.Mods.RA/Move/PathFinder.cs @@ -120,7 +120,8 @@ namespace OpenRA.Mods.RA.Move public List FindBidiPath( /* searches from both ends toward each other */ PathSearch fromSrc, - PathSearch fromDest) + PathSearch fromDest, + Player onBehalfOf) { using (new PerfSample("Pathfinder")) { @@ -155,8 +156,8 @@ namespace OpenRA.Mods.RA.Move 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); + dbg.AddLayer(fromSrc.considered.Select(p => new Pair(p, fromSrc.cellInfo[p.X, p.Y].MinCost)), fromSrc.maxCost, onBehalfOf); + dbg.AddLayer(fromDest.considered.Select(p => new Pair(p, fromDest.cellInfo[p.X, p.Y].MinCost)), fromDest.maxCost, onBehalfOf); } if (path != null) diff --git a/OpenRA.Mods.RA/Widgets/Logic/CheatsLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/CheatsLogic.cs index 8d97a5173f..c42ceaca0f 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/CheatsLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/CheatsLogic.cs @@ -59,6 +59,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic widget.Get("RESET_EXPLORATION").OnClick = () => world.IssueOrder(new Order("DevResetExploration", world.LocalPlayer.PlayerActor, false)); + var dbgOverlay = world.WorldActor.TraitOrDefault(); + var showAstarCostCheckbox = widget.Get("SHOW_ASTAR"); + showAstarCostCheckbox.IsChecked = () => dbgOverlay != null ? dbgOverlay.Visible : false; + showAstarCostCheckbox.OnClick = () => { if (dbgOverlay != null) dbgOverlay.Visible ^= true; }; + widget.Get("CLOSE").OnClick = () => { Ui.CloseWindow(); onExit(); }; } diff --git a/OpenRA.Mods.RA/World/DebugOverlay.cs b/OpenRA.Mods.RA/World/DebugOverlay.cs index 4d1f1b8af0..5af455f1e5 100644 --- a/OpenRA.Mods.RA/World/DebugOverlay.cs +++ b/OpenRA.Mods.RA/World/DebugOverlay.cs @@ -15,46 +15,61 @@ namespace OpenRA.Mods.RA class DebugOverlay : IRenderOverlay, IWorldLoaded { - int[,] layer; + Dictionary layers; int refreshTick; World world; + public bool Visible; public void WorldLoaded(World w) { this.world = w; - this.layer = new int[w.Map.MapSize.X, w.Map.MapSize.Y]; this.refreshTick = 0; + this.layers = new Dictionary(8); + // Enabled via Cheats menu + this.Visible = false; } - public void AddLayer(IEnumerable> cellWeights, int maxWeight) + public void AddLayer(IEnumerable> cellWeights, int maxWeight, Player pl) { if (maxWeight == 0) return; + int[,] layer; + if (!layers.TryGetValue(pl, out layer)) + { + layer = new int[world.Map.MapSize.X, world.Map.MapSize.Y]; + layers.Add(pl, layer); + } + foreach (var p in cellWeights) - layer[p.First.X, p.First.Y] = layer[p.First.X, p.First.Y] / 2 + (p.Second * 128 / maxWeight); + layer[p.First.X, p.First.Y] = Math.Min(128, (layer[p.First.X, p.First.Y] / 2) + ((maxWeight - p.Second) * 64 / maxWeight)); } public void Render(WorldRenderer wr) { + if (!Visible) return; + var qr = Game.Renderer.WorldQuadRenderer; - bool doSwap = refreshTick - world.FrameNumber <= 0; - if (doSwap) refreshTick = world.FrameNumber + 20; + bool doDim = refreshTick - world.FrameNumber <= 0; + if (doDim) refreshTick = world.FrameNumber + 15; - 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; + foreach (var pair in layers) + { + Color c = (pair.Key != null) ? pair.Key.ColorRamp.GetColor(0f) : Color.PaleTurquoise; + var layer = pair.Value; - var cell = new CPos(i, j); - var pix = cell.ToPPos(); - - var w = Math.Max(0, Math.Min(layer[i, j], 224)); - if (doSwap) + 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) { - layer[i, j] = layer[i, j] * 4 / 5; + var ploc = new CPos(i, j).ToPPos(); + + var w = Math.Max(0, Math.Min(layer[i, j], 128)); + if (doDim) + { + layer[i, j] = layer[i, j] * 4 / 5; + } + qr.FillRect(new RectangleF(ploc.X, ploc.Y, Game.CellSize, Game.CellSize), Color.FromArgb(w, c)); } - qr.FillRect(new RectangleF(pix.X, pix.Y, Game.CellSize, Game.CellSize), Color.FromArgb(w, Color.White)); - } + } } } } diff --git a/mods/ra/chrome/cheats.yaml b/mods/ra/chrome/cheats.yaml index d93e09a360..0539423ca2 100644 --- a/mods/ra/chrome/cheats.yaml +++ b/mods/ra/chrome/cheats.yaml @@ -3,7 +3,7 @@ Background@CHEATS_PANEL: X:(WINDOW_RIGHT - WIDTH)/2 Y:(WINDOW_BOTTOM - HEIGHT)/2 Width:350 - Height:420 + Height:450 Visible:true Children: Label@LABEL_TITLE: @@ -75,6 +75,12 @@ Background@CHEATS_PANEL: Width:PARENT_RIGHT - 30 Height:20 Text:Build Anywhere + Checkbox@SHOW_ASTAR: + X:30 + Y:320 + Width:PARENT_RIGHT - 30 + Height:20 + Text:Show A* Cost Button@CLOSE: X:30 Y:360 From 2abde381a77c3dc4ddb8175879d885e662fd3648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Wed, 6 Mar 2013 17:26:07 +0100 Subject: [PATCH 3/6] Exposed PathSearch.owner and removed Player argument from PathFinder functions. --- OpenRA.Mods.RA/Move/Move.cs | 5 +++-- OpenRA.Mods.RA/Move/PathFinder.cs | 25 ++++++++++++++++++++----- OpenRA.Mods.RA/Move/PathSearch.cs | 12 +++++++++++- OpenRA.Mods.RA/World/DebugOverlay.cs | 2 +- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/OpenRA.Mods.RA/Move/Move.cs b/OpenRA.Mods.RA/Move/Move.cs index 4806593020..b86f2278cc 100755 --- a/OpenRA.Mods.RA/Move/Move.cs +++ b/OpenRA.Mods.RA/Move/Move.cs @@ -49,8 +49,9 @@ namespace OpenRA.Mods.RA.Move { this.getPath = (self,mobile) => self.World.WorldActor.Trait().FindPath( - PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, destination, false ) - .WithIgnoredBuilding( ignoreBuilding )); + PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, destination, false) + .WithIgnoredBuilding(ignoreBuilding) + ); this.destination = destination; this.nearEnough = 0; diff --git a/OpenRA.Mods.RA/Move/PathFinder.cs b/OpenRA.Mods.RA/Move/PathFinder.cs index d2eb745c0f..2a7556f1d8 100755 --- a/OpenRA.Mods.RA/Move/PathFinder.cs +++ b/OpenRA.Mods.RA/Move/PathFinder.cs @@ -90,13 +90,29 @@ namespace OpenRA.Mods.RA.Move using (new PerfSample("Pathfinder")) { using (search) + { + List path = null; + while (!search.queue.Empty) { var p = search.Expand(world); if (search.heuristic(p) == 0) - return MakePath(search.cellInfo, p); + { + path = MakePath(search.cellInfo, p); + break; + } } + var dbg = world.WorldActor.TraitOrDefault(); + if (dbg != null) + { + dbg.AddLayer(search.considered.Select(p => new Pair(p, search.cellInfo[p.X, p.Y].MinCost)), search.maxCost, search.owner); + } + + if (path != null) + return path; + } + // no path exists return new List(0); } @@ -120,8 +136,7 @@ namespace OpenRA.Mods.RA.Move public List FindBidiPath( /* searches from both ends toward each other */ PathSearch fromSrc, - PathSearch fromDest, - Player onBehalfOf) + PathSearch fromDest) { using (new PerfSample("Pathfinder")) { @@ -156,8 +171,8 @@ namespace OpenRA.Mods.RA.Move 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, onBehalfOf); - dbg.AddLayer(fromDest.considered.Select(p => new Pair(p, fromDest.cellInfo[p.X, p.Y].MinCost)), fromDest.maxCost, onBehalfOf); + dbg.AddLayer(fromSrc.considered.Select(p => new Pair(p, fromSrc.cellInfo[p.X, p.Y].MinCost)), fromSrc.maxCost, fromSrc.owner); + dbg.AddLayer(fromDest.considered.Select(p => new Pair(p, fromDest.cellInfo[p.X, p.Y].MinCost)), fromDest.maxCost, fromDest.owner); } if (path != null) diff --git a/OpenRA.Mods.RA/Move/PathSearch.cs b/OpenRA.Mods.RA/Move/PathSearch.cs index be8b3d6d45..308de78e8e 100755 --- a/OpenRA.Mods.RA/Move/PathSearch.cs +++ b/OpenRA.Mods.RA/Move/PathSearch.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenRA.FileFormats; using OpenRA.Traits; @@ -28,6 +29,7 @@ namespace OpenRA.Mods.RA.Move public bool inReverse; public HashSet considered; public int maxCost; + Pair[] nextDirections; MobileInfo mobileInfo; Actor self; public Player owner { get { return self.Owner; } } @@ -42,6 +44,7 @@ namespace OpenRA.Mods.RA.Move queue = new PriorityQueue(); considered = new HashSet(); maxCost = 0; + nextDirections = directions.Select(d => new Pair(d, 0)).ToArray(); } public PathSearch InReverse() @@ -114,8 +117,11 @@ namespace OpenRA.Mods.RA.Move // This current cell is ok; check all immediate directions: considered.Add(p.Location); - foreach( CVec d in directions ) + for (int i = 0; i < nextDirections.Length; ++i) { + CVec d = nextDirections[i].First; + nextDirections[i].Second = int.MaxValue; + CPos newHere = p.Location + d; // Is this direction flat-out unusable or already seen? @@ -171,12 +177,16 @@ namespace OpenRA.Mods.RA.Move cellInfo[newHere.X, newHere.Y].Path = p.Location; cellInfo[newHere.X, newHere.Y].MinCost = newCost; + nextDirections[i].Second = newCost + est; queue.Add(new PathDistance(newCost + est, newHere)); if (newCost > maxCost) maxCost = newCost; considered.Add(newHere); } + // Sort to prefer the cheaper direction: + Array.Sort(nextDirections, (a, b) => a.Second.CompareTo(b.Second)); + return p.Location; } diff --git a/OpenRA.Mods.RA/World/DebugOverlay.cs b/OpenRA.Mods.RA/World/DebugOverlay.cs index 5af455f1e5..64ce23e844 100644 --- a/OpenRA.Mods.RA/World/DebugOverlay.cs +++ b/OpenRA.Mods.RA/World/DebugOverlay.cs @@ -50,7 +50,7 @@ namespace OpenRA.Mods.RA var qr = Game.Renderer.WorldQuadRenderer; bool doDim = refreshTick - world.FrameNumber <= 0; - if (doDim) refreshTick = world.FrameNumber + 15; + if (doDim) refreshTick = world.FrameNumber + 25; foreach (var pair in layers) { From 7e913c4bb79fecc5ec1ef49163050a9523783e73 Mon Sep 17 00:00:00 2001 From: James Dunne Date: Tue, 3 Jul 2012 14:54:13 -0500 Subject: [PATCH 4/6] Lame attempts to improve A*. --- OpenRA.Mods.RA/Move/PathSearch.cs | 13 +++++++------ OpenRA.Mods.RA/World/DebugOverlay.cs | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/OpenRA.Mods.RA/Move/PathSearch.cs b/OpenRA.Mods.RA/Move/PathSearch.cs index 308de78e8e..2775e3a3de 100755 --- a/OpenRA.Mods.RA/Move/PathSearch.cs +++ b/OpenRA.Mods.RA/Move/PathSearch.cs @@ -171,7 +171,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) + if (newCost > cellInfo[newHere.X, newHere.Y].MinCost) continue; cellInfo[newHere.X, newHere.Y].Path = p.Location; @@ -185,7 +185,7 @@ namespace OpenRA.Mods.RA.Move } // Sort to prefer the cheaper direction: - Array.Sort(nextDirections, (a, b) => a.Second.CompareTo(b.Second)); + //Array.Sort(nextDirections, (a, b) => a.Second.CompareTo(b.Second)); return p.Location; } @@ -291,10 +291,11 @@ namespace OpenRA.Mods.RA.Move { return here => { - CVec d = (here - destination).Abs(); - int diag = Math.Min(d.X, d.Y); - int straight = Math.Abs(d.X - d.Y); - return (3400 * diag / 24) + (100 * straight); + int diag = Math.Min(Math.Abs(here.X - destination.X), Math.Abs(here.Y - destination.Y)); + int straight = (Math.Abs(here.X - destination.X) + Math.Abs(here.Y - destination.Y)); + int h = (3400 * diag / 24) + 100 * (straight - (2 * diag)); + h = (int)(h * 1.001); + return h; }; } diff --git a/OpenRA.Mods.RA/World/DebugOverlay.cs b/OpenRA.Mods.RA/World/DebugOverlay.cs index 64ce23e844..ba3d6eea90 100644 --- a/OpenRA.Mods.RA/World/DebugOverlay.cs +++ b/OpenRA.Mods.RA/World/DebugOverlay.cs @@ -41,7 +41,7 @@ namespace OpenRA.Mods.RA } foreach (var p in cellWeights) - layer[p.First.X, p.First.Y] = Math.Min(128, (layer[p.First.X, p.First.Y] / 2) + ((maxWeight - p.Second) * 64 / maxWeight)); + layer[p.First.X, p.First.Y] = Math.Min(128, (layer[p.First.X, p.First.Y]) + ((maxWeight - p.Second) * 64 / maxWeight)); } public void Render(WorldRenderer wr) @@ -61,6 +61,7 @@ namespace OpenRA.Mods.RA for (int i = world.Map.Bounds.Left; i <= world.Map.Bounds.Right; ++i) { var ploc = new CPos(i, j).ToPPos(); + if (layer[i, j] <= 0) continue; var w = Math.Max(0, Math.Min(layer[i, j], 128)); if (doDim) From d8c752ecb9fa70cb3bb6608753d2af22d01a90cd Mon Sep 17 00:00:00 2001 From: James Dunne Date: Tue, 3 Jul 2012 18:31:17 -0500 Subject: [PATCH 5/6] DebugOverlay improvements to only render inside viewing range. --- OpenRA.Mods.RA/World/DebugOverlay.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/OpenRA.Mods.RA/World/DebugOverlay.cs b/OpenRA.Mods.RA/World/DebugOverlay.cs index ba3d6eea90..8aa63d0038 100644 --- a/OpenRA.Mods.RA/World/DebugOverlay.cs +++ b/OpenRA.Mods.RA/World/DebugOverlay.cs @@ -50,24 +50,31 @@ namespace OpenRA.Mods.RA var qr = Game.Renderer.WorldQuadRenderer; bool doDim = refreshTick - world.FrameNumber <= 0; - if (doDim) refreshTick = world.FrameNumber + 25; + if (doDim) refreshTick = world.FrameNumber + 20; + + var viewBounds = Game.viewport.WorldBounds(world); + var mapBounds = world.Map.Bounds; foreach (var pair in layers) { Color c = (pair.Key != null) ? pair.Key.ColorRamp.GetColor(0f) : Color.PaleTurquoise; var layer = pair.Value; - 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) + for (int j = mapBounds.Top; j <= mapBounds.Bottom; ++j) + for (int i = mapBounds.Left; i <= mapBounds.Right; ++i) { - var ploc = new CPos(i, j).ToPPos(); if (layer[i, j] <= 0) continue; var w = Math.Max(0, Math.Min(layer[i, j], 128)); if (doDim) { - layer[i, j] = layer[i, j] * 4 / 5; + layer[i, j] = layer[i, j] * 5 / 6; } + + if (!viewBounds.Contains(i, j)) continue; + + // Only render quads in viewing range: + var ploc = new CPos(i, j).ToPPos(); qr.FillRect(new RectangleF(ploc.X, ploc.Y, Game.CellSize, Game.CellSize), Color.FromArgb(w, c)); } } From 1a6a7da9c1e9483d360f7c5f7ceceae8e386ca47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Sun, 10 Mar 2013 07:47:00 +0100 Subject: [PATCH 6/6] apply recent refactoring to quad renderer --- OpenRA.Game/Graphics/QuadRenderer.cs | 7 +++++++ OpenRA.Game/Graphics/Renderer.cs | 1 + 2 files changed, 8 insertions(+) diff --git a/OpenRA.Game/Graphics/QuadRenderer.cs b/OpenRA.Game/Graphics/QuadRenderer.cs index 26ab90664d..83ecf2886c 100644 --- a/OpenRA.Game/Graphics/QuadRenderer.cs +++ b/OpenRA.Game/Graphics/QuadRenderer.cs @@ -56,5 +56,12 @@ namespace OpenRA.Graphics nv += 4; } + + public void SetShaderParams(ITexture palette, Size screen, float zoom, float2 scroll) + { + shader.SetVec("Scroll", (int)scroll.X, (int)scroll.Y); + shader.SetVec("r1", zoom*2f/screen.Width, -zoom*2f/screen.Height); + shader.SetVec("r2", -1, 1); + } } } diff --git a/OpenRA.Game/Graphics/Renderer.cs b/OpenRA.Game/Graphics/Renderer.cs index d98ddecd9d..443ad08844 100644 --- a/OpenRA.Game/Graphics/Renderer.cs +++ b/OpenRA.Game/Graphics/Renderer.cs @@ -69,6 +69,7 @@ namespace OpenRA.Graphics device.Clear(); WorldSpriteRenderer.SetShaderParams(PaletteTexture, Resolution, zoom, scroll); WorldLineRenderer.SetShaderParams(PaletteTexture, Resolution, zoom, scroll); + WorldQuadRenderer.SetShaderParams(PaletteTexture, Resolution, zoom, scroll); SpriteRenderer.SetShaderParams(PaletteTexture, Resolution, 1f, float2.Zero); LineRenderer.SetShaderParams(PaletteTexture, Resolution, 1f, float2.Zero); RgbaSpriteRenderer.SetShaderParams(PaletteTexture, Resolution, 1f, float2.Zero);