Skip to content

Commit

Permalink
Merge pull request #2968 from pchote/map-chooser
Browse files Browse the repository at this point in the history
Map chooser polish & refactoring
  • Loading branch information
Mailaender committed Apr 6, 2013
2 parents 99516fd + aa97bbb commit b25e291
Show file tree
Hide file tree
Showing 18 changed files with 381 additions and 87 deletions.
3 changes: 2 additions & 1 deletion OpenRA.Game/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ static void Tick( OrderManager orderManager )
else
if (orderManager.NetFrameNumber == 0)
orderManager.LastTickTime = Environment.TickCount;


world.TickRender(worldRenderer);
viewport.Tick();
}
}
Expand Down
1 change: 1 addition & 0 deletions OpenRA.Game/OpenRA.Game.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
<Compile Include="World.cs" />
<Compile Include="WorldUtils.cs" />
<Compile Include="Network\ReplayRecorderConnection.cs" />
<Compile Include="Widgets\TooltipContainerWidget.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
Expand Down
1 change: 1 addition & 0 deletions OpenRA.Game/Traits/TraitsInterfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class AttackInfo
}

public interface ITick { void Tick(Actor self); }
public interface ITickRender { void TickRender(WorldRenderer wr, Actor self); }
public interface IRender { IEnumerable<Renderable> Render(Actor self, WorldRenderer wr); }
public interface IAutoSelectionSize { int2 SelectionSize(Actor self); }

Expand Down
138 changes: 117 additions & 21 deletions OpenRA.Game/Widgets/MapPreviewWidget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,42 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Network;

namespace OpenRA.Widgets
{
public class MapPreviewWidget : Widget
{
public Func<Map> Map = () => null;
public Func<Dictionary<int2, Color>> SpawnColors = () => new Dictionary<int2, Color>();
public Func<Dictionary<int2, Session.Client>> SpawnClients = () => new Dictionary<int2, Session.Client>();
public Action<MouseInput> OnMouseDown = _ => {};
public Action<int, int2> OnTooltip = (_, __) => { };
public bool IgnoreMouseInput = false;
public bool ShowSpawnPoints = true;

static readonly Cache<Map,Bitmap> PreviewCache = new Cache<Map, Bitmap>(stub => Minimap.RenderMapPreview( new Map( stub.Path )));
public readonly string TooltipContainer;
public readonly string TooltipTemplate = "SPAWN_TOOLTIP";
Lazy<TooltipContainerWidget> tooltipContainer;
public int TooltipSpawnIndex = -1;

public MapPreviewWidget() : base() { }
public MapPreviewWidget() : base()
{
tooltipContainer = Lazy.New(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
}

protected MapPreviewWidget(MapPreviewWidget other)
: base(other)
{
lastMap = other.lastMap;
Map = other.Map;
SpawnColors = other.SpawnColors;
SpawnClients = other.SpawnClients;
ShowSpawnPoints = other.ShowSpawnPoints;
TooltipTemplate = other.TooltipTemplate;
TooltipContainer = other.TooltipContainer;
tooltipContainer = Lazy.New(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
}

public override Widget Clone() { return new MapPreviewWidget(this); }
Expand All @@ -53,6 +64,18 @@ public override bool HandleMouseInput(MouseInput mi)
return true;
}

public override void MouseEntered()
{
if (TooltipContainer == null) return;
tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() {{ "preview", this }});
}

public override void MouseExited()
{
if (TooltipContainer == null) return;
tooltipContainer.Value.RemoveTooltip();
}

public int2 ConvertToPreview(int2 point)
{
var map = Map();
Expand All @@ -68,19 +91,30 @@ public int2 ConvertToPreview(int2 point)
public override void Draw()
{
var map = Map();
if( map == null ) return;
if (map == null)
return;

// Preview unavailable
if (!Loaded)
{
GeneratePreview();
return;
}

if (lastMap != map)
{
lastMap = map;

// Update image data
var preview = PreviewCache[map];
if( mapChooserSheet == null || mapChooserSheet.Size.Width != preview.Width || mapChooserSheet.Size.Height != preview.Height )
mapChooserSheet = new Sheet(new Size( preview.Width, preview.Height ) );
Bitmap preview;
lock (syncRoot)
preview = Previews[map.Uid];

if (mapChooserSheet == null || mapChooserSheet.Size.Width != preview.Width || mapChooserSheet.Size.Height != preview.Height)
mapChooserSheet = new Sheet(new Size(preview.Width, preview.Height));

mapChooserSheet.Texture.SetData( preview );
mapChooserSprite = new Sprite( mapChooserSheet, new Rectangle( 0, 0, map.Bounds.Width, map.Bounds.Height ), TextureChannel.Alpha );
mapChooserSheet.Texture.SetData(preview);
mapChooserSprite = new Sprite(mapChooserSheet, new Rectangle(0, 0, map.Bounds.Width, map.Bounds.Height), TextureChannel.Alpha);
}

// Update map rect
Expand All @@ -90,13 +124,14 @@ public override void Draw()
var dh = (int)(PreviewScale * (size - map.Bounds.Height)) / 2;
MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Bounds.Width * PreviewScale), (int)(map.Bounds.Height * PreviewScale));

Game.Renderer.RgbaSpriteRenderer.DrawSprite( mapChooserSprite,
Game.Renderer.RgbaSpriteRenderer.DrawSprite(mapChooserSprite,
new float2(MapRect.Location),
new float2( MapRect.Size ) );
new float2(MapRect.Size));

TooltipSpawnIndex = -1;
if (ShowSpawnPoints)
{
var colors = SpawnColors();
var colors = SpawnClients().ToDictionary(c => c.Key, c => c.Value.ColorRamp.GetColor(0));

var spawnPoints = map.GetSpawnPoints().ToList();
foreach (var p in spawnPoints)
Expand All @@ -113,21 +148,82 @@ public override void Draw()

if ((pos - Viewport.LastMousePos).LengthSquared < 64)
{
OnTooltip(spawnPoints.IndexOf(p) + 1, pos);
TooltipSpawnIndex = spawnPoints.IndexOf(p) + 1;

// Legacy tooltip behavior
if (TooltipContainer == null)
OnTooltip(TooltipSpawnIndex, pos);
}
}
}
}

