mirror of
https://gitlab.acidiclight.dev/sociallydistant/sociallydistant.git
synced 2025-01-22 17:41:49 -05:00
Add support for shaders
This commit is contained in:
parent
301289554d
commit
99a4b7e289
16 changed files with 308 additions and 53 deletions
43
mgfxc-wine-setup.sh
Executable file
43
mgfxc-wine-setup.sh
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# This script is used to setup the needed Wine environment
|
||||||
|
# so that mgfxc can be run on Linux / macOS systems.
|
||||||
|
|
||||||
|
# check dependencies
|
||||||
|
if ! type "wine64" > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "wine64 not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! type "7z" > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "7z not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# init wine stuff
|
||||||
|
export WINEARCH=win64
|
||||||
|
export WINEPREFIX=$HOME/.winemonogame
|
||||||
|
wine64 wineboot
|
||||||
|
|
||||||
|
TEMP_DIR="${TMPDIR:-/tmp}"
|
||||||
|
SCRIPT_DIR="$TEMP_DIR/winemg2"
|
||||||
|
mkdir -p "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# get dotnet
|
||||||
|
DOTNET_URL="https://download.visualstudio.microsoft.com/download/pr/adeab8b1-1c44-41b2-b12a-156442f307e9/65ebf805366410c63edeb06e53959383/dotnet-sdk-3.1.201-win-x64.zip"
|
||||||
|
curl $DOTNET_URL --output "$SCRIPT_DIR/dotnet-sdk.zip"
|
||||||
|
7z x "$SCRIPT_DIR/dotnet-sdk.zip" -o"$WINEPREFIX/drive_c/windows/system32/"
|
||||||
|
|
||||||
|
# get d3dcompiler_47
|
||||||
|
FIREFOX_URL="https://download-installer.cdn.mozilla.net/pub/firefox/releases/62.0.3/win64/ach/Firefox%20Setup%2062.0.3.exe"
|
||||||
|
curl $FIREFOX_URL --output "$SCRIPT_DIR/firefox.exe"
|
||||||
|
7z x "$SCRIPT_DIR/firefox.exe" -o"$SCRIPT_DIR/firefox_data/"
|
||||||
|
cp -f "$SCRIPT_DIR/firefox_data/core/d3dcompiler_47.dll" "$WINEPREFIX/drive_c/windows/system32/d3dcompiler_47.dll"
|
||||||
|
|
||||||
|
# append MGFXC_WINE_PATH env variable
|
||||||
|
echo "export MGFXC_WINE_PATH=$HOME/.winemonogame" >> ~/.profile
|
||||||
|
echo "export MGFXC_WINE_PATH=$HOME/.winemonogame" >> ~/.zprofile
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
rm -rf "$SCRIPT_DIR"
|
9
src/AcidicGUI/Effects/IEffect.cs
Normal file
9
src/AcidicGUI/Effects/IEffect.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace AcidicGUI.Effects;
|
||||||
|
|
||||||
|
public interface IEffect
|
||||||
|
{
|
||||||
|
int PassesCount { get; }
|
||||||
|
|
||||||
|
void Use(int pass);
|
||||||
|
void UpdateOpacity(float opacity);
|
||||||
|
}
|
13
src/AcidicGUI/Effects/IWidgetEffect.cs
Normal file
13
src/AcidicGUI/Effects/IWidgetEffect.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using AcidicGUI.Rendering;
|
||||||
|
using AcidicGUI.Widgets;
|
||||||
|
|
||||||
|
namespace AcidicGUI.Effects;
|
||||||
|
|
||||||
|
public interface IWidgetEffect : IEffect
|
||||||
|
{
|
||||||
|
void UpdateParameters(Widget widget, GuiRenderer renderer);
|
||||||
|
|
||||||
|
void BeforeRebuildGeometry(GeometryHelper geometry);
|
||||||
|
void AfterRebuildGeometry(GeometryHelper geometry);
|
||||||
|
}
|
||||||
|
|
|
@ -253,7 +253,7 @@ public sealed class GuiManager : IFontFamilyProvider
|
||||||
|
|
||||||
if (previous == current)
|
if (previous == current)
|
||||||
{
|
{
|
||||||
if (widgetBeingDragged == null)
|
if (widgetBeingDragged == null || current == ButtonState.Released)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Bubble<IDragHandler, MouseButtonEvent>(widgetBeingDragged, e, x => x.OnDrag);
|
Bubble<IDragHandler, MouseButtonEvent>(widgetBeingDragged, e, x => x.OnDrag);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using AcidicGUI.Effects;
|
||||||
using AcidicGUI.Layout;
|
using AcidicGUI.Layout;
|
||||||
using AcidicGUI.Rendering;
|
using AcidicGUI.Rendering;
|
||||||
using AcidicGUI.TextRendering;
|
using AcidicGUI.TextRendering;
|
||||||
|
@ -13,7 +14,13 @@ public interface IGuiContext
|
||||||
GraphicsDevice GraphicsDevice { get; }
|
GraphicsDevice GraphicsDevice { get; }
|
||||||
|
|
||||||
void Render(VertexPositionColorTexture[] vertices, int[] indices, Texture2D? texture, LayoutRect? clipRect = null);
|
void Render(VertexPositionColorTexture[] vertices, int[] indices, Texture2D? texture, LayoutRect? clipRect = null);
|
||||||
void Render(VertexBuffer vertices, IndexBuffer indices, int offset, int primitiveCount, Texture2D? texture, LayoutRect? clipRect = null);
|
void Render(VertexBuffer vertices, IndexBuffer indices, int offset, int primitiveCount, Texture2D? texture, LayoutRect? clipRect = null, IEffect? effectOverride = null, float opacity = 1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renders the user interface to the given RenderTarget2D. Useful for certain widget rendering techniques such as background blurs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination"></param>
|
||||||
|
void Grab(RenderTarget2D destination);
|
||||||
|
|
||||||
IFontFamily GetFallbackFont();
|
IFontFamily GetFallbackFont();
|
||||||
}
|
}
|
|
@ -7,21 +7,19 @@ namespace AcidicGUI.Rendering;
|
||||||
|
|
||||||
public class GeometryHelper : IFontStashRenderer2
|
public class GeometryHelper : IFontStashRenderer2
|
||||||
{
|
{
|
||||||
private readonly GuiMeshBuilder whiteMesh;
|
private readonly GuiMeshBuilder whiteMesh;
|
||||||
private readonly Dictionary<Texture2D, GuiMeshBuilder> meshes = new();
|
private readonly Dictionary<Texture2D, GuiMeshBuilder> meshes = new();
|
||||||
private readonly GuiRenderer guiRenderer;
|
private readonly GuiRenderer guiRenderer;
|
||||||
private readonly bool desaturate;
|
private readonly bool desaturate;
|
||||||
private readonly float opacity;
|
private readonly LayoutRect? clipRect;
|
||||||
private readonly LayoutRect? clipRect;
|
|
||||||
|
|
||||||
internal GeometryHelper(GuiRenderer guiRenderer, float opacity, bool desaturate, LayoutRect? clipRect)
|
internal GeometryHelper(GuiRenderer guiRenderer, bool desaturate, LayoutRect? clipRect)
|
||||||
{
|
{
|
||||||
this.opacity = opacity;
|
|
||||||
this.desaturate = desaturate;
|
this.desaturate = desaturate;
|
||||||
this.guiRenderer = guiRenderer;
|
this.guiRenderer = guiRenderer;
|
||||||
this.clipRect = clipRect;
|
this.clipRect = clipRect;
|
||||||
|
|
||||||
whiteMesh = new GuiMeshBuilder(null, guiRenderer.GetVertexCount(null), guiRenderer.Layer, opacity, desaturate);
|
whiteMesh = new GuiMeshBuilder(null, guiRenderer.GetVertexCount(null), guiRenderer.Layer, desaturate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GuiMesh ExportMesh()
|
public GuiMesh ExportMesh()
|
||||||
|
@ -47,7 +45,7 @@ public class GeometryHelper : IFontStashRenderer2
|
||||||
|
|
||||||
if (!meshes.TryGetValue(texture, out GuiMeshBuilder? builder))
|
if (!meshes.TryGetValue(texture, out GuiMeshBuilder? builder))
|
||||||
{
|
{
|
||||||
builder = new GuiMeshBuilder(texture, guiRenderer.GetVertexCount(texture), guiRenderer.Layer, opacity, desaturate);
|
builder = new GuiMeshBuilder(texture, guiRenderer.GetVertexCount(texture), guiRenderer.Layer, desaturate);
|
||||||
meshes.Add(texture, builder);
|
meshes.Add(texture, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,13 @@ public sealed class GuiMeshBuilder
|
||||||
private readonly List<VertexPositionColorTexture> vertices = new();
|
private readonly List<VertexPositionColorTexture> vertices = new();
|
||||||
private readonly List<int> indices = new();
|
private readonly List<int> indices = new();
|
||||||
private readonly Texture2D? texture;
|
private readonly Texture2D? texture;
|
||||||
private readonly float opacity;
|
|
||||||
private readonly bool desaturate;
|
private readonly bool desaturate;
|
||||||
private readonly int baseVertex;
|
private readonly int baseVertex;
|
||||||
private readonly float layer;
|
private readonly float layer;
|
||||||
|
|
||||||
public GuiMeshBuilder(Texture2D? texture, int baseVertex, int layer, float opacity, bool desaturate)
|
public GuiMeshBuilder(Texture2D? texture, int baseVertex, int layer, bool desaturate)
|
||||||
{
|
{
|
||||||
this.texture = texture;
|
this.texture = texture;
|
||||||
this.opacity = opacity;
|
|
||||||
this.desaturate = desaturate;
|
this.desaturate = desaturate;
|
||||||
//this.baseVertex = baseVertex;
|
//this.baseVertex = baseVertex;
|
||||||
//this.layer = layer * float.Epsilon;
|
//this.layer = layer * float.Epsilon;
|
||||||
|
@ -37,7 +35,6 @@ public sealed class GuiMeshBuilder
|
||||||
int index = vertices.Count;
|
int index = vertices.Count;
|
||||||
|
|
||||||
vertex.Position.Z = layer;
|
vertex.Position.Z = layer;
|
||||||
vertex.Color.A = (byte)(vertex.Color.A * opacity);
|
|
||||||
|
|
||||||
if (desaturate)
|
if (desaturate)
|
||||||
vertex.Color.A = (byte) (vertex.Color.A / 2);
|
vertex.Color.A = (byte) (vertex.Color.A / 2);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using AcidicGUI.Effects;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
namespace AcidicGUI.Rendering;
|
namespace AcidicGUI.Rendering;
|
||||||
|
@ -80,12 +81,12 @@ public sealed class GuiRenderer
|
||||||
whiteBatch.Submit(subMesh);
|
whiteBatch.Submit(subMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenderBatches()
|
public void RenderBatches(IEffect? effectOverride = null, float opacity = 1)
|
||||||
{
|
{
|
||||||
whiteBatch?.DrawBatch();
|
whiteBatch?.DrawBatch(effectOverride, opacity);
|
||||||
|
|
||||||
foreach (GuiBatch batch in batches.Values)
|
foreach (GuiBatch batch in batches.Values)
|
||||||
batch.DrawBatch();
|
batch.DrawBatch(effectOverride, opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GraphicsDevice GraphicsDevice => context.GraphicsDevice;
|
public GraphicsDevice GraphicsDevice => context.GraphicsDevice;
|
||||||
|
@ -171,7 +172,7 @@ public sealed class GuiBatch
|
||||||
cpuIndices.AddRange(subMesh.Indices);
|
cpuIndices.AddRange(subMesh.Indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawBatch()
|
public void DrawBatch(IEffect? effectOverride, float opacity)
|
||||||
{
|
{
|
||||||
if (cpuIndices.Count == 0 || cpuVertices.Count == 0)
|
if (cpuIndices.Count == 0 || cpuVertices.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -203,7 +204,7 @@ public sealed class GuiBatch
|
||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Render(vertexBuffer, indexBuffer, 0, cpuIndices.Count / 3, texture, null);
|
context.Render(vertexBuffer, indexBuffer, 0, cpuIndices.Count / 3, texture, null, effectOverride, opacity);
|
||||||
|
|
||||||
cpuVertices.Clear();
|
cpuVertices.Clear();
|
||||||
cpuIndices.Clear();
|
cpuIndices.Clear();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using AcidicGUI.CustomProperties;
|
using AcidicGUI.CustomProperties;
|
||||||
|
using AcidicGUI.Effects;
|
||||||
using AcidicGUI.Layout;
|
using AcidicGUI.Layout;
|
||||||
using AcidicGUI.Rendering;
|
using AcidicGUI.Rendering;
|
||||||
using AcidicGUI.TextRendering;
|
using AcidicGUI.TextRendering;
|
||||||
|
@ -12,15 +13,22 @@ public abstract partial class Widget : IFontFamilyProvider
|
||||||
private readonly WidgetCollection children;
|
private readonly WidgetCollection children;
|
||||||
private readonly Dictionary<Type, CustomPropertyObject> customProperties = new();
|
private readonly Dictionary<Type, CustomPropertyObject> customProperties = new();
|
||||||
|
|
||||||
private IVisualStyle? visualStyleOverride;
|
private IVisualStyle? visualStyleOverride;
|
||||||
private Widget? parent;
|
private Widget? parent;
|
||||||
private GuiManager? guiManager;
|
private GuiManager? guiManager;
|
||||||
private GuiMesh? cachedGeometry;
|
private GuiMesh? cachedGeometry;
|
||||||
private float renderOpacity = 1;
|
private float renderOpacity = 1;
|
||||||
private bool enabled = true;
|
private bool enabled = true;
|
||||||
private ClippingMode clippingMode;
|
private ClippingMode clippingMode;
|
||||||
private LayoutRect clipRect;
|
private LayoutRect clipRect;
|
||||||
|
private IWidgetEffect? effectOverride;
|
||||||
|
|
||||||
|
public IWidgetEffect? RenderEffect
|
||||||
|
{
|
||||||
|
get => effectOverride;
|
||||||
|
set => effectOverride = value;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsFocused
|
public bool IsFocused
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -191,15 +199,19 @@ public abstract partial class Widget : IFontFamilyProvider
|
||||||
if (visibility != Visibility.Visible)
|
if (visibility != Visibility.Visible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
effectOverride?.UpdateParameters(this, renderer);
|
||||||
|
|
||||||
if (cachedGeometry == null)
|
if (cachedGeometry == null)
|
||||||
{
|
{
|
||||||
var geometryHelper = new GeometryHelper(renderer, ComputedOpacity, !HierarchyEnabled, clipRect);
|
var geometryHelper = new GeometryHelper(renderer, !HierarchyEnabled, clipRect);
|
||||||
|
effectOverride?.BeforeRebuildGeometry(geometryHelper);
|
||||||
RebuildGeometry(geometryHelper);
|
RebuildGeometry(geometryHelper);
|
||||||
|
effectOverride?.AfterRebuildGeometry(geometryHelper);
|
||||||
cachedGeometry = geometryHelper.ExportMesh();
|
cachedGeometry = geometryHelper.ExportMesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.RenderGuiMesh(cachedGeometry.Value);
|
renderer.RenderGuiMesh(cachedGeometry.Value);
|
||||||
renderer.RenderBatches();
|
renderer.RenderBatches(effectOverride, ComputedOpacity);
|
||||||
|
|
||||||
renderer.PushLayer();
|
renderer.PushLayer();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
using AcidicGUI.Effects;
|
||||||
|
using AcidicGUI.Rendering;
|
||||||
|
using AcidicGUI.Widgets;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace SociallyDistant.Core.UI.Effects;
|
||||||
|
|
||||||
|
public sealed class BackgroundBlurEffect : MonoGameEffect,
|
||||||
|
IWidgetEffect
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
public BackgroundBlurEffect(Effect underlyingEffect, int techniqueIndex = 0) : base(underlyingEffect, techniqueIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateParameters(Widget widget, GuiRenderer renderer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BeforeRebuildGeometry(GeometryHelper geometry)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AfterRebuildGeometry(GeometryHelper geometry)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
57
src/SociallyDistant.Framework/UI/Effects/MonoGameEffect.cs
Normal file
57
src/SociallyDistant.Framework/UI/Effects/MonoGameEffect.cs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
using AcidicGUI.Effects;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace SociallyDistant.Core.UI.Effects;
|
||||||
|
|
||||||
|
public class MonoGameEffect :
|
||||||
|
IEffect,
|
||||||
|
IDisposable
|
||||||
|
{
|
||||||
|
public static readonly string TransformMatrixParameterName = "TransformMatrix";
|
||||||
|
public static readonly string OpacityParameterName = "Opacity";
|
||||||
|
private readonly Effect underlyingEffect;
|
||||||
|
private readonly int techniqueIndex;
|
||||||
|
private readonly EffectParameter transformMatrixParameter;
|
||||||
|
private readonly EffectParameter opacityParameter;
|
||||||
|
private Viewport lastViewport;
|
||||||
|
private Matrix transformMatrix;
|
||||||
|
|
||||||
|
public int PassesCount => underlyingEffect.Techniques[techniqueIndex].Passes.Count;
|
||||||
|
|
||||||
|
public MonoGameEffect(Effect underlyingEffect, int techniqueIndex = 0)
|
||||||
|
{
|
||||||
|
this.underlyingEffect = underlyingEffect;
|
||||||
|
this.techniqueIndex = techniqueIndex;
|
||||||
|
|
||||||
|
transformMatrixParameter = underlyingEffect.Parameters[TransformMatrixParameterName];
|
||||||
|
opacityParameter = underlyingEffect.Parameters[OpacityParameterName];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
underlyingEffect.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateOpacity(float opacity)
|
||||||
|
{
|
||||||
|
opacityParameter.SetValue(opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Use(int pass)
|
||||||
|
{
|
||||||
|
underlyingEffect.Techniques[techniqueIndex].Passes[pass].Apply();
|
||||||
|
|
||||||
|
Viewport viewport = underlyingEffect.GraphicsDevice.Viewport;
|
||||||
|
|
||||||
|
if (viewport.Width != lastViewport.Width || viewport.Height != lastViewport.Height)
|
||||||
|
{
|
||||||
|
lastViewport = viewport;
|
||||||
|
|
||||||
|
Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, -1, out transformMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
transformMatrixParameter.SetValue(transformMatrix);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using AcidicGUI;
|
using AcidicGUI;
|
||||||
using AcidicGUI.CustomProperties;
|
using AcidicGUI.CustomProperties;
|
||||||
|
using AcidicGUI.Effects;
|
||||||
using AcidicGUI.Layout;
|
using AcidicGUI.Layout;
|
||||||
using AcidicGUI.Rendering;
|
using AcidicGUI.Rendering;
|
||||||
using AcidicGUI.TextRendering;
|
using AcidicGUI.TextRendering;
|
||||||
|
@ -8,6 +9,7 @@ using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using SociallyDistant.Core.Modules;
|
using SociallyDistant.Core.Modules;
|
||||||
|
using SociallyDistant.Core.UI.Effects;
|
||||||
using SociallyDistant.Core.UI.VisualStyles;
|
using SociallyDistant.Core.UI.VisualStyles;
|
||||||
|
|
||||||
namespace SociallyDistant.Core.UI;
|
namespace SociallyDistant.Core.UI;
|
||||||
|
@ -23,18 +25,18 @@ public sealed class GuiService :
|
||||||
AlphaSourceBlend = Blend.One,
|
AlphaSourceBlend = Blend.One,
|
||||||
AlphaDestinationBlend = Blend.InverseSourceAlpha,
|
AlphaDestinationBlend = Blend.InverseSourceAlpha,
|
||||||
};
|
};
|
||||||
private readonly IGameContext context;
|
private readonly IGameContext context;
|
||||||
private readonly GuiManager acidicGui;
|
private readonly GuiManager acidicGui;
|
||||||
private readonly IGuiContext guiContext;
|
private readonly IGuiContext guiContext;
|
||||||
private readonly int[] screenQuad = new int[] { 0, 1, 2, 2, 1, 3 };
|
private readonly int[] screenQuad = new int[] { 0, 1, 2, 2, 1, 3 };
|
||||||
private readonly VertexPositionColorTexture[] screenQuadVerts = new VertexPositionColorTexture[4];
|
private readonly VertexPositionColorTexture[] screenQuadVerts = new VertexPositionColorTexture[4];
|
||||||
private readonly SociallyDistantVisualStyle visualStyle;
|
private readonly SociallyDistantVisualStyle visualStyle;
|
||||||
private IFontFamily? fallbackFont;
|
private IFontFamily? fallbackFont;
|
||||||
private SpriteEffect? defaultEffect;
|
private MonoGameEffect? defaultEffect;
|
||||||
private Texture2D? white = null;
|
private Texture2D? white = null;
|
||||||
private RenderTarget2D? virtualScreen;
|
private RenderTarget2D? virtualScreen;
|
||||||
private RasterizerState? scissor;
|
private RasterizerState? scissor;
|
||||||
private RasterizerState? noScissor;
|
private RasterizerState? noScissor;
|
||||||
|
|
||||||
public GuiManager GuiRoot => acidicGui;
|
public GuiManager GuiRoot => acidicGui;
|
||||||
|
|
||||||
|
@ -122,12 +124,17 @@ public sealed class GuiService :
|
||||||
|
|
||||||
public float PhysicalScreenWidget => virtualScreen?.Width ?? Game.GraphicsDevice.Viewport.Width;
|
public float PhysicalScreenWidget => virtualScreen?.Width ?? Game.GraphicsDevice.Viewport.Width;
|
||||||
public float PhysicalScreenHeight => virtualScreen?.Height ?? Game.GraphicsDevice.Viewport.Height;
|
public float PhysicalScreenHeight => virtualScreen?.Height ?? Game.GraphicsDevice.Viewport.Height;
|
||||||
|
|
||||||
|
private MonoGameEffect LoadDefaultEffect()
|
||||||
|
{
|
||||||
|
return new MonoGameEffect(Game.Content.Load<Effect>("/Core/Shaders/UI_Core"));
|
||||||
|
}
|
||||||
|
|
||||||
public void Render(VertexPositionColorTexture[] vertices, int[] indices, Texture2D? texture, LayoutRect? clipRect = null)
|
public void Render(VertexPositionColorTexture[] vertices, int[] indices, Texture2D? texture, LayoutRect? clipRect = null)
|
||||||
{
|
{
|
||||||
if (defaultEffect == null)
|
if (defaultEffect == null)
|
||||||
{
|
{
|
||||||
defaultEffect = new SpriteEffect(Game.GraphicsDevice);
|
defaultEffect = LoadDefaultEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (white == null)
|
if (white == null)
|
||||||
|
@ -144,7 +151,7 @@ public sealed class GuiService :
|
||||||
|
|
||||||
var graphics = Game.GraphicsDevice;
|
var graphics = Game.GraphicsDevice;
|
||||||
|
|
||||||
defaultEffect.Techniques[0].Passes[0].Apply();
|
defaultEffect.Use(0);
|
||||||
graphics.Textures[0] = texture ?? white;
|
graphics.Textures[0] = texture ?? white;
|
||||||
graphics.SamplerStates[0] = SamplerState.LinearClamp;
|
graphics.SamplerStates[0] = SamplerState.LinearClamp;
|
||||||
graphics.BlendState = blendState;
|
graphics.BlendState = blendState;
|
||||||
|
@ -160,14 +167,16 @@ public sealed class GuiService :
|
||||||
int offset,
|
int offset,
|
||||||
int primitiveCount,
|
int primitiveCount,
|
||||||
Texture2D? texture,
|
Texture2D? texture,
|
||||||
LayoutRect? clipRect = null
|
LayoutRect? clipRect = null,
|
||||||
|
IEffect? effectOverride = null,
|
||||||
|
float opacity = 1
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var device = Game.GraphicsDevice;
|
var device = Game.GraphicsDevice;
|
||||||
|
|
||||||
if (defaultEffect == null)
|
if (defaultEffect == null)
|
||||||
{
|
{
|
||||||
defaultEffect = new SpriteEffect(Game.GraphicsDevice);
|
defaultEffect = LoadDefaultEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (white == null)
|
if (white == null)
|
||||||
|
@ -178,8 +187,11 @@ public sealed class GuiService :
|
||||||
|
|
||||||
if (primitiveCount == 0)
|
if (primitiveCount == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
IEffect effectToUse = effectOverride ?? defaultEffect;
|
||||||
|
|
||||||
defaultEffect.Techniques[0].Passes[0].Apply();
|
effectToUse.Use(0);
|
||||||
|
effectToUse.UpdateOpacity(opacity);
|
||||||
device.Textures[0] = texture ?? white;
|
device.Textures[0] = texture ?? white;
|
||||||
device.SamplerStates[0] = SamplerState.LinearClamp;
|
device.SamplerStates[0] = SamplerState.LinearClamp;
|
||||||
device.BlendState = blendState;
|
device.BlendState = blendState;
|
||||||
|
@ -192,6 +204,11 @@ public sealed class GuiService :
|
||||||
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, offset, primitiveCount);
|
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, offset, primitiveCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Grab(RenderTarget2D destination)
|
||||||
|
{
|
||||||
|
// TODO: Implement grabbing
|
||||||
|
}
|
||||||
|
|
||||||
private RasterizerState GetRasterizerState(LayoutRect? clipRect)
|
private RasterizerState GetRasterizerState(LayoutRect? clipRect)
|
||||||
{
|
{
|
||||||
scissor ??= new RasterizerState()
|
scissor ??= new RasterizerState()
|
||||||
|
|
|
@ -5,6 +5,15 @@
|
||||||
/profile:Reach
|
/profile:Reach
|
||||||
/compress:false
|
/compress:false
|
||||||
|
|
||||||
|
#begin Shaders/UI_Core.fx
|
||||||
|
/importer:EffectImporter
|
||||||
|
/processor:EffectProcessor
|
||||||
|
/processorParam:Importer=EffectImporter
|
||||||
|
/processorParam:Processor=EffectProcessor
|
||||||
|
/processorParam:DebugMode=Auto
|
||||||
|
/processorParam:Defines=
|
||||||
|
/build:Shaders/UI_Core.fx
|
||||||
|
|
||||||
#begin Backgrounds/Socially-Distant-Bg-wallpapers-dark-distorted.jpg
|
#begin Backgrounds/Socially-Distant-Bg-wallpapers-dark-distorted.jpg
|
||||||
/importer:TextureImporter
|
/importer:TextureImporter
|
||||||
/processor:TextureProcessor
|
/processor:TextureProcessor
|
||||||
|
|
56
src/SociallyDistant/Content/Shaders/UI_Core.fx
Normal file
56
src/SociallyDistant/Content/Shaders/UI_Core.fx
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* SOCIALLY DISTANT - CORE USER INTERFACE SHADER
|
||||||
|
*
|
||||||
|
* This effect file contains all necessary shader code needed to render
|
||||||
|
* the game's user interface. Do not modify it unless you seriously know
|
||||||
|
* what you're doing, as it is very tightly coupled with the UI renderer
|
||||||
|
* code. If you've never seen that code before, you may wanna go look at it
|
||||||
|
* for a few hours before fuckin' around in here. Don't break Ritchie's
|
||||||
|
* exquisitly-programmed UI render code D:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* standard MG boilerplate */
|
||||||
|
#if OPENGL
|
||||||
|
#define SV_POSITION POSITION
|
||||||
|
#define VS_SHADERMODEL vs_3_0
|
||||||
|
#define PS_SHADERMODEL ps_3_0
|
||||||
|
#else
|
||||||
|
#define VS_SHADERMODEL vs_4_0_level_9_1
|
||||||
|
#define PS_SHADERMODEL ps_4_0_level_9_1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct VSOut {
|
||||||
|
float4 position : SV_Position;
|
||||||
|
float4 color : COLOR0;
|
||||||
|
float2 texcoord : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
matrix TransformMatrix;
|
||||||
|
|
||||||
|
sampler2D MainTexture : register(s0);
|
||||||
|
|
||||||
|
float Opacity;
|
||||||
|
|
||||||
|
|
||||||
|
VSOut VS(float4 position : SV_Position, float4 color : COLOR0, float2 texcoord : TEXCOORD0)
|
||||||
|
{
|
||||||
|
VSOut vsout;
|
||||||
|
vsout.position = mul(position, TransformMatrix);
|
||||||
|
vsout.color = color * Opacity;
|
||||||
|
vsout.texcoord = texcoord;
|
||||||
|
return vsout;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 BasicPixelShader(VSOut data) : COLOR0
|
||||||
|
{
|
||||||
|
return tex2D(MainTexture, data.texcoord) * data.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
technique BasicRender
|
||||||
|
{
|
||||||
|
pass BlitThyPixels
|
||||||
|
{
|
||||||
|
VertexShader = compile VS_SHADERMODEL VS();
|
||||||
|
PixelShader = compile PS_SHADERMODEL BasicPixelShader();
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,14 +12,14 @@ namespace SociallyDistant.UI.Windowing;
|
||||||
|
|
||||||
public class WindowDecoration : Widget
|
public class WindowDecoration : Widget
|
||||||
{
|
{
|
||||||
private readonly FlexPanel flexPanel = new();
|
private readonly FlexPanel flexPanel = new();
|
||||||
private readonly FlexPanel titleBar = new();
|
private readonly FlexPanel titleBar = new();
|
||||||
private readonly Box borderBox = new();
|
private readonly Box borderBox = new();
|
||||||
private readonly Box clientBox = new();
|
private readonly Box clientBox = new();
|
||||||
private readonly WindowBase window;
|
private readonly WindowBase window;
|
||||||
private readonly WindowDragSurface dragSurface;
|
private readonly WindowDragSurface dragSurface;
|
||||||
private readonly CompositeIconWidget titleIcon = new();
|
private readonly CompositeIconWidget titleIcon = new();
|
||||||
private readonly WindowTabList tabList = new();
|
private readonly WindowTabList tabList = new();
|
||||||
|
|
||||||
private WindowHints hints;
|
private WindowHints hints;
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@ public sealed class WindowDragSurface :
|
||||||
|
|
||||||
public void OnDrag(MouseButtonEvent e)
|
public void OnDrag(MouseButtonEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.Button != MouseButton.Left)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!dragging)
|
if (!dragging)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -46,6 +49,9 @@ public sealed class WindowDragSurface :
|
||||||
|
|
||||||
public void OnDragEnd(MouseButtonEvent e)
|
public void OnDragEnd(MouseButtonEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.Button != MouseButton.Left)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!dragging)
|
if (!dragging)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue