package visuals import "base:runtime" import "core:c" import "core:fmt" import "core:log" import "vendor:OpenGL" import "vendor:sdl3" State :: struct { window: ^sdl3.Window, program: u32, vertex_pos_location: u32, vao: u32, vbo: u32, ibo: u32, wireframe: bool, } init :: proc() -> (state: State, ok: bool) { GL_MAJOR :: 3 GL_MINOR :: 3 // {{{ Configure logging @(static) g_ctx: runtime.Context g_ctx = context sdl3.SetLogPriorities(.VERBOSE) sdl3.SetLogOutputFunction( proc "c" ( userdata: rawptr, category: sdl3.LogCategory, priority: sdl3.LogPriority, message: cstring, ) { context = g_ctx level: log.Level switch priority { case .TRACE, .DEBUG, .VERBOSE: level = .Debug case .INFO: level = .Info case .WARN: level = .Warning case .ERROR: level = .Error case .CRITICAL: level = .Fatal case .INVALID: fallthrough case: log.panicf("Unexpected log level %v", priority) } options: runtime.Logger_Options = context.logger.options - {.Short_File_Path, .Long_File_Path, .Procedure, .Line} context.logger.procedure( context.logger.data, level, fmt.tprintf("[SDL/%v]: %v", category, message), options, ) }, nil, ) // }}} sdl3.Init(sdl3.InitFlags{.VIDEO}) or_return sdl3.GL_SetAttribute(.CONTEXT_MAJOR_VERSION, GL_MAJOR) or_return sdl3.GL_SetAttribute(.CONTEXT_MINOR_VERSION, GL_MINOR) or_return sdl3.GL_SetAttribute(.CONTEXT_PROFILE_MASK, c.int(sdl3.GL_CONTEXT_PROFILE_CORE)) or_return sdl3.GL_SetSwapInterval(1) // vsync state.window = sdl3.CreateWindow( "SDL visual experiment", 640, 480, {.FULLSCREEN, .OPENGL, .RESIZABLE}, ) (state.window != nil) or_return sdl3.StartTextInput(state.window) or_return gl_ctx := sdl3.GL_CreateContext(state.window) (gl_ctx != nil) or_return OpenGL.load_up_to(GL_MAJOR, GL_MINOR, sdl3.gl_set_proc_address) state.program = OpenGL.load_shaders_source( #load("./vert.glsl"), #load("./frag.glsl"), ) or_return // log.debug("Doing Opengl stuff") vertex_pos_location := OpenGL.GetAttribLocation(state.program, "aPos") (vertex_pos_location != -1) or_return state.vertex_pos_location = u32(vertex_pos_location) OpenGL.ClearColor(0, 0, 0, 1) // VBO data vertex_data := 2 * [?]f32{-0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5} // IBO data index_data := [?]u32{0, 1, 2, 3} OpenGL.GenVertexArrays(1, &state.vao) OpenGL.BindVertexArray(state.vao) //Create VBO OpenGL.GenBuffers(1, &state.vbo) OpenGL.BindBuffer(OpenGL.ARRAY_BUFFER, state.vbo) OpenGL.BufferData(OpenGL.ARRAY_BUFFER, 2 * 4 * size_of(f32), &vertex_data, OpenGL.STATIC_DRAW) OpenGL.EnableVertexAttribArray(state.vertex_pos_location) OpenGL.VertexAttribPointer( state.vertex_pos_location, 2, OpenGL.FLOAT, false, 2 * size_of(f32), 0, ) OpenGL.GenBuffers(1, auto_cast &state.ibo) OpenGL.BindBuffer(OpenGL.ELEMENT_ARRAY_BUFFER, state.ibo) OpenGL.BufferData( OpenGL.ELEMENT_ARRAY_BUFFER, 4 * size_of(u32), &index_data, OpenGL.STATIC_DRAW, ) OpenGL.BindVertexArray(0) OpenGL.DisableVertexAttribArray(state.vertex_pos_location) return state, true } render :: proc(state: State) { OpenGL.Clear(OpenGL.COLOR_BUFFER_BIT) OpenGL.UseProgram(state.program) defer OpenGL.UseProgram(0) if state.wireframe { OpenGL.PolygonMode(OpenGL.FRONT_AND_BACK, OpenGL.LINE) } else { OpenGL.PolygonMode(OpenGL.FRONT_AND_BACK, OpenGL.FILL) } OpenGL.BindVertexArray(state.vao) OpenGL.DrawElements(OpenGL.TRIANGLE_FAN, 4, OpenGL.UNSIGNED_INT, nil) } close :: proc(state: State) { OpenGL.DeleteProgram(state.program) _ = sdl3.StopTextInput(state.window) sdl3.DestroyWindow(state.window) sdl3.Quit() } main :: proc() { log.Level_Headers = { 0 ..< 10 = "[DEBUG] ", 10 ..< 20 = "[INFO ] ", 20 ..< 30 = "[WARN ] ", 30 ..< 40 = "[ERROR] ", 40 ..< 50 = "[FATAL] ", } logger := log.create_console_logger() logger.options -= {.Date, .Time} context.logger = logger state, ok := init() log.assertf(ok, "Got SDL error: %v", sdl3.GetError()) defer close(state) quit := false for !quit { event: sdl3.Event for sdl3.PollEvent(&event) { #partial switch event.type { case .WINDOW_RESIZED: OpenGL.Viewport(0, 0, event.window.data1, event.window.data2) case .QUIT: quit = true case .TEXT_INPUT: switch ([^]u8)(event.text.text)[0] { case 'w': state.wireframe = !state.wireframe } log.debug(event.text) } } render(state) sdl3.GL_SwapWindow(state.window) } }