/// <summary>
/// Forces loading the preview into the map cache.
/// </summary>
public Bitmap LoadMapPreview()
// Async map preview generation bits
enum PreviewStatus { Invalid, Uncached, Generating, Cached }
static Thread previewLoaderThread;
static object syncRoot = new object();
static Queue<string> cacheUids = new Queue<string>();
static readonly Dictionary<string, Bitmap> Previews = new Dictionary<string, Bitmap>();

void LoadAsyncInternal()
{
var map = Map();
if( map == null ) return null;
for (;;)
{
string uid;
lock (syncRoot)
{
if (cacheUids.Count == 0)
break;
uid = cacheUids.Peek();
}

return PreviewCache[map];
var bitmap = Minimap.RenderMapPreview(Game.modData.AvailableMaps[uid]);
lock (syncRoot)
{
// TODO: We should add previews to a sheet here (with multiple previews per sheet)
Previews.Add(uid, bitmap);
cacheUids.Dequeue();
}

// Yuck... But this helps the UI Jank when opening the map selector significantly.
Thread.Sleep(50);
}
}

void GeneratePreview()
{
var m = Map();
if (m == null)
return;

var status = Status(m);
if (status == PreviewStatus.Uncached)
lock (syncRoot)
cacheUids.Enqueue(m.Uid);

if (previewLoaderThread == null || !previewLoaderThread.IsAlive)
{
previewLoaderThread = new Thread(LoadAsyncInternal);
previewLoaderThread.Start();
}
}

static PreviewStatus Status(Map m)
{
if (m == null)
return PreviewStatus.Invalid;

lock (syncRoot)
{
if (Previews.ContainsKey(m.Uid))
return PreviewStatus.Cached;

if (cacheUids.Contains(m.Uid))
return PreviewStatus.Generating;
}
return PreviewStatus.Uncached;
}

