Support multiple sheets in TerrainSpriteLayer.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
@@ -17,7 +18,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class SpriteRenderer : Renderer.IBatchRenderer
|
||||
{
|
||||
const int SheetCount = 7;
|
||||
public const int SheetCount = 7;
|
||||
static readonly string[] SheetIndexToTextureName = Exts.MakeArray(SheetCount, i => "Texture{0}".F(i));
|
||||
|
||||
readonly Renderer renderer;
|
||||
@@ -151,15 +152,30 @@ namespace OpenRA.Graphics
|
||||
nv += 6;
|
||||
}
|
||||
|
||||
public void DrawVertexBuffer(IVertexBuffer<Vertex> buffer, int start, int length, PrimitiveType type, Sheet sheet, BlendMode blendMode)
|
||||
public void DrawVertexBuffer(IVertexBuffer<Vertex> buffer, int start, int length, PrimitiveType type, IEnumerable<Sheet> sheets, BlendMode blendMode)
|
||||
{
|
||||
shader.SetTexture("Texture0", sheet.GetTexture());
|
||||
var i = 0;
|
||||
foreach (var s in sheets)
|
||||
{
|
||||
if (i >= SheetCount)
|
||||
ThrowSheetOverflow(nameof(sheets));
|
||||
|
||||
if (s != null)
|
||||
shader.SetTexture(SheetIndexToTextureName[i++], s.GetTexture());
|
||||
}
|
||||
|
||||
renderer.Context.SetBlendMode(blendMode);
|
||||
shader.PrepareRender();
|
||||
renderer.DrawBatch(buffer, start, length, type);
|
||||
renderer.Context.SetBlendMode(BlendMode.None);
|
||||
}
|
||||
|
||||
// PERF: methods that throw won't be inlined by the JIT, so extract a static helper for use on hot paths
|
||||
static void ThrowSheetOverflow(string paramName)
|
||||
{
|
||||
throw new ArgumentException("SpriteRenderer only supports {0} simultaneous textures".F(SheetCount), paramName);
|
||||
}
|
||||
|
||||
// For RGBAColorRenderer
|
||||
internal void DrawRGBAVertices(Vertex[] v)
|
||||
{
|
||||
|
||||
@@ -20,9 +20,9 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
static readonly int[] CornerVertexMap = { 0, 1, 2, 2, 3, 0 };
|
||||
|
||||
public readonly Sheet Sheet;
|
||||
public readonly BlendMode BlendMode;
|
||||
|
||||
readonly Sheet[] sheets;
|
||||
readonly Sprite emptySprite;
|
||||
|
||||
readonly IVertexBuffer<Vertex> vertexBuffer;
|
||||
@@ -37,11 +37,12 @@ namespace OpenRA.Graphics
|
||||
|
||||
readonly PaletteReference[] palettes;
|
||||
|
||||
public TerrainSpriteLayer(World world, WorldRenderer wr, Sheet sheet, BlendMode blendMode, bool restrictToBounds)
|
||||
public TerrainSpriteLayer(World world, WorldRenderer wr, Sprite emptySprite, BlendMode blendMode, bool restrictToBounds)
|
||||
{
|
||||
worldRenderer = wr;
|
||||
this.restrictToBounds = restrictToBounds;
|
||||
Sheet = sheet;
|
||||
this.emptySprite = emptySprite;
|
||||
sheets = new Sheet[SpriteRenderer.SheetCount];
|
||||
BlendMode = blendMode;
|
||||
|
||||
map = world.Map;
|
||||
@@ -50,7 +51,6 @@ namespace OpenRA.Graphics
|
||||
vertices = new Vertex[rowStride * map.MapSize.Y];
|
||||
palettes = new PaletteReference[map.MapSize.X * map.MapSize.Y];
|
||||
vertexBuffer = Game.Renderer.Context.CreateVertexBuffer(vertices.Length);
|
||||
emptySprite = new Sprite(sheet, Rectangle.Empty, TextureChannel.Alpha);
|
||||
|
||||
wr.PaletteInvalidated += UpdatePaletteIndices;
|
||||
|
||||
@@ -136,25 +136,48 @@ namespace OpenRA.Graphics
|
||||
dirtyRows.Add(uv.V);
|
||||
}
|
||||
|
||||
int GetOrAddSheetIndex(Sheet sheet)
|
||||
{
|
||||
if (sheet == null)
|
||||
return 0;
|
||||
|
||||
for (var i = 0; i < sheets.Length; i++)
|
||||
{
|
||||
if (sheets[i] == sheet)
|
||||
return i;
|
||||
|
||||
if (sheets[i] == null)
|
||||
{
|
||||
sheets[i] = sheet;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidDataException("Sheet overflow");
|
||||
}
|
||||
|
||||
public void Update(MPos uv, Sprite sprite, PaletteReference palette, in float3 pos, bool ignoreTint)
|
||||
{
|
||||
int2 samplers;
|
||||
if (sprite != null)
|
||||
{
|
||||
if (sprite.Sheet != Sheet)
|
||||
throw new InvalidDataException("Attempted to add sprite from a different sheet");
|
||||
|
||||
if (sprite.BlendMode != BlendMode)
|
||||
throw new InvalidDataException("Attempted to add sprite with a different blend mode");
|
||||
|
||||
samplers = new int2(GetOrAddSheetIndex(sprite.Sheet), GetOrAddSheetIndex((sprite as SpriteWithSecondaryData)?.SecondarySheet));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite = emptySprite;
|
||||
samplers = int2.Zero;
|
||||
}
|
||||
|
||||
// The vertex buffer does not have geometry for cells outside the map
|
||||
if (!map.Tiles.Contains(uv))
|
||||
return;
|
||||
|
||||
var offset = rowStride * uv.V + 6 * uv.U;
|
||||
Util.FastCreateQuad(vertices, pos, sprite, int2.Zero, palette?.TextureIndex ?? 0, offset, sprite.Size, float3.Ones, 1f);
|
||||
Util.FastCreateQuad(vertices, pos, sprite, samplers, palette?.TextureIndex ?? 0, offset, sprite.Size, float3.Ones, 1f);
|
||||
palettes[uv.V * map.MapSize.X + uv.U] = palette;
|
||||
|
||||
if (worldRenderer.TerrainLighting != null)
|
||||
@@ -188,7 +211,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer(
|
||||
vertexBuffer, rowStride * firstRow, rowStride * (lastRow - firstRow),
|
||||
PrimitiveType.TriangleList, Sheet, BlendMode);
|
||||
PrimitiveType.TriangleList, sheets, BlendMode);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -63,14 +64,12 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (spriteLayer == null)
|
||||
{
|
||||
var first = r.Value.Variants.First().Value.GetSprite(0);
|
||||
spriteLayer = new TerrainSpriteLayer(w, wr, first.Sheet, first.BlendMode, wr.World.Type != WorldType.Editor);
|
||||
var emptySprite = new Sprite(first.Sheet, Rectangle.Empty, TextureChannel.Alpha);
|
||||
spriteLayer = new TerrainSpriteLayer(w, wr, emptySprite, first.BlendMode, wr.World.Type != WorldType.Editor);
|
||||
}
|
||||
|
||||
// All resources must share a sheet and blend mode
|
||||
var sprites = r.Value.Variants.Values.SelectMany(v => Exts.MakeArray(v.Length, x => v.GetSprite(x)));
|
||||
if (sprites.Any(s => s.Sheet != spriteLayer.Sheet))
|
||||
throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier.");
|
||||
|
||||
if (sprites.Any(s => s.BlendMode != spriteLayer.BlendMode))
|
||||
throw new InvalidDataException("Resource sprites specify different blend modes. "
|
||||
+ "Try using different ResourceRenderer traits for resource types that use different blend modes.");
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -190,26 +191,19 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
visibleUnderFog = puv => map.Contains(puv);
|
||||
|
||||
var shroudSheet = shroudSprites[0].Sheet;
|
||||
if (shroudSprites.Any(s => s.Sheet != shroudSheet))
|
||||
throw new InvalidDataException("Shroud sprites span multiple sheets. Try loading their sequences earlier.");
|
||||
|
||||
var shroudBlend = shroudSprites[0].BlendMode;
|
||||
if (shroudSprites.Any(s => s.BlendMode != shroudBlend))
|
||||
throw new InvalidDataException("Shroud sprites must all use the same blend mode.");
|
||||
|
||||
var fogSheet = fogSprites[0].Sheet;
|
||||
if (fogSprites.Any(s => s.Sheet != fogSheet))
|
||||
throw new InvalidDataException("Fog sprites span multiple sheets. Try loading their sequences earlier.");
|
||||
|
||||
var fogBlend = fogSprites[0].BlendMode;
|
||||
if (fogSprites.Any(s => s.BlendMode != fogBlend))
|
||||
throw new InvalidDataException("Fog sprites must all use the same blend mode.");
|
||||
|
||||
var emptySprite = new Sprite(shroudSprites[0].Sheet, Rectangle.Empty, TextureChannel.Alpha);
|
||||
shroudPaletteReference = wr.Palette(info.ShroudPalette);
|
||||
fogPaletteReference = wr.Palette(info.FogPalette);
|
||||
shroudLayer = new TerrainSpriteLayer(w, wr, shroudSheet, shroudBlend, false);
|
||||
fogLayer = new TerrainSpriteLayer(w, wr, fogSheet, fogBlend, false);
|
||||
shroudLayer = new TerrainSpriteLayer(w, wr, emptySprite, shroudBlend, false);
|
||||
fogLayer = new TerrainSpriteLayer(w, wr, emptySprite, fogBlend, false);
|
||||
|
||||
WorldOnRenderPlayerChanged(world.RenderPlayer);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Effects;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -114,16 +115,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
var sprites = smudges.Values.SelectMany(v => Exts.MakeArray(v.Length, x => v.GetSprite(x))).ToList();
|
||||
var sheet = sprites[0].Sheet;
|
||||
var blendMode = sprites[0].BlendMode;
|
||||
|
||||
if (sprites.Any(s => s.Sheet != sheet))
|
||||
throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier.");
|
||||
var emptySprite = new Sprite(sheet, Rectangle.Empty, TextureChannel.Alpha);
|
||||
|
||||
if (sprites.Any(s => s.BlendMode != blendMode))
|
||||
throw new InvalidDataException("Smudges specify different blend modes. "
|
||||
+ "Try using different smudge types for smudges that use different blend modes.");
|
||||
|
||||
paletteReference = wr.Palette(Info.Palette);
|
||||
render = new TerrainSpriteLayer(w, wr, sheet, blendMode, w.Type != WorldType.Editor);
|
||||
render = new TerrainSpriteLayer(w, wr, emptySprite, blendMode, w.Type != WorldType.Editor);
|
||||
|
||||
// Add map smudges
|
||||
foreach (var kv in Info.InitialSmudges)
|
||||
|
||||
@@ -80,7 +80,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr)
|
||||
{
|
||||
worldRenderer = wr;
|
||||
spriteLayer = new TerrainSpriteLayer(world, wr, tileCache.Sheet, BlendMode.Alpha, world.Type != WorldType.Editor);
|
||||
var emptySprite = new Sprite(tileCache.Sheet, Rectangle.Empty, TextureChannel.Alpha);
|
||||
spriteLayer = new TerrainSpriteLayer(world, wr, emptySprite, BlendMode.Alpha, world.Type != WorldType.Editor);
|
||||
|
||||
foreach (var cell in map.AllCells)
|
||||
UpdateCell(cell);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.D2k.Traits
|
||||
@@ -51,7 +52,8 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
|
||||
void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr)
|
||||
{
|
||||
render = new TerrainSpriteLayer(w, wr, terrainRenderer.Sheet, BlendMode.Alpha, wr.World.Type != WorldType.Editor);
|
||||
var emptySprite = new Sprite(terrainRenderer.Sheet, Rectangle.Empty, TextureChannel.Alpha);
|
||||
render = new TerrainSpriteLayer(w, wr, emptySprite, BlendMode.Alpha, wr.World.Type != WorldType.Editor);
|
||||
paletteReference = wr.Palette(info.Palette);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user