diff --git a/Robust.Client/Graphics/Clyde/Clyde.Constants.cs b/Robust.Client/Graphics/Clyde/Clyde.Constants.cs
index 41c49c0e8..94b1fe3ac 100644
--- a/Robust.Client/Graphics/Clyde/Clyde.Constants.cs
+++ b/Robust.Client/Graphics/Clyde/Clyde.Constants.cs
@@ -5,20 +5,19 @@ namespace Robust.Client.Graphics.Clyde
private static readonly (string, uint)[] BaseShaderAttribLocations =
{
("aPos", 0),
- ("tCoord", 1)
+ ("tCoord", 1),
+ ("modulate", 2)
};
private const int UniIModUV = 0;
private const int UniIModelMatrix = 1;
- private const int UniIModulate = 2;
- private const int UniITexturePixelSize = 3;
- private const int UniIMainTexture = 4;
- private const int UniILightTexture = 5;
- private const int UniCount = 6;
+ private const int UniITexturePixelSize = 2;
+ private const int UniIMainTexture = 3;
+ private const int UniILightTexture = 4;
+ private const int UniCount = 5;
private const string UniModUV = "modifyUV";
private const string UniModelMatrix = "modelMatrix";
- private const string UniModulate = "modulate";
private const string UniTexturePixelSize = "TEXTURE_PIXEL_SIZE";
private const string UniMainTexture = "TEXTURE";
private const string UniLightTexture = "lightMap";
diff --git a/Robust.Client/Graphics/Clyde/Clyde.GridRendering.cs b/Robust.Client/Graphics/Clyde/Clyde.GridRendering.cs
index b2dd5eab7..e4f3b67c4 100644
--- a/Robust.Client/Graphics/Clyde/Clyde.GridRendering.cs
+++ b/Robust.Client/Graphics/Clyde/Clyde.GridRendering.cs
@@ -37,7 +37,6 @@ namespace Robust.Client.Graphics.Clyde
gridProgram.SetUniformTextureMaybe(UniIMainTexture, TextureUnit.Texture0);
gridProgram.SetUniformTextureMaybe(UniILightTexture, TextureUnit.Texture1);
gridProgram.SetUniform(UniIModUV, new Vector4(0, 0, 1, 1));
- gridProgram.SetUniform(UniIModulate, Color.White);
foreach (var mapGrid in _mapManager.FindGridsIntersecting(mapId, worldBounds))
{
@@ -115,10 +114,10 @@ namespace Robust.Client.Graphics.Clyde
var gy = y + cScaled.Y;
var vIdx = i * 4;
- vertexBuffer[vIdx + 0] = new Vertex2D(gx, gy, region.Left, region.Bottom);
- vertexBuffer[vIdx + 1] = new Vertex2D(gx + 1, gy, region.Right, region.Bottom);
- vertexBuffer[vIdx + 2] = new Vertex2D(gx + 1, gy + 1, region.Right, region.Top);
- vertexBuffer[vIdx + 3] = new Vertex2D(gx, gy + 1, region.Left, region.Top);
+ vertexBuffer[vIdx + 0] = new Vertex2D(gx, gy, region.Left, region.Bottom, Color.White);
+ vertexBuffer[vIdx + 1] = new Vertex2D(gx + 1, gy, region.Right, region.Bottom, Color.White);
+ vertexBuffer[vIdx + 2] = new Vertex2D(gx + 1, gy + 1, region.Right, region.Top, Color.White);
+ vertexBuffer[vIdx + 3] = new Vertex2D(gx, gy + 1, region.Left, region.Top, Color.White);
var nIdx = i * GetQuadBatchIndexCount();
var tIdx = (ushort)(i * 4);
QuadBatchIndexWrite(indexBuffer, ref nIdx, tIdx);
@@ -151,12 +150,7 @@ namespace Robust.Client.Graphics.Clyde
eboSize, $"Grid {grid.Index} chunk {chunk.Indices} EBO");
ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, vao, $"Grid {grid.Index} chunk {chunk.Indices} VAO");
- // Vertex Coords
- GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0);
- GL.EnableVertexAttribArray(0);
- // Texture Coords.
- GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float));
- GL.EnableVertexAttribArray(1);
+ SetupVAOLayout();
CheckGlError();
// Assign VBO and EBO to VAO.
diff --git a/Robust.Client/Graphics/Clyde/Clyde.Layout.cs b/Robust.Client/Graphics/Clyde/Clyde.Layout.cs
index 8c5c36299..0b9f43004 100644
--- a/Robust.Client/Graphics/Clyde/Clyde.Layout.cs
+++ b/Robust.Client/Graphics/Clyde/Clyde.Layout.cs
@@ -1,3 +1,4 @@
+using OpenToolkit.Graphics.OpenGL4;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using JetBrains.Annotations;
@@ -8,6 +9,26 @@ namespace Robust.Client.Graphics.Clyde
// Contains various layout/rendering structs used inside Clyde.
internal partial class Clyde
{
+ ///
+ /// Sets up VAO layout for Vertex2D for base and raw shader types.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void SetupVAOLayout()
+ {
+ // Vertex Coords
+ GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0);
+ GL.EnableVertexAttribArray(0);
+ // Texture Coords.
+ GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float));
+ GL.EnableVertexAttribArray(1);
+ // Colour Modulation.
+ GL.VertexAttribPointer(2, 4, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 4 * sizeof(float));
+ GL.EnableVertexAttribArray(2);
+ }
+
+ // NOTE: This is:
+ // + Directly cast from DrawVertexUV2DColor!!!
+ // + GLContextWindow does it's own thing with this for winblit, be careful!
[StructLayout(LayoutKind.Sequential)]
[PublicAPI]
private readonly struct Vertex2D
@@ -16,6 +37,8 @@ namespace Robust.Client.Graphics.Clyde
public readonly Vector2 Position;
public readonly Vector2 TextureCoordinates;
+ // Note that this color is in linear space.
+ public readonly Color Modulate;
static Vertex2D()
{
@@ -26,27 +49,34 @@ namespace Robust.Client.Graphics.Clyde
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vertex2D(Vector2 position, Vector2 textureCoordinates)
+ public Vertex2D(Vector2 position, Vector2 textureCoordinates, Color modulate)
{
Position = position;
TextureCoordinates = textureCoordinates;
+ Modulate = modulate;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vertex2D(float x, float y, float u, float v)
- : this(new Vector2(x, y), new Vector2(u, v))
+ public Vertex2D(float x, float y, float u, float v, float r, float g, float b, float a)
+ : this(new Vector2(x, y), new Vector2(u, v), new Color(r, g, b, a))
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vertex2D(Vector2 position, float u, float v)
- : this(position, new Vector2(u, v))
+ public Vertex2D(float x, float y, float u, float v, Color modulate)
+ : this(new Vector2(x, y), new Vector2(u, v), modulate)
+ {
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vertex2D(Vector2 position, float u, float v, Color modulate)
+ : this(position, new Vector2(u, v), modulate)
{
}
public override string ToString()
{
- return $"Vertex2D: {Position}, {TextureCoordinates}";
+ return $"Vertex2D: {Position}, {TextureCoordinates}, {Modulate}";
}
}
diff --git a/Robust.Client/Graphics/Clyde/Clyde.RenderHandle.cs b/Robust.Client/Graphics/Clyde/Clyde.RenderHandle.cs
index 9c4b14f85..b1f588d7f 100644
--- a/Robust.Client/Graphics/Clyde/Clyde.RenderHandle.cs
+++ b/Robust.Client/Graphics/Clyde/Clyde.RenderHandle.cs
@@ -208,60 +208,34 @@ namespace Robust.Client.Graphics.Clyde
_clyde.DrawClear(color);
}
- public void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, ReadOnlySpan vertices,
- Color color)
- {
- // TODO: Maybe don't stackalloc if the data is too large.
- Span drawVertices = stackalloc DrawVertexUV2D[vertices.Length];
- PadVertices(vertices, drawVertices);
-
- DrawPrimitives(primitiveTopology, Texture.White, drawVertices, color);
- }
-
- public void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, ReadOnlySpan indices,
- ReadOnlySpan vertices, Color color)
- {
- // TODO: Maybe don't stackalloc if the data is too large.
- Span drawVertices = stackalloc DrawVertexUV2D[vertices.Length];
- PadVertices(vertices, drawVertices);
-
- DrawPrimitives(primitiveTopology, Texture.White, indices, drawVertices, color);
- }
-
public void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
- ReadOnlySpan vertices, Color color)
+ ReadOnlySpan vertices)
{
if (!(texture is ClydeTexture clydeTexture))
{
throw new ArgumentException("Texture must be a basic texture.");
}
- var castSpan = MemoryMarshal.Cast(vertices);
+ var castSpan = MemoryMarshal.Cast(vertices);
- _clyde.DrawPrimitives(primitiveTopology, clydeTexture.TextureId, castSpan, color);
+ _clyde.DrawPrimitives(primitiveTopology, clydeTexture.TextureId, castSpan);
}
public void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
ReadOnlySpan indices,
- ReadOnlySpan vertices, Color color)
+ ReadOnlySpan vertices)
{
if (!(texture is ClydeTexture clydeTexture))
{
throw new ArgumentException("Texture must be a basic texture.");
}
- var castSpan = MemoryMarshal.Cast(vertices);
+ var castSpan = MemoryMarshal.Cast(vertices);
- _clyde.DrawPrimitives(primitiveTopology, clydeTexture.TextureId, indices, castSpan, color);
+ _clyde.DrawPrimitives(primitiveTopology, clydeTexture.TextureId, indices, castSpan);
}
- private void PadVertices(ReadOnlySpan input, Span output)
- {
- for (var i = 0; i < output.Length; i++)
- {
- output[i] = new DrawVertexUV2D(input[i], (0.5f, 0.5f));
- }
- }
+ // ---- (end) ----
private sealed class DrawingHandleScreenImpl : DrawingHandleScreen
{
@@ -282,38 +256,16 @@ namespace Robust.Client.Graphics.Clyde
_renderHandle.UseShader(shader);
}
- public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology,
- ReadOnlySpan vertices,
- Color color)
+ public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
+ ReadOnlySpan vertices)
{
- var realColor = color * Modulate;
-
- _renderHandle.DrawPrimitives(primitiveTopology, vertices, realColor);
- }
-
- public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology,
- ReadOnlySpan indices,
- ReadOnlySpan vertices, Color color)
- {
- var realColor = color * Modulate;
-
- _renderHandle.DrawPrimitives(primitiveTopology, indices, vertices, realColor);
+ _renderHandle.DrawPrimitives(primitiveTopology, texture, vertices);
}
public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
- ReadOnlySpan vertices, Color? color = null)
+ ReadOnlySpan indices, ReadOnlySpan vertices)
{
- var realColor = (color ?? Color.White) * Modulate;
-
- _renderHandle.DrawPrimitives(primitiveTopology, texture, vertices, realColor);
- }
-
- public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
- ReadOnlySpan indices, ReadOnlySpan vertices, Color? color = null)
- {
- var realColor = (color ?? Color.White) * Modulate;
-
- _renderHandle.DrawPrimitives(primitiveTopology, texture, indices, vertices, realColor);
+ _renderHandle.DrawPrimitives(primitiveTopology, texture, indices, vertices);
}
public override void DrawLine(Vector2 from, Vector2 to, Color color)
@@ -379,7 +331,16 @@ namespace Robust.Client.Graphics.Clyde
int divisions = Math.Max(16,(int)(radius * 16));
float arcLength = MathF.PI * 2 / divisions;
- Span filledTriangle = stackalloc Vector2[3];
+ var colorReal = color * Modulate;
+
+ if (filled)
+ {
+ // Unfilled (using _renderHandle.DrawLine) does the linear conversion internally.
+ // Filled meanwhile uses DrawPrimitives, so has to do it here.
+ colorReal = Color.FromSrgb(color);
+ }
+
+ Span filledTriangle = stackalloc DrawVertexUV2DColor[3];
// Draws a "circle", but its just a polygon with a bunch of sides
// this is the GL_LINES version, not GL_LINE_STRIP
@@ -389,14 +350,14 @@ namespace Robust.Client.Graphics.Clyde
var endPos = new Vector2(MathF.Cos(arcLength * (i+1)) * radius, MathF.Sin(arcLength * (i + 1)) * radius);
if(!filled)
- _renderHandle.DrawLine(startPos, endPos, color);
+ _renderHandle.DrawLine(startPos, endPos, colorReal);
else
{
- filledTriangle[0] = startPos + position;
- filledTriangle[1] = endPos + position;
- filledTriangle[2] = Vector2.Zero + position;
+ filledTriangle[0] = new DrawVertexUV2DColor(startPos + position, colorReal);
+ filledTriangle[1] = new DrawVertexUV2DColor(endPos + position, colorReal);
+ filledTriangle[2] = new DrawVertexUV2DColor(position, colorReal);
- _renderHandle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, filledTriangle, color);
+ _renderHandle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, Texture.White, filledTriangle);
}
}
}
@@ -477,38 +438,16 @@ namespace Robust.Client.Graphics.Clyde
quad.TopLeft, quad.TopRight, color, in subRegion);
}
- public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology,
- ReadOnlySpan vertices,
- Color color)
+ public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
+ ReadOnlySpan vertices)
{
- var realColor = color * Modulate;
-
- _renderHandle.DrawPrimitives(primitiveTopology, vertices, realColor);
- }
-
- public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology,
- ReadOnlySpan indices,
- ReadOnlySpan vertices, Color color)
- {
- var realColor = color * Modulate;
-
- _renderHandle.DrawPrimitives(primitiveTopology, indices, vertices, realColor);
+ _renderHandle.DrawPrimitives(primitiveTopology, texture, vertices);
}
public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
- ReadOnlySpan vertices, Color? color = null)
+ ReadOnlySpan indices, ReadOnlySpan vertices)
{
- var realColor = (color ?? Color.White) * Modulate;
-
- _renderHandle.DrawPrimitives(primitiveTopology, texture, vertices, realColor);
- }
-
- public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
- ReadOnlySpan indices, ReadOnlySpan vertices, Color? color = null)
- {
- var realColor = (color ?? Color.White) * Modulate;
-
- _renderHandle.DrawPrimitives(primitiveTopology, texture, indices, vertices, realColor);
+ _renderHandle.DrawPrimitives(primitiveTopology, texture, indices, vertices);
}
}
}
diff --git a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs
index f12dc4911..2b63523e8 100644
--- a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs
+++ b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs
@@ -239,7 +239,6 @@ namespace Robust.Client.Graphics.Clyde
// Reset ModUV to ensure it's identity and doesn't touch anything.
program.SetUniformMaybe(UniIModUV, new Vector4(0, 0, 1, 1));
- program.SetUniformMaybe(UniIModulate, command.Modulate);
program.SetUniformMaybe(UniITexturePixelSize, Vector2.One / loadedTexture.Size);
var primitiveType = MapPrimitiveType(command.PrimitiveType);
@@ -529,25 +528,27 @@ namespace Robust.Client.Graphics.Clyde
/// Bottom right vertex of the quad in object space.
/// Top left vertex of the quad in object space.
/// Top right vertex of the quad in object space.
- /// A color to multiply the texture by when shading.
+ /// A color to multiply the texture by when shading. Non-linear.
/// The four corners of the texture coordinates, matching the four vertices.
private void DrawTexture(ClydeHandle texture, Vector2 bl, Vector2 br, Vector2 tl, Vector2 tr, in Color modulate,
in Box2 texCoords)
{
EnsureBatchSpaceAvailable(4, GetQuadBatchIndexCount());
- EnsureBatchState(texture, in modulate, true, GetQuadBatchPrimitiveType(), _queuedShader);
+ EnsureBatchState(texture, true, GetQuadBatchPrimitiveType(), _queuedShader);
bl = _currentMatrixModel.Transform(bl);
br = _currentMatrixModel.Transform(br);
tr = _currentMatrixModel.Transform(tr);
tl = _currentMatrixModel.Transform(tl);
+ var modulateLinear = Color.FromSrgb(modulate);
+
// TODO: split batch if necessary.
var vIdx = BatchVertexIndex;
- BatchVertexData[vIdx + 0] = new Vertex2D(bl, texCoords.BottomLeft);
- BatchVertexData[vIdx + 1] = new Vertex2D(br, texCoords.BottomRight);
- BatchVertexData[vIdx + 2] = new Vertex2D(tr, texCoords.TopRight);
- BatchVertexData[vIdx + 3] = new Vertex2D(tl, texCoords.TopLeft);
+ BatchVertexData[vIdx + 0] = new Vertex2D(bl, texCoords.BottomLeft, modulateLinear);
+ BatchVertexData[vIdx + 1] = new Vertex2D(br, texCoords.BottomRight, modulateLinear);
+ BatchVertexData[vIdx + 2] = new Vertex2D(tr, texCoords.TopRight, modulateLinear);
+ BatchVertexData[vIdx + 3] = new Vertex2D(tl, texCoords.TopLeft, modulateLinear);
BatchVertexIndex += 4;
QuadBatchIndexWrite(BatchIndexData, ref BatchIndexIndex, (ushort) vIdx);
@@ -555,7 +556,7 @@ namespace Robust.Client.Graphics.Clyde
}
private void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, ClydeHandle textureId,
- ReadOnlySpan indices, ReadOnlySpan vertices, in Color color)
+ ReadOnlySpan indices, ReadOnlySpan vertices)
{
FinishBatch();
_batchMetaData = null;
@@ -585,7 +586,6 @@ namespace Robust.Client.Graphics.Clyde
command.DrawBatch.Indexed = true;
command.DrawBatch.StartIndex = BatchIndexIndex;
command.DrawBatch.PrimitiveType = MapDrawToBatchPrimitiveType(primitiveTopology);
- command.DrawBatch.Modulate = color;
command.DrawBatch.TextureId = textureId;
command.DrawBatch.ShaderInstance = _queuedShader;
@@ -598,7 +598,7 @@ namespace Robust.Client.Graphics.Clyde
}
private void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, ClydeHandle textureId,
- in ReadOnlySpan vertices, in Color color)
+ in ReadOnlySpan vertices)
{
FinishBatch();
_batchMetaData = null;
@@ -612,7 +612,6 @@ namespace Robust.Client.Graphics.Clyde
command.DrawBatch.Indexed = false;
command.DrawBatch.StartIndex = BatchVertexIndex;
command.DrawBatch.PrimitiveType = MapDrawToBatchPrimitiveType(primitiveTopology);
- command.DrawBatch.Modulate = color;
command.DrawBatch.TextureId = textureId;
command.DrawBatch.ShaderInstance = _queuedShader;
@@ -641,15 +640,17 @@ namespace Robust.Client.Graphics.Clyde
private void DrawLine(Vector2 a, Vector2 b, Color color)
{
EnsureBatchSpaceAvailable(2, 0);
- EnsureBatchState(_stockTextureWhite.TextureId, color, false, BatchPrimitiveType.LineList, _queuedShader);
+ EnsureBatchState(_stockTextureWhite.TextureId, false, BatchPrimitiveType.LineList, _queuedShader);
a = _currentMatrixModel.Transform(a);
b = _currentMatrixModel.Transform(b);
+ var colorLinear = Color.FromSrgb(color);
+
// TODO: split batch if necessary.
var vIdx = BatchVertexIndex;
- BatchVertexData[vIdx + 0] = new Vertex2D(a, Vector2.Zero);
- BatchVertexData[vIdx + 1] = new Vertex2D(b, Vector2.Zero);
+ BatchVertexData[vIdx + 0] = new Vertex2D(a, Vector2.Zero, colorLinear);
+ BatchVertexData[vIdx + 1] = new Vertex2D(b, Vector2.Zero, colorLinear);
BatchVertexIndex += 2;
_debugStats.LastClydeDrawCalls += 1;
@@ -716,14 +717,13 @@ namespace Robust.Client.Graphics.Clyde
/// Ensures that batching metadata matches the current batch.
/// If not, the current batch is finished and a new one is started.
///
- private void EnsureBatchState(ClydeHandle textureId, in Color color, bool indexed,
+ private void EnsureBatchState(ClydeHandle textureId, bool indexed,
BatchPrimitiveType primitiveType, ClydeHandle shaderInstance)
{
if (_batchMetaData.HasValue)
{
var metaData = _batchMetaData.Value;
if (metaData.TextureId == textureId &&
- StrictColorEquality(metaData.Color, color) &&
indexed == metaData.Indexed &&
metaData.PrimitiveType == primitiveType &&
metaData.ShaderInstance == shaderInstance)
@@ -737,7 +737,7 @@ namespace Robust.Client.Graphics.Clyde
}
// ... and start another.
- _batchMetaData = new BatchMetaData(textureId, color, indexed, primitiveType,
+ _batchMetaData = new BatchMetaData(textureId, indexed, primitiveType,
indexed ? BatchIndexIndex : BatchVertexIndex, shaderInstance);
/*
@@ -769,7 +769,6 @@ namespace Robust.Client.Graphics.Clyde
command.DrawBatch.Indexed = indexed;
command.DrawBatch.StartIndex = metaData.StartIndex;
command.DrawBatch.PrimitiveType = metaData.PrimitiveType;
- command.DrawBatch.Modulate = metaData.Color;
command.DrawBatch.TextureId = metaData.TextureId;
command.DrawBatch.ShaderInstance = metaData.ShaderInstance;
@@ -898,7 +897,6 @@ namespace Robust.Client.Graphics.Clyde
{
public ClydeHandle TextureId;
public ClydeHandle ShaderInstance;
- public Color Modulate;
public int StartIndex;
public int Count;
@@ -970,17 +968,15 @@ namespace Robust.Client.Graphics.Clyde
private readonly struct BatchMetaData
{
public readonly ClydeHandle TextureId;
- public readonly Color Color;
public readonly bool Indexed;
public readonly BatchPrimitiveType PrimitiveType;
public readonly int StartIndex;
public readonly ClydeHandle ShaderInstance;
- public BatchMetaData(ClydeHandle textureId, in Color color, bool indexed, BatchPrimitiveType primitiveType,
+ public BatchMetaData(ClydeHandle textureId, bool indexed, BatchPrimitiveType primitiveType,
int startIndex, ClydeHandle shaderInstance)
{
TextureId = textureId;
- Color = color;
Indexed = indexed;
PrimitiveType = primitiveType;
StartIndex = startIndex;
diff --git a/Robust.Client/Graphics/Clyde/Clyde.cs b/Robust.Client/Graphics/Clyde/Clyde.cs
index 89bec6a54..a3a673312 100644
--- a/Robust.Client/Graphics/Clyde/Clyde.cs
+++ b/Robust.Client/Graphics/Clyde/Clyde.cs
@@ -14,6 +14,7 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
+using Robust.Shared.Maths;
using Robust.Shared.Profiling;
using Robust.Shared.Timing;
using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute;
@@ -275,10 +276,10 @@ namespace Robust.Client.Graphics.Clyde
{
Span quadVertices = stackalloc[]
{
- new Vertex2D(1, 0, 1, 1),
- new Vertex2D(0, 0, 0, 1),
- new Vertex2D(1, 1, 1, 0),
- new Vertex2D(0, 1, 0, 0)
+ new Vertex2D(1, 0, 1, 1, Color.White),
+ new Vertex2D(0, 0, 0, 1, Color.White),
+ new Vertex2D(1, 1, 1, 0, Color.White),
+ new Vertex2D(0, 1, 0, 0, Color.White)
};
QuadVBO = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw,
@@ -294,10 +295,10 @@ namespace Robust.Client.Graphics.Clyde
{
Span winVertices = stackalloc[]
{
- new Vertex2D(-1, 1, 0, 1),
- new Vertex2D(-1, -1, 0, 0),
- new Vertex2D(1, 1, 1, 1),
- new Vertex2D(1, -1, 1, 0),
+ new Vertex2D(-1, 1, 0, 1, Color.White),
+ new Vertex2D(-1, -1, 0, 0, Color.White),
+ new Vertex2D(1, 1, 1, 1, Color.White),
+ new Vertex2D(1, -1, 1, 0, Color.White),
};
WindowVBO = new GLBuffer(
@@ -318,12 +319,7 @@ namespace Robust.Client.Graphics.Clyde
BatchVAO = new GLHandle(GenVertexArray());
BindVertexArray(BatchVAO.Handle);
ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, BatchVAO, nameof(BatchVAO));
- // Vertex Coords
- GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0);
- GL.EnableVertexAttribArray(0);
- // Texture Coords.
- GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float));
- GL.EnableVertexAttribArray(1);
+ SetupVAOLayout();
CheckGlError();
@@ -347,12 +343,7 @@ namespace Robust.Client.Graphics.Clyde
BindVertexArray(vao.Handle);
ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, vao, nameof(QuadVAO));
GL.BindBuffer(BufferTarget.ArrayBuffer, QuadVBO.ObjectHandle);
- // Vertex Coords
- GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0);
- GL.EnableVertexAttribArray(0);
- // Texture Coords.
- GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float));
- GL.EnableVertexAttribArray(1);
+ SetupVAOLayout();
return vao;
}
diff --git a/Robust.Client/Graphics/Clyde/GLObjects/Clyde.ShaderProgram.cs b/Robust.Client/Graphics/Clyde/GLObjects/Clyde.ShaderProgram.cs
index 158c6a8f9..8ad90a14b 100644
--- a/Robust.Client/Graphics/Clyde/GLObjects/Clyde.ShaderProgram.cs
+++ b/Robust.Client/Graphics/Clyde/GLObjects/Clyde.ShaderProgram.cs
@@ -178,9 +178,6 @@ namespace Robust.Client.Graphics.Clyde
case UniIModUV:
name = UniModUV;
break;
- case UniIModulate:
- name = UniModulate;
- break;
case UniILightTexture:
name = UniLightTexture;
break;
diff --git a/Robust.Client/Graphics/Clyde/Shaders/base-default.frag b/Robust.Client/Graphics/Clyde/Shaders/base-default.frag
index 1c5eda2e4..b50f73bfc 100644
--- a/Robust.Client/Graphics/Clyde/Shaders/base-default.frag
+++ b/Robust.Client/Graphics/Clyde/Shaders/base-default.frag
@@ -1,8 +1,8 @@
varying highp vec2 UV;
varying highp vec2 Pos;
+varying highp vec4 VtxModulate;
uniform sampler2D lightMap;
-uniform highp vec4 modulate;
// [SHADER_HEADER_CODE]
@@ -16,5 +16,5 @@ void main()
lowp vec3 lightSample = texture2D(lightMap, Pos).rgb;
- gl_FragColor = zAdjustResult(COLOR * modulate * vec4(lightSample, 1.0));
+ gl_FragColor = zAdjustResult(COLOR * VtxModulate * vec4(lightSample, 1.0));
}
diff --git a/Robust.Client/Graphics/Clyde/Shaders/base-default.vert b/Robust.Client/Graphics/Clyde/Shaders/base-default.vert
index a3d42c6df..2e137329f 100644
--- a/Robust.Client/Graphics/Clyde/Shaders/base-default.vert
+++ b/Robust.Client/Graphics/Clyde/Shaders/base-default.vert
@@ -2,9 +2,12 @@
/*layout (location = 0)*/ attribute vec2 aPos;
// Texture coordinates.
/*layout (location = 1)*/ attribute vec2 tCoord;
+// Colour modulation.
+/*layout (location = 2)*/ attribute vec4 modulate;
varying vec2 UV;
varying vec2 Pos;
+varying vec4 VtxModulate;
// Maybe we should merge these CPU side.
// idk yet.
@@ -33,4 +36,5 @@ void main()
gl_Position = vec4(VERTEX, 0.0, 1.0);
Pos = (VERTEX + 1.0) / 2.0;
UV = mix(modifyUV.xy, modifyUV.zw, tCoord);
+ VtxModulate = modulate;
}
diff --git a/Robust.Client/Graphics/Clyde/Shaders/base-raw.frag b/Robust.Client/Graphics/Clyde/Shaders/base-raw.frag
index 1340e10b6..e72eaeebb 100644
--- a/Robust.Client/Graphics/Clyde/Shaders/base-raw.frag
+++ b/Robust.Client/Graphics/Clyde/Shaders/base-raw.frag
@@ -1,7 +1,6 @@
varying highp vec2 UV;
uniform sampler2D lightMap;
-uniform highp vec4 modulate;
// [SHADER_HEADER_CODE]
@@ -13,5 +12,7 @@ void main()
// [SHADER_CODE]
+ // NOTE: You may want to add modulation here. Problem: Game doesn't like that.
+ // In particular, walls disappear.
gl_FragColor = zAdjustResult(COLOR);
}
diff --git a/Robust.Client/Graphics/Clyde/Shaders/base-raw.vert b/Robust.Client/Graphics/Clyde/Shaders/base-raw.vert
index 05105ad66..e5b8cf27f 100644
--- a/Robust.Client/Graphics/Clyde/Shaders/base-raw.vert
+++ b/Robust.Client/Graphics/Clyde/Shaders/base-raw.vert
@@ -2,6 +2,8 @@
/*layout (location = 0)*/ attribute vec2 aPos;
// Texture coordinates.
/*layout (location = 1)*/ attribute vec2 tCoord;
+// Colour modulation.
+/*layout (location = 2)*/ attribute vec4 modulate;
varying vec2 UV;
diff --git a/Robust.Client/Graphics/Drawing/DrawingHandleBase.cs b/Robust.Client/Graphics/Drawing/DrawingHandleBase.cs
index 5dd582752..7037cc8f6 100644
--- a/Robust.Client/Graphics/Drawing/DrawingHandleBase.cs
+++ b/Robust.Client/Graphics/Drawing/DrawingHandleBase.cs
@@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using Robust.Shared.Maths;
namespace Robust.Client.Graphics
@@ -12,6 +14,15 @@ namespace Robust.Client.Graphics
//private protected IRenderHandle _renderHandle;
private protected readonly int _handleId;
public bool Disposed { get; private set; }
+ ///
+ /// Drawing commands that do NOT receive per-vertex modulation get modulated by this.
+ /// Specifically, *DrawPrimitives w/ DrawVertexUV2DColor IS NOT AFFECTED BY THIS*.
+ /// The only code that should ever be setting this is UserInterfaceManager.
+ /// It's absolutely evil statefulness.
+ /// I understand it's existence and operation.
+ /// I understand that removing it would require rewriting all the UI controls everywhere.
+ /// I still wish it a prolonged death - it's a performance nightmare. - 20kdc
+ ///
public Color Modulate { get; set; } = Color.White;
public void Dispose()
@@ -37,14 +48,25 @@ namespace Robust.Client.Graphics
public abstract void UseShader(ShaderInstance? shader);
+ // ---- DrawPrimitives: Vector2 API ----
+
///
/// Draws arbitrary geometry primitives with a flat color.
///
/// The topology of the primitives to draw.
/// The set of vertices to render.
/// The color to draw with.
- public abstract void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, ReadOnlySpan vertices,
- Color color);
+ public void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, ReadOnlySpan vertices,
+ Color color)
+ {
+ var realColor = color * Modulate;
+
+ // TODO: Maybe don't stackalloc if the data is too large.
+ Span drawVertices = stackalloc DrawVertexUV2DColor[vertices.Length];
+ PadVerticesV2(vertices, drawVertices, realColor);
+
+ DrawPrimitives(primitiveTopology, Texture.White, drawVertices);
+ }
///
/// Draws arbitrary indexed geometry primitives with a flat color.
@@ -53,8 +75,28 @@ namespace Robust.Client.Graphics
/// The indices into to render.
/// The set of vertices to render.
/// The color to draw with.
- public abstract void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, ReadOnlySpan indices,
- ReadOnlySpan vertices, Color color);
+ public void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, ReadOnlySpan indices,
+ ReadOnlySpan vertices, Color color)
+ {
+ var realColor = color * Modulate;
+
+ // TODO: Maybe don't stackalloc if the data is too large.
+ Span drawVertices = stackalloc DrawVertexUV2DColor[vertices.Length];
+ PadVerticesV2(vertices, drawVertices, realColor);
+
+ DrawPrimitives(primitiveTopology, Texture.White, indices, drawVertices);
+ }
+
+ private void PadVerticesV2(ReadOnlySpan input, Span output, Color color)
+ {
+ Color colorLinear = Color.FromSrgb(color);
+ for (var i = 0; i < output.Length; i++)
+ {
+ output[i] = new DrawVertexUV2DColor(input[i], (0.5f, 0.5f), colorLinear);
+ }
+ }
+
+ // ---- DrawPrimitives: DrawVertexUV2D API ----
///
/// Draws arbitrary geometry primitives with a texture.
@@ -63,20 +105,70 @@ namespace Robust.Client.Graphics
/// The texture to render with.
/// The set of vertices to render.
/// The color to draw with.
+ public void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture, ReadOnlySpan vertices,
+ Color? color = null)
+ {
+ var realColor = (color ?? Color.White) * Modulate;
+
+ // TODO: Maybe don't stackalloc if the data is too large.
+ Span drawVertices = stackalloc DrawVertexUV2DColor[vertices.Length];
+ PadVerticesUV(vertices, drawVertices, realColor);
+
+ DrawPrimitives(primitiveTopology, texture, drawVertices);
+ }
+
+ ///
+ /// Draws arbitrary geometry primitives with a texture.
+ ///
+ /// The topology of the primitives to draw.
+ /// The texture to render with.
+ /// The set of vertices to render.
+ /// The indices into to render.
+ /// The color to draw with.
+ public void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture, ReadOnlySpan indices,
+ ReadOnlySpan vertices, Color? color = null)
+ {
+ var realColor = (color ?? Color.White) * Modulate;
+
+ // TODO: Maybe don't stackalloc if the data is too large.
+ Span drawVertices = stackalloc DrawVertexUV2DColor[vertices.Length];
+ PadVerticesUV(vertices, drawVertices, realColor);
+
+ DrawPrimitives(primitiveTopology, texture, indices, drawVertices);
+ }
+
+ private void PadVerticesUV(ReadOnlySpan input, Span output, Color color)
+ {
+ Color colorLinear = Color.FromSrgb(color);
+ for (var i = 0; i < output.Length; i++)
+ {
+ output[i] = new DrawVertexUV2DColor(input[i], colorLinear);
+ }
+ }
+
+ // ---- End wrappers ----
+
+ ///
+ /// Draws arbitrary geometry primitives with a texture.
+ /// Be aware that this ignores the Modulate property! Apply it yourself if necessary.
+ ///
+ /// The topology of the primitives to draw.
+ /// The texture to render with.
+ /// The set of vertices to render.
public abstract void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
- ReadOnlySpan vertices, Color? color = null);
+ ReadOnlySpan vertices);
///
/// Draws arbitrary geometry primitives with a flat color.
+ /// Be aware that this ignores the Modulate property! Apply it yourself if necessary.
///
/// The topology of the primitives to draw.
/// The texture to render with.
/// The indices into to render.
/// The set of vertices to render.
- /// The color to draw with.
public abstract void DrawPrimitives(DrawPrimitiveTopology primitiveTopology, Texture texture,
ReadOnlySpan indices,
- ReadOnlySpan vertices, Color? color = null);
+ ReadOnlySpan vertices);
[DebuggerStepThrough]
protected void CheckDisposed()
@@ -108,4 +200,51 @@ namespace Robust.Client.Graphics
UV = uv;
}
}
+
+ ///
+ /// 2D Vertex that contains position and UV coordinates, and a modulation colour (Linear!!!)
+ /// NOTE: This is directly cast into Clyde Vertex2D!!!!
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct DrawVertexUV2DColor
+ {
+ public Vector2 Position;
+ public Vector2 UV;
+ ///
+ /// Modulation colour for this vertex.
+ /// Note that this color is in linear space.
+ ///
+ public Color Color;
+
+ /// The location.
+ /// The texture coordinate.
+ /// Modulation colour (In linear space, use Color.FromSrgb if needed)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public DrawVertexUV2DColor(Vector2 position, Vector2 uv, Color col)
+ {
+ Position = position;
+ UV = uv;
+ Color = col;
+ }
+
+ /// The location.
+ /// Modulation colour (In linear space, use Color.FromSrgb if needed)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public DrawVertexUV2DColor(Vector2 position, Color col)
+ {
+ Position = position;
+ UV = new Vector2(0.5f, 0.5f);
+ Color = col;
+ }
+
+ /// The existing position/UV pair.
+ /// Modulation colour (In linear space, use Color.FromSrgb if needed)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public DrawVertexUV2DColor(DrawVertexUV2D b, Color col)
+ {
+ Position = b.Position;
+ UV = b.UV;
+ Color = col;
+ }
+ }
}
diff --git a/Robust.Client/UserInterface/UserInterfaceManager.cs b/Robust.Client/UserInterface/UserInterfaceManager.cs
index 46fa9b070..cc5fb60e6 100644
--- a/Robust.Client/UserInterface/UserInterfaceManager.cs
+++ b/Robust.Client/UserInterface/UserInterfaceManager.cs
@@ -787,7 +787,6 @@ namespace Robust.Client.UserInterface
}
}
-
var clip = control.RectClipContent;
var scissorRegion = scissorBox;
if (clip)
@@ -815,11 +814,14 @@ namespace Robust.Client.UserInterface
var handle = renderHandle.DrawingHandleScreen;
handle.SetTransform(position, Angle.Zero, Vector2.One);
modulate *= control.Modulate;
- handle.Modulate = modulate * control.ActualModulateSelf;
if (_rendering || control.AlwaysRender)
{
+ // Handle modulation with care.
+ var oldMod = handle.Modulate;
+ handle.Modulate = modulate * control.ActualModulateSelf;
control.DrawInternal(renderHandle);
+ handle.Modulate = oldMod;
handle.UseShader(null);
}
diff --git a/Robust.Shared.Maths/Color.cs b/Robust.Shared.Maths/Color.cs
index 7cce3498d..3dc664a7d 100644
--- a/Robust.Shared.Maths/Color.cs
+++ b/Robust.Shared.Maths/Color.cs
@@ -28,6 +28,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Xml.Linq;
using JetBrains.Annotations;
using SysVector3 = System.Numerics.Vector3;
@@ -44,6 +45,7 @@ namespace Robust.Shared.Maths
/// Represents a color with 4 floating-point components (R, G, B, A).
///
[Serializable]
+ [StructLayout(LayoutKind.Sequential)]
public struct Color : IEquatable
{
///