Successfully rendered a quad!
This commit is contained in:
6
material.odin
Normal file
6
material.odin
Normal file
@@ -0,0 +1,6 @@
|
||||
package renderer
|
||||
|
||||
Material :: struct {
|
||||
shader_program: Shader_Program,
|
||||
// uniforms, textures, etc.
|
||||
}
|
||||
40
mesh.odin
Normal file
40
mesh.odin
Normal file
@@ -0,0 +1,40 @@
|
||||
package renderer
|
||||
|
||||
Mesh :: struct {
|
||||
amount_of_indices: u32,
|
||||
backend: Mesh_Backend,
|
||||
}
|
||||
|
||||
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.
|
||||
mesh: Mesh
|
||||
|
||||
if len(vertices) == 0 {
|
||||
return {}, false
|
||||
}
|
||||
if len(indices) == 0 {
|
||||
return {}, false
|
||||
}
|
||||
|
||||
m: Mesh
|
||||
m.amount_of_indices = u32(len(indices))
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_mesh, ok := opengl_create_mesh(renderer, vertices, indices)
|
||||
if !ok {
|
||||
return {}, false
|
||||
}
|
||||
m.backend = opengl_mesh
|
||||
}
|
||||
else {
|
||||
#assert(false)
|
||||
}
|
||||
|
||||
return m, true
|
||||
}
|
||||
23
pass.odin
23
pass.odin
@@ -1,6 +1,29 @@
|
||||
package renderer
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
MAX_DRAW_COMMANDS_PER_PASS :: 4096
|
||||
|
||||
Pass :: struct {
|
||||
name: string,
|
||||
clear_color: RGB_Color,
|
||||
|
||||
draw_commands: [MAX_DRAW_COMMANDS_PER_PASS]Draw_Command,
|
||||
draw_command_count: u32,
|
||||
}
|
||||
|
||||
Draw_Command :: struct {
|
||||
mesh: Mesh,
|
||||
material: Material,
|
||||
}
|
||||
|
||||
add_command_to_pass :: proc(pass: ^Pass, command: Draw_Command) -> bool {
|
||||
if pass.draw_command_count >= len(pass.draw_commands) {
|
||||
return false
|
||||
}
|
||||
|
||||
pass.draw_commands[pass.draw_command_count] = command
|
||||
pass.draw_command_count += 1
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -65,17 +65,32 @@ set_viewport :: proc(renderer: ^Renderer, x, y, width, height: u16) {
|
||||
}
|
||||
}
|
||||
|
||||
@(private="file") clear_screen :: proc(renderer: ^Renderer) { // TODO: SS - Add options here to say if you want to clear depth or not, for example.
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_clear_screen(renderer)
|
||||
}
|
||||
}
|
||||
|
||||
render_frame :: proc(renderer: ^Renderer) {
|
||||
pipeline := &renderer.pipeline
|
||||
for i in 0 ..< pipeline.amount_of_passes {
|
||||
pass := pipeline.passes[i]
|
||||
|
||||
// TODO: SS - "Activate" the pass.
|
||||
set_clear_color(renderer, pass.clear_color)
|
||||
clear_screen(renderer)
|
||||
|
||||
// TODO: SS - Loop over the pass' render-commands.
|
||||
for i in 0..<pass.draw_command_count {
|
||||
command := &pass.draw_commands[i]
|
||||
|
||||
activate_material(&command.material)
|
||||
|
||||
draw_mesh(&command.mesh)
|
||||
}
|
||||
|
||||
// TODO: SS - "Deactivate" the pass.
|
||||
|
||||
// Clear the pass' draw-commands.
|
||||
pass.draw_command_count = 0
|
||||
}
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
@@ -91,3 +106,19 @@ destroy :: proc(renderer: ^Renderer) {
|
||||
assert(renderer != nil)
|
||||
free(renderer)
|
||||
}
|
||||
|
||||
@(private) activate_material :: proc(material: ^Material) {
|
||||
assert(material != nil)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_activate_material(material)
|
||||
}
|
||||
}
|
||||
|
||||
@(private) draw_mesh :: proc(mesh: ^Mesh) {
|
||||
assert(mesh != nil)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_draw_mesh(mesh)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#+private
|
||||
package renderer
|
||||
|
||||
import "core:strings"
|
||||
import "core:fmt"
|
||||
import gl "vendor:OpenGL"
|
||||
import win "core:sys/windows"
|
||||
@@ -14,6 +16,9 @@ when RENDER_BACKEND_OPENGL {
|
||||
|
||||
backend: Backend_OpenGL_Windows
|
||||
|
||||
OPENGL_MAJOR :: 3
|
||||
OPENGL_MINOR :: 3
|
||||
|
||||
opengl_init :: proc(renderer: ^Renderer) -> bool {
|
||||
renderer.backend = &backend
|
||||
|
||||
@@ -37,11 +42,28 @@ when RENDER_BACKEND_OPENGL {
|
||||
set_pixel_format_ok := win.SetPixelFormat(backend.hdc, format_index, &pfd)
|
||||
assert(set_pixel_format_ok == win.TRUE, "SetPixelFormat failed")
|
||||
|
||||
backend.gl_context = win.wglCreateContext(backend.hdc)
|
||||
assert(backend.gl_context != nil, "Failed to create OpenGL context")
|
||||
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)
|
||||
// fmt.printfln("GL Context: %v", backend.gl_context)
|
||||
|
||||
gl.load_up_to(3, 3, proc(p: rawptr, name: cstring) {
|
||||
addr := win.wglGetProcAddress(name)
|
||||
@@ -52,14 +74,13 @@ when RENDER_BACKEND_OPENGL {
|
||||
(^rawptr)(p)^ = addr
|
||||
})
|
||||
|
||||
|
||||
opengl_swap_buffers(renderer)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
opengl_viewport_changed :: proc(renderer: ^Renderer) {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
||||
opengl_clear_screen(renderer)
|
||||
|
||||
gl.Viewport(
|
||||
i32(renderer.viewport.x),
|
||||
@@ -78,9 +99,13 @@ when RENDER_BACKEND_OPENGL {
|
||||
)
|
||||
}
|
||||
|
||||
opengl_swap_buffers :: proc(renderer: ^Renderer) {
|
||||
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) {
|
||||
@@ -90,4 +115,123 @@ when RENDER_BACKEND_OPENGL {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
81
shader.odin
Normal file
81
shader.odin
Normal file
@@ -0,0 +1,81 @@
|
||||
package renderer
|
||||
|
||||
import os "core:os/os2"
|
||||
|
||||
Shader :: struct {
|
||||
type: Shader_Type,
|
||||
backend: Shader_Backend,
|
||||
}
|
||||
|
||||
Shader_Program :: struct {
|
||||
vertex_shader, fragment_shader: Shader,
|
||||
backend: Shader_Program_Backend,
|
||||
}
|
||||
|
||||
Shader_Type :: enum {
|
||||
Vertex,
|
||||
Fragment,
|
||||
// ..
|
||||
}
|
||||
|
||||
create_shader :: proc(renderer: ^Renderer, type: Shader_Type, path: string) -> (Shader, bool) {
|
||||
bytes, error := os.read_entire_file_from_path(path, context.allocator)
|
||||
if error != nil {
|
||||
return {}, false
|
||||
}
|
||||
defer delete(bytes)
|
||||
|
||||
s: Shader
|
||||
s.type = type
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
shader_opengl, ok := opengl_create_shader(renderer, type, bytes)
|
||||
if !ok {
|
||||
return {}, false
|
||||
}
|
||||
s.backend = shader_opengl
|
||||
}
|
||||
else {
|
||||
#assert(false)
|
||||
}
|
||||
|
||||
return s, true
|
||||
}
|
||||
|
||||
delete_shader :: proc(renderer: ^Renderer, shader: ^Shader) {
|
||||
assert(shader != nil)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_delete_shader(renderer, shader)
|
||||
}
|
||||
}
|
||||
|
||||
create_shader_program :: proc(renderer: ^Renderer, vertex_shader, fragment_shader: ^Shader) -> (Shader_Program, bool) {
|
||||
assert(vertex_shader != nil)
|
||||
assert(fragment_shader != nil)
|
||||
|
||||
p: Shader_Program
|
||||
p.vertex_shader = vertex_shader^
|
||||
p.fragment_shader = fragment_shader^
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
program_opengl, ok := opengl_create_shader_program(renderer, vertex_shader, fragment_shader)
|
||||
if !ok {
|
||||
return {}, false
|
||||
}
|
||||
p.backend = program_opengl
|
||||
}
|
||||
else {
|
||||
#assert(false)
|
||||
}
|
||||
|
||||
return p, true
|
||||
}
|
||||
|
||||
delete_shader_program :: proc(renderer: ^Renderer, shader_program: ^Shader_Program) {
|
||||
assert(shader_program != nil)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_delete_shader_program(renderer, shader_program)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user