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
|
package renderer
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
MAX_DRAW_COMMANDS_PER_PASS :: 4096
|
||||||
|
|
||||||
Pass :: struct {
|
Pass :: struct {
|
||||||
name: string,
|
name: string,
|
||||||
clear_color: RGB_Color,
|
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) {
|
render_frame :: proc(renderer: ^Renderer) {
|
||||||
pipeline := &renderer.pipeline
|
pipeline := &renderer.pipeline
|
||||||
for i in 0 ..< pipeline.amount_of_passes {
|
for i in 0 ..< pipeline.amount_of_passes {
|
||||||
pass := pipeline.passes[i]
|
pass := pipeline.passes[i]
|
||||||
|
|
||||||
// TODO: SS - "Activate" the pass.
|
|
||||||
set_clear_color(renderer, pass.clear_color)
|
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.
|
// TODO: SS - "Deactivate" the pass.
|
||||||
|
|
||||||
|
// Clear the pass' draw-commands.
|
||||||
|
pass.draw_command_count = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
when RENDER_BACKEND_OPENGL {
|
when RENDER_BACKEND_OPENGL {
|
||||||
@@ -91,3 +106,19 @@ destroy :: proc(renderer: ^Renderer) {
|
|||||||
assert(renderer != nil)
|
assert(renderer != nil)
|
||||||
free(renderer)
|
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
|
package renderer
|
||||||
|
|
||||||
|
import "core:strings"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import gl "vendor:OpenGL"
|
import gl "vendor:OpenGL"
|
||||||
import win "core:sys/windows"
|
import win "core:sys/windows"
|
||||||
@@ -14,6 +16,9 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
|
|
||||||
backend: Backend_OpenGL_Windows
|
backend: Backend_OpenGL_Windows
|
||||||
|
|
||||||
|
OPENGL_MAJOR :: 3
|
||||||
|
OPENGL_MINOR :: 3
|
||||||
|
|
||||||
opengl_init :: proc(renderer: ^Renderer) -> bool {
|
opengl_init :: proc(renderer: ^Renderer) -> bool {
|
||||||
renderer.backend = &backend
|
renderer.backend = &backend
|
||||||
|
|
||||||
@@ -37,11 +42,28 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
set_pixel_format_ok := win.SetPixelFormat(backend.hdc, format_index, &pfd)
|
set_pixel_format_ok := win.SetPixelFormat(backend.hdc, format_index, &pfd)
|
||||||
assert(set_pixel_format_ok == win.TRUE, "SetPixelFormat failed")
|
assert(set_pixel_format_ok == win.TRUE, "SetPixelFormat failed")
|
||||||
|
|
||||||
backend.gl_context = win.wglCreateContext(backend.hdc)
|
temp_context := win.wglCreateContext(backend.hdc)
|
||||||
assert(backend.gl_context != nil, "Failed to create OpenGL context")
|
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)
|
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) {
|
gl.load_up_to(3, 3, proc(p: rawptr, name: cstring) {
|
||||||
addr := win.wglGetProcAddress(name)
|
addr := win.wglGetProcAddress(name)
|
||||||
@@ -52,14 +74,13 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
(^rawptr)(p)^ = addr
|
(^rawptr)(p)^ = addr
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
opengl_swap_buffers(renderer)
|
opengl_swap_buffers(renderer)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
opengl_viewport_changed :: proc(renderer: ^Renderer) {
|
opengl_viewport_changed :: proc(renderer: ^Renderer) {
|
||||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
opengl_clear_screen(renderer)
|
||||||
|
|
||||||
gl.Viewport(
|
gl.Viewport(
|
||||||
i32(renderer.viewport.x),
|
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)
|
gl.Clear(gl.COLOR_BUFFER_BIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
opengl_swap_buffers :: proc(renderer: ^Renderer) {
|
||||||
win.SwapBuffers(backend.hdc)
|
win.SwapBuffers(backend.hdc)
|
||||||
|
opengl_clear_screen(renderer)
|
||||||
}
|
}
|
||||||
|
|
||||||
opengl_destroy :: proc(renderer: ^Renderer) {
|
opengl_destroy :: proc(renderer: ^Renderer) {
|
||||||
@@ -90,4 +115,123 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
|
|
||||||
backend = {}
|
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