odin(sdl-opengl-rendering): tinker with instancing
This commit is contained in:
parent
f98d2a6baa
commit
b3aad17877
odin/sdl-opengl-rendering
|
@ -46,11 +46,19 @@
|
|||
system:
|
||||
let
|
||||
pkgs = inputs.nixpkgs.legacyPackages.${system}.extend inputs.self.overlays.default;
|
||||
raylib = pkgs.raylib.override { platform = "SDL"; };
|
||||
cross = import inputs.nixpkgs {
|
||||
localSystem = system;
|
||||
crossSystem.config = "x86_64-w64-mingw32";
|
||||
};
|
||||
|
||||
inherit (pkgs) lib;
|
||||
in
|
||||
{
|
||||
packages = { inherit (pkgs) odin; };
|
||||
packages = {
|
||||
inherit (pkgs) odin;
|
||||
gcc = cross.callPackage (import ./gcc.nix) { };
|
||||
libgl = cross.libGL;
|
||||
};
|
||||
|
||||
# {{{ Shell
|
||||
devShell = pkgs.mkShell rec {
|
||||
|
@ -65,18 +73,19 @@
|
|||
pkgs.gdb # Debugger
|
||||
pkgs.seer # Debugger GUI
|
||||
pkgs.valgrind # Detect memory leaks
|
||||
pkgs.renderdoc # Graphics debugger
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
# pkgs.libGL
|
||||
# pkgs.libxkbcommon
|
||||
# pkgs.xorg.libXi
|
||||
# pkgs.xorg.libX11
|
||||
# pkgs.xorg.libXrandr
|
||||
# pkgs.xorg.libXinerama
|
||||
# pkgs.xorg.libXcursor
|
||||
# pkgs.wayland
|
||||
pkgs.sdl3
|
||||
|
||||
pkgs.xorg.libX11
|
||||
pkgs.xorg.libXScrnSaver
|
||||
pkgs.xorg.libXcursor
|
||||
pkgs.xorg.libXext
|
||||
pkgs.xorg.libXfixes
|
||||
pkgs.xorg.libXi
|
||||
pkgs.xorg.libXrandr
|
||||
];
|
||||
|
||||
LD_LIBRARY_PATH = with pkgs; lib.makeLibraryPath buildInputs;
|
||||
|
|
|
@ -4,17 +4,16 @@ import "base:runtime"
|
|||
import "core:c"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import "core:math"
|
||||
import "vendor:OpenGL"
|
||||
import "vendor:sdl3"
|
||||
|
||||
State :: struct {
|
||||
window: ^sdl3.Window,
|
||||
program: u32,
|
||||
vertex_pos_location: u32,
|
||||
vao: u32,
|
||||
vbo: u32,
|
||||
ibo: u32,
|
||||
wireframe: bool,
|
||||
tick: u32,
|
||||
window: ^sdl3.Window,
|
||||
program: u32,
|
||||
rect_vao: VAO,
|
||||
wireframe: bool,
|
||||
}
|
||||
|
||||
init :: proc() -> (state: State, ok: bool) {
|
||||
|
@ -67,6 +66,11 @@ init :: proc() -> (state: State, ok: bool) {
|
|||
)
|
||||
// }}}
|
||||
|
||||
sdl3.SetAppMetadata(
|
||||
"odin-rendering-experiments",
|
||||
"<hash-here>",
|
||||
"dev.moonythm.odin-rendering-experiments",
|
||||
) or_return
|
||||
sdl3.Init(sdl3.InitFlags{.VIDEO}) or_return
|
||||
sdl3.GL_SetAttribute(.CONTEXT_MAJOR_VERSION, GL_MAJOR) or_return
|
||||
sdl3.GL_SetAttribute(.CONTEXT_MINOR_VERSION, GL_MINOR) or_return
|
||||
|
@ -87,60 +91,24 @@ init :: proc() -> (state: State, ok: bool) {
|
|||
(gl_ctx != nil) or_return
|
||||
|
||||
OpenGL.load_up_to(GL_MAJOR, GL_MINOR, sdl3.gl_set_proc_address)
|
||||
OpenGL.ClearColor(0, 0, 0, 1)
|
||||
OpenGL.Enable(OpenGL.DEPTH_TEST)
|
||||
|
||||
state.program = OpenGL.load_shaders_source(
|
||||
#load("./vert.glsl"),
|
||||
#load("./frag.glsl"),
|
||||
) or_return
|
||||
// log.debug("Doing Opengl stuff")
|
||||
|
||||
vertex_pos_location := OpenGL.GetAttribLocation(state.program, "aPos")
|
||||
(vertex_pos_location != -1) or_return
|
||||
state.vertex_pos_location = u32(vertex_pos_location)
|
||||
state.rect_vao = create_vao({{-1, -1}, {1, -1}, {1, 1}, {-1, 1}}, {0, 1, 2, 3}) or_return
|
||||
|
||||
OpenGL.ClearColor(0, 0, 0, 1)
|
||||
|
||||
// VBO data
|
||||
vertex_data := 2 * [?]f32{-0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5}
|
||||
|
||||
// IBO data
|
||||
index_data := [?]u32{0, 1, 2, 3}
|
||||
|
||||
OpenGL.GenVertexArrays(1, &state.vao)
|
||||
OpenGL.BindVertexArray(state.vao)
|
||||
|
||||
//Create VBO
|
||||
OpenGL.GenBuffers(1, &state.vbo)
|
||||
OpenGL.BindBuffer(OpenGL.ARRAY_BUFFER, state.vbo)
|
||||
OpenGL.BufferData(OpenGL.ARRAY_BUFFER, 2 * 4 * size_of(f32), &vertex_data, OpenGL.STATIC_DRAW)
|
||||
|
||||
OpenGL.EnableVertexAttribArray(state.vertex_pos_location)
|
||||
OpenGL.VertexAttribPointer(
|
||||
state.vertex_pos_location,
|
||||
2,
|
||||
OpenGL.FLOAT,
|
||||
false,
|
||||
2 * size_of(f32),
|
||||
0,
|
||||
)
|
||||
|
||||
OpenGL.GenBuffers(1, auto_cast &state.ibo)
|
||||
OpenGL.BindBuffer(OpenGL.ELEMENT_ARRAY_BUFFER, state.ibo)
|
||||
OpenGL.BufferData(
|
||||
OpenGL.ELEMENT_ARRAY_BUFFER,
|
||||
4 * size_of(u32),
|
||||
&index_data,
|
||||
OpenGL.STATIC_DRAW,
|
||||
)
|
||||
|
||||
OpenGL.BindVertexArray(0)
|
||||
OpenGL.DisableVertexAttribArray(state.vertex_pos_location)
|
||||
init_command_queue()
|
||||
|
||||
return state, true
|
||||
}
|
||||
|
||||
render :: proc(state: State) {
|
||||
OpenGL.Clear(OpenGL.COLOR_BUFFER_BIT)
|
||||
render :: proc(state: ^State) {
|
||||
state.tick += 1
|
||||
OpenGL.Clear(OpenGL.COLOR_BUFFER_BIT | OpenGL.DEPTH_BUFFER_BIT)
|
||||
|
||||
OpenGL.UseProgram(state.program)
|
||||
defer OpenGL.UseProgram(0)
|
||||
|
@ -151,8 +119,23 @@ render :: proc(state: State) {
|
|||
OpenGL.PolygonMode(OpenGL.FRONT_AND_BACK, OpenGL.FILL)
|
||||
}
|
||||
|
||||
OpenGL.BindVertexArray(state.vao)
|
||||
OpenGL.DrawElements(OpenGL.TRIANGLE_FAN, 4, OpenGL.UNSIGNED_INT, nil)
|
||||
draw_rect({-0.5, 0}, {0.75, 0.5}, {1, 0, 0, 1}, z = 0.5)
|
||||
draw_rect({0.5, 0.25}, {0.3, 0.5}, {0, 1, 0, 1}, z = -0.5)
|
||||
|
||||
count := ℝ(32)
|
||||
for x in ℝ(0) ..< count {
|
||||
for y in ℝ(0) ..< count {
|
||||
i := x * count + y
|
||||
pos :=
|
||||
ℝ²{x + math.sin_f32(2 * math.π * (ℝ(state.tick) + i) / 60), y} *
|
||||
2 /
|
||||
ℝ(count) -
|
||||
1
|
||||
draw_rect(Rect{pos, 1 / ℝ(count), 0, {(pos.x + 1) / 2, (pos.y + 1) / 2, 1, 1}})
|
||||
}
|
||||
}
|
||||
|
||||
render_queue(state)
|
||||
}
|
||||
|
||||
close :: proc(state: State) {
|
||||
|
@ -194,11 +177,12 @@ main :: proc() {
|
|||
case 'w':
|
||||
state.wireframe = !state.wireframe
|
||||
}
|
||||
log.debug(event.text)
|
||||
}
|
||||
}
|
||||
|
||||
render(state)
|
||||
render(&state)
|
||||
sdl3.GL_SwapWindow(state.window)
|
||||
|
||||
free_all(context.temp_allocator)
|
||||
}
|
||||
}
|
||||
|
|
195
odin/sdl-opengl-rendering/src/shape.odin
Normal file
195
odin/sdl-opengl-rendering/src/shape.odin
Normal file
|
@ -0,0 +1,195 @@
|
|||
package visuals
|
||||
|
||||
import "core:log"
|
||||
import "vendor:OpenGL"
|
||||
|
||||
// {{{ Math constants
|
||||
ℝ :: f32
|
||||
ℝ² :: [2]ℝ
|
||||
ℝ³ :: [3]ℝ
|
||||
ℕ :: uint
|
||||
Mat3 :: matrix[3, 3]ℝ
|
||||
Color :: [4]ℝ
|
||||
// }}}
|
||||
// {{{ Command queues
|
||||
Rect :: struct {
|
||||
top_left: ℝ²,
|
||||
dimensions: ℝ²,
|
||||
z: ℝ,
|
||||
fill: Color,
|
||||
}
|
||||
|
||||
Circle :: struct {
|
||||
center: ℝ²,
|
||||
radius: ℝ,
|
||||
}
|
||||
|
||||
Shape :: union {
|
||||
Rect,
|
||||
Circle,
|
||||
}
|
||||
|
||||
Command_Queue :: struct {
|
||||
rects: [dynamic]Rect,
|
||||
}
|
||||
|
||||
queue: ^Command_Queue
|
||||
|
||||
init_command_queue :: proc() {
|
||||
queue = new(Command_Queue)
|
||||
queue^ = Command_Queue {
|
||||
rects = make([dynamic]Rect),
|
||||
}
|
||||
}
|
||||
|
||||
draw_rect_args :: proc(top_left: ℝ², dimensions: ℝ², color: Color, z: ℝ = 0) {
|
||||
draw_rect_struct(Rect{top_left, dimensions, z, color})
|
||||
}
|
||||
|
||||
draw_rect_struct :: proc(rect: Rect) {
|
||||
append(&queue.rects, rect)
|
||||
}
|
||||
|
||||
draw_rect :: proc {
|
||||
draw_rect_args,
|
||||
draw_rect_struct,
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ VAO & consts
|
||||
VAO :: struct {
|
||||
vao: u32,
|
||||
ibo: u32,
|
||||
vertex_pos_buffer: u32,
|
||||
instance_fill_buffer: u32,
|
||||
instance_mat_buffer: u32,
|
||||
index_count: ℕ,
|
||||
}
|
||||
|
||||
INSTANCES :: 1024 // The number of instances to allocate space in the buffer for
|
||||
VERTEX_POS_LOCATION :: 0
|
||||
INSTANCE_FILL_LOCATION :: 1
|
||||
INSTANCE_MAT_LOCATION :: 2
|
||||
// }}}
|
||||
// {{{ Create VAO
|
||||
create_vao :: proc(vertices: []ℝ², indices: []u32) -> (out: VAO, ok: bool) {
|
||||
out.index_count = len(indices)
|
||||
|
||||
// Create VAO
|
||||
OpenGL.GenVertexArrays(1, &out.vao)
|
||||
OpenGL.BindVertexArray(out.vao)
|
||||
|
||||
// Create instance fill VBO
|
||||
OpenGL.GenBuffers(1, auto_cast &out.instance_fill_buffer)
|
||||
OpenGL.BindBuffer(OpenGL.ARRAY_BUFFER, out.instance_fill_buffer)
|
||||
|
||||
OpenGL.EnableVertexAttribArray(INSTANCE_FILL_LOCATION)
|
||||
OpenGL.VertexAttribPointer(INSTANCE_FILL_LOCATION, 4, OpenGL.FLOAT, false, size_of(Color), 0)
|
||||
OpenGL.VertexAttribDivisor(INSTANCE_FILL_LOCATION, 1)
|
||||
|
||||
// Create instance mat VBO
|
||||
OpenGL.GenBuffers(1, auto_cast &out.instance_mat_buffer)
|
||||
OpenGL.BindBuffer(OpenGL.ARRAY_BUFFER, out.instance_mat_buffer)
|
||||
|
||||
for i in u32(0) ..< 3 {
|
||||
OpenGL.EnableVertexAttribArray(INSTANCE_MAT_LOCATION + i)
|
||||
vec3_size :: size_of(ℝ³)
|
||||
OpenGL.VertexAttribPointer(
|
||||
INSTANCE_MAT_LOCATION + i,
|
||||
3,
|
||||
OpenGL.FLOAT,
|
||||
false,
|
||||
3 * vec3_size,
|
||||
uintptr(i * vec3_size),
|
||||
)
|
||||
OpenGL.VertexAttribDivisor(INSTANCE_MAT_LOCATION + i, 1)
|
||||
}
|
||||
|
||||
//Create position VBO
|
||||
OpenGL.GenBuffers(1, &out.vertex_pos_buffer)
|
||||
OpenGL.BindBuffer(OpenGL.ARRAY_BUFFER, out.vertex_pos_buffer)
|
||||
OpenGL.BufferData(
|
||||
OpenGL.ARRAY_BUFFER,
|
||||
len(vertices) * 2 * size_of(ℝ),
|
||||
raw_data(vertices),
|
||||
OpenGL.STATIC_DRAW,
|
||||
)
|
||||
|
||||
// Put the data into the VBO
|
||||
OpenGL.EnableVertexAttribArray(VERTEX_POS_LOCATION)
|
||||
OpenGL.VertexAttribPointer(VERTEX_POS_LOCATION, 2, OpenGL.FLOAT, false, 2 * size_of(ℝ), 0)
|
||||
|
||||
// Create the IBO
|
||||
OpenGL.GenBuffers(1, auto_cast &out.ibo)
|
||||
OpenGL.BindBuffer(OpenGL.ELEMENT_ARRAY_BUFFER, out.ibo)
|
||||
OpenGL.BufferData(
|
||||
OpenGL.ELEMENT_ARRAY_BUFFER,
|
||||
len(indices) * size_of(u32),
|
||||
raw_data(indices),
|
||||
OpenGL.STATIC_DRAW,
|
||||
)
|
||||
|
||||
OpenGL.BindVertexArray(0)
|
||||
|
||||
return out, true
|
||||
}
|
||||
// }}}
|
||||
// {{{ Set rect transforms
|
||||
set_rect_transforms :: proc(vao: ^VAO, rects: []Rect) -> ℕ {
|
||||
log.assert(len(rects) <= INSTANCES, "Attempting to send too many rects to the GPU")
|
||||
matrices := new([INSTANCES]Mat3, context.temp_allocator)
|
||||
fills := new([INSTANCES]Color, context.temp_allocator)
|
||||
|
||||
for rect, i in rects {
|
||||
// This matrix must transform the rect [-1, 1]² into the desired rect
|
||||
mat: Mat3
|
||||
|
||||
center := rect.top_left + rect.dimensions / 2
|
||||
mat[0, 0] = rect.dimensions.x / 2
|
||||
mat[1, 1] = rect.dimensions.y / 2
|
||||
mat[2].xy = center.xy
|
||||
mat[2].z = rect.z
|
||||
|
||||
matrices[i] = mat
|
||||
fills[i] = rect.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(rects)
|
||||
}
|
||||
// }}}
|
||||
// {{{ Render the entire queue
|
||||
draw_instances :: proc(vao: VAO, instances: ℕ) {
|
||||
OpenGL.BindVertexArray(vao.vao)
|
||||
OpenGL.DrawElementsInstanced(
|
||||
OpenGL.TRIANGLE_FAN,
|
||||
i32(vao.index_count),
|
||||
OpenGL.UNSIGNED_INT,
|
||||
nil,
|
||||
i32(instances),
|
||||
)
|
||||
}
|
||||
|
||||
render_queue :: proc(state: ^State) {
|
||||
rect_steps := len(queue.rects) / INSTANCES
|
||||
|
||||
for i := 0; i < len(queue.rects); i += INSTANCES {
|
||||
slice := queue.rects[i:]
|
||||
if len(slice) > INSTANCES {slice = slice[:INSTANCES]}
|
||||
instances := set_rect_transforms(&state.rect_vao, slice)
|
||||
draw_instances(state.rect_vao, instances)
|
||||
}
|
||||
|
||||
clear(&queue.rects)
|
||||
}
|
||||
// }}}
|
|
@ -1,10 +1,13 @@
|
|||
#version 330
|
||||
|
||||
in vec2 aPos;
|
||||
layout (location = 0) in vec2 aPos;
|
||||
layout (location = 1) in vec4 instanceFill;
|
||||
layout (location = 2) in mat3 instanceMatrix;
|
||||
|
||||
out vec4 vertexColor;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aPos.x, aPos.y, 0, 1);
|
||||
vertexColor = vec4((aPos.x + 1) / 2, (aPos.y + 1) / 2, 1, 1);
|
||||
vec3 pos = instanceMatrix * vec3(aPos.xy, 1);
|
||||
gl_Position = vec4(pos.xyz, 1);
|
||||
vertexColor = instanceFill;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue