#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" ---
+
this.renderbuffers = [];
this.textures = [];
this.uniformlocs = [];
+ this.vertexArrays = [];
this.canvas = document.getElementById(canvasname);
if (this.canvas == null) return 0;
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); },
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]); },
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); },
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(); },
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); },
};