04.10.2020

+ render pipeline system for more control about the renderering.
+ Log system
+ Framebuffer system

~ Default shader was moved to pipelines.
This commit is contained in:
Michel Fedde 2020-10-04 16:31:48 +02:00
parent 97e638d9d9
commit 820d6ce700
34 changed files with 660 additions and 106 deletions

View file

@ -1,6 +1,7 @@
using SM.Base.Objects; using SM.Base.Objects;
using SM.Base.Objects.Static; using SM.Base.Objects.Static;
using SM.Base.Scene; using SM.Base.Scene;
using SM.Base.Text;
using SM.OGL.Mesh; using SM.OGL.Mesh;
using SM.Utility; using SM.Utility;
@ -11,15 +12,16 @@ namespace SM.Base
/// </summary> /// </summary>
public class Defaults public class Defaults
{ {
/// <summary>
/// The default shader.
/// </summary>
public static IShader DefaultShader;
/// <summary> /// <summary>
/// The default mesh. /// The default mesh.
/// </summary> /// </summary>
public static GenericMesh DefaultMesh = Plate.Object; public static GenericMesh DefaultMesh = Plate.Object;
/// <summary>
/// The default font.
/// </summary>
public static Font DefaultFont;
/// <summary> /// <summary>
/// The default deltatime helper. /// The default deltatime helper.
/// </summary> /// </summary>

View file

@ -25,20 +25,21 @@ namespace SM.Base.Scene
} }
/// <inheritdoc /> /// <inheritdoc />
public virtual void Draw(DrawContext context) public void Draw(DrawContext context)
{ {
context.Material = _material;
context.Mesh = _mesh;
DrawContext(ref context);
} }
/// <summary> /// <summary>
/// Applies the current settings to the context. /// Draws the context, that was given to them.
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected void ApplyContext(ref DrawContext context) protected virtual void DrawContext(ref DrawContext context)
{ {
_material.Shader ??= Defaults.DefaultShader;
context.Material = _material;
context.Mesh = _mesh;
} }
} }
/// <summary> /// <summary>

View file

@ -18,9 +18,8 @@ namespace SM.Base.Scene
public Color4 Tint = Color4.White; public Color4 Tint = Color4.White;
/// <summary> /// <summary>
/// A shader, that is used to draw this material. /// A custom shader, that is used to draw this material.
/// <para>Default: Defaults.DefaultShaders </para>
/// </summary> /// </summary>
public IShader Shader = Defaults.DefaultShader; public IShader CustomShader;
} }
} }

236
SMCode/SM.Base/Log.cs Normal file
View file

@ -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
{
/// <summary>
/// Specifies the target.
/// </summary>
[Flags]
public enum LogTarget
{
/// <summary>
/// No target, will not draw.
/// </summary>
None = 0,
/// <summary>
/// Takes the <see cref="Log.DefaultTarget"/>.
/// </summary>
Default = 1,
/// <summary>
/// Writes the log to the console.
/// </summary>
Console = 2,
/// <summary>
/// Writes the log to the debugger at <see cref="Debug"/>.
/// </summary>
Debugger = 4,
/// <summary>
/// Writes the log to the specific file.
/// </summary>
File = 8,
/// <summary>
/// Writes the log to every target.
/// </summary>
All = Console | Debugger | File
}
/// <summary>
/// Preset log types.
/// </summary>
public enum LogType
{
/// <summary>
/// Informations. Console Color: Green
/// </summary>
Info,
/// <summary>
/// Warnings. Console Color: Yellow
/// </summary>
Warning,
/// <summary>
/// Error. Console Color: Red
/// </summary>
Error
}
/// <summary>
/// Contains the system for logging.
/// </summary>
public class Log
{
private static StreamWriter _logStream;
private static bool _init = false;
/// <summary>
/// Presets for the log targets.
/// </summary>
public static Dictionary<LogTarget, string> Preset = new Dictionary<LogTarget, string>()
{
{LogTarget.Console, "[%type%] %msg%"},
{LogTarget.Debugger, "[%type%] %msg%"},
{LogTarget.File, "<%date%, %time%> [%type%] %msg%"}
};
private static readonly Dictionary<LogType, ConsoleColor> Colors = new Dictionary<LogType, ConsoleColor>()
{
{LogType.Info, ConsoleColor.Green},
{LogType.Warning, ConsoleColor.Yellow},
{LogType.Error, ConsoleColor.Red},
};
/// <summary>
/// Specified the default target.
/// </summary>
public static LogTarget DefaultTarget = LogTarget.All;
/// <summary>
/// Sets the log file. At wish compresses the old file to a zip file.
/// </summary>
/// <param name="path">The path to the log file.</param>
/// <param name="compressionFolder">Path for the compression, if desired.</param>
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();
}
}
/// <summary>
/// Writes multiple lines of the same type to the log.
/// </summary>
public static void Write<T>(LogType type, params T[] values) => Write<T>(type.ToString(), Colors[type], values);
/// <summary>
/// Writes multiple lines of the same type to the log.
/// </summary>
public static void Write<T>(string type, ConsoleColor color, params T[] values)
{
for (var i = 0; i < values.Length; i++)
{
Write(type, color, values[i], DefaultTarget);
}
}
/// <summary>
/// Writes one line to the log.
/// </summary>
public static void Write<T>(LogType type, T value, LogTarget target = LogTarget.Default) =>
Write<T>(type.ToString(), Colors[type], value, target);
/// <summary>
/// Writes one line to the log.
///
/// </summary>
public static void Write<T>(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()));
}
/// <summary>
/// Writes a text with a different color.
/// </summary>
/// <param name="color"></param>
/// <param name="value"></param>
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);
}
}
}

View file

@ -40,6 +40,9 @@
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@ -54,6 +57,7 @@
<Compile Include="Drawing\GenericTransformation.cs" /> <Compile Include="Drawing\GenericTransformation.cs" />
<Compile Include="Drawing\Instance.cs" /> <Compile Include="Drawing\Instance.cs" />
<Compile Include="Drawing\IShader.cs" /> <Compile Include="Drawing\IShader.cs" />
<Compile Include="Log.cs" />
<Compile Include="Objects\Mesh.cs" /> <Compile Include="Objects\Mesh.cs" />
<Compile Include="Scene\IShowCollection.cs" /> <Compile Include="Scene\IShowCollection.cs" />
<Compile Include="Scene\IShowItem.cs" /> <Compile Include="Scene\IShowItem.cs" />
@ -82,6 +86,7 @@
<Compile Include="Scene\GenericCamera.cs" /> <Compile Include="Scene\GenericCamera.cs" />
<Compile Include="Scene\GenericScene.cs" /> <Compile Include="Scene\GenericScene.cs" />
<Compile Include="Objects\Static\Plate.cs" /> <Compile Include="Objects\Static\Plate.cs" />
<Compile Include="Window\RenderPipeline.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="OpenTK.dll.config" /> <None Include="OpenTK.dll.config" />

View file

@ -54,7 +54,7 @@ namespace SM.Base.Scene
public abstract bool Orthographic { get; } public abstract bool Orthographic { get; }
/// <summary> /// <summary>
/// This will calculate the world. /// This will calculate the world.
/// <para>This is called on <see cref="GenericWindow{TScene,TItem,TCamera}.ViewportCamera"/> to calculate the world.</para> /// <para>This is called on <see cref="GenericWindow{TScene,TCamera}.ViewportCamera"/> to calculate the world.</para>
/// </summary> /// </summary>
/// <param name="world">The world scale</param> /// <param name="world">The world scale</param>
/// <param name="aspect">The aspect ratio from the window.</param> /// <param name="aspect">The aspect ratio from the window.</param>

View file

@ -7,23 +7,24 @@ namespace SM.Base.Scene
/// Contains a list of show items. /// Contains a list of show items.
/// </summary> /// </summary>
/// <typeparam name="TItem">The type of show items.</typeparam> /// <typeparam name="TItem">The type of show items.</typeparam>
public abstract class GenericItemCollection<TItem> : IShowItem, IShowCollection<TItem> public abstract class GenericItemCollection<TItem> : List<TItem>, IShowItem, IShowCollection<TItem>
where TItem : IShowItem where TItem : IShowItem
{ {
/// <inheritdoc /> /// <inheritdoc />
public List<TItem> Objects { get; } = new List<TItem>(); public List<TItem> Objects => this;
/// <inheritdoc /> /// <inheritdoc />
public void Update(UpdateContext context) public void Update(UpdateContext context)
{ {
throw new System.NotImplementedException(); for(int i = 0; i < Objects.Count; i++)
this[i].Update(context);
} }
/// <inheritdoc cref="IShowCollection{TItem}.Draw" /> /// <inheritdoc cref="IShowCollection{TItem}.Draw" />
public virtual void Draw(DrawContext context) public virtual void Draw(DrawContext context)
{ {
for (int i = 0; i < Objects.Count; i++) for (int i = 0; i < Objects.Count; i++)
Objects[i].Draw(context); this[i].Draw(context);
} }
} }

View file

@ -4,13 +4,48 @@ using SM.Base.Contexts;
namespace SM.Base.Scene namespace SM.Base.Scene
{ {
/// <summary>
/// A generic scene, that imports functions for scene control.
/// </summary>
public abstract class GenericScene
{
/// <summary>
/// This contains the background.
/// </summary>
protected IBackgroundItem _background;
/// <summary>
/// Draws this scene.
/// </summary>
public virtual void Draw(DrawContext context)
{
}
/// <summary>
/// Called, when the user activates the scene.
/// </summary>
internal void Activate()
{
OnActivating();
}
/// <summary>
/// Called, when the user activates the scene.
/// </summary>
protected virtual void OnActivating()
{ }
}
/// <summary> /// <summary>
/// A generic scene that imports different functions. /// A generic scene that imports different functions.
/// </summary> /// </summary>
/// <typeparam name="TCamera">The type of cameras.</typeparam> /// <typeparam name="TCamera">The type of cameras.</typeparam>
/// <typeparam name="TItem">The type of show items.</typeparam> /// <typeparam name="TItem">The type of show items.</typeparam>
public abstract class GenericScene<TCamera, TItem> : GenericItemCollection<TItem> /// <typeparam name="TCollection">The type for collections</typeparam>
public abstract class GenericScene<TCamera, TCollection, TItem> : GenericScene
where TCamera : GenericCamera, new() where TCamera : GenericCamera, new()
where TCollection : GenericItemCollection<TItem>, new()
where TItem : IShowItem where TItem : IShowItem
{ {
/// <summary> /// <summary>
@ -28,13 +63,13 @@ namespace SM.Base.Scene
public TCamera HUDCamera { get; set; } = new TCamera(); public TCamera HUDCamera { get; set; } = new TCamera();
/// <summary> /// <summary>
/// This contains the background. /// Objects inside the scene.
/// </summary> /// </summary>
protected IBackgroundItem _background; public TCollection Objects { get; set; } = new TCollection();
/// <summary> /// <summary>
/// This defines the HUD objects. /// This defines the HUD objects.
/// </summary> /// </summary>
public List<TItem> HUD { get; } = new List<TItem>(); public TCollection HUD { get; } = new TCollection();
/// <summary> /// <summary>
/// A collection for cameras to switch easier to different cameras. /// A collection for cameras to switch easier to different cameras.
/// </summary> /// </summary>
@ -49,25 +84,10 @@ namespace SM.Base.Scene
backgroundDrawContext.View = BackgroundCamera.CalculateViewMatrix(); backgroundDrawContext.View = BackgroundCamera.CalculateViewMatrix();
_background?.Draw(backgroundDrawContext); _background?.Draw(backgroundDrawContext);
base.Draw(context); Objects.Draw(context);
context.View = HUDCamera.CalculateViewMatrix(); context.View = HUDCamera.CalculateViewMatrix();
for (int i = 0; i < HUD.Count; i++) HUD.Draw(context);
HUD[i].Draw(context);
} }
/// <summary>
/// Called, when the user activates the scene.
/// </summary>
internal void Activate()
{
OnActivating();
}
/// <summary>
/// Called, when the user activates the scene.
/// </summary>
protected virtual void OnActivating()
{ }
} }
} }

View file

@ -127,7 +127,7 @@ namespace SM.Base.Text
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void Compile() public override void Compile()
{ {
RegenerateTexture(); RegenerateTexture();
base.Compile(); base.Compile();

View file

@ -75,9 +75,8 @@ namespace SM.Base.Text
/// <inheritdoc /> /// <inheritdoc />
public override void Draw(DrawContext context) protected override void DrawContext(ref DrawContext context)
{ {
base.Draw(context);
if (_instances == null) GenerateMatrixes(); if (_instances == null) GenerateMatrixes();
} }

View file

@ -46,7 +46,7 @@ namespace SM.Base.Textures
/// <inheritdoc /> /// <inheritdoc />
protected override void Compile() public override void Compile()
{ {
base.Compile(); base.Compile();
@ -54,7 +54,7 @@ namespace SM.Base.Textures
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void Dispose() public override void Dispose()
{ {
base.Dispose(); base.Dispose();

View file

@ -38,9 +38,20 @@ namespace SM.Base.Contexts
/// </summary> /// </summary>
public Material Material; public Material Material;
/// <summary>
/// Contains the currently used render pipeline.
/// </summary>
public RenderPipeline ActivePipeline;
/// <summary> /// <summary>
/// The current world scale. /// The current world scale.
/// </summary> /// </summary>
public Vector2 WorldScale; public Vector2 WorldScale;
/// <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 IShader Shader => Material.CustomShader ?? ActivePipeline._defaultShader;
} }
} }

View file

@ -41,14 +41,14 @@ namespace SM.Base
{ {
GLSystem.INIT_SYSTEM(); GLSystem.INIT_SYSTEM();
Console.Write("----------------------\n" + Log.Write("#", ConsoleColor.Cyan, "----------------------",
"--- OpenGL Loading ---\n" + "--- OpenGL Loading ---",
"----------------------------------\n" + "----------------------------------",
$"--- {"DeviceVersion",14}: {GLSystem.DeviceVersion,-10} ---\n" + $"--- {"DeviceVersion",14}: {GLSystem.DeviceVersion,-10} ---",
$"--- {"ForcedVersion",14}: {GLSystem.ForcedVersion,-10} ---\n" + $"--- {"ForcedVersion",14}: {GLSystem.ForcedVersion,-10} ---",
$"--- {"ShadingVersion",14}: {GLSystem.ShadingVersion,-10} ---\n" + $"--- {"ShadingVersion",14}: {GLSystem.ShadingVersion,-10} ---",
$"--- {"Debugging",14}: {GLSystem.Debugging,-10} ---\n" + $"--- {"Debugging",14}: {GLSystem.Debugging,-10} ---",
$"----------------------------------\n"); $"----------------------------------");
base.OnLoad(e); base.OnLoad(e);
_loading = true; _loading = true;
@ -123,11 +123,9 @@ namespace SM.Base
/// The base window. /// The base window.
/// </summary> /// </summary>
/// <typeparam name="TScene">The scene type</typeparam> /// <typeparam name="TScene">The scene type</typeparam>
/// <typeparam name="TItem">The base item type</typeparam>
/// <typeparam name="TCamera">The camera type</typeparam> /// <typeparam name="TCamera">The camera type</typeparam>
public abstract class GenericWindow<TScene, TItem, TCamera> : GenericWindow public abstract class GenericWindow<TScene, TCamera> : GenericWindow
where TScene : GenericScene<TCamera, TItem>, new() where TScene : GenericScene, new()
where TItem : IShowItem
where TCamera : GenericCamera, new() where TCamera : GenericCamera, new()
{ {
/// <summary> /// <summary>
@ -144,6 +142,11 @@ namespace SM.Base
/// </summary> /// </summary>
public TScene CurrentScene { get; private set; } public TScene CurrentScene { get; private set; }
/// <summary>
/// Controls how a scene is rendered.
/// </summary>
public RenderPipeline<TScene> RenderPipeline { get; private set; }
/// <inheritdoc /> /// <inheritdoc />
protected GenericWindow() protected GenericWindow()
{ {
@ -153,6 +156,7 @@ namespace SM.Base
/// <inheritdoc /> /// <inheritdoc />
protected override void OnRenderFrame(FrameEventArgs e) protected override void OnRenderFrame(FrameEventArgs e)
{ {
Deltatime.RenderDelta = (float)e.Time;
DrawContext drawContext = new DrawContext() DrawContext drawContext = new DrawContext()
{ {
World = ViewportCamera.World, World = ViewportCamera.World,
@ -165,11 +169,11 @@ namespace SM.Base
base.OnRenderFrame(e); base.OnRenderFrame(e);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); RenderPipeline.Render(ref drawContext, CurrentScene);
CurrentScene.Draw(drawContext);
SwapBuffers(); SwapBuffers();
GLDebugging.CheckGLErrors();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -178,6 +182,7 @@ namespace SM.Base
base.OnResize(e); base.OnResize(e);
ViewportCamera.RecalculateWorld(_worldScale, Aspect); ViewportCamera.RecalculateWorld(_worldScale, Aspect);
RenderPipeline.Resize();
} }
/// <summary> /// <summary>
@ -189,5 +194,15 @@ namespace SM.Base
CurrentScene = scene; CurrentScene = scene;
scene.Activate(); scene.Activate();
} }
/// <summary>
/// Defines the render pipeline.
/// </summary>
/// <param name="pipeline"></param>
public void SetRenderPipeline(RenderPipeline<TScene> pipeline)
{
RenderPipeline = pipeline;
pipeline.Activate(this);
}
} }
} }

View file

@ -0,0 +1,74 @@
using System.Collections.Generic;
using SM.Base.Contexts;
using SM.Base.Scene;
using SM.OGL.Framebuffer;
namespace SM.Base
{
/// <summary>
/// Definition of specific render options.
/// </summary>
public abstract class RenderPipeline
{
/// <summary>
/// The framebuffers, that are used in this Pipeline.
/// </summary>
protected virtual List<Framebuffer> _framebuffers { get; }
/// <summary>
/// The default shader for the pipeline.
/// </summary>
protected internal virtual IShader _defaultShader { get; }
/// <summary>
/// Occurs, when the window is loading.
/// </summary>
protected internal virtual void Load()
{
foreach (Framebuffer framebuffer in _framebuffers)
framebuffer.Compile();
}
/// <summary>
/// Occurs, when the window is resizing.
/// </summary>
protected internal virtual void Resize()
{ }
/// <summary>
/// Occurs, when the pipeline was connected to a window.
/// </summary>
protected internal virtual void Activate(GenericWindow window)
{
}
/// <summary>
/// Occurs, when the window is unloading.
/// </summary>
protected internal virtual void Unload()
{
foreach (Framebuffer framebuffer in _framebuffers)
{
framebuffer.Dispose();
}
}
}
/// <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>
protected internal virtual void Render(ref DrawContext context, TScene scene)
{
context.ActivePipeline = this;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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<string, ColorAttachment> ColorAttachments { get; private set; } = new Dictionary<string, ColorAttachment>();
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<string, ColorAttachment> 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);
}
}
}

View file

@ -4,11 +4,12 @@ using System.Net.Http;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using OpenTK.Graphics.OpenGL4; using OpenTK.Graphics.OpenGL4;
using OpenTK.Platform.Egl; using OpenTK.Platform.Egl;
using ErrorCode = OpenTK.Graphics.OpenGL4.ErrorCode;
namespace SM.OGL namespace SM.OGL
{ {
/// <summary> /// <summary>
/// Contains everything that is needed to properly debug OpenGL /// Contains everything that is needed to debug OpenGL
/// </summary> /// </summary>
public static class GLDebugging public static class GLDebugging
{ {
@ -63,5 +64,26 @@ namespace SM.OGL
if (type == DebugType.DebugTypeError) throw new Exception(msg); if (type == DebugType.DebugTypeError) throw new Exception(msg);
} }
/// <summary>
/// A action, that is performed, when <see cref="GLDebugging.CheckGLErrors"/> find an error.
/// </summary>
public static Action<ErrorCode> GlErrorAction;
/// <summary>
/// Checks for OpenGL errors.
/// </summary>
public static bool CheckGLErrors()
{
bool hasError = false;
ErrorCode c;
while ((c = GL.GetError()) != ErrorCode.NoError)
{
hasError = true;
GlErrorAction?.Invoke(c);
}
return hasError;
}
} }
} }

