odin(sdl-opengl-rendering): circle rendering & half-broken transparency
This commit is contained in:
		
					parent
					
						
							
								b3aad17877
							
						
					
				
			
			
				commit
				
					
						7a2c5c141b
					
				
			
		
					 2 changed files with 115 additions and 28 deletions
				
			
		odin/sdl-opengl-rendering/src
|  | @ -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) | ||||
| 	} | ||||
| } | ||||
| // }}} | ||||
|  |  | |||
|  | @ -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) | ||||
| } | ||||
| // }}} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue