Move threading into the preview generation.
This commit is contained in:
@@ -12,6 +12,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
@@ -26,8 +27,6 @@ namespace OpenRA.Widgets
|
||||
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 MapPreviewWidget() : base() { }
|
||||
|
||||
protected MapPreviewWidget(MapPreviewWidget other)
|
||||
@@ -68,19 +67,30 @@ namespace OpenRA.Widgets
|
||||
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];
|
||||
|
||||
mapChooserSheet.Texture.SetData( preview );
|
||||
mapChooserSprite = new Sprite( mapChooserSheet, new Rectangle( 0, 0, map.Bounds.Width, map.Bounds.Height ), TextureChannel.Alpha );
|
||||
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);
|
||||
}
|
||||
|
||||
// Update map rect
|
||||
@@ -90,9 +100,9 @@ namespace OpenRA.Widgets
|
||||
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));
|
||||
|
||||
if (ShowSpawnPoints)
|
||||
{
|
||||
@@ -119,15 +129,70 @@ namespace OpenRA.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces loading the preview into the map cache.
|
||||
/// </summary>
|
||||
public Bitmap LoadMapPreview()
|
||||
{
|
||||
var map = Map();
|
||||
if( map == null ) return null;
|
||||
// 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>();
|
||||
|
||||
return PreviewCache[map];
|
||||
void LoadAsyncInternal()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
string uid;
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (cacheUids.Count == 0)
|
||||
break;
|
||||
uid = cacheUids.Peek();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.Priority = ThreadPriority.Lowest;
|
||||
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; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
ScrollPanelWidget scrollpanel;
|
||||
ScrollItemWidget itemTemplate;
|
||||
string gameMode;
|
||||
Thread mapLoaderThread;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
internal MapChooserLogic(Widget widget, string initialMap, Action onExit, Action<Map> onSelect)
|
||||
@@ -61,7 +60,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(template,
|
||||
() => gameMode == ii.First,
|
||||
() => { gameMode = ii.First; EnumerateMapsAsync(); });
|
||||
() => { gameMode = ii.First; EnumerateMaps(); });
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => showItem(ii);
|
||||
return item;
|
||||
};
|
||||
@@ -84,16 +83,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
randomMapButton.IsDisabled = () => visibleMaps == null || visibleMaps.Count == 0;
|
||||
}
|
||||
|
||||
EnumerateMapsAsync();
|
||||
}
|
||||
|
||||
void EnumerateMapsAsync()
|
||||
{
|
||||
if (mapLoaderThread != null && mapLoaderThread.IsAlive)
|
||||
mapLoaderThread.Abort(); // violent, but should be fine since we are not doing anything sensitive in this thread
|
||||
|
||||
mapLoaderThread = new Thread(EnumerateMaps);
|
||||
mapLoaderThread.Start();
|
||||
EnumerateMaps();
|
||||
}
|
||||
|
||||
void EnumerateMaps()
|
||||
@@ -104,7 +94,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
.OrderBy(kv => kv.Value.PlayerCount)
|
||||
.ThenBy(kv => kv.Value.Title);
|
||||
|
||||
var children = new List<ScrollItemWidget>();
|
||||
scrollpanel.RemoveChildren();
|
||||
foreach (var kv in maps)
|
||||
{
|
||||
var m = kv.Value;
|
||||
@@ -117,17 +107,20 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
previewWidget.IgnoreMouseOver = true;
|
||||
previewWidget.IgnoreMouseInput = true;
|
||||
previewWidget.Map = () => m;
|
||||
previewWidget.LoadMapPreview();
|
||||
|
||||
var detailsWidget = item.Get<LabelWidget>("DETAILS");
|
||||
var previewLoadingWidget = item.GetOrNull<BackgroundWidget>("PREVIEW_PLACEHOLDER");
|
||||
if (previewLoadingWidget != null)
|
||||
previewLoadingWidget.IsVisible = () => !previewWidget.Loaded;
|
||||
|
||||
var detailsWidget = item.GetOrNull<LabelWidget>("DETAILS");
|
||||
if (detailsWidget != null)
|
||||
detailsWidget.GetText = () => "{0} ({1})".F(m.Type, m.PlayerCount);
|
||||
|
||||
var authorWidget = item.Get<LabelWidget>("AUTHOR");
|
||||
var authorWidget = item.GetOrNull<LabelWidget>("AUTHOR");
|
||||
if (authorWidget != null)
|
||||
authorWidget.GetText = () => m.Author;
|
||||
|
||||
var sizeWidget = item.Get<LabelWidget>("SIZE");
|
||||
var sizeWidget = item.GetOrNull<LabelWidget>("SIZE");
|
||||
if (sizeWidget != null)
|
||||
{
|
||||
var size = m.Bounds.Width + "x" + m.Bounds.Height;
|
||||
@@ -139,20 +132,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
sizeWidget.GetText = () => size;
|
||||
}
|
||||
|
||||
children.Add(item);
|
||||
scrollpanel.AddChild(item);
|
||||
}
|
||||
|
||||
Game.RunAfterTick(() =>
|
||||
{
|
||||
scrollpanel.RemoveChildren();
|
||||
|
||||
foreach (var c in children)
|
||||
scrollpanel.AddChild(c);
|
||||
|
||||
visibleMaps = maps.ToDictionary(kv => kv.Key, kv => kv.Value);
|
||||
if (visibleMaps.ContainsValue(map))
|
||||
scrollpanel.ScrollToItem(visibleMaps.First(m => m.Value == map).Key);
|
||||
});
|
||||
visibleMaps = maps.ToDictionary(kv => kv.Key, kv => kv.Value);
|
||||
if (visibleMaps.ContainsValue(map))
|
||||
scrollpanel.ScrollToItem(visibleMaps.First(m => m.Value == map).Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,13 @@ Container@MAPCHOOSER_PANEL:
|
||||
Y:0
|
||||
Visible:false
|
||||
Children:
|
||||
Background@PREVIEW_PLACEHOLDER:
|
||||
X:(PARENT_RIGHT - WIDTH)/2
|
||||
Y:4
|
||||
Width:158
|
||||
Height:158
|
||||
Background:panel-black
|
||||
ClickThrough: false
|
||||
MapPreview@PREVIEW:
|
||||
X:(PARENT_RIGHT - WIDTH)/2
|
||||
Y:4
|
||||
|
||||
Reference in New Issue
Block a user