Move ownership of tile sprites to the terrain renderer.

This commit is contained in:
Paul Chote
2020-12-30 18:42:25 +00:00
committed by reaperrr
parent 2eee911c58
commit 0a374e2264
9 changed files with 84 additions and 50 deletions

View File

@@ -53,6 +53,9 @@ namespace OpenRA.Mods.Common.Traits
public void RulesetLoaded(Ruleset rules, ActorInfo ai)
{
if (!rules.Actors["world"].HasTraitInfo<ITiledTerrainRendererInfo>())
throw new YamlException("Bridge requires a tile-based terrain renderer.");
if (string.IsNullOrEmpty(DemolishWeapon))
throw new YamlException("A value for DemolishWeapon of a Bridge trait is missing.");
@@ -93,6 +96,7 @@ namespace OpenRA.Mods.Common.Traits
readonly BuildingInfo buildingInfo;
readonly Bridge[] neighbours = new Bridge[2];
readonly LegacyBridgeHut[] huts = new LegacyBridgeHut[2]; // Huts before this / first & after this / last
readonly ITiledTerrainRenderer terrainRenderer;
readonly Health health;
readonly Actor self;
readonly BridgeInfo info;
@@ -114,6 +118,7 @@ namespace OpenRA.Mods.Common.Traits
type = self.Info.Name;
isDangling = new Lazy<bool>(() => huts[0] == huts[1] && (neighbours[0] == null || neighbours[1] == null));
buildingInfo = self.Info.TraitInfo<BuildingInfo>();
terrainRenderer = self.World.WorldActor.Trait<ITiledTerrainRenderer>();
}
public Bridge Neighbour(int direction) { return neighbours[direction]; }
@@ -198,7 +203,7 @@ namespace OpenRA.Mods.Common.Traits
var offset = buildingInfo.CenterOffset(self.World).Y + 1024;
return footprint.Select(c => (IRenderable)(new SpriteRenderable(
wr.Theater.TileSprite(new TerrainTile(template, c.Value)),
terrainRenderer.TileSprite(new TerrainTile(template, c.Value)),
wr.World.Map.CenterOfCell(c.Key), WVec.Zero, -offset, palette, 1f, true))).ToArray();
}
@@ -224,7 +229,7 @@ namespace OpenRA.Mods.Common.Traits
foreach (var kv in footprint)
{
var xy = wr.ScreenPxPosition(wr.World.Map.CenterOfCell(kv.Key));
var size = wr.Theater.TileSprite(new TerrainTile(template, kv.Value)).Bounds.Size;
var size = terrainRenderer.TileSprite(new TerrainTile(template, kv.Value)).Bounds.Size;
// Add an extra pixel padding to avoid issues with odd-sized sprites
var halfWidth = size.Width / 2 + 1;

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits
public enum EditorCursorType { None, Actor, TerrainTemplate, Resource }
[Desc("Required for the map editor to work. Attach this to the world actor.")]
public class EditorCursorLayerInfo : TraitInfo, Requires<EditorActorLayerInfo>
public class EditorCursorLayerInfo : TraitInfo, Requires<EditorActorLayerInfo>, Requires<ITiledTerrainRendererInfo>
{
public readonly WAngle PreviewFacing = new WAngle(384);
@@ -30,6 +30,7 @@ namespace OpenRA.Mods.Common.Traits
{
readonly EditorCursorLayerInfo info;
readonly EditorActorLayer editorLayer;
readonly ITiledTerrainRenderer terrainRenderer;
readonly World world;
public int CurrentToken { get; private set; }
@@ -51,6 +52,7 @@ namespace OpenRA.Mods.Common.Traits
this.info = info;
world = self.World;
editorLayer = self.Trait<EditorActorLayer>();
terrainRenderer = self.Trait<ITiledTerrainRenderer>();
Type = EditorCursorType.None;
}
@@ -81,7 +83,7 @@ namespace OpenRA.Mods.Common.Traits
if (!world.Map.Rules.TileSet.TryGetTileInfo(tile, out var tileInfo))
continue;
var sprite = wr.Theater.TileSprite(tile, 0);
var sprite = terrainRenderer.TileSprite(tile, 0);
var offset = world.Map.Offset(new CVec(x, y), tileInfo.Height);
var palette = wr.Palette(TerrainTemplate.Palette ?? TileSet.TerrainPaletteInternalName);

View File

@@ -11,31 +11,31 @@
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class TerrainRendererInfo : TraitInfo
public class TerrainRendererInfo : TraitInfo, ITiledTerrainRendererInfo
{
public override object Create(ActorInitializer init) { return new TerrainRenderer(init.World); }
}
public sealed class TerrainRenderer : IRenderTerrain, IWorldLoaded, INotifyActorDisposing
public sealed class TerrainRenderer : IRenderTerrain, IWorldLoaded, INotifyActorDisposing, ITiledTerrainRenderer
{
readonly Map map;
readonly Dictionary<string, TerrainSpriteLayer> spriteLayers = new Dictionary<string, TerrainSpriteLayer>();
Theater theater;
readonly Theater theater;
bool disposed;
public TerrainRenderer(World world)
{
map = world.Map;
theater = new Theater(world.Map.Rules.TileSet);
}
void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr)
{
theater = wr.Theater;
foreach (var template in map.Rules.TileSet.Templates)
{
var palette = template.Value.Palette ?? TileSet.TerrainPaletteInternalName;
@@ -57,9 +57,8 @@ namespace OpenRA.Mods.Common.Traits
if (map.Rules.TileSet.Templates.ContainsKey(tile.Type))
palette = map.Rules.TileSet.Templates[tile.Type].Palette ?? palette;
var sprite = theater.TileSprite(tile);
foreach (var kv in spriteLayers)
kv.Value.Update(cell, palette == kv.Key ? sprite : null, false);
kv.Value.Update(cell, palette == kv.Key ? theater.TileSprite(tile) : null, false);
}
void IRenderTerrain.RenderTerrain(WorldRenderer wr, Viewport viewport)
@@ -82,7 +81,42 @@ namespace OpenRA.Mods.Common.Traits
foreach (var kv in spriteLayers.Values)
kv.Dispose();
theater.Dispose();
disposed = true;
}
Sheet ITiledTerrainRenderer.Sheet { get { return theater.Sheet; } }
Sprite ITiledTerrainRenderer.TileSprite(TerrainTile r, int? variant)
{
return theater.TileSprite(r, variant);
}
Rectangle ITiledTerrainRenderer.TemplateBounds(TerrainTemplateInfo template)
{
Rectangle? templateRect = null;
var tileSize = map.Grid.TileSize;
var i = 0;
for (var y = 0; y < template.Size.Y; y++)
{
for (var x = 0; x < template.Size.X; x++)
{
var tile = new TerrainTile(template.Id, (byte)(i++));
if (!map.Rules.TileSet.TryGetTileInfo(tile, out var tileInfo))
continue;
var sprite = theater.TileSprite(tile);
var u = map.Grid.Type == MapGridType.Rectangular ? x : (x - y) / 2f;
var v = map.Grid.Type == MapGridType.Rectangular ? y : (x + y) / 2f;
var tl = new float2(u * tileSize.Width, (v - 0.5f * tileInfo.Height) * tileSize.Height) - 0.5f * sprite.Size;
var rect = new Rectangle((int)(tl.X + sprite.Offset.X), (int)(tl.Y + sprite.Offset.Y), (int)sprite.Size.X, (int)sprite.Size.Y);
templateRect = templateRect.HasValue ? Rectangle.Union(templateRect.Value, rect) : rect;
}
}
return templateRect ?? Rectangle.Empty;
}
}
}

