Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save oskarnp/eb1f220c097d18c30bcca202c45d2e0c to your computer and use it in GitHub Desktop.
Save oskarnp/eb1f220c097d18c30bcca202c45d2e0c to your computer and use it in GitHub Desktop.
// Sample code showing how to create a modern OpenGL window and rendering
// context on Win32, using Odin.
//
// Ported from https://gist.github.com/nickrolfe/1127313ed1dbf80254b614a721b3ee9c
package main
import "core:sys/windows"
import "core:strings"
import "core:fmt"
import "core:intrinsics"
import "core:c"
import gl "vendor:OpenGL"
CONTEXT_GL_MAJOR := 3
CONTEXT_GL_MINOR := 3
L :: intrinsics.constant_utf16_cstring
window_callback :: proc "system" (window: windows.HWND,
msg: windows.UINT,
wparam: windows.WPARAM,
lparam: windows.LPARAM) -> (result: windows.LRESULT) {
using windows
switch msg {
case WM_CLOSE:
DestroyWindow(window)
case WM_DESTROY:
PostQuitMessage(0)
case:
result = DefWindowProcW(window, msg, wparam, lparam)
}
return
}
fatal_error :: proc(msg: cstring) {
using windows
fmt.eprintln(msg)
MessageBoxW(nil, utf8_to_wstring(string(msg)), L("Error"), MB_OK | MB_ICONEXCLAMATION)
ExitProcess(1)
}
init_opengl_extensions :: proc() {
using windows
// Before we can load extensions, we need a dummy OpenGL context, created
// using a dummy window. We use a dummy window because you can only set
// the pixel format for a window once. For the real window, we want to
// use wglChoosePixelFormatARB (so we can potentially specify options
// that aren't available in PIXELFORMATDESCRIPTOR), but we can't load and
// use that before we have a context.
window_class := WNDCLASSW {
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
lpfnWndProc = DefWindowProcW,
hInstance = HINSTANCE(GetModuleHandleW(nil)),
lpszClassName = L("Dummy_WGL_djuasiodwa"),
}
if RegisterClassW(&window_class) == 0 {
fatal_error("Failed to register dummy OpenGL window.")
}
dummy_window := CreateWindowExW(
0,
window_class.lpszClassName,
L("Dummy OpenGL Window"),
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
nil,
nil,
window_class.hInstance,
nil)
if dummy_window == nil {
fatal_error("Failed to create dummy OpenGL window.")
}
dummy_dc := GetDC(dummy_window)
pfd := PIXELFORMATDESCRIPTOR {
nSize = size_of(PIXELFORMATDESCRIPTOR),
nVersion = 1,
iPixelType = PFD_TYPE_RGBA,
dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
cColorBits = 32,
cAlphaBits = 8,
iLayerType = PFD_MAIN_PLANE,
cDepthBits = 24,
cStencilBits = 8,
}
pixel_format := ChoosePixelFormat(dummy_dc, &pfd)
if pixel_format == 0 {
fatal_error("Failed to find a suitable pixel format.")
}
if !SetPixelFormat(dummy_dc, pixel_format, &pfd) {
fatal_error("Failed to set the pixel format.")
}
dummy_context := wglCreateContext(dummy_dc)
if dummy_context == nil {
fatal_error("Failed to create a dummy OpenGL rendering context.")
}
if !wglMakeCurrent(dummy_dc, dummy_context) {
fatal_error("Failed to activate dummy OpenGL rendering context.")
}
wglCreateContextAttribsARB = cast(CreateContextAttribsARBType) wglGetProcAddress("wglCreateContextAttribsARB")
wglChoosePixelFormatARB = cast(ChoosePixelFormatARBType) wglGetProcAddress("wglChoosePixelFormatARB")
wglMakeCurrent(dummy_dc, nil)
wglDeleteContext(dummy_context)
ReleaseDC(dummy_window, dummy_dc)
DestroyWindow(dummy_window)
}
init_opengl :: proc(real_dc: windows.HDC) -> windows.HGLRC {
using windows
init_opengl_extensions()
// Now we can choose a pixel format the modern way, using
// wglChoosePixelFormatARB.
pixel_format_attribs := [?]c.int{
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_ACCELERATION_ARB, windows.WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, windows.WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0,
}
pixel_format: c.int
num_formats: UINT
wglChoosePixelFormatARB(real_dc, &pixel_format_attribs[0], nil, 1, &pixel_format, &num_formats)
if num_formats == 0 {
fatal_error("wglChoosePixelFormatARB")
}
pfd: PIXELFORMATDESCRIPTOR
DescribePixelFormat(real_dc, pixel_format, size_of(pfd), &pfd)
if !SetPixelFormat(real_dc, pixel_format, &pfd) {
fatal_error("SetPixelFormat")
}
gl_attribs := [?]c.int{
WGL_CONTEXT_MAJOR_VERSION_ARB, c.int(CONTEXT_GL_MAJOR),
WGL_CONTEXT_MINOR_VERSION_ARB, c.int(CONTEXT_GL_MINOR),
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0,
};
gl_context := wglCreateContextAttribsARB(real_dc, nil, &gl_attribs[0])
if gl_context == nil {
fatal_error("wglCreateContextAttribsARB")
}
if !wglMakeCurrent(real_dc, gl_context) {
fatal_error("wglMakeCurrent")
}
return gl_context
}
create_window :: proc(inst: windows.HINSTANCE) -> windows.HWND {
using windows
window_class := WNDCLASSW {
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
lpfnWndProc = window_callback,
hInstance = inst,
hCursor = windows.LoadCursorW(nil, transmute([^]u16)IDC_ARROW),
hbrBackground = nil,
lpszClassName = L("WGL_fdjhsklf"),
}
if RegisterClassW(&window_class) == 0 {
fatal_error("Failed to register window.")
}
// Specify a desired width and height, then adjust the rect so the
// window's client area will be that size.
rect := RECT {
right = 1024,
bottom = 576,
};
window_style: DWORD = WS_OVERLAPPEDWINDOW
AdjustWindowRect(&rect, window_style, false)
window := CreateWindowW(
window_class.lpszClassName,
L("OpenGL"),
window_style,
CW_USEDEFAULT,
CW_USEDEFAULT,
rect.right - rect.left,
rect.bottom - rect.top,
nil,
nil,
inst,
nil)
if window == nil {
fatal_error("Failed to create window.")
}
return window
}
main :: proc() {
using windows
window := create_window(nil)
gldc := GetDC(window)
glrc := init_opengl(gldc)
gl.load_up_to(CONTEXT_GL_MAJOR, CONTEXT_GL_MINOR, proc(p0: rawptr, name: cstring) {
p := windows.wglGetProcAddress(name)
if p <= rawptr(uintptr(3)) {
module := windows.LoadLibraryW(L("opengl32.dll"))
p = windows.GetProcAddress(module, name)
}
if p == nil {
fmt.eprintf("Failed to load GL proc: %s", name)
}
(cast(^rawptr)p0)^ = p
})
ShowWindow(window, SW_SHOW)
UpdateWindow(window)
loop: for {
msg: MSG
for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) {
if msg.message == WM_QUIT {
break loop
} else {
TranslateMessage(&msg)
DispatchMessageW(&msg)
}
}
gl.ClearColor(1.0, 0.5, 0.5, 1.0)
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
SwapBuffers(gldc)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment