/// <inheritdoc />
        public override RenderTarget CreateRenderTarget(Vector2 size, bool smooth      = false, TextureInternalFormat internalFormat = TextureInternalFormat.Rgba,
                                                        TexturePixelFormat pixelFormat = TexturePixelFormat.Rgba, bool attachStencil = false)
        {
            RenderTarget resultTarget = null;

            InternalFormat intFormat = (InternalFormat)Enum.Parse(typeof(InternalFormat), internalFormat.ToString());
            PixelFormat    glFormat  = (PixelFormat)Enum.Parse(typeof(PixelFormat), pixelFormat.ToString());

            GLThread.ExecuteGLThread(() =>
            {
                // Create the FBO which rendering will be done to.
                uint newFbo = Gl.GenFramebuffer();
                Gl.BindFramebuffer(FramebufferTarget.Framebuffer, newFbo);

                // Create the texture.
                uint renderTexture = Gl.GenTexture();
                Gl.BindTexture(TextureTarget.Texture2d, renderTexture);
                Gl.TexImage2D(TextureTarget.Texture2d, 0, intFormat, (int)size.X, (int)size.Y, 0, glFormat,
                              PixelType.UnsignedByte, IntPtr.Zero);
                Gl.TexParameter(TextureTarget.Texture2d, TextureParameterName.TextureMinFilter, smooth ? Gl.LINEAR : Gl.NEAREST);
                Gl.TexParameter(TextureTarget.Texture2d, TextureParameterName.TextureMagFilter, smooth ? Gl.LINEAR : Gl.NEAREST);

                // Attach the texture to the frame buffer.
                Gl.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2d, renderTexture, 0);

                // Attach color components.
                int[] modes = { Gl.COLOR_ATTACHMENT0 };
                Gl.DrawBuffers(modes);

                // Create render buffer.
                uint depthBuffer = Gl.GenRenderbuffer();
                Gl.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthBuffer);
                Gl.RenderbufferStorage(RenderbufferTarget.Renderbuffer, InternalFormat.Depth24Stencil8, (int)size.X,
                                       (int)size.Y);
                Gl.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, attachStencil ? FramebufferAttachment.DepthStencilAttachment : FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, depthBuffer);

                // Check status.
                FramebufferStatus status = Gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
                if (status != FramebufferStatus.FramebufferComplete)
                {
                    Engine.Log.Warning($"Framebuffer creation failed. Error code {status}.", MessageSource.GL);
                }

                // Create the texture object.
                Texture targetTexture = new GLTexture(renderTexture, new Vector2(size.X, size.Y), null, $"FBO {newFbo} Texture");

                // Create the render target object.
                resultTarget = new GlRenderTarget(newFbo, size, targetTexture);

                // Clear the target.
                ClearScreen();

                CheckError("creating scale fbo");

                // Restore bindings and so on.
                Engine.Renderer?.EnsureRenderTarget();
            });

            return(resultTarget);
        }
        /// <inheritdoc />
        public override RenderTarget CreateMSAARenderTarget(int samples, Vector2 size, TextureInternalFormat internalFormat = TextureInternalFormat.Rgba, bool attachStencil = false)
        {
            RenderTarget resultTarget = null;

            InternalFormat intFormat = (InternalFormat)Enum.Parse(typeof(InternalFormat), internalFormat.ToString());

            GLThread.ExecuteGLThread(() =>
            {
                // Create the FBO.
                uint newFbo = Gl.GenFramebuffer();
                Gl.BindFramebuffer(FramebufferTarget.Framebuffer, newFbo);

                // Create the texture.
                uint renderTexture = Gl.GenTexture();
                Gl.BindTexture(TextureTarget.Texture2dMultisample, renderTexture);
                Gl.TexImage2DMultisample(TextureTarget.Texture2dMultisample, samples, intFormat, (int)size.X, (int)size.Y, true);

                // Attach the texture to the frame buffer.
                Gl.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2dMultisample, renderTexture, 0);

                // Attach color components.
                int[] modes = { Gl.COLOR_ATTACHMENT0 };
                Gl.DrawBuffers(modes);

                // Create render buffer.
                uint depthBuffer = Gl.GenRenderbuffer();
                Gl.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthBuffer);
                Gl.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, samples, InternalFormat.Depth24Stencil8, (int)size.X, (int)size.Y);
                Gl.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, attachStencil ? FramebufferAttachment.DepthStencilAttachment : FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, depthBuffer);

                // Check status.
                FramebufferStatus status = Gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
                if (status != FramebufferStatus.FramebufferComplete)
                {
                    Engine.Log.Warning($"MSAA Framebuffer creation failed. Error code {status}.", MessageSource.GL);
                }

                // Construct a texture object for it.
                Texture targetTexture = new GLTexture(renderTexture, new Vector2(size.X, size.Y), null, $"MSAA{samples} FBO Texture");

                // Create the render target object.
                resultTarget = new GlRenderTarget(newFbo, size, targetTexture);

                // Clear the target.
                ClearScreen();

                CheckError("creating msaa fbo");

                // Restore bindings and so on.
                Engine.Renderer?.EnsureRenderTarget();
            });

            return(resultTarget);
        }
        /// <inheritdoc />
        public override void BindRenderTarget(RenderTarget t)
        {
            GLThread.ExecuteGLThread(() =>
            {
                // Check if restoring the window target.
                if (t == null)
                {
                    Gl.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
                    Gl.Viewport((int)Viewport.X, (int)Viewport.Y, (int)Viewport.Width, (int)Viewport.Height);
                    return;
                }

                GlRenderTarget target = (GlRenderTarget)t;
                Gl.BindFramebuffer(FramebufferTarget.Framebuffer, target.Pointer);
                Gl.Viewport((int)target.Viewport.X, (int)target.Viewport.Y, (int)target.Viewport.Width, (int)target.Viewport.Height);
            });
        }