public bool Loaded { get { return Status(Map()) == PreviewStatus.Cached; } }
}
}
10 changes: 10 additions & 0 deletions OpenRA.Game/Widgets/ScrollItemWidget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace OpenRA.Widgets
{
public class ScrollItemWidget : ButtonWidget
{
public string ItemKey;

public ScrollItemWidget()
: base()
{
Expand All @@ -28,6 +30,7 @@ protected ScrollItemWidget(ScrollItemWidget other)
IsVisible = () => false;
VisualHeight = 0;
IgnoreChildMouseOver = true;
Key = other.Key;
}

public Func<bool> IsSelected = () => false;
Expand Down Expand Up @@ -59,5 +62,12 @@ public static ScrollItemWidget Setup(ScrollItemWidget template, Func<bool> isSel
w.OnDoubleClick = onDoubleClick;
return w;
}

public static ScrollItemWidget Setup(string key, ScrollItemWidget template, Func<bool> isSelected, Action onClick)
{
var w = Setup(template, isSelected, onClick);
w.ItemKey = key;
return w;
}
}
}
20 changes: 20 additions & 0 deletions OpenRA.Game/Widgets/ScrollPanelWidget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

using System;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;

namespace OpenRA.Widgets
Expand Down Expand Up @@ -143,6 +144,25 @@ public void ScrollToTop()
ListOffset = 0;
}

public void ScrollToItem(string itemKey)
{
var item = Children.FirstOrDefault(c =>
{
var si = c as ScrollItemWidget;
return si != null && si.ItemKey == itemKey;
});

if (item == null)
return;

// Scroll the item to be visible
if (item.Bounds.Top + ListOffset < 0)
ListOffset = ItemSpacing - item.Bounds.Top;

if (item.Bounds.Bottom + ListOffset > RenderBounds.Height)
ListOffset = RenderBounds.Height - item.Bounds.Bottom - ItemSpacing;
}

public override void Tick ()
{
if (UpPressed) Scroll(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Mods.RA;
using OpenRA.Widgets;
using System;

namespace OpenRA.Mods.Cnc.Widgets
namespace OpenRA.Widgets
{
public class TooltipContainerWidget : Widget
{
Expand Down
8 changes: 7 additions & 1 deletion OpenRA.Game/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Linq;
using OpenRA.Effects;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Orders;
using OpenRA.Support;
Expand Down Expand Up @@ -192,7 +193,12 @@ public void Tick()

while (frameEndActions.Count != 0)
frameEndActions.Dequeue()(this);

}

// For things that want to update their render state once per tick, ignoring pause state
public void TickRender(WorldRenderer wr)
{
ActorsWithTrait<ITickRender>().Do(x => x.Trait.TickRender(wr, x.Actor));
}

public IEnumerable<Actor> Actors { get { return actors; } }
Expand Down
5 changes: 3 additions & 2 deletions OpenRA.Mods.Cnc/CncMenuPaletteEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Collections.Generic;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Traits;

namespace OpenRA.Mods.Cnc
Expand All @@ -22,7 +23,7 @@ public class CncMenuPaletteEffectInfo : ITraitInfo
public object Create(ActorInitializer init) { return new CncMenuPaletteEffect(this); }
}

public class CncMenuPaletteEffect : IPaletteModifier, ITick
public class CncMenuPaletteEffect : IPaletteModifier, ITickRender
{
public enum EffectType { None, Black, Desaturated }
public readonly CncMenuPaletteEffectInfo Info;
Expand All @@ -40,7 +41,7 @@ public void Fade(EffectType type)
to = type;
}

public void Tick(Actor self)
public void TickRender(WorldRenderer wr, Actor self)
{
if (remainingFrames > 0)
remainingFrames--;
Expand Down
2 changes: 1 addition & 1 deletion OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@
<Compile Include="Widgets\ProductionTabsWidget.cs" />
<Compile Include="Widgets\SupportPowersWidget.cs" />
<Compile Include="Widgets\ToggleButtonWidget.cs" />
<Compile Include="Widgets\TooltipContainerWidget.cs" />
<Compile Include="WithFire.cs" />
<Compile Include="WithRoof.cs" />
<Compile Include="Widgets\ResourceBarWidget.cs" />
<Compile Include="Widgets\Logic\SpawnSelectorTooltipLogic.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
Expand Down
Loading

0 comments on commit b25e291

Please sign in to comment.