View file

@ -1,4 +1,5 @@
using OpenTK.Graphics.OpenGL4; using System.Diagnostics;
using OpenTK.Graphics.OpenGL4;
namespace SM.OGL namespace SM.OGL
{ {
@ -29,7 +30,7 @@ namespace SM.OGL
{ {
get get
{ {
if (AutoCompile && !WasCompiled) Compile(); if (AutoCompile && !WasCompiled) PerformCompile();
return _id; return _id;
} }
} }
@ -39,10 +40,17 @@ namespace SM.OGL
/// </summary> /// </summary>
public abstract ObjectLabelIdentifier TypeIdentifier { get; } public abstract ObjectLabelIdentifier TypeIdentifier { get; }
[DebuggerStepThrough]
private void PerformCompile()
{
Compile();
}
/// <summary> /// <summary>
/// The action, that is called, when "ID" tries to compile something. /// The action, that is called, when "ID" tries to compile something.
/// </summary> /// </summary>
protected virtual void Compile()
public virtual void Compile()
{ {
} }
@ -50,7 +58,7 @@ namespace SM.OGL
/// <summary> /// <summary>
/// Is triggered, when something want to dispose this object. /// Is triggered, when something want to dispose this object.
/// </summary> /// </summary>
protected virtual void Dispose() {} public virtual void Dispose() {}
/// <summary> /// <summary>
/// Re-compiles the object. /// Re-compiles the object.
@ -72,10 +80,15 @@ namespace SM.OGL
if (GLSystem.Debugging) GL.ObjectLabel(TypeIdentifier, _id, name.Length, name); if (GLSystem.Debugging) GL.ObjectLabel(TypeIdentifier, _id, name.Length, name);
} }
protected virtual int GetID()
{
return _id;
}
/// <summary> /// <summary>
/// Returns the ID for the object. /// Returns the ID for the object.
/// </summary> /// </summary>
/// <param name="glo"></param> /// <param name="glo"></param>
public static implicit operator int(GLObject glo) => glo.ID; public static implicit operator int(GLObject glo) => glo.GetID();
} }
} }

