Skip to content

Commit 3dbf086

Browse files
committed
Implement modular retained GL UI architecture with auto-layout container and SDF rounded corners
1 parent 07e74a4 commit 3dbf086

14 files changed

Lines changed: 225 additions & 42 deletions

File tree

assets/Shaders/rectangle.frag

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
11
#version 150 core
22
in vec2 textureCoord;
3+
in vec2 fragOffset;
34
uniform vec2 uAlphaTest;
45
uniform bool uRectangleHasColour;
56
uniform vec4 uColor;
67
uniform sampler2D uTexture;
8+
uniform vec2 uSize;
9+
uniform float uCornerRadius;
710
out vec4 fragColor;
811

12+
float roundSDF(vec2 p, vec2 b, float r)
13+
{
14+
vec2 q = abs(p) - b + r;
15+
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;
16+
}
17+
918
void main(void)
1019
{
1120
vec4 textureColour = texture(uTexture, textureCoord);
12-
1321
vec4 finalColor = textureColour * uColor;
1422

23+
if (uCornerRadius > 0.0)
24+
{
25+
vec2 halfSize = uSize * 0.5;
26+
vec2 pos = (fragOffset - 0.5) * uSize;
27+
float dist = roundSDF(pos, halfSize, uCornerRadius);
28+
29+
float alpha = 1.0 - smoothstep(-0.5, 0.5, dist);
30+
if (alpha <= 0.0)
31+
{
32+
discard;
33+
}
34+
finalColor.a *= alpha;
35+
}
36+
1537
/*
1638
* NOTES:
1739
* Unused alpha functions must not be added to the shader

assets/Shaders/rectangle.vert

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ uniform vec2 uPoint;
55
uniform vec2 uSize;
66
uniform vec2 uCoordinates;
77
out vec2 textureCoord;
8+
out vec2 fragOffset;
89

910
// Offset lookup table to map gl_VertexID to quad corners without branching
1011
const vec2 offsets[6] = vec2[](
@@ -22,5 +23,6 @@ void main()
2223
vec2 offset = offsets[gl_VertexID];
2324
vec4 viewPos = uCurrentModelViewMatrix * vec4(uPoint + offset * uSize, 0.0, 1.0);
2425
textureCoord = offset * uCoordinates;
26+
fragOffset = offset;
2527
gl_Position = uCurrentProjectionMatrix * viewPos;
2628
}

source/LibRender2/BaseRenderer.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
using OpenBveApi.FileSystem;
2828
using OpenBveApi.Hosts;
2929
using OpenBveApi.Interface;
30+
using OpenBveApi.Graphics;
3031
using OpenBveApi.Math;
3132
using OpenBveApi.Objects;
3233
using OpenBveApi.Routes;
@@ -42,7 +43,7 @@
4243

4344
namespace LibRender2
4445
{
45-
public abstract class BaseRenderer
46+
public abstract class BaseRenderer : OpenBveApi.Graphics.IGLRenderer
4647
{
4748
// constants
4849
protected const float inv255 = 1.0f / 255.0f;
@@ -1873,5 +1874,29 @@ public void RunInRenderThread(ThreadStart job, int timeout)
18731874
Monitor.Wait(job, timeout);
18741875
}
18751876
}
1877+
1878+
/// <inheritdoc />
1879+
public bool LoadTexture(ref Texture texture, OpenGlTextureWrapMode wrapMode)
1880+
{
1881+
return currentHost.LoadTexture(ref texture, wrapMode);
1882+
}
1883+
1884+
/// <inheritdoc />
1885+
public void DrawRectangle(Texture texture, Vector2 location, Vector2 size, Color128 color, OpenGlTextureWrapMode? wrapMode = null, float cornerRadius = 0f)
1886+
{
1887+
Rectangle.Draw(texture, location, size, color, null, wrapMode, cornerRadius);
1888+
}
1889+
1890+
/// <inheritdoc />
1891+
public void DrawRectangleAlpha(Texture texture, Vector2 location, Vector2 size, Color128 color, Vector2 scale, OpenGlTextureWrapMode? wrapMode = null, float cornerRadius = 0f)
1892+
{
1893+
Rectangle.DrawAlpha(texture, location, size, color, scale, wrapMode, cornerRadius);
1894+
}
1895+
1896+
/// <inheritdoc />
1897+
public void DrawText(string text, Vector2 location, Color128 color)
1898+
{
1899+
OpenGlString.Draw(Fonts.NormalFont, text, location, TextAlignment.TopLeft, color);
1900+
}
18761901
}
18771902
}

source/LibRender2/LibRender2.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<Compile Include="Primitives\Button.cs" />
101101
<Compile Include="Primitives\Cube.cs" />
102102
<Compile Include="Primitives\GLControl.cs" />
103+
<Compile Include="Primitives\VerticalLayoutGroup.cs" />
103104
<Compile Include="Primitives\Label.cs" />
104105
<Compile Include="Primitives\Particle.cs" />
105106
<Compile Include="Primitives\Picturebox.cs" />

source/LibRender2/Primitives/Button.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//Simplified BSD License (BSD-2-Clause)
1+
//Simplified BSD License (BSD-2-Clause)
22
//
33
//Copyright (c) 2023, Christopher Lees, The OpenBVE Project
44
//
@@ -38,7 +38,7 @@ public string Text
3838
set
3939
{
4040
_text = value;
41-
Size = Font.MeasureString(Text) * 1.5 * Renderer.currentOptions.UserInterfaceScaleFactor;
41+
Size = Font.MeasureString(Text) * 1.5 * baseRenderer.currentOptions.UserInterfaceScaleFactor;
4242
}
4343
}
4444

@@ -57,9 +57,11 @@ public string Text
5757
/// <summary>The font for the button</summary>
5858
public OpenGlFont Font;
5959

60-
public Button(BaseRenderer renderer, string text) : base(renderer)
60+
private BaseRenderer baseRenderer => Renderer as BaseRenderer;
61+
62+
public Button(IGLRenderer renderer, string text) : base(renderer)
6163
{
62-
Font = Renderer.Fonts.LargeFont;
64+
Font = baseRenderer.Fonts.LargeFont;
6365
Text = text;
6466
Enabled = true;
6567
// default colors to match GLMenu
@@ -75,12 +77,12 @@ public override void Draw()
7577
{
7678
return;
7779
}
78-
Renderer.Rectangle.Draw(Texture, Location, Size, BackgroundColor);
80+
baseRenderer.Rectangle.Draw(Texture, Location, Size, BackgroundColor, null, null, CornerRadius);
7981
if (CurrentlySelected && Enabled)
8082
{
81-
Renderer.Rectangle.Draw(Texture, Location + Size * 0.1, Size - (Size * 0.2), HighlightColor);
83+
baseRenderer.Rectangle.Draw(Texture, Location + Size * 0.1, Size - (Size * 0.2), HighlightColor, null, null, CornerRadius * 0.8f);
8284
}
83-
Renderer.OpenGlString.Draw(Font, Text, Location + (Size * 0.15), TextAlignment.TopLeft, Enabled ? EnabledTextColor : DisabledTextColor);
85+
baseRenderer.OpenGlString.Draw(Font, Text, Location + (Size * 0.15), TextAlignment.TopLeft, Enabled ? EnabledTextColor : DisabledTextColor);
8486
}
8587

8688
public override void MouseMove(int x, int y)

source/LibRender2/Primitives/GLControl.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//Simplified BSD License (BSD-2-Clause)
1+
//Simplified BSD License (BSD-2-Clause)
22
//
33
//Copyright (c) 2023, Christopher Lees, The OpenBVE Project
44
//
@@ -24,6 +24,7 @@
2424

2525
using System;
2626
using OpenBveApi.Colors;
27+
using OpenBveApi.Graphics;
2728
using OpenBveApi.Math;
2829
using OpenBveApi.Textures;
2930

@@ -32,8 +33,8 @@ namespace LibRender2.Primitives
3233
/// <summary>An abstract OpenGL based control</summary>
3334
public abstract class GLControl
3435
{
35-
/// <summary>Holds a reference to the base renderer</summary>
36-
internal readonly BaseRenderer Renderer;
36+
/// <summary>Holds a reference to the base renderer interface</summary>
37+
public readonly IGLRenderer Renderer;
3738
/// <summary>The background color for the control</summary>
3839
public Color128 BackgroundColor;
3940
/// <summary>The texture for the control</summary>
@@ -42,14 +43,16 @@ public abstract class GLControl
4243
public Vector2 Location;
4344
/// <summary>The stored size for the control</summary>
4445
public Vector2 Size;
46+
/// <summary>The corner radius for rounded corners (in pixels)</summary>
47+
public float CornerRadius;
4548
/// <summary>Whether the control is currently selected by the mouse</summary>
4649
public bool CurrentlySelected;
4750
/// <summary>The event handler for the OnClick event</summary>
4851
public EventHandler OnClick;
4952
/// <summary>Whether the control is currently visible</summary>
5053
public bool IsVisible;
5154

52-
protected GLControl(BaseRenderer renderer)
55+
protected GLControl(IGLRenderer renderer)
5356
{
5457
Renderer = renderer;
5558
}

source/LibRender2/Primitives/Label.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//Simplified BSD License (BSD-2-Clause)
1+
//Simplified BSD License (BSD-2-Clause)
22
//
33
//Copyright (c) 2022, Christopher Lees, The OpenBVE Project
44
//
@@ -37,10 +37,12 @@ public class Label : GLControl
3737
/// <summary>The font for the label</summary>
3838
public OpenGlFont Font;
3939

40-
public Label(BaseRenderer renderer, string text) : base(renderer)
40+
private BaseRenderer baseRenderer => Renderer as BaseRenderer;
41+
42+
public Label(IGLRenderer renderer, string text) : base(renderer)
4143
{
4244
Text = text;
43-
Font = Renderer.Fonts.LargeFont;
45+
Font = baseRenderer.Fonts.LargeFont;
4446
Size = Font.MeasureString(Text) * 1.5;
4547
// default colors to match GLMenu
4648
BackgroundColor = Color128.Black;
@@ -49,8 +51,8 @@ public Label(BaseRenderer renderer, string text) : base(renderer)
4951

5052
public override void Draw()
5153
{
52-
Renderer.Rectangle.Draw(Texture, Location, Size, BackgroundColor);
53-
Renderer.OpenGlString.Draw(Font, Text, Location + (Size * 0.15), TextAlignment.TopLeft, TextColor);
54+
baseRenderer.Rectangle.Draw(Texture, Location, Size, BackgroundColor, null, null, CornerRadius);
55+
baseRenderer.OpenGlString.Draw(Font, Text, Location + (Size * 0.15), TextAlignment.TopLeft, TextColor);
5456
}
5557
}
5658
}

source/LibRender2/Primitives/Picturebox.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using OpenBveApi.Colors;
2+
using OpenBveApi.Graphics;
23
using OpenBveApi.Math;
34
using OpenBveApi.Textures;
45
using OpenTK.Graphics.OpenGL;
@@ -13,14 +14,14 @@ public class Picturebox : GLControl
1314
private bool flipX;
1415
private bool flipY;
1516

16-
public Picturebox(BaseRenderer renderer) : base(renderer)
17+
public Picturebox(IGLRenderer renderer) : base(renderer)
1718
{
1819
SizeMode = ImageSizeMode.Zoom;
1920
}
2021

2122
public override void Draw()
2223
{
23-
if (!Renderer.currentHost.LoadTexture(ref Texture, OpenGlTextureWrapMode.ClampClamp))
24+
if (!Renderer.LoadTexture(ref Texture, OpenGlTextureWrapMode.ClampClamp))
2425
{
2526
return;
2627
}
@@ -31,7 +32,7 @@ public override void Draw()
3132
{
3233
case ImageSizeMode.Normal:
3334
//Draw box containing backing color first
34-
Renderer.Rectangle.Draw(Texture, Location, Size, BackgroundColor);
35+
Renderer.DrawRectangle(Texture, Location, Size, BackgroundColor);
3536
//Calculate the new size
3637
newSize = Texture.Size;
3738
if (newSize.X > Size.X)
@@ -44,11 +45,11 @@ public override void Draw()
4445
newSize.Y = Size.Y;
4546
}
4647
//Two-pass draw the texture in appropriate place
47-
Renderer.Rectangle.DrawAlpha(Texture, Location, newSize, Color128.White, new Vector2(newSize / Size));
48+
Renderer.DrawRectangleAlpha(Texture, Location, newSize, Color128.White, new Vector2(newSize / Size));
4849
break;
4950
case ImageSizeMode.Center:
5051
//Draw box containing backing color first
51-
Renderer.Rectangle.Draw(Texture, Location, Size, BackgroundColor);
52+
Renderer.DrawRectangle(Texture, Location, Size, BackgroundColor);
5253
//Calculate the new size
5354
newSize = Texture.Size;
5455
if (newSize.X > Size.X)
@@ -61,15 +62,15 @@ public override void Draw()
6162
newSize.Y = Size.Y;
6263
}
6364
//Two-pass draw the texture in appropriate place
64-
Renderer.Rectangle.DrawAlpha(Texture, Location + new Vector2(newSize - Size) / 2, newSize, Color128.White, new Vector2(newSize / Size));
65+
Renderer.DrawRectangleAlpha(Texture, Location + new Vector2(newSize - Size) / 2, newSize, Color128.White, new Vector2(newSize / Size));
6566
break;
6667
case ImageSizeMode.Stretch:
6768
//No need to draw a backing color box as texture covers the whole thing
68-
Renderer.Rectangle.Draw(Texture, Location, Size, BackgroundColor);
69+
Renderer.DrawRectangle(Texture, Location, Size, BackgroundColor);
6970
break;
7071
case ImageSizeMode.Zoom:
7172
//Draw box containing backing color first
72-
Renderer.Rectangle.Draw(null, Location, Size, BackgroundColor);
73+
Renderer.DrawRectangle(null, Location, Size, BackgroundColor);
7374
//Calculate the new size
7475
Vector2 ratio = Size / Texture.Size;
7576
double newRatio = ratio.X < ratio.Y ? ratio.X : ratio.Y;
@@ -84,7 +85,7 @@ public override void Draw()
8485
{
8586
wrapMode = wrapMode == OpenGlTextureWrapMode.RepeatClamp ? OpenGlTextureWrapMode.RepeatRepeat : OpenGlTextureWrapMode.ClampRepeat;
8687
}
87-
Renderer.Rectangle.DrawAlpha(Texture, new Vector2(Location.X + (Size.X - newSize.X) / 2,Location.Y + (Size.Y - newSize.Y) / 2), newSize, Color128.White, new Vector2(flipX ? -1 : 1,flipY ? -1 : 1), wrapMode);
88+
Renderer.DrawRectangleAlpha(Texture, new Vector2(Location.X + (Size.X - newSize.X) / 2,Location.Y + (Size.Y - newSize.Y) / 2), newSize, Color128.White, new Vector2(flipX ? -1 : 1,flipY ? -1 : 1), wrapMode);
8889
break;
8990
}
9091
}

source/LibRender2/Primitives/Rectangle.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,17 @@ internal Rectangle(BaseRenderer renderer)
6060
/// <param name="color">The color, or a null reference.</param>
6161
/// <param name="textureCoordinates">The texture coordinates to be applied</param>
6262
/// <param name="wrapMode">A wrap mode if overriding that of the texture</param>
63-
public void DrawAlpha(Texture texture, Vector2 point, Vector2 size, Color128? color = null, Vector2? textureCoordinates = null, OpenGlTextureWrapMode? wrapMode = null)
63+
/// <param name="cornerRadius">Corner radius in pixels for rounded corners</param>
64+
public void DrawAlpha(Texture texture, Vector2 point, Vector2 size, Color128? color = null, Vector2? textureCoordinates = null, OpenGlTextureWrapMode? wrapMode = null, float cornerRadius = 0f)
6465
{
6566
renderer.UnsetBlendFunc();
6667
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
6768
GL.DepthMask(true);
68-
Draw(texture, point, size, color, textureCoordinates, wrapMode);
69+
Draw(texture, point, size, color, textureCoordinates, wrapMode, cornerRadius);
6970
renderer.SetBlendFunc();
7071
renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
7172
GL.DepthMask(false);
72-
Draw(texture, point, size, color, textureCoordinates, wrapMode);
73+
Draw(texture, point, size, color, textureCoordinates, wrapMode, cornerRadius);
7374
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
7475
}
7576

@@ -102,17 +103,18 @@ public void DrawAlpha(Texture texture, Vector2 point, Color128? color = null, Ve
102103
/// <param name="color">The color, or a null reference.</param>
103104
/// <param name="textureCoordinates">The texture coordinates to be applied</param>
104105
/// <param name="wrapMode">A wrap mode if overriding that of the texture</param>
105-
public void Draw(Texture texture, Vector2 point, Vector2 size, Color128? color = null, Vector2? textureCoordinates = null, OpenGlTextureWrapMode? wrapMode = null)
106+
/// <param name="cornerRadius">Corner radius in pixels for rounded corners</param>
107+
public void Draw(Texture texture, Vector2 point, Vector2 size, Color128? color = null, Vector2? textureCoordinates = null, OpenGlTextureWrapMode? wrapMode = null, float cornerRadius = 0f)
106108
{
107109
if (renderer.AvailableNewRenderer && Shader != null)
108110
{
109111
if (textureCoordinates == null)
110112
{
111-
DrawWithShader(texture, point, size, color, Vector2.One, wrapMode);
113+
DrawWithShader(texture, point, size, color, Vector2.One, wrapMode, cornerRadius);
112114
}
113115
else
114116
{
115-
DrawWithShader(texture, point, size, color, (Vector2)textureCoordinates, wrapMode);
117+
DrawWithShader(texture, point, size, color, (Vector2)textureCoordinates, wrapMode, cornerRadius);
116118
}
117119
}
118120
else
@@ -234,7 +236,7 @@ private void DrawImmediate(Texture texture, Vector2 point, Vector2 size, Color12
234236
GL.PopMatrix();
235237
}
236238

237-
private void DrawWithShader(Texture texture, Vector2 point, Vector2 size, Color128? color, Vector2 coordinates, OpenGlTextureWrapMode? wrapMode = null)
239+
private void DrawWithShader(Texture texture, Vector2 point, Vector2 size, Color128? color, Vector2 coordinates, OpenGlTextureWrapMode? wrapMode = null, float cornerRadius = 0f)
238240
{
239241
Shader.Activate();
240242
if (wrapMode == null)
@@ -258,6 +260,7 @@ private void DrawWithShader(Texture texture, Vector2 point, Vector2 size, Color1
258260
Shader.SetPoint(point);
259261
Shader.SetSize(size);
260262
Shader.SetCoordinates(coordinates);
263+
Shader.SetCornerRadius(cornerRadius);
261264
/*
262265
* In order to call GL.DrawArrays with procedural data within the shader,
263266
* we first need to bind a dummy VAO

0 commit comments

Comments
 (0)