using System.Runtime.InteropServices; using Engine.Renderer.Pixel; using OpenTK.Graphics.OpenGL; using Serilog; using Serilog.Events; namespace Engine.Renderer; public class Renderer { internal Texture.Texture TextureInternal => _framebuffer.TextureInternal; private readonly Framebuffer.Framebuffer _framebuffer; private readonly Queue> _renderActions = new(); public Renderer(int width, int height) { InitializeOpenGl(); _framebuffer = new Framebuffer.Framebuffer(width, height); } private void InitializeOpenGl() { GL.Enable(EnableCap.DebugOutput); GL.DebugMessageCallback(DebugCallback, IntPtr.Zero); GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.FramebufferSrgb); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Enable(EnableCap.Blend); } private static void DebugCallback(DebugSource source, DebugType type, int id, DebugSeverity severity, int length, IntPtr message, IntPtr userParam) { var logger = Log.ForContext(); var messageText = Marshal.PtrToStringAnsi(message, length) ?? "Unknown OpenGL Error"; var typePrefix = type switch { DebugType.DebugTypeError => "Error", DebugType.DebugTypeDeprecatedBehavior => "Deprecated", DebugType.DebugTypeUndefinedBehavior => "Undefined", DebugType.DebugTypePortability => "Portability", DebugType.DebugTypePerformance => "Performance", DebugType.DebugTypeMarker => "Marker", DebugType.DebugTypePushGroup => "PushGroup", DebugType.DebugTypePopGroup => "PopGroup", DebugType.DebugTypeOther => "Info", _ => "Unknown" }; var sourcePrefix = source switch { DebugSource.DebugSourceApi => "API", DebugSource.DebugSourceWindowSystem => "Window", DebugSource.DebugSourceShaderCompiler => "Shader", DebugSource.DebugSourceThirdParty => "ThirdParty", DebugSource.DebugSourceApplication => "Application", DebugSource.DebugSourceOther => "Other", _ => "Unknown" }; logger.Write( GetLogLevel(severity), "[OpenGL {TypePrefix}] [{Source}] {Message} (ID: 0x{Id:X8})", typePrefix, sourcePrefix, messageText, id ); } private static LogEventLevel GetLogLevel(DebugSeverity severity) { return severity switch { DebugSeverity.DebugSeverityNotification => LogEventLevel.Information, DebugSeverity.DebugSeverityHigh => LogEventLevel.Error, DebugSeverity.DebugSeverityMedium => LogEventLevel.Warning, DebugSeverity.DebugSeverityLow => LogEventLevel.Debug, _ => LogEventLevel.Debug }; } internal void Commit(Action renderAction) { _renderActions.Enqueue(renderAction); } internal void Render() { _framebuffer.Bind(); while (_renderActions.TryDequeue(out var renderAction)) renderAction(this); _framebuffer.Unbind(); } internal void Resize(int width, int height) { _framebuffer.Resize(width, height); } }