Skip to content

Commit

Permalink
Add index buffer to TerrainSpriteLayer
Browse files Browse the repository at this point in the history
  • Loading branch information
PunkPun committed Aug 24, 2023
1 parent 8aaca89 commit 9dfe3b9
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 24 deletions.
6 changes: 4 additions & 2 deletions OpenRA.Game/Graphics/SpriteRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using OpenRA.Primitives;

namespace OpenRA.Graphics
Expand All @@ -19,6 +20,7 @@ public class SpriteRenderer : Renderer.IBatchRenderer
{
public const int SheetCount = 8;
static readonly string[] SheetIndexToTextureName = Exts.MakeArray(SheetCount, i => $"Texture{i}");
static readonly int UintSize = Marshal.SizeOf(typeof(uint));

readonly Renderer renderer;
readonly IShader shader;
Expand Down Expand Up @@ -171,7 +173,7 @@ internal void DrawSprite(Sprite s, float paletteTextureIndex, in float3 a, in fl
nv += 6;
}

public void DrawVertexBuffer(IVertexBuffer<Vertex> buffer, int start, int length, PrimitiveType type, IEnumerable<Sheet> sheets, BlendMode blendMode)
public void DrawVertexBuffer(IVertexBuffer<Vertex> buffer, IIndexBuffer indices, int start, int length, IEnumerable<Sheet> sheets, BlendMode blendMode)
{
var i = 0;
foreach (var s in sheets)
Expand All @@ -185,7 +187,7 @@ public void DrawVertexBuffer(IVertexBuffer<Vertex> buffer, int start, int length

renderer.Context.SetBlendMode(blendMode);
shader.PrepareRender();
renderer.DrawBatch(buffer, start, length, type);
renderer.DrawBatch(buffer, indices, length, UintSize * start);
renderer.Context.SetBlendMode(BlendMode.None);
}

Expand Down
58 changes: 40 additions & 18 deletions OpenRA.Game/Graphics/TerrainSpriteLayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ namespace OpenRA.Graphics
{
public sealed class TerrainSpriteLayer : IDisposable
{
static readonly int[] CornerVertexMap = { 0, 1, 2, 2, 3, 0 };
// PERF: we can reuse the IndexBuffer as all layers have the same size
static int indexBufferUsers = 0;
static IIndexBuffer indexBuffer = null;

public readonly BlendMode BlendMode;

Expand All @@ -28,7 +30,8 @@ public sealed class TerrainSpriteLayer : IDisposable
readonly Vertex[] vertices;
readonly bool[] ignoreTint;
readonly HashSet<int> dirtyRows = new();
readonly int rowStride;
readonly int indexRowStride;
readonly int vertexRowStride;
readonly bool restrictToBounds;

readonly WorldRenderer worldRenderer;
Expand All @@ -43,19 +46,32 @@ public TerrainSpriteLayer(World world, WorldRenderer wr, Sprite emptySprite, Ble
this.emptySprite = emptySprite;
sheets = new Sheet[SpriteRenderer.SheetCount];
BlendMode = blendMode;

map = world.Map;
rowStride = 6 * map.MapSize.X;

vertices = new Vertex[rowStride * map.MapSize.Y];
palettes = new PaletteReference[map.MapSize.X * map.MapSize.Y];
vertexRowStride = 4 * map.MapSize.X;
vertices = new Vertex[vertexRowStride * map.MapSize.Y];
vertexBuffer = Game.Renderer.Context.CreateVertexBuffer(vertices.Length);

indexRowStride = 6 * map.MapSize.X;
if (indexBuffer == null)
{
var indices = new uint[indexRowStride * map.MapSize.Y];
var cornerVertexMap = new uint[] { 0, 1, 2, 2, 3, 0 };
for (var i = 0; i < indices.Length; i++)
indices[i] = cornerVertexMap[i % 6] + (uint)(4 * (i / 6));

indexBuffer = Game.Renderer.Context.CreateIndexBuffer(indices.Length);
indexBuffer.SetData(indices, indices.Length);
}

indexBufferUsers++;

palettes = new PaletteReference[map.MapSize.X * map.MapSize.Y];
wr.PaletteInvalidated += UpdatePaletteIndices;

if (wr.TerrainLighting != null)
{
ignoreTint = new bool[rowStride * map.MapSize.Y];
ignoreTint = new bool[vertexRowStride * map.MapSize.Y];
wr.TerrainLighting.CellChanged += UpdateTint;
}
}
Expand All @@ -65,7 +81,7 @@ void UpdatePaletteIndices()
for (var i = 0; i < vertices.Length; i++)
{
var v = vertices[i];
var p = palettes[i / 6]?.TextureIndex ?? 0;
var p = palettes[i / 4]?.TextureIndex ?? 0;
vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, p, v.C, v.R, v.G, v.B, v.A);
}

Expand Down Expand Up @@ -97,10 +113,10 @@ public void Update(CPos cell, Sprite sprite, PaletteReference palette, float sca

void UpdateTint(MPos uv)
{
var offset = rowStride * uv.V + 6 * uv.U;
var offset = vertexRowStride * uv.V + 4 * uv.U;
if (ignoreTint[offset])
{
for (var i = 0; i < 6; i++)
for (var i = 0; i < 4; i++)
{
var v = vertices[offset + i];
vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, v.P, v.C, v.A * float3.Ones, v.A);
Expand All @@ -125,10 +141,10 @@ void UpdateTint(MPos uv)

// Apply tint directly to the underlying vertices
// This saves us from having to re-query the sprite information, which has not changed
for (var i = 0; i < 6; i++)
for (var i = 0; i < 4; i++)
{
var v = vertices[offset + i];
vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, v.P, v.C, v.A * weights[CornerVertexMap[i]], v.A);
vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, v.P, v.C, v.A * weights[i], v.A);
}

dirtyRows.Add(uv.V);
Expand Down Expand Up @@ -180,8 +196,8 @@ public void Update(MPos uv, Sprite sprite, PaletteReference palette, in float3 p
if (!map.Tiles.Contains(uv))
return;

var offset = rowStride * uv.V + 6 * uv.U;
Util.FastCreateQuad(vertices, pos, sprite, samplers, palette?.TextureIndex ?? 0, offset, scale * sprite.Size, alpha * float3.Ones, alpha);
var offset = vertexRowStride * uv.V + 4 * uv.U;
Util.FastCreateQuad(vertices, pos, sprite, samplers, palette?.TextureIndex ?? 0, offset, scale * sprite.Size, alpha * float3.Ones, alpha, vertex6: false);
palettes[uv.V * map.MapSize.X + uv.U] = palette;

if (worldRenderer.TerrainLighting != null)
Expand Down Expand Up @@ -209,13 +225,13 @@ public void Draw(Viewport viewport)
if (!dirtyRows.Remove(row))
continue;

var rowOffset = rowStride * row;
vertexBuffer.SetData(vertices, rowOffset, rowOffset, rowStride);
var rowOffset = vertexRowStride * row;
vertexBuffer.SetData(vertices, rowOffset, rowOffset, vertexRowStride);
}

Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer(
vertexBuffer, rowStride * firstRow, rowStride * (lastRow - firstRow),
PrimitiveType.TriangleList, sheets, BlendMode);
vertexBuffer, indexBuffer, indexRowStride * firstRow,
indexRowStride * (lastRow - firstRow), sheets, BlendMode);

Game.Renderer.Flush();
}
Expand All @@ -227,6 +243,12 @@ public void Dispose()
worldRenderer.TerrainLighting.CellChanged -= UpdateTint;

vertexBuffer.Dispose();
indexBufferUsers--;
if (indexBufferUsers == 0)
{
indexBuffer.Dispose();
indexBuffer = null;
}
}
}
}
27 changes: 23 additions & 4 deletions OpenRA.Game/Graphics/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static class Util
static readonly int[] ChannelMasks = { 2, 1, 0, 3 };

public static void FastCreateQuad(Vertex[] vertices, in float3 o, Sprite r, int2 samplers, float paletteTextureIndex, int nv,
in float3 size, in float3 tint, float alpha, float rotation = 0f)
in float3 size, in float3 tint, float alpha, float rotation = 0f, bool vertex6 = true)
{
float3 a, b, c, d;

Expand Down Expand Up @@ -57,13 +57,13 @@ public static class Util
d = new float3(o.X, o.Y + size.Y, o.Z + size.Z);
}

FastCreateQuad(vertices, a, b, c, d, r, samplers, paletteTextureIndex, tint, alpha, nv);
FastCreateQuad(vertices, a, b, c, d, r, samplers, paletteTextureIndex, tint, alpha, nv, vertex6);
}

public static void FastCreateQuad(Vertex[] vertices,
in float3 a, in float3 b, in float3 c, in float3 d,
Sprite r, int2 samplers, float paletteTextureIndex,
in float3 tint, float alpha, int nv)
in float3 tint, float alpha, int nv, bool vertex6 = true)
{
float sl = 0;
float st = 0;
Expand All @@ -84,7 +84,26 @@ public static class Util
attribC |= samplers.Y << 9;
}

var fAttribC = (float)attribC;
if (vertex6)
FastCreateQuad6Vertex(vertices, r, paletteTextureIndex, nv, a, b, c, d, sl, st, sr, sb, attribC, tint, alpha);
else
FastCreateQuad4Vertex(vertices, r, paletteTextureIndex, nv, a, b, c, d, sl, st, sr, sb, attribC, tint, alpha);
}

public static void FastCreateQuad4Vertex(Vertex[] vertices, Sprite r, float paletteTextureIndex, int nv,
in float3 a, in float3 b, in float3 c, in float3 d, in float sl, in float st, in float sr, in float sb,
in float fAttribC, in float3 tint, float alpha)
{
vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint, alpha);
vertices[nv + 1] = new Vertex(b, r.Right, r.Top, sr, st, paletteTextureIndex, fAttribC, tint, alpha);
vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC, tint, alpha);
vertices[nv + 3] = new Vertex(d, r.Left, r.Bottom, sl, sb, paletteTextureIndex, fAttribC, tint, alpha);
}

public static void FastCreateQuad6Vertex(Vertex[] vertices, Sprite r, float paletteTextureIndex, int nv,
in float3 a, in float3 b, in float3 c, in float3 d, in float sl, in float st, in float sr, in float sb,
in float fAttribC, in float3 tint, float alpha)
{
vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint, alpha);
vertices[nv + 1] = new Vertex(b, r.Right, r.Top, sr, st, paletteTextureIndex, fAttribC, tint, alpha);
vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC, tint, alpha);
Expand Down

0 comments on commit 9dfe3b9

Please sign in to comment.