From d987f31769f28ca7cd96a1765e9fb239e5bfd7d0 Mon Sep 17 00:00:00 2001 From: samstalhandske Date: Tue, 25 Nov 2025 19:15:18 +0100 Subject: [PATCH] Textured quad. --- material.odin | 1 + mesh.odin | 5 +- pass.odin | 2 +- pipeline.odin | 2 +- renderer_backend_opengl_windows.odin | 97 ++++++++++++++++++++++++++-- texture.odin | 54 ++++++++++++++++ 6 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 texture.odin diff --git a/material.odin b/material.odin index d1d905b..faa8e71 100644 --- a/material.odin +++ b/material.odin @@ -2,5 +2,6 @@ package renderer Material :: struct { shader_program: Shader_Program, + texture: Texture, // Diffuse, normal etc later. // uniforms, textures, etc. } \ No newline at end of file diff --git a/mesh.odin b/mesh.odin index dcb64ce..b309b22 100644 --- a/mesh.odin +++ b/mesh.odin @@ -8,11 +8,8 @@ Mesh :: struct { Mesh_Handle :: distinct u32 Buffer_Handle :: distinct u32 -Vertex :: distinct [3]f32 -Index :: distinct u32 - -create_mesh :: proc(renderer: ^Renderer, vertices: []Vertex, indices: []Index) -> (Mesh, bool) { // TODO: SS - Should probably return a Mesh_Handle. +create_mesh :: proc(renderer: ^Renderer, vertices: []f32, indices: []u32) -> (Mesh, bool) { // TODO: SS - Should probably return a Mesh_Handle. mesh: Mesh if len(vertices) == 0 { diff --git a/pass.odin b/pass.odin index 51221ca..6d534e6 100644 --- a/pass.odin +++ b/pass.odin @@ -2,7 +2,7 @@ package renderer import "core:fmt" -MAX_DRAW_COMMANDS_PER_PASS :: 4096 +MAX_DRAW_COMMANDS_PER_PASS :: 1024 Pass :: struct { name: string, diff --git a/pipeline.odin b/pipeline.odin index c58f3f4..7f1b67d 100644 --- a/pipeline.odin +++ b/pipeline.odin @@ -41,7 +41,7 @@ set_pipeline :: proc(renderer: ^Renderer, passes: []^Pass) { pipeline.passes[pipeline.amount_of_passes] = pass pipeline.amount_of_passes += 1 - log.infof("Successfully added pass '%v' to pipeline.", pass.name) + // log.infof("Successfully added pass '%v' to pipeline.", pass.name) return true } \ No newline at end of file diff --git a/renderer_backend_opengl_windows.odin b/renderer_backend_opengl_windows.odin index 07a4f5f..dd97603 100644 --- a/renderer_backend_opengl_windows.odin +++ b/renderer_backend_opengl_windows.odin @@ -1,6 +1,9 @@ #+private package renderer +import "core:bytes" +import "core:slice" +import "core:image" import "core:strings" import "core:fmt" import gl "vendor:OpenGL" @@ -119,6 +122,7 @@ when RENDER_BACKEND_OPENGL { Mesh_Backend :: Mesh_OpenGL Shader_Backend :: Shader_OpenGL Shader_Program_Backend :: Shader_Program_OpenGL + Texture_Backend :: Texture_OpenGL Mesh_OpenGL :: struct { vbo, vao, ebo: u32, @@ -132,8 +136,12 @@ when RENDER_BACKEND_OPENGL { handle: u32, } - opengl_create_mesh :: proc(renderer: ^Renderer, vertices: []Vertex, indices: []Index) -> (Mesh_OpenGL, bool) { - fmt.printfln("OPENGL: Creating mesh from vertices: %v.", vertices) + Texture_OpenGL :: struct { + handle: u32, + } + + opengl_create_mesh :: proc(renderer: ^Renderer, vertices: []f32, indices: []u32) -> (Mesh_OpenGL, bool) { + // fmt.printfln("OPENGL: Creating mesh from vertices: %v.", vertices) m: Mesh_OpenGL @@ -144,13 +152,19 @@ when RENDER_BACKEND_OPENGL { 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.BufferData(gl.ARRAY_BUFFER, len(vertices) * size_of(f32), raw_data(vertices), 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.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices) * size_of(u32), raw_data(indices), gl.STATIC_DRAW) - gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 3 * size_of(f32), 0) + gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 8 * size_of(f32), uintptr(0)) gl.EnableVertexAttribArray(0) + + gl.VertexAttribPointer(1, 3, gl.FLOAT, gl.FALSE, 8 * size_of(f32), uintptr(3 * size_of(f32))) + gl.EnableVertexAttribArray(1) + + gl.VertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 8 * size_of(f32), uintptr(6 * size_of(f32))) + gl.EnableVertexAttribArray(2) } gl.BindVertexArray(0) @@ -226,12 +240,83 @@ when RENDER_BACKEND_OPENGL { opengl_activate_material :: proc(material: ^Material) { gl.UseProgram(material.shader_program.backend.handle) + + gl.ActiveTexture(gl.TEXTURE0) + gl.BindTexture(gl.TEXTURE_2D, material.texture.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) + } + + opengl_load_texture :: proc(renderer: ^Renderer, t: ^Texture, pixels: rawptr) -> bool { + handle: u32 + gl.GenTextures(1, &handle) + gl.BindTexture(gl.TEXTURE_2D, handle) + + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + type := gl.UNSIGNED_BYTE + switch t.depth { + case 8: type = gl.UNSIGNED_BYTE + case 16: type = gl.UNSIGNED_SHORT + case 32: type = gl.UNSIGNED_INT + } + + format := gl.RGBA + switch t.channels { + case 1: format = gl.RED + case 2: format = gl.RG + case 3: format = gl.RGB + case 4: format = gl.RGBA + } + + internal := gl.RGBA8 + + if t.depth == 8 { + switch t.channels { + case 1: internal = gl.R8 + case 2: internal = gl.RG8 + case 3: internal = gl.RGB8 + case 4: internal = gl.RGBA8 + } + } else if t.depth == 16 { + switch t.channels { + case 1: internal = gl.R16 + case 2: internal = gl.RG16 + case 3: internal = gl.RGB16 + case 4: internal = gl.RGBA16 + } + } + + // bytes.reverse(bytes.buffer_to_bytes(img.pixels)) + + gl.TexImage2D( + target = gl.TEXTURE_2D, + level = 0, + internalformat = i32(internal), + width = i32(t.width), + height = i32(t.height), + border = 0, + format = u32(format), + type = u32(type), + pixels = pixels, + // pixels = &pixels[0] + // pixels = &bytes.reverse(bytes.buffer_to_bytes(&img.pixels))[0] + ) + + gl.GenerateMipmap(gl.TEXTURE_2D) + + t.backend = Texture_OpenGL { handle = handle } + return true + } + + opengl_delete_texture :: proc(renderer: ^Renderer, t: ^Texture) { + } } \ No newline at end of file diff --git a/texture.odin b/texture.odin new file mode 100644 index 0000000..a3ff4c3 --- /dev/null +++ b/texture.odin @@ -0,0 +1,54 @@ +package renderer + +import "core:strings" +import "core:c" +import "vendor:stb/image" +import "core:fmt" + +Texture :: struct { + width, height, channels, depth: u32, + backend: Texture_Backend, +} + +create_texture :: proc { + create_texture_from_path, +} + +create_texture_from_path :: proc(renderer: ^Renderer, path: string) -> (Texture, bool) { + width, height, depth, channels: c.int + + path_cstr := strings.clone_to_cstring(path) + defer delete(path_cstr) + image.set_flip_vertically_on_load(1) // NOTE: SS - This should not necessarily happen on all graphics-apis. + data := image.load(path_cstr, &width, &height, &channels, desired_channels = 0) + if data == nil { + return {}, false + } + depth = 8 + + t: Texture + t.width = u32(width) + t.height = u32(height) + t.channels = u32(channels) + t.depth = u32(depth) + + when RENDER_BACKEND_OPENGL { + if !opengl_load_texture(renderer, &t, data) { + return {}, false + } + } + else { + #assert(false) + } + + return t, true +} + +delete_texture :: proc(renderer: ^Renderer, texture: ^Texture) { + when RENDER_BACKEND_OPENGL { + opengl_delete_texture(renderer, texture) + } + else { + #assert(false) + } +} \ No newline at end of file