From 820d6ce7006fd14efad45f604a9656ea3facd285 Mon Sep 17 00:00:00 2001 From: Michel Fedde Date: Sun, 4 Oct 2020 16:31:48 +0200 Subject: [PATCH] 04.10.2020 + render pipeline system for more control about the renderering. + Log system + Framebuffer system ~ Default shader was moved to pipelines. --- SMCode/SM.Base/Defaults.cs | 10 +- SMCode/SM.Base/Drawing/DrawingBasis.cs | 13 +- SMCode/SM.Base/Drawing/Material.cs | 5 +- SMCode/SM.Base/Log.cs | 236 ++++++++++++++++++ SMCode/SM.Base/SM.Base.csproj | 5 + SMCode/SM.Base/Scene/GenericCamera.cs | 2 +- SMCode/SM.Base/Scene/GenericItemCollection.cs | 9 +- SMCode/SM.Base/Scene/GenericScene.cs | 62 +++-- SMCode/SM.Base/Text/Font.cs | 2 +- SMCode/SM.Base/Text/TextDrawingBasis.cs | 3 +- SMCode/SM.Base/Textures/Texture.cs | 4 +- SMCode/SM.Base/Window/Contexts/DrawContext.cs | 11 + SMCode/SM.Base/Window/GenericWindow.cs | 45 ++-- SMCode/SM.Base/Window/RenderPipeline.cs | 74 ++++++ SMCode/SM.OGL/Framebuffer/ColorAttachment.cs | 35 +++ SMCode/SM.OGL/Framebuffer/Framebuffer.cs | 88 +++++++ SMCode/SM.OGL/GLDebugging.cs | 24 +- SMCode/SM.OGL/GLObject.cs | 23 +- SMCode/SM.OGL/Mesh/GenericMesh.cs | 2 +- SMCode/SM.OGL/SM.OGL.csproj | 2 + SMCode/SM.OGL/Shaders/GenericShader.cs | 4 +- SMCode/SM.OGL/Texture/TextureBase.cs | 6 + SMCode/SM2D/Drawing/DrawBackground.cs | 4 +- SMCode/SM2D/Drawing/DrawColor.cs | 6 +- SMCode/SM2D/Drawing/DrawComplex.cs | 7 +- SMCode/SM2D/Drawing/DrawText.cs | 10 +- SMCode/SM2D/Drawing/DrawTexture.cs | 14 +- SMCode/SM2D/GLWindow2D.cs | 11 +- SMCode/SM2D/Pipelines/Basic2DPipeline.cs | 23 ++ SMCode/SM2D/SM2D.csproj | 1 + SMCode/SM2D/Scene/ItemCollection.cs | 2 +- SMCode/SM2D/Scene/Scene.cs | 8 +- SMCode/SM2D/Shader/Default2DShader.cs | 8 +- SM_TEST/Program.cs | 7 +- 34 files changed, 660 insertions(+), 106 deletions(-) create mode 100644 SMCode/SM.Base/Log.cs create mode 100644 SMCode/SM.Base/Window/RenderPipeline.cs create mode 100644 SMCode/SM.OGL/Framebuffer/ColorAttachment.cs create mode 100644 SMCode/SM.OGL/Framebuffer/Framebuffer.cs create mode 100644 SMCode/SM2D/Pipelines/Basic2DPipeline.cs diff --git a/SMCode/SM.Base/Defaults.cs b/SMCode/SM.Base/Defaults.cs index cab5f23..5c6e62f 100644 --- a/SMCode/SM.Base/Defaults.cs +++ b/SMCode/SM.Base/Defaults.cs @@ -1,6 +1,7 @@ using SM.Base.Objects; using SM.Base.Objects.Static; using SM.Base.Scene; +using SM.Base.Text; using SM.OGL.Mesh; using SM.Utility; @@ -11,15 +12,16 @@ namespace SM.Base /// public class Defaults { - /// - /// The default shader. - /// - public static IShader DefaultShader; /// /// The default mesh. /// public static GenericMesh DefaultMesh = Plate.Object; + /// + /// The default font. + /// + public static Font DefaultFont; + /// /// The default deltatime helper. /// diff --git a/SMCode/SM.Base/Drawing/DrawingBasis.cs b/SMCode/SM.Base/Drawing/DrawingBasis.cs index 7594647..a0325f5 100644 --- a/SMCode/SM.Base/Drawing/DrawingBasis.cs +++ b/SMCode/SM.Base/Drawing/DrawingBasis.cs @@ -25,20 +25,21 @@ namespace SM.Base.Scene } /// - public virtual void Draw(DrawContext context) + public void Draw(DrawContext context) { + context.Material = _material; + context.Mesh = _mesh; + + DrawContext(ref context); } /// - /// Applies the current settings to the context. + /// Draws the context, that was given to them. /// /// - protected void ApplyContext(ref DrawContext context) + protected virtual void DrawContext(ref DrawContext context) { - _material.Shader ??= Defaults.DefaultShader; - context.Material = _material; - context.Mesh = _mesh; } } /// diff --git a/SMCode/SM.Base/Drawing/Material.cs b/SMCode/SM.Base/Drawing/Material.cs index 7d29edf..839ab4f 100644 --- a/SMCode/SM.Base/Drawing/Material.cs +++ b/SMCode/SM.Base/Drawing/Material.cs @@ -18,9 +18,8 @@ namespace SM.Base.Scene public Color4 Tint = Color4.White; /// - /// A shader, that is used to draw this material. - /// Default: Defaults.DefaultShaders + /// A custom shader, that is used to draw this material. /// - public IShader Shader = Defaults.DefaultShader; + public IShader CustomShader; } } \ No newline at end of file diff --git a/SMCode/SM.Base/Log.cs b/SMCode/SM.Base/Log.cs new file mode 100644 index 0000000..95124d5 --- /dev/null +++ b/SMCode/SM.Base/Log.cs @@ -0,0 +1,236 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Net.Http; +using System.Windows.Forms; +using OpenTK.Graphics.OpenGL4; +using SM.OGL; + +namespace SM.Base +{ + /// + /// Specifies the target. + /// + [Flags] + public enum LogTarget + { + /// + /// No target, will not draw. + /// + None = 0, + /// + /// Takes the . + /// + Default = 1, + /// + /// Writes the log to the console. + /// + Console = 2, + /// + /// Writes the log to the debugger at . + /// + Debugger = 4, + /// + /// Writes the log to the specific file. + /// + File = 8, + /// + /// Writes the log to every target. + /// + All = Console | Debugger | File + } + + /// + /// Preset log types. + /// + public enum LogType + { + /// + /// Informations. Console Color: Green + /// + Info, + /// + /// Warnings. Console Color: Yellow + /// + Warning, + /// + /// Error. Console Color: Red + /// + Error + } + + /// + /// Contains the system for logging. + /// + public class Log + { + private static StreamWriter _logStream; + private static bool _init = false; + + /// + /// Presets for the log targets. + /// + public static Dictionary Preset = new Dictionary() + { + {LogTarget.Console, "[%type%] %msg%"}, + {LogTarget.Debugger, "[%type%] %msg%"}, + {LogTarget.File, "<%date%, %time%> [%type%] %msg%"} + }; + + private static readonly Dictionary Colors = new Dictionary() + { + {LogType.Info, ConsoleColor.Green}, + {LogType.Warning, ConsoleColor.Yellow}, + {LogType.Error, ConsoleColor.Red}, + }; + + /// + /// Specified the default target. + /// + public static LogTarget DefaultTarget = LogTarget.All; + + /// + /// Sets the log file. At wish compresses the old file to a zip file. + /// + /// The path to the log file. + /// Path for the compression, if desired. + public static void SetLogFile(string path = "sm.log", string compressionFolder = "") + { + _logStream?.Close(); + + if (!_init) Init(); + + if (File.Exists(path)) + { + if (compressionFolder != "") + { + DateTime creation = File.GetLastWriteTime(path); + try + { + using ZipArchive archive = + ZipFile.Open( + $"{compressionFolder}{Path.DirectorySeparatorChar}{Path.GetFileName(path)}_{creation.Year.ToString() + creation.Month + creation.Day}_{creation.Hour.ToString() + creation.Minute + creation.Second + creation.Millisecond}.zip", + ZipArchiveMode.Create); + archive.CreateEntryFromFile(path, Path.GetFileName(path)); + } + catch + { + // ignore + } + } + + File.Delete(path); + } + + _logStream = new StreamWriter(path) {AutoFlush = true}; + + Write(LogType.Info, $"Activated new log file. ['{path}']"); + + } + + static void Init() + { + AppDomain.CurrentDomain.UnhandledException += ExceptionHandler; + AppDomain.CurrentDomain.DomainUnload += (sender, args) => + { + _logStream.WriteLine("Unload application"); + _logStream.Close(); + }; + + GLDebugging.DebugAction = GLDebugAction; + GLDebugging.GlErrorAction = code => + { + Write(LogType.Warning, $"A '{code}' GL error occured."); + }; + _init = true; + } + + private static void GLDebugAction(DebugSource source, DebugType type, DebugSeverity severity, string msg) + { + if (type.HasFlag(DebugType.DebugTypeError)) + { + throw new Exception("[GLError] "+msg); + } + Write(type != DebugType.DontCare ? type.ToString().Substring(9) : "DontCare", ConsoleColor.Gray, msg); + } + + [DebuggerStepThrough] + private static void ExceptionHandler(object sender, UnhandledExceptionEventArgs e) + { + Write(e.IsTerminating ? "Terminating Error" : LogType.Error.ToString(), e.IsTerminating ? ConsoleColor.DarkRed : ConsoleColor.Red, e.ExceptionObject); + + if (e.IsTerminating) + { + MessageBox.Show($"Critical error occured.\n\n{e.ExceptionObject}", + $"Terminating Error: {e.ExceptionObject.GetType().Name}"); + _logStream?.Close(); + } + } + + /// + /// Writes multiple lines of the same type to the log. + /// + public static void Write(LogType type, params T[] values) => Write(type.ToString(), Colors[type], values); + + /// + /// Writes multiple lines of the same type to the log. + /// + public static void Write(string type, ConsoleColor color, params T[] values) + { + for (var i = 0; i < values.Length; i++) + { + Write(type, color, values[i], DefaultTarget); + } + } + + /// + /// Writes one line to the log. + /// + public static void Write(LogType type, T value, LogTarget target = LogTarget.Default) => + Write(type.ToString(), Colors[type], value, target); + + /// + /// Writes one line to the log. + /// + /// + public static void Write(string type, ConsoleColor color, T value, LogTarget target = LogTarget.Default) + { + if (target == LogTarget.Default) + target = DefaultTarget; + + if (target.HasFlag(LogTarget.Console)) + ColorfulWriteLine(color, ProcessPreset(LogTarget.Console, type, value.ToString())); + if (target.HasFlag(LogTarget.Debugger)) + Debug.WriteLine(ProcessPreset(LogTarget.Debugger, type, value.ToString())); + if (target.HasFlag(LogTarget.File)) + _logStream?.WriteLine(ProcessPreset(LogTarget.File, type, value.ToString())); + } + + /// + /// Writes a text with a different color. + /// + /// + /// + public static void ColorfulWriteLine(ConsoleColor color, string value) + { + ConsoleColor before = Console.ForegroundColor; + + Console.ForegroundColor = color; + Console.WriteLine(value); + Console.ForegroundColor = before; + } + + static string ProcessPreset(LogTarget target, string type, string msg) + { + string preset = Preset[target]; + DateTime now = DateTime.Now; + + return preset.Replace("%date%", now.ToShortDateString()) + .Replace("%time%", now.ToShortTimeString()) + .Replace("%type%", type) + .Replace("%msg%", msg); + } + } +} \ No newline at end of file diff --git a/SMCode/SM.Base/SM.Base.csproj b/SMCode/SM.Base/SM.Base.csproj index 4c63000..1810f80 100644 --- a/SMCode/SM.Base/SM.Base.csproj +++ b/SMCode/SM.Base/SM.Base.csproj @@ -40,6 +40,9 @@ + + + @@ -54,6 +57,7 @@ + @@ -82,6 +86,7 @@ + diff --git a/SMCode/SM.Base/Scene/GenericCamera.cs b/SMCode/SM.Base/Scene/GenericCamera.cs index e6d3887..441b0a9 100644 --- a/SMCode/SM.Base/Scene/GenericCamera.cs +++ b/SMCode/SM.Base/Scene/GenericCamera.cs @@ -54,7 +54,7 @@ namespace SM.Base.Scene public abstract bool Orthographic { get; } /// /// This will calculate the world. - /// This is called on to calculate the world. + /// This is called on to calculate the world. /// /// The world scale /// The aspect ratio from the window. diff --git a/SMCode/SM.Base/Scene/GenericItemCollection.cs b/SMCode/SM.Base/Scene/GenericItemCollection.cs index 84d081f..30f7882 100644 --- a/SMCode/SM.Base/Scene/GenericItemCollection.cs +++ b/SMCode/SM.Base/Scene/GenericItemCollection.cs @@ -7,23 +7,24 @@ namespace SM.Base.Scene /// Contains a list of show items. /// /// The type of show items. - public abstract class GenericItemCollection : IShowItem, IShowCollection + public abstract class GenericItemCollection : List, IShowItem, IShowCollection where TItem : IShowItem { /// - public List Objects { get; } = new List(); + public List Objects => this; /// public void Update(UpdateContext context) { - throw new System.NotImplementedException(); + for(int i = 0; i < Objects.Count; i++) + this[i].Update(context); } /// public virtual void Draw(DrawContext context) { for (int i = 0; i < Objects.Count; i++) - Objects[i].Draw(context); + this[i].Draw(context); } } diff --git a/SMCode/SM.Base/Scene/GenericScene.cs b/SMCode/SM.Base/Scene/GenericScene.cs index 6b6cdf9..53ed232 100644 --- a/SMCode/SM.Base/Scene/GenericScene.cs +++ b/SMCode/SM.Base/Scene/GenericScene.cs @@ -4,13 +4,48 @@ using SM.Base.Contexts; namespace SM.Base.Scene { + /// + /// A generic scene, that imports functions for scene control. + /// + public abstract class GenericScene + { + /// + /// This contains the background. + /// + protected IBackgroundItem _background; + + /// + /// Draws this scene. + /// + public virtual void Draw(DrawContext context) + { + + } + + /// + /// Called, when the user activates the scene. + /// + internal void Activate() + { + OnActivating(); + } + + /// + /// Called, when the user activates the scene. + /// + protected virtual void OnActivating() + { } + } + /// /// A generic scene that imports different functions. /// /// The type of cameras. /// The type of show items. - public abstract class GenericScene : GenericItemCollection + /// The type for collections + public abstract class GenericScene : GenericScene where TCamera : GenericCamera, new() + where TCollection : GenericItemCollection, new() where TItem : IShowItem { /// @@ -28,13 +63,13 @@ namespace SM.Base.Scene public TCamera HUDCamera { get; set; } = new TCamera(); /// - /// This contains the background. + /// Objects inside the scene. /// - protected IBackgroundItem _background; + public TCollection Objects { get; set; } = new TCollection(); /// /// This defines the HUD objects. /// - public List HUD { get; } = new List(); + public TCollection HUD { get; } = new TCollection(); /// /// A collection for cameras to switch easier to different cameras. /// @@ -49,25 +84,10 @@ namespace SM.Base.Scene backgroundDrawContext.View = BackgroundCamera.CalculateViewMatrix(); _background?.Draw(backgroundDrawContext); - base.Draw(context); + Objects.Draw(context); context.View = HUDCamera.CalculateViewMatrix(); - for (int i = 0; i < HUD.Count; i++) - HUD[i].Draw(context); + HUD.Draw(context); } - - /// - /// Called, when the user activates the scene. - /// - internal void Activate() - { - OnActivating(); - } - - /// - /// Called, when the user activates the scene. - /// - protected virtual void OnActivating() - { } } } \ No newline at end of file diff --git a/SMCode/SM.Base/Text/Font.cs b/SMCode/SM.Base/Text/Font.cs index 4225543..b8cbfd0 100644 --- a/SMCode/SM.Base/Text/Font.cs +++ b/SMCode/SM.Base/Text/Font.cs @@ -127,7 +127,7 @@ namespace SM.Base.Text } /// - protected override void Compile() + public override void Compile() { RegenerateTexture(); base.Compile(); diff --git a/SMCode/SM.Base/Text/TextDrawingBasis.cs b/SMCode/SM.Base/Text/TextDrawingBasis.cs index 66cbfdf..07bd17d 100644 --- a/SMCode/SM.Base/Text/TextDrawingBasis.cs +++ b/SMCode/SM.Base/Text/TextDrawingBasis.cs @@ -75,9 +75,8 @@ namespace SM.Base.Text /// - public override void Draw(DrawContext context) + protected override void DrawContext(ref DrawContext context) { - base.Draw(context); if (_instances == null) GenerateMatrixes(); } diff --git a/SMCode/SM.Base/Textures/Texture.cs b/SMCode/SM.Base/Textures/Texture.cs index 020d2e7..2fc5a96 100644 --- a/SMCode/SM.Base/Textures/Texture.cs +++ b/SMCode/SM.Base/Textures/Texture.cs @@ -46,7 +46,7 @@ namespace SM.Base.Textures /// - protected override void Compile() + public override void Compile() { base.Compile(); @@ -54,7 +54,7 @@ namespace SM.Base.Textures } /// - protected override void Dispose() + public override void Dispose() { base.Dispose(); diff --git a/SMCode/SM.Base/Window/Contexts/DrawContext.cs b/SMCode/SM.Base/Window/Contexts/DrawContext.cs index a25c60e..406eede 100644 --- a/SMCode/SM.Base/Window/Contexts/DrawContext.cs +++ b/SMCode/SM.Base/Window/Contexts/DrawContext.cs @@ -38,9 +38,20 @@ namespace SM.Base.Contexts /// public Material Material; + /// + /// Contains the currently used render pipeline. + /// + public RenderPipeline ActivePipeline; + /// /// The current world scale. /// public Vector2 WorldScale; + + /// + /// Returns the appropriate shader. + /// Returns the material shader, if available, otherwise it will take the default shader from the render pipeline. + /// + public IShader Shader => Material.CustomShader ?? ActivePipeline._defaultShader; } } \ No newline at end of file diff --git a/SMCode/SM.Base/Window/GenericWindow.cs b/SMCode/SM.Base/Window/GenericWindow.cs index 1b92b4f..7aa2751 100644 --- a/SMCode/SM.Base/Window/GenericWindow.cs +++ b/SMCode/SM.Base/Window/GenericWindow.cs @@ -41,14 +41,14 @@ namespace SM.Base { GLSystem.INIT_SYSTEM(); - Console.Write("----------------------\n" + - "--- OpenGL Loading ---\n" + - "----------------------------------\n" + - $"--- {"DeviceVersion",14}: {GLSystem.DeviceVersion,-10} ---\n" + - $"--- {"ForcedVersion",14}: {GLSystem.ForcedVersion,-10} ---\n" + - $"--- {"ShadingVersion",14}: {GLSystem.ShadingVersion,-10} ---\n" + - $"--- {"Debugging",14}: {GLSystem.Debugging,-10} ---\n" + - $"----------------------------------\n"); + Log.Write("#", ConsoleColor.Cyan, "----------------------", + "--- OpenGL Loading ---", + "----------------------------------", + $"--- {"DeviceVersion",14}: {GLSystem.DeviceVersion,-10} ---", + $"--- {"ForcedVersion",14}: {GLSystem.ForcedVersion,-10} ---", + $"--- {"ShadingVersion",14}: {GLSystem.ShadingVersion,-10} ---", + $"--- {"Debugging",14}: {GLSystem.Debugging,-10} ---", + $"----------------------------------"); base.OnLoad(e); _loading = true; @@ -123,11 +123,9 @@ namespace SM.Base /// The base window. /// /// The scene type - /// The base item type /// The camera type - public abstract class GenericWindow : GenericWindow - where TScene : GenericScene, new() - where TItem : IShowItem + public abstract class GenericWindow : GenericWindow + where TScene : GenericScene, new() where TCamera : GenericCamera, new() { /// @@ -144,6 +142,11 @@ namespace SM.Base /// public TScene CurrentScene { get; private set; } + /// + /// Controls how a scene is rendered. + /// + public RenderPipeline RenderPipeline { get; private set; } + /// protected GenericWindow() { @@ -153,6 +156,7 @@ namespace SM.Base /// protected override void OnRenderFrame(FrameEventArgs e) { + Deltatime.RenderDelta = (float)e.Time; DrawContext drawContext = new DrawContext() { World = ViewportCamera.World, @@ -165,11 +169,11 @@ namespace SM.Base base.OnRenderFrame(e); - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - - CurrentScene.Draw(drawContext); + RenderPipeline.Render(ref drawContext, CurrentScene); SwapBuffers(); + + GLDebugging.CheckGLErrors(); } /// @@ -178,6 +182,7 @@ namespace SM.Base base.OnResize(e); ViewportCamera.RecalculateWorld(_worldScale, Aspect); + RenderPipeline.Resize(); } /// @@ -189,5 +194,15 @@ namespace SM.Base CurrentScene = scene; scene.Activate(); } + + /// + /// Defines the render pipeline. + /// + /// + public void SetRenderPipeline(RenderPipeline pipeline) + { + RenderPipeline = pipeline; + pipeline.Activate(this); + } } } \ No newline at end of file diff --git a/SMCode/SM.Base/Window/RenderPipeline.cs b/SMCode/SM.Base/Window/RenderPipeline.cs new file mode 100644 index 0000000..60c5e22 --- /dev/null +++ b/SMCode/SM.Base/Window/RenderPipeline.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using SM.Base.Contexts; +using SM.Base.Scene; +using SM.OGL.Framebuffer; + +namespace SM.Base +{ + /// + /// Definition of specific render options. + /// + public abstract class RenderPipeline + { + + /// + /// The framebuffers, that are used in this Pipeline. + /// + protected virtual List _framebuffers { get; } + + /// + /// The default shader for the pipeline. + /// + protected internal virtual IShader _defaultShader { get; } + + /// + /// Occurs, when the window is loading. + /// + protected internal virtual void Load() + { + foreach (Framebuffer framebuffer in _framebuffers) + framebuffer.Compile(); + } + + /// + /// Occurs, when the window is resizing. + /// + protected internal virtual void Resize() + { } + + /// + /// Occurs, when the pipeline was connected to a window. + /// + protected internal virtual void Activate(GenericWindow window) + { + } + + /// + /// Occurs, when the window is unloading. + /// + protected internal virtual void Unload() + { + foreach (Framebuffer framebuffer in _framebuffers) + { + framebuffer.Dispose(); + } + } + } + + /// + /// Represents a render pipeline. + /// + /// The scene type + public abstract class RenderPipeline : RenderPipeline + where TScene : GenericScene + { + + /// + /// The system to render stuff. + /// + protected internal virtual void Render(ref DrawContext context, TScene scene) + { + context.ActivePipeline = this; + } + } +} \ No newline at end of file diff --git a/SMCode/SM.OGL/Framebuffer/ColorAttachment.cs b/SMCode/SM.OGL/Framebuffer/ColorAttachment.cs new file mode 100644 index 0000000..60865b1 --- /dev/null +++ b/SMCode/SM.OGL/Framebuffer/ColorAttachment.cs @@ -0,0 +1,35 @@ +using System; +using OpenTK.Graphics.OpenGL4; +using SM.OGL.Texture; + +namespace SM.OGL.Framebuffer +{ + public class ColorAttachment : TextureBase + { + public int AttachmentID { get; } + + public FramebufferAttachment FramebufferAttachment => FramebufferAttachment.ColorAttachment0 + AttachmentID; + public DrawBufferMode DrawBufferMode => DrawBufferMode.ColorAttachment0 + AttachmentID; + public ReadBufferMode ReadBufferMode => ReadBufferMode.ColorAttachment0 + AttachmentID; + public DrawBuffersEnum DrawBuffersEnum => DrawBuffersEnum.ColorAttachment0 + AttachmentID; + + public ColorAttachment(int attachmentId) + { + AttachmentID = attachmentId; + } + + public void Generate(Framebuffer f) + { + _id = GL.GenTexture(); + GL.BindTexture(TextureTarget.Texture2D, _id); + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, + (int) f.Size.X, (int) f.Size.Y, + 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero); + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureParameterName.ClampToEdge); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureParameterName.ClampToEdge); + } + } +} \ No newline at end of file diff --git a/SMCode/SM.OGL/Framebuffer/Framebuffer.cs b/SMCode/SM.OGL/Framebuffer/Framebuffer.cs new file mode 100644 index 0000000..82b81b6 --- /dev/null +++ b/SMCode/SM.OGL/Framebuffer/Framebuffer.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using OpenTK; +using OpenTK.Graphics.OpenGL4; +using OpenTK.Platform; + +namespace SM.OGL.Framebuffer +{ + // TODO: Write summeries for framebuffer-system. + public class Framebuffer : GLObject + { + public static readonly Framebuffer Screen = new Framebuffer() + { + _id = 0, + _canBeCompiled = false + }; + + private bool _canBeCompiled = true; + + public override ObjectLabelIdentifier TypeIdentifier { get; } = ObjectLabelIdentifier.Framebuffer; + + public Vector2 Size { get; private set; } + + public Dictionary ColorAttachments { get; private set; } = new Dictionary(); + + public Framebuffer() + { } + + public Framebuffer(INativeWindow window, float scale = 1) : this(new Vector2(window.Width * scale, window.Height * scale)) + { } + + public Framebuffer(Vector2 size) + { + Size = size; + } + + public override void Compile() + { + if (!_canBeCompiled) return; + + base.Compile(); + _id = GL.GenFramebuffer(); + GL.BindFramebuffer(FramebufferTarget.Framebuffer, _id); + + DrawBuffersEnum[] enums = new DrawBuffersEnum[ColorAttachments.Count]; + int c = 0; + foreach (KeyValuePair pair in ColorAttachments) + { + pair.Value.Generate(this); + + enums[c++] = pair.Value.DrawBuffersEnum; + } + + GL.DrawBuffers(enums.Length, enums); + foreach (var pair in ColorAttachments) + GL.FramebufferTexture(FramebufferTarget.Framebuffer, pair.Value.FramebufferAttachment, pair.Value.ID, 0); + + FramebufferErrorCode err = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer); + if (err != FramebufferErrorCode.FramebufferComplete) + throw new Exception("Failed loading framebuffer.\nProblem: "+err); + + GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); + GL.BindTexture(TextureTarget.Texture2D, 0); + } + + public override void Dispose() + { + base.Dispose(); + foreach (ColorAttachment attachment in ColorAttachments.Values) attachment.Dispose(); + GL.DeleteFramebuffer(this); + } + + public void Append(string key, ColorAttachment value) + { + ColorAttachments.Add(key, value); + } + + + public void Activate() => Activate(FramebufferTarget.Framebuffer, ClearBufferMask.None); + public void Activate(FramebufferTarget target) => Activate(target, ClearBufferMask.None); + public void Activate(ClearBufferMask clearMask) => Activate(FramebufferTarget.Framebuffer, clearMask); + public void Activate(FramebufferTarget target, ClearBufferMask clear) + { + GL.Clear(clear); + GL.BindFramebuffer(target, this); + } + } +} \ No newline at end of file diff --git a/SMCode/SM.OGL/GLDebugging.cs b/SMCode/SM.OGL/GLDebugging.cs index 94b4fbd..daa3ae1 100644 --- a/SMCode/SM.OGL/GLDebugging.cs +++ b/SMCode/SM.OGL/GLDebugging.cs @@ -4,11 +4,12 @@ using System.Net.Http; using System.Runtime.InteropServices; using OpenTK.Graphics.OpenGL4; using OpenTK.Platform.Egl; +using ErrorCode = OpenTK.Graphics.OpenGL4.ErrorCode; namespace SM.OGL { /// - /// Contains everything that is needed to properly debug OpenGL + /// Contains everything that is needed to debug OpenGL /// public static class GLDebugging { @@ -63,5 +64,26 @@ namespace SM.OGL if (type == DebugType.DebugTypeError) throw new Exception(msg); } + + /// + /// A action, that is performed, when find an error. + /// + public static Action GlErrorAction; + + /// + /// Checks for OpenGL errors. + /// + public static bool CheckGLErrors() + { + bool hasError = false; + ErrorCode c; + while ((c = GL.GetError()) != ErrorCode.NoError) + { + hasError = true; + GlErrorAction?.Invoke(c); + } + + return hasError; + } } } \ No newline at end of file diff --git a/SMCode/SM.OGL/GLObject.cs b/SMCode/SM.OGL/GLObject.cs index 3de92f7..6f52109 100644 --- a/SMCode/SM.OGL/GLObject.cs +++ b/SMCode/SM.OGL/GLObject.cs @@ -1,4 +1,5 @@ -using OpenTK.Graphics.OpenGL4; +using System.Diagnostics; +using OpenTK.Graphics.OpenGL4; namespace SM.OGL { @@ -29,7 +30,7 @@ namespace SM.OGL { get { - if (AutoCompile && !WasCompiled) Compile(); + if (AutoCompile && !WasCompiled) PerformCompile(); return _id; } } @@ -39,10 +40,17 @@ namespace SM.OGL /// public abstract ObjectLabelIdentifier TypeIdentifier { get; } + [DebuggerStepThrough] + private void PerformCompile() + { + Compile(); + } + /// /// The action, that is called, when "ID" tries to compile something. /// - protected virtual void Compile() + + public virtual void Compile() { } @@ -50,7 +58,7 @@ namespace SM.OGL /// /// Is triggered, when something want to dispose this object. /// - protected virtual void Dispose() {} + public virtual void Dispose() {} /// /// Re-compiles the object. @@ -72,10 +80,15 @@ namespace SM.OGL if (GLSystem.Debugging) GL.ObjectLabel(TypeIdentifier, _id, name.Length, name); } + protected virtual int GetID() + { + return _id; + } + /// /// Returns the ID for the object. /// /// - public static implicit operator int(GLObject glo) => glo.ID; + public static implicit operator int(GLObject glo) => glo.GetID(); } } \ No newline at end of file diff --git a/SMCode/SM.OGL/Mesh/GenericMesh.cs b/SMCode/SM.OGL/Mesh/GenericMesh.cs index 702e1f8..3af41fd 100644 --- a/SMCode/SM.OGL/Mesh/GenericMesh.cs +++ b/SMCode/SM.OGL/Mesh/GenericMesh.cs @@ -64,7 +64,7 @@ namespace SM.OGL.Mesh } /// - protected override void Compile() + public override void Compile() { _id = GL.GenVertexArray(); GL.BindVertexArray(_id); diff --git a/SMCode/SM.OGL/SM.OGL.csproj b/SMCode/SM.OGL/SM.OGL.csproj index 0039260..5fc7a58 100644 --- a/SMCode/SM.OGL/SM.OGL.csproj +++ b/SMCode/SM.OGL/SM.OGL.csproj @@ -46,6 +46,8 @@ + + diff --git a/SMCode/SM.OGL/Shaders/GenericShader.cs b/SMCode/SM.OGL/Shaders/GenericShader.cs index a09f2c3..a39e659 100644 --- a/SMCode/SM.OGL/Shaders/GenericShader.cs +++ b/SMCode/SM.OGL/Shaders/GenericShader.cs @@ -59,7 +59,7 @@ namespace SM.OGL.Shaders } /// - protected override void Compile() + public override void Compile() { Load(); } @@ -70,7 +70,7 @@ namespace SM.OGL.Shaders /// The mesh. /// The amounts for instancing. /// Binds the vertex array for the mesh. - protected void DrawObject(Mesh.GenericMesh mesh, int amount, bool bindVAO = false) + protected void DrawObject(Mesh.GenericMesh mesh, int amount = 1, bool bindVAO = false) { if (bindVAO) GL.BindVertexArray(mesh); diff --git a/SMCode/SM.OGL/Texture/TextureBase.cs b/SMCode/SM.OGL/Texture/TextureBase.cs index d2ffb23..8779140 100644 --- a/SMCode/SM.OGL/Texture/TextureBase.cs +++ b/SMCode/SM.OGL/Texture/TextureBase.cs @@ -33,5 +33,11 @@ namespace SM.OGL.Texture /// The height of the texture /// public int Height { get; protected set; } + + public override void Dispose() + { + base.Dispose(); + GL.DeleteTexture(_id); + } } } \ No newline at end of file diff --git a/SMCode/SM2D/Drawing/DrawBackground.cs b/SMCode/SM2D/Drawing/DrawBackground.cs index 2f1eab5..bdc17c8 100644 --- a/SMCode/SM2D/Drawing/DrawBackground.cs +++ b/SMCode/SM2D/Drawing/DrawBackground.cs @@ -50,13 +50,11 @@ namespace SM2D.Drawing public void Draw(DrawContext context) { - if (_material.Shader == null) _material.Shader = Defaults.DefaultShader; - context.Material = _material; context.Mesh = Plate.Object; context.Instances[0].ModelMatrix = Matrix4.CreateScale(context.WorldScale.X, context.WorldScale.Y, 1); - _material.Shader.Draw(context); + context.Shader.Draw(context); } } } \ No newline at end of file diff --git a/SMCode/SM2D/Drawing/DrawColor.cs b/SMCode/SM2D/Drawing/DrawColor.cs index 695f5ef..2cc6b84 100644 --- a/SMCode/SM2D/Drawing/DrawColor.cs +++ b/SMCode/SM2D/Drawing/DrawColor.cs @@ -24,13 +24,11 @@ namespace SM2D.Drawing _material.Tint = color; } - public override void Draw(DrawContext context) + protected override void DrawContext(ref DrawContext context) { - base.Draw(context); - ApplyContext(ref context); context.Instances[0].ModelMatrix = Transform.GetMatrix(); - _material.Shader.Draw(context); + context.Shader.Draw(context); } } } \ No newline at end of file diff --git a/SMCode/SM2D/Drawing/DrawComplex.cs b/SMCode/SM2D/Drawing/DrawComplex.cs index a6f9370..6d52794 100644 --- a/SMCode/SM2D/Drawing/DrawComplex.cs +++ b/SMCode/SM2D/Drawing/DrawComplex.cs @@ -22,14 +22,11 @@ namespace SM2D.Drawing set => _mesh = value; } - public override void Draw(DrawContext context) + protected override void DrawContext(ref DrawContext context) { - base.Draw(context); - ApplyContext(ref context); - context.Instances[0].ModelMatrix = Transform.GetMatrix(); - _material.Shader.Draw(context); + context.Shader.Draw(context); } } } \ No newline at end of file diff --git a/SMCode/SM2D/Drawing/DrawText.cs b/SMCode/SM2D/Drawing/DrawText.cs index e18ff07..66e2985 100644 --- a/SMCode/SM2D/Drawing/DrawText.cs +++ b/SMCode/SM2D/Drawing/DrawText.cs @@ -1,4 +1,5 @@ -using SM.Base.Contexts; +using SM.Base; +using SM.Base.Contexts; using SM.Base.Text; using SM.Base.Types; using SM2D.Scene; @@ -14,15 +15,14 @@ namespace SM2D.Drawing Transform.Size = new CVector2(1); } - public override void Draw(DrawContext context) + protected override void DrawContext(ref DrawContext context) { - base.Draw(context); + base.DrawContext(ref context); context.Instances = _instances; - ApplyContext(ref context); context.View = Transform.GetMatrix() * context.View; - _material.Shader.Draw(context); + context.Shader.Draw(context); } public int ZIndex { get; set; } diff --git a/SMCode/SM2D/Drawing/DrawTexture.cs b/SMCode/SM2D/Drawing/DrawTexture.cs index ad7b550..bc2765c 100644 --- a/SMCode/SM2D/Drawing/DrawTexture.cs +++ b/SMCode/SM2D/Drawing/DrawTexture.cs @@ -15,6 +15,7 @@ namespace SM2D.Drawing public static float MasterScale = .25f; public float Scale = 1; + public bool ManualSize = false; public Texture Texture { get => (Texture) _material.Texture; @@ -28,16 +29,19 @@ namespace SM2D.Drawing public DrawTexture(Bitmap map) : this(map, Color4.White) { } - public DrawTexture(Bitmap map, Color4 color) + public DrawTexture(Bitmap map, Color4 color) : this((Texture)map, color) + { } + + public DrawTexture(Texture texture, Color4 color) { - _material.Texture = new Texture(map); + _material.Texture = texture; _material.Tint = color; } - public override void Draw(DrawContext context) + protected override void DrawContext(ref DrawContext context) { - Transform.Size = new CVector2(Texture.Map.Width * MasterScale * Scale, Texture.Map.Height * MasterScale * Scale); - base.Draw(context); + if (!ManualSize) Transform.Size = new CVector2(Texture.Map.Width * MasterScale * Scale, Texture.Map.Height * MasterScale * Scale); + base.DrawContext(ref context); } } } \ No newline at end of file diff --git a/SMCode/SM2D/GLWindow2D.cs b/SMCode/SM2D/GLWindow2D.cs index b1342b5..da64f07 100644 --- a/SMCode/SM2D/GLWindow2D.cs +++ b/SMCode/SM2D/GLWindow2D.cs @@ -5,13 +5,14 @@ using OpenTK.Input; using SM.Base; using SM.Base.Controls; using SM2D.Controls; +using SM2D.Pipelines; using SM2D.Scene; using SM2D.Shader; using Vector2 = OpenTK.Vector2; namespace SM2D { - public class GLWindow2D : GenericWindow + public class GLWindow2D : GenericWindow { public Vector2? Scaling { get; set; } public Vector2 WorldScale => _worldScale; @@ -25,13 +26,17 @@ namespace SM2D protected override void OnLoad(EventArgs e) { - Defaults.DefaultShader = new Default2DShader(); - base.OnLoad(e); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); } + protected override void OnLoaded() + { + base.OnLoaded(); + SetRenderPipeline(new Basic2DPipeline()); + } + protected override void OnRenderFrame(FrameEventArgs e) { GL.Disable(EnableCap.DepthTest); diff --git a/SMCode/SM2D/Pipelines/Basic2DPipeline.cs b/SMCode/SM2D/Pipelines/Basic2DPipeline.cs new file mode 100644 index 0000000..d70a156 --- /dev/null +++ b/SMCode/SM2D/Pipelines/Basic2DPipeline.cs @@ -0,0 +1,23 @@ +using OpenTK.Graphics.OpenGL4; +using SM.Base; +using SM.Base.Contexts; +using SM.Base.Scene; +using SM.OGL.Framebuffer; +using SM2D.Shader; + +namespace SM2D.Pipelines +{ + public class Basic2DPipeline : RenderPipeline + { + protected override IShader _defaultShader { get; } = Default2DShader.Shader; + + protected override void Render(ref DrawContext context, Scene.Scene scene) + { + base.Render(ref context, scene); + + Framebuffer.Screen.Activate(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + + scene.Draw(context); + } + } +} \ No newline at end of file diff --git a/SMCode/SM2D/SM2D.csproj b/SMCode/SM2D/SM2D.csproj index 9484dd6..dd1d2da 100644 --- a/SMCode/SM2D/SM2D.csproj +++ b/SMCode/SM2D/SM2D.csproj @@ -55,6 +55,7 @@ + diff --git a/SMCode/SM2D/Scene/ItemCollection.cs b/SMCode/SM2D/Scene/ItemCollection.cs index 986f5d4..6dbb38e 100644 --- a/SMCode/SM2D/Scene/ItemCollection.cs +++ b/SMCode/SM2D/Scene/ItemCollection.cs @@ -14,7 +14,7 @@ namespace SM2D.Scene public override void Draw(DrawContext context) { - Objects.Sort((x, y) => x.ZIndex - y.ZIndex); + Sort((x, y) => x.ZIndex - y.ZIndex); base.Draw(context); } diff --git a/SMCode/SM2D/Scene/Scene.cs b/SMCode/SM2D/Scene/Scene.cs index 17f784f..9a94156 100644 --- a/SMCode/SM2D/Scene/Scene.cs +++ b/SMCode/SM2D/Scene/Scene.cs @@ -5,7 +5,7 @@ using SM2D.Drawing; namespace SM2D.Scene { - public class Scene : GenericScene + public class Scene : GenericScene { public DrawBackground Background => (DrawBackground)_background; @@ -13,11 +13,5 @@ namespace SM2D.Scene { _background = new DrawBackground(Color4.Black); } - - public override void Draw(DrawContext context) - { - Objects.Sort((x,y) => x.ZIndex - y.ZIndex); - base.Draw(context); - } } } \ No newline at end of file diff --git a/SMCode/SM2D/Shader/Default2DShader.cs b/SMCode/SM2D/Shader/Default2DShader.cs index 1932adf..854f00f 100644 --- a/SMCode/SM2D/Shader/Default2DShader.cs +++ b/SMCode/SM2D/Shader/Default2DShader.cs @@ -8,13 +8,15 @@ namespace SM2D.Shader { public class Default2DShader : GenericShader, IShader { - protected override bool AutoCompile { get; } = true; + public static Default2DShader Shader = new Default2DShader(); - public Default2DShader() : base(new ShaderFileCollection( + //protected override bool AutoCompile { get; } = true; + + private Default2DShader() : base(new ShaderFileCollection( AssemblyUtility.ReadAssemblyFile("SM2D.Shader.ShaderFiles.default.vert"), AssemblyUtility.ReadAssemblyFile("SM2D.Shader.ShaderFiles.default.frag"))) { - + Load(); } public void Draw(DrawContext context) { diff --git a/SM_TEST/Program.cs b/SM_TEST/Program.cs index ae04fc0..ad6816d 100644 --- a/SM_TEST/Program.cs +++ b/SM_TEST/Program.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.Runtime.InteropServices; using OpenTK; using OpenTK.Graphics; +using SM.Base; using SM.Base.Time; using SM2D; using SM2D.Drawing; @@ -28,6 +29,8 @@ namespace SM_TEST FontSize = 32 }; + Log.SetLogFile(compressionFolder:"logs"); + window = new GLWindow2D {Scaling = new Vector2(0, 1000)}; //window.GrabCursor(); window.SetScene(scene = new Scene()); @@ -53,11 +56,11 @@ namespace SM_TEST ZIndex = 1 }; - col.Objects.Add(new DrawTexture(new Bitmap("soldier_logo.png")) + col.Add(new DrawTexture(new Bitmap("soldier_logo.png")) { ZIndex = 1 }); - col.Objects.Add(new DrawColor(Color4.Black) + col.Add(new DrawColor(Color4.Black) { Transform = { Rotation = 45, Position = new SM.Base.Types.CVector2(0, 25) }, ZIndex = 2