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]; 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 Sheet Sheet { get { return sheetBuilder.Current; } }
public void Dispose() public void Dispose()

View File

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

View File

@@ -53,6 +53,9 @@ namespace OpenRA.Mods.Common.Traits
public void RulesetLoaded(Ruleset rules, ActorInfo ai) 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)) if (string.IsNullOrEmpty(DemolishWeapon))
throw new YamlException("A value for DemolishWeapon of a Bridge trait is missing."); 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 BuildingInfo buildingInfo;
readonly Bridge[] neighbours = new Bridge[2]; readonly Bridge[] neighbours = new Bridge[2];
readonly LegacyBridgeHut[] huts = new LegacyBridgeHut[2]; // Huts before this / first & after this / last readonly LegacyBridgeHut[] huts = new LegacyBridgeHut[2]; // Huts before this / first & after this / last
readonly ITiledTerrainRenderer terrainRenderer;
readonly Health health; readonly Health health;
readonly Actor self; readonly Actor self;
readonly BridgeInfo info; readonly BridgeInfo info;
@@ -114,6 +118,7 @@ namespace OpenRA.Mods.Common.Traits
type = self.Info.Name; type = self.Info.Name;
isDangling = new Lazy<bool>(() => huts[0] == huts[1] && (neighbours[0] == null || neighbours[1] == null)); isDangling = new Lazy<bool>(() => huts[0] == huts[1] && (neighbours[0] == null || neighbours[1] == null));
buildingInfo = self.Info.TraitInfo<BuildingInfo>(); buildingInfo = self.Info.TraitInfo<BuildingInfo>();
terrainRenderer = self.World.WorldActor.Trait<ITiledTerrainRenderer>();
} }
public Bridge Neighbour(int direction) { return neighbours[direction]; } 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; var offset = buildingInfo.CenterOffset(self.World).Y + 1024;
return footprint.Select(c => (IRenderable)(new SpriteRenderable( 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(); 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) foreach (var kv in footprint)
{ {
var xy = wr.ScreenPxPosition(wr.World.Map.CenterOfCell(kv.Key)); 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 // Add an extra pixel padding to avoid issues with odd-sized sprites
var halfWidth = size.Width / 2 + 1; var halfWidth = size.Width / 2 + 1;

View File

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

View File

@@ -11,31 +11,31 @@
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Primitives;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.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 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 Map map;
readonly Dictionary<string, TerrainSpriteLayer> spriteLayers = new Dictionary<string, TerrainSpriteLayer>(); readonly Dictionary<string, TerrainSpriteLayer> spriteLayers = new Dictionary<string, TerrainSpriteLayer>();
Theater theater; readonly Theater theater;
bool disposed; bool disposed;
public TerrainRenderer(World world) public TerrainRenderer(World world)
{ {
map = world.Map; map = world.Map;
theater = new Theater(world.Map.Rules.TileSet);
} }
void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr) void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr)
{ {
theater = wr.Theater;
foreach (var template in map.Rules.TileSet.Templates) foreach (var template in map.Rules.TileSet.Templates)
{ {
var palette = template.Value.Palette ?? TileSet.TerrainPaletteInternalName; var palette = template.Value.Palette ?? TileSet.TerrainPaletteInternalName;
@@ -57,9 +57,8 @@ namespace OpenRA.Mods.Common.Traits
if (map.Rules.TileSet.Templates.ContainsKey(tile.Type)) if (map.Rules.TileSet.Templates.ContainsKey(tile.Type))
palette = map.Rules.TileSet.Templates[tile.Type].Palette ?? palette; palette = map.Rules.TileSet.Templates[tile.Type].Palette ?? palette;
var sprite = theater.TileSprite(tile);
foreach (var kv in spriteLayers) 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) void IRenderTerrain.RenderTerrain(WorldRenderer wr, Viewport viewport)
@@ -82,7 +81,42 @@ namespace OpenRA.Mods.Common.Traits
foreach (var kv in spriteLayers.Values) foreach (var kv in spriteLayers.Values)
kv.Dispose(); kv.Dispose();
theater.Dispose();
disposed = true; 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); 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 System.Linq;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
using OpenRA.Widgets; using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic namespace OpenRA.Mods.Common.Widgets.Logic
@@ -36,6 +37,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
} }
readonly TileSet tileset; readonly TileSet tileset;
readonly ITiledTerrainRenderer terrainRenderer;
readonly TileSelectorTemplate[] allTemplates; readonly TileSelectorTemplate[] allTemplates;
readonly EditorCursorLayer editorCursor; readonly EditorCursorLayer editorCursor;
@@ -44,6 +46,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
: base(widget, world, worldRenderer, "TILETEMPLATE_LIST", "TILEPREVIEW_TEMPLATE") : base(widget, world, worldRenderer, "TILETEMPLATE_LIST", "TILEPREVIEW_TEMPLATE")
{ {
tileset = world.Map.Rules.TileSet; 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(); allTemplates = tileset.Templates.Values.Select(t => new TileSelectorTemplate(t)).ToArray();
editorCursor = world.WorldActor.Trait<EditorCursorLayer>(); editorCursor = world.WorldActor.Trait<EditorCursorLayer>();
@@ -106,8 +112,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var preview = item.Get<TerrainTemplatePreviewWidget>("TILE_PREVIEW"); var preview = item.Get<TerrainTemplatePreviewWidget>("TILE_PREVIEW");
var template = tileset.Templates[tileId]; var template = tileset.Templates[tileId];
var grid = WorldRenderer.World.Map.Grid; var bounds = terrainRenderer.TemplateBounds(template);
var bounds = WorldRenderer.Theater.TemplateBounds(template, grid.TileSize, grid.Type);
// Scale templates to fit within the panel // Scale templates to fit within the panel
var scale = 1f; var scale = 1f;

View File

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

View File

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