/// <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); }
private void CheckStatus() { FramebufferStatus status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer); if (status != FramebufferStatus.Complete) { throw new CKGLException("Invalid Framebuffer: " + status); } }
private static void RenderOsdFramebuffer(DeviceContext deviceContext) { IntPtr glContext = IntPtr.Zero; uint framebuffer = 0; uint renderbuffer = 0; try { // Create context and make current on this thread if ((glContext = deviceContext.CreateContext(IntPtr.Zero)) == IntPtr.Zero) { throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error()); // XXX } deviceContext.MakeCurrent(glContext); // Create framebuffer resources int w = Math.Min(800, Gl.CurrentLimits.MaxRenderbufferSize); int h = Math.Min(600, Gl.CurrentLimits.MaxRenderbufferSize); renderbuffer = Gl.GenRenderbuffer(); Gl.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderbuffer); Gl.RenderbufferStorage(RenderbufferTarget.Renderbuffer, InternalFormat.Rgb8, w, h); framebuffer = Gl.GenFramebuffer(); Gl.BindFramebuffer(FramebufferTarget.ReadFramebuffer, framebuffer); Gl.BindFramebuffer(FramebufferTarget.Framebuffer, framebuffer); Gl.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, renderbuffer); FramebufferStatus framebufferStatus = Gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer); if (framebufferStatus != FramebufferStatus.FramebufferComplete) { throw new InvalidOperationException("framebuffer not complete"); } Gl.DrawBuffers(Gl.COLOR_ATTACHMENT0); RenderOsd(w, h); Gl.ReadBuffer(ReadBufferMode.ColorAttachment0); SnapshotOsd(w, h); } finally { if (renderbuffer != 0) { Gl.DeleteRenderbuffers(renderbuffer); } if (framebuffer != 0) { Gl.DeleteFramebuffers(framebuffer); } if (glContext != IntPtr.Zero) { deviceContext.DeleteContext(glContext); } } }
/// <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); }
void BindFramebuffer(FramebufferTarget Target) { #if DEBUG FramebufferStatus S = Gl.CheckNamedFramebufferStatus(ID, Target); if (S != FramebufferStatus.FramebufferComplete) { throw new InvalidOperationException("Incomplete framebuffer"); } #endif this.Target = Target; Gl.BindFramebuffer(Target, ID); }
public override unsafe Bitmap Bitmap(RectangleI rectangle) { switch (Type) { //case TextureType.Texture1D when Platform.GraphicsBackend == GraphicsBackend.OpenGL: // Not available in OpenGL ES // break; //case TextureType.Texture1DArray when Platform.GraphicsBackend == GraphicsBackend.OpenGL: // Not available in OpenGL ES // break; case TextureType.Texture2D: #region Old OpenGL-only implementation with glTexImage //Colour[] data = new Colour[Width * Height]; //Bind(); //fixed (Colour* ptr = data) // GL.GetTexImage(TextureTarget, 0, Format.ToOpenGL().PixelFormat(), Format.ToOpenGL().PixelType(), ptr); //return new Bitmap(data, Width, Height); #endregion // OpenGL ES friendly implementation with crop functionality Framebuffer originalFramebuffer = Framebuffer.Current; GLuint tempFramebuffer = GL.GenFramebuffer(); GL.BindFramebuffer(FramebufferTarget.Framebuffer, tempFramebuffer); //Framebuffer.Swaps++; // TODO GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, TextureAttachment.Colour0.ToOpenGL(), TextureTarget, ID, 0); FramebufferStatus status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer); if (status != FramebufferStatus.Complete) { throw new CKGLException("Invalid Framebuffer: " + status); } GL.ReadBuffer(ReadBuffer.Colour0); Bitmap bitmap = new Bitmap(GL.ReadPixelsAsColourArray(rectangle, PixelFormat.RGBA), rectangle.W, rectangle.H); GL.DeleteFramebuffer(tempFramebuffer); originalFramebuffer.Bind(); return(bitmap); //case TextureType.Texture2DArray: // break; //case TextureType.Texture2DMultisample: // break; //case TextureType.Texture3D: // break; default: throw new IllegalValueException(typeof(TextureType), Type); } }
/// <summary> /// Validate this Framebuffer. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> used for validating this Framebuffer. /// </param> /// <exception cref="InvalidOperationException"> /// Exception thrown whenever this Framebuffer is not valid. /// </exception> private static void Validate(GraphicsContext ctx) { // Check frambuffer completeness FramebufferStatus status = Gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer); if (status != FramebufferStatus.FramebufferComplete) { switch (status) { case FramebufferStatus.FramebufferComplete: return; // No error case FramebufferStatus.FramebufferUndefined: throw new InvalidOperationException("framebuffer undefined"); case FramebufferStatus.FramebufferIncompleteAttachment: throw new InvalidOperationException("framebuffer incomplete attachment"); case FramebufferStatus.FramebufferIncompleteMissingAttachment: throw new InvalidOperationException("framebuffer incomplete missing attachment"); #if !MONODROID case FramebufferStatus.FramebufferIncompleteReadBuffer: throw new InvalidOperationException("framebuffer incomplete read buffer"); #endif case FramebufferStatus.FramebufferUnsupported: throw new InvalidOperationException("framebuffer unsupported"); case FramebufferStatus.FramebufferIncompleteMultisample: throw new InvalidOperationException("framebuffer incomplete multisample"); case FramebufferStatus.FramebufferIncompleteLayerTargets: throw new InvalidOperationException("framebuffer incomplete layer targets"); default: throw new InvalidOperationException(String.Format("unknown error code 0x{0}", status.ToString("X8"))); } } }
/// <summary> /// Creates a framebuffer object and its associated resources (depth and frame buffers). /// </summary> /// <param name="size">Specifies the size (in pixels) of the framebuffer and its associated buffers.</param> /// <param name="attachments">Specifies the attachments to use for the frame buffer.</param> /// <param name="format">Specifies the internal pixel format for the frame buffer.</param> /// <param name="mipmaps">Specifies whether to build mipmaps after the frame buffer is unbound.</param> /// <param name="filterType">Specifies the type of filtering to apply to the frame buffer when bound as a texture.</param> /// <param name="pixelType">Specifies the pixel type to use for the underlying format of the frame buffer.</param> public FBO(Sizei size, FramebufferAttachment[] attachments, PixelInternalFormat format, bool mipmaps = false, TextureParameter filterType = TextureParameter.Linear, PixelType pixelType = PixelType.UnsignedByte, bool renderbuffer = true, bool multisampled = false) { Size = size; Attachments = attachments; Format = format; MipMaps = mipmaps; Multisampled = multisampled; // First create the framebuffer BufferID = GL.GenFramebuffer(); GL.BindFramebuffer(FramebufferTarget.Framebuffer, BufferID); _attachementMap = new Dictionary <FramebufferAttachment, uint>(); TextureTarget textureTarget = Multisampled ? TextureTarget.Texture2DMultisample : TextureTarget.Texture2D; if (Attachments.Length == 1 && Attachments[0] == FramebufferAttachment.DepthAttachment) { // if this is a depth attachment only TextureID = new uint[] { GL.GenTexture() }; GL.BindTexture(textureTarget, TextureID[0]); if (Multisampled) { GL.TexImage2DMultisample(textureTarget, GameSettings.MultisampleLevel, Format, Size.Width, Size.Height, true); } else { GL.TexImage2D(textureTarget, 0, Format, Size.Width, Size.Height, 0, PixelFormat.DepthComponent, PixelType.Float, IntPtr.Zero); GL.TexParameteri(textureTarget, TextureParameterName.TextureMagFilter, TextureParameter.Nearest); GL.TexParameteri(textureTarget, TextureParameterName.TextureMinFilter, TextureParameter.Nearest); GL.TexParameteri(textureTarget, TextureParameterName.TextureWrapS, TextureParameter.ClampToEdge); GL.TexParameteri(textureTarget, TextureParameterName.TextureWrapT, TextureParameter.ClampToEdge); } GL.BindTexture(textureTarget, 0); GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, textureTarget, TextureID[0], 0); GL.DrawBuffer(DrawBufferMode.None); GL.ReadBuffer(ReadBufferMode.None); _attachementMap.Add(FramebufferAttachment.DepthAttachment, 0); } else { // Create n texture buffers (known by the number of attachments) TextureID = new uint[Attachments.Length]; GL.GenTextures(Attachments.Length, TextureID); // Bind the n texture buffers to the framebuffer for (int i = 0; i < Attachments.Length; i++) { GL.BindTexture(textureTarget, TextureID[i]); if (Multisampled) { GL.TexImage2DMultisample(textureTarget, GameSettings.MultisampleLevel, Format, Size.Width, Size.Height, true); } else { GL.TexImage2D(textureTarget, 0, Format, Size.Width, Size.Height, 0, PixelFormat.Rgba, pixelType, IntPtr.Zero); if (MipMaps) { GL.TexParameteri(textureTarget, TextureParameterName.TextureMagFilter, TextureParameter.Linear); GL.TexParameteri(textureTarget, TextureParameterName.TextureMinFilter, TextureParameter.LinearMipMapLinear); GL.GenerateMipmap(Multisampled ? GenerateMipmapTarget.Texture2DMultisample : GenerateMipmapTarget.Texture2D); } else { GL.TexParameteri(textureTarget, TextureParameterName.TextureMagFilter, filterType); GL.TexParameteri(textureTarget, TextureParameterName.TextureMinFilter, filterType); } } GL.BindTexture(textureTarget, 0); GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, Attachments[i], textureTarget, TextureID[i], 0); _attachementMap.Add(Attachments[i], TextureID[i]); } if (renderbuffer) { // Create and attach a 24-bit depth buffer to the framebuffer DepthID = GL.GenRenderbuffer(); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, DepthID); if (Multisampled) { GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, GameSettings.MultisampleLevel, PixelInternalFormat.Depth32fStencil8, Size.Width, Size.Height); } else { GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, PixelInternalFormat.Depth24Stencil8, Size.Width, Size.Height); } GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0); GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, DepthID); //GL.TexParameteri(textureTarget, TextureParameterName.TextureMagFilter, TextureParameter.Nearest); //GL.TexParameteri(textureTarget, TextureParameterName.TextureMinFilter, TextureParameter.Nearest); //GL.TexParameteri(textureTarget, TextureParameterName.TextureWrapS, TextureParameter.ClampToEdge); //GL.TexParameteri(textureTarget, TextureParameterName.TextureWrapT, TextureParameter.ClampToEdge); //GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, textureTarget, DepthID, 0); //GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.StencilAttachment, textureTarget, DepthID, 0); _attachementMap.Add(FramebufferAttachment.DepthStencilAttachment, DepthID); //_attachementMap.Add(FramebufferAttachment.StencilAttachment, DepthID); } } // Build the framebuffer and check for errors FramebufferStatus status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer); if (status != FramebufferStatus.FramebufferComplete) { Console.WriteLine("Frame buffer did not compile correctly. Returned {0}, glError: {1}", status.ToString(), GL.GetError().ToString()); } // Make sure this framebuffer is not modified from outside GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); // Register this framebuffer as a disposable object ResourcesManager.AddDisposableResource(this); }
/// <summary> /// Updates the <see cref="FramebufferObject"/>'s parameters and checks that the framebuffer is valid. /// This should always be called after being done attaching or detaching resources. /// </summary> public void UpdateFramebufferData() { uint width = uint.MaxValue; uint height = uint.MaxValue; uint samples = uint.MaxValue; for (int i = 0; i < textureAttachments.Count; i++) { Texture tex = textureAttachments[i].Texture; if (tex is Texture1D tex1d) { ValidateSize(tex1d.Width, 1); } else if (tex is Texture2D tex2d) { ValidateSize(tex2d.Width, tex2d.Height); } else { throw new FramebufferException("The texture format cannot be attached: " + tex.TextureType); } ValidateSamples(tex is TextureMultisamplable ms ? ms.Samples : 0); } for (int i = 0; i < renderbufferAttachments.Count; i++) { RenderbufferObject rend = renderbufferAttachments[i].Renderbuffer; ValidateSize(rend.Width, rend.Height); ValidateSamples(rend.Samples); } Width = width; Height = height; Samples = samples; void ValidateSize(uint w, uint h) { if (width == uint.MaxValue) { width = w; } else if (width != w) { throw new FramebufferException("All the attachments must be the same size"); } if (height == uint.MaxValue) { height = h; } else if (height != h) { throw new FramebufferException("All the attachments must be the same size"); } } void ValidateSamples(uint s) { if (samples == uint.MaxValue) { samples = s; } else if (samples != s) { throw new FramebufferException("All the attachments must have the same amount of samples"); } } FramebufferStatus c = GetStatus(); if (c != FramebufferStatus.FramebufferComplete) { throw new FramebufferException("The " + nameof(FramebufferObject) + " is not complete: " + c); } }
/// <summary> /// initializes the Fbo with <b>with</b> and <b>height</b>. You have to call that, when <see cref="FboHandle"/> less than 0 or when the size of the fbo has changed. /// </summary> /// <param name="Width">is the width.</param> /// <param name="Height">is the height.</param> public virtual void Init(int Width, int Height) { if (FboHandle > 0) { Dispose(); } width = Width; height = Height; ActiveTexture = GL.GetInteger(GetPName.TextureBinding2D); if (FboHandle < 0) { _GenFramebuffers(1, out _Fbo[0]); } if (FboHandle < 0) { throw new System.Exception("Can not create a frame buffer"); } _BindFramebuffer(FramebufferTarget.Framebuffer, FboHandle); if (Depthbuffer < 0) { _GenRenderbuffers(1, out _Depth[0]); } _BindRenderbuffer(RenderbufferTarget.Renderbuffer, Depthbuffer); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.DepthComponent, width, height, 0, PixelFormat.DepthComponent, PixelType.UnsignedInt, IntPtr.Zero); if (GL.GetError() != OpenTK.Graphics.OpenGL.ErrorCode.NoError) { Dispose(); throw new Exception("OutOf Memory"); } // GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent16, Width, Height); _RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent16, Width, Height); _BindFramebuffer(FramebufferTarget.DrawFramebuffer, FboHandle); if (FboTexture < 0) { GL.GenTextures(1, _Texture); } GL.BindTexture(TextureTarget.Texture2D, FboTexture); GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, ref GL_NEAREST); GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, ref GL_NEAREST); { GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); _FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, FboTexture, 0); _FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, Depthbuffer); } int status = (int)GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer); FramebufferStatus FS = (FramebufferStatus)(status - 0x8CD5); if (FS != FramebufferStatus.FRAMEBUFFER_COMPLETE) { int[] FB = new int[] { 1 }; Dispose(); throw new System.Exception(FS.ToString()); } _BindFramebuffer(FramebufferTarget.Framebuffer, 0); _BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); _BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0); GL.BindTexture(TextureTarget.Texture2D, ActiveTexture); ; }
internal Screen(Application.Client client) { Instance = this; Client = client; client.Resize += OnResize; #region MULTISAMPLED FBO int maxSamples = GL.GetInteger(GetPName.MaxSamples); samples = Math.Clamp(Client.Graphics.SampleCount, min: 1, maxSamples); logger.LogDebug( Events.VisualQuality, "Set sample count to {Samples}, of maximum {Max} possible samples", samples, maxSamples); GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.CullFace); GL.Enable(EnableCap.Multisample); msTex = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2DMultisample, msTex); GL.TexImage2DMultisample( TextureTargetMultisample.Texture2DMultisample, samples, PixelInternalFormat.Rgba8, Size.X, Size.Y, fixedsamplelocations: true); GL.BindTexture(TextureTarget.Texture2DMultisample, texture: 0); GL.CreateFramebuffers(n: 1, out msFBO); GL.NamedFramebufferTexture(msFBO, FramebufferAttachment.ColorAttachment0, msTex, level: 0); FramebufferStatus multisampledFboStatus = GL.CheckNamedFramebufferStatus(msFBO, FramebufferTarget.Framebuffer); while (multisampledFboStatus != FramebufferStatus.FramebufferComplete) { logger.LogWarning( Events.VisualsSetup, "Multi-sampled FBO not complete [{Status}], waiting...", multisampledFboStatus); Thread.Sleep(millisecondsTimeout: 100); multisampledFboStatus = GL.CheckNamedFramebufferStatus(msFBO, FramebufferTarget.Framebuffer); } GL.CreateRenderbuffers(n: 1, out msRBO); GL.NamedRenderbufferStorageMultisample(msRBO, samples, RenderbufferStorage.Depth24Stencil8, Size.X, Size.Y); GL.NamedFramebufferRenderbuffer( msFBO, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, msRBO); GL.BindFramebuffer(FramebufferTarget.Framebuffer, msFBO); GL.DrawBuffer(DrawBufferMode.ColorAttachment0); #endregion MULTISAMPLED FBO #region DEPTH TEXTURE depthTex = GL.GenTexture(); GL.ActiveTexture(TextureUnit.Texture20); GL.BindTexture(TextureTarget.Texture2D, depthTex); GL.TexImage2D( TextureTarget.Texture2D, level: 0, PixelInternalFormat.DepthComponent, Size.X, Size.Y, border: 0, PixelFormat.DepthComponent, PixelType.Float, IntPtr.Zero); GL.TexParameter( TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter( TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.CreateFramebuffers(n: 1, out depthFBO); GL.NamedFramebufferTexture(depthFBO, FramebufferAttachment.DepthAttachment, depthTex, level: 0); FramebufferStatus depthFboStatus = GL.CheckNamedFramebufferStatus(depthFBO, FramebufferTarget.Framebuffer); while (depthFboStatus != FramebufferStatus.FramebufferComplete) { logger.LogWarning(Events.VisualsSetup, "Depth FBO not complete [{Status}], waiting...", depthFboStatus); Thread.Sleep(millisecondsTimeout: 100); depthFboStatus = GL.CheckNamedFramebufferStatus(depthFBO, FramebufferTarget.Framebuffer); } GL.ActiveTexture(TextureUnit.Texture0); #endregion DEPTH TEXTURE #region SCREENSHOT FBO GL.CreateFramebuffers(n: 1, out screenshotFBO); GL.CreateRenderbuffers(n: 1, out screenshotRBO); GL.NamedRenderbufferStorage(screenshotRBO, RenderbufferStorage.Rgba8, Size.X, Size.Y); GL.NamedFramebufferRenderbuffer( screenshotFBO, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, screenshotRBO); FramebufferStatus screenshotFboStatus = GL.CheckNamedFramebufferStatus(screenshotFBO, FramebufferTarget.Framebuffer); while (screenshotFboStatus != FramebufferStatus.FramebufferComplete) { logger.LogWarning( Events.VisualsSetup, "Screenshot FBO not complete [{Status}], waiting...", screenshotFboStatus); Thread.Sleep(millisecondsTimeout: 100); screenshotFboStatus = GL.CheckNamedFramebufferStatus(screenshotFBO, FramebufferTarget.Framebuffer); } #endregion SCREENSHOT FBO }
/// <summary> /// Start your app. /// </summary> /// <param name="width">Stage width</param> /// <param name="height">Stage height</param> /// <param name="viewportHeight"></param> /// <param name="viewportWidth"></param> /// <param name="rootType">The root class of your app</param> /// <exception cref="InvalidOperationException">When rootType is null or this function is called twice</exception> /// <exception cref="NotSupportedException">When the OpenGL framebuffer creation fails.</exception> /// <exception cref="ArgumentException">When width or height are less than 32.</exception> public static void Start(uint width, uint height, uint viewportWidth, uint viewportHeight, Type rootType) { Debug.WriteLine("Sparrow starting"); if (width < 32 || height < 32 || viewportWidth < 32 || viewportHeight < 32) { throw new ArgumentException($"Invalid dimensions: {width}x{height}"); } var ver = Gl.CurrentVersion; if (ver.Api == "gl") { if (ver.Major < 4) { throw new NotSupportedException("You need at least OpenGL 4.0 to run Sparrow!"); } } else { if (ver.Major < 3) { throw new NotSupportedException("You need at least OpenGL ES 3.0 to run Sparrow!"); } IsRunningOpenGLES = true; } Gl.Disable(EnableCap.CullFace); Gl.Disable(EnableCap.Dither); Gl.Enable(EnableCap.DepthTest); Gl.DepthFunc(DepthFunction.Always); BlendMode.Get(BlendMode.NORMAL).Activate(); FramebufferStatus status = Gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer); if (status != FramebufferStatus.FramebufferComplete) { throw new NotSupportedException("GL Framebuffer creation error. Status: " + status); } _viewPort = Rectangle.Create(0, 0, viewportWidth, viewportHeight); _previousViewPort = Rectangle.Create(); GPUInfo.PrintGPUInfo(); // Desktop GL core profile needs a VAO for vertex attrib pointers to work. uint vao = Gl.GenVertexArray(); Gl.BindVertexArray(vao); if (rootType == null) { throw new InvalidOperationException("Root cannot be null!"); } if (Root != null) { throw new InvalidOperationException("App already initialized!"); } _painter = new Painter(width, height); Stage = new Stage(width, height); DefaultJuggler = new Juggler(); UpdateViewPort(true); Root = (DisplayObject)Activator.CreateInstance(rootType); Stage.AddChild(Root); _frameId = 1; // starts with 1, so things on the first frame are cached }