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

@@ -162,32 +162,6 @@ namespace OpenRA.Graphics
return template.Sprites[start * template.Stride + r.Index];
}
public Rectangle TemplateBounds(TerrainTemplateInfo template, Size tileSize, MapGridType mapGrid)
{
Rectangle? templateRect = null;
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 (!tileset.TryGetTileInfo(tile, out var tileInfo))
continue;
var sprite = TileSprite(tile);
var u = mapGrid == MapGridType.Rectangular ? x : (x - y) / 2f;
var v = mapGrid == 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.HasValue ? templateRect.Value : Rectangle.Empty;
}
public Sheet Sheet { get { return sheetBuilder.Current; } }
public void Dispose()

View File

@@ -26,7 +26,6 @@ namespace OpenRA.Graphics
public readonly Size TileSize;
public readonly int TileScale;
public readonly World World;
public readonly Theater Theater;
public Viewport Viewport { get; private set; }
public readonly ITerrainLighting TerrainLighting;
@@ -68,7 +67,6 @@ namespace OpenRA.Graphics
palette.Initialize();
Theater = new Theater(world.Map.Rules.TileSet);
TerrainLighting = world.WorldActor.TraitOrDefault<ITerrainLighting>();
terrainRenderer = world.WorldActor.TraitOrDefault<IRenderTerrain>();
@@ -425,7 +423,6 @@ namespace OpenRA.Graphics
World.Dispose();
palette.Dispose();
Theater.Dispose();
}
}
}

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;

View File

@@ -18,7 +18,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.D2k.Traits
{
[Desc("Attach this to the world actor. Required for LaysTerrain to work.")]
public class BuildableTerrainLayerInfo : TraitInfo
public class BuildableTerrainLayerInfo : TraitInfo, Requires<ITiledTerrainRendererInfo>
{
[Desc("Palette to render the layer sprites in.")]
public readonly string Palette = TileSet.TerrainPaletteInternalName;
@@ -33,11 +33,11 @@ namespace OpenRA.Mods.D2k.Traits
{
readonly BuildableTerrainLayerInfo info;
readonly Dictionary<CPos, TerrainTile?> dirty = new Dictionary<CPos, TerrainTile?>();
readonly ITiledTerrainRenderer terrainRenderer;
readonly World world;
readonly CellLayer<int> strength;
TerrainSpriteLayer render;
Theater theater;
bool disposed;
public BuildableTerrainLayer(Actor self, BuildableTerrainLayerInfo info)
@@ -45,12 +45,12 @@ namespace OpenRA.Mods.D2k.Traits
this.info = info;
world = self.World;
strength = new CellLayer<int>(world.Map);
terrainRenderer = self.Trait<ITiledTerrainRenderer>();
}
public void WorldLoaded(World w, WorldRenderer wr)
{
theater = wr.Theater;
render = new TerrainSpriteLayer(w, wr, theater.Sheet, BlendMode.Alpha, wr.Palette(info.Palette), wr.World.Type != WorldType.Editor);
render = new TerrainSpriteLayer(w, wr, terrainRenderer.Sheet, BlendMode.Alpha, wr.Palette(info.Palette), wr.World.Type != WorldType.Editor);
}
public void AddTile(CPos cell, TerrainTile tile)
@@ -98,7 +98,7 @@ namespace OpenRA.Mods.D2k.Traits
if (tile.HasValue)
{
// Terrain tiles define their origin at the topleft
var s = theater.TileSprite(tile.Value);
var s = terrainRenderer.TileSprite(tile.Value);
var ss = new Sprite(s.Sheet, s.Bounds, s.ZRamp, float2.Zero, s.Channel, s.BlendMode);
render.Update(kv.Key, ss, false);
}