public static void Main(string[] args) { Glfw.SetErrorCallback((error, description) => { Console.WriteLine($"GLFW Error {error}: {description}"); }); Glfw.Init(); IntPtr primaryMonitorPtr = Glfw.GetPrimaryMonitor(); Glfw.VidMode videoMode = Glfw.GetVideoMode(primaryMonitorPtr); Glfw.GetMonitorWorkarea(primaryMonitorPtr, out var workAreaX, out var workAreaY, out var workAreaWidth, out var workAreaHeight); // For a full-screen game, replace IntPtr.Zero with primaryMonitorPtr IntPtr monitorPtr = IntPtr.Zero; // Create a GLFW window var windowPtr = Glfw.CreateWindow(workAreaWidth, workAreaHeight, "C# tutorial for Mats", monitorPtr, IntPtr.Zero); Glfw.GetWindowSize(windowPtr, out var viewWidth, out var viewHeight); // Switch to full screen. // Glfw.SetWindowMonitor(windowPtr, primaryMonitorPtr, 0, 0, workAreaWidth, workAreaHeight, 60); // Make sure the OpenGL rendering context is set on the current thread, // otherwise Skia's GRContext.Create(GRBackend.OpenGL) will return null Glfw.MakeContextCurrent(windowPtr); var frameBufferInfo = new GRGlFramebufferInfo((uint)new UIntPtr(0), GRPixelConfig.Rgba8888.ToGlSizedFormat()); using var backendRenderTarget = new GRBackendRenderTarget(viewWidth, viewHeight, 0, 8, frameBufferInfo); using var grContext = GRContext.Create(GRBackend.OpenGL); using var skSurface = SKSurface.Create(grContext, backendRenderTarget, GRSurfaceOrigin.BottomLeft, SKImageInfo.PlatformColorType); // get the canvas from the surface using var skCanvas = skSurface.Canvas; var scene = Level.Load(); var frameDuration = TimeSpan.FromSeconds(1.0 / videoMode.RefreshRate); var stopwatch = new Stopwatch(); using var fpsTextPaint = new SKPaint { Style = SKPaintStyle.Fill, Color = SKColors.White, IsAntialias = true, TextSize = 20, }; TimeSpan renderDuration = default; TimeSpan updateDuration = default; var viewScale = viewWidth / Grid.Width * 0.95f; var viewTransform = new SKMatrix( viewScale, 0, viewWidth / 2f, 0, viewScale, viewHeight / 2f, 0, 0, 1); var inputState = new InputState(windowPtr, viewTransform); while (Glfw.WindowShouldClose(windowPtr) == Glfw.False) { stopwatch.Restart(); // Let GLFW process any queued input events, like keyboard, mouse, ... Glfw.PollEvents(); skCanvas.Save(); skCanvas.SetMatrix(viewTransform); // Clear the drawing canvas skCanvas.Clear(SKColors.DimGray); // Draw to scene to the canvas scene.Draw(skCanvas); skCanvas.Restore(); // skCanvas.DrawText($"Render: {renderDuration.TotalMilliseconds:0.0}ms Update: {updateDuration.TotalMilliseconds:0.0}ms", fpsTextPaint.TextSize, fpsTextPaint.TextSize, fpsTextPaint); // Flush all pending Skia drawing commands grContext.Flush(); // Present the canvas on the display Glfw.SwapBuffers(windowPtr); renderDuration = stopwatch.Elapsed; stopwatch.Restart(); // Update the scene, moving it forward in time. scene.Update((float)frameDuration.TotalSeconds, inputState); inputState.Update(); updateDuration = stopwatch.Elapsed; //Glfw.SetWindowTitle(windowPtr, ); if (inputState.IsKeyDown(Key.Enter) && inputState.IsKeyDown(Key.LeftAlt)) { if (Glfw.GetWindowMonitor(windowPtr) == IntPtr.Zero) { // Switch to full screen. Glfw.SetWindowMonitor(windowPtr, primaryMonitorPtr, 0, 0, Grid.Width, Grid.Height, 60); } else { // Switch to windowed mode Glfw.SetWindowMonitor(windowPtr, IntPtr.Zero, workAreaX + (workAreaWidth - Grid.Width) / 2, workAreaY + (workAreaHeight - Grid.Height) / 2, Grid.Width, Grid.Height, 0); } } // Glfw.SetWindowTitle(windowPtr, $"FPS = {1 / frameDuration.TotalSeconds:000.0}"); } }
public new void DrawInRect(GLKView view, CGRect rect) { if (designMode) { return; } // create the contexts if not done already if (context == null) { var glInterface = GRGlInterface.Create(); context = GRContext.CreateGl(glInterface); } // get the new surface size var newSize = new SKSizeI((int)DrawableWidth, (int)DrawableHeight); // manage the drawing surface if (renderTarget == null || lastSize != newSize || !renderTarget.IsValid) { // create or update the dimensions lastSize = newSize; // read the info from the buffer Gles.glGetIntegerv(Gles.GL_FRAMEBUFFER_BINDING, out var framebuffer); Gles.glGetIntegerv(Gles.GL_STENCIL_BITS, out var stencil); Gles.glGetIntegerv(Gles.GL_SAMPLES, out var samples); var maxSamples = context.GetMaxSurfaceSampleCount(colorType); if (samples > maxSamples) { samples = maxSamples; } glInfo = new GRGlFramebufferInfo((uint)framebuffer, colorType.ToGlSizedFormat()); // destroy the old surface surface?.Dispose(); surface = null; canvas = null; // re-create the render target renderTarget?.Dispose(); renderTarget = new GRBackendRenderTarget(newSize.Width, newSize.Height, samples, stencil, glInfo); } // create the surface if (surface == null) { surface = SKSurface.Create(context, renderTarget, surfaceOrigin, colorType); canvas = surface.Canvas; } using (new SKAutoCanvasRestore(canvas, true)) { // start drawing #pragma warning disable CS0618 // Type or member is obsolete var e = new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType, glInfo); OnPaintSurface(e); DrawInSurface(e.Surface, e.RenderTarget); #pragma warning restore CS0618 // Type or member is obsolete } // flush the SkiaSharp contents to GL canvas.Flush(); context.Flush(); }
protected override void OnPaint(PaintEventArgs e) { if (designMode) { e.Graphics.Clear(BackColor); return; } base.OnPaint(e); MakeCurrent(); // create the contexts if not done already if (grContext == null) { var glInterface = GRGlInterface.CreateDefaultInterface(); grContext = GRContext.CreateGl(glInterface); } // get the new surface size var newSize = new SKSizeI(Width, Height); // manage the drawing surface if (renderTarget == null || lastSize != newSize || !renderTarget.IsValid) { // create or update the dimensions lastSize = newSize; GL.GetInteger(GetPName.FramebufferBinding, out var framebuffer); GL.GetInteger(GetPName.StencilBits, out var stencil); GL.GetInteger(GetPName.Samples, out var samples); var maxSamples = grContext.GetMaxSurfaceSampleCount(colorType); if (samples > maxSamples) { samples = maxSamples; } glInfo = new GRGlFramebufferInfo((uint)framebuffer, colorType.ToGlSizedFormat()); // destroy the old surface surface?.Dispose(); surface = null; canvas = null; // re-create the render target renderTarget?.Dispose(); renderTarget = new GRBackendRenderTarget(newSize.Width, newSize.Height, samples, stencil, glInfo); } // create the surface if (surface == null) { surface = SKSurface.Create(grContext, renderTarget, surfaceOrigin, colorType); canvas = surface.Canvas; } using (new SKAutoCanvasRestore(canvas, true)) { // start drawing OnPaintSurface(new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType)); } // update the control canvas.Flush(); SwapBuffers(); }
protected override void OnUnload(EventArgs e) { base.OnUnload(e); this.context?.Dispose(); this.context = null; }
public GlRenderTarget(GRContext grContext, IGlPlatformSurface glSurface) { _grContext = grContext; _surface = glSurface.CreateGlRenderTarget(); }
public FboSkiaSurface(GRContext grContext, IGlContext glContext, PixelSize pixelSize) { _grContext = grContext; _glContext = glContext; _pixelSize = pixelSize; var InternalFormat = glContext.Version.Type == GlProfileType.OpenGLES ? GL_RGBA : GL_RGBA8; var gl = glContext.GlInterface; // Save old bindings gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, out var oldFbo); gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderbuffer); gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture); var arr = new int[2]; // Generate FBO gl.GenFramebuffers(1, arr); _fbo = arr[0]; gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo); // Create a texture to render into gl.GenTextures(1, arr); _texture = arr[0]; gl.BindTexture(GL_TEXTURE_2D, _texture); gl.TexImage2D(GL_TEXTURE_2D, 0, InternalFormat, pixelSize.Width, pixelSize.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, IntPtr.Zero); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); var success = false; foreach (var useStencil8 in TrueFalse) { gl.GenRenderbuffers(1, arr); _depthStencil = arr[0]; gl.BindRenderbuffer(GL_RENDERBUFFER, _depthStencil); if (useStencil8) { gl.RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, pixelSize.Width, pixelSize.Height); gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); } else { gl.RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, pixelSize.Width, pixelSize.Height); gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); } var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER); if (status == GL_FRAMEBUFFER_COMPLETE) { success = true; break; } else { gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderbuffer); gl.DeleteRenderbuffers(1, arr); } } gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderbuffer); gl.BindTexture(GL_TEXTURE_2D, oldTexture); gl.BindFramebuffer(GL_FRAMEBUFFER, oldFbo); if (!success) { arr[0] = _fbo; gl.DeleteFramebuffers(1, arr); arr[0] = _texture; gl.DeleteTextures(1, arr); throw new OpenGlException("Unable to create FBO with stencil"); } var target = new GRBackendRenderTarget(pixelSize.Width, pixelSize.Height, 0, 8, new GRGlFramebufferInfo((uint)_fbo, SKColorType.Rgba8888.ToGlSizedFormat())); Surface = SKSurface.Create(_grContext, target, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888); CanBlit = gl.BlitFramebuffer != null; }