#+private package renderer import "core:strings" import "core:fmt" import gl "vendor:OpenGL" import win "core:sys/windows" when RENDER_BACKEND_OPENGL { Backend_OpenGL_Windows :: struct { hwnd: win.HWND, hdc: win.HDC, gl_context: win.HGLRC, } backend: Backend_OpenGL_Windows OPENGL_MAJOR :: 3 OPENGL_MINOR :: 3 opengl_init :: proc(renderer: ^Renderer) -> bool { renderer.backend = &backend backend.hwnd = win.HWND(renderer.surface_ptr) backend.hdc = win.GetDC(backend.hwnd) pfd := win.PIXELFORMATDESCRIPTOR { nSize = size_of(win.PIXELFORMATDESCRIPTOR), nVersion = 1, dwFlags = win.PFD_DRAW_TO_WINDOW | win.PFD_SUPPORT_OPENGL | win.PFD_DOUBLEBUFFER, iPixelType = win.PFD_TYPE_RGBA, cColorBits = 32, cDepthBits = 24, cStencilBits = 8, iLayerType = win.PFD_MAIN_PLANE, } format_index := win.ChoosePixelFormat(backend.hdc, &pfd) assert(format_index != 0, "ChoosePixelFormat failed") set_pixel_format_ok := win.SetPixelFormat(backend.hdc, format_index, &pfd) assert(set_pixel_format_ok == win.TRUE, "SetPixelFormat failed") temp_context := win.wglCreateContext(backend.hdc) assert(temp_context != nil, "Failed to create temp OpenGL context") win.wglMakeCurrent(backend.hdc, temp_context) win.wglCreateContextAttribsARB = transmute(win.CreateContextAttribsARBType)win.wglGetProcAddress("wglCreateContextAttribsARB") assert(win.wglCreateContextAttribsARB != nil, "wglCreateContextAttribsARB not available") attribs := [?]i32 { win.WGL_CONTEXT_MAJOR_VERSION_ARB, OPENGL_MAJOR, win.WGL_CONTEXT_MINOR_VERSION_ARB, OPENGL_MINOR, win.WGL_CONTEXT_PROFILE_MASK_ARB, win.WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0 } backend.gl_context = win.wglCreateContextAttribsARB(backend.hdc, nil, raw_data(&attribs)) assert(backend.gl_context != nil, fmt.tprintf("Failed to create OpenGL %v.%v core context", OPENGL_MAJOR, OPENGL_MINOR)) win.wglMakeCurrent(nil, nil) win.wglDeleteContext(temp_context) win.wglMakeCurrent(backend.hdc, backend.gl_context) gl.load_up_to(3, 3, proc(p: rawptr, name: cstring) { addr := win.wglGetProcAddress(name) if addr == nil { dll := win.LoadLibraryW(win.utf8_to_wstring("opengl32.dll")) addr = win.GetProcAddress(dll, name) } (^rawptr)(p)^ = addr }) opengl_swap_buffers(renderer) return true } opengl_viewport_changed :: proc(renderer: ^Renderer) { opengl_clear_screen(renderer) gl.Viewport( i32(renderer.viewport.x), i32(renderer.viewport.y), i32(renderer.viewport.width), i32(renderer.viewport.height) ) } opengl_set_clear_color :: proc(renderer: ^Renderer, color: RGB_Color) { gl.ClearColor( f32(color.r) / f32(max(u8)), f32(color.g) / f32(max(u8)), f32(color.b) / f32(max(u8)), 1.0 ) } opengl_clear_screen :: proc(renderer: ^Renderer) { gl.Clear(gl.COLOR_BUFFER_BIT) } opengl_swap_buffers :: proc(renderer: ^Renderer) { win.SwapBuffers(backend.hdc) opengl_clear_screen(renderer) } opengl_destroy :: proc(renderer: ^Renderer) { win.wglMakeCurrent(nil, nil) win.wglDeleteContext(backend.gl_context) win.ReleaseDC(backend.hwnd, backend.hdc) backend = {} } Mesh_Backend :: Mesh_OpenGL Shader_Backend :: Shader_OpenGL Shader_Program_Backend :: Shader_Program_OpenGL Mesh_OpenGL :: struct { vbo, vao, ebo: u32, } Shader_OpenGL :: struct { handle: u32, } Shader_Program_OpenGL :: struct { handle: u32, } opengl_create_mesh :: proc(renderer: ^Renderer, vertices: []Vertex, indices: []Index) -> (Mesh_OpenGL, bool) { fmt.printfln("OPENGL: Creating mesh from vertices: %v.", vertices) m: Mesh_OpenGL gl.GenVertexArrays(1, &m.vao) gl.GenBuffers(1, &m.vbo) gl.GenBuffers(1, &m.ebo) gl.BindVertexArray(m.vao) { gl.BindBuffer(gl.ARRAY_BUFFER, m.vbo) gl.BufferData(gl.ARRAY_BUFFER, len(vertices) * size_of(Vertex), raw_data(&vertices[0]), gl.STATIC_DRAW) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, m.ebo) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices) * size_of(Index), raw_data(indices), gl.STATIC_DRAW) gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 3 * size_of(f32), 0) gl.EnableVertexAttribArray(0) } gl.BindVertexArray(0) gl.BindBuffer(gl.ARRAY_BUFFER, 0) return m, true } opengl_create_shader :: proc(renderer: ^Renderer, type: Shader_Type, data: []u8) -> (Shader_OpenGL, bool) { handle: u32 switch type { case .Vertex: { handle = gl.CreateShader(gl.VERTEX_SHADER) } case .Fragment: { handle = gl.CreateShader(gl.FRAGMENT_SHADER) } } assert(handle != 0) src := strings.clone_to_cstring(transmute(string)data, context.allocator) defer delete(src) gl.ShaderSource(handle, 1, &src, nil) gl.CompileShader(handle) success: i32 info_log: [512]u8 gl.GetShaderiv(handle, gl.COMPILE_STATUS, &success) if success != 1 { gl.GetShaderInfoLog(handle, 512, nil, raw_data(&info_log)) fmt.printfln("OPENGL: Failed to compile shader of type %v. Log: '%v'.", type, info_log) return {}, false } s: Shader_OpenGL s.handle = handle return s, true } opengl_delete_shader :: proc(renderer: ^Renderer, shader: ^Shader) { gl.DeleteShader(shader.backend.handle) } opengl_create_shader_program :: proc(renderer: ^Renderer, vertex_shader, fragment_shader: ^Shader) -> (Shader_Program_OpenGL, bool) { handle := gl.CreateProgram() gl.AttachShader(handle, vertex_shader.backend.handle) gl.AttachShader(handle, fragment_shader.backend.handle) gl.LinkProgram(handle) success: i32 info_log: [512]u8 gl.GetProgramiv(handle, gl.LINK_STATUS, &success) if success != 1 { gl.GetProgramInfoLog(handle, 512, nil, raw_data(&info_log)) fmt.printfln("OPENGL: Failed to create shader-program. Log: '%v'.", info_log) return {}, false } s: Shader_Program_OpenGL s.handle = handle return s, true } opengl_delete_shader_program :: proc(renderer: ^Renderer, shader_program: ^Shader_Program) { gl.DeleteProgram(shader_program.backend.handle) } opengl_activate_material :: proc(material: ^Material) { gl.UseProgram(material.shader_program.backend.handle) } opengl_draw_mesh :: proc(mesh: ^Mesh) { gl.BindVertexArray(mesh.backend.vao) assert(mesh.amount_of_indices < u32(max(i32))) gl.DrawElements(gl.TRIANGLES, i32(mesh.amount_of_indices), gl.UNSIGNED_INT, nil) gl.BindVertexArray(0) } }