Skip to content

Instantly share code, notes, and snippets.

@ghishadow
Forked from GrumpyLion/win32_opengl_demo.odin
Created July 5, 2025 14:45
Show Gist options
  • Save ghishadow/61ed7f892099351958540058d09bdcda to your computer and use it in GitHub Desktop.
Save ghishadow/61ed7f892099351958540058d09bdcda to your computer and use it in GitHub Desktop.

Revisions

  1. @GrumpyLion GrumpyLion revised this gist Sep 4, 2024. 1 changed file with 17 additions and 17 deletions.
    34 changes: 17 additions & 17 deletions win32_opengl_demo.odin
    Original file line number Diff line number Diff line change
    @@ -88,14 +88,14 @@ main :: proc() {
    win32.CS_HREDRAW | win32.CS_VREDRAW,
    WinProc,
    0,0,
    hinst,icon,cursor,nil,nil,
    hinst,icon,cursor, nil, nil,
    win32.L(CLASSNAME),
    nil,
    }

    if error := win32.RegisterClassExW(&window_context); error == 0 {
    win32.MessageBoxW(nil,win32.L("Unable to Register Window Class"), win32.L("Error"), win32.MB_ICONERROR)
    return;
    win32.MessageBoxW(nil, win32.L("Unable to Register Window Class"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    wglChoosePixelFormatARB : win32.ChoosePixelFormatARBType
    @@ -109,19 +109,19 @@ main :: proc() {
    win32.L(CLASSNAME),
    win32.L(APPNAME),
    dw_style,
    win32.CW_USEDEFAULT,win32.CW_USEDEFAULT,win32.CW_USEDEFAULT,win32.CW_USEDEFAULT,
    nil,nil,hinst,nil,
    win32.CW_USEDEFAULT, win32.CW_USEDEFAULT, win32.CW_USEDEFAULT, win32.CW_USEDEFAULT,
    nil, nil, hinst, nil,
    )

    if hwnd == nil {
    win32.MessageBoxW(nil,win32.L("Unable to Create Window"),win32.L("Error"), win32.MB_ICONERROR)
    win32.MessageBoxW(nil, win32.L("Unable to Create Window"),win32.L("Error"), win32.MB_ICONERROR)
    return
    }


    fake_dc := win32.GetDC(hwnd)
    if fake_dc == nil {
    win32.MessageBoxW(nil,win32.L("Unable to Get DC"), win32.L("Error"), win32.MB_ICONERROR)
    win32.MessageBoxW(nil, win32.L("Unable to Get DC"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    @@ -137,23 +137,23 @@ main :: proc() {

    pixel_format := win32.ChoosePixelFormat(fake_dc, &pfd)
    if pixel_format == 0 {
    win32.MessageBoxW(nil,win32.L("Failed to get pixel format"), win32.L("Error"), win32.MB_ICONERROR)
    win32.MessageBoxW(nil, win32.L("Failed to get pixel format"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    if !win32.SetPixelFormat(fake_dc, pixel_format, &pfd) {
    win32.MessageBoxW(nil,win32.L("Failed to set pixel format"), win32.L("Error"), win32.MB_ICONERROR)
    win32.MessageBoxW(nil, win32.L("Failed to set pixel format"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    fake_rc := win32.wglCreateContext(fake_dc)
    if fake_rc == nil {
    win32.MessageBoxW(nil,win32.L("Failed to create context"), win32.L("Error"), win32.MB_ICONERROR)
    win32.MessageBoxW(nil, win32.L("Failed to create context"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    if !win32.wglMakeCurrent(fake_dc, fake_rc) {
    win32.MessageBoxW(nil,win32.L("Failed to Get Pixel Format"), win32.L("Error"), win32.MB_ICONERROR)
    win32.MessageBoxW(nil, win32.L("Failed to Get Pixel Format"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    @@ -187,7 +187,7 @@ main :: proc() {
    defer win32.DestroyWindow(hwnd)

    if hwnd == nil {
    win32.MessageBoxW(nil,win32.L("Unable to Create Window"), win32.L("Error"), win32.MB_ICONERROR)
    win32.MessageBoxW(nil, win32.L("Unable to Create Window"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    @@ -245,10 +245,10 @@ main :: proc() {

    gl.load_up_to(int(GL_MAJOR_VERSION), GL_MINOR_VERSION, gl_set_proc_address)

    gl.Enable(gl.DEBUG_OUTPUT);
    gl.Enable(gl.DEBUG_OUTPUT)
    gl.Enable(gl.DEBUG_OUTPUT_SYNCHRONOUS)
    gl.DebugMessageCallback(gl_debug_callback, nil)
    gl.Viewport(0, 0, width, height);
    gl.Viewport(0, 0, width, height)

    // shader init

    @@ -292,8 +292,8 @@ main :: proc() {
    gl.CreateBuffers(1, &vbo); defer gl.DeleteBuffers(1, &vbo)
    gl.CreateBuffers(1, &ebo); defer gl.DeleteBuffers(1, &ebo)

    gl.NamedBufferData(vbo, len(vertices)*size_of(Vertex), raw_data(vertices), gl.STATIC_DRAW)
    gl.NamedBufferData(ebo, len(indices)*size_of(u16), raw_data(indices), gl.STATIC_DRAW)
    gl.NamedBufferData(vbo, len(vertices) * size_of(Vertex), raw_data(vertices), gl.STATIC_DRAW)
    gl.NamedBufferData(ebo, len(indices) * size_of(u16), raw_data(indices), gl.STATIC_DRAW)

    gl.EnableVertexArrayAttrib(vao, 0)
    gl.VertexArrayAttribBinding(vao, 0, 0)
    @@ -309,7 +309,7 @@ main :: proc() {
    msg : win32.MSG
    running = true
    for running {
    // windows handling
    // window handling
    for win32.PeekMessageA(&msg, hwnd, 0, 0, win32.PM_REMOVE) {
    win32.TranslateMessage(&msg)
    win32.DispatchMessageW(&msg)
  2. @GrumpyLion GrumpyLion revised this gist Sep 4, 2024. 1 changed file with 49 additions and 49 deletions.
    98 changes: 49 additions & 49 deletions win32_opengl_demo.odin
    Original file line number Diff line number Diff line change
    @@ -17,9 +17,9 @@ vertex_source := `
    layout(location=0) in vec3 a_position;
    layout(location=1) in vec4 a_color;
    out vec4 v_color;
    void main() {
    gl_Position = vec4(a_position, 1.0);
    v_color = a_color;
    void main() {
    gl_Position = vec4(a_position, 1.0);
    v_color = a_color;
    }
    `

    @@ -28,7 +28,7 @@ fragment_source := `
    in vec4 v_color;
    out vec4 o_color;
    void main() {
    o_color = v_color;
    o_color = v_color;
    }
    `

    @@ -37,13 +37,13 @@ running : bool = false

    // is also available in core/sys/windows/wgl.odin
    gl_set_proc_address :: proc(p: rawptr, name: cstring) {
    func := win32.wglGetProcAddress(name)
    switch uintptr(func) {
    case 0, 1, 2, 3, ~uintptr(0):
    module := win32.LoadLibraryW(win32.L("opengl32.dll"))
    func = win32.GetProcAddress(module, name)
    }
    (^rawptr)(p)^ = func
    func := win32.wglGetProcAddress(name)
    switch uintptr(func) {
    case 0, 1, 2, 3, ~uintptr(0):
    module := win32.LoadLibraryW(win32.L("opengl32.dll"))
    func = win32.GetProcAddress(module, name)
    }
    (^rawptr)(p)^ = func
    }

    GL_MAJOR_VERSION : c.int : 4
    @@ -252,48 +252,48 @@ main :: proc() {

    // shader init

    program, program_ok := gl.load_shaders_source(vertex_source, fragment_source)
    if !program_ok {
    program, program_ok := gl.load_shaders_source(vertex_source, fragment_source)
    if !program_ok {
    win32.MessageBoxW(nil,win32.L("Failed to create GLSL program"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }
    defer gl.DeleteProgram(program)
    gl.UseProgram(program)
    uniforms := gl.get_uniforms_from_program(program)
    defer delete(uniforms)
    return
    }
    defer gl.DeleteProgram(program)

    gl.UseProgram(program)

    uniforms := gl.get_uniforms_from_program(program)
    defer delete(uniforms)

    // vertex struct

    Vertex :: struct {
    pos: glm.vec3,
    col: glm.vec4,
    }
    vertices := []Vertex{
    {{-0.5, +0.5, 0}, {1.0, 0.0, 0.0, 0.75}},
    {{-0.5, -0.5, 0}, {1.0, 1.0, 0.0, 0.75}},
    {{+0.5, -0.5, 0}, {0.0, 1.0, 0.0, 0.75}},
    {{+0.5, +0.5, 0}, {0.0, 0.0, 1.0, 0.75}},
    }
    indices := []u16{
    0, 1, 2,
    2, 3, 0,
    }
    Vertex :: struct {
    pos: glm.vec3,
    col: glm.vec4,
    }

    vertices := []Vertex{
    {{-0.5, +0.5, 0}, {1.0, 0.0, 0.0, 0.75}},
    {{-0.5, -0.5, 0}, {1.0, 1.0, 0.0, 0.75}},
    {{+0.5, -0.5, 0}, {0.0, 1.0, 0.0, 0.75}},
    {{+0.5, +0.5, 0}, {0.0, 0.0, 1.0, 0.75}},
    }

    indices := []u16{
    0, 1, 2,
    2, 3, 0,
    }

    // buffers init

    vao: u32
    gl.CreateVertexArrays(1, &vao); defer gl.DeleteVertexArrays(1, &vao)
    vbo, ebo: u32
    gl.CreateBuffers(1, &vbo); defer gl.DeleteBuffers(1, &vbo)
    gl.CreateBuffers(1, &ebo); defer gl.DeleteBuffers(1, &ebo)
    vao: u32
    gl.CreateVertexArrays(1, &vao); defer gl.DeleteVertexArrays(1, &vao)

    vbo, ebo: u32
    gl.CreateBuffers(1, &vbo); defer gl.DeleteBuffers(1, &vbo)
    gl.CreateBuffers(1, &ebo); defer gl.DeleteBuffers(1, &ebo)

    gl.NamedBufferData(vbo, len(vertices)*size_of(Vertex), raw_data(vertices), gl.STATIC_DRAW)
    gl.NamedBufferData(ebo, len(indices)*size_of(u16), raw_data(indices), gl.STATIC_DRAW)
    gl.NamedBufferData(vbo, len(vertices)*size_of(Vertex), raw_data(vertices), gl.STATIC_DRAW)
    gl.NamedBufferData(ebo, len(indices)*size_of(u16), raw_data(indices), gl.STATIC_DRAW)

    gl.EnableVertexArrayAttrib(vao, 0)
    gl.VertexArrayAttribBinding(vao, 0, 0)
    @@ -309,7 +309,7 @@ main :: proc() {
    msg : win32.MSG
    running = true
    for running {
    // window handling
    // windows handling
    for win32.PeekMessageA(&msg, hwnd, 0, 0, win32.PM_REMOVE) {
    win32.TranslateMessage(&msg)
    win32.DispatchMessageW(&msg)
    @@ -320,7 +320,7 @@ main :: proc() {
    gl.ClearColor(0.5, 0.5, 0.5, 1.0)
    gl.BindVertexArray(vao)
    gl.UseProgram(program)
    gl.DrawElements(gl.TRIANGLES, i32(len(indices)), gl.UNSIGNED_SHORT, nil)
    gl.DrawElements(gl.TRIANGLES, i32(len(indices)), gl.UNSIGNED_SHORT, nil)

    win32.SwapBuffers(dc)
    }
  3. @GrumpyLion GrumpyLion created this gist Sep 4, 2024.
    327 changes: 327 additions & 0 deletions win32_opengl_demo.odin
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,327 @@
    package main

    // This is how you can manually initialize a window and OpenGL context on windows, instead of using SDL or GLFW.
    // Also renders a colorful quad onto the screen.
    // I made this as an exercise and getting into Odin.
    // This is my first "complete" odin program, so there's probably much better ways of doing this :D

    import "base:runtime"
    import "core:fmt"
    import "core:c"
    import win32 "core:sys/windows"
    import glm "core:math/linalg/glsl"
    import gl "vendor:OpenGL"

    vertex_source := `
    #version 330 core
    layout(location=0) in vec3 a_position;
    layout(location=1) in vec4 a_color;
    out vec4 v_color;
    void main() {
    gl_Position = vec4(a_position, 1.0);
    v_color = a_color;
    }
    `

    fragment_source := `
    #version 330 core
    in vec4 v_color;
    out vec4 o_color;
    void main() {
    o_color = v_color;
    }
    `

    wglSwapIntervalEXT : win32.SwapIntervalEXTType
    running : bool = false

    // is also available in core/sys/windows/wgl.odin
    gl_set_proc_address :: proc(p: rawptr, name: cstring) {
    func := win32.wglGetProcAddress(name)
    switch uintptr(func) {
    case 0, 1, 2, 3, ~uintptr(0):
    module := win32.LoadLibraryW(win32.L("opengl32.dll"))
    func = win32.GetProcAddress(module, name)
    }
    (^rawptr)(p)^ = func
    }

    GL_MAJOR_VERSION : c.int : 4
    GL_MINOR_VERSION :: 6

    CLASSNAME : cstring : "OpenGLClass"
    APPNAME : cstring : "OpenGL"

    WinProc :: proc "stdcall" (
    window: win32.HWND,
    message: win32.UINT,
    wparam: win32.WPARAM,
    lparam: win32.LPARAM
    ) -> win32.LRESULT {
    result: win32.LRESULT

    switch message {
    case win32.WM_DESTROY:
    win32.DestroyWindow(window)
    win32.PostQuitMessage(0)
    running = false
    result = 0
    case:
    result = win32.DefWindowProcW( window, message, wparam, lparam)
    }

    return result
    }

    gl_debug_callback :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, message: cstring, userParam: rawptr) {
    context = runtime.default_context()
    fmt.println(message)
    }

    main :: proc() {
    hinst : win32.HANDLE = auto_cast win32.GetModuleHandleW(nil)
    icon := win32.LoadIconA(nil, win32.IDI_APPLICATION)
    cursor := win32.LoadCursorA(nil, win32.IDC_ARROW)

    window_context := win32.WNDCLASSEXW {
    size_of(win32.WNDCLASSEXW),
    win32.CS_HREDRAW | win32.CS_VREDRAW,
    WinProc,
    0,0,
    hinst,icon,cursor,nil,nil,
    win32.L(CLASSNAME),
    nil,
    }

    if error := win32.RegisterClassExW(&window_context); error == 0 {
    win32.MessageBoxW(nil,win32.L("Unable to Register Window Class"), win32.L("Error"), win32.MB_ICONERROR)
    return;
    }

    wglChoosePixelFormatARB : win32.ChoosePixelFormatARBType
    wglCreateContextAttribsARB : win32.CreateContextAttribsARBType
    dw_style := win32.WS_OVERLAPPEDWINDOW

    // fake window and context for acquiring functions pointers

    hwnd := win32.CreateWindowExW(
    win32.WS_EX_OVERLAPPEDWINDOW,
    win32.L(CLASSNAME),
    win32.L(APPNAME),
    dw_style,
    win32.CW_USEDEFAULT,win32.CW_USEDEFAULT,win32.CW_USEDEFAULT,win32.CW_USEDEFAULT,
    nil,nil,hinst,nil,
    )

    if hwnd == nil {
    win32.MessageBoxW(nil,win32.L("Unable to Create Window"),win32.L("Error"), win32.MB_ICONERROR)
    return
    }


    fake_dc := win32.GetDC(hwnd)
    if fake_dc == nil {
    win32.MessageBoxW(nil,win32.L("Unable to Get DC"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    pfd := win32.PIXELFORMATDESCRIPTOR{
    nSize = size_of(win32.PIXELFORMATDESCRIPTOR),
    nVersion = 1,
    dwFlags = win32.PFD_DRAW_TO_WINDOW | win32.PFD_SUPPORT_OPENGL | win32.PFD_DOUBLEBUFFER,
    iPixelType = win32.PFD_TYPE_RGBA,
    cColorBits = 32,
    cAlphaBits = 8,
    cDepthBits = 24
    }

    pixel_format := win32.ChoosePixelFormat(fake_dc, &pfd)
    if pixel_format == 0 {
    win32.MessageBoxW(nil,win32.L("Failed to get pixel format"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    if !win32.SetPixelFormat(fake_dc, pixel_format, &pfd) {
    win32.MessageBoxW(nil,win32.L("Failed to set pixel format"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    fake_rc := win32.wglCreateContext(fake_dc)
    if fake_rc == nil {
    win32.MessageBoxW(nil,win32.L("Failed to create context"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    if !win32.wglMakeCurrent(fake_dc, fake_rc) {
    win32.MessageBoxW(nil,win32.L("Failed to Get Pixel Format"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    gl_set_proc_address(&wglChoosePixelFormatARB, "wglChoosePixelFormatARB")
    gl_set_proc_address(&wglCreateContextAttribsARB, "wglCreateContextAttribsARB")
    gl_set_proc_address(&wglSwapIntervalEXT, "wglSwapIntervalEXT")

    win32.wglMakeCurrent(fake_dc, nil)
    win32.wglDeleteContext(fake_rc)
    win32.ReleaseDC(hwnd, fake_dc)
    win32.DestroyWindow(hwnd)

    // actual window and context creation

    width : i32 = 1024
    height : i32 = 600

    border_rect : win32.RECT = {}
    win32.AdjustWindowRectEx(&border_rect, dw_style, false, 0)
    width += border_rect.right - border_rect.left
    height += border_rect.bottom - border_rect.top

    hwnd = win32.CreateWindowExW(
    win32.WS_EX_OVERLAPPEDWINDOW,
    win32.L(CLASSNAME),
    win32.L(APPNAME),
    dw_style,
    100, 100, width, height,
    nil,nil,hinst,nil,
    )
    defer win32.DestroyWindow(hwnd)

    if hwnd == nil {
    win32.MessageBoxW(nil,win32.L("Unable to Create Window"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    dc := win32.GetDC(hwnd)
    defer win32.ReleaseDC(hwnd, dc)

    pixel_attribs : []i32 = {
    win32.WGL_DRAW_TO_WINDOW_ARB, 1,
    win32.WGL_SUPPORT_OPENGL_ARB, 1,
    win32.WGL_DOUBLE_BUFFER_ARB, 1,
    win32.WGL_SWAP_METHOD_ARB, win32.WGL_SWAP_COPY_ARB,
    win32.WGL_PIXEL_TYPE_ARB, win32.WGL_TYPE_RGBA_ARB,
    win32.WGL_ACCELERATION_ARB, win32.WGL_FULL_ACCELERATION_ARB,
    win32.WGL_COLOR_BITS_ARB, 32,
    win32.WGL_ALPHA_BITS_ARB, 8,
    win32.WGL_DEPTH_BITS_ARB, 24,
    0
    }

    pixel_format = 0
    num_pixel_formats : win32.UINT32 = 0
    if !wglChoosePixelFormatARB(dc, raw_data(pixel_attribs), nil, 1, &pixel_format, &num_pixel_formats) {
    win32.MessageBoxW(nil,win32.L("Failed to choose a pixel format"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    pixel_format_descriptor : win32.PIXELFORMATDESCRIPTOR
    win32.DescribePixelFormat(dc, pixel_format, size_of(win32.PIXELFORMATDESCRIPTOR), &pixel_format_descriptor)

    if !win32.SetPixelFormat(dc, pixel_format, &pixel_format_descriptor) {
    win32.MessageBoxW(nil,win32.L("Unable to set pixle format"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }

    context_attribs : []i32 = {
    win32.WGL_CONTEXT_MAJOR_VERSION_ARB, GL_MAJOR_VERSION,
    win32.WGL_CONTEXT_MINOR_VERSION_ARB, GL_MINOR_VERSION,
    win32.WGL_CONTEXT_PROFILE_MASK_ARB, win32.WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
    win32.WGL_CONTEXT_FLAGS_ARB, win32.WGL_CONTEXT_DEBUG_BIT_ARB,
    0
    }

    render_context := wglCreateContextAttribsARB(dc, nil, raw_data(context_attribs))
    defer win32.wglDeleteContext(render_context)

    if !win32.wglMakeCurrent(dc, render_context) {
    win32.MessageBoxW(nil,win32.L("Failed to make the current context"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }
    defer win32.wglMakeCurrent(dc, nil)

    win32.ShowWindow(hwnd, win32.SW_SHOWNORMAL)

    // opengl init

    gl.load_up_to(int(GL_MAJOR_VERSION), GL_MINOR_VERSION, gl_set_proc_address)

    gl.Enable(gl.DEBUG_OUTPUT);
    gl.Enable(gl.DEBUG_OUTPUT_SYNCHRONOUS)
    gl.DebugMessageCallback(gl_debug_callback, nil)
    gl.Viewport(0, 0, width, height);

    // shader init

    program, program_ok := gl.load_shaders_source(vertex_source, fragment_source)
    if !program_ok {
    win32.MessageBoxW(nil,win32.L("Failed to create GLSL program"), win32.L("Error"), win32.MB_ICONERROR)
    return
    }
    defer gl.DeleteProgram(program)

    gl.UseProgram(program)

    uniforms := gl.get_uniforms_from_program(program)
    defer delete(uniforms)

    // vertex struct

    Vertex :: struct {
    pos: glm.vec3,
    col: glm.vec4,
    }

    vertices := []Vertex{
    {{-0.5, +0.5, 0}, {1.0, 0.0, 0.0, 0.75}},
    {{-0.5, -0.5, 0}, {1.0, 1.0, 0.0, 0.75}},
    {{+0.5, -0.5, 0}, {0.0, 1.0, 0.0, 0.75}},
    {{+0.5, +0.5, 0}, {0.0, 0.0, 1.0, 0.75}},
    }

    indices := []u16{
    0, 1, 2,
    2, 3, 0,
    }

    // buffers init

    vao: u32
    gl.CreateVertexArrays(1, &vao); defer gl.DeleteVertexArrays(1, &vao)

    vbo, ebo: u32
    gl.CreateBuffers(1, &vbo); defer gl.DeleteBuffers(1, &vbo)
    gl.CreateBuffers(1, &ebo); defer gl.DeleteBuffers(1, &ebo)

    gl.NamedBufferData(vbo, len(vertices)*size_of(Vertex), raw_data(vertices), gl.STATIC_DRAW)
    gl.NamedBufferData(ebo, len(indices)*size_of(u16), raw_data(indices), gl.STATIC_DRAW)

    gl.EnableVertexArrayAttrib(vao, 0)
    gl.VertexArrayAttribBinding(vao, 0, 0)
    gl.VertexArrayAttribFormat(vao, 0, 3, gl.FLOAT, false, 0)

    gl.EnableVertexArrayAttrib(vao, 1)
    gl.VertexArrayAttribBinding(vao, 1, 0)
    gl.VertexArrayAttribFormat(vao, 1, 4, gl.FLOAT, false, 3 * size_of(f32))

    gl.VertexArrayVertexBuffer(vao, 0, vbo, 0, size_of(Vertex))
    gl.VertexArrayElementBuffer(vao, ebo)

    msg : win32.MSG
    running = true
    for running {
    // window handling
    for win32.PeekMessageA(&msg, hwnd, 0, 0, win32.PM_REMOVE) {
    win32.TranslateMessage(&msg)
    win32.DispatchMessageW(&msg)
    }

    // draw
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.ClearColor(0.5, 0.5, 0.5, 1.0)
    gl.BindVertexArray(vao)
    gl.UseProgram(program)
    gl.DrawElements(gl.TRIANGLES, i32(len(indices)), gl.UNSIGNED_SHORT, nil)

    win32.SwapBuffers(dc)
    }
    }