Reorganize cursor plumbing in preparation for hardware cursors.
This commit is contained in:
@@ -29,6 +29,7 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
public static ModData modData;
|
public static ModData modData;
|
||||||
public static Settings Settings;
|
public static Settings Settings;
|
||||||
|
public static ICursor Cursor;
|
||||||
static WorldRenderer worldRenderer;
|
static WorldRenderer worldRenderer;
|
||||||
|
|
||||||
internal static OrderManager orderManager;
|
internal static OrderManager orderManager;
|
||||||
@@ -129,6 +130,7 @@ namespace OpenRA
|
|||||||
public static event Action BeforeGameStart = () => { };
|
public static event Action BeforeGameStart = () => { };
|
||||||
internal static void StartGame(string mapUID, bool isShellmap)
|
internal static void StartGame(string mapUID, bool isShellmap)
|
||||||
{
|
{
|
||||||
|
Cursor.SetCursor(null);
|
||||||
BeforeGameStart();
|
BeforeGameStart();
|
||||||
|
|
||||||
Map map;
|
Map map;
|
||||||
@@ -157,6 +159,7 @@ namespace OpenRA
|
|||||||
orderManager.LastTickTime = RunTime;
|
orderManager.LastTickTime = RunTime;
|
||||||
orderManager.StartGame();
|
orderManager.StartGame();
|
||||||
worldRenderer.RefreshPalette();
|
worldRenderer.RefreshPalette();
|
||||||
|
Cursor.SetCursor("default");
|
||||||
|
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
@@ -287,11 +290,14 @@ namespace OpenRA
|
|||||||
Sound.Initialize();
|
Sound.Initialize();
|
||||||
|
|
||||||
modData = new ModData(mod, true);
|
modData = new ModData(mod, true);
|
||||||
|
|
||||||
Renderer.InitializeFonts(modData.Manifest);
|
Renderer.InitializeFonts(modData.Manifest);
|
||||||
modData.InitializeLoaders();
|
modData.InitializeLoaders();
|
||||||
using (new PerfTimer("LoadMaps"))
|
using (new PerfTimer("LoadMaps"))
|
||||||
modData.MapCache.LoadMaps();
|
modData.MapCache.LoadMaps();
|
||||||
|
|
||||||
|
Cursor = new SoftwareCursor(modData.CursorProvider);
|
||||||
|
|
||||||
PerfHistory.items["render"].hasNormalTick = false;
|
PerfHistory.items["render"].hasNormalTick = false;
|
||||||
PerfHistory.items["batches"].hasNormalTick = false;
|
PerfHistory.items["batches"].hasNormalTick = false;
|
||||||
PerfHistory.items["render_widgets"].hasNormalTick = false;
|
PerfHistory.items["render_widgets"].hasNormalTick = false;
|
||||||
@@ -401,8 +407,6 @@ namespace OpenRA
|
|||||||
public static void RunAfterTick(Action a) { delayedActions.Add(a); }
|
public static void RunAfterTick(Action a) { delayedActions.Add(a); }
|
||||||
public static void RunAfterDelay(int delay, Action a) { delayedActions.Add(a, delay); }
|
public static void RunAfterDelay(int delay, Action a) { delayedActions.Add(a, delay); }
|
||||||
|
|
||||||
static float cursorFrame = 0f;
|
|
||||||
|
|
||||||
static void InnerLogicTick(OrderManager orderManager)
|
static void InnerLogicTick(OrderManager orderManager)
|
||||||
{
|
{
|
||||||
var tick = RunTime;
|
var tick = RunTime;
|
||||||
@@ -419,7 +423,7 @@ namespace OpenRA
|
|||||||
Viewport.TicksSinceLastMove += uiTickDelta / Timestep;
|
Viewport.TicksSinceLastMove += uiTickDelta / Timestep;
|
||||||
|
|
||||||
Sync.CheckSyncUnchanged(world, Ui.Tick);
|
Sync.CheckSyncUnchanged(world, Ui.Tick);
|
||||||
cursorFrame += 0.5f;
|
Cursor.Tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
var worldTimestep = world == null ? Timestep : world.Timestep;
|
var worldTimestep = world == null ? Timestep : world.Timestep;
|
||||||
@@ -509,8 +513,8 @@ namespace OpenRA
|
|||||||
|
|
||||||
if (modData != null && modData.CursorProvider != null)
|
if (modData != null && modData.CursorProvider != null)
|
||||||
{
|
{
|
||||||
var cursorName = Ui.Root.GetCursorOuter(Viewport.LastMousePos) ?? "default";
|
Cursor.SetCursor(Ui.Root.GetCursorOuter(Viewport.LastMousePos) ?? "default");
|
||||||
modData.CursorProvider.DrawCursor(Renderer, cursorName, Viewport.LastMousePos, (int)cursorFrame);
|
Cursor.Render(Renderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,26 +10,21 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.FileSystem;
|
using OpenRA.FileSystem;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
public sealed class CursorProvider : IDisposable
|
public sealed class CursorProvider
|
||||||
{
|
{
|
||||||
readonly HardwarePalette palette = new HardwarePalette();
|
public readonly IReadOnlyDictionary<string, CursorSequence> Cursors;
|
||||||
readonly Dictionary<string, CursorSequence> cursors = new Dictionary<string, CursorSequence>();
|
public readonly IReadOnlyDictionary<string, ImmutablePalette> Palettes;
|
||||||
readonly Cache<string, PaletteReference> palettes;
|
|
||||||
readonly SheetBuilder sheetBuilder;
|
|
||||||
|
|
||||||
public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } }
|
|
||||||
|
|
||||||
public CursorProvider(ModData modData)
|
public CursorProvider(ModData modData)
|
||||||
{
|
{
|
||||||
var sequenceFiles = modData.Manifest.Cursors;
|
var sequenceFiles = modData.Manifest.Cursors;
|
||||||
|
|
||||||
palettes = new Cache<string, PaletteReference>(CreatePaletteReference);
|
|
||||||
var sequences = new MiniYaml(null, sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.MergeLiberal));
|
var sequences = new MiniYaml(null, sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.MergeLiberal));
|
||||||
var shadowIndex = new int[] { };
|
var shadowIndex = new int[] { };
|
||||||
|
|
||||||
@@ -41,65 +36,35 @@ namespace OpenRA.Graphics
|
|||||||
out shadowIndex[shadowIndex.Length - 1]);
|
out shadowIndex[shadowIndex.Length - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var palettes = new Dictionary<string, ImmutablePalette>();
|
||||||
foreach (var p in nodesDict["Palettes"].Nodes)
|
foreach (var p in nodesDict["Palettes"].Nodes)
|
||||||
palette.AddPalette(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false);
|
palettes.Add(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex));
|
||||||
|
|
||||||
sheetBuilder = new SheetBuilder(SheetType.Indexed);
|
Palettes = palettes.AsReadOnly();
|
||||||
var spriteCache = new SpriteCache(modData.SpriteLoaders, new string[0], sheetBuilder);
|
|
||||||
|
var frameCache = new FrameCache(modData.SpriteLoaders, new string[0]);
|
||||||
|
var cursors = new Dictionary<string, CursorSequence>();
|
||||||
foreach (var s in nodesDict["Cursors"].Nodes)
|
foreach (var s in nodesDict["Cursors"].Nodes)
|
||||||
LoadSequencesForCursor(spriteCache, s.Key, s.Value);
|
foreach (var sequence in s.Value.Nodes)
|
||||||
sheetBuilder.Current.ReleaseBuffer();
|
cursors.Add(sequence.Key, new CursorSequence(frameCache, sequence.Key, s.Key, s.Value.Value, sequence.Value));
|
||||||
|
|
||||||
palette.Initialize();
|
Cursors = cursors.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
PaletteReference CreatePaletteReference(string name)
|
public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } }
|
||||||
{
|
|
||||||
var pal = palette.GetPalette(name);
|
|
||||||
return new PaletteReference(name, palette.GetPaletteIndex(name), pal);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadSequencesForCursor(SpriteCache cache, string cursorSrc, MiniYaml cursor)
|
|
||||||
{
|
|
||||||
foreach (var sequence in cursor.Nodes)
|
|
||||||
cursors.Add(sequence.Key, new CursorSequence(cache, cursorSrc, cursor.Value, sequence.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasCursorSequence(string cursor)
|
public bool HasCursorSequence(string cursor)
|
||||||
{
|
{
|
||||||
return cursors.ContainsKey(cursor);
|
return Cursors.ContainsKey(cursor);
|
||||||
}
|
|
||||||
|
|
||||||
public void DrawCursor(Renderer renderer, string cursorName, int2 lastMousePos, int cursorFrame)
|
|
||||||
{
|
|
||||||
var cursorSequence = GetCursorSequence(cursorName);
|
|
||||||
var cursorSprite = cursorSequence.GetSprite(cursorFrame);
|
|
||||||
var cursorSize = CursorViewportZoomed ? 2.0f * cursorSprite.size : cursorSprite.size;
|
|
||||||
|
|
||||||
var cursorOffset = CursorViewportZoomed ?
|
|
||||||
(2 * cursorSequence.Hotspot) + cursorSprite.size.ToInt2() :
|
|
||||||
cursorSequence.Hotspot + (0.5f * cursorSprite.size).ToInt2();
|
|
||||||
|
|
||||||
renderer.SetPalette(palette);
|
|
||||||
renderer.SpriteRenderer.DrawSprite(cursorSprite,
|
|
||||||
lastMousePos - cursorOffset,
|
|
||||||
palettes[cursorSequence.Palette],
|
|
||||||
cursorSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CursorSequence GetCursorSequence(string cursor)
|
public CursorSequence GetCursorSequence(string cursor)
|
||||||
{
|
{
|
||||||
try { return cursors[cursor]; }
|
try { return Cursors[cursor]; }
|
||||||
catch (KeyNotFoundException)
|
catch (KeyNotFoundException)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Cursor does not have a sequence `{0}`".F(cursor));
|
throw new InvalidOperationException("Cursor does not have a sequence `{0}`".F(cursor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
palette.Dispose();
|
|
||||||
sheetBuilder.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,47 +8,46 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
public class CursorSequence
|
public class CursorSequence
|
||||||
{
|
{
|
||||||
readonly int start, length;
|
public readonly string Name;
|
||||||
readonly string palette;
|
public readonly int Start;
|
||||||
|
public readonly int Length;
|
||||||
public int Start { get { return start; } }
|
public readonly string Palette;
|
||||||
public int End { get { return start + length; } }
|
|
||||||
public int Length { get { return length; } }
|
|
||||||
public string Palette { get { return palette; } }
|
|
||||||
public readonly int2 Hotspot;
|
public readonly int2 Hotspot;
|
||||||
|
|
||||||
Sprite[] sprites;
|
public readonly ISpriteFrame[] Frames;
|
||||||
|
|
||||||
public CursorSequence(SpriteCache cache, string cursorSrc, string palette, MiniYaml info)
|
public CursorSequence(FrameCache cache, string name, string cursorSrc, string palette, MiniYaml info)
|
||||||
{
|
{
|
||||||
sprites = cache[cursorSrc];
|
|
||||||
var d = info.ToDictionary();
|
var d = info.ToDictionary();
|
||||||
|
|
||||||
start = Exts.ParseIntegerInvariant(d["Start"].Value);
|
Start = Exts.ParseIntegerInvariant(d["Start"].Value);
|
||||||
this.palette = palette;
|
Palette = palette;
|
||||||
|
Name = name;
|
||||||
|
|
||||||
if ((d.ContainsKey("Length") && d["Length"].Value == "*") || (d.ContainsKey("End") && d["End"].Value == "*"))
|
if ((d.ContainsKey("Length") && d["Length"].Value == "*") || (d.ContainsKey("End") && d["End"].Value == "*"))
|
||||||
length = sprites.Length - start;
|
Length = Frames.Length - Start;
|
||||||
else if (d.ContainsKey("Length"))
|
else if (d.ContainsKey("Length"))
|
||||||
length = Exts.ParseIntegerInvariant(d["Length"].Value);
|
Length = Exts.ParseIntegerInvariant(d["Length"].Value);
|
||||||
else if (d.ContainsKey("End"))
|
else if (d.ContainsKey("End"))
|
||||||
length = Exts.ParseIntegerInvariant(d["End"].Value) - start;
|
Length = Exts.ParseIntegerInvariant(d["End"].Value) - Start;
|
||||||
else
|
else
|
||||||
length = 1;
|
Length = 1;
|
||||||
|
|
||||||
|
Frames = cache[cursorSrc]
|
||||||
|
.Skip(Start)
|
||||||
|
.Take(Length)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
if (d.ContainsKey("X"))
|
if (d.ContainsKey("X"))
|
||||||
Exts.TryParseIntegerInvariant(d["X"].Value, out Hotspot.X);
|
Exts.TryParseIntegerInvariant(d["X"].Value, out Hotspot.X);
|
||||||
if (d.ContainsKey("Y"))
|
if (d.ContainsKey("Y"))
|
||||||
Exts.TryParseIntegerInvariant(d["Y"].Value, out Hotspot.Y);
|
Exts.TryParseIntegerInvariant(d["Y"].Value, out Hotspot.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sprite GetSprite(int frame)
|
|
||||||
{
|
|
||||||
return sprites[(frame % length) + start];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
100
OpenRA.Game/Graphics/SoftwareCursor.cs
Normal file
100
OpenRA.Game/Graphics/SoftwareCursor.cs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2014 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
using OpenRA.Primitives;
|
||||||
|
|
||||||
|
namespace OpenRA.Graphics
|
||||||
|
{
|
||||||
|
public interface ICursor : IDisposable
|
||||||
|
{
|
||||||
|
void Render(Renderer renderer);
|
||||||
|
void SetCursor(string cursor);
|
||||||
|
void Tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SoftwareCursor : ICursor
|
||||||
|
{
|
||||||
|
readonly HardwarePalette palette = new HardwarePalette();
|
||||||
|
readonly Cache<string, PaletteReference> paletteReferences;
|
||||||
|
readonly Dictionary<string, Sprite[]> sprites = new Dictionary<string, Sprite[]>();
|
||||||
|
readonly CursorProvider cursorProvider;
|
||||||
|
readonly SheetBuilder sheetBuilder;
|
||||||
|
|
||||||
|
public SoftwareCursor(CursorProvider cursorProvider)
|
||||||
|
{
|
||||||
|
this.cursorProvider = cursorProvider;
|
||||||
|
|
||||||
|
paletteReferences = new Cache<string, PaletteReference>(CreatePaletteReference);
|
||||||
|
foreach (var p in cursorProvider.Palettes)
|
||||||
|
palette.AddPalette(p.Key, p.Value, false);
|
||||||
|
|
||||||
|
palette.Initialize();
|
||||||
|
|
||||||
|
sheetBuilder = new SheetBuilder(SheetType.Indexed);
|
||||||
|
foreach (var kv in cursorProvider.Cursors)
|
||||||
|
{
|
||||||
|
var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray();
|
||||||
|
sprites.Add(kv.Key, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
sheetBuilder.Current.ReleaseBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
PaletteReference CreatePaletteReference(string name)
|
||||||
|
{
|
||||||
|
var pal = palette.GetPalette(name);
|
||||||
|
return new PaletteReference(name, palette.GetPaletteIndex(name), pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
string cursorName;
|
||||||
|
public void SetCursor(string cursor)
|
||||||
|
{
|
||||||
|
cursorName = cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
float cursorFrame;
|
||||||
|
public void Tick()
|
||||||
|
{
|
||||||
|
cursorFrame += 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Renderer renderer)
|
||||||
|
{
|
||||||
|
if (cursorName == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var cursorSequence = cursorProvider.GetCursorSequence(cursorName);
|
||||||
|
var cursorSprite = sprites[cursorName][((int)cursorFrame % cursorSequence.Length)];
|
||||||
|
var cursorSize = CursorProvider.CursorViewportZoomed ? 2.0f * cursorSprite.size : cursorSprite.size;
|
||||||
|
|
||||||
|
var cursorOffset = CursorProvider.CursorViewportZoomed ?
|
||||||
|
(2 * cursorSequence.Hotspot) + cursorSprite.size.ToInt2() :
|
||||||
|
cursorSequence.Hotspot + (0.5f * cursorSprite.size).ToInt2();
|
||||||
|
|
||||||
|
renderer.SetPalette(palette);
|
||||||
|
renderer.SpriteRenderer.DrawSprite(cursorSprite,
|
||||||
|
Viewport.LastMousePos - cursorOffset,
|
||||||
|
paletteReferences[cursorSequence.Palette],
|
||||||
|
cursorSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
palette.Dispose();
|
||||||
|
sheetBuilder.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -90,8 +90,6 @@ namespace OpenRA
|
|||||||
VoxelLoader.Dispose();
|
VoxelLoader.Dispose();
|
||||||
VoxelLoader = new VoxelLoader();
|
VoxelLoader = new VoxelLoader();
|
||||||
|
|
||||||
if (CursorProvider != null)
|
|
||||||
CursorProvider.Dispose();
|
|
||||||
CursorProvider = new CursorProvider(this);
|
CursorProvider = new CursorProvider(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,8 +173,6 @@ namespace OpenRA
|
|||||||
MapCache.Dispose();
|
MapCache.Dispose();
|
||||||
if (VoxelLoader != null)
|
if (VoxelLoader != null)
|
||||||
VoxelLoader.Dispose();
|
VoxelLoader.Dispose();
|
||||||
if (CursorProvider != null)
|
|
||||||
CursorProvider.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -252,6 +252,7 @@
|
|||||||
<Compile Include="Graphics\TargetLineRenderable.cs" />
|
<Compile Include="Graphics\TargetLineRenderable.cs" />
|
||||||
<Compile Include="Graphics\UISpriteRenderable.cs" />
|
<Compile Include="Graphics\UISpriteRenderable.cs" />
|
||||||
<Compile Include="GameRules\DamageWarhead.cs" />
|
<Compile Include="GameRules\DamageWarhead.cs" />
|
||||||
|
<Compile Include="Graphics\SoftwareCursor.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="FileSystem\D2kSoundResources.cs" />
|
<Compile Include="FileSystem\D2kSoundResources.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user