Created
September 11, 2025 03:58
-
-
Save fearofcode/4e7ef5d9c72fb4590186646a93183c0a to your computer and use it in GitHub Desktop.
Simple microui Odin OpenGL basic example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import "core:fmt" | |
| import glm "core:math/linalg/glsl" | |
| import gl "vendor:OpenGL" | |
| import mu "vendor:microui" | |
| Microui_Vertex :: struct { | |
| pos : glm.vec2, | |
| tex : glm.vec2, | |
| col : [4]u8, | |
| } | |
| Debug_UI_Context :: struct { | |
| mu_ctx : mu.Context, | |
| mu_shader : Shader, | |
| mu_vao : u32, | |
| mu_vbo : u32, | |
| mu_ebo : u32, | |
| mu_atlas_tex : u32, | |
| // Buffers for batching draw commands | |
| vert_buf : [dynamic]Microui_Vertex, | |
| index_buf : [dynamic]u32, | |
| } | |
| debug_ui_context : Debug_UI_Context | |
| DEBUG_UI_VERTEX_SOURCE := `#version 330 core | |
| layout(location=0) in vec2 a_position; | |
| layout(location=1) in vec2 a_tex_coord; | |
| layout(location=2) in vec4 a_color; | |
| out vec2 v_tex_coord; | |
| out vec4 v_color; | |
| uniform mat4 u_projection; | |
| void main() { | |
| gl_Position = u_projection * vec4(a_position, 0.0, 1.0); | |
| v_tex_coord = a_tex_coord; | |
| v_color = a_color; | |
| } | |
| ` | |
| DEBUG_UI_FRAGMENT_SOURCE := `#version 330 core | |
| in vec2 v_tex_coord; | |
| in vec4 v_color; | |
| out vec4 o_color; | |
| uniform sampler2D u_texture; | |
| void main() { | |
| // Sample the alpha channel from the atlas and multiply by vertex color | |
| float alpha = texture(u_texture, v_tex_coord).r; | |
| o_color = vec4(v_color.rgb, v_color.a * alpha); | |
| } | |
| ` | |
| debug_ui_init :: proc() -> bool { | |
| shader, shader_ok := shader_from_source_strings(DEBUG_UI_VERTEX_SOURCE, DEBUG_UI_FRAGMENT_SOURCE) | |
| if !shader_ok { | |
| fmt.eprintln("Error compiling debug UI shader") | |
| return false | |
| } | |
| debug_ui_context.mu_shader = shader | |
| gl.GenVertexArrays(1, &debug_ui_context.mu_vao) | |
| gl.GenBuffers(1, &debug_ui_context.mu_vbo) | |
| gl.GenBuffers(1, &debug_ui_context.mu_ebo) | |
| gl.BindVertexArray(debug_ui_context.mu_vao) | |
| gl.BindBuffer(gl.ARRAY_BUFFER, debug_ui_context.mu_vbo) | |
| gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, debug_ui_context.mu_ebo) | |
| gl.EnableVertexAttribArray(0) // pos | |
| gl.EnableVertexAttribArray(1) // tex | |
| gl.EnableVertexAttribArray(2) // col | |
| gl.VertexAttribPointer(0, 2, gl.FLOAT, false, size_of(Microui_Vertex), offset_of(Microui_Vertex, pos)) | |
| gl.VertexAttribPointer(1, 2, gl.FLOAT, false, size_of(Microui_Vertex), offset_of(Microui_Vertex, tex)) | |
| gl.VertexAttribPointer(2, 4, gl.UNSIGNED_BYTE, true, size_of(Microui_Vertex), offset_of(Microui_Vertex, col)) | |
| // Create atlas texture | |
| gl.GenTextures(1, &debug_ui_context.mu_atlas_tex) | |
| gl.BindTexture(gl.TEXTURE_2D, debug_ui_context.mu_atlas_tex) | |
| gl.TexImage2D( | |
| gl.TEXTURE_2D, | |
| 0, | |
| gl.R8, // Internal format: Store as 8-bit Red channel | |
| mu.DEFAULT_ATLAS_WIDTH, | |
| mu.DEFAULT_ATLAS_HEIGHT, | |
| 0, | |
| gl.RED, // Source format: The data we provide is in the Red channel | |
| gl.UNSIGNED_BYTE, | |
| &mu.default_atlas_alpha, | |
| ) | |
| gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) | |
| gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) | |
| // Initialize microui context | |
| mu.init(&debug_ui_context.mu_ctx) | |
| debug_ui_context.mu_ctx.text_width = mu.default_atlas_text_width | |
| debug_ui_context.mu_ctx.text_height = mu.default_atlas_text_height | |
| return true | |
| } | |
| // Flushes the vertex/index buffers to the GPU and issues a draw call | |
| microui_flush :: proc() { | |
| if len(debug_ui_context.index_buf) == 0 { | |
| return | |
| } | |
| gl.BindVertexArray(debug_ui_context.mu_vao) | |
| // Upload vertex and index data to GPU | |
| gl.BindBuffer(gl.ARRAY_BUFFER, debug_ui_context.mu_vbo) | |
| gl.BufferData( | |
| gl.ARRAY_BUFFER, | |
| len(debug_ui_context.vert_buf) * size_of(Microui_Vertex), | |
| raw_data(debug_ui_context.vert_buf), | |
| gl.STREAM_DRAW, | |
| ) | |
| gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, debug_ui_context.mu_ebo) | |
| gl.BufferData( | |
| gl.ELEMENT_ARRAY_BUFFER, | |
| len(debug_ui_context.index_buf) * size_of(u32), | |
| raw_data(debug_ui_context.index_buf), | |
| gl.STREAM_DRAW, | |
| ) | |
| // Draw the batch | |
| gl.DrawElements(gl.TRIANGLES, i32(len(debug_ui_context.index_buf)), gl.UNSIGNED_INT, nil) | |
| // Reset buffers for the next batch | |
| clear(&debug_ui_context.vert_buf) | |
| clear(&debug_ui_context.index_buf) | |
| } | |
| // Pushes a quad to the vertex/index buffers | |
| microui_push_quad :: proc(dst, src : mu.Rect, color : mu.Color) { | |
| idx := u32(len(debug_ui_context.vert_buf)) | |
| atlas_w, atlas_h := f32(mu.DEFAULT_ATLAS_WIDTH), f32(mu.DEFAULT_ATLAS_HEIGHT) | |
| u0, v0 := f32(src.x) / atlas_w, f32(src.y) / atlas_h | |
| u1, v1 := f32(src.x + src.w) / atlas_w, f32(src.y + src.h) / atlas_h | |
| x0, y0 := f32(dst.x), f32(dst.y) | |
| x1, y1 := f32(dst.x + dst.w), f32(dst.y + dst.h) | |
| col := [4]u8{color.r, color.g, color.b, color.a} | |
| append( | |
| &debug_ui_context.vert_buf, | |
| Microui_Vertex{{x0, y0}, {u0, v0}, col}, | |
| Microui_Vertex{{x1, y0}, {u1, v0}, col}, | |
| Microui_Vertex{{x1, y1}, {u1, v1}, col}, | |
| Microui_Vertex{{x0, y1}, {u0, v1}, col}, | |
| ) | |
| append(&debug_ui_context.index_buf, idx, idx + 1, idx + 2, idx, idx + 2, idx + 3) | |
| } | |
| // Process the Microui command list and render it | |
| microui_render :: proc() { | |
| // Prepare OpenGL state for 2D UI rendering | |
| gl.Enable(gl.BLEND) | |
| gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) | |
| gl.Disable(gl.CULL_FACE) | |
| gl.Disable(gl.DEPTH_TEST) | |
| gl.Enable(gl.SCISSOR_TEST) | |
| gl.ActiveTexture(gl.TEXTURE0) | |
| gl.BindTexture(gl.TEXTURE_2D, debug_ui_context.mu_atlas_tex) | |
| use_shader(debug_ui_context.mu_shader) | |
| // Set up orthographic projection | |
| projection_matrix := glm.mat4Ortho3d(0, f32(WINDOW_WIDTH) / UI_SCALE, f32(WINDOW_HEIGHT) / UI_SCALE, 0, -1, 1) | |
| set_shader_uniform_mat4(debug_ui_context.mu_shader, "u_projection", projection_matrix) | |
| set_shader_uniform_int(debug_ui_context.mu_shader, "u_texture", 0) | |
| // Process commands | |
| command_backing : ^mu.Command | |
| for variant in mu.next_command_iterator(&debug_ui_context.mu_ctx, &command_backing) { | |
| #partial switch cmd in variant { | |
| case ^mu.Command_Text: | |
| dst := mu.Rect{cmd.pos.x, cmd.pos.y, 0, 0} | |
| for ch in cmd.str { | |
| if ch & 0xc0 == 0x80 {continue} | |
| r := min(int(ch), 127) | |
| src := mu.default_atlas[mu.DEFAULT_ATLAS_FONT + r] | |
| dst.w, dst.h = src.w, src.h | |
| microui_push_quad(dst, src, cmd.color) | |
| dst.x += dst.w | |
| } | |
| case ^mu.Command_Rect: | |
| // Use the special white pixel in the atlas for solid colors | |
| white_pixel_rect := mu.default_atlas[mu.DEFAULT_ATLAS_WHITE] | |
| microui_push_quad(cmd.rect, white_pixel_rect, cmd.color) | |
| case ^mu.Command_Icon: | |
| src := mu.default_atlas[cmd.id] | |
| x := cmd.rect.x + (cmd.rect.w - src.w) / 2 | |
| y := cmd.rect.y + (cmd.rect.h - src.h) / 2 | |
| microui_push_quad(mu.Rect{x, y, src.w, src.h}, src, cmd.color) | |
| case ^mu.Command_Clip: | |
| microui_flush() // Flush before changing scissor rect | |
| gl.Scissor(cmd.rect.x, WINDOW_HEIGHT - (cmd.rect.y + cmd.rect.h), cmd.rect.w, cmd.rect.h) | |
| } | |
| } | |
| microui_flush() // Flush remaining commands at the end of the frame | |
| // Reset scissor to full screen | |
| gl.Scissor(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT) | |
| } | |
| // Defines and processes the UI for our application | |
| run_debug_ui :: proc() { | |
| if !app_state.show_debug_ui { | |
| return | |
| } | |
| mu.begin(&debug_ui_context.mu_ctx) | |
| // open and close UI with F1, don't let UI be closed by clicking X | |
| if mu.window(&debug_ui_context.mu_ctx, "Controls", {10, 10, 200, 150}, {.NO_CLOSE}) { | |
| mu.layout_row(&debug_ui_context.mu_ctx, {-1}, 0) | |
| mu.label(&debug_ui_context.mu_ctx, "Simple UI Controls") | |
| mu.layout_row(&debug_ui_context.mu_ctx, {-1}, 0) | |
| if .CHANGE in mu.checkbox(&debug_ui_context.mu_ctx, "Show 3D Quad", &app_state.show_quad) { | |
| fmt.println("show_quad changed to", app_state.show_quad) | |
| } | |
| mu.layout_row(&debug_ui_context.mu_ctx, {20, -1}) | |
| mu.label(&debug_ui_context.mu_ctx, "BG:") | |
| // A helper to create a u8 slider | |
| u8_slider :: proc(val : ^u8, lo, hi : int) { | |
| ctx := &debug_ui_context.mu_ctx | |
| // Push the memory address of `val` as a unique ID for this slider. | |
| mu.push_id(ctx, uintptr(val)) | |
| // This static var is now safe because Microui uses the ID stack | |
| // to distinguish between the controls that use it. | |
| @(static) tmp : mu.Real | |
| tmp = mu.Real(val^) | |
| mu.slider(ctx, &tmp, f32(lo), f32(hi), 0, "%.0f", {}) | |
| val^ = u8(tmp) | |
| // Pop the ID to restore the stack for the next control. | |
| mu.pop_id(ctx) | |
| } | |
| mu.layout_begin_column(&debug_ui_context.mu_ctx) | |
| u8_slider(&app_state.bg_color.r, 0, 255) | |
| u8_slider(&app_state.bg_color.g, 0, 255) | |
| u8_slider(&app_state.bg_color.b, 0, 255) | |
| mu.layout_end_column(&debug_ui_context.mu_ctx) | |
| } | |
| mu.end(&debug_ui_context.mu_ctx) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import "core:fmt" | |
| import "core:math" | |
| import glm "core:math/linalg/glsl" | |
| import "core:time" | |
| import gl "vendor:OpenGL" | |
| import mu "vendor:microui" | |
| import SDL "vendor:sdl2" | |
| App_State :: struct { | |
| bg_color : mu.Color, | |
| show_quad : bool, | |
| show_debug_ui : bool, | |
| } | |
| app_state : App_State | |
| Vertex :: struct { | |
| pos : glm.vec3, | |
| col : glm.vec4, | |
| } | |
| main :: proc() { | |
| window_context, window_ok := init_sdl_opengl_context() | |
| if !window_ok { | |
| return | |
| } | |
| defer sdl_opengl_cleanup(window_context) | |
| main_shader, shader_ok := shader_from_source_strings(vertex_source, fragment_source) | |
| if !shader_ok { | |
| fmt.eprintln("Failed to create GLSL program") | |
| return | |
| } | |
| defer cleanup_shader(main_shader) | |
| use_shader(main_shader) | |
| vao : u32 | |
| gl.GenVertexArrays(1, &vao); defer gl.DeleteVertexArrays(1, &vao) | |
| gl.BindVertexArray(vao) | |
| vbo, ebo : u32 | |
| gl.GenBuffers(1, &vbo) | |
| defer gl.DeleteBuffers(1, &vbo) | |
| gl.GenBuffers(1, &ebo) | |
| defer gl.DeleteBuffers(1, &ebo) | |
| vertices := []Vertex { | |
| // position color | |
| {{-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} | |
| index_count := i32(len(indices)) | |
| gl.BindBuffer(gl.ARRAY_BUFFER, vbo) | |
| gl.BufferData(gl.ARRAY_BUFFER, len(vertices) * size_of(vertices[0]), raw_data(vertices), gl.STATIC_DRAW) | |
| gl.VertexAttribPointer(0, 3, gl.FLOAT, false, size_of(Vertex), offset_of(Vertex, pos)) | |
| gl.EnableVertexAttribArray(0) | |
| gl.VertexAttribPointer(1, 4, gl.FLOAT, false, size_of(Vertex), offset_of(Vertex, col)) | |
| gl.EnableVertexAttribArray(1) | |
| gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo) | |
| gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices) * size_of(indices[0]), raw_data(indices), gl.STATIC_DRAW) | |
| if (!debug_ui_init()) { | |
| fmt.eprintln("Error initializing debug UI") | |
| return | |
| } | |
| start_tick := time.tick_now() | |
| camera_position : glm.vec3 = {0, 0, -2} | |
| world_center : glm.vec3 = {0, 0, 0} | |
| y_up : glm.vec3 = {0, 1, 0} | |
| camera_fov := math.to_radians_f32(45) | |
| app_state.bg_color = {100, 100, 100, 255} | |
| app_state.show_quad = true | |
| app_state.show_debug_ui = true | |
| loop: for { | |
| duration := time.tick_since(start_tick) | |
| t := f32(time.duration_seconds(duration)) | |
| event : SDL.Event | |
| for SDL.PollEvent(&event) { | |
| #partial switch event.type { | |
| case .QUIT: | |
| break loop | |
| case .MOUSEMOTION: | |
| scaled_x := i32(f32(event.motion.x) / UI_SCALE) | |
| scaled_y := i32(f32(event.motion.y) / UI_SCALE) | |
| mu.input_mouse_move(&debug_ui_context.mu_ctx, scaled_x, scaled_y) | |
| case .MOUSEWHEEL: | |
| mu.input_scroll(&debug_ui_context.mu_ctx, event.wheel.x * 30, event.wheel.y * -30) | |
| case .TEXTINPUT: | |
| mu.input_text(&debug_ui_context.mu_ctx, string(cstring(&event.text.text[0]))) | |
| case .MOUSEBUTTONDOWN, .MOUSEBUTTONUP: | |
| fn := mu.input_mouse_down if event.type == .MOUSEBUTTONDOWN else mu.input_mouse_up | |
| // Also scale mouse coordinates here! | |
| scaled_x := i32(f32(event.button.x) / UI_SCALE) | |
| scaled_y := i32(f32(event.button.y) / UI_SCALE) | |
| switch event.button.button { | |
| case SDL.BUTTON_LEFT: | |
| fn(&debug_ui_context.mu_ctx, scaled_x, scaled_y, .LEFT) | |
| case SDL.BUTTON_MIDDLE: | |
| fn(&debug_ui_context.mu_ctx, scaled_x, scaled_y, .MIDDLE) | |
| case SDL.BUTTON_RIGHT: | |
| fn(&debug_ui_context.mu_ctx, scaled_x, scaled_y, .RIGHT) | |
| } | |
| case .KEYDOWN, .KEYUP: | |
| if event.key.keysym.sym == .ESCAPE {break loop} | |
| if event.type == .KEYDOWN { | |
| #partial switch event.key.keysym.sym { | |
| case .F1: | |
| app_state.show_debug_ui = !app_state.show_debug_ui | |
| } | |
| } | |
| fn := mu.input_key_down if event.type == .KEYDOWN else mu.input_key_up | |
| #partial switch event.key.keysym.sym { | |
| case .LSHIFT, .RSHIFT: | |
| fn(&debug_ui_context.mu_ctx, .SHIFT) | |
| case .LCTRL, .RCTRL: | |
| fn(&debug_ui_context.mu_ctx, .CTRL) | |
| case .LALT, .RALT: | |
| fn(&debug_ui_context.mu_ctx, .ALT) | |
| case .RETURN, .KP_ENTER: | |
| fn(&debug_ui_context.mu_ctx, .RETURN) | |
| case .BACKSPACE: | |
| fn(&debug_ui_context.mu_ctx, .BACKSPACE) | |
| } | |
| } | |
| } | |
| run_debug_ui() | |
| bg := app_state.bg_color | |
| gl.Viewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT) | |
| gl.ClearColor(f32(bg.r) / 255, f32(bg.g) / 255, f32(bg.b) / 255, 1.0) | |
| gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) | |
| if app_state.show_quad { | |
| gl.Enable(gl.DEPTH_TEST) | |
| gl.Disable(gl.SCISSOR_TEST) | |
| gl.Disable(gl.BLEND) | |
| gl.BindVertexArray(vao) | |
| // rotate about Z axis | |
| model := mat4_identity() * glm.mat4Rotate({0, 1, 0}, t) | |
| view := glm.mat4LookAt(eye = camera_position, centre = world_center, up = y_up) | |
| projection := glm.mat4Perspective(camera_fov, ASPECT, 0.1, 100.0) | |
| use_shader(main_shader) | |
| transform := projection * view * model | |
| set_shader_uniform_mat4(main_shader, "u_transform", transform) | |
| gl.DrawElements(gl.TRIANGLES, index_count, gl.UNSIGNED_SHORT, nil) | |
| } | |
| if app_state.show_debug_ui { | |
| microui_render() | |
| } | |
| SDL.GL_SwapWindow(window_context.window) | |
| free_all(context.temp_allocator) | |
| } | |
| } | |
| vertex_source := `#version 460 core | |
| layout(location=0) in vec3 a_position; | |
| layout(location=1) in vec4 a_color; | |
| out vec4 v_color; | |
| uniform mat4 u_transform; | |
| void main() { | |
| gl_Position = u_transform * vec4(a_position, 1.0); | |
| v_color = a_color; | |
| } | |
| ` | |
| fragment_source := `#version 460 core | |
| in vec4 v_color; | |
| out vec4 o_color; | |
| void main() { | |
| o_color = v_color; | |
| } | |
| ` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import "core:fmt" | |
| import glm "core:math/linalg/glsl" | |
| import gl "vendor:OpenGL" | |
| Shader :: struct { | |
| program_id : u32, | |
| uniforms : gl.Uniforms, | |
| } | |
| shader_from_source_strings :: proc(vertex_source, fragment_source : string) -> (Shader, bool) { | |
| shader : Shader | |
| program_id, program_ok := gl.load_shaders_source(vertex_source, fragment_source) | |
| if !program_ok { | |
| fmt.eprintln("Failed to create GLSL program!") | |
| } | |
| shader.program_id = program_id | |
| shader.uniforms = gl.get_uniforms_from_program(program_id) | |
| return shader, program_ok | |
| } | |
| cleanup_shader :: proc(shader : Shader) { | |
| gl.DeleteProgram(shader.program_id) | |
| delete(shader.uniforms) | |
| } | |
| use_shader :: proc(shader : Shader) { | |
| gl.UseProgram(shader.program_id) | |
| } | |
| set_shader_uniform_mat4 :: proc(shader : Shader, name : string, m : glm.mat4) { | |
| m := m // so we can pass a pointer | |
| gl.UniformMatrix4fv(shader.uniforms[name].location, 1, false, &m[0, 0]) | |
| } | |
| set_shader_uniform_int :: proc(shader : Shader, name : string, i : i32) { | |
| gl.Uniform1i(shader.uniforms[name].location, i) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import glm "core:math/linalg/glsl" | |
| mat4_identity :: proc() -> glm.mat4 { | |
| return glm.mat4{1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0} | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import "core:fmt" | |
| import gl "vendor:OpenGL" | |
| import SDL "vendor:sdl2" | |
| GL_VERSION_MAJOR :: 4 | |
| GL_VERSION_MINOR :: 6 | |
| WINDOW_WIDTH :: 1920 | |
| WINDOW_HEIGHT :: 1080 | |
| ASPECT :: WINDOW_WIDTH / WINDOW_HEIGHT | |
| UI_SCALE :: 1.0 // todo compute this dynamically based on window and display dimensions | |
| SDL_Window_Context :: struct { | |
| window : ^SDL.Window, | |
| gl_context : SDL.GLContext, | |
| } | |
| init_sdl_opengl_context :: proc() -> (SDL_Window_Context, bool) { | |
| window_context : SDL_Window_Context | |
| SDL.Init({.VIDEO}) | |
| window := SDL.CreateWindow( | |
| "Odin SDL2 Demo", | |
| SDL.WINDOWPOS_UNDEFINED, | |
| SDL.WINDOWPOS_UNDEFINED, | |
| WINDOW_WIDTH, | |
| WINDOW_HEIGHT, | |
| {.OPENGL}, | |
| ) | |
| if window == nil { | |
| fmt.eprintln("Failed to create window") | |
| return window_context, false | |
| } | |
| SDL.GL_SetAttribute(.CONTEXT_PROFILE_MASK, i32(SDL.GLprofile.CORE)) | |
| SDL.GL_SetAttribute(.CONTEXT_MAJOR_VERSION, GL_VERSION_MAJOR) | |
| SDL.GL_SetAttribute(.CONTEXT_MINOR_VERSION, GL_VERSION_MINOR) | |
| gl_context := SDL.GL_CreateContext(window) | |
| // vsync | |
| SDL.GL_SetSwapInterval(1) | |
| gl.load_up_to(GL_VERSION_MAJOR, GL_VERSION_MINOR, SDL.gl_set_proc_address) | |
| window_context.window = window | |
| window_context.gl_context = gl_context | |
| return window_context, true | |
| } | |
| sdl_opengl_cleanup :: proc(window_context : SDL_Window_Context) { | |
| SDL.Quit() | |
| SDL.DestroyWindow(window_context.window) | |
| SDL.GL_DeleteContext(window_context.gl_context) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment