Skip to content

Instantly share code, notes, and snippets.

@bmitc
Last active July 11, 2024 02:54
Show Gist options
  • Save bmitc/e4d4399a1d7b71e1036914b8be5e337e to your computer and use it in GitHub Desktop.
Save bmitc/e4d4399a1d7b71e1036914b8be5e337e to your computer and use it in GitHub Desktop.
GLFW window with SkiaSharp rendering in F#
(*
The following creates a GLFW window and then draws to the window's OpenGL context using SkiaSharp,
which are .NET bindings for Skia. The bindings shown that look like `glfw<name>` are F# bindings to
GLFW and directly match the GLFW function names. So this example could even be used as a blueprint
for using GLFW and Skia together in other languages.
*)
open System
open SkiaSharp
open Windowing.GLFW.FSharp
open Windowing.GLFW.Native.OpenGL
open Windowing.GLFW.Native.Helpers
open Windowing.GLFW.Native.Initialization
open Windowing.GLFW.Native.Context
open Windowing.GLFW.Native.Window
let mutable width, height = 500, 500
let mutable framebufferWidth, framebufferHeight = width, height
// Loads the GLFW DLL and then calls glfwInit
initialize()
|> Convert.ToBoolean
|> printfn "Initialized?: %A"
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6)
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
printfn "Starting to create window..."
let window = glfwCreateWindow(width, height, "Test Window", NULL_MONITOR, NULL_WINDOW)
printfn "Window: %A" window
printfn "Ending creating window..."
glfwMakeContextCurrent(window)
let grGlInterface = GRGlInterface.Create(glfwGetProcAddress)
if not (grGlInterface.Validate())
then raise (System.Exception("Invalid GRGlInterface"))
let grContext = GRContext.CreateGl(grGlInterface)
let grGlFramebufferInfo = new GRGlFramebufferInfo(0u, uint32(GL_RGBA8))
let draw(window, width, height) =
glfwPollEvents()
grContext.ResetContext()
let grBackendRenderTarget = new GRBackendRenderTarget(width, height, 1, 0, grGlFramebufferInfo)
let surface = SKSurface.Create(grContext, grBackendRenderTarget, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888)
let canvas = surface.Canvas
canvas.Clear(SKColors.Cyan)
let red = new SKPaint(Color = SKColor(200uy, 100uy, 200uy, 255uy))
canvas.DrawCircle(float32(width)/2.0f, float32(height)/2.0f, 100.0f, red)
canvas.Flush()
glfwSwapBuffers(window)
red.Dispose()
surface.Dispose()
grBackendRenderTarget.Dispose()
let resizeCallback (window, newWidth: int, newHeight: int) =
width <- newWidth
height <- newHeight
draw(window, newWidth, newHeight)
glfwSetFramebufferSizeCallback(window, GLFWframebuffersizefun(fun window width height -> resizeCallback(window, width, height)))
|> ignore
while glfwWindowShouldClose window <> 1 do
glfwGetFramebufferSize(window, &framebufferWidth, &framebufferHeight)
draw(window, framebufferWidth, framebufferHeight)
glfwDestroyWindow(window)
glfwTerminate()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment