146 lines
4.0 KiB
Odin

package render
import rl "libs:raylib"
import gl "vendor:OpenGL"
MAX_VERTICES :: 4096
MAX_INDICES :: 4096
MAX_DRAWS :: 4096
Vec3 :: [3]f32
Draw_Call :: struct {
color: rl.Color,
first_index, num_indices: i32,
base_vertex: i32,
}
Immediate_Buffer :: enum {
Vertices = 0,
Indices,
}
Immediate_Draw_State :: struct {
vertices: [MAX_VERTICES]Vec3,
indices: [MAX_INDICES]u16,
draws: [MAX_DRAWS]Draw_Call,
num_vertices, num_indices, num_draws: int,
vbo_ids: [Immediate_Buffer]u32,
vao_id: u32,
}
push_mesh :: proc(ds: ^Immediate_Draw_State, vertices: []Vec3, indices: []u16, color: rl.Color) {
copy(ds.vertices[ds.num_vertices:][:len(vertices)], vertices)
copy(ds.indices[ds.num_indices:][:len(indices)], indices)
ds.draws[ds.num_draws] = {
color = color,
first_index = i32(ds.num_indices),
num_indices = i32(len(indices)),
base_vertex = i32(ds.num_vertices),
}
ds.num_vertices += len(vertices)
ds.num_indices += len(indices)
ds.num_draws += 1
}
// rudimentary batching
find_or_push_cmd :: proc(ds: ^Immediate_Draw_State, color: rl.Color) -> (cmd: ^Draw_Call) {
if ds.num_draws > 0 && ds.draws[ds.num_draws - 1].color == color {
cmd = &ds.draws[ds.num_draws - 1]
assert(i32(ds.num_indices) == cmd.first_index + cmd.num_indices)
} else {
ds.draws[ds.num_draws] = {
color = color,
first_index = i32(ds.num_indices),
num_indices = 0,
base_vertex = i32(ds.num_vertices),
}
cmd = &ds.draws[ds.num_draws]
ds.num_draws += 1
}
return
}
push_tri :: proc(ds: ^Immediate_Draw_State, v1, v2, v3: Vec3, color: rl.Color) {
draw := find_or_push_cmd(ds, color)
ds.vertices[ds.num_vertices + 0] = v1
ds.vertices[ds.num_vertices + 1] = v2
ds.vertices[ds.num_vertices + 2] = v3
ds.indices[ds.num_indices + 0] = u16(ds.num_vertices + 0)
ds.indices[ds.num_indices + 1] = u16(ds.num_vertices + 1)
ds.indices[ds.num_indices + 2] = u16(ds.num_vertices + 2)
ds.num_vertices += 3
ds.num_indices += 3
draw.num_indices += 3
}
push_quad :: proc(ds: ^Immediate_Draw_State, v1, v2, v3, v4: Vec3, color: rl.Color) {
push_tri(ds, v1, v2, v3, color)
push_tri(ds, v1, v3, v4, color)
}
draw_batch :: proc(ds: ^Immediate_Draw_State) {
if ds.vbo_ids == {} {
gl.GenBuffers(len(ds.vbo_ids), &ds.vbo_ids[.Vertices])
gl.GenVertexArrays(1, &ds.vao_id)
gl.BindVertexArray(ds.vao_id)
gl.EnableVertexAttribArray(u32(rl.ShaderLocationIndex.VERTEX_POSITION))
gl.BindBuffer(gl.ARRAY_BUFFER, ds.vbo_ids[.Vertices])
gl.VertexAttribPointer(
u32(rl.ShaderLocationIndex.VERTEX_POSITION),
3,
gl.FLOAT,
false,
0,
0,
)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ds.vbo_ids[.Indices])
} else {
gl.BindVertexArray(ds.vao_id)
}
gl.BindVertexArray(0)
defer gl.BindBuffer(gl.ARRAY_BUFFER, 0)
gl.BufferData(gl.ARRAY_BUFFER, MAX_VERTICES * size_of(Vec3), nil, gl.STREAM_DRAW)
gl.BufferSubData(gl.ARRAY_BUFFER, 0, ds.num_vertices * size_of(Vec3), raw_data(ds.vertices[:]))
gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, 0)
gl.EnableVertexAttribArray(0)
defer gl.DisableVertexAttribArray(0)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ds.vbo_ids[.Indices])
defer gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, MAX_INDICES * size_of(u16), nil, gl.STREAM_DRAW)
gl.BufferSubData(
gl.ELEMENT_ARRAY_BUFFER,
0,
ds.num_indices * size_of(u16),
raw_data(ds.indices[:]),
)
shader := rl.LoadMaterialDefault().shader
rl.BeginShaderMode(shader)
defer rl.EndShaderMode()
for draw in ds.draws[:ds.num_draws] {
color: [4]f32 = {
f32(draw.color.r) / 255.0,
f32(draw.color.g) / 255.0,
f32(draw.color.b) / 255.0,
f32(draw.color.a) / 255.0,
}
gl.Uniform4fv(shader.locs[rl.ShaderLocationIndex.COLOR_DIFFUSE], 1, raw_data(color[:]))
gl.DrawElementsBaseVertex(
gl.TRIANGLES,
i32(ds.num_indices / 3),
gl.UNSIGNED_SHORT,
rawptr(uintptr(draw.first_index) * size_of(u16)),
draw.base_vertex,
)
}
}