67
OpenRA.Game/Graphics/QuadRenderer.cs
Normal file
67
OpenRA.Game/Graphics/QuadRenderer.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
|
||||
@@ -67,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);
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
<Compile Include="ActorInitializer.cs" />
|
||||
<Compile Include="ActorMap.cs" />
|
||||
<Compile Include="ActorReference.cs" />
|
||||
<Compile Include="Graphics\QuadRenderer.cs" />
|
||||
<Compile Include="PSubVec.cs" />
|
||||
<Compile Include="PSubPos.cs" />
|
||||
<Compile Include="PVecInt.cs" />
|
||||
|
||||
@@ -49,8 +49,9 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
this.getPath = (self,mobile) =>
|
||||
self.World.WorldActor.Trait<PathFinder>().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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -89,13 +90,29 @@ namespace OpenRA.Mods.RA.Move
|
||||
using (new PerfSample("Pathfinder"))
|
||||
{
|
||||
using (search)
|
||||
{
|
||||
List<CPos> 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<DebugOverlay>();
|
||||
if (dbg != null)
|
||||
{
|
||||
dbg.AddLayer(search.considered.Select(p => new Pair<CPos, int>(p, search.cellInfo[p.X, p.Y].MinCost)), search.maxCost, search.owner);
|
||||
}
|
||||
|
||||
if (path != null)
|
||||
return path;
|
||||
}
|
||||
|
||||
// no path exists
|
||||
return new List<CPos>(0);
|
||||
}
|
||||
@@ -125,21 +142,43 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
using (fromSrc)
|
||||
using (fromDest)
|
||||
{
|
||||
List<CPos> 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<DebugOverlay>();
|
||||
if (dbg != null)
|
||||
{
|
||||
dbg.AddLayer(fromSrc.considered.Select(p => new Pair<CPos, int>(p, fromSrc.cellInfo[p.X, p.Y].MinCost)), fromSrc.maxCost, fromSrc.owner);
|
||||
dbg.AddLayer(fromDest.considered.Select(p => new Pair<CPos, int>(p, fromDest.cellInfo[p.X, p.Y].MinCost)), fromDest.maxCost, fromDest.owner);
|
||||
}
|
||||
|
||||
if (path != null)
|
||||
return path;
|
||||
}
|
||||
|
||||
return new List<CPos>(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -26,7 +27,9 @@ namespace OpenRA.Mods.RA.Move
|
||||
public bool checkForBlocked;
|
||||
public Actor ignoreBuilding;
|
||||
public bool inReverse;
|
||||
|
||||
public HashSet<CPos> considered;
|
||||
public int maxCost;
|
||||
Pair<CVec, int>[] nextDirections;
|
||||
MobileInfo mobileInfo;
|
||||
Actor self;
|
||||
public Player owner { get { return self.Owner; } }
|
||||
@@ -39,6 +42,9 @@ namespace OpenRA.Mods.RA.Move
|
||||
this.self = self;
|
||||
customCost = null;
|
||||
queue = new PriorityQueue<PathDistance>();
|
||||
considered = new HashSet<CPos>();
|
||||
maxCost = 0;
|
||||
nextDirections = directions.Select(d => new Pair<CVec, int>(d, 0)).ToArray();
|
||||
}
|
||||
|
||||
public PathSearch InReverse()
|
||||
@@ -108,14 +114,23 @@ namespace OpenRA.Mods.RA.Move
|
||||
return p.Location;
|
||||
}
|
||||
|
||||
foreach( CVec d in directions )
|
||||
// This current cell is ok; check all immediate directions:
|
||||
considered.Add(p.Location);
|
||||
|
||||
for (int i = 0; i < nextDirections.Length; ++i)
|
||||
{
|
||||
CVec d = nextDirections[i].First;
|
||||
nextDirections[i].Second = int.MaxValue;
|
||||
|
||||
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 +149,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,14 +170,23 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
int newCost = cellInfo[p.Location.X, p.Location.Y].MinCost + cellCost;
|
||||
|
||||
if (newCost >= cellInfo[newHere.X, newHere.Y].MinCost)
|
||||
// Cost is even higher; next direction:
|
||||
if (newCost > cellInfo[newHere.X, newHere.Y].MinCost)
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -263,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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -403,6 +403,7 @@
|
||||
<Compile Include="Widgets\WorldCommandWidget.cs" />
|
||||
<Compile Include="Widgets\WorldTooltipWidget.cs" />
|
||||
<Compile Include="World\ChooseBuildTabOnSelect.cs" />
|
||||
<Compile Include="World\DebugOverlay.cs" />
|
||||
<Compile Include="World\ResourceClaim.cs" />
|
||||
<Compile Include="World\ResourceClaimLayer.cs" />
|
||||
<Compile Include="World\PlayMusicOnMapLoad.cs" />
|
||||
|
||||
@@ -59,6 +59,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
widget.Get<ButtonWidget>("RESET_EXPLORATION").OnClick = () =>
|
||||
world.IssueOrder(new Order("DevResetExploration", world.LocalPlayer.PlayerActor, false));
|
||||
|
||||
var dbgOverlay = world.WorldActor.TraitOrDefault<DebugOverlay>();
|
||||
var showAstarCostCheckbox = widget.Get<CheckboxWidget>("SHOW_ASTAR");
|
||||
showAstarCostCheckbox.IsChecked = () => dbgOverlay != null ? dbgOverlay.Visible : false;
|
||||
showAstarCostCheckbox.OnClick = () => { if (dbgOverlay != null) dbgOverlay.Visible ^= true; };
|
||||
|
||||
widget.Get<ButtonWidget>("CLOSE").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
||||
}
|
||||
|
||||
|
||||
83
OpenRA.Mods.RA/World/DebugOverlay.cs
Normal file
83
OpenRA.Mods.RA/World/DebugOverlay.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
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
|
||||
{
|
||||
Dictionary<Player, int[,]> layers;
|
||||
int refreshTick;
|
||||
World world;
|
||||
public bool Visible;
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
this.world = w;
|
||||
this.refreshTick = 0;
|
||||
this.layers = new Dictionary<Player, int[,]>(8);
|
||||
// Enabled via Cheats menu
|
||||
this.Visible = false;
|
||||
}
|
||||
|
||||
public void AddLayer(IEnumerable<Pair<CPos, int>> 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] = Math.Min(128, (layer[p.First.X, p.First.Y]) + ((maxWeight - p.Second) * 64 / maxWeight));
|
||||
}
|
||||
|
||||
public void Render(WorldRenderer wr)
|
||||
{
|
||||
if (!Visible) return;
|
||||
|
||||
var qr = Game.Renderer.WorldQuadRenderer;
|
||||
bool doDim = refreshTick - world.FrameNumber <= 0;
|
||||
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 = mapBounds.Top; j <= mapBounds.Bottom; ++j)
|
||||
for (int i = mapBounds.Left; i <= mapBounds.Right; ++i)
|
||||
{
|
||||
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] * 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user