From cb7566c18cb13442e666baa462d52ffd705dec0b Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Wed, 2 Sep 2020 20:07:35 -0500 Subject: [PATCH] refactored quad rendering --- index.html | 2 +- index.js | 3 +- src/gfx/quad_renderer.onyx | 143 ++++++++++++++++++++++++++++++++ src/main.onyx | 162 +++++++------------------------------ src/shaders/basic.frag | 4 +- src/shaders/basic.vert | 9 ++- src/utils/gl.onyx | 32 ++++++++ 7 files changed, 215 insertions(+), 140 deletions(-) create mode 100644 src/gfx/quad_renderer.onyx create mode 100644 src/utils/gl.onyx diff --git a/index.html b/index.html index 8540cc5..efc08a7 100644 --- a/index.html +++ b/index.html @@ -11,6 +11,6 @@ - No canvas for you. + No canvas for you. diff --git a/index.js b/index.js index 5013e63..09d5390 100644 --- a/index.js +++ b/index.js @@ -19,7 +19,8 @@ function main(module) { }); } -fetch("game.wasm") +//fetch("game.wasm") +fetch("out.wasm") .then(res => res.arrayBuffer()) .then(buffer => WebAssembly.compile(buffer)) .then(main); diff --git a/src/gfx/quad_renderer.onyx b/src/gfx/quad_renderer.onyx new file mode 100644 index 0000000..d2c44fa --- /dev/null +++ b/src/gfx/quad_renderer.onyx @@ -0,0 +1,143 @@ +package gfx + +use package core +use package gl as gl +use package gl_utils as gl_utils + +Vec2 :: struct { + x : f32; + y : f32; +} + +QuadRenderer :: struct { + is_initialized : bool = false; + + quad_data : [..] Quad; + + vertexArray : gl.GLVertexArrayObject; + vertexBuffer : gl.GLBuffer; + indexBuffer : gl.GLBuffer; + quadBuffer : gl.GLBuffer; + + program : gl.GLProgram; +} + +Quad :: struct { + x : f32; + y : f32; + w : f32; + h : f32; + r : f32; + g : f32; + b : f32; +} + +quad_renderer_init :: proc (use qr: ^QuadRenderer, initial_quads := 10) { + vertexArray = gl.createVertexArray(); + gl.bindVertexArray(vertexArray); + + // Set up vertex and index data + vertex_data : [4] Vec2; + vertex_data[0] = Vec2.{ 0.0f, 0.0f }; + vertex_data[1] = Vec2.{ 0.0f, 1.0f }; + vertex_data[2] = Vec2.{ 1.0f, 1.0f }; + vertex_data[3] = Vec2.{ 1.0f, 0.0f }; + + vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, Buffer.{ + count = sizeof [4] Vec2, + data = cast(^void) vertex_data + }, gl.STATIC_DRAW); + + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 2 * sizeof gl.GLfloat, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, -1); + + array_init(^quad_data, initial_quads); + + for i: 0, initial_quads { + array_push(^quad_data, Quad.{ + x = cast(f32) random_between(0, 1000) / 1000.0f, + y = cast(f32) random_between(0, 1000) / 1000.0f, + w = 0.1f, + h = 0.1f, + r = 1.0f, + g = 0.0f, + b = 0.0f, + }); + } + + quadBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer); + gl.bufferData(gl.ARRAY_BUFFER, Buffer.{ + count = sizeof Quad * quad_data.count, + data = cast(^void) quad_data.data, + }, gl.DYNAMIC_DRAW); + + gl.enableVertexAttribArray(1); + gl.enableVertexAttribArray(2); + gl.enableVertexAttribArray(3); + gl.vertexAttribDivisor(1, 1); + gl.vertexAttribDivisor(2, 1); + gl.vertexAttribDivisor(3, 1); + gl.vertexAttribPointer(1, 2, gl.FLOAT, false, sizeof Quad, 0); + gl.vertexAttribPointer(2, 2, gl.FLOAT, false, sizeof Quad, 2 * sizeof f32); + gl.vertexAttribPointer(3, 3, gl.FLOAT, false, sizeof Quad, 4 * sizeof f32); + gl.bindBuffer(gl.ARRAY_BUFFER, -1); + + index_data : [6] gl.GLubyte; + index_data[0] = cast(gl.GLubyte) 0; + index_data[1] = cast(gl.GLubyte) 1; + index_data[2] = cast(gl.GLubyte) 2; + index_data[3] = cast(gl.GLubyte) 0; + index_data[4] = cast(gl.GLubyte) 2; + index_data[5] = cast(gl.GLubyte) 3; + + indexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Buffer.{ + count = sizeof [6] gl.GLubyte, + data = cast(^void) index_data, + }, gl.STATIC_DRAW); + + gl.bindVertexArray(-1); + + vertex_shader := gl_utils.compile_shader(gl.VERTEX_SHADER, #file_contents "./src/shaders/basic.vert"); + fragment_shader := gl_utils.compile_shader(gl.FRAGMENT_SHADER, #file_contents "./src/shaders/basic.frag"); + program = gl_utils.link_program(vertex_shader, fragment_shader); + gl.useProgram(program); + + u_proj_loc := gl.getUniformLocation(program, "u_proj"); + proj_mat : [9] gl.GLfloat; + proj_mat[3 * 0 + 0] = 2.0f; + proj_mat[3 * 0 + 1] = 0.0f; + proj_mat[3 * 0 + 2] = 0.0f; + proj_mat[3 * 1 + 0] = 0.0f; + proj_mat[3 * 1 + 1] = -2.0f; + proj_mat[3 * 1 + 2] = 0.0f; + proj_mat[3 * 2 + 0] = -1.0f; + proj_mat[3 * 2 + 1] = 1.0f; + proj_mat[3 * 2 + 2] = 1.0f; + + gl.uniformMatrix3(u_proj_loc, false, proj_mat); +} + +quad_renderer_draw :: proc (use qr: ^QuadRenderer) { + gl.bindVertexArray(vertexArray); + gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, quad_data.count); + gl.bindVertexArray(-1); +} + +quad_update_at_index :: proc (use qr: ^QuadRenderer, idx: i32, quad: Quad) { + quad_data[idx] = quad; +} + +quad_rebuffer_data :: proc (use qr: ^QuadRenderer) { + gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, Buffer.{ + count = quad_data.count * sizeof Quad, + data = cast(^void) quad_data.data, + }); + gl.bindBuffer(gl.ARRAY_BUFFER, -1); +} diff --git a/src/main.onyx b/src/main.onyx index 25745e8..e2573ab 100644 --- a/src/main.onyx +++ b/src/main.onyx @@ -3,37 +3,40 @@ package main #include_file "core/std/js" #include_file "core/js/webgl" +#include_folder "src/" +#include_file "utils/gl" +#include_file "gfx/quad_renderer" + use package core +use package gfx use package gl as gl -Vec2 :: struct { - x : f32; - y : f32; -} - -// print_vec2 :: proc (v: Vec2) #add_overload print { -// print("Vec2("); -// print(v.x); -// print(", "); -// print(v.y); -// print(")"); -// } - - GameState :: struct { dummy : i32; + quad_renderer : QuadRenderer; } -update :: proc (gs: ^GameState) { +update :: proc (use gs: ^GameState) { + for i: 0, 10000 { + quad_update_at_index(^quad_renderer, i, Quad.{ + x = cast(f32) random_between(0, 100) / 100.0f, + y = cast(f32) random_between(0, 100) / 100.0f, + w = cast(f32) random_between(1, 10) / 1000.0f, + h = cast(f32) random_between(1, 10) / 1000.0f, + r = cast(f32) random_between(0, 255) / 255.0f, + g = cast(f32) random_between(0, 255) / 255.0f, + b = cast(f32) random_between(0, 255) / 255.0f, + // r = 0.0f, g = 0.0f, b = 1.0f + }); + } } -draw :: proc (gs: ^GameState) { +draw :: proc (use gs: ^GameState) { gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f); gl.clear(gl.COLOR_BUFFER_BIT); - gl.bindVertexArray(vao); - gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, NUM_QUADS); - gl.bindVertexArray(-1); + quad_rebuffer_data(^quad_renderer); + quad_renderer_draw(^quad_renderer); } // This procedure is called asynchronously from JS. @@ -43,132 +46,21 @@ new_frame_callback :: proc (gs: ^GameState) #export { draw(gs); } -NUM_QUADS :: 500 -vao : gl.GLVertexArrayObject - -compile_shader :: proc (shader_type: gl.GLenum, source: cstring) -> gl.GLShader { - shader := gl.createShader(shader_type); - gl.shaderSource(shader, string_make(source)); - gl.compileShader(shader); - - if cast(i32) gl.getShaderParameter(shader, gl.COMPILE_STATUS) == 0 { - gl.printShaderInfoLog(shader); - return -1; - } - - return shader; -} - -link_program :: proc (vertex_shader: gl.GLShader, frag_shader: gl.GLShader) -> gl.GLProgram { - program := gl.createProgram(); - gl.attachShader(program, vertex_shader); - gl.attachShader(program, frag_shader); - gl.linkProgram(program); - - if cast(i32) gl.getProgramParameter(program, gl.LINK_STATUS) == 0 { - gl.printProgramInfoLog(program); - return -1; - } - - return program; -} - -setup_drawing :: proc { - vao = gl.createVertexArray(); - gl.bindVertexArray(vao); - - vertex_data : [8] gl.GLfloat; - vertex_data[2 * 0 + 0] = 0.0f; - vertex_data[2 * 0 + 1] = 0.0f; - vertex_data[2 * 1 + 0] = 0.0f; - vertex_data[2 * 1 + 1] = 0.1f; - vertex_data[2 * 2 + 0] = 0.1f; - vertex_data[2 * 2 + 1] = 0.1f; - vertex_data[2 * 3 + 0] = 0.1f; - vertex_data[2 * 3 + 1] = 0.0f; - - vertex_buffer := gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); - gl.bufferData(gl.ARRAY_BUFFER, Buffer.{ - count = sizeof [8] gl.GLfloat, - data = cast(^void) vertex_data - }, gl.STATIC_DRAW); - - gl.enableVertexAttribArray(0); - gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 2 * sizeof gl.GLfloat, 0); - - pos_buffer := gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, pos_buffer); - - positions : [..] Vec2; - array_init(^positions, NUM_QUADS); - defer array_free(^positions); - - for i: 0, NUM_QUADS { - array_push(^positions, Vec2.{ - x = cast(f32) random_between(0, 50) / 50.0f, - y = cast(f32) random_between(0, 50) / 50.0f, - }); - } - - gl.bufferData(gl.ARRAY_BUFFER, Buffer.{ - count = NUM_QUADS * sizeof Vec2, - data = cast(^void) positions.data, - }, gl.DYNAMIC_DRAW); - - gl.enableVertexAttribArray(1); - gl.vertexAttribDivisor(1, 1); - gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 2 * sizeof gl.GLfloat, 0); - - index_data : [6] gl.GLubyte; - index_data[0] = cast(gl.GLubyte) 0; - index_data[1] = cast(gl.GLubyte) 1; - index_data[2] = cast(gl.GLubyte) 2; - index_data[3] = cast(gl.GLubyte) 0; - index_data[4] = cast(gl.GLubyte) 2; - index_data[5] = cast(gl.GLubyte) 3; - - index_buffer := gl.createBuffer(); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Buffer.{ - count = sizeof [6] gl.GLubyte, - data = cast(^void) index_data, - }, gl.STATIC_DRAW); - - gl.bindVertexArray(-1); - - vertex_shader := compile_shader(gl.VERTEX_SHADER, #file_contents "./src/shaders/basic.vert"); - fragment_shader := compile_shader(gl.FRAGMENT_SHADER, #file_contents "./src/shaders/basic.frag"); - program := link_program(vertex_shader, fragment_shader); - gl.useProgram(program); - - u_proj_loc := gl.getUniformLocation(program, "u_proj"); - proj_mat : [9] gl.GLfloat; - proj_mat[3 * 0 + 0] = 2.0f; - proj_mat[3 * 0 + 1] = 0.0f; - proj_mat[3 * 0 + 2] = 0.0f; - proj_mat[3 * 1 + 0] = 0.0f; - proj_mat[3 * 1 + 1] = -2.0f; - proj_mat[3 * 1 + 2] = 0.0f; - proj_mat[3 * 2 + 0] = -1.0f; - proj_mat[3 * 2 + 1] = 1.0f; - proj_mat[3 * 2 + 2] = 1.0f; - - gl.uniformMatrix3(u_proj_loc, false, proj_mat); +setup_drawing :: proc (use state: ^GameState) { + quad_renderer_init(^quad_renderer, 10000); } - main :: proc (args: [] cstring) { - print("Hello, World!\n"); + print("Setting up WebGL2 canvas...\n"); if !gl.init("gamecanvas") { print("Failed to initialize GL canvas."); return; } - setup_drawing(); - gs := cast(^GameState) calloc(sizeof GameState); + setup_drawing(gs); + game_launch(gs); } diff --git a/src/shaders/basic.frag b/src/shaders/basic.frag index 5a5229b..cce4d85 100644 --- a/src/shaders/basic.frag +++ b/src/shaders/basic.frag @@ -2,8 +2,10 @@ precision mediump float; +in vec3 v_col; + out vec4 fragColor; void main() { - fragColor = vec4(1, 0, 1, 1); + fragColor = vec4(v_col, 1); } diff --git a/src/shaders/basic.vert b/src/shaders/basic.vert index 4b52d22..f3e02e2 100644 --- a/src/shaders/basic.vert +++ b/src/shaders/basic.vert @@ -2,9 +2,14 @@ layout(location = 0) in vec2 a_vert_pos; layout(location = 1) in vec2 a_pos; +layout(location = 2) in vec2 a_size; +layout(location = 3) in vec3 a_col; uniform mat3 u_proj; +out vec3 v_col; + void main() { - gl_Position = vec4(u_proj * vec3(a_vert_pos + a_pos, 1), 1); -} \ No newline at end of file + gl_Position = vec4(u_proj * vec3(a_vert_pos * a_size + a_pos, 1), 1); + v_col = a_col; +} diff --git a/src/utils/gl.onyx b/src/utils/gl.onyx new file mode 100644 index 0000000..9083295 --- /dev/null +++ b/src/utils/gl.onyx @@ -0,0 +1,32 @@ +package gl_utils + +use package core { string_make } +use package gl as gl + +compile_shader :: proc (shader_type: gl.GLenum, source: cstring) -> gl.GLShader { + shader := gl.createShader(shader_type); + gl.shaderSource(shader, string_make(source)); + gl.compileShader(shader); + + if cast(i32) gl.getShaderParameter(shader, gl.COMPILE_STATUS) == 0 { + gl.printShaderInfoLog(shader); + return -1; + } + + return shader; +} + +link_program :: proc (vertex_shader: gl.GLShader, frag_shader: gl.GLShader) -> gl.GLProgram { + program := gl.createProgram(); + gl.attachShader(program, vertex_shader); + gl.attachShader(program, frag_shader); + gl.linkProgram(program); + + if cast(i32) gl.getProgramParameter(program, gl.LINK_STATUS) == 0 { + gl.printProgramInfoLog(program); + return -1; + } + + return program; +} + -- 2.25.1