aboutsummaryrefslogtreecommitdiff
path: root/src/fw/opengl.odin
diff options
context:
space:
mode:
Diffstat (limited to 'src/fw/opengl.odin')
-rw-r--r--src/fw/opengl.odin363
1 files changed, 363 insertions, 0 deletions
diff --git a/src/fw/opengl.odin b/src/fw/opengl.odin
new file mode 100644
index 0000000..ab2bb81
--- /dev/null
+++ b/src/fw/opengl.odin
@@ -0,0 +1,363 @@
+package fw
+
+import "base:runtime"
+
+import "core:log"
+import "core:fmt"
+import "core:math/linalg"
+import "core:os"
+
+import "vendor:glfw"
+import gl "vendor:OpenGL"
+
+@(private)
+enum_conv: map[All_Enums]u32
+
+vert_shader_src := string(#load("shader.vert"))
+frag_shader_src := string(#load("shader.frag"))
+
+vao: u32
+vbo: u32
+ebo: u32
+
+framebuf: struct {
+ handle: u32,
+ color: Texture, // so we can reuse pre-existing draw procs
+ depth: u32,
+}
+shader_program: u32
+
+projection_loc: i32
+view_loc: i32
+tex0_loc: i32
+
+// @(private)
+// _gl_debug_message :: proc "c" (
+// source: u32,
+// type: u32,
+// id: u32,
+// severity: u32,
+// length: i32,
+// message: cstring,
+// userParam: rawptr,
+// ) {
+// context = runtime.default_context()
+// switch severity {
+// case gl.DEBUG_SEVERITY_HIGH: fmt.print("[HIGH]")
+// case gl.DEBUG_SEVERITY_MEDIUM: fmt.print("[MEDIUM]")
+// case gl.DEBUG_SEVERITY_LOW: fmt.print("[LOW]")
+// case gl.DEBUG_SEVERITY_NOTIFICATION: fmt.print("[NOTIF]")
+// }
+// fmt.printfln(" OpenGL %v: %v", id, message)
+// }
+
+@(private)
+_init_vertex_buffer_and_array :: proc(vao: u32, vbo: u32, ebo: u32) {
+ gl.BindVertexArray(vao)
+
+ gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
+ gl.BufferData(gl.ARRAY_BUFFER, 0, nil, gl.DYNAMIC_DRAW)
+
+ gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo)
+ gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, 0, nil, gl.DYNAMIC_DRAW)
+
+ stride := i32(size_of(Vertex))
+
+ gl.EnableVertexAttribArray(0)
+ gl.VertexAttribPointer(0, 3, gl.FLOAT, false, stride, offset_of(Vertex, pos))
+
+ gl.EnableVertexAttribArray(1)
+ gl.VertexAttribPointer(1, 2, gl.FLOAT, false, stride, offset_of(Vertex, uv))
+
+ gl.EnableVertexAttribArray(2)
+ gl.VertexAttribPointer(
+ 2,
+ 4,
+ gl.FLOAT,
+ false,
+ stride,
+ offset_of(Vertex, color),
+ )
+}
+
+@(private)
+_gl_load_shader :: proc(src: string, type: u32) -> u32 {
+ shader := gl.CreateShader(type)
+ csrc := cstring(raw_data(src))
+ src_len := i32(len(src))
+ gl.ShaderSource(shader, 1, &csrc, &src_len)
+ gl.CompileShader(shader)
+
+ status: i32
+ gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
+ if status == 0 {
+ gl.DeleteShader(shader)
+ return 0
+ }
+
+ return shader
+}
+
+@(private)
+_gl_load_shader_program :: proc(vert_src: string, frag_src: string) -> u32 {
+ vert_shader := _gl_load_shader(vert_src, gl.VERTEX_SHADER)
+ defer gl.DeleteShader(vert_shader)
+ frag_shader := _gl_load_shader(frag_src, gl.FRAGMENT_SHADER)
+ defer gl.DeleteShader(frag_shader)
+
+ program := gl.CreateProgram()
+ gl.AttachShader(program, vert_shader)
+ gl.AttachShader(program, frag_shader)
+ gl.LinkProgram(program)
+
+ status: i32
+ gl.GetProgramiv(program, gl.LINK_STATUS, &status)
+ if status == 0 {
+ gl.DeleteProgram(program)
+ return 0
+ }
+
+ return program
+}
+
+gl_init :: proc() {
+ glfw.MakeContextCurrent(window)
+
+ gl.load_up_to(3, 3, glfw.gl_set_proc_address)
+
+ gl.Enable(gl.DEPTH_TEST)
+ gl.DepthFunc(gl.LEQUAL)
+
+ // gl.Enable(gl.BLEND);
+ // gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+ renderer.vt.start_frame = gl_start_frame
+ renderer.vt.end_frame = gl_end_frame
+ renderer.vt.draw = gl_draw
+ renderer.vt.clear = gl_clear
+ renderer.vt.init_texture = gl_init_texture
+ renderer.vt.destroy_texture = gl_destroy_texture
+ renderer.vt.init_screen = gl_init_screen
+
+ enum_conv[Vertex_Mode.None] = gl.TRIANGLES
+ enum_conv[Vertex_Mode.Triangles] = gl.TRIANGLES
+ enum_conv[Vertex_Mode.Triangle_Fan] = gl.TRIANGLE_FAN
+ enum_conv[Vertex_Mode.Triangle_Strip] = gl.TRIANGLE_STRIP
+ enum_conv[Vertex_Mode.Lines] = gl.LINES
+ enum_conv[Vertex_Mode.Line_Strip] = gl.LINE_STRIP
+ enum_conv[Vertex_Mode.Line_Loop] = gl.LINE_LOOP
+ enum_conv[Vertex_Mode.Points] = gl.POINTS
+
+ gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1);
+
+ gl.GenBuffers(1, &vbo)
+ gl.GenBuffers(1, &ebo)
+ gl.GenVertexArrays(1, &vao)
+ _init_vertex_buffer_and_array(vao, vbo, ebo)
+
+ shader_program = _gl_load_shader_program(vert_shader_src, frag_shader_src)
+ projection_loc = gl.GetUniformLocation(shader_program, "projection")
+ view_loc = gl.GetUniformLocation(shader_program, "view")
+ tex0_loc = gl.GetUniformLocation(shader_program, "tex0")
+}
+
+gl_deinit :: proc() {
+ delete(enum_conv)
+
+ destroy_texture(framebuf.color)
+ gl.DeleteRenderbuffers(1, &framebuf.depth)
+ gl.DeleteFramebuffers(1, &framebuf.handle)
+
+ gl.DeleteProgram(shader_program)
+
+ gl.DeleteBuffers(1, &vbo)
+ gl.DeleteVertexArrays(1, &vao)
+}
+
+gl_start_frame :: proc() {
+ gl.BindFramebuffer(gl.FRAMEBUFFER, framebuf.handle)
+ gl.Viewport(0, 0, framebuf.color.size.x, framebuf.color.size.y)
+ renderer.projection = linalg.matrix_ortho3d(
+ f32(0), f32(framebuf.color.size.x),
+ f32(framebuf.color.size.y), 0,
+ -1, 1,
+ )
+}
+
+gl_end_frame :: proc() {
+ gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
+
+ w_width, w_height := glfw.GetWindowSize(window)
+
+ gl.Viewport(0, 0, w_width, w_height)
+
+ renderer.projection = linalg.matrix_ortho3d(
+ f32(0), f32(w_width),
+ 0, f32(w_height),
+ -1, 1,
+ )
+
+ draw_rect({0, 0}, {f32(w_width), f32(w_height)}, tex = framebuf.color)
+ flush_batch(&renderer.draw_call)
+}
+
+gl_draw :: proc(draw_call: Draw_Call) {
+ draw_call := draw_call
+
+ gl.UseProgram(shader_program)
+
+ gl.ActiveTexture(gl.TEXTURE0)
+ gl.BindTexture(gl.TEXTURE_2D, draw_call.tex)
+
+ gl.Uniform1i(tex0_loc, 0)
+ gl.UniformMatrix4fv(
+ projection_loc,
+ 1,
+ false,
+ transmute([^]f32)(&draw_call.projection),
+ )
+ gl.UniformMatrix4fv(view_loc, 1, false, transmute([^]f32)(&draw_call.view))
+
+ gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
+ gl.BufferData(
+ gl.ARRAY_BUFFER,
+ size_of(Vertex) * len(draw_call.vertices),
+ raw_data(draw_call.vertices),
+ gl.DYNAMIC_DRAW,
+ )
+
+ gl.BindVertexArray(vao)
+
+ if !draw_call.indexed {
+ gl.DrawArrays(
+ enum_conv[draw_call.vertex_mode],
+ 0,
+ i32(len(draw_call.vertices)),
+ )
+ } else {
+ gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo)
+ gl.BufferData(
+ gl.ELEMENT_ARRAY_BUFFER,
+ size_of(Index) * len(draw_call.indices),
+ raw_data(draw_call.indices),
+ gl.DYNAMIC_DRAW,
+ )
+
+ gl.DrawElements(
+ enum_conv[draw_call.vertex_mode],
+ i32(len(draw_call.indices)),
+ gl.UNSIGNED_SHORT,
+ nil,
+ )
+ gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
+ }
+
+ gl.BindBuffer(gl.ARRAY_BUFFER, 0)
+ gl.BindVertexArray(0)
+}
+
+gl_clear :: proc(col: Color) {
+ gl.ClearColor(col.r, col.g, col.b, col.a)
+ gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
+}
+
+gl_init_texture :: proc(
+ texture: ^Texture,
+ data: []u8,
+ channels: i32,
+) {
+ tex: u32
+ gl.GenTextures(1, &tex)
+
+ format := gl.RGBA
+ switch channels {
+ case 3: format = gl.RGB
+ case 4: format = gl.RGBA
+ case: panic("Unsupported amount of channels. Must be either 3 or 4.")
+ }
+
+ gl.BindTexture(gl.TEXTURE_2D, tex)
+ gl.TexImage2D(
+ gl.TEXTURE_2D,
+ 0,
+ i32(format),
+ texture.size.x,
+ texture.size.y,
+ 0,
+ u32(format),
+ gl.UNSIGNED_BYTE,
+ raw_data(data),
+ )
+
+ gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
+ gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
+
+ gl.GenerateMipmap(gl.TEXTURE_2D)
+
+ texture.handle = tex
+}
+
+gl_destroy_texture :: proc(texture: Texture_Handle) {
+ texture := texture
+ gl.DeleteTextures(1, &texture)
+}
+
+gl_init_screen :: proc(screen_size: Vec2i) {
+ assert(screen_size.x * screen_size.y > 0)
+
+ gl.GenFramebuffers(1, &framebuf.handle)
+ gl.BindFramebuffer(gl.FRAMEBUFFER, framebuf.handle)
+
+ color_tex: u32
+ gl.GenTextures(1, &color_tex)
+ gl.BindTexture(gl.TEXTURE_2D, color_tex)
+
+ gl.TexImage2D(
+ gl.TEXTURE_2D,
+ 0,
+ gl.RGB,
+ screen_size.x,
+ screen_size.y,
+ 0,
+ gl.RGB,
+ gl.UNSIGNED_BYTE,
+ nil,
+ )
+ gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
+ gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
+
+ gl.FramebufferTexture2D(
+ gl.FRAMEBUFFER,
+ gl.COLOR_ATTACHMENT0,
+ gl.TEXTURE_2D,
+ color_tex,
+ 0,
+ )
+
+ framebuf.color = Texture {
+ handle = color_tex,
+ size = screen_size,
+ }
+
+ gl.GenRenderbuffers(1, &framebuf.depth)
+ gl.BindRenderbuffer(gl.RENDERBUFFER, framebuf.depth)
+ gl.RenderbufferStorage(
+ gl.RENDERBUFFER,
+ gl.DEPTH_COMPONENT32F,
+ screen_size.x,
+ screen_size.y,
+ );
+ gl.FramebufferRenderbuffer(
+ gl.FRAMEBUFFER,
+ gl.DEPTH_ATTACHMENT,
+ gl.RENDERBUFFER,
+ framebuf.depth,
+ );
+
+ if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE {
+ log.fatal("[OPENGL] Framebuffer could not be completed")
+ os.exit(1)
+ }
+
+ gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
+}