getting basic webgl rendering working
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 2 Sep 2020 18:38:39 +0000 (13:38 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 2 Sep 2020 18:38:39 +0000 (13:38 -0500)
src/main.onyx
src/shaders/basic.frag [new file with mode: 0644]
src/shaders/basic.vert [new file with mode: 0644]
webgl.js

index 9093f5bd86ac4e08d606fd203e642dbd143f9eb9..25745e889558aed5424327adb0027e1ed7c5fb37 100644 (file)
@@ -3,38 +3,176 @@ package main
 #include_file "core/std/js"
 #include_file "core/js/webgl"
 
-use package builtin
 use package core
 use package gl as gl
 
 Vec2 :: struct {
-    x : i32;
-    y : i32;
+    x : f32;
+    y : f32;
 }
 
-print_vec2 :: proc (v: Vec2) #add_overload print {
-    print("Vec2(");
-    print(v.x);
-    print(", ");
-    print(v.y);
-    print(")");
+// print_vec2 :: proc (v: Vec2) #add_overload print {
+//     print("Vec2(");
+//     print(v.x);
+//     print(", ");
+//     print(v.y);
+//     print(")");
+// }
+
+
+GameState :: struct {
+    dummy : i32;
 }
 
-main :: proc (args: [] cstring) {
-    arr : [..] Vec2;
-    array_init(^arr);
-    defer array_free(^arr);
+update :: proc (gs: ^GameState) {
+}
+
+draw :: proc (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);
+}
+
+// This procedure is called asynchronously from JS.
+// It provides us with the pointer game it in main.
+new_frame_callback :: proc (gs: ^GameState) #export {
+    update(gs);
+    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;
 
-    for i: 0, 100 do array_push(^arr, Vec2.{ i * 2, i * 3 });
+    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);
+}
+
+
+main :: proc (args: [] cstring) {
     print("Hello, World!\n");
-    print_array(^arr, "\n");
 
     if !gl.init("gamecanvas") {
         print("Failed to initialize GL canvas.");
         return;
     }
 
-    gl.clearColor(1.0f, 0.0f, 1.0f, 1.0f);
-    gl.clear(gl.COLOR_BUFFER_BIT);
+    setup_drawing();
+
+    gs := cast(^GameState) calloc(sizeof GameState);
+    game_launch(gs);
 }
+
+
+
+game_launch :: proc (gs: ^GameState) #foreign "game" "launch" ---
+
diff --git a/src/shaders/basic.frag b/src/shaders/basic.frag
new file mode 100644 (file)
index 0000000..5a5229b
--- /dev/null
@@ -0,0 +1,9 @@
+#version 300 es
+
+precision mediump float;
+
+out vec4 fragColor;
+
+void main() {
+       fragColor = vec4(1, 0, 1, 1);
+}
diff --git a/src/shaders/basic.vert b/src/shaders/basic.vert
new file mode 100644 (file)
index 0000000..4b52d22
--- /dev/null
@@ -0,0 +1,10 @@
+#version 300 es
+
+layout(location = 0) in vec2 a_vert_pos;
+layout(location = 1) in vec2 a_pos;
+
+uniform mat3 u_proj;
+
+void main() {
+       gl_Position = vec4(u_proj * vec3(a_vert_pos + a_pos, 1), 1);
+}
\ No newline at end of file
index 16b971e2d917493b8ecae2955a42e3c8554cb121..1199e8969f6625fe7027fe7d1cf61b1bbcf325f6 100644 (file)
--- a/webgl.js
+++ b/webgl.js
@@ -11,6 +11,7 @@ WebGl_Wasm = {
         this.renderbuffers = [];
         this.textures = [];
         this.uniformlocs = [];
+        this.vertexArrays = [];
 
         this.canvas = document.getElementById(canvasname);
         if (this.canvas == null) return 0;
@@ -34,6 +35,8 @@ WebGl_Wasm = {
     bindFramebuffer(target, framebuffer) { this.gl.bindFramebuffer(target, this.framebuffers[framebuffer]); },
     bindRenderbuffer(target, renderbuffer) { this.gl.bindRenderbuffer(target, this.renderbuffers[renderbuffer]); },
     bindTexture(target, texture) { this.gl.bindTexture(target, this.textures[texture]); },
+    bindVertexArray(vertexArray) { this.gl.bindVertexArray(this.vertexArrays[vertexArray]); },
+
     blendColor(red, green, blue, alpha) { this.gl.blendColor(red, green, blue, alpha); },
     blendEquation(mode) { this.gl.blendEquation(mode); },
     blendEquationSeparate(modeRGB, modeAlpha) { this.gl.blendEquationSeparate(modeRGB, modeAlpha); },
@@ -118,6 +121,13 @@ WebGl_Wasm = {
         this.textures.push(texture);
         return this.textures.length - 1;
     },
+    createVertexArray() {
+        const vao = this.gl.createVertexArray();
+        if (vao == null) return -1;
+
+        this.vertexArrays.push(vao);
+        return this.vertexArrays.length - 1;
+    },
     cullFace(mode) { this.gl.cullFace(mode); },
     deleteBuffer(buffer) { this.gl.deleteBuffer(this.buffers[buffer]); },
     deleteFramebuffer(framebuffer) { this.gl.deleteFramebuffer(this.framebuffers[framebuffer]); },
@@ -125,6 +135,7 @@ WebGl_Wasm = {
     deleteRenderbuffer(renderbuffer) { this.gl.deleteRenderbuffer(this.renderbuffers[renderbuffer]); },
     deleteShader(shader) { this.gl.deleteShader(this.shaders[shader]); },
     deleteTexture(texture) { this.gl.deleteTexture(this.textures[texture]); },
+    deleteVertexArray(vertexArray) { this.gl.deleteVertexArray(this.vertexArrays[vertexArray]); },
     depthFunc(func) { this.gl.depthFunc(func); },
     depthMask(flag) { this.gl.depthMask(flag); },
     depthRange(znear, zfar) { this.gl.depthRange(znear, zfar); },
@@ -132,7 +143,9 @@ WebGl_Wasm = {
     disable(cap) { this.gl.disable(cap); },
     disableVertexAttribArray(index) { this.gl.disableVertexAttribArray(index); },
     drawArrays(mode, first, count) { this.gl.drawArrays(mode, first, count); },
+    drawArraysInstanced(mode, first, count, instanceCount) { this.gl.drawArraysInstanced(mode, first, count, instanceCount); },
     drawElements(mode, count, type, offset) { this.gl.drawElements(mode, count, type, offset); },
+    drawElementsInstanced(mode, count, type, offset, instanceCount) { this.gl.drawElementsInstanced(mode, count, type, offset, instanceCount); },
     enable(cap) { this.gl.enable(cap); },
     enableVertexAttribArray(index) { this.gl.enableVertexAttribArray(index); },
     finish() { this.gl.finish(); },
@@ -261,6 +274,7 @@ WebGl_Wasm = {
     vertexAttrib3f(idx, x, y, z) { this.gl.vertexAttrib3f(idx, x, y, z); },
     vertexAttrib4f(idx, x, y, z, w) { this.gl.vertexAttrib4f(idx, x, y, z, w); },
     vertexAttribPointer(idx, size, type, normalized, stride, offset) { this.gl.vertexAttribPointer(idx, size, type, normalized, stride, offset); },
+    vertexAttribDivisor(idx, divisor) { this.gl.vertexAttribDivisor(idx, divisor); },
     viewport(x, y, width, height) { this.gl.viewport(x, y, width, height); },
 
 };