View File

@@ -643,4 +643,15 @@ namespace OpenRA.Mods.Common.Traits
IEnumerable<IRenderable> RenderDecoration(Actor self, WorldRenderer wr, ISelectionDecorations container);
}
[RequireExplicitImplementation]
public interface ITiledTerrainRendererInfo : ITraitInfoInterface { }
[RequireExplicitImplementation]
public interface ITiledTerrainRenderer
{
Sheet Sheet { get; }
Sprite TileSprite(TerrainTile r, int? variant = null);
Rectangle TemplateBounds(TerrainTemplateInfo template);
}
}

View File

@@ -13,6 +13,7 @@ using System;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
@@ -36,6 +37,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}
readonly TileSet tileset;
readonly ITiledTerrainRenderer terrainRenderer;
readonly TileSelectorTemplate[] allTemplates;
readonly EditorCursorLayer editorCursor;
@@ -44,6 +46,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
: base(widget, world, worldRenderer, "TILETEMPLATE_LIST", "TILEPREVIEW_TEMPLATE")
{
tileset = world.Map.Rules.TileSet;
terrainRenderer = world.WorldActor.TraitOrDefault<ITiledTerrainRenderer>();
if (terrainRenderer == null)
throw new YamlException("TileSelectorLogic requires a tile-based terrain renderer.");
allTemplates = tileset.Templates.Values.Select(t => new TileSelectorTemplate(t)).ToArray();
editorCursor = world.WorldActor.Trait<EditorCursorLayer>();
@@ -106,8 +112,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var preview = item.Get<TerrainTemplatePreviewWidget>("TILE_PREVIEW");
var template = tileset.Templates[tileId];
var grid = WorldRenderer.World.Map.Grid;
var bounds = WorldRenderer.Theater.TemplateBounds(template, grid.TileSize, grid.Type);
var bounds = terrainRenderer.TemplateBounds(template);
// Scale templates to fit within the panel
var scale = 1f;

View File

@@ -11,7 +11,9 @@
using System;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
@@ -20,6 +22,7 @@ namespace OpenRA.Mods.Common.Widgets
{
public Func<float> GetScale = () => 1f;
readonly ITiledTerrainRenderer terrainRenderer;
readonly WorldRenderer worldRenderer;
readonly TileSet tileset;
@@ -39,8 +42,7 @@ namespace OpenRA.Mods.Common.Widgets
if (template == null)
return;
var grid = Game.ModData.Manifest.Get<MapGrid>();
bounds = worldRenderer.Theater.TemplateBounds(template, grid.TileSize, grid.Type);
bounds = terrainRenderer.TemplateBounds(template);
}
}
@@ -49,6 +51,9 @@ namespace OpenRA.Mods.Common.Widgets
{
this.worldRenderer = worldRenderer;
tileset = world.Map.Rules.TileSet;
terrainRenderer = world.WorldActor.TraitOrDefault<ITiledTerrainRenderer>();
if (terrainRenderer == null)
throw new YamlException("TerrainTemplatePreviewWidget requires a tile-based terrain renderer.");
}
protected TerrainTemplatePreviewWidget(TerrainTemplatePreviewWidget other)
@@ -56,6 +61,7 @@ namespace OpenRA.Mods.Common.Widgets
{
worldRenderer = other.worldRenderer;
tileset = other.worldRenderer.World.Map.Rules.TileSet;
terrainRenderer = other.terrainRenderer;
Template = other.Template;
GetScale = other.GetScale;
}
@@ -84,7 +90,7 @@ namespace OpenRA.Mods.Common.Widgets
if (!tileset.TryGetTileInfo(tile, out var tileInfo))
continue;
var sprite = worldRenderer.Theater.TileSprite(tile, 0);
var sprite = terrainRenderer.TileSprite(tile, 0);
var size = new float2(sprite.Size.X * scale, sprite.Size.Y * scale);
var u = gridType == MapGridType.Rectangular ? x : (x - y) / 2f;