Loads and loads of small improvements I added while developing on my game
This commit is contained in:
parent
41421b1df9
commit
a7c71e7ea1
107 changed files with 2278 additions and 1023 deletions
103
Legacy/Window/Contexts/DrawContext.cs
Normal file
103
Legacy/Window/Contexts/DrawContext.cs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using OpenTK;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL.Mesh;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Contexts
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains important information for drawing.
|
||||
/// </summary>
|
||||
public struct DrawContext
|
||||
{
|
||||
/// <summary>
|
||||
/// This says if it was forced to use the viewport camera.
|
||||
/// </summary>
|
||||
public bool ForceViewport;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the currently used render pipeline.
|
||||
/// </summary>
|
||||
public RenderPipeline ActivePipeline;
|
||||
|
||||
public GenericScene ActiveScene;
|
||||
public IGenericWindow Window;
|
||||
|
||||
|
||||
public GenericCamera UsedCamera =>
|
||||
ForceViewport || ActiveScene._camera == null ? Window.ViewportCamera : ActiveScene._camera;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The mesh.
|
||||
/// </summary>
|
||||
public GenericMesh Mesh;
|
||||
|
||||
/// <summary>
|
||||
/// The material.
|
||||
/// </summary>
|
||||
public Material Material;
|
||||
|
||||
/// <summary>
|
||||
/// The drawing instances.
|
||||
/// <para>If there is only one, it's index 0</para>
|
||||
/// </summary>
|
||||
public IList<Instance> Instances;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The current world scale.
|
||||
/// </summary>
|
||||
public Vector2 WorldScale;
|
||||
|
||||
/// <summary>
|
||||
/// The last collection the context was passed though.
|
||||
/// </summary>
|
||||
public object LastPassthough;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the appropriate shader.
|
||||
/// <para>
|
||||
/// Returns the material shader, if available, otherwise it will take the default shader from the render
|
||||
/// pipeline.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public MaterialShader Shader => Material.CustomShader ?? ActivePipeline._defaultShader;
|
||||
/// <summary>
|
||||
/// Arguments for shaders
|
||||
/// </summary>
|
||||
public IDictionary<string, object> ShaderArguments;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The current world matrix.
|
||||
/// </summary>
|
||||
public Matrix4 World;
|
||||
|
||||
/// <summary>
|
||||
/// The current view matrix.
|
||||
/// </summary>
|
||||
public Matrix4 View;
|
||||
|
||||
/// <summary>
|
||||
/// The current WorldView matrix.
|
||||
/// </summary>
|
||||
public Matrix4 WorldView;
|
||||
|
||||
/// <summary>
|
||||
/// The master model matrix.
|
||||
/// </summary>
|
||||
public Matrix4 ModelMaster;
|
||||
}
|
||||
}
|
||||
32
Legacy/Window/Contexts/UpdateContext.cs
Normal file
32
Legacy/Window/Contexts/UpdateContext.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK.Input;
|
||||
using SM.Base.Scene;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Contexts
|
||||
{
|
||||
/// <summary>
|
||||
/// The update context.
|
||||
/// </summary>
|
||||
public struct UpdateContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The delta time.
|
||||
/// </summary>
|
||||
public float Deltatime => SMRenderer.DefaultDeltatime.DeltaTime;
|
||||
|
||||
/// <summary>
|
||||
/// The current keyboard state.
|
||||
/// </summary>
|
||||
public KeyboardState KeyboardState;
|
||||
|
||||
/// <summary>
|
||||
/// The current mouse state.
|
||||
/// </summary>
|
||||
public MouseState MouseState;
|
||||
|
||||
public GenericScene CurrentScene;
|
||||
}
|
||||
}
|
||||
37
Legacy/Window/IGenericWindow.cs
Normal file
37
Legacy/Window/IGenericWindow.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
using System.Drawing;
|
||||
using System.Windows;
|
||||
using OpenTK;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL.Framebuffer;
|
||||
|
||||
namespace SM.Base
|
||||
{
|
||||
public interface IGenericWindow : IFramebufferWindow
|
||||
{
|
||||
bool Loading { get; }
|
||||
float Aspect { get; set; }
|
||||
|
||||
GenericCamera ViewportCamera { get; }
|
||||
bool ForceViewportCamera { get; set; }
|
||||
|
||||
int Width { get; }
|
||||
int Height { get; }
|
||||
|
||||
Rectangle ClientRectangle { get; }
|
||||
Vector2 WorldScale { get; set; }
|
||||
|
||||
void SetWorldScale();
|
||||
}
|
||||
|
||||
public interface IGenericWindow<TScene, TCamera> : IGenericWindow
|
||||
where TScene : GenericScene, new()
|
||||
where TCamera : GenericCamera, new()
|
||||
{
|
||||
TScene CurrentScene { get; }
|
||||
|
||||
RenderPipeline<TScene> RenderPipeline { get; }
|
||||
|
||||
void SetScene(TScene scene);
|
||||
void SetRenderPipeline(RenderPipeline<TScene> renderPipeline);
|
||||
}
|
||||
}
|
||||
150
Legacy/Window/RenderPipeline.cs
Normal file
150
Legacy/Window/RenderPipeline.cs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL.Framebuffer;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base
|
||||
{
|
||||
/// <summary>
|
||||
/// Definition of specific render options.
|
||||
/// </summary>
|
||||
public abstract class RenderPipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, this pipeline was already once activated.
|
||||
/// </summary>
|
||||
public bool IsInitialized { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The window the pipeline is connected to.
|
||||
/// </summary>
|
||||
protected IGenericWindow _window { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The framebuffers, that are used in this Pipeline.
|
||||
/// </summary>
|
||||
public virtual List<Framebuffer> Framebuffers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default shader for the pipeline.
|
||||
/// </summary>
|
||||
protected internal virtual MaterialShader _defaultShader { get; set; }
|
||||
|
||||
public virtual Framebuffer MainFramebuffer { get; protected set; }= Framebuffer.Screen;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the window is loading.
|
||||
/// </summary>
|
||||
protected internal virtual void Load()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the window is resizing.
|
||||
/// </summary>
|
||||
protected internal virtual void Resize()
|
||||
{
|
||||
if (Framebuffers == null) return;
|
||||
|
||||
foreach (var framebuffer in Framebuffers)
|
||||
framebuffer.Dispose();
|
||||
|
||||
Thread.Sleep(50);
|
||||
|
||||
foreach (Framebuffer framebuffer in Framebuffers)
|
||||
{
|
||||
framebuffer.Compile();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Activate(IGenericWindow window)
|
||||
{
|
||||
_window = window;
|
||||
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (_defaultShader == null) _defaultShader = SMRenderer.DefaultMaterialShader;
|
||||
Framebuffers = new List<Framebuffer>();
|
||||
|
||||
Initialization(window);
|
||||
|
||||
Framebuffers.Add(MainFramebuffer);
|
||||
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
Activation(window);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the pipeline was connected to a window.
|
||||
/// </summary>
|
||||
protected internal virtual void Activation(IGenericWindow window)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the pipeline was connected to a window the first time.
|
||||
/// </summary>
|
||||
/// <param name="window"></param>
|
||||
protected internal virtual void Initialization(IGenericWindow window)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the window is unloading.
|
||||
/// </summary>
|
||||
protected internal virtual void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a framebuffer, that has specific (often) required settings already applied.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Framebuffer CreateWindowFramebuffer()
|
||||
{
|
||||
Framebuffer framebuffer = new Framebuffer(window: SMRenderer.CurrentWindow);
|
||||
framebuffer.Append("color", 0);
|
||||
return framebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a render pipeline.
|
||||
/// </summary>
|
||||
/// <typeparam name="TScene">The scene type</typeparam>
|
||||
public abstract class RenderPipeline<TScene> : RenderPipeline
|
||||
where TScene : GenericScene
|
||||
{
|
||||
/// <summary>
|
||||
/// The system to render stuff.
|
||||
/// </summary>
|
||||
internal void Render(ref DrawContext context)
|
||||
{
|
||||
context.ActivePipeline = this;
|
||||
if (context.ActiveScene == null) return;
|
||||
|
||||
RenderProcess(ref context, (TScene)context.ActiveScene);
|
||||
}
|
||||
|
||||
protected abstract void RenderProcess(ref DrawContext context, TScene scene);
|
||||
|
||||
/// <summary>
|
||||
/// Event, that triggers, when the scene in the current window changes.
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
protected internal virtual void SceneChanged(TScene scene)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
111
SMCode/SM.Base/Controls/Keyboard.cs
Normal file
111
SMCode/SM.Base/Controls/Keyboard.cs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Forms;
|
||||
using OpenTK.Input;
|
||||
using SharpDX.Win32;
|
||||
|
||||
namespace SM.Base.Controls
|
||||
{
|
||||
public class Keyboard
|
||||
{
|
||||
internal static KeyboardState? _keyboardState;
|
||||
internal static List<Key> _lastPressedKeys = new List<Key>();
|
||||
|
||||
public static bool IsAnyKeyPressed => _keyboardState?.IsAnyKeyDown == true;
|
||||
|
||||
|
||||
internal static void SetStage()
|
||||
{
|
||||
if (_keyboardState.HasValue)
|
||||
{
|
||||
_lastPressedKeys = new List<Key>();
|
||||
|
||||
foreach (object o in Enum.GetValues(typeof(Key)))
|
||||
{
|
||||
if (_keyboardState.Value[(Key)o]) _lastPressedKeys.Add((Key)o);
|
||||
}
|
||||
}
|
||||
|
||||
_keyboardState = OpenTK.Input.Keyboard.GetState();
|
||||
}
|
||||
|
||||
public static bool IsDown(Key key, bool once = false) => _keyboardState?[key] == true && !(once && _lastPressedKeys.Contains(key));
|
||||
public static bool WasDown(Key key) => _keyboardState?[key] == false && _lastPressedKeys.Contains(key);
|
||||
public static bool IsUp(Key key, bool once = false) => _keyboardState?[key] == false && !(once && !_lastPressedKeys.Contains(key));
|
||||
|
||||
public static bool AreSpecificKeysPressed(int startIndex, int endIndex, bool once = false)
|
||||
{
|
||||
if (startIndex > endIndex)
|
||||
throw new ArgumentException("The startIndex is greater than the endIndex.", nameof(startIndex));
|
||||
|
||||
int length = endIndex - startIndex;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int actualIndex = i + startIndex;
|
||||
Key key = (Key) actualIndex;
|
||||
if (IsDown(key, once)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool AreSpecificKeysPressed(params Key[] keys) => AreSpecificKeysPressed(false, keys);
|
||||
|
||||
public static bool AreSpecificKeysPressed(bool once, params Key[] keys)
|
||||
{
|
||||
foreach (Key key in keys)
|
||||
{
|
||||
if (IsDown(key, once)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool AreSpecificKeysPressed(int startIndex, int endIndex, out Key[] pressedKeys, bool once = false)
|
||||
{
|
||||
if (startIndex > endIndex)
|
||||
throw new ArgumentException("The startIndex is greater than the endIndex.", nameof(startIndex));
|
||||
|
||||
int length = endIndex - startIndex;
|
||||
|
||||
bool success = false;
|
||||
List<Key> keys = new List<Key>();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int actualIndex = i + startIndex;
|
||||
Key key = (Key)actualIndex;
|
||||
if (IsDown(key, once))
|
||||
{
|
||||
keys.Add(key);
|
||||
success = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pressedKeys = keys.ToArray();
|
||||
return success;
|
||||
}
|
||||
|
||||
public static bool AreSpecificKeysPressed(out Key[] pressedKey, params Key[] keys) => AreSpecificKeysPressed(false, out pressedKey, keys);
|
||||
|
||||
public static bool AreSpecificKeysPressed(bool once, out Key[] pressedKeys, params Key[] keys)
|
||||
{
|
||||
List<Key> pressedKey = new List<Key>();
|
||||
bool success = false;
|
||||
|
||||
foreach (Key key in keys)
|
||||
{
|
||||
if (IsDown(key, once))
|
||||
{
|
||||
pressedKey.Add(key);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
pressedKeys = pressedKey.ToArray();
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
#region usings
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Documents;
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -11,41 +15,51 @@ namespace SM.Base.Controls
|
|||
/// Mouse controller
|
||||
/// </summary>
|
||||
/// <typeparam name="TWindow">The type of window this controller is connected to.</typeparam>
|
||||
public class Mouse<TWindow>
|
||||
where TWindow : IGenericWindow
|
||||
public class Mouse
|
||||
{
|
||||
/// <summary>
|
||||
/// The window it is connected to.
|
||||
/// </summary>
|
||||
protected TWindow _window;
|
||||
|
||||
/// <summary>
|
||||
/// The constructor
|
||||
/// </summary>
|
||||
/// <param name="window">The window, its listen to.</param>
|
||||
protected internal Mouse(TWindow window)
|
||||
{
|
||||
_window = window;
|
||||
}
|
||||
internal static MouseState? _mouseState;
|
||||
internal static List<MouseButton> _lastButtonsPressed = new List<MouseButton>();
|
||||
|
||||
/// <summary>
|
||||
/// The current position of the mouse in the screen.
|
||||
/// </summary>
|
||||
public Vector2 InScreen { get; private set; }
|
||||
public static Vector2 InScreen { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current position of the mouse in the screen from 0..1.
|
||||
/// </summary>
|
||||
public Vector2 InScreenNormalized { get; private set; }
|
||||
public static Vector2 InScreenNormalized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The event to update the values.
|
||||
/// </summary>
|
||||
/// <param name="mmea">The event args.</param>
|
||||
protected void MouseMoveEvent(MouseMoveEventArgs mmea)
|
||||
internal static void MouseMoveEvent(MouseMoveEventArgs mmea, IGenericWindow window)
|
||||
{
|
||||
InScreen = new Vector2(mmea.X, mmea.Y);
|
||||
InScreenNormalized = new Vector2(mmea.X / (float) _window.Width, mmea.Y / (float) _window.Height);
|
||||
InScreenNormalized = new Vector2(mmea.X / (float)window.Width, mmea.Y / (float)window.Height);
|
||||
}
|
||||
|
||||
internal static void SetState()
|
||||
{
|
||||
if (_mouseState.HasValue)
|
||||
{
|
||||
_lastButtonsPressed = new List<MouseButton>();
|
||||
|
||||
foreach (object o in Enum.GetValues(typeof(MouseButton)))
|
||||
{
|
||||
if (_mouseState.Value[(MouseButton)o]) _lastButtonsPressed.Add((MouseButton)o);
|
||||
}
|
||||
}
|
||||
|
||||
_mouseState = OpenTK.Input.Mouse.GetState();
|
||||
|
||||
}
|
||||
|
||||
public static bool IsDown(MouseButton button, bool once = false) => _mouseState?[button] == true && !(once && _lastButtonsPressed.Contains(button));
|
||||
|
||||
public static bool IsUp(MouseButton button, bool once = false) =>
|
||||
_mouseState?[button] == false && !(once && !_lastButtonsPressed.Contains(button));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Mesh;
|
||||
|
||||
#endregion
|
||||
|
|
@ -12,17 +13,21 @@ namespace SM.Base.Drawing
|
|||
/// <summary>
|
||||
/// Contains general basis systems for drawing objects.
|
||||
/// </summary>
|
||||
public abstract class DrawingBasis : IShowItem
|
||||
public abstract class DrawingBasis : IShowItem, IModelItem
|
||||
{
|
||||
/// <summary>
|
||||
/// The material it should use.
|
||||
/// </summary>
|
||||
protected Material _material = new Material();
|
||||
public Material Material = new Material();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The mesh it should use.
|
||||
/// </summary>
|
||||
protected GenericMesh _mesh = SMRenderer.DefaultMesh;
|
||||
public GenericMesh Mesh { get; set; } = SMRenderer.DefaultMesh;
|
||||
|
||||
public ShaderArguments ShaderArguments => Material.ShaderArguments;
|
||||
public TextureTransformation TextureTransform = new TextureTransformation();
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Parent { get; set; }
|
||||
|
|
@ -36,15 +41,13 @@ namespace SM.Base.Drawing
|
|||
/// <summary>
|
||||
/// This value determents if the object should draw something.
|
||||
/// </summary>
|
||||
public bool Active = true;
|
||||
public bool Active { get; set; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Draw(DrawContext context)
|
||||
{
|
||||
if (!Active) return;
|
||||
|
||||
context.Material = _material;
|
||||
context.Mesh = _mesh;
|
||||
context.Material = Material;
|
||||
context.Mesh = Mesh;
|
||||
|
||||
DrawContext(ref context);
|
||||
}
|
||||
|
|
@ -65,6 +68,7 @@ namespace SM.Base.Drawing
|
|||
/// <param name="context"></param>
|
||||
protected virtual void DrawContext(ref DrawContext context)
|
||||
{
|
||||
context.TextureMatrix *= TextureTransform.GetMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,19 +76,20 @@ namespace SM.Base.Drawing
|
|||
/// Contains general basis systems for drawing objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTransformation">The transformation type</typeparam>
|
||||
public abstract class DrawingBasis<TTransformation> : DrawingBasis
|
||||
public abstract class DrawingBasis<TTransformation> : DrawingBasis, IShowTransformItem<TTransformation>
|
||||
where TTransformation : GenericTransformation, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// The current transformation.
|
||||
/// </summary>
|
||||
public TTransformation Transform = new TTransformation();
|
||||
public TTransformation Transform { get; set; } = new TTransformation();
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DrawContext(ref DrawContext context)
|
||||
{
|
||||
base.DrawContext(ref context);
|
||||
context.ModelMaster *= Transform.GetMatrix();
|
||||
Transform.LastMaster = context.ModelMatrix;
|
||||
context.ModelMatrix = Transform.MergeMatrix(context.ModelMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,8 @@ namespace SM.Base.Drawing
|
|||
/// </summary>
|
||||
public bool Ignore = false;
|
||||
|
||||
public Matrix4 LastMaster { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the current model matrix.
|
||||
/// </summary>
|
||||
|
|
@ -43,6 +45,11 @@ namespace SM.Base.Drawing
|
|||
return _modelMatrix;
|
||||
}
|
||||
|
||||
public Matrix4 MergeMatrix(Matrix4 matrix)
|
||||
{
|
||||
return GetMatrix() * matrix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the current matrix.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -16,14 +16,6 @@ namespace SM.Base.Drawing
|
|||
/// </summary>
|
||||
public Matrix4 ModelMatrix = Matrix4.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// The texture offset.
|
||||
/// </summary>
|
||||
public Vector2 TexturePosition = Vector2.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The texture scale.
|
||||
/// </summary>
|
||||
public Vector2 TextureScale = Vector2.One;
|
||||
public Matrix3 TextureMatrix = Matrix3.Identity;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenTK.Graphics;
|
||||
using SM.OGL.Texture;
|
||||
|
||||
|
|
@ -26,5 +27,9 @@ namespace SM.Base.Drawing
|
|||
/// The tint or color.
|
||||
/// </summary>
|
||||
public Color4 Tint = Color4.White;
|
||||
|
||||
public ShaderArguments ShaderArguments { get; internal set; } = new ShaderArguments();
|
||||
|
||||
public bool Blending = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Time;
|
||||
using SM.Base.Types;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Shaders;
|
||||
|
||||
namespace SM.Base.Drawing.Particles
|
||||
|
|
|
|||
13
SMCode/SM.Base/Drawing/ShaderArguments.cs
Normal file
13
SMCode/SM.Base/Drawing/ShaderArguments.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
public class ShaderArguments : Dictionary<string, object>
|
||||
{
|
||||
public TType Get<TType>(string name, TType defaultValue = default)
|
||||
{
|
||||
return ContainsKey(name) ? (TType)this[name] : defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,8 @@ namespace SM.Base.Drawing.Text
|
|||
/// </summary>
|
||||
public float FontSize = 12;
|
||||
|
||||
public float Spacing = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The font style.
|
||||
/// <para>Default: <see cref="System.Drawing.FontStyle.Regular" /></para>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -32,13 +33,19 @@ namespace SM.Base.Drawing.Text
|
|||
/// </summary>
|
||||
public float Spacing = 1;
|
||||
|
||||
public float ActualSpacing => Spacing * Font.Spacing;
|
||||
|
||||
public float Width;
|
||||
public float Height;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a text object with a font.
|
||||
/// </summary>
|
||||
/// <param name="font">The font.</param>
|
||||
protected TextDrawingBasis(Font font)
|
||||
{
|
||||
_material.Texture = font;
|
||||
Material.Texture = font;
|
||||
Material.Blending = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -46,10 +53,10 @@ namespace SM.Base.Drawing.Text
|
|||
/// </summary>
|
||||
public Font Font
|
||||
{
|
||||
get => (Font) _material.Texture;
|
||||
get => (Font) Material.Texture;
|
||||
set
|
||||
{
|
||||
_material.Texture = value;
|
||||
Material.Texture = value;
|
||||
GenerateMatrixes();
|
||||
}
|
||||
}
|
||||
|
|
@ -72,8 +79,8 @@ namespace SM.Base.Drawing.Text
|
|||
/// </summary>
|
||||
public Color4 Color
|
||||
{
|
||||
get => _material.Tint;
|
||||
set => _material.Tint = value;
|
||||
get => Material.Tint;
|
||||
set => Material.Tint = value;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -92,15 +99,26 @@ namespace SM.Base.Drawing.Text
|
|||
{
|
||||
if (!Font.WasCompiled) Font.RegenerateTexture();
|
||||
|
||||
_text = _text.Replace("\r\n", "\n").Replace("\t", " ");
|
||||
|
||||
_instances = new Instance[_text.Length];
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
var _last = new CharParameter();
|
||||
for (var i = 0; i < _text.Length; i++)
|
||||
{
|
||||
if (_text[i] == 32)
|
||||
if (_text[i] == ' ')
|
||||
{
|
||||
x += _last.Width * Spacing;
|
||||
x += Font.FontSize * ActualSpacing;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_text[i] == '\n')
|
||||
{
|
||||
y += Font.Height;
|
||||
Width = Math.Max(Width, x);
|
||||
x = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -115,17 +133,19 @@ namespace SM.Base.Drawing.Text
|
|||
}
|
||||
|
||||
var matrix = Matrix4.CreateScale(parameter.Width, Font.Height, 1) *
|
||||
Matrix4.CreateTranslation(x, 0, 0);
|
||||
Matrix4.CreateTranslation(x, -y, 0);
|
||||
_instances[i] = new Instance
|
||||
{
|
||||
ModelMatrix = matrix,
|
||||
TexturePosition = new Vector2(parameter.NormalizedX, 0),
|
||||
TextureScale = new Vector2(parameter.NormalizedWidth, 1)
|
||||
TextureMatrix = TextureTransformation.CalculateMatrix(new Vector2(parameter.NormalizedX, 0), new Vector2(parameter.NormalizedWidth, 1), 0),
|
||||
};
|
||||
|
||||
x += parameter.Width * Spacing;
|
||||
x += parameter.Width * ActualSpacing;
|
||||
_last = parameter;
|
||||
}
|
||||
|
||||
Width = Math.Max(Width, x);
|
||||
Height = y + Font.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
SMCode/SM.Base/Drawing/TextureTransformation.cs
Normal file
26
SMCode/SM.Base/Drawing/TextureTransformation.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using OpenTK;
|
||||
using SM.Base.Types;
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
public class TextureTransformation
|
||||
{
|
||||
public CVector2 Offset = new CVector2(0);
|
||||
public CVector2 Scale = new CVector2(1);
|
||||
public CVector1 Rotation = new CVector1(0);
|
||||
|
||||
public Matrix3 GetMatrix()
|
||||
{
|
||||
return CalculateMatrix(Offset, Scale, Rotation);
|
||||
}
|
||||
|
||||
public static Matrix3 CalculateMatrix(Vector2 offset, Vector2 scale, float rotation)
|
||||
{
|
||||
float radians = MathHelper.DegreesToRadians(rotation);
|
||||
Matrix3 result = Matrix3.CreateScale(scale.X, scale.Y, 1) * Matrix3.CreateRotationZ(radians);
|
||||
result.Row2 = new Vector3(offset.X, offset.Y, 1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ namespace SM.Base
|
|||
|
||||
_logStream = new StreamWriter(path) {AutoFlush = true};
|
||||
|
||||
Write(LogType.Info, $"Activated new log file. ['{path}']");
|
||||
Write(LogType.Info, $"Activate new log file. ['{path}']");
|
||||
}
|
||||
|
||||
internal static void Init()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using SM.OGL.Mesh;
|
|||
|
||||
namespace SM.Base.Objects
|
||||
{
|
||||
public class InstancedMesh : Mesh
|
||||
public class InstancedMesh : Mesh, ILineMesh
|
||||
{
|
||||
public InstancedMesh(PrimitiveType type, string[] enabledAttibute) : base(type)
|
||||
{
|
||||
|
|
@ -26,5 +26,7 @@ namespace SM.Base.Objects
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float LineWidth { get; set; } = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
using System.ComponentModel;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.PostProcess;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Framebuffer;
|
||||
using SM.OGL.Texture;
|
||||
using SM.Utility;
|
||||
|
|
@ -10,37 +13,76 @@ namespace SM.Base.PostEffects
|
|||
{
|
||||
public class BloomEffect : PostProcessEffect
|
||||
{
|
||||
private static BezierCurve _defaultCurve = new BezierCurve(Vector2.UnitY, new Vector2(0.32f, 1), new Vector2(0.432f, 0), new Vector2(1,0));
|
||||
|
||||
private const float _textureScale = .75f;
|
||||
|
||||
private Framebuffer _bloomBuffer1;
|
||||
private Framebuffer _bloomBuffer2;
|
||||
|
||||
private ColorAttachment _xBuffer;
|
||||
private ColorAttachment _yBuffer;
|
||||
|
||||
private PostProcessShader _shader = new PostProcessShader(AssemblyUtility.ReadAssemblyFile("SM.Base.PostEffects.Shaders.bloom_blur.glsl"));
|
||||
private PostProcessShader _mergeShader = new PostProcessShader(AssemblyUtility.ReadAssemblyFile("SM.Base.PostEffects.Shaders.bloom_merge.glsl"));
|
||||
private PostProcessShader _shader = new PostProcessShader(AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath+".bloom_blur.glsl"));
|
||||
private PostProcessShader _mergeShader = new PostProcessShader(AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath+".bloom_merge_vert.glsl"), AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath+".bloom_merge.glsl"));
|
||||
|
||||
private int _bloomLocation;
|
||||
private bool _hdr;
|
||||
private Framebuffer _source;
|
||||
|
||||
public int Iterations = 5;
|
||||
public float Threshold = 0.8f;
|
||||
private BezierCurve _weightCurve ;
|
||||
private float[] _weights;
|
||||
|
||||
public float[] Weights = { 0.227027f, 0.1945946f, 0.1216216f, 0.054054f, 0.016216f };
|
||||
public int Iterations = 1;
|
||||
public float Threshold = .8f;
|
||||
public float Power = 1;
|
||||
|
||||
public BloomEffect(int bloomLocation, bool hdr = false)
|
||||
public bool Enable = true;
|
||||
|
||||
public float MinAmount = 0;
|
||||
public float MaxAmount = 1;
|
||||
public TextureBase AmountMap;
|
||||
public TextureTransformation AmountTransform = new TextureTransformation();
|
||||
|
||||
public BezierCurve WeightCurve
|
||||
{
|
||||
_bloomLocation = bloomLocation;
|
||||
get => _weightCurve;
|
||||
set
|
||||
{
|
||||
_weightCurve = value;
|
||||
UpdateWeights();
|
||||
}
|
||||
}
|
||||
|
||||
public int WeightCurvePickAmount = 4;
|
||||
|
||||
|
||||
public BloomEffect(Framebuffer source = null, bool hdr = false)
|
||||
{
|
||||
_source = source;
|
||||
_hdr = hdr;
|
||||
|
||||
WeightCurve = _defaultCurve;
|
||||
}
|
||||
|
||||
|
||||
private void UpdateWeights()
|
||||
{
|
||||
_weights = new float[WeightCurvePickAmount];
|
||||
|
||||
for (int i = 0; i < WeightCurvePickAmount; i++)
|
||||
{
|
||||
_weights[i] = _weightCurve.CalculatePoint((float)(i + 1) / (WeightCurvePickAmount + 1)).Y;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void InitProcess()
|
||||
{
|
||||
Pipeline.MainFramebuffer.ColorAttachments["color"].PixelInformation = PixelInformation.RGBA_HDR;
|
||||
_source.ColorAttachments["color"].PixelInformation = PixelInformation.RGBA_HDR;
|
||||
|
||||
_bloomBuffer1 = new Framebuffer(SMRenderer.CurrentWindow);
|
||||
_bloomBuffer1 = new Framebuffer(Pipeline.ConnectedWindow, _textureScale);
|
||||
_bloomBuffer1.Append("xBuffer", _xBuffer = new ColorAttachment(0, PixelInformation.RGBA_HDR));
|
||||
_bloomBuffer1.Compile();
|
||||
_bloomBuffer2 = new Framebuffer(SMRenderer.CurrentWindow);
|
||||
_bloomBuffer2 = new Framebuffer(Pipeline.ConnectedWindow, _textureScale);
|
||||
_bloomBuffer2.Append("yBuffer", _yBuffer = new ColorAttachment(0, PixelInformation.RGBA_HDR));
|
||||
_bloomBuffer2.Compile();
|
||||
|
||||
|
|
@ -50,35 +92,51 @@ namespace SM.Base.PostEffects
|
|||
|
||||
public override void Draw(DrawContext context)
|
||||
{
|
||||
Framebuffer target = Framebuffer.GetCurrentlyActive();
|
||||
if (Enable)
|
||||
{
|
||||
GL.Viewport(0,0, (int)(Pipeline.ConnectedWindow.Width * _textureScale), (int)(Pipeline.ConnectedWindow.Height * _textureScale));
|
||||
|
||||
Framebuffer target = Framebuffer.GetCurrentlyActive();
|
||||
bool first = true, hoz = true;
|
||||
int iter = Iterations * 2;
|
||||
for (int i = 0; i < iter; i++)
|
||||
{
|
||||
(hoz ? _bloomBuffer1 : _bloomBuffer2).Activate();
|
||||
|
||||
_shader.Draw(first ? Pipeline.MainFramebuffer.ColorAttachments["color"] : (hoz ? _yBuffer : _xBuffer), collection =>
|
||||
_shader.Draw(collection =>
|
||||
{
|
||||
collection["renderedTexture"].SetTexture(first ? _source.ColorAttachments["color"] : (hoz ? _yBuffer : _xBuffer));
|
||||
collection["RenderScale"].SetUniform1(_textureScale);
|
||||
|
||||
collection["First"].SetUniform1(first);
|
||||
collection["Threshold"].SetUniform1(Threshold);
|
||||
|
||||
collection["Horizontal"].SetUniform1(hoz);
|
||||
|
||||
collection["Weights"].SetUniform1(Weights);
|
||||
collection["WeightCount"].SetUniform1(Weights.Length);
|
||||
collection["Weights"].SetUniform1(_weights);
|
||||
collection["WeightCount"].SetUniform1(WeightCurvePickAmount);
|
||||
collection["Power"].SetUniform1(Power);
|
||||
});
|
||||
|
||||
hoz = !hoz;
|
||||
if (first) first = false;
|
||||
}
|
||||
|
||||
GL.Viewport(Pipeline.ConnectedWindow.ClientRectangle);
|
||||
target.Activate();
|
||||
_mergeShader.Draw(Pipeline.MainFramebuffer.ColorAttachments["color"], collection =>
|
||||
}
|
||||
|
||||
_mergeShader.Draw(collection =>
|
||||
{
|
||||
collection["Scene"].SetTexture(_source.ColorAttachments["color"]);
|
||||
collection["Bloom"].SetTexture(_yBuffer);
|
||||
|
||||
collection["Exposure"].SetUniform1(context.UsedCamera.Exposure);
|
||||
collection["MinAmount"].SetUniform1(MinAmount);
|
||||
collection["MaxAmount"].SetUniform1(MaxAmount);
|
||||
collection["AmountMap"].SetTexture(AmountMap, collection["HasAmountMap"]);
|
||||
collection["TextureTransform"].SetMatrix3(AmountTransform.GetMatrix());
|
||||
|
||||
collection["Exposure"].SetUniform1(context.UseCamera.Exposure);
|
||||
collection["HDR"].SetUniform1(_hdr);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
46
SMCode/SM.Base/PostEffects/PostProcessFinals.cs
Normal file
46
SMCode/SM.Base/PostEffects/PostProcessFinals.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
using System.Windows.Controls;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base.PostProcess;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Framebuffer;
|
||||
using SM.Utility;
|
||||
|
||||
namespace SM.Base.PostEffects
|
||||
{
|
||||
public class PostProcessFinals
|
||||
{
|
||||
static PostProcessShader _hdrExposureShader = new PostProcessShader(AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath+".finalize_hdr.glsl"));
|
||||
static PostProcessShader _gammaShader = new PostProcessShader(AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath + ".finalize_gamma.glsl"));
|
||||
|
||||
public static float Gamma = 2.2f;
|
||||
|
||||
public static void ResolveMultisampledBuffers(Framebuffer multisampledBuffers, Framebuffer target)
|
||||
{
|
||||
multisampledBuffers.Activate(FramebufferTarget.ReadFramebuffer);
|
||||
target.Activate(FramebufferTarget.DrawFramebuffer);
|
||||
GL.BlitFramebuffer(0, 0, (int)multisampledBuffers.Size.X, (int)multisampledBuffers.Size.Y, 0, 0, (int)target.Size.X, (int)target.Size.Y, ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
|
||||
|
||||
target.Activate();
|
||||
}
|
||||
|
||||
public static void FinalizeHDR(ColorAttachment attachment, float exposure)
|
||||
{
|
||||
|
||||
_hdrExposureShader.Draw(u =>
|
||||
{
|
||||
u["Gamma"].SetUniform1(Gamma);
|
||||
u["Exposure"].SetUniform1(exposure);
|
||||
u["Scene"].SetTexture(attachment);
|
||||
});
|
||||
}
|
||||
|
||||
public static void FinalizeGamma(ColorAttachment attachment)
|
||||
{
|
||||
_gammaShader.Draw(u =>
|
||||
{
|
||||
u["Gamma"].SetUniform1(Gamma);
|
||||
u["Scene"].SetTexture(attachment);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
#version 330
|
||||
#define PI 3.14159265359
|
||||
|
||||
uniform sampler2D renderedTexture;
|
||||
uniform float RenderScale;
|
||||
|
||||
uniform bool First;
|
||||
uniform float Threshold;
|
||||
|
|
@ -9,27 +11,35 @@ uniform bool Horizontal;
|
|||
|
||||
uniform float[32] Weights;
|
||||
uniform int WeightCount;
|
||||
uniform float Power;
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
vec4 GetRenderColorOffset(vec2 offset);
|
||||
|
||||
float brightness(vec3 c)
|
||||
{
|
||||
return max(max(c.r, c.g), c.b);
|
||||
}
|
||||
|
||||
float bright;
|
||||
|
||||
float GetWeight(int dif) {
|
||||
return Weights[dif];
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 thres = vec3(First ? Threshold : 0);
|
||||
|
||||
vec2 tex_offset = 1.0 / textureSize(renderedTexture, 0);
|
||||
vec3 result = max(GetRenderColorOffset(vec2(0)).rgb - thres, 0) * Weights[0];
|
||||
vec2 tex_offset = 1.0 / textureSize(renderedTexture, 0) * vec2(Horizontal ? 1 : 0, Horizontal ? 0 : 1);
|
||||
|
||||
vec3 result = max(GetRenderColorOffset(vec2(0)).rgb - thres, 0) * (First ? Power : 1);
|
||||
result *= GetWeight(0);
|
||||
|
||||
if (Horizontal) {
|
||||
for(int i = 1; i < WeightCount; i++) {
|
||||
result += max(GetRenderColorOffset(vec2(tex_offset.x * i, 0)).rgb - thres, 0) * Weights[i];
|
||||
result += max(GetRenderColorOffset(vec2(-tex_offset.x * i, 0)).rgb - thres, 0) * Weights[i];
|
||||
}
|
||||
} else {
|
||||
for(int i = 1; i < WeightCount; i++) {
|
||||
result += GetRenderColorOffset(vec2(0, tex_offset.x * i)).rgb * Weights[i];
|
||||
result += GetRenderColorOffset(vec2(0, -tex_offset.x * i)).rgb * Weights[i];
|
||||
}
|
||||
result += max(GetRenderColorOffset(tex_offset * i).rgb - thres, 0) * (First ? Power : 1) * GetWeight(i);
|
||||
result += max(GetRenderColorOffset(-tex_offset * i).rgb - thres, 0) * (First ? Power : 1) * GetWeight(i);
|
||||
}
|
||||
|
||||
color = vec4(result, 1);
|
||||
}
|
||||
|
|
@ -1,10 +1,16 @@
|
|||
#version 330
|
||||
|
||||
in vec2 vTexture;
|
||||
in vec2 TransformedTexture;
|
||||
|
||||
uniform sampler2D renderedTexture;
|
||||
uniform sampler2D Scene;
|
||||
uniform sampler2D Bloom;
|
||||
|
||||
uniform float MinAmount;
|
||||
uniform float MaxAmount;
|
||||
uniform sampler2D AmountMap;
|
||||
uniform bool HasAmountMap;
|
||||
|
||||
uniform float Exposure;
|
||||
uniform bool HDR;
|
||||
|
||||
|
|
@ -12,10 +18,13 @@ layout(location = 0) out vec4 color;
|
|||
|
||||
void main() {
|
||||
vec3 result = texture(Bloom, vTexture).rgb;
|
||||
if (HasAmountMap) result *= clamp(length(texture(AmountMap, TransformedTexture).rgb) * (MaxAmount - MinAmount) + MinAmount, 0, 1);
|
||||
if (!HDR) {
|
||||
result = vec3(1.0) - exp(-result * Exposure);
|
||||
}
|
||||
result += texture(renderedTexture, vTexture).rgb;
|
||||
|
||||
|
||||
result = texture(Scene, vTexture).rgb + result;
|
||||
|
||||
color = vec4(result, 1);
|
||||
}
|
||||
11
SMCode/SM.Base/PostEffects/Shaders/bloom_merge_vert.glsl
Normal file
11
SMCode/SM.Base/PostEffects/Shaders/bloom_merge_vert.glsl
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#version 330
|
||||
|
||||
layout(location = 1) in vec2 aTex;
|
||||
|
||||
uniform mat3 TextureTransform;
|
||||
|
||||
out vec2 TransformedTexture;
|
||||
|
||||
void vertex() {
|
||||
TransformedTexture = vec2(TextureTransform * vec3(aTex, 1));
|
||||
}
|
||||
12
SMCode/SM.Base/PostEffects/Shaders/finalize_gamma.glsl
Normal file
12
SMCode/SM.Base/PostEffects/Shaders/finalize_gamma.glsl
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#version 330
|
||||
|
||||
in vec2 vTexture;
|
||||
|
||||
uniform sampler2D Scene;
|
||||
uniform float Gamma;
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = vec4(pow(texture(Scene, vTexture).rgb, vec3(1 / Gamma)), 1);
|
||||
}
|
||||
15
SMCode/SM.Base/PostEffects/Shaders/finalize_hdr.glsl
Normal file
15
SMCode/SM.Base/PostEffects/Shaders/finalize_hdr.glsl
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#version 330
|
||||
|
||||
in vec2 vTexture;
|
||||
|
||||
uniform sampler2D Scene;
|
||||
uniform float Exposure;
|
||||
uniform float Gamma;
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
void main() {
|
||||
vec3 result = vec3(1) - exp(-texture(Scene, vTexture).rgb * Exposure);
|
||||
|
||||
color = vec4(pow(result, vec3(1 / Gamma)), 1);
|
||||
}
|
||||
|
|
@ -4,15 +4,11 @@ layout(location = 0) in vec3 aPos;
|
|||
layout(location = 1) in vec2 aTex;
|
||||
|
||||
uniform mat4 MVP;
|
||||
uniform mat4 ModelMatrix;
|
||||
|
||||
out vec2 vTexture;
|
||||
out vec2 FragPos;
|
||||
|
||||
void main() {
|
||||
vTexture = aTex;
|
||||
|
||||
FragPos = vec2(ModelMatrix * vec4(aPos, 1));
|
||||
|
||||
gl_Position = MVP * vec4(aPos, 1);
|
||||
}
|
||||
|
|
@ -4,18 +4,14 @@ layout(location = 0) in vec3 aPos;
|
|||
layout(location = 1) in vec2 aTex;
|
||||
|
||||
uniform mat4 MVP;
|
||||
uniform mat4 ModelMatrix;
|
||||
|
||||
out vec2 vTexture;
|
||||
out vec2 FragPos;
|
||||
|
||||
void vertex();
|
||||
|
||||
void main() {
|
||||
vTexture = aTex;
|
||||
|
||||
FragPos = vec2(ModelMatrix * vec4(aPos, 1));
|
||||
|
||||
gl_Position = MVP * vec4(aPos, 1);
|
||||
|
||||
vertex();
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Objects.Static;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Framebuffer;
|
||||
using SM.OGL.Shaders;
|
||||
|
||||
|
|
@ -16,8 +17,7 @@ namespace SM.Base.PostProcess
|
|||
/// </summary>
|
||||
public abstract class PostProcessEffect
|
||||
{
|
||||
internal static Matrix4 Mvp;
|
||||
internal static Matrix4 Model;
|
||||
public static Matrix4 Mvp = Matrix4.Identity;
|
||||
|
||||
protected RenderPipeline Pipeline;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,45 +42,23 @@ namespace SM.Base.PostProcess
|
|||
fragment.GLSLExtensions.Add(_fragExtensions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the shader without special uniforms.
|
||||
/// </summary>
|
||||
/// <param name="color"></param>
|
||||
public void Draw(ColorAttachment color)
|
||||
{
|
||||
GL.UseProgram(this);
|
||||
GL.BindVertexArray(Plate.Object);
|
||||
|
||||
Uniforms["MVP"].SetMatrix4(PostProcessEffect.Mvp);
|
||||
Uniforms["ModelMatrix"].SetMatrix4(PostProcessEffect.Model);
|
||||
Uniforms["renderedTexture"].SetTexture(color);
|
||||
|
||||
GL.DrawArrays(PrimitiveType.Quads, 0, 4);
|
||||
|
||||
CleanUp();
|
||||
GL.UseProgram(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the shader with special uniforms.
|
||||
/// </summary>
|
||||
/// <param name="color"></param>
|
||||
/// <param name="setUniformAction"></param>
|
||||
public void Draw(ColorAttachment color, Action<UniformCollection> setUniformAction)
|
||||
public void Draw(Action<UniformCollection> setUniformAction)
|
||||
{
|
||||
GL.UseProgram(this);
|
||||
GL.BindVertexArray(Plate.Object);
|
||||
Activate();
|
||||
Plate.Object.Activate();
|
||||
|
||||
Uniforms["MVP"].SetMatrix4(PostProcessEffect.Mvp);
|
||||
Uniforms["ModelMatrix"].SetMatrix4(PostProcessEffect.Model);
|
||||
Uniforms["renderedTexture"].SetTexture(color);
|
||||
|
||||
setUniformAction(Uniforms);
|
||||
|
||||
GL.DrawArrays(PrimitiveType.Quads, 0, 4);
|
||||
|
||||
CleanUp();
|
||||
GL.UseProgram(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -58,15 +58,25 @@
|
|||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Controls\Keyboard.cs" />
|
||||
<Compile Include="Controls\Mouse.cs" />
|
||||
<Compile Include="Drawing\DrawingBasis.cs" />
|
||||
<Compile Include="Drawing\GenericTransformation.cs" />
|
||||
<Compile Include="Drawing\Instance.cs" />
|
||||
<Compile Include="Drawing\MaterialShader.cs" />
|
||||
<Compile Include="Drawing\ShaderArguments.cs" />
|
||||
<Compile Include="Drawing\TextureTransformation.cs" />
|
||||
<Compile Include="PostEffects\PostProcessFinals.cs" />
|
||||
<Compile Include="Shaders\MaterialShader.cs" />
|
||||
<Compile Include="Drawing\Particles\ParticleContext.cs" />
|
||||
<Compile Include="Drawing\Particles\ParticleMovement.cs" />
|
||||
<Compile Include="Drawing\Particles\ParticleStruct.cs" />
|
||||
<Compile Include="Drawing\Particles\ParticleDrawingBasis.cs" />
|
||||
<Compile Include="Shaders\SimpleShader.cs" />
|
||||
<Compile Include="Utility\IInitializable.cs" />
|
||||
<Compile Include="Utility\Util.cs" />
|
||||
<Compile Include="Window\Contexts\DrawContext.cs" />
|
||||
<Compile Include="Window\Contexts\UpdateContext.cs" />
|
||||
<Compile Include="Window\GLWindow.cs" />
|
||||
<Compile Include="Log.cs" />
|
||||
<Compile Include="Objects\InstancedMesh.cs" />
|
||||
<Compile Include="Objects\Mesh.cs" />
|
||||
|
|
@ -80,7 +90,7 @@
|
|||
<Compile Include="Drawing\Material.cs" />
|
||||
<Compile Include="Scene\IBackgroundItem.cs" />
|
||||
<Compile Include="Scene\GenericItemCollection.cs" />
|
||||
<Compile Include="ShaderExtension\ExtensionManager.cs" />
|
||||
<Compile Include="Shaders\Extensions\ExtensionManager.cs" />
|
||||
<Compile Include="SMRenderer.cs" />
|
||||
<Compile Include="Textures\Texture.cs" />
|
||||
<Compile Include="Drawing\Text\CharParameter.cs" />
|
||||
|
|
@ -98,20 +108,17 @@
|
|||
<Compile Include="Utility\Randomize.cs" />
|
||||
<Compile Include="Utility\RotationUtility.cs" />
|
||||
<Compile Include="Utility\ShaderUtility.cs" />
|
||||
<Compile Include="Window\Contexts\DrawContext.cs" />
|
||||
<Compile Include="Window\Contexts\UpdateContext.cs" />
|
||||
<Compile Include="Window\GenericWindow.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Scene\GenericCamera.cs" />
|
||||
<Compile Include="Scene\GenericScene.cs" />
|
||||
<Compile Include="Objects\Static\Plate.cs" />
|
||||
<Compile Include="Window\GenericWindowCode.cs" />
|
||||
<Compile Include="Window\GenericWPFWindow.cs" />
|
||||
<Compile Include="Window\IGenericWindow.cs" />
|
||||
<Compile Include="Window\ISetup.cs" />
|
||||
<Compile Include="Window\RenderPipeline.cs" />
|
||||
<Compile Include="Window\WindowCode.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ShaderExtension\vertex\basic.vert" />
|
||||
<EmbeddedResource Include="Shaders\Extensions\vertex\basic.vert" />
|
||||
<EmbeddedResource Include="PostProcess\DefaultFiles\vertexFile.vert" />
|
||||
<EmbeddedResource Include="PostProcess\DefaultFiles\extensions.frag" />
|
||||
</ItemGroup>
|
||||
|
|
@ -121,9 +128,7 @@
|
|||
<Name>SM.OGL</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="ShaderExtension\fragment\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="PostProcess\DefaultFiles\vertexWithExt.vert" />
|
||||
</ItemGroup>
|
||||
|
|
@ -134,6 +139,13 @@
|
|||
<ItemGroup>
|
||||
<None Include="OpenTK.dll.config" />
|
||||
<None Include="packages.config" />
|
||||
<EmbeddedResource Include="Shaders\SimpleShaderPresets\basic_vertex.glsl" />
|
||||
<EmbeddedResource Include="Shaders\SimpleShaderPresets\instanced_vertex.glsl" />
|
||||
<EmbeddedResource Include="PostEffects\Shaders\bloom_merge_vert.glsl" />
|
||||
<EmbeddedResource Include="PostEffects\Shaders\finalize_hdr.glsl" />
|
||||
<EmbeddedResource Include="PostEffects\Shaders\finalize_gamma.glsl" />
|
||||
<EmbeddedResource Include="Shaders\Extensions\fragment\textureGamma.glsl" />
|
||||
<EmbeddedResource Include="Shaders\Extensions\fragment\noise.glsl" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
5
SMCode/SM.Base/SM.Base.csproj.DotSettings
Normal file
5
SMCode/SM.Base/SM.Base.csproj.DotSettings
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">Latest</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=windows/@EntryIndexedValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=windows_005Ccontexts/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=window_005Ccontexts/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
|
@ -4,6 +4,7 @@ using SM.Base.Drawing;
|
|||
using SM.Base.Drawing.Text;
|
||||
using SM.Base.Objects.Static;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Mesh;
|
||||
using SM.OGL.Shaders;
|
||||
using SM.Utility;
|
||||
|
|
@ -17,6 +18,8 @@ namespace SM.Base
|
|||
/// </summary>
|
||||
public class SMRenderer
|
||||
{
|
||||
internal const string PostProcessPath = "SM.Base.PostEffects.Shaders";
|
||||
|
||||
/// <summary>
|
||||
/// Defines, how many instances the 'SM_base_vertex_basic'-extension can handle.
|
||||
/// </summary>
|
||||
|
|
@ -50,7 +53,7 @@ namespace SM.Base
|
|||
/// <summary>
|
||||
/// Current Frame
|
||||
/// </summary>
|
||||
public static ulong CurrentFrame { get; internal set; } = 0;
|
||||
public static ulong CurrentFrame { get; internal set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the current active window.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -11,48 +12,44 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
public abstract class GenericCamera
|
||||
{
|
||||
/// <summary>
|
||||
/// The matrix for the orthographic world.
|
||||
/// </summary>
|
||||
public static Matrix4 OrthographicWorld { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The matrix for the perspective world.
|
||||
/// </summary>
|
||||
public static Matrix4 PerspectiveWorld { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// This defines what is up. (Normalized)
|
||||
/// <para>Default: <see cref="Vector3.UnitY" /></para>
|
||||
/// </summary>
|
||||
public static Vector3 UpVector { get; set; } = Vector3.UnitY;
|
||||
public Vector3 UpVector { get; set; } = Vector3.UnitY;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the world matrix that is connected to this camera.
|
||||
/// </summary>
|
||||
public Matrix4 World { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the view matrix of this camera.
|
||||
/// <para>Default: <see cref="Matrix4.Identity" /></para>
|
||||
/// </summary>
|
||||
public Matrix4 ViewMatrix { get; protected set; } = Matrix4.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the world matrix that is connected to this camera.
|
||||
/// </summary>
|
||||
public Matrix4 World => Orthographic ? OrthographicWorld : PerspectiveWorld;
|
||||
public Matrix4 View { get; protected set; } = Matrix4.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// Represents if the camera is orthographic.
|
||||
/// </summary>
|
||||
public abstract bool Orthographic { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Exposure defines the exposure to the Scene.
|
||||
/// </summary>
|
||||
public float Exposure = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the view matrix.
|
||||
/// </summary>
|
||||
/// <returns>The calculated view matrix. Same as <see cref="ViewMatrix" /></returns>
|
||||
internal Matrix4 CalculateViewMatrix()
|
||||
/// <returns>The calculated view matrix. Same as <see cref="View" /></returns>
|
||||
internal void CalculateViewMatrix(IGenericWindow window)
|
||||
{
|
||||
ViewMatrix = ViewCalculation();
|
||||
return ViewMatrix;
|
||||
View = ViewCalculation(window);
|
||||
if (WorldCalculation(window, out Matrix4 world))
|
||||
{
|
||||
World = world;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -60,16 +57,10 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
/// <returns>
|
||||
/// The new view matrix. This is the returns for <see cref="CalculateViewMatrix" /> and the next value for
|
||||
/// <see cref="ViewMatrix" />.
|
||||
/// <see cref="View" />.
|
||||
/// </returns>
|
||||
protected abstract Matrix4 ViewCalculation();
|
||||
protected abstract Matrix4 ViewCalculation(IGenericWindow window);
|
||||
|
||||
/// <summary>
|
||||
/// This will calculate the world.
|
||||
/// <para>This is called on <see cref="GenericWindow{TScene,TCamera}.ViewportCamera" /> to calculate the world.</para>
|
||||
/// </summary>
|
||||
/// <param name="world">The world scale</param>
|
||||
/// <param name="aspect">The aspect ratio from the window.</param>
|
||||
public abstract void RecalculateWorld(Vector2 world, float aspect);
|
||||
protected abstract bool WorldCalculation(IGenericWindow window, out Matrix4 world);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using SM.Base.Contexts;
|
||||
using OpenTK;
|
||||
using SM.Base;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -12,9 +14,7 @@ namespace SM.Base.Scene
|
|||
/// <summary>
|
||||
/// Contains a list of show items.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of show items.</typeparam>
|
||||
public abstract class GenericItemCollection<TItem> : List<TItem>, IShowItem, IShowCollection<TItem>, IScriptable
|
||||
where TItem : IShowItem
|
||||
public abstract class GenericItemCollection : List<IShowItem>, IShowItem, IShowCollection, IScriptable
|
||||
{
|
||||
private List<IScriptable> _scriptableObjects = new List<IScriptable>();
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
public ReadOnlyCollection<IScriptable> ScriptableObjects => new ReadOnlyCollection<IScriptable>(_scriptableObjects);
|
||||
/// <inheritdoc />
|
||||
public List<TItem> Objects => this;
|
||||
public List<IShowItem> Objects => this;
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Parent { get; set; }
|
||||
|
|
@ -34,21 +34,33 @@ namespace SM.Base.Scene
|
|||
/// <inheritdoc />
|
||||
public ICollection<string> Flags { get; set; } = new List<string>() {"collection"};
|
||||
|
||||
public bool Active { get; set; } = true;
|
||||
public bool UpdateActive { get; set; } = true;
|
||||
public bool RenderActive { get; set; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void Update(UpdateContext context)
|
||||
{
|
||||
if (!Active || !UpdateActive) return;
|
||||
|
||||
for (var i = 0; i < _scriptableObjects.Count; i++)
|
||||
{
|
||||
if (!_scriptableObjects[i].Active) continue;
|
||||
_scriptableObjects[i].Update(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IShowCollection{TItem}.Draw" />
|
||||
/// <inheritdoc cref="IShowCollection.Draw" />
|
||||
public virtual void Draw(DrawContext context)
|
||||
{
|
||||
context.LastPassthough = this;
|
||||
if (!Active || !RenderActive) return;
|
||||
|
||||
for (var i = 0; i < Objects.Count; i++)
|
||||
{
|
||||
if (!this[i].Active) continue;
|
||||
this[i].Draw(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void OnAdded(object sender)
|
||||
|
|
@ -63,20 +75,22 @@ namespace SM.Base.Scene
|
|||
/// <summary>
|
||||
/// Adds a item to the draw and the script collection, when applicable.
|
||||
/// </summary>
|
||||
public new void Add(TItem item)
|
||||
public new void Add(params IShowItem[] items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
AddObject(item);
|
||||
|
||||
if (item is IScriptable scriptable)
|
||||
AddScript(scriptable);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the object to the collection.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void AddObject(TItem item)
|
||||
public void AddObject(IShowItem item)
|
||||
{
|
||||
base.Add(item);
|
||||
item.Parent = this;
|
||||
|
|
@ -91,23 +105,22 @@ namespace SM.Base.Scene
|
|||
_scriptableObjects.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a item from the draw and script collection, when applicable.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public new void Remove(TItem item)
|
||||
public new void Remove(params IShowItem[] items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
RemoveObject(item);
|
||||
|
||||
if (item.GetType().IsAssignableFrom(typeof(IScriptable)))
|
||||
RemoveScript((IScriptable)item);
|
||||
if (item is IScriptable scriptable)
|
||||
RemoveScript(scriptable);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the object from the draw collection.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void RemoveObject(TItem item)
|
||||
public void RemoveObject(IShowItem item)
|
||||
{
|
||||
base.Remove(item);
|
||||
item.Parent = null;
|
||||
|
|
@ -123,15 +136,27 @@ namespace SM.Base.Scene
|
|||
_scriptableObjects.Remove(item);
|
||||
}
|
||||
|
||||
public ICollection<IShowItem> GetAllItems(bool includeCollections = false)
|
||||
{
|
||||
List<IShowItem> items = new List<IShowItem>();
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (!includeCollections && this[i] is IShowCollection) continue;
|
||||
items.Add(this[i]);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a object with this name or the default, if not available.
|
||||
/// <para>Not reclusive.</para>
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public TItem GetItemByName(string name)
|
||||
public IShowItem GetItemByName(string name)
|
||||
{
|
||||
TItem obj = default;
|
||||
IShowItem obj = default;
|
||||
for (var i = 0; i < Count; i++)
|
||||
if (this[i].Name == name)
|
||||
{
|
||||
|
|
@ -148,7 +173,7 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
/// <typeparam name="TGetItem">Type of return</typeparam>
|
||||
public TGetItem GetItemByName<TGetItem>(string name)
|
||||
where TGetItem : TItem
|
||||
where TGetItem : IShowItem
|
||||
{
|
||||
return (TGetItem) GetItemByName(name);
|
||||
}
|
||||
|
|
@ -157,9 +182,9 @@ namespace SM.Base.Scene
|
|||
/// Returns all object that have this flag.
|
||||
/// <para>Only in this list.</para>
|
||||
/// </summary>
|
||||
public ICollection<TItem> GetItemsWithFlag(string flag)
|
||||
public ICollection<IShowItem> GetItemsWithFlag(string flag)
|
||||
{
|
||||
var list = new List<TItem>();
|
||||
var list = new List<IShowItem>();
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
var obj = this[i];
|
||||
|
|
@ -176,19 +201,19 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of show items.</typeparam>
|
||||
/// <typeparam name="TTransformation">The type of transformation.</typeparam>
|
||||
public abstract class GenericItemCollection<TItem, TTransformation> : GenericItemCollection<TItem>
|
||||
where TItem : IShowItem
|
||||
public abstract class GenericItemCollection<TTransformation> : GenericItemCollection, IShowTransformItem<TTransformation>
|
||||
where TTransformation : GenericTransformation, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Transformation of the collection
|
||||
/// </summary>
|
||||
public TTransformation Transform = new TTransformation();
|
||||
public TTransformation Transform { get; set; } = new TTransformation();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw(DrawContext context)
|
||||
{
|
||||
context.ModelMaster = Transform.GetMatrix() * context.ModelMaster;
|
||||
Transform.LastMaster = context.ModelMatrix;
|
||||
context.ModelMatrix = Transform.MergeMatrix(context.ModelMatrix);
|
||||
|
||||
base.Draw(context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using SM.Base.Contexts;
|
||||
using System.Windows.Controls;
|
||||
using SM.Base;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Windows;
|
||||
using SM.Utility;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -13,8 +16,11 @@ namespace SM.Base.Scene
|
|||
/// <summary>
|
||||
/// A generic scene, that imports functions for scene control.
|
||||
/// </summary>
|
||||
public abstract class GenericScene
|
||||
public abstract class GenericScene : IInitializable
|
||||
{
|
||||
|
||||
private GenericItemCollection _hud;
|
||||
private GenericItemCollection _objectCollection;
|
||||
private IBackgroundItem _background;
|
||||
private Dictionary<Type, object> _extensions = new Dictionary<Type, object>();
|
||||
|
||||
|
|
@ -32,10 +38,30 @@ namespace SM.Base.Scene
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The active camera, that is used if the context doesn't force the viewport camera.
|
||||
/// <para>If none set, it automaticly uses the viewport camera.</para>
|
||||
/// Objects inside the scene.
|
||||
/// </summary>
|
||||
internal GenericCamera _camera { get; set; }
|
||||
public GenericItemCollection Objects
|
||||
{
|
||||
get => _objectCollection;
|
||||
set
|
||||
{
|
||||
value.Parent = this;
|
||||
_objectCollection = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This defines the HUD objects.
|
||||
/// </summary>
|
||||
public GenericItemCollection HUD
|
||||
{
|
||||
get => _hud;
|
||||
set
|
||||
{
|
||||
value.Parent = this;
|
||||
_hud = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A collection for cameras to switch easier to different cameras.
|
||||
|
|
@ -45,15 +71,38 @@ namespace SM.Base.Scene
|
|||
/// <summary>
|
||||
/// If true, the scene was already initialized.
|
||||
/// </summary>
|
||||
public bool IsInitialized { get; private set; }
|
||||
public bool IsInitialized { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// If true, shows a axis helper at (0,0,0)
|
||||
/// </summary>
|
||||
public bool ShowAxisHelper { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The active camera, that is used if the context doesn't force the viewport camera.
|
||||
/// <para>If none set, it automaticly uses the viewport camera.</para>
|
||||
/// </summary>
|
||||
public GenericCamera Camera { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A camera to control the background.
|
||||
/// </summary>
|
||||
public GenericCamera BackgroundCamera { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A camera to control the HUD.
|
||||
/// </summary>
|
||||
public GenericCamera HUDCamera { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates this scene.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public virtual void Update(UpdateContext context)
|
||||
{
|
||||
_objectCollection?.Update(context);
|
||||
_hud?.Update(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -61,6 +110,52 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
public virtual void Draw(DrawContext context)
|
||||
{
|
||||
DrawBackground(context);
|
||||
|
||||
DrawMainObjects(context);
|
||||
|
||||
DrawHUD(context);
|
||||
DrawDebug(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws only the background.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void DrawBackground(DrawContext context)
|
||||
{
|
||||
var backgroundDrawContext = context;
|
||||
backgroundDrawContext.SetCamera(BackgroundCamera);
|
||||
_Background?.Draw(backgroundDrawContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws only the main objects
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void DrawMainObjects(DrawContext context)
|
||||
{
|
||||
if (!context.Window.ForceViewportCamera && Camera != null) context.SetCamera(Camera);
|
||||
_objectCollection.Draw(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws only the HUD
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void DrawHUD(DrawContext context)
|
||||
{
|
||||
context.SetCamera(HUDCamera);
|
||||
_hud?.Draw(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the debug informations.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public virtual void DrawDebug(DrawContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -90,31 +185,18 @@ namespace SM.Base.Scene
|
|||
return (T)ext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called, when the user activates the scene.
|
||||
/// </summary>
|
||||
internal void Activate()
|
||||
|
||||
public virtual void Activate()
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
OnInitialization();
|
||||
IsInitialized = true;
|
||||
|
||||
}
|
||||
|
||||
OnActivating();
|
||||
public virtual void Initialization()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called, when the user activates the scene for the first time.
|
||||
/// </summary>
|
||||
protected virtual void OnInitialization()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Called, when the user activates the scene.
|
||||
/// </summary>
|
||||
protected virtual void OnActivating()
|
||||
{ }
|
||||
public virtual void Deactivate() {}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -123,117 +205,43 @@ namespace SM.Base.Scene
|
|||
/// <typeparam name="TCamera">The type of cameras.</typeparam>
|
||||
/// <typeparam name="TItem">The type of show items.</typeparam>
|
||||
/// <typeparam name="TCollection">The type for collections</typeparam>
|
||||
public abstract class GenericScene<TCamera, TCollection, TItem> : GenericScene
|
||||
public abstract class GenericScene<TCamera, TCollection> : GenericScene
|
||||
where TCamera : GenericCamera, new()
|
||||
where TCollection : GenericItemCollection<TItem>, new()
|
||||
where TItem : IShowItem
|
||||
where TCollection : GenericItemCollection, new()
|
||||
{
|
||||
private TCollection _hud = new TCollection();
|
||||
private TCollection _objectCollection = new TCollection();
|
||||
|
||||
/// <summary>
|
||||
/// If true, shows a axis helper at (0,0,0)
|
||||
/// </summary>
|
||||
public bool ShowAxisHelper { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The active camera, that is used if the context doesn't force the viewport camera.
|
||||
/// <para>If none set, it automaticly uses the viewport camera.</para>
|
||||
/// </summary>
|
||||
public TCamera Camera => (TCamera) _camera;
|
||||
|
||||
/// <summary>
|
||||
/// A camera to control the background.
|
||||
/// </summary>
|
||||
public TCamera BackgroundCamera { get; set; } = new TCamera();
|
||||
|
||||
/// <summary>
|
||||
/// A camera to control the HUD.
|
||||
/// </summary>
|
||||
public TCamera HUDCamera { get; set; } = new TCamera();
|
||||
|
||||
/// <summary>
|
||||
/// Objects inside the scene.
|
||||
/// </summary>
|
||||
public TCollection Objects
|
||||
public new TCollection Objects
|
||||
{
|
||||
get => _objectCollection;
|
||||
set
|
||||
get => (TCollection) base.Objects;
|
||||
set => base.Objects = value;
|
||||
}
|
||||
|
||||
public new TCollection HUD
|
||||
{
|
||||
value.Parent = this;
|
||||
_objectCollection = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This defines the HUD objects.
|
||||
/// </summary>
|
||||
public TCollection HUD
|
||||
get
|
||||
{
|
||||
get => _hud;
|
||||
set
|
||||
base.HUD ??= new TCollection();
|
||||
return (TCollection) base.HUD;
|
||||
}
|
||||
set => base.HUD = value;
|
||||
}
|
||||
|
||||
public new TCamera Camera
|
||||
{
|
||||
value.Parent = this;
|
||||
_hud = value;
|
||||
}
|
||||
get => (TCamera) base.Camera;
|
||||
set => base.Camera = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(UpdateContext context)
|
||||
public new TCamera HUDCamera
|
||||
{
|
||||
_objectCollection.Update(context);
|
||||
_hud.Update(context);
|
||||
get => (TCamera) base.HUDCamera;
|
||||
set => base.HUDCamera = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw(DrawContext context)
|
||||
public new TCamera BackgroundCamera
|
||||
{
|
||||
DrawBackground(context);
|
||||
|
||||
DrawMainObjects(context);
|
||||
|
||||
DrawHUD(context);
|
||||
DrawDebug(context);
|
||||
get => (TCamera) base.BackgroundCamera;
|
||||
set => base.BackgroundCamera = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws only the background.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void DrawBackground(DrawContext context)
|
||||
{
|
||||
var backgroundDrawContext = context;
|
||||
backgroundDrawContext.View = BackgroundCamera.CalculateViewMatrix();
|
||||
_Background?.Draw(backgroundDrawContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws only the main objects
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void DrawMainObjects(DrawContext context)
|
||||
{
|
||||
if (!context.ForceViewport && Camera != null) context.View = Camera.CalculateViewMatrix();
|
||||
_objectCollection.Draw(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws only the HUD
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void DrawHUD(DrawContext context)
|
||||
{
|
||||
context.View = HUDCamera.CalculateViewMatrix();
|
||||
_hud.Draw(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the debug informations.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public virtual void DrawDebug(DrawContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Windows;
|
||||
|
||||
namespace SM.Base.Scene
|
||||
{
|
||||
|
|
@ -7,6 +8,8 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
public interface IScriptable
|
||||
{
|
||||
bool Active { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the object.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -11,12 +12,12 @@ namespace SM.Base.Scene
|
|||
/// Adds functions, that is required for a collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of show item.</typeparam>
|
||||
public interface IShowCollection<TItem> where TItem : IShowItem
|
||||
public interface IShowCollection
|
||||
{
|
||||
/// <summary>
|
||||
/// The object collection.
|
||||
/// </summary>
|
||||
List<TItem> Objects { get; }
|
||||
List<IShowItem> Objects { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This draws the objects in the <see cref="Objects" /> list.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Mesh;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -27,6 +30,8 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
ICollection<string> Flags { get; set; }
|
||||
|
||||
bool Active { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tells the object to draw its object.
|
||||
/// </summary>
|
||||
|
|
@ -43,4 +48,19 @@ namespace SM.Base.Scene
|
|||
/// </summary>
|
||||
void OnRemoved(object sender);
|
||||
}
|
||||
|
||||
public interface ITransformItem<TTransform>
|
||||
where TTransform : GenericTransformation
|
||||
{
|
||||
TTransform Transform { get; set; }
|
||||
}
|
||||
|
||||
public interface IShowTransformItem<TTransform> : IShowItem, ITransformItem<TTransform>
|
||||
where TTransform : GenericTransformation
|
||||
{}
|
||||
|
||||
public interface IModelItem
|
||||
{
|
||||
GenericMesh Mesh { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ namespace SM.Base.ShaderExtension
|
|||
{
|
||||
internal static void InitExtensions()
|
||||
{
|
||||
ShaderExtensions.AddAssemblyExtensions("SM_base", "SM.Base.ShaderExtension");
|
||||
ShaderExtensions.AddAssemblyExtensions("SM_base", "SM.Base.Shaders.Extensions");
|
||||
|
||||
ShaderExtensions.Extensions["SM_base_vertex_basic"].StringOverrides["instanceMax"] =
|
||||
SMRenderer.MaxInstances.ToString();
|
||||
71
SMCode/SM.Base/Shaders/Extensions/fragment/noise.glsl
Normal file
71
SMCode/SM.Base/Shaders/Extensions/fragment/noise.glsl
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#version 330
|
||||
|
||||
// Permute
|
||||
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }
|
||||
vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
|
||||
|
||||
// Classic Perlin 2D Noise
|
||||
// by Stefan Gustavson
|
||||
vec2 fade(vec2 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}
|
||||
|
||||
float ClassicPerlinNoise(vec2 P){
|
||||
vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
|
||||
vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
|
||||
Pi = mod(Pi, 289.0); // To avoid truncation effects in permutation
|
||||
vec4 ix = Pi.xzxz;
|
||||
vec4 iy = Pi.yyww;
|
||||
vec4 fx = Pf.xzxz;
|
||||
vec4 fy = Pf.yyww;
|
||||
vec4 i = permute(permute(ix) + iy);
|
||||
vec4 gx = 2.0 * fract(i * 0.0243902439) - 1.0; // 1/41 = 0.024...
|
||||
vec4 gy = abs(gx) - 0.5;
|
||||
vec4 tx = floor(gx + 0.5);
|
||||
gx = gx - tx;
|
||||
vec2 g00 = vec2(gx.x,gy.x);
|
||||
vec2 g10 = vec2(gx.y,gy.y);
|
||||
vec2 g01 = vec2(gx.z,gy.z);
|
||||
vec2 g11 = vec2(gx.w,gy.w);
|
||||
vec4 norm = 1.79284291400159 - 0.85373472095314 *
|
||||
vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11));
|
||||
g00 *= norm.x;
|
||||
g01 *= norm.y;
|
||||
g10 *= norm.z;
|
||||
g11 *= norm.w;
|
||||
float n00 = dot(g00, vec2(fx.x, fy.x));
|
||||
float n10 = dot(g10, vec2(fx.y, fy.y));
|
||||
float n01 = dot(g01, vec2(fx.z, fy.z));
|
||||
float n11 = dot(g11, vec2(fx.w, fy.w));
|
||||
vec2 fade_xy = fade(Pf.xy);
|
||||
vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
|
||||
float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
|
||||
return 2.3 * n_xy;
|
||||
}
|
||||
|
||||
// Simplex 2D noise
|
||||
|
||||
float SimplexNoise(vec2 v){
|
||||
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
|
||||
-0.577350269189626, 0.024390243902439);
|
||||
vec2 i = floor(v + dot(v, C.yy) );
|
||||
vec2 x0 = v - i + dot(i, C.xx);
|
||||
vec2 i1;
|
||||
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
||||
vec4 x12 = x0.xyxy + C.xxzz;
|
||||
x12.xy -= i1;
|
||||
i = mod(i, 289.0);
|
||||
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
|
||||
+ i.x + vec3(0.0, i1.x, 1.0 ));
|
||||
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
|
||||
dot(x12.zw,x12.zw)), 0.0);
|
||||
m = m*m ;
|
||||
m = m*m ;
|
||||
vec3 x = 2.0 * fract(p * C.www) - 1.0;
|
||||
vec3 h = abs(x) - 0.5;
|
||||
vec3 ox = floor(x + 0.5);
|
||||
vec3 a0 = x - ox;
|
||||
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
|
||||
vec3 g;
|
||||
g.x = a0.x * x0.x + h.x * x0.y;
|
||||
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
|
||||
return 130.0 * dot(m, g);
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#version 330
|
||||
|
||||
uniform float Gamma;
|
||||
|
||||
vec4 texture2DGamma(sampler2D s, vec2 P) {
|
||||
vec4 tex = texture2D(s, P);
|
||||
return vec4(pow(tex.rgb, vec3(Gamma)), tex.a);
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Mesh;
|
||||
using SM.OGL.Shaders;
|
||||
|
||||
#endregion
|
||||
|
|
@ -33,17 +35,22 @@ namespace SM.Base.Drawing
|
|||
/// <param name="context">The context</param>
|
||||
public virtual void Draw(DrawContext context)
|
||||
{
|
||||
GL.UseProgram(this);
|
||||
context.Shader.Activate();
|
||||
|
||||
GL.BindVertexArray(context.Mesh);
|
||||
context.Mesh.Activate();
|
||||
|
||||
if (context.Mesh is ILineMesh lineMesh)
|
||||
GL.LineWidth(context.Material.ShaderArguments.Get("LineWidth", lineMesh.LineWidth));
|
||||
|
||||
if (context.Material.Blending)
|
||||
{
|
||||
GL.Enable(EnableCap.Blend);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
} else GL.Disable(EnableCap.Blend);
|
||||
|
||||
DrawProcess(context);
|
||||
|
||||
CleanUp();
|
||||
|
||||
GL.UseProgram(0);
|
||||
|
||||
context.ShaderArguments.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
118
SMCode/SM.Base/Shaders/SimpleShader.cs
Normal file
118
SMCode/SM.Base/Shaders/SimpleShader.cs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Shaders;
|
||||
using SM.Utility;
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
public class SimpleShader : MaterialShader
|
||||
{
|
||||
public static Dictionary<string, Tuple<ShaderFile, Action<UniformCollection, DrawContext>>> VertexFiles =
|
||||
new Dictionary<string, Tuple<ShaderFile, Action<UniformCollection, DrawContext>>>();
|
||||
|
||||
static ShaderFile _extensionDefineFile = new ShaderFile("#define SM_SIMPLE_EXTENSION");
|
||||
|
||||
static SimpleShader()
|
||||
{
|
||||
VertexFiles.Add("basic", new Tuple<ShaderFile, Action<UniformCollection, DrawContext>>(
|
||||
new ShaderFile(AssemblyUtility.ReadAssemblyFile("SM.Base.Shaders.SimpleShaderPresets.basic_vertex.glsl"))
|
||||
{
|
||||
StringOverrides = {["extension"] = "0"}
|
||||
},
|
||||
BasicSetUniforms
|
||||
));
|
||||
VertexFiles.Add("E_basic", new Tuple<ShaderFile, Action<UniformCollection, DrawContext>>(
|
||||
new ShaderFile(AssemblyUtility.ReadAssemblyFile("SM.Base.Shaders.SimpleShaderPresets.basic_vertex.glsl"))
|
||||
{
|
||||
StringOverrides = {["extension"] = "1"}
|
||||
},
|
||||
BasicSetUniforms
|
||||
));
|
||||
|
||||
VertexFiles.Add("instanced", new Tuple<ShaderFile, Action<UniformCollection, DrawContext>>(
|
||||
new ShaderFile(
|
||||
AssemblyUtility.ReadAssemblyFile("SM.Base.Shaders.SimpleShaderPresets.instanced_vertex.glsl"))
|
||||
{
|
||||
StringOverrides = { ["instanceMax"] = SMRenderer.MaxInstances.ToString(), ["extension"] = "0" }
|
||||
},
|
||||
InstancedSetUniforms
|
||||
));
|
||||
VertexFiles.Add("E_instanced", new Tuple<ShaderFile, Action<UniformCollection, DrawContext>>(
|
||||
new ShaderFile(
|
||||
AssemblyUtility.ReadAssemblyFile("SM.Base.Shaders.SimpleShaderPresets.instanced_vertex.glsl"))
|
||||
{
|
||||
StringOverrides = { ["instanceMax"] = SMRenderer.MaxInstances.ToString(), ["extension"] = "0" }
|
||||
},
|
||||
InstancedSetUniforms
|
||||
));
|
||||
}
|
||||
|
||||
static void BasicSetUniforms(UniformCollection uniforms, DrawContext context)
|
||||
{
|
||||
// Vertex Uniforms
|
||||
uniforms["MVP"].SetMatrix4(context.Instances[0].ModelMatrix * context.ModelMatrix * context.View * context.World);
|
||||
uniforms["MasterTextureMatrix"].SetMatrix3(context.Instances[0].TextureMatrix * context.TextureMatrix);
|
||||
uniforms["HasVColor"]
|
||||
.SetUniform1(context.Mesh.Attributes.Has("color"));
|
||||
|
||||
DrawObject(context.Mesh);
|
||||
}
|
||||
|
||||
static void InstancedSetUniforms(UniformCollection uniforms, DrawContext context)
|
||||
{
|
||||
uniforms["MVP"].SetMatrix4(context.ModelMatrix * context.View * context.World);
|
||||
uniforms["MasterTextureMatrix"].SetMatrix3(context.TextureMatrix);
|
||||
uniforms["HasVColor"]
|
||||
.SetUniform1(context.Mesh.Attributes.Has("color"));
|
||||
|
||||
UniformArray instances = uniforms.GetArray("Instances");
|
||||
|
||||
int shaderInstanceI = 0;
|
||||
for (int i = 0; i < context.Instances.Count; i++)
|
||||
{
|
||||
if (shaderInstanceI > instances.Length - 1)
|
||||
{
|
||||
DrawObject(context.Mesh, instances.Length);
|
||||
shaderInstanceI = 0;
|
||||
}
|
||||
|
||||
var shaderInstance = instances[shaderInstanceI];
|
||||
var instance = context.Instances[i];
|
||||
if (instance == null) continue;
|
||||
shaderInstance["ModelMatrix"].SetMatrix4(instance.ModelMatrix);
|
||||
shaderInstance["TextureMatrix"].SetMatrix3(instance.TextureMatrix);
|
||||
|
||||
shaderInstanceI++;
|
||||
}
|
||||
DrawObject(context.Mesh, shaderInstanceI);
|
||||
}
|
||||
|
||||
private string _vertexPreset;
|
||||
|
||||
public Action<UniformCollection, DrawContext> SetUniform;
|
||||
|
||||
public SimpleShader(string vertexPreset, string fragment, Action<UniformCollection, DrawContext> setUniform) : base(new ShaderFileCollection(VertexFiles[vertexPreset].Item1, new ShaderFile(fragment)))
|
||||
{
|
||||
_vertexPreset = vertexPreset;
|
||||
SetUniform = setUniform;
|
||||
}
|
||||
|
||||
public SimpleShader(string vertexPreset, string vertexExtension, string fragment,
|
||||
Action<UniformCollection, DrawContext> setUniform) : base(new ShaderFileCollection(
|
||||
new[] {VertexFiles["E_"+vertexPreset].Item1, new ShaderFile(vertexExtension)},
|
||||
new[] {new ShaderFile(fragment),}))
|
||||
{
|
||||
_vertexPreset = vertexPreset;
|
||||
SetUniform = setUniform;
|
||||
}
|
||||
|
||||
protected override void DrawProcess(DrawContext context)
|
||||
{
|
||||
SetUniform?.Invoke(Uniforms, context);
|
||||
|
||||
VertexFiles[_vertexPreset].Item2(Uniforms, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
SMCode/SM.Base/Shaders/SimpleShaderPresets/basic_vertex.glsl
Normal file
32
SMCode/SM.Base/Shaders/SimpleShaderPresets/basic_vertex.glsl
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#version 330
|
||||
#define SM_SIMPLE_EXTENSION //!extension
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_Texture;
|
||||
layout(location = 3) in vec4 a_Color;
|
||||
|
||||
uniform bool HasVColor;
|
||||
uniform mat4 MVP;
|
||||
uniform mat3 MasterTextureMatrix;
|
||||
|
||||
out vec3 v_VertexPosition;
|
||||
out vec2 v_TexCoords;
|
||||
out vec4 v_Color;
|
||||
|
||||
#if (SM_SIMPLE_EXTENSION == 1)
|
||||
void v_Extension();
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
v_Color = vec4(1);
|
||||
if (HasVColor) v_Color = a_Color;
|
||||
|
||||
v_TexCoords = vec2(MasterTextureMatrix * vec3(a_Texture, 1));
|
||||
|
||||
v_VertexPosition = a_Position;
|
||||
gl_Position = MVP * vec4(a_Position, 1);
|
||||
|
||||
#if (SM_SIMPLE_EXTENSION == 1)
|
||||
v_Extension();
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#version 330
|
||||
#define maxInstances //!instanceMax
|
||||
#define SM_SIMPLE_EXTENSION //!extension
|
||||
|
||||
struct Instance {
|
||||
mat4 ModelMatrix;
|
||||
mat3 TextureMatrix;
|
||||
};
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_Texture;
|
||||
layout(location = 3) in vec4 a_Color;
|
||||
|
||||
uniform mat4 MVP;
|
||||
uniform mat3 MasterTextureMatrix;
|
||||
uniform Instance[maxInstances] Instances;
|
||||
uniform bool HasVColor;
|
||||
|
||||
out vec3 v_VertexPosition;
|
||||
out vec2 v_TexCoords;
|
||||
out vec4 v_Color;
|
||||
|
||||
#if (SM_SIMPLE_EXTENSION == 1)
|
||||
void v_Extension();
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
v_Color = vec4(1);
|
||||
if (HasVColor) v_Color = a_Color;
|
||||
|
||||
v_TexCoords = vec2(MasterTextureMatrix * Instances[gl_InstanceID].TextureMatrix * vec3(a_Texture, 1));
|
||||
|
||||
v_VertexPosition = a_Position;
|
||||
gl_Position = MVP * Instances[gl_InstanceID].ModelMatrix * vec4(a_Position, 1);
|
||||
|
||||
#if (SM_SIMPLE_EXTENSION == 1)
|
||||
v_Extension();
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
#region usings
|
||||
|
||||
using System;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,11 @@ namespace SM.Base.Types
|
|||
/// <summary>
|
||||
/// X - Component
|
||||
/// </summary>
|
||||
public float X { get; set; }
|
||||
public float X
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The length/magnitute of the vector.
|
||||
|
|
@ -26,6 +30,8 @@ namespace SM.Base.Types
|
|||
/// </remarks>
|
||||
public float LengthSquared => GetLength(true);
|
||||
|
||||
public event Action Changed;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a class vector
|
||||
/// </summary>
|
||||
|
|
@ -63,14 +69,16 @@ namespace SM.Base.Types
|
|||
/// Sets the X-Component.
|
||||
/// </summary>
|
||||
/// <param name="x">X-Component</param>
|
||||
public virtual void Set(float uniform)
|
||||
public virtual void Set(float uniform, bool triggerChanged = true)
|
||||
{
|
||||
X = uniform;
|
||||
if (triggerChanged) TriggerChanged();
|
||||
}
|
||||
|
||||
public virtual void Add(float uniform)
|
||||
public virtual void Add(float uniform, bool triggerChanged = true)
|
||||
{
|
||||
X += uniform;
|
||||
if (triggerChanged) TriggerChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -82,15 +90,20 @@ namespace SM.Base.Types
|
|||
/// </summary>
|
||||
/// <param name="f"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator CVector1(float f) => new CVector1(f);
|
||||
//public static implicit operator CVector1(float f) => new CVector1(f);
|
||||
|
||||
private protected virtual float GetLengthProcess()
|
||||
protected virtual float GetLengthProcess()
|
||||
{
|
||||
return X * X;
|
||||
}
|
||||
private protected virtual void NormalizationProcess(float length)
|
||||
protected virtual void NormalizationProcess(float length)
|
||||
{
|
||||
X *= length;
|
||||
}
|
||||
|
||||
protected void TriggerChanged()
|
||||
{
|
||||
Changed?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,12 +29,12 @@ namespace SM.Base.Types
|
|||
Y = y;
|
||||
}
|
||||
|
||||
private protected override float GetLengthProcess()
|
||||
protected override float GetLengthProcess()
|
||||
{
|
||||
return base.GetLengthProcess() + Y * Y;
|
||||
}
|
||||
|
||||
private protected override void NormalizationProcess(float length)
|
||||
protected override void NormalizationProcess(float length)
|
||||
{
|
||||
base.NormalizationProcess(length);
|
||||
Y *= length;
|
||||
|
|
@ -44,19 +44,19 @@ namespace SM.Base.Types
|
|||
/// Sets each component to the same value
|
||||
/// </summary>
|
||||
/// <param name="uniform"></param>
|
||||
public override void Set(float uniform)
|
||||
public override void Set(float uniform, bool triggerChanged = true)
|
||||
{
|
||||
base.Set(uniform);
|
||||
Y = uniform;
|
||||
base.Set(uniform, triggerChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets each component to the <see cref="Vector2"/> counter-part.
|
||||
/// </summary>
|
||||
/// <param name="vector"></param>
|
||||
public void Set(Vector2 vector)
|
||||
public void Set(Vector2 vector, bool triggerChanged = true)
|
||||
{
|
||||
Set(vector.X, vector.Y);
|
||||
Set(vector.X, vector.Y, triggerChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -64,27 +64,27 @@ namespace SM.Base.Types
|
|||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public void Set(float x, float y)
|
||||
public void Set(float x, float y, bool triggerChanged = true)
|
||||
{
|
||||
base.Set(x);
|
||||
Y = y;
|
||||
base.Set(x, triggerChanged);
|
||||
}
|
||||
|
||||
public override void Add(float uniform)
|
||||
public override void Add(float uniform, bool triggerChanged = true)
|
||||
{
|
||||
base.Add(uniform);
|
||||
Y += uniform;
|
||||
base.Add(uniform, triggerChanged);
|
||||
}
|
||||
|
||||
public void Add(Vector2 vector)
|
||||
public void Add(Vector2 vector, bool triggerChanged = true)
|
||||
{
|
||||
Add(vector.X, vector.Y);
|
||||
Add(vector.X, vector.Y, triggerChanged);
|
||||
}
|
||||
|
||||
public void Add(float x, float y)
|
||||
public void Add(float x, float y, bool triggerChanged = true)
|
||||
{
|
||||
base.Add(x);
|
||||
Y += y;
|
||||
base.Add(x, triggerChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -28,56 +28,56 @@ namespace SM.Base.Types
|
|||
Z = z;
|
||||
}
|
||||
|
||||
private protected override float GetLengthProcess()
|
||||
protected override float GetLengthProcess()
|
||||
{
|
||||
return base.GetLengthProcess() + Z * Z;
|
||||
}
|
||||
|
||||
private protected override void NormalizationProcess(float length)
|
||||
protected override void NormalizationProcess(float length)
|
||||
{
|
||||
base.NormalizationProcess(length);
|
||||
Z *= length;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Set(float uniform)
|
||||
public override void Set(float uniform, bool triggerChanged = true)
|
||||
{
|
||||
base.Set(uniform);
|
||||
Z = uniform;
|
||||
base.Set(uniform, triggerChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the a own value to each component.
|
||||
/// </summary>
|
||||
public void Set(float x, float y, float z)
|
||||
public void Set(float x, float y, float z, bool triggerChanged = true)
|
||||
{
|
||||
base.Set(x,y);
|
||||
Z = z;
|
||||
base.Set(x,y, triggerChanged);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets each component to the <see cref="Vector3"/> counter-part.
|
||||
/// </summary>
|
||||
/// <param name="vector"></param>
|
||||
public void Set(Vector3 vector)
|
||||
public void Set(Vector3 vector, bool triggerChanged = true)
|
||||
{
|
||||
Set(vector.X, vector.Y, vector.Z);
|
||||
Set(vector.X, vector.Y, vector.Z, triggerChanged);
|
||||
}
|
||||
|
||||
public override void Add(float uniform)
|
||||
public override void Add(float uniform, bool triggerChanged = true)
|
||||
{
|
||||
base.Add(uniform);
|
||||
Z += uniform;
|
||||
base.Add(uniform, triggerChanged);
|
||||
}
|
||||
|
||||
public void Add(Vector3 vector)
|
||||
public void Add(Vector3 vector, bool triggerChanged = true)
|
||||
{
|
||||
Add(vector.X, vector.Y, vector.Z);
|
||||
Add(vector.X, vector.Y, vector.Z, triggerChanged);
|
||||
}
|
||||
|
||||
public void Add(float x, float y, float z)
|
||||
public void Add(float x, float y, float z, bool triggerChanged = true)
|
||||
{
|
||||
base.Add(x,y);
|
||||
Z += z;
|
||||
base.Add(x,y, triggerChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
10
SMCode/SM.Base/Utility/IInitializable.cs
Normal file
10
SMCode/SM.Base/Utility/IInitializable.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
namespace SM.Utility
|
||||
{
|
||||
public interface IInitializable
|
||||
{
|
||||
bool IsInitialized { get; set; }
|
||||
|
||||
void Activate();
|
||||
void Initialization();
|
||||
}
|
||||
}
|
||||
15
SMCode/SM.Base/Utility/Util.cs
Normal file
15
SMCode/SM.Base/Utility/Util.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
namespace SM.Utility
|
||||
{
|
||||
public class Util
|
||||
{
|
||||
public static void Activate(IInitializable obj)
|
||||
{
|
||||
if (!obj.IsInitialized)
|
||||
{
|
||||
obj.Initialization();
|
||||
obj.IsInitialized = true;
|
||||
}
|
||||
obj.Activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +1,33 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL.Mesh;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Contexts
|
||||
namespace SM.Base.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains important information for drawing.
|
||||
/// </summary>
|
||||
public struct DrawContext
|
||||
{
|
||||
/// <summary>
|
||||
/// This says if it was forced to use the viewport camera.
|
||||
/// </summary>
|
||||
public bool ForceViewport;
|
||||
public IGenericWindow Window { get; internal set; }
|
||||
public GenericScene Scene { get; internal set; }
|
||||
public RenderPipeline RenderPipeline { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the currently used render pipeline.
|
||||
/// </summary>
|
||||
public RenderPipeline ActivePipeline;
|
||||
public GenericCamera UseCamera { get; internal set; }
|
||||
public Matrix4 World => UseCamera.World;
|
||||
public Matrix4 View => UseCamera.View;
|
||||
|
||||
public GenericScene ActiveScene;
|
||||
public IGenericWindow Window;
|
||||
public GenericMesh Mesh { get; set; }
|
||||
public Material Material { get; set; }
|
||||
public MaterialShader Shader => Material.CustomShader ?? RenderPipeline.DefaultShader;
|
||||
|
||||
|
||||
public GenericCamera UsedCamera =>
|
||||
ForceViewport || ActiveScene._camera == null ? Window.ViewportCamera : ActiveScene._camera;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The mesh.
|
||||
/// </summary>
|
||||
public GenericMesh Mesh;
|
||||
|
||||
/// <summary>
|
||||
/// The material.
|
||||
/// </summary>
|
||||
public Material Material;
|
||||
|
||||
/// <summary>
|
||||
/// The drawing instances.
|
||||
/// <para>If there is only one, it's index 0</para>
|
||||
/// </summary>
|
||||
public Matrix4 ModelMatrix;
|
||||
public Matrix3 TextureMatrix;
|
||||
public IList<Instance> Instances;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The current world scale.
|
||||
/// </summary>
|
||||
public Vector2 WorldScale;
|
||||
|
||||
/// <summary>
|
||||
/// The last collection the context was passed though.
|
||||
/// </summary>
|
||||
public object LastPassthough;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the appropriate shader.
|
||||
/// <para>
|
||||
/// Returns the material shader, if available, otherwise it will take the default shader from the render
|
||||
/// pipeline.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public MaterialShader Shader => Material.CustomShader ?? ActivePipeline._defaultShader;
|
||||
/// <summary>
|
||||
/// Arguments for shaders
|
||||
/// </summary>
|
||||
public IDictionary<string, object> ShaderArguments;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The current world matrix.
|
||||
/// </summary>
|
||||
public Matrix4 World;
|
||||
|
||||
/// <summary>
|
||||
/// The current view matrix.
|
||||
/// </summary>
|
||||
public Matrix4 View;
|
||||
|
||||
/// <summary>
|
||||
/// The current WorldView matrix.
|
||||
/// </summary>
|
||||
public Matrix4 WorldView;
|
||||
|
||||
/// <summary>
|
||||
/// The master model matrix.
|
||||
/// </summary>
|
||||
public Matrix4 ModelMaster;
|
||||
public void SetCamera(GenericCamera camera)
|
||||
{
|
||||
UseCamera = camera;
|
||||
camera.CalculateViewMatrix(Window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,14 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK.Input;
|
||||
using OpenTK.Input;
|
||||
using SM.Base.Scene;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Contexts
|
||||
namespace SM.Base.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// The update context.
|
||||
/// </summary>
|
||||
public struct UpdateContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The delta time.
|
||||
/// </summary>
|
||||
public IGenericWindow Window;
|
||||
|
||||
public float Deltatime => SMRenderer.DefaultDeltatime.DeltaTime;
|
||||
|
||||
/// <summary>
|
||||
/// The current keyboard state.
|
||||
/// </summary>
|
||||
public KeyboardState KeyboardState;
|
||||
|
||||
/// <summary>
|
||||
/// The current mouse state.
|
||||
/// </summary>
|
||||
public MouseState MouseState;
|
||||
|
||||
public GenericScene CurrentScene;
|
||||
public GenericScene Scene;
|
||||
}
|
||||
}
|
||||
130
SMCode/SM.Base/Window/GLWindow.cs
Normal file
130
SMCode/SM.Base/Window/GLWindow.cs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
using SM.Base.Controls;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL;
|
||||
using Mouse = SM.Base.Controls.Mouse;
|
||||
|
||||
namespace SM.Base.Windows
|
||||
{
|
||||
public class GLWindow : GameWindow, IGenericWindow
|
||||
{
|
||||
public bool Loading { get; private set; } = true;
|
||||
public float AspectRatio { get; set; }
|
||||
public float AspectRatioReverse { get; set; }
|
||||
|
||||
public GenericCamera ViewportCamera { get; set; }
|
||||
public bool ForceViewportCamera { get; set; }
|
||||
|
||||
public bool DrawWhileUnfocused { get; set; } = true;
|
||||
public bool UpdateWhileUnfocused { get; set; } = false;
|
||||
|
||||
public Vector2 WindowSize { get; set; }
|
||||
|
||||
public ISetup AppliedSetup { get; private set; }
|
||||
public event Action<IGenericWindow> Resize;
|
||||
public event Action<IGenericWindow> Load;
|
||||
public event Action<IGenericWindow> Loaded;
|
||||
|
||||
public GenericScene CurrentScene { get; private set; }
|
||||
public RenderPipeline CurrentRenderPipeline { get; private set; }
|
||||
|
||||
public GLWindow() : this(1280, 720, "Generic OpenGL Title", GameWindowFlags.Default) {}
|
||||
|
||||
public GLWindow(int width, int height, string title, GameWindowFlags flags, VSyncMode vSync = VSyncMode.On) :
|
||||
base(width, height, default, title, flags, DisplayDevice.Default, GLSettings.ForcedVersion.MajorVersion, GLSettings.ForcedVersion.MinorVersion, GraphicsContextFlags.Default)
|
||||
{
|
||||
VSync = vSync;
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
WindowCode.Load(this);
|
||||
SMRenderer.CurrentWindow = this;
|
||||
|
||||
base.OnLoad(e);
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
|
||||
WindowCode.Resize(this);
|
||||
|
||||
if (Loading)
|
||||
{
|
||||
Loading = false;
|
||||
Loaded?.Invoke(this);
|
||||
AppliedSetup?.Loaded(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||
{
|
||||
if (!Focused && !UpdateWhileUnfocused) return;
|
||||
|
||||
base.OnUpdateFrame(e);
|
||||
|
||||
WindowCode.Update(this, (float)e.Time);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnRenderFrame(FrameEventArgs e)
|
||||
{
|
||||
base.OnRenderFrame(e);
|
||||
|
||||
WindowCode.Render(this, (float)e.Time);
|
||||
|
||||
SwapBuffers();
|
||||
|
||||
GLDebugging.CheckGLErrors();
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseMoveEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
Mouse.MouseMoveEvent(e, this);
|
||||
}
|
||||
|
||||
public void Update(UpdateContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ApplySetup(ISetup setup)
|
||||
{
|
||||
AppliedSetup = setup;
|
||||
setup.Applied(this);
|
||||
}
|
||||
|
||||
public void SetScene(GenericScene scene)
|
||||
{
|
||||
if (Loading)
|
||||
{
|
||||
Loaded += window => SetScene(scene);
|
||||
return;
|
||||
}
|
||||
|
||||
WindowCode.PrepareScene(this, scene);
|
||||
CurrentScene = scene;
|
||||
}
|
||||
|
||||
public void SetRenderPipeline(RenderPipeline renderPipeline)
|
||||
{
|
||||
if (Loading)
|
||||
{
|
||||
Loaded += window => SetRenderPipeline(renderPipeline);
|
||||
return;
|
||||
}
|
||||
|
||||
WindowCode.PreparePipeline(this, renderPipeline);
|
||||
CurrentRenderPipeline = renderPipeline;
|
||||
}
|
||||
|
||||
public void TriggerLoad() => Load?.Invoke(this);
|
||||
|
||||
public void TriggerResize() => Resize?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +1,48 @@
|
|||
using System.Drawing;
|
||||
using System.Windows;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenTK;
|
||||
using SM.Base.Controls;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL.Framebuffer;
|
||||
|
||||
namespace SM.Base
|
||||
namespace SM.Base.Windows
|
||||
{
|
||||
public interface IGenericWindow : IFramebufferWindow
|
||||
{
|
||||
bool Loading { get; }
|
||||
float Aspect { get; set; }
|
||||
float AspectRatio { get; set; }
|
||||
float AspectRatioReverse { get; set; }
|
||||
|
||||
GenericCamera ViewportCamera { get; }
|
||||
GenericCamera ViewportCamera { get; set; }
|
||||
bool ForceViewportCamera { get; set; }
|
||||
|
||||
bool DrawWhileUnfocused { get; set; }
|
||||
bool UpdateWhileUnfocused { get; set; }
|
||||
|
||||
int Width { get; }
|
||||
int Height { get; }
|
||||
Vector2 WindowSize { get; set; }
|
||||
|
||||
Rectangle ClientRectangle { get; }
|
||||
Vector2 WorldScale { get; set; }
|
||||
|
||||
void SetWorldScale();
|
||||
}
|
||||
ISetup AppliedSetup { get; }
|
||||
|
||||
public interface IGenericWindow<TScene, TCamera> : IGenericWindow
|
||||
where TScene : GenericScene, new()
|
||||
where TCamera : GenericCamera, new()
|
||||
{
|
||||
TScene CurrentScene { get; }
|
||||
event Action<IGenericWindow> Resize;
|
||||
event Action<IGenericWindow> Load;
|
||||
|
||||
RenderPipeline<TScene> RenderPipeline { get; }
|
||||
GenericScene CurrentScene { get; }
|
||||
RenderPipeline CurrentRenderPipeline { get; }
|
||||
|
||||
void SetScene(TScene scene);
|
||||
void SetRenderPipeline(RenderPipeline<TScene> renderPipeline);
|
||||
void Update(UpdateContext context);
|
||||
|
||||
void ApplySetup(ISetup setup);
|
||||
|
||||
void SetScene(GenericScene scene);
|
||||
void SetRenderPipeline(RenderPipeline renderPipeline);
|
||||
|
||||
void TriggerLoad();
|
||||
void TriggerResize();
|
||||
|
||||
void Close();
|
||||
}
|
||||
}
|
||||
10
SMCode/SM.Base/Window/ISetup.cs
Normal file
10
SMCode/SM.Base/Window/ISetup.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
namespace SM.Base.Windows
|
||||
{
|
||||
public interface ISetup
|
||||
{
|
||||
void Applied(IGenericWindow window);
|
||||
void Load(IGenericWindow window);
|
||||
void Loaded(IGenericWindow window);
|
||||
void Resize(IGenericWindow window);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +1,57 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL.Framebuffer;
|
||||
using SM.OGL.Texture;
|
||||
using SM.Utility;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base
|
||||
namespace SM.Base.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Definition of specific render options.
|
||||
/// </summary>
|
||||
public abstract class RenderPipeline
|
||||
public abstract class RenderPipeline : IInitializable
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, this pipeline was already once activated.
|
||||
/// </summary>
|
||||
public bool IsInitialized { get; private set; } = false;
|
||||
public IGenericWindow ConnectedWindow { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The window the pipeline is connected to.
|
||||
/// </summary>
|
||||
protected IGenericWindow _window { get; private set; }
|
||||
public Framebuffer MainFramebuffer { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// The framebuffers, that are used in this Pipeline.
|
||||
/// </summary>
|
||||
public virtual List<Framebuffer> Framebuffers { get; private set; }
|
||||
public List<Framebuffer> Framebuffers { get; } = new List<Framebuffer>();
|
||||
|
||||
/// <summary>
|
||||
/// The default shader for the pipeline.
|
||||
/// </summary>
|
||||
protected internal virtual MaterialShader _defaultShader { get; set; }
|
||||
public virtual MaterialShader DefaultShader { get; protected set; }
|
||||
public virtual Material DefaultMaterial { get; protected set; }
|
||||
|
||||
public virtual Framebuffer MainFramebuffer { get; protected set; }= Framebuffer.Screen;
|
||||
public bool IsInitialized { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the window is loading.
|
||||
/// </summary>
|
||||
protected internal virtual void Load()
|
||||
{
|
||||
}
|
||||
internal void Render(ref DrawContext context) => RenderProcess(ref context);
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the window is resizing.
|
||||
/// </summary>
|
||||
protected internal virtual void Resize()
|
||||
protected abstract void RenderProcess(ref DrawContext context);
|
||||
|
||||
public virtual void Resize()
|
||||
{
|
||||
if (Framebuffers == null) return;
|
||||
|
||||
foreach(var framebuffer in Framebuffers)
|
||||
framebuffer.Dispose();
|
||||
|
||||
Thread.Sleep(50);
|
||||
|
||||
foreach (Framebuffer framebuffer in Framebuffers)
|
||||
{
|
||||
foreach(var framebuffer in Framebuffers)
|
||||
framebuffer.Compile();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Activate(IGenericWindow window)
|
||||
{
|
||||
_window = window;
|
||||
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (_defaultShader == null) _defaultShader = SMRenderer.DefaultMaterialShader;
|
||||
Framebuffers = new List<Framebuffer>();
|
||||
|
||||
Initialization(window);
|
||||
|
||||
Framebuffers.Add(MainFramebuffer);
|
||||
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
Activation(window);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the pipeline was connected to a window.
|
||||
/// </summary>
|
||||
protected internal virtual void Activation(IGenericWindow window)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the pipeline was connected to a window the first time.
|
||||
/// </summary>
|
||||
/// <param name="window"></param>
|
||||
protected internal virtual void Initialization(IGenericWindow window)
|
||||
public virtual void Activate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs, when the window is unloading.
|
||||
/// </summary>
|
||||
protected internal virtual void Unload()
|
||||
public virtual void Initialization()
|
||||
{
|
||||
if (MainFramebuffer != null) Framebuffers.Add(MainFramebuffer);
|
||||
DefaultShader ??= SMRenderer.DefaultMaterialShader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a framebuffer, that has specific (often) required settings already applied.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Framebuffer CreateWindowFramebuffer()
|
||||
public Framebuffer CreateWindowFramebuffer(int multisamples)
|
||||
{
|
||||
Framebuffer framebuffer = new Framebuffer(window: SMRenderer.CurrentWindow);
|
||||
framebuffer.Append("color", 0);
|
||||
Framebuffer framebuffer = new Framebuffer(window: ConnectedWindow);
|
||||
framebuffer.Append("color", new ColorAttachment(0, PixelInformation.RGBA_LDR, multisamples));
|
||||
return framebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a render pipeline.
|
||||
/// </summary>
|
||||
/// <typeparam name="TScene">The scene type</typeparam>
|
||||
public abstract class RenderPipeline<TScene> : RenderPipeline
|
||||
where TScene : GenericScene
|
||||
{
|
||||
/// <summary>
|
||||
/// The system to render stuff.
|
||||
/// </summary>
|
||||
internal void Render(ref DrawContext context)
|
||||
{
|
||||
context.ActivePipeline = this;
|
||||
if (context.ActiveScene == null) return;
|
||||
|
||||
RenderProcess(ref context, (TScene)context.ActiveScene);
|
||||
}
|
||||
|
||||
protected abstract void RenderProcess(ref DrawContext context, TScene scene);
|
||||
|
||||
/// <summary>
|
||||
/// Event, that triggers, when the scene in the current window changes.
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
protected internal virtual void SceneChanged(TScene scene)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
133
SMCode/SM.Base/Window/WindowCode.cs
Normal file
133
SMCode/SM.Base/Window/WindowCode.cs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Input;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Objects.Static;
|
||||
using SM.Base.PostProcess;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.ShaderExtension;
|
||||
using SM.Base.Time;
|
||||
using SM.OGL;
|
||||
using SM.Utility;
|
||||
using Keyboard = SM.Base.Controls.Keyboard;
|
||||
|
||||
namespace SM.Base.Windows
|
||||
{
|
||||
internal class WindowCode
|
||||
{
|
||||
internal static void Load(IGenericWindow window)
|
||||
{
|
||||
GLSystem.INIT_SYSTEM();
|
||||
GLSettings.ShaderPreProcessing = true;
|
||||
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
if (args.Contains("--advDebugging"))
|
||||
{
|
||||
SMRenderer.AdvancedDebugging = true;
|
||||
GLSettings.InfoEveryUniform = true;
|
||||
}
|
||||
|
||||
Log.Init();
|
||||
|
||||
Log.Write("#", ConsoleColor.Cyan, "----------------------",
|
||||
"--- OpenGL Loading ---",
|
||||
"----------------------------------",
|
||||
$"--- {"DeviceVersion",14}: {GLSystem.DeviceVersion,-10} ---",
|
||||
$"--- {"ForcedVersion",14}: {GLSettings.ForcedVersion,-10} ---",
|
||||
$"--- {"ShadingVersion",14}: {GLSystem.ShadingVersion,-10} ---",
|
||||
$"--- {"Debugging",14}: {GLSystem.Debugging,-10} ---",
|
||||
$"--- {"AdvDebugging",14}: {SMRenderer.AdvancedDebugging,-10} ---",
|
||||
"----------------------------------");
|
||||
|
||||
if (SMRenderer.AdvancedDebugging) Log.Write("Extension", ConsoleColor.DarkCyan, GLSystem.Extensions);
|
||||
|
||||
ExtensionManager.InitExtensions();
|
||||
|
||||
window.TriggerLoad();
|
||||
window.AppliedSetup?.Load(window);
|
||||
}
|
||||
|
||||
internal static void Resize(IGenericWindow window)
|
||||
{
|
||||
window.WindowSize = new Vector2(window.Width, window.Height);
|
||||
window.AspectRatio = (float) window.Width / window.Height;
|
||||
window.AspectRatioReverse = (float) window.Height / window.Width;
|
||||
GL.Viewport(window.ClientRectangle);
|
||||
|
||||
window.CurrentRenderPipeline?.Resize();
|
||||
|
||||
PostProcessEffect.Mvp = Matrix4.CreateScale(window.Width, -window.Height, 1) *
|
||||
Matrix4.LookAt(Vector3.UnitZ, Vector3.Zero, Vector3.UnitY) *
|
||||
Matrix4.CreateOrthographic(window.Width, window.Height, .1f, 100f);
|
||||
|
||||
window.AppliedSetup?.Resize(window);
|
||||
}
|
||||
|
||||
internal static void Update(IGenericWindow window, float deltatime)
|
||||
{
|
||||
Deltatime.UpdateDelta = deltatime;
|
||||
SM.Base.Controls.Mouse.SetState();
|
||||
Controls.Keyboard.SetStage();
|
||||
var context = new UpdateContext()
|
||||
{
|
||||
Window = window,
|
||||
|
||||
Scene = window.CurrentScene
|
||||
};
|
||||
|
||||
if (Keyboard.IsDown(Key.AltLeft) && Keyboard.IsDown(Key.F4))
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
|
||||
Stopwatch.PerformTicks(context);
|
||||
window.CurrentScene?.Update(context);
|
||||
window.Update(context);
|
||||
}
|
||||
|
||||
internal static void Render(IGenericWindow window, float deltatime)
|
||||
{
|
||||
if (window.CurrentScene == null) return;
|
||||
|
||||
SMRenderer.CurrentFrame++;
|
||||
|
||||
Deltatime.RenderDelta = deltatime;
|
||||
var drawContext = new DrawContext()
|
||||
{
|
||||
Window = window,
|
||||
Scene = window.CurrentScene,
|
||||
RenderPipeline = window.CurrentRenderPipeline,
|
||||
|
||||
Mesh = Plate.Object,
|
||||
Material = window.CurrentRenderPipeline.DefaultMaterial,
|
||||
|
||||
ModelMatrix = Matrix4.Identity,
|
||||
TextureMatrix = Matrix3.Identity,
|
||||
Instances = new Instance[1]
|
||||
{
|
||||
new Instance() {ModelMatrix = Matrix4.Identity, TextureMatrix = Matrix3.Identity}
|
||||
}
|
||||
};
|
||||
drawContext.SetCamera(window.ViewportCamera);
|
||||
|
||||
window.CurrentRenderPipeline?.Render(ref drawContext);
|
||||
}
|
||||
|
||||
internal static void PrepareScene(IGenericWindow window, GenericScene scene)
|
||||
{
|
||||
window.CurrentScene?.Deactivate();
|
||||
|
||||
Util.Activate(scene);
|
||||
}
|
||||
|
||||
internal static void PreparePipeline(IGenericWindow window, RenderPipeline pipeline)
|
||||
{
|
||||
pipeline.ConnectedWindow = window;
|
||||
Util.Activate(pipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,19 +14,7 @@ namespace SM.OGL.Framebuffer
|
|||
/// </summary>
|
||||
public class ColorAttachment : TextureBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a attachment with a specific id.
|
||||
/// </summary>
|
||||
/// <param name="attachmentId"></param>
|
||||
public ColorAttachment(int attachmentId) : this(attachmentId, PixelInformation.RGBA_LDR)
|
||||
{ }
|
||||
|
||||
public ColorAttachment(int attachmentID, PixelInformation pixelInformation)
|
||||
{
|
||||
|
||||
AttachmentID = attachmentID;
|
||||
PixelInformation = pixelInformation;
|
||||
}
|
||||
private int _multisamples;
|
||||
|
||||
/// <summary>
|
||||
/// The ID the attachment was given.
|
||||
|
|
@ -50,6 +38,22 @@ namespace SM.OGL.Framebuffer
|
|||
/// </summary>
|
||||
public DrawBuffersEnum DrawBuffersEnum => DrawBuffersEnum.ColorAttachment0 + AttachmentID;
|
||||
|
||||
public bool IsMultisampled => _multisamples > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a attachment with a specific id.
|
||||
/// </summary>
|
||||
/// <param name="attachmentId"></param>
|
||||
public ColorAttachment(int attachmentId) : this(attachmentId, PixelInformation.RGBA_LDR)
|
||||
{ }
|
||||
|
||||
public ColorAttachment(int attachmentID, PixelInformation pixelInformation, int multisamples = 0)
|
||||
{
|
||||
AttachmentID = attachmentID;
|
||||
PixelInformation = pixelInformation;
|
||||
_multisamples = multisamples;
|
||||
Target = IsMultisampled ? TextureTarget.Texture2DMultisample : TextureTarget.Texture2D;
|
||||
}
|
||||
/// <summary>
|
||||
/// Generates the attachment.
|
||||
/// </summary>
|
||||
|
|
@ -57,6 +61,13 @@ namespace SM.OGL.Framebuffer
|
|||
public void Generate(Framebuffer f)
|
||||
{
|
||||
_id = GL.GenTexture();
|
||||
|
||||
if (IsMultisampled) GenerateMultisampledTexture(f);
|
||||
else GenerateTexture(f);
|
||||
}
|
||||
|
||||
private void GenerateTexture(Framebuffer f)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, _id);
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInformation.InternalFormat,
|
||||
(int)f.Size.X, (int)f.Size.Y,
|
||||
|
|
@ -71,6 +82,15 @@ namespace SM.OGL.Framebuffer
|
|||
(int)TextureParameterName.ClampToEdge);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT,
|
||||
(int)TextureParameterName.ClampToEdge);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, 0);
|
||||
}
|
||||
|
||||
private void GenerateMultisampledTexture(Framebuffer f)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2DMultisample, _id);
|
||||
GL.TexImage2DMultisample(TextureTargetMultisample.Texture2DMultisample, _multisamples, PixelInformation.InternalFormat, (int)f.Size.X, (int)f.Size.Y, true);
|
||||
GL.BindTexture(TextureTarget.Texture2DMultisample, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@ namespace SM.OGL.Framebuffer
|
|||
/// </summary>
|
||||
public class Framebuffer : GLObject
|
||||
{
|
||||
protected override bool AutoCompile { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the screen buffer.
|
||||
/// </summary>
|
||||
|
|
@ -92,7 +94,7 @@ namespace SM.OGL.Framebuffer
|
|||
|
||||
GL.DrawBuffers(enums.Length, enums);
|
||||
foreach (var pair in ColorAttachments)
|
||||
GL.FramebufferTexture(FramebufferTarget.Framebuffer, pair.Value.FramebufferAttachment, pair.Value.ID,
|
||||
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, pair.Value.FramebufferAttachment, pair.Value.Target, pair.Value.ID,
|
||||
0);
|
||||
|
||||
var err = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
|
||||
|
|
@ -123,7 +125,6 @@ namespace SM.OGL.Framebuffer
|
|||
ColorAttachments.Add(key, value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Activates the framebuffer without clearing the buffer.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -47,9 +48,35 @@ namespace SM.OGL.Mesh
|
|||
/// <param name="y">If true, it takes the Y-value of maximum, otherwise the minimum.</param>
|
||||
/// <param name="z">If true, it takes the Z-value of maximum, otherwise the minimum.</param>
|
||||
/// <returns></returns>
|
||||
public Vector3 this[bool x, bool y, bool z] =>
|
||||
new Vector3(x ? Max.X : Min.X, y ? Max.Y : Min.Y, z ? Max.Z : Min.Z);
|
||||
public Vector3 this[bool x, bool y, bool z] => Get(x,y,z);
|
||||
|
||||
public Vector3 Get(bool x, bool y, bool z)
|
||||
{
|
||||
return new Vector3(x ? Max.X : Min.X, y ? Max.Y : Min.Y, z ? Max.Z : Min.Z);
|
||||
}
|
||||
|
||||
public Vector3 Get(bool xyz) => Get(xyz, xyz, xyz);
|
||||
|
||||
public Vector3 Get(Matrix4 transformation, bool x, bool y, bool z)
|
||||
{
|
||||
Vector3 get = Get(x, y, z);
|
||||
return (new Vector4(get, 1) * transformation).Xyz;
|
||||
}
|
||||
|
||||
public Vector3 Get(Matrix4 transformation, bool xyz) => Get(transformation, xyz, xyz, xyz);
|
||||
|
||||
public void Update(GenericMesh mesh)
|
||||
{
|
||||
int pos = 0;
|
||||
foreach (float f in mesh.Vertex)
|
||||
{
|
||||
Min[pos] = Math.Min(Min[pos], f);
|
||||
Max[pos] = Math.Max(Max[pos], f);
|
||||
|
||||
pos++;
|
||||
pos %= mesh.Vertex.PointerSize;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Updates the bounding box.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ namespace SM.OGL.Mesh
|
|||
/// </summary>
|
||||
public abstract class GenericMesh : GLObject
|
||||
{
|
||||
private bool _boundingBoxUpdated = false;
|
||||
|
||||
public static int LastID { get; internal set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Generates the AttribDataIndex
|
||||
|
|
@ -69,6 +72,17 @@ namespace SM.OGL.Mesh
|
|||
/// </summary>
|
||||
public virtual int[] Indices { get; set; }
|
||||
|
||||
public void UpdateBoundingBox()
|
||||
{
|
||||
BoundingBox.Update(this);
|
||||
_boundingBoxUpdated = true;
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
GL.BindVertexArray(ID);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Compile()
|
||||
{
|
||||
|
|
@ -77,6 +91,9 @@ namespace SM.OGL.Mesh
|
|||
|
||||
if (Attributes == null || Attributes.Count == 0) throw new Exception("[Critical] The model requires attributes.");
|
||||
|
||||
if (!_boundingBoxUpdated)
|
||||
UpdateBoundingBox();
|
||||
|
||||
foreach (var kvp in Attributes)
|
||||
kvp.ConnectedVBO?.BindBuffer(kvp.Index);
|
||||
|
||||
|
|
|
|||
7
SMCode/SM.OGL/Mesh/ILineMesh.cs
Normal file
7
SMCode/SM.OGL/Mesh/ILineMesh.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
namespace SM.OGL.Mesh
|
||||
{
|
||||
public interface ILineMesh
|
||||
{
|
||||
float LineWidth { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace SM.OGL.Mesh
|
||||
{
|
||||
|
|
@ -50,5 +51,11 @@ namespace SM.OGL.Mesh
|
|||
//if (vbo == null) return;
|
||||
Add(new MeshAttribute(id, name, vbo));
|
||||
}
|
||||
|
||||
public bool Has(string name)
|
||||
{
|
||||
VBO attribute = this[name];
|
||||
return attribute != null && attribute.Active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,8 @@ namespace SM.OGL.Mesh
|
|||
/// </summary>
|
||||
public int PointerStride;
|
||||
|
||||
public bool Active = true;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the data type of each component in the array.
|
||||
/// </summary>
|
||||
|
|
@ -133,6 +135,14 @@ namespace SM.OGL.Mesh
|
|||
Add(vector.X, vector.Y, z, w);
|
||||
}
|
||||
|
||||
public void Add(params Vector2[] vectors)
|
||||
{
|
||||
foreach (Vector2 vector in vectors)
|
||||
{
|
||||
Add(vector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a Vector3.
|
||||
/// </summary>
|
||||
|
|
@ -149,6 +159,13 @@ namespace SM.OGL.Mesh
|
|||
Add(vector.X, vector.Y, vector.Z, w);
|
||||
}
|
||||
|
||||
public void Add(params Vector3[] vectors)
|
||||
{
|
||||
foreach (Vector3 vector in vectors)
|
||||
{
|
||||
Add(vector);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a vector4.
|
||||
/// </summary>
|
||||
|
|
@ -172,6 +189,8 @@ namespace SM.OGL.Mesh
|
|||
/// <param name="attribID">The id for the attribute.</param>
|
||||
internal void BindBuffer(int attribID)
|
||||
{
|
||||
if (!Active) return;
|
||||
|
||||
var data = ToArray();
|
||||
|
||||
var buffer = GL.GenBuffer();
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
<Compile Include="GLSystem.cs" />
|
||||
<Compile Include="Mesh\BoundingBox.cs" />
|
||||
<Compile Include="Mesh\GenericMesh.cs" />
|
||||
<Compile Include="Mesh\ILineMesh.cs" />
|
||||
<Compile Include="Mesh\MeshAttribute.cs" />
|
||||
<Compile Include="Mesh\MeshAttributeList.cs" />
|
||||
<Compile Include="Mesh\VBO.cs" />
|
||||
|
|
|
|||
|
|
@ -106,6 +106,11 @@ namespace SM.OGL.Shaders
|
|||
GLDebugging.CheckGLErrors($"A error occured at shader creation for '{GetType()}': %code%");
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
GL.UseProgram(ID);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Compile()
|
||||
{
|
||||
|
|
@ -122,7 +127,7 @@ namespace SM.OGL.Shaders
|
|||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="amount">The amounts for instancing.</param>
|
||||
protected void DrawObject(GenericMesh mesh, int amount = 1)
|
||||
public static void DrawObject(GenericMesh mesh, int amount = 1)
|
||||
{
|
||||
if (mesh.Indices != null)
|
||||
GL.DrawElementsInstanced(mesh.PrimitiveType, 0, DrawElementsType.UnsignedInt, mesh.Indices, amount);
|
||||
|
|
@ -138,7 +143,6 @@ namespace SM.OGL.Shaders
|
|||
Uniforms.NextTexture = 0;
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, 0);
|
||||
GL.BindVertexArray(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,17 +14,17 @@ namespace SM.OGL.Shaders
|
|||
/// <summary>
|
||||
/// Contains the vertex file.
|
||||
/// </summary>
|
||||
public ShaderFile Vertex;
|
||||
public ShaderFile[] Vertex;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the geometry file.
|
||||
/// </summary>
|
||||
public ShaderFile Geometry;
|
||||
public ShaderFile[] Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the fragment file.
|
||||
/// </summary>
|
||||
public ShaderFile Fragment;
|
||||
public ShaderFile[] Fragment;
|
||||
|
||||
/// <summary>
|
||||
/// Creating the collection with vertex and fragment files.
|
||||
|
|
@ -44,6 +44,14 @@ namespace SM.OGL.Shaders
|
|||
/// <param name="fragment"></param>
|
||||
/// <param name="geometry"></param>
|
||||
public ShaderFileCollection(ShaderFile vertex, ShaderFile fragment, ShaderFile geometry = default)
|
||||
{
|
||||
Vertex = new []{vertex};
|
||||
if (geometry != null) Geometry = new[] {geometry};
|
||||
else Geometry = default;
|
||||
Fragment = new []{fragment};
|
||||
}
|
||||
|
||||
public ShaderFileCollection(ShaderFile[] vertex, ShaderFile[] fragment, ShaderFile[] geometry = default)
|
||||
{
|
||||
Vertex = vertex;
|
||||
Geometry = geometry;
|
||||
|
|
@ -56,9 +64,15 @@ namespace SM.OGL.Shaders
|
|||
/// <param name="shader"></param>
|
||||
internal void Append(GenericShader shader)
|
||||
{
|
||||
Vertex.Compile(shader, ShaderType.VertexShader);
|
||||
Geometry?.Compile(shader, ShaderType.GeometryShader);
|
||||
Fragment.Compile(shader, ShaderType.FragmentShader);
|
||||
foreach (ShaderFile file in Vertex)
|
||||
file.Compile(shader, ShaderType.VertexShader);
|
||||
|
||||
if (Geometry != null)
|
||||
foreach (ShaderFile file in Geometry)
|
||||
file.Compile(shader, ShaderType.GeometryShader);
|
||||
|
||||
foreach (ShaderFile file in Fragment)
|
||||
file.Compile(shader, ShaderType.FragmentShader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -67,9 +81,15 @@ namespace SM.OGL.Shaders
|
|||
/// <param name="shader"></param>
|
||||
internal void Detach(GenericShader shader)
|
||||
{
|
||||
GL.DetachShader(shader, Vertex);
|
||||
if (Geometry != null) GL.DetachShader(shader, Geometry);
|
||||
GL.DetachShader(shader, Fragment);
|
||||
foreach (ShaderFile file in Vertex)
|
||||
GL.DetachShader(shader, file);
|
||||
|
||||
if (Geometry != null)
|
||||
foreach (ShaderFile file in Geometry)
|
||||
GL.DetachShader(shader, file);
|
||||
|
||||
foreach (ShaderFile file in Fragment)
|
||||
GL.DetachShader(shader, file);
|
||||
|
||||
GLDebugging.CheckGLErrors($"Error at detaching '{shader.GetType()}'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ namespace SM.OGL.Shaders
|
|||
|
||||
#region Matrix2
|
||||
|
||||
public void SetMatrix2(ref Matrix2 matrix, bool transpose = false)
|
||||
public void SetMatrix2(Matrix2 matrix, bool transpose = false)
|
||||
{
|
||||
GL.UniformMatrix2(Location, transpose, ref matrix);
|
||||
}
|
||||
|
|
@ -383,7 +383,7 @@ namespace SM.OGL.Shaders
|
|||
|
||||
#region Matrix3
|
||||
|
||||
public void SetMatrix3(ref Matrix3 matrix, bool transpose = false)
|
||||
public void SetMatrix3(Matrix3 matrix, bool transpose = false)
|
||||
{
|
||||
GL.UniformMatrix3(Location, transpose, ref matrix);
|
||||
}
|
||||
|
|
@ -485,7 +485,7 @@ namespace SM.OGL.Shaders
|
|||
{
|
||||
Parent.NextTexture = texturePos + 1;
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + texturePos);
|
||||
GL.BindTexture(TextureTarget.Texture2D, texture);
|
||||
GL.BindTexture(texture.Target, texture);
|
||||
SetUniform1(texturePos);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace SM.OGL.Shaders
|
|||
public string Name { get; internal set; }
|
||||
public UniformCollection Parent { get; internal set; }
|
||||
public GenericShader ParentShader { get; internal set; }
|
||||
public int Length => storedUniforms.Count;
|
||||
|
||||
public Dictionary<string, Uniform> this[int index] => Get(index);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace SM.OGL.Shaders
|
|||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
GLCustomActions.AtWarning?.Invoke("Uniform '" + KeyString + key + "' was not found. Tried to recreate it.");
|
||||
GLCustomActions.AtWarning?.Invoke("Uniform '" + KeyString + key + "' at '" + ParentShader.GetType().Name + "' was not found. Tried to recreate it.");
|
||||
var u = new Uniform(GL.GetUniformLocation(ParentShader, KeyString + key), this);
|
||||
Add(key, u);
|
||||
return u;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,14 @@ namespace SM.OGL.Texture
|
|||
/// <inheritdoc />
|
||||
protected override bool AutoCompile { get; } = true;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ObjectLabelIdentifier TypeIdentifier { get; } = ObjectLabelIdentifier.Texture;
|
||||
|
||||
public PixelInformation PixelInformation;
|
||||
|
||||
public TextureTarget Target { get; set; } = TextureTarget.Texture2D;
|
||||
|
||||
/// <summary>
|
||||
/// The texture filter.
|
||||
/// <para>Default: <see cref="TextureMinFilter.Linear" /></para>
|
||||
|
|
|
|||
|
|
@ -1,41 +1,63 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
using SM.Base.Controls;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Scene;
|
||||
using SM2D.Scene;
|
||||
using SM2D.Types;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM2D.Controls
|
||||
{
|
||||
public class Mouse2D : Mouse<IGLWindow2D>
|
||||
public class Mouse2D
|
||||
{
|
||||
protected internal Mouse2D(IGLWindow2D window) : base(window)
|
||||
public static Vector2 InWorld(Vector2 worldScale)
|
||||
{
|
||||
}
|
||||
|
||||
internal new void MouseMoveEvent(MouseMoveEventArgs mmea)
|
||||
{
|
||||
base.MouseMoveEvent(mmea);
|
||||
}
|
||||
|
||||
public Vector2 InWorld()
|
||||
{
|
||||
var res = _window.WorldScale;
|
||||
var res = worldScale;
|
||||
res.Y *= -1;
|
||||
return InScreenNormalized * res - res / 2;
|
||||
return Mouse.InScreenNormalized * res - res / 2;
|
||||
}
|
||||
|
||||
public Vector2 InWorld(Camera cam)
|
||||
public static Vector2 InWorld(Camera cam)
|
||||
{
|
||||
return InWorld() + cam.Position;
|
||||
return InWorld(cam.WorldScale) + cam.Position;
|
||||
}
|
||||
|
||||
public Vector2 InWorld(Vector2 position)
|
||||
public static Vector2 InWorld(Vector2 worldScale, Vector2 position)
|
||||
{
|
||||
return InWorld() + position;
|
||||
return InWorld(worldScale) + position;
|
||||
}
|
||||
|
||||
public static bool MouseOver<TObject>(Vector2 mousePos, params TObject[] checkingObjects)
|
||||
where TObject : IModelItem, ITransformItem<Transformation>
|
||||
=> MouseOver(mousePos, out _, checkingObjects);
|
||||
|
||||
public static bool MouseOver<TObject>(Vector2 mousePos, ICollection<TObject> checkingObjects)
|
||||
where TObject : IModelItem, ITransformItem<Transformation>
|
||||
=> MouseOver<TObject>(mousePos, out _, checkingObjects);
|
||||
|
||||
public static bool MouseOver<TObject>(Vector2 mousePos, out TObject clicked, params TObject[] checkingObjects)
|
||||
where TObject : IModelItem, ITransformItem<Transformation>
|
||||
=> MouseOver<TObject>(mousePos, out clicked, (ICollection<TObject>)checkingObjects);
|
||||
|
||||
public static bool MouseOver<TObject>(Vector2 mousePos, out TObject clickedObj, ICollection<TObject> checkingObjects)
|
||||
where TObject : IModelItem, ITransformItem<Transformation>
|
||||
{
|
||||
clickedObj = default;
|
||||
|
||||
foreach (TObject obj in checkingObjects)
|
||||
{
|
||||
Vector3 min = obj.Mesh.BoundingBox.Get(obj.Transform.MergeMatrix(obj.Transform.LastMaster), false);
|
||||
Vector3 max = obj.Mesh.BoundingBox.Get(obj.Transform.MergeMatrix(obj.Transform.LastMaster), true);
|
||||
|
||||
if (mousePos.X > min.X && mousePos.X < max.X &&
|
||||
mousePos.Y > min.Y && mousePos.Y < max.Y)
|
||||
{
|
||||
clickedObj = obj;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,20 +4,38 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Objects.Static;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Textures;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Texture;
|
||||
using SM2D.Scene;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM2D.Drawing
|
||||
{
|
||||
public class DrawBackground : IBackgroundItem
|
||||
public class DrawBackground : DrawingBasis, IBackgroundItem
|
||||
{
|
||||
private Material _material = new Material();
|
||||
public Color4 Color
|
||||
{
|
||||
get => Material.Tint;
|
||||
set => Material.Tint = value;
|
||||
}
|
||||
|
||||
public TextureBase Texture
|
||||
{
|
||||
get => Material.Texture;
|
||||
set
|
||||
{
|
||||
if (Material.Tint == Color4.Black) Material.Tint = Color4.White;
|
||||
Material.Texture = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DrawBackground() : this(Color4.Black) {}
|
||||
|
||||
public DrawBackground(Color4 color)
|
||||
{
|
||||
|
|
@ -35,41 +53,12 @@ namespace SM2D.Drawing
|
|||
Texture = (Texture) texture;
|
||||
}
|
||||
|
||||
public Color4 Color
|
||||
|
||||
protected override void DrawContext(ref DrawContext context)
|
||||
{
|
||||
get => _material.Tint;
|
||||
set => _material.Tint = value;
|
||||
}
|
||||
|
||||
public TextureBase Texture
|
||||
{
|
||||
get => _material.Texture;
|
||||
set => _material.Texture = value;
|
||||
}
|
||||
|
||||
public object Parent { get; set; }
|
||||
public string Name { get; set; } = "Background";
|
||||
public ICollection<string> Flags { get; set; } = new string[0];
|
||||
|
||||
public void Update(UpdateContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void Draw(DrawContext context)
|
||||
{
|
||||
context.Material = _material;
|
||||
context.Mesh = Plate.Object;
|
||||
|
||||
context.ModelMaster = Matrix4.CreateScale(context.WorldScale.X, context.WorldScale.Y, 1);
|
||||
base.DrawContext(ref context);
|
||||
context.ModelMatrix = Matrix4.CreateScale((context.UseCamera as Camera).WorldScale.X, (context.UseCamera as Camera).WorldScale.Y, 1);
|
||||
context.Shader.Draw(context);
|
||||
}
|
||||
|
||||
public void OnAdded(object sender)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnRemoved(object sender)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,30 +2,30 @@
|
|||
using System.Drawing;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Objects;
|
||||
using SM.Base.Textures;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Mesh;
|
||||
using SM2D.Object;
|
||||
using SM2D.Scene;
|
||||
using SM2D.Types;
|
||||
|
||||
namespace SM2D.Drawing
|
||||
{
|
||||
public class DrawObject2D : DrawingBasis<Transformation>, I2DShowItem
|
||||
public class DrawObject2D : DrawingBasis<Transformation>
|
||||
{
|
||||
public int ZIndex { get; set; }
|
||||
|
||||
public Texture Texture
|
||||
{
|
||||
get => (Texture) _material.Texture;
|
||||
set => _material.Texture = value;
|
||||
get => (Texture) Material.Texture;
|
||||
set => Material.Texture = value;
|
||||
}
|
||||
|
||||
public Color4 Color
|
||||
{
|
||||
get => _material.Tint;
|
||||
set => _material.Tint = value;
|
||||
get => Material.Tint;
|
||||
set => Material.Tint = value;
|
||||
}
|
||||
|
||||
protected override void DrawContext(ref DrawContext context)
|
||||
|
|
@ -34,34 +34,29 @@ namespace SM2D.Drawing
|
|||
context.Shader.Draw(context);
|
||||
}
|
||||
|
||||
public Material GetMaterialReference() => _material;
|
||||
public void SetMaterialReference(Material material) => _material = material;
|
||||
public void SetShader(MaterialShader shader) => Material.CustomShader = shader;
|
||||
|
||||
public void SetShader(MaterialShader shader) => _material.CustomShader = shader;
|
||||
|
||||
public Polygon ApplyPolygon(ICollection<Vector2> vertices)
|
||||
public Polygon ApplyPolygon(ICollection<Vector2> vertices, bool centerUVs = false)
|
||||
{
|
||||
Polygon polygon = new Polygon(vertices);
|
||||
_mesh = polygon;
|
||||
Mesh = polygon;
|
||||
return polygon;
|
||||
}
|
||||
public Polygon ApplyPolygon(ICollection<PolygonVertex> vertices)
|
||||
public Polygon ApplyPolygon(ICollection<PolygonVertex> vertices, bool centerUVs = false)
|
||||
{
|
||||
Polygon polygon = new Polygon(vertices);
|
||||
_mesh = polygon;
|
||||
Mesh = polygon;
|
||||
return polygon;
|
||||
}
|
||||
public void ApplyPolygon(Polygon polygon)
|
||||
{
|
||||
_mesh = polygon;
|
||||
Mesh = polygon;
|
||||
}
|
||||
|
||||
public void ApplyMesh(Mesh mesh) => _mesh = mesh;
|
||||
|
||||
public Polygon ApplyCircle(int segments = 32)
|
||||
public Polygon ApplyCircle(int segments = 32, bool centerUVs = false)
|
||||
{
|
||||
Polygon pol = Polygon.GenerateCircle(segments);
|
||||
_mesh = pol;
|
||||
Mesh = pol;
|
||||
return pol;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ using SM2D.Types;
|
|||
|
||||
namespace SM2D.Drawing
|
||||
{
|
||||
public class DrawParticles : ParticleDrawingBasis<Transformation, Vector2>, I2DShowItem
|
||||
public class DrawParticles : ParticleDrawingBasis<Transformation, Vector2>
|
||||
{
|
||||
public int ZIndex { get; set; }
|
||||
public override Func<Vector2, ParticleContext, Vector2> MovementCalculation { get; set; } = ParticleMovement.Default2D;
|
||||
|
||||
public DrawParticles(TimeSpan duration) : base(duration)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#region usings
|
||||
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Drawing.Text;
|
||||
using SM.Base.Types;
|
||||
using SM.Base.Windows;
|
||||
using SM2D.Scene;
|
||||
using SM2D.Types;
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ using SM2D.Types;
|
|||
|
||||
namespace SM2D.Drawing
|
||||
{
|
||||
public class DrawText : TextDrawingBasis<Transformation>, I2DShowItem
|
||||
public class DrawText : TextDrawingBasis<Transformation>
|
||||
{
|
||||
public DrawText(Font font, string text) : base(font)
|
||||
{
|
||||
|
|
@ -18,8 +19,6 @@ namespace SM2D.Drawing
|
|||
Transform.Size = new CVector2(1);
|
||||
}
|
||||
|
||||
public int ZIndex { get; set; }
|
||||
|
||||
protected override void DrawContext(ref DrawContext context)
|
||||
{
|
||||
base.DrawContext(ref context);
|
||||
|
|
|
|||
35
SMCode/SM2D/Object/PolyLine.cs
Normal file
35
SMCode/SM2D/Object/PolyLine.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base.Objects;
|
||||
using SM.OGL.Mesh;
|
||||
|
||||
namespace SM2D.Object
|
||||
{
|
||||
public enum PolyLineType
|
||||
{
|
||||
NotConnected = 1,
|
||||
Connected = 3,
|
||||
ConnectedLoop = 2
|
||||
}
|
||||
|
||||
public class PolyLine : Polygon, ILineMesh
|
||||
{
|
||||
public float LineWidth { get; set; } = 1;
|
||||
|
||||
public PolyLine(ICollection<Vector2> vertices, PolyLineType lineType = PolyLineType.NotConnected) : base(vertices)
|
||||
{
|
||||
UVs.Active = false;
|
||||
|
||||
PrimitiveType = (PrimitiveType)lineType;
|
||||
}
|
||||
|
||||
public PolyLine(ICollection<PolygonVertex> vertices, PolyLineType lineType = PolyLineType.NotConnected) : base(vertices)
|
||||
{
|
||||
UVs.Active = false;
|
||||
PrimitiveType = (PrimitiveType)lineType;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -16,13 +16,16 @@ namespace SM2D.Object
|
|||
{
|
||||
public Polygon(ICollection<Vector2> vertices) : base(PrimitiveType.TriangleFan)
|
||||
{
|
||||
Color.Active = false;
|
||||
|
||||
foreach (var vertex in vertices)
|
||||
{
|
||||
Color.Add(Color4.White);
|
||||
AddVertex(vertex);
|
||||
Vertex.Add(vertex, 0);
|
||||
}
|
||||
|
||||
foreach (var vertex in vertices) AddUV(vertex);
|
||||
UpdateBoundingBox();
|
||||
|
||||
if (UVs.Active) foreach (var vertex in vertices) AddUV(vertex);
|
||||
}
|
||||
|
||||
public Polygon(ICollection<PolygonVertex> vertices) : base(PrimitiveType.TriangleFan)
|
||||
|
|
@ -30,10 +33,12 @@ namespace SM2D.Object
|
|||
foreach (var polygonVertex in vertices)
|
||||
{
|
||||
Color.Add(polygonVertex.Color);
|
||||
AddVertex(polygonVertex.Vertex);
|
||||
Vertex.Add(polygonVertex.Vertex, 0);
|
||||
}
|
||||
|
||||
foreach (var vertex in vertices) AddUV(vertex.Vertex);
|
||||
UpdateBoundingBox();
|
||||
|
||||
if (UVs.Active) foreach (var vertex in vertices) AddUV(vertex.Vertex);
|
||||
}
|
||||
|
||||
public override VBO Vertex { get; protected set; } = new VBO();
|
||||
|
|
@ -42,12 +47,6 @@ namespace SM2D.Object
|
|||
|
||||
public override PrimitiveType PrimitiveType { get; protected set; } = PrimitiveType.TriangleFan;
|
||||
|
||||
private void AddVertex(Vector2 vertex)
|
||||
{
|
||||
BoundingBox.Update(vertex);
|
||||
Vertex.Add(vertex, 0);
|
||||
}
|
||||
|
||||
private void AddUV(Vector2 vertex)
|
||||
{
|
||||
var uv = Vector2.Divide(vertex - BoundingBox.Min.Xy, BoundingBox.Max.Xy - BoundingBox.Min.Xy);
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
namespace SM2D.Pipelines
|
||||
{
|
||||
public class Adv2DPipeline
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +1,23 @@
|
|||
using System;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Framebuffer;
|
||||
using SM2D.Shader;
|
||||
|
||||
namespace SM2D.Pipelines
|
||||
{
|
||||
public class Basic2DPipeline : RenderPipeline<Scene.Scene>
|
||||
public class Basic2DPipeline : RenderPipeline
|
||||
{
|
||||
public static Basic2DPipeline Pipeline = new Basic2DPipeline();
|
||||
|
||||
public override MaterialShader DefaultShader { get; protected set; } = ShaderCollection.Instanced;
|
||||
|
||||
private Basic2DPipeline()
|
||||
{
|
||||
_defaultShader = Basic2DShader.Shader;
|
||||
}
|
||||
|
||||
protected override void RenderProcess(ref DrawContext context, Scene.Scene scene)
|
||||
protected override void RenderProcess(ref DrawContext context)
|
||||
{
|
||||
scene?.Draw(context);
|
||||
context.Scene?.Draw(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL.Framebuffer;
|
||||
using SM2D.Shader;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM2D.Pipelines
|
||||
{
|
||||
public class Default2DPipeline : RenderPipeline<Scene.Scene>
|
||||
{
|
||||
public static Default2DPipeline Pipeline = new Default2DPipeline();
|
||||
|
||||
|
||||
private Default2DPipeline()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Initialization(IGenericWindow window)
|
||||
{
|
||||
MainFramebuffer = CreateWindowFramebuffer();
|
||||
}
|
||||
|
||||
protected override void RenderProcess(ref DrawContext context, Scene.Scene scene)
|
||||
{
|
||||
if (scene != null)
|
||||
{
|
||||
scene.DrawBackground(context);
|
||||
|
||||
scene.DrawMainObjects(context);
|
||||
|
||||
scene.DrawHUD(context);
|
||||
scene.DrawDebug(context);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SceneChanged(Scene.Scene scene)
|
||||
{
|
||||
base.SceneChanged(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -45,22 +45,19 @@
|
|||
<Compile Include="Drawing\DrawObject2D.cs" />
|
||||
<Compile Include="Drawing\DrawParticles.cs" />
|
||||
<Compile Include="Drawing\DrawText.cs" />
|
||||
<Compile Include="Window\GLWindow2D.cs" />
|
||||
<Compile Include="Window\GLWPFWindow2D.cs" />
|
||||
<Compile Include="Object\Polygon.cs" />
|
||||
<Compile Include="Object\PolygonVertex.cs" />
|
||||
<Compile Include="Pipelines\Adv2DPipeline.cs" />
|
||||
<Compile Include="Object\PolyLine.cs" />
|
||||
<Compile Include="Pipelines\Basic2DPipeline.cs" />
|
||||
<Compile Include="Pipelines\Default2DPipeline.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Scene\Camera.cs" />
|
||||
<Compile Include="Scene\I2DShowItem.cs" />
|
||||
<Compile Include="Scene\ItemCollection.cs" />
|
||||
<Compile Include="Scene\Scene.cs" />
|
||||
<Compile Include="Shader\Basic2DShader.cs" />
|
||||
<Compile Include="Shader\Default2DShader.cs" />
|
||||
<Compile Include="Shader\ShaderCollection.cs" />
|
||||
<Compile Include="Types\Transformation.cs" />
|
||||
<Compile Include="Window\IGLWindow2D.cs" />
|
||||
<Compile Include="Window\Window2DSetup.cs" />
|
||||
<Compile Include="Window\I2DSetup.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SM.Base\SM.Base.csproj">
|
||||
|
|
@ -72,9 +69,6 @@
|
|||
<Name>SM.OGL</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Shader\ShaderFiles\default.glsl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK">
|
||||
<Version>3.3.1</Version>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=light_005Clightobjects/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=shader_005Cshaderfiles/@EntryIndexedValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=window/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
#region usings
|
||||
|
||||
using System;
|
||||
using OpenTK;
|
||||
using SM.Base;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Types;
|
||||
using SM.Base.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -10,18 +13,73 @@ namespace SM2D.Scene
|
|||
{
|
||||
public class Camera : GenericCamera
|
||||
{
|
||||
internal static int ResizeCounter = 0;
|
||||
|
||||
private int _resizeCounter = 0;
|
||||
private bool _updateWorldScale = false;
|
||||
private Vector2? _requestedWorldScale = null;
|
||||
|
||||
public Vector2? RequestedWorldScale
|
||||
{
|
||||
get => _requestedWorldScale;
|
||||
set
|
||||
{
|
||||
_requestedWorldScale = value;
|
||||
_updateWorldScale = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 WorldScale { get; private set; } = Vector2.Zero;
|
||||
|
||||
public event Action<Camera> WorldScaleChanged;
|
||||
|
||||
public CVector2 Position = new CVector2(0);
|
||||
public override bool Orthographic { get; } = true;
|
||||
|
||||
protected override Matrix4 ViewCalculation()
|
||||
protected override Matrix4 ViewCalculation(IGenericWindow window)
|
||||
{
|
||||
return Matrix4.LookAt(Position.X, Position.Y, 2, Position.X, Position.Y, 0, 0, 1, 0);
|
||||
return Matrix4.LookAt(Position.X, Position.Y, 1, Position.X, Position.Y, 0, 0, 1, 0);
|
||||
}
|
||||
|
||||
public override void RecalculateWorld(Vector2 world, float aspect)
|
||||
protected override bool WorldCalculation(IGenericWindow window, out Matrix4 world)
|
||||
{
|
||||
OrthographicWorld =
|
||||
Matrix4.CreateOrthographic(world.X, world.Y, 0.1f, 100f);
|
||||
world = Matrix4.Identity;
|
||||
if (ResizeCounter != _resizeCounter || _updateWorldScale)
|
||||
{
|
||||
_updateWorldScale = false;
|
||||
_resizeCounter = ResizeCounter;
|
||||
CalculateWorldScale(window);
|
||||
|
||||
world = Matrix4.CreateOrthographic(WorldScale.X, WorldScale.Y, .0001f, 1.5f);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CalculateWorldScale(IGenericWindow window)
|
||||
{
|
||||
if (RequestedWorldScale.HasValue)
|
||||
{
|
||||
float aspect = window.Width > window.Height ? window.AspectRatio : window.AspectRatioReverse;
|
||||
Vector2 requested = RequestedWorldScale.Value;
|
||||
|
||||
if (requested.X > 0 && requested.Y > 0)
|
||||
{
|
||||
float requestRatio = requested.X / requested.Y;
|
||||
|
||||
if (requestRatio > aspect) WorldScale = new Vector2(requested.X, requested.X / aspect);
|
||||
else WorldScale = new Vector2(aspect * requested.Y, requested.Y);
|
||||
}
|
||||
else if (requested.X > 0) WorldScale = new Vector2(requested.X, requested.X / aspect);
|
||||
else if (requested.Y > 0) WorldScale = new Vector2(aspect * requested.Y, requested.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
WorldScale = window.WindowSize;
|
||||
}
|
||||
|
||||
WorldScaleChanged?.Invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
#region usings
|
||||
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Types;
|
||||
using SM.Base.Windows;
|
||||
using SM2D.Types;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM2D.Scene
|
||||
{
|
||||
public class ItemCollection : GenericItemCollection<I2DShowItem, Transformation>, I2DShowItem
|
||||
public class ItemCollection : GenericItemCollection<Transformation>
|
||||
{
|
||||
public ItemCollection()
|
||||
{
|
||||
|
|
@ -18,11 +19,7 @@ namespace SM2D.Scene
|
|||
|
||||
public override void Draw(DrawContext context)
|
||||
{
|
||||
Sort((x, y) => x.ZIndex - y.ZIndex);
|
||||
|
||||
base.Draw(context);
|
||||
}
|
||||
|
||||
public int ZIndex { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base;
|
||||
using SM.Base.Objects.Static;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Windows;
|
||||
using SM2D.Drawing;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM2D.Scene
|
||||
{
|
||||
public class Scene : GenericScene<Camera, ItemCollection, I2DShowItem>
|
||||
public class Scene : GenericScene<Camera, ItemCollection>
|
||||
{
|
||||
private static DrawObject2D _axisHelper;
|
||||
|
||||
|
|
@ -19,16 +20,24 @@ namespace SM2D.Scene
|
|||
static Scene()
|
||||
{
|
||||
_axisHelper = new DrawObject2D();
|
||||
_axisHelper.ApplyMesh(AxisHelper.Object);
|
||||
_axisHelper.Mesh = AxisHelper.Object;
|
||||
}
|
||||
|
||||
public Scene()
|
||||
{
|
||||
_Background = new DrawBackground(Color4.Black);
|
||||
Objects = new ItemCollection();
|
||||
|
||||
BackgroundCamera = new Camera();
|
||||
HUDCamera = new Camera();
|
||||
}
|
||||
|
||||
|
||||
public DrawBackground Background => (DrawBackground) _Background;
|
||||
public DrawBackground Background
|
||||
{
|
||||
get => (DrawBackground) _Background;
|
||||
set => _Background = value;
|
||||
}
|
||||
|
||||
public override void DrawDebug(DrawContext context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
using SM.Base.Contexts;
|
||||
using SM.Base.Drawing;
|
||||
using SM.OGL.Shaders;
|
||||
using SM.Utility;
|
||||
|
||||
namespace SM2D.Shader
|
||||
{
|
||||
public class Basic2DShader : MaterialShader
|
||||
{
|
||||
|
||||
public static Basic2DShader Shader = new Basic2DShader();
|
||||
private Basic2DShader() : base(AssemblyUtility.ReadAssemblyFile("SM2D.Shader.ShaderFiles.basic.glsl"))
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DrawProcess(DrawContext context)
|
||||
{
|
||||
// Vertex Uniforms
|
||||
Uniforms["MVP"].SetMatrix4(context.ModelMaster * context.View * context.World);
|
||||
Uniforms["HasVColor"]
|
||||
.SetUniform1(context.Mesh.Attributes["color"] != null);
|
||||
|
||||
UniformArray instances = Uniforms.GetArray("Instances");
|
||||
for (int i = 0; i < context.Instances.Count; i++)
|
||||
{
|
||||
var shaderInstance = instances[i];
|
||||
var instance = context.Instances[i];
|
||||
shaderInstance["ModelMatrix"].SetMatrix4(instance.ModelMatrix);
|
||||
shaderInstance["TextureOffset"].SetUniform2(instance.TexturePosition);
|
||||
shaderInstance["TextureScale"].SetUniform2(instance.TextureScale);
|
||||
}
|
||||
|
||||
// Fragment Uniforms
|
||||
Uniforms["Tint"].SetUniform4(context.Material.Tint);
|
||||
Uniforms["Texture"].SetTexture(context.Material.Texture, Uniforms["UseTexture"]);
|
||||
|
||||
DrawObject(context.Mesh, context.Instances.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base.Contexts;
|
||||
using SM.Base.Drawing;
|
||||
using SM.Base.Scene;
|
||||
using SM.OGL.Shaders;
|
||||
using SM.Utility;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM2D.Shader
|
||||
{
|
||||
public class Default2DShader : MaterialShader
|
||||
{
|
||||
public static Default2DShader MaterialShader = new Default2DShader();
|
||||
|
||||
|
||||
private Default2DShader() : base(AssemblyUtility.ReadAssemblyFile("SM2D.Shader.ShaderFiles.default.glsl"))
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DrawProcess(DrawContext context)
|
||||
{
|
||||
// Vertex Uniforms
|
||||
Uniforms["MVP"].SetMatrix4(context.ModelMaster * context.View * context.World);
|
||||
Uniforms["HasVColor"]
|
||||
.SetUniform1(context.Mesh.Attributes["color"] != null);
|
||||
Uniforms["occlude"].SetUniform1(context.ShaderArguments.ContainsKey("occluder"));
|
||||
|
||||
UniformArray instances = Uniforms.GetArray("Instances");
|
||||
for (int i = 0; i < context.Instances.Count; i++)
|
||||
{
|
||||
var shaderInstance = instances[i];
|
||||
var instance = context.Instances[i];
|
||||
shaderInstance["ModelMatrix"].SetMatrix4(instance.ModelMatrix);
|
||||
shaderInstance["TextureOffset"].SetUniform2(instance.TexturePosition);
|
||||
shaderInstance["TextureScale"].SetUniform2(instance.TextureScale);
|
||||
}
|
||||
|
||||
// Fragment Uniforms
|
||||
Uniforms["Tint"].SetUniform4(context.Material.Tint);
|
||||
Uniforms["Texture"].SetTexture(context.Material.Texture, Uniforms["UseTexture"]);
|
||||
|
||||
DrawObject(context.Mesh, context.Instances.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
SMCode/SM2D/Shader/ShaderCollection.cs
Normal file
19
SMCode/SM2D/Shader/ShaderCollection.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using SM.Base.Drawing;
|
||||
using SM.Base.Windows;
|
||||
using SM.OGL.Shaders;
|
||||
using SM.Utility;
|
||||
|
||||
namespace SM2D.Shader
|
||||
{
|
||||
public class ShaderCollection
|
||||
{
|
||||
public static SimpleShader Basic = new SimpleShader("basic", AssemblyUtility.ReadAssemblyFile("SM2D.Shader.ShaderFiles.basic.glsl"), SetUniforms);
|
||||
public static SimpleShader Instanced = new SimpleShader("instanced", AssemblyUtility.ReadAssemblyFile("SM2D.Shader.ShaderFiles.basic.glsl"), SetUniforms);
|
||||
|
||||
static void SetUniforms(UniformCollection uniforms, DrawContext context)
|
||||
{
|
||||
uniforms["Tint"].SetUniform4(context.Material.Tint);
|
||||
uniforms["Texture"].SetTexture(context.Material.Texture, uniforms["UseTexture"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,6 @@
|
|||
#version 330
|
||||
//# region vertex
|
||||
|
||||
//# import SM_base_vertex_basic
|
||||
void ApplyTexModifier();
|
||||
void CheckVertexColor();
|
||||
void ApplyModelTransformation();
|
||||
|
||||
void vmain() {
|
||||
ApplyTexModifier();
|
||||
CheckVertexColor();
|
||||
ApplyModelTransformation();
|
||||
}
|
||||
|
||||
//# region fragment
|
||||
in vec2 vTexture;
|
||||
in vec4 vColor;
|
||||
in vec2 v_TexCoords;
|
||||
in vec4 v_Color;
|
||||
|
||||
uniform vec4 Tint;
|
||||
uniform bool UseTexture;
|
||||
|
|
@ -22,7 +8,9 @@ uniform sampler2D Texture;
|
|||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
void fmain() {
|
||||
color = vColor * Tint;
|
||||
if (UseTexture) color *= texture(Texture, vTexture);
|
||||
void main() {
|
||||
color = vec4(v_TexCoords, 0, 1);
|
||||
return;
|
||||
color = v_Color * Tint;
|
||||
if (UseTexture) color = texture(Texture, v_TexCoords);
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#version 330
|
||||
|
||||
//# region vertex
|
||||
|
||||
//# import SM_base_vertex_basic
|
||||
void ApplyTexModifier();
|
||||
void CheckVertexColor();
|
||||
void ApplyModelTransformation();
|
||||
|
||||
void vmain() {
|
||||
ApplyTexModifier();
|
||||
CheckVertexColor();
|
||||
ApplyModelTransformation();
|
||||
}
|
||||
|
||||
//# region fragment
|
||||
in vec2 vTexture;
|
||||
in vec4 vColor;
|
||||
|
||||
uniform bool occlude;
|
||||
|
||||
uniform vec4 Tint;
|
||||
uniform bool UseTexture;
|
||||
uniform sampler2D Texture;
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
layout(location = 1) out vec4 bloom;
|
||||
|
||||
void fmain() {
|
||||
color = vColor * Tint;
|
||||
if (UseTexture) color *= texture(Texture, vTexture);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue