Added QuadRenderer to render shaded/colored quads. Added DebugOverlay to World to show A* bidi search cost per cell.
This commit is contained in:
60
OpenRA.Game/Graphics/QuadRenderer.cs
Normal file
60
OpenRA.Game/Graphics/QuadRenderer.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ namespace OpenRA.Graphics
|
|||||||
internal static int TempBufferCount;
|
internal static int TempBufferCount;
|
||||||
|
|
||||||
public SpriteRenderer WorldSpriteRenderer { get; private set; }
|
public SpriteRenderer WorldSpriteRenderer { get; private set; }
|
||||||
|
public QuadRenderer WorldQuadRenderer { get; private set; }
|
||||||
public LineRenderer WorldLineRenderer { get; private set; }
|
public LineRenderer WorldLineRenderer { get; private set; }
|
||||||
public LineRenderer LineRenderer { get; private set; }
|
public LineRenderer LineRenderer { get; private set; }
|
||||||
public SpriteRenderer RgbaSpriteRenderer { get; private set; }
|
public SpriteRenderer RgbaSpriteRenderer { get; private set; }
|
||||||
@@ -48,6 +49,7 @@ namespace OpenRA.Graphics
|
|||||||
WorldSpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp"));
|
WorldSpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp"));
|
||||||
WorldLineRenderer = new LineRenderer(this, device.CreateShader("line"));
|
WorldLineRenderer = new LineRenderer(this, device.CreateShader("line"));
|
||||||
LineRenderer = 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"));
|
RgbaSpriteRenderer = new SpriteRenderer(this, device.CreateShader("rgba"));
|
||||||
SpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp"));
|
SpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp"));
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@
|
|||||||
<Compile Include="ActorInitializer.cs" />
|
<Compile Include="ActorInitializer.cs" />
|
||||||
<Compile Include="ActorMap.cs" />
|
<Compile Include="ActorMap.cs" />
|
||||||
<Compile Include="ActorReference.cs" />
|
<Compile Include="ActorReference.cs" />
|
||||||
|
<Compile Include="Graphics\QuadRenderer.cs" />
|
||||||
<Compile Include="PSubVec.cs" />
|
<Compile Include="PSubVec.cs" />
|
||||||
<Compile Include="PSubPos.cs" />
|
<Compile Include="PSubPos.cs" />
|
||||||
<Compile Include="PVecInt.cs" />
|
<Compile Include="PVecInt.cs" />
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Support;
|
using OpenRA.Support;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
@@ -125,19 +126,41 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
{
|
{
|
||||||
using (fromSrc)
|
using (fromSrc)
|
||||||
using (fromDest)
|
using (fromDest)
|
||||||
|
{
|
||||||
|
List<CPos> path = null;
|
||||||
|
|
||||||
while (!fromSrc.queue.Empty && !fromDest.queue.Empty)
|
while (!fromSrc.queue.Empty && !fromDest.queue.Empty)
|
||||||
{
|
{
|
||||||
/* make some progress on the first search */
|
/* make some progress on the first search */
|
||||||
var p = fromSrc.Expand(world);
|
var p = fromSrc.Expand(world);
|
||||||
|
|
||||||
if (fromDest.cellInfo[p.X, p.Y].Seen && fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity)
|
if (fromDest.cellInfo[p.X, p.Y].Seen &&
|
||||||
return MakeBidiPath(fromSrc, fromDest, p);
|
fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity)
|
||||||
|
{
|
||||||
|
path = MakeBidiPath(fromSrc, fromDest, p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* make some progress on the second search */
|
/* make some progress on the second search */
|
||||||
var q = fromDest.Expand(world);
|
var q = fromDest.Expand(world);
|
||||||
|
|
||||||
if (fromSrc.cellInfo[q.X, q.Y].Seen && fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity)
|
if (fromSrc.cellInfo[q.X, q.Y].Seen &&
|
||||||
return MakeBidiPath(fromSrc, fromDest, q);
|
fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity)
|
||||||
|
{
|
||||||
|
path = MakeBidiPath(fromSrc, fromDest, q);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dbg = world.WorldActor.TraitOrDefault<DebugOverlay>();
|
||||||
|
if (dbg != null)
|
||||||
|
{
|
||||||
|
dbg.AddLayer(fromSrc.considered.Select(p => new Pair<CPos, int>(p, fromSrc.cellInfo[p.X, p.Y].MinCost)), fromSrc.maxCost);
|
||||||
|
dbg.AddLayer(fromDest.considered.Select(p => new Pair<CPos, int>(p, fromDest.cellInfo[p.X, p.Y].MinCost)), fromDest.maxCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path != null)
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new List<CPos>(0);
|
return new List<CPos>(0);
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
public bool checkForBlocked;
|
public bool checkForBlocked;
|
||||||
public Actor ignoreBuilding;
|
public Actor ignoreBuilding;
|
||||||
public bool inReverse;
|
public bool inReverse;
|
||||||
|
public HashSet<CPos> considered;
|
||||||
|
public int maxCost;
|
||||||
MobileInfo mobileInfo;
|
MobileInfo mobileInfo;
|
||||||
Actor self;
|
Actor self;
|
||||||
public Player owner { get { return self.Owner; } }
|
public Player owner { get { return self.Owner; } }
|
||||||
@@ -39,6 +40,8 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
this.self = self;
|
this.self = self;
|
||||||
customCost = null;
|
customCost = null;
|
||||||
queue = new PriorityQueue<PathDistance>();
|
queue = new PriorityQueue<PathDistance>();
|
||||||
|
considered = new HashSet<CPos>();
|
||||||
|
maxCost = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PathSearch InReverse()
|
public PathSearch InReverse()
|
||||||
@@ -108,14 +111,20 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
return p.Location;
|
return p.Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This current cell is ok; check all immediate directions:
|
||||||
|
considered.Add(p.Location);
|
||||||
|
|
||||||
foreach( CVec d in directions )
|
foreach( CVec d in directions )
|
||||||
{
|
{
|
||||||
CPos newHere = p.Location + d;
|
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)
|
if (cellInfo[newHere.X, newHere.Y].Seen)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Now we may seriously consider this direction using heuristics:
|
||||||
var costHere = mobileInfo.MovementCostForCell(world, newHere);
|
var costHere = mobileInfo.MovementCostForCell(world, newHere);
|
||||||
|
|
||||||
if (costHere == int.MaxValue)
|
if (costHere == int.MaxValue)
|
||||||
@@ -134,8 +143,12 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
int cellCost = costHere;
|
int cellCost = costHere;
|
||||||
if (d.X * d.Y != 0) cellCost = (cellCost * 34) / 24;
|
if (d.X * d.Y != 0) cellCost = (cellCost * 34) / 24;
|
||||||
|
|
||||||
|
int userCost = 0;
|
||||||
if (customCost != null)
|
if (customCost != null)
|
||||||
cellCost += customCost(newHere);
|
{
|
||||||
|
userCost = customCost(newHere);
|
||||||
|
cellCost += userCost;
|
||||||
|
}
|
||||||
|
|
||||||
// directional bonuses for smoother flow!
|
// directional bonuses for smoother flow!
|
||||||
if (LaneBias != 0)
|
if (LaneBias != 0)
|
||||||
@@ -151,6 +164,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
|
|
||||||
int newCost = cellInfo[p.Location.X, p.Location.Y].MinCost + cellCost;
|
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;
|
continue;
|
||||||
|
|
||||||
@@ -158,7 +172,11 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
cellInfo[newHere.X, newHere.Y].MinCost = newCost;
|
cellInfo[newHere.X, newHere.Y].MinCost = newCost;
|
||||||
|
|
||||||
queue.Add(new PathDistance(newCost + est, newHere));
|
queue.Add(new PathDistance(newCost + est, newHere));
|
||||||
|
|
||||||
|
if (newCost > maxCost) maxCost = newCost;
|
||||||
|
considered.Add(newHere);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.Location;
|
return p.Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -403,6 +403,7 @@
|
|||||||
<Compile Include="Widgets\WorldCommandWidget.cs" />
|
<Compile Include="Widgets\WorldCommandWidget.cs" />
|
||||||
<Compile Include="Widgets\WorldTooltipWidget.cs" />
|
<Compile Include="Widgets\WorldTooltipWidget.cs" />
|
||||||
<Compile Include="World\ChooseBuildTabOnSelect.cs" />
|
<Compile Include="World\ChooseBuildTabOnSelect.cs" />
|
||||||
|
<Compile Include="World\DebugOverlay.cs" />
|
||||||
<Compile Include="World\ResourceClaim.cs" />
|
<Compile Include="World\ResourceClaim.cs" />
|
||||||
<Compile Include="World\ResourceClaimLayer.cs" />
|
<Compile Include="World\ResourceClaimLayer.cs" />
|
||||||
<Compile Include="World\PlayMusicOnMapLoad.cs" />
|
<Compile Include="World\PlayMusicOnMapLoad.cs" />
|
||||||
|
|||||||
60
OpenRA.Mods.RA/World/DebugOverlay.cs
Normal file
60
OpenRA.Mods.RA/World/DebugOverlay.cs
Normal file
@@ -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<DebugOverlay>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Pair<CPos, int>> 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -562,6 +562,7 @@ World:
|
|||||||
Type:Crater
|
Type:Crater
|
||||||
Types:cr1,cr2,cr3,cr4,cr5,cr6
|
Types:cr1,cr2,cr3,cr4,cr5,cr6
|
||||||
Depths:5,5,5,5,5,5
|
Depths:5,5,5,5,5,5
|
||||||
|
DebugOverlay:
|
||||||
SpawnMapActors:
|
SpawnMapActors:
|
||||||
CreateMPPlayers:
|
CreateMPPlayers:
|
||||||
MPStartLocations:
|
MPStartLocations:
|
||||||
|
|||||||
Reference in New Issue
Block a user