refactored quad rendering
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 3 Sep 2020 01:07:35 +0000 (20:07 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 3 Sep 2020 01:07:35 +0000 (20:07 -0500)
index.html
index.js
src/gfx/quad_renderer.onyx [new file with mode: 0644]
src/main.onyx
src/shaders/basic.frag
src/shaders/basic.vert
src/utils/gl.onyx [new file with mode: 0644]

index 8540cc5f1fdd85b8409078de944ad6cf2aaf9fd7..efc08a77ff3bc1a4053cab6b46bcd9d759992540 100644 (file)
@@ -11,6 +11,6 @@
 
     </head>
     <body style="background: black">
-        <canvas id="gamecanvas" width="800" height="600">No canvas for you.</canvas>
+        <canvas id="gamecanvas" width="1200" height="1200">No canvas for you.</canvas>
     </body>
 </html>
index 5013e63ac6edd861c921ca60e737727467f161cd..09d5390a67d1ea6e62d4750994860afa360e73db 100644 (file)
--- 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 (file)
index 0000000..d2c44fa
--- /dev/null
@@ -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);
+}
index 25745e889558aed5424327adb0027e1ed7c5fb37..e2573abcbb12b180d48286c2ba1a166cdf28a146 100644 (file)
@@ -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);
 }
 
index 5a5229b1c1fc84b051881698024831eb7e85b004..cce4d85776251fd15a12285f9ccddc37d0dc3a72 100644 (file)
@@ -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);
 }
index 4b52d2254ea4a61227f7eedcf08a376432839fc3..f3e02e25da0f98a35d976ed838604e05ae823f48 100644 (file)
@@ -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 (file)
index 0000000..9083295
--- /dev/null
@@ -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;
+}
+