View file

@ -64,7 +64,7 @@ namespace SM.OGL.Mesh
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void Compile() public override void Compile()
{ {
_id = GL.GenVertexArray(); _id = GL.GenVertexArray();
GL.BindVertexArray(_id); GL.BindVertexArray(_id);

View file

@ -46,6 +46,8 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Framebuffer\ColorAttachment.cs" />
<Compile Include="Framebuffer\Framebuffer.cs" />
<Compile Include="GLDebugging.cs" /> <Compile Include="GLDebugging.cs" />
<Compile Include="GLObject.cs" /> <Compile Include="GLObject.cs" />
<Compile Include="GLSystem.cs" /> <Compile Include="GLSystem.cs" />

View file

@ -59,7 +59,7 @@ namespace SM.OGL.Shaders
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void Compile() public override void Compile()
{ {
Load(); Load();
} }
@ -70,7 +70,7 @@ namespace SM.OGL.Shaders
/// <param name="mesh">The mesh.</param> /// <param name="mesh">The mesh.</param>
/// <param name="amount">The amounts for instancing.</param> /// <param name="amount">The amounts for instancing.</param>
/// <param name="bindVAO">Binds the vertex array for the mesh.</param> /// <param name="bindVAO">Binds the vertex array for the mesh.</param>
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); if (bindVAO) GL.BindVertexArray(mesh);

View file

@ -33,5 +33,11 @@ namespace SM.OGL.Texture
/// The height of the texture /// The height of the texture
/// </summary> /// </summary>
public int Height { get; protected set; } public int Height { get; protected set; }
public override void Dispose()
{
base.Dispose();
GL.DeleteTexture(_id);
}
} }
} }

View file

@ -50,13 +50,11 @@ namespace SM2D.Drawing
public void Draw(DrawContext context) public void Draw(DrawContext context)
{ {
if (_material.Shader == null) _material.Shader = Defaults.DefaultShader;
context.Material = _material; context.Material = _material;
context.Mesh = Plate.Object; context.Mesh = Plate.Object;
context.Instances[0].ModelMatrix = Matrix4.CreateScale(context.WorldScale.X, context.WorldScale.Y, 1); context.Instances[0].ModelMatrix = Matrix4.CreateScale(context.WorldScale.X, context.WorldScale.Y, 1);
_material.Shader.Draw(context); context.Shader.Draw(context);
} }
} }
} }

View file

@ -24,13 +24,11 @@ namespace SM2D.Drawing
_material.Tint = color; _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(); context.Instances[0].ModelMatrix = Transform.GetMatrix();
_material.Shader.Draw(context); context.Shader.Draw(context);
} }
} }
} }

View file

@ -22,14 +22,11 @@ namespace SM2D.Drawing
set => _mesh = value; 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(); context.Instances[0].ModelMatrix = Transform.GetMatrix();
_material.Shader.Draw(context); context.Shader.Draw(context);
} }
} }
} }

View file

@ -1,4 +1,5 @@
using SM.Base.Contexts; using SM.Base;
using SM.Base.Contexts;
using SM.Base.Text; using SM.Base.Text;
using SM.Base.Types; using SM.Base.Types;
using SM2D.Scene; using SM2D.Scene;
@ -14,15 +15,14 @@ namespace SM2D.Drawing
Transform.Size = new CVector2(1); 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; context.Instances = _instances;
ApplyContext(ref context);
context.View = Transform.GetMatrix() * context.View; context.View = Transform.GetMatrix() * context.View;
_material.Shader.Draw(context); context.Shader.Draw(context);
} }
public int ZIndex { get; set; } public int ZIndex { get; set; }

View file

@ -15,6 +15,7 @@ namespace SM2D.Drawing
public static float MasterScale = .25f; public static float MasterScale = .25f;
public float Scale = 1; public float Scale = 1;
public bool ManualSize = false;
public Texture Texture public Texture Texture
{ {
get => (Texture) _material.Texture; get => (Texture) _material.Texture;
@ -28,16 +29,19 @@ namespace SM2D.Drawing
public DrawTexture(Bitmap map) : this(map, Color4.White) 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; _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); if (!ManualSize) Transform.Size = new CVector2(Texture.Map.Width * MasterScale * Scale, Texture.Map.Height * MasterScale * Scale);
base.Draw(context); base.DrawContext(ref context);
} }
} }
} }

View file

@ -5,13 +5,14 @@ using OpenTK.Input;
using SM.Base; using SM.Base;
using SM.Base.Controls; using SM.Base.Controls;
using SM2D.Controls; using SM2D.Controls;
using SM2D.Pipelines;
using SM2D.Scene; using SM2D.Scene;
using SM2D.Shader; using SM2D.Shader;
using Vector2 = OpenTK.Vector2; using Vector2 = OpenTK.Vector2;
namespace SM2D namespace SM2D
{ {
public class GLWindow2D : GenericWindow<Scene.Scene, I2DShowItem, Camera> public class GLWindow2D : GenericWindow<Scene.Scene, Camera>
{ {
public Vector2? Scaling { get; set; } public Vector2? Scaling { get; set; }
public Vector2 WorldScale => _worldScale; public Vector2 WorldScale => _worldScale;
@ -25,13 +26,17 @@ namespace SM2D
protected override void OnLoad(EventArgs e) protected override void OnLoad(EventArgs e)
{ {
Defaults.DefaultShader = new Default2DShader();
base.OnLoad(e); base.OnLoad(e);
GL.Enable(EnableCap.Blend); GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
} }
protected override void OnLoaded()
{
base.OnLoaded();
SetRenderPipeline(new Basic2DPipeline());
}
protected override void OnRenderFrame(FrameEventArgs e) protected override void OnRenderFrame(FrameEventArgs e)
{ {
GL.Disable(EnableCap.DepthTest); GL.Disable(EnableCap.DepthTest);

View file

@ -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<Scene.Scene>
{
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);
}
}
}

View file

@ -55,6 +55,7 @@
<Compile Include="GLWindow2D.cs" /> <Compile Include="GLWindow2D.cs" />
<Compile Include="Object\Polygon.cs" /> <Compile Include="Object\Polygon.cs" />
<Compile Include="Object\PolygonVertex.cs" /> <Compile Include="Object\PolygonVertex.cs" />
<Compile Include="Pipelines\Basic2DPipeline.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Scene\Camera.cs" /> <Compile Include="Scene\Camera.cs" />
<Compile Include="Scene\I2DShowItem.cs" /> <Compile Include="Scene\I2DShowItem.cs" />

View file

@ -14,7 +14,7 @@ namespace SM2D.Scene
public override void Draw(DrawContext context) public override void Draw(DrawContext context)
{ {
Objects.Sort((x, y) => x.ZIndex - y.ZIndex); Sort((x, y) => x.ZIndex - y.ZIndex);
base.Draw(context); base.Draw(context);
} }

View file

@ -5,7 +5,7 @@ using SM2D.Drawing;
namespace SM2D.Scene namespace SM2D.Scene
{ {
public class Scene : GenericScene<Camera, I2DShowItem> public class Scene : GenericScene<Camera, ItemCollection, I2DShowItem>
{ {
public DrawBackground Background => (DrawBackground)_background; public DrawBackground Background => (DrawBackground)_background;
@ -13,11 +13,5 @@ namespace SM2D.Scene
{ {
_background = new DrawBackground(Color4.Black); _background = new DrawBackground(Color4.Black);
} }
public override void Draw(DrawContext context)
{
Objects.Sort((x,y) => x.ZIndex - y.ZIndex);
base.Draw(context);
}
} }
} }

View file

@ -8,13 +8,15 @@ namespace SM2D.Shader
{ {
public class Default2DShader : GenericShader, IShader 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.vert"),
AssemblyUtility.ReadAssemblyFile("SM2D.Shader.ShaderFiles.default.frag"))) AssemblyUtility.ReadAssemblyFile("SM2D.Shader.ShaderFiles.default.frag")))
{ {
Load();
} }
public void Draw(DrawContext context) public void Draw(DrawContext context)
{ {

View file

@ -4,6 +4,7 @@ using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using SM.Base;
using SM.Base.Time; using SM.Base.Time;
using SM2D; using SM2D;
using SM2D.Drawing; using SM2D.Drawing;
@ -28,6 +29,8 @@ namespace SM_TEST
FontSize = 32 FontSize = 32
}; };
Log.SetLogFile(compressionFolder:"logs");
window = new GLWindow2D {Scaling = new Vector2(0, 1000)}; window = new GLWindow2D {Scaling = new Vector2(0, 1000)};
//window.GrabCursor(); //window.GrabCursor();
window.SetScene(scene = new Scene()); window.SetScene(scene = new Scene());
@ -53,11 +56,11 @@ namespace SM_TEST
ZIndex = 1 ZIndex = 1
}; };
col.Objects.Add(new DrawTexture(new Bitmap("soldier_logo.png")) col.Add(new DrawTexture(new Bitmap("soldier_logo.png"))
{ {
ZIndex = 1 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) }, Transform = { Rotation = 45, Position = new SM.Base.Types.CVector2(0, 25) },
ZIndex = 2 ZIndex = 2