1
Fork 0

odin(sdl-opengl-rendering): circle rendering & half-broken transparency

This commit is contained in:
prescientmoon 2025-04-02 00:32:05 +02:00
parent b3aad17877
commit 7a2c5c141b
Signed by: prescientmoon
SSH key fingerprint: SHA256:UUF9JT2s8Xfyv76b8ZuVL7XrmimH4o49p4b+iexbVH4
2 changed files with 115 additions and 28 deletions
odin/sdl-opengl-rendering/src

View file

@ -9,13 +9,15 @@ import "vendor:OpenGL"
import "vendor:sdl3"
State :: struct {
tick: u32,
window: ^sdl3.Window,
program: u32,
rect_vao: VAO,
wireframe: bool,
tick: u32,
window: ^sdl3.Window,
program: u32,
rect_vao: VAO,
circle_vao: VAO,
wireframe: bool,
}
// {{{ Initialization
init :: proc() -> (state: State, ok: bool) {
GL_MAJOR :: 3
GL_MINOR :: 3
@ -93,6 +95,8 @@ init :: proc() -> (state: State, ok: bool) {
OpenGL.load_up_to(GL_MAJOR, GL_MINOR, sdl3.gl_set_proc_address)
OpenGL.ClearColor(0, 0, 0, 1)
OpenGL.Enable(OpenGL.DEPTH_TEST)
OpenGL.Enable(OpenGL.BLEND)
OpenGL.BlendFunc(OpenGL.SRC_ALPHA, OpenGL.ONE_MINUS_SRC_ALPHA)
state.program = OpenGL.load_shaders_source(
#load("./vert.glsl"),
@ -101,11 +105,35 @@ init :: proc() -> (state: State, ok: bool) {
state.rect_vao = create_vao({{-1, -1}, {1, -1}, {1, 1}, {-1, 1}}, {0, 1, 2, 3}) or_return
CIRCLE_POINTS :: 127
circle_vertices: [CIRCLE_POINTS + 1]²
circle_indices: [CIRCLE_POINTS + 2]u32
for i in 0 ..< CIRCLE_POINTS {
θ := (i) * 2 * math.π / CIRCLE_POINTS
circle_vertices[i + 1] = {math.cos(θ), math.sin(θ)}
circle_indices[i + 1] = u32(i + 1)
}
circle_indices[CIRCLE_POINTS + 1] = circle_indices[1]
state.circle_vao = create_vao(circle_vertices[:], circle_indices[:]) or_return
init_command_queue()
return state, true
}
// }}}
// {{{ Close
close :: proc(state: State) {
OpenGL.DeleteProgram(state.program)
_ = sdl3.StopTextInput(state.window)
sdl3.DestroyWindow(state.window)
sdl3.Quit()
}
// }}}
// {{{ Render
render :: proc(state: ^State) {
state.tick += 1
OpenGL.Clear(OpenGL.COLOR_BUFFER_BIT | OpenGL.DEPTH_BUFFER_BIT)
@ -131,20 +159,22 @@ render :: proc(state: ^State) {
2 /
(count) -
1
draw_rect(Rect{pos, 1 / (count), 0, {(pos.x + 1) / 2, (pos.y + 1) / 2, 1, 1}})
color := Color{(pos.x + 1) / 2, (pos.y + 1) / 2, 1, 1}
if x > y {
draw_rect(pos, 1 / (count), color)
} else {
r := 1 / (count) / 2
draw_circle(pos + r, r, color)
}
}
}
draw_circle({-0.25, -0.3}, 0.6, Color{0, 0, 0.5, 0.75}, z = -0.1)
render_queue(state)
}
close :: proc(state: State) {
OpenGL.DeleteProgram(state.program)
_ = sdl3.StopTextInput(state.window)
sdl3.DestroyWindow(state.window)
sdl3.Quit()
}
// }}}
// {{{ Main
main :: proc() {
log.Level_Headers = {
0 ..< 10 = "[DEBUG] ",
@ -186,3 +216,4 @@ main :: proc() {
free_all(context.temp_allocator)
}
}
// }}}

View file

@ -12,25 +12,25 @@ Mat3 :: matrix[3, 3]
Color :: [4]
// }}}
// {{{ Command queues
Shape :: struct {
z: ,
fill: Color,
}
Rect :: struct {
top_left: ²,
dimensions: ²,
z: ,
fill: Color,
using shape: Shape,
top_left: ²,
dimensions: ²,
}
Circle :: struct {
center: ²,
radius: ,
}
Shape :: union {
Rect,
Circle,
using shape: Shape,
center: ²,
radius: ,
}
Command_Queue :: struct {
rects: [dynamic]Rect,
rects: [dynamic]Rect,
circles: [dynamic]Circle,
}
queue: ^Command_Queue
@ -43,7 +43,9 @@ init_command_queue :: proc() {
}
draw_rect_args :: proc(top_left: ², dimensions: ², color: Color, z: = 0) {
draw_rect_struct(Rect{top_left, dimensions, z, color})
draw_rect_struct(
Rect{top_left = top_left, dimensions = dimensions, shape = Shape{z = z, fill = color}},
)
}
draw_rect_struct :: proc(rect: Rect) {
@ -51,10 +53,24 @@ draw_rect_struct :: proc(rect: Rect) {
}
draw_rect :: proc {
draw_rect_args,
draw_rect_struct,
draw_rect_args,
}
draw_circle_args :: proc(center: ², radius: , color: Color, z: = 0) {
draw_circle_struct(
Circle{center = center, radius = radius, shape = Shape{z = z, fill = color}},
)
}
draw_circle_struct :: proc(circle: Circle) {
append(&queue.circles, circle)
}
draw_circle :: proc {
draw_circle_struct,
draw_circle_args,
}
// }}}
// {{{ VAO & consts
@ -167,6 +183,36 @@ set_rect_transforms :: proc(vao: ^VAO, rects: []Rect) -> {
return len(rects)
}
set_circle_transforms :: proc(vao: ^VAO, circles: []Circle) -> {
log.assert(len(circles) <= INSTANCES, "Attempting to send too many circles to the GPU")
matrices := new([INSTANCES]Mat3, context.temp_allocator)
fills := new([INSTANCES]Color, context.temp_allocator)
for circle, i in circles {
mat: Mat3
mat[0, 0] = circle.radius
mat[1, 1] = circle.radius
mat[2].xy = circle.center.xy
mat[2].z = circle.z
matrices[i] = mat
fills[i] = circle.fill
}
OpenGL.BindBuffer(OpenGL.ARRAY_BUFFER, vao.instance_mat_buffer)
OpenGL.BufferData(
OpenGL.ARRAY_BUFFER,
INSTANCES * size_of(Mat3),
matrices,
OpenGL.DYNAMIC_DRAW,
)
OpenGL.BindBuffer(OpenGL.ARRAY_BUFFER, vao.instance_fill_buffer)
OpenGL.BufferData(OpenGL.ARRAY_BUFFER, INSTANCES * size_of(Color), fills, OpenGL.DYNAMIC_DRAW)
return len(circles)
}
// }}}
// {{{ Render the entire queue
draw_instances :: proc(vao: VAO, instances: ) {
@ -191,5 +237,15 @@ render_queue :: proc(state: ^State) {
}
clear(&queue.rects)
circle_steps := len(queue.circles) / INSTANCES
for i := 0; i < len(queue.circles); i += INSTANCES {
slice := queue.circles[i:]
if len(slice) > INSTANCES {slice = slice[:INSTANCES]}
instances := set_circle_transforms(&state.circle_vao, slice)
draw_instances(state.circle_vao, instances)
}
clear(&queue.circles)
}
// }}}