commit 2f0e582c173fb59b35d0a99c330e0861a8435aa9
parent c0855c54283731633610d318693898b162beebd2
Author: amin <dev@aminmesbah.com>
Date: Mon, 1 Jul 2019 05:29:33 +0000
Adapt wasm platform layer from transparent cube
Wasm now compiles, but linking still fails.
FossilOrigin-Name: 7588ae299560652737899782c4d59e91e862d62f03c939e291a6329e2c653404
Diffstat:
10 files changed, 762 insertions(+), 3 deletions(-)
diff --git a/build_wasm.sh b/build_wasm.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+set -e # fail if any command has a non-zero exit status
+set -u # fail if any undefined variable is referenced
+set -o pipefail # propagate failure exit status through a pipeline
+shopt -s globstar nullglob # enable recursive and null globbing
+
+out_dir="./out"
+wasm_dir="${out_dir}/wasm"
+
+mkdir -p $wasm_dir
+cp src/platform_wasm_loader.js $wasm_dir/script.js
+cp src/platform_wasm_index.html $wasm_dir/index.html
+cp -r shader/ $wasm_dir
+
+clang \
+ -cc1 \
+ -Ofast \
+ -emit-llvm-bc \
+ -triple=wasm32-unknown-unknown-unknown-wasm \
+ -ffreestanding \
+ -fno-builtin \
+ -std=c11 \
+ -DGAME_WEBGL \
+ -o $wasm_dir/wasm.bc \
+ src/platform_wasm.c
+
+llvm-link -o $wasm_dir/wasm.bc $wasm_dir/wasm.bc
+opt -O3 -disable-simplify-libcalls $wasm_dir/wasm.bc -o $wasm_dir/wasm.bc
+llc -O3 -disable-simplify-libcalls -filetype=obj $wasm_dir/wasm.bc -o $wasm_dir/wasm.o
+
+wasm-ld \
+ --no-entry $wasm_dir/wasm.o \
+ -o $wasm_dir/binary.wasm \
+ -allow-undefined-file src/platform_wasm_js_symbols.txt \
+ --export=init \
+ --export=render \
+ --export=window_resize \
+ --import-memory
+
+rm $wasm_dir/*.o
+rm $wasm_dir/*.bc
diff --git a/src/game.c b/src/game.c
@@ -1,5 +1,9 @@
#include "game.h"
+
+#ifndef GAME_WEBGL
#include "glad.c"
+#endif
+
#include "shader.c"
#include "memory.c"
#include "collision.c"
diff --git a/src/game.h b/src/game.h
@@ -14,7 +14,11 @@
#include <stdio.h>
#include <stdlib.h>
-#include <glad/glad.h>
+#ifdef GAME_WEBGL
+#include "webgl.h"
+#else
+#include "glad/glad.h"
+#endif
#include "types.h"
#include "intrinsics.h"
@@ -76,3 +80,37 @@ struct GameState
internal void game_init(struct GameMemory *game_memory, v2u framebuffer);
internal void game_cleanup(struct GameMemory *game_memory);
+
+// TODO: organize this stuff
+internal void *memset(void *s, int c, size_t n)
+{
+ u8 *p = s;
+ while(n > 0)
+ {
+ *p = (u8)c;
+ p++;
+ n--;
+ }
+ return s;
+}
+
+// TODO: assert no overlap
+internal void *memcpy(void *dst, const void *src, size_t n)
+{
+ u8 *destination = (u8 *)dst;
+ u8 *source = (u8 *)src;
+
+ while (n--) {
+ *destination = *source;
+ destination++;
+ source++;
+ }
+
+ return dst;
+}
+
+// TODO: actually implement
+internal void *memmove(void *dst, const void *src, size_t n)
+{
+ return memcpy(dst, src, n);
+}
diff --git a/src/platform.h b/src/platform.h
@@ -1,7 +1,5 @@
#pragma once
-#include <time.h>
-
#include "types.h"
#define KIBIBYTES(n) (n) * 1024LL
@@ -23,6 +21,7 @@ struct GameMemory
};
#ifdef PLATFORM_HOTLOAD_GAME_CODE
+#include <time.h>
// We need to call this from the platform layer in order for the game, when
// built as a shared object library to have access to the OpenGL symbols.
// https://github.com/Dav1dde/glad/issues/151
diff --git a/src/platform_wasm.c b/src/platform_wasm.c
@@ -0,0 +1,82 @@
+#include "game.c"
+#include "platform.h"
+#include "platform_wasm.h"
+
+extern unsigned char __heap_base;
+
+struct GameMemory game_memory = {0};
+struct GameInput game_input = {0};
+i32 g_width = PLATFORM_SCR_WIDTH;
+i32 g_height = PLATFORM_SCR_HEIGHT;
+// TODO: replace with allocator
+char g_mem_buffer[1000] = {0};
+i32 g_mem_buffer_i = 0;
+u32 time = 0;
+
+i32 str_length(const char *str)
+{
+ i32 i = 0;
+ while(str[i] != '\0')
+ {
+ i++;
+ }
+ return i;
+}
+
+int wasm_print(const char *format, ...)
+{
+ i32 len = str_length(format);
+ js_print((i32)format, len);
+ return 0;
+}
+
+bool init(void)
+{
+ bool init_successful = true;
+ game_memory = (struct GameMemory) {
+ .buffer_size = MEBIBYTES(64),
+ .platform = {
+ &wasm_read_entire_file,
+ },
+ .buffer = &__heap_base,
+ };
+ if (!game_memory.buffer)
+ {
+ wasm_print("Game memory allocation failed\n");
+ init_successful = false;
+ }
+ game_init(&game_memory, (v2u) {g_width, g_height});
+ return init_successful;
+}
+
+void render(void)
+{
+ // TODO: measure dt
+ game_input.dt = 16;
+ game_update_and_render(&game_memory, &game_input, (v2u) {g_width, g_height});
+}
+
+void window_resize(int w, int h)
+{
+ g_width = w;
+ g_height = h;
+ glViewport(0, 0, g_width, g_height);
+}
+
+PLATFORM_READ_ENTIRE_FILE(wasm_read_entire_file)
+{
+ g_mem_buffer_i++;
+ char *buf = &g_mem_buffer[g_mem_buffer_i];
+ if(js_read_entire_file((i32)file_path, str_length(file_path), buf))
+ {
+ i32 file_data_length = str_length(buf);
+ g_mem_buffer_i += file_data_length;
+ g_mem_buffer[g_mem_buffer_i] = '\0';
+ wasm_print("Succeeded in reading file.");
+ }
+ else
+ {
+ wasm_print("Failed to read file.");
+ }
+ return buf;
+}
diff --git a/src/platform_wasm.h b/src/platform_wasm.h
@@ -0,0 +1,8 @@
+#define PLATFORM_SCR_WIDTH 600
+#define PLATFORM_SCR_HEIGHT 600
+
+PLATFORM_READ_ENTIRE_FILE(wasm_read_entire_file);
+
+// Functions implemented in the JS loader
+char *js_read_entire_file(i32 file_path, i32 name_len, char *file_data);
+int js_print(i32 string, i32 len);
diff --git a/src/platform_wasm_index.html b/src/platform_wasm_index.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>Transparent Cube</title>
+<meta name=viewport content='width=device-width,initial-scale=1' charset='utf-8'>
+<style>
+body {
+ margin: 0;
+ overflow: hidden;
+}
+#webglcanvas {
+ width: 100vw;
+ height: 100vh;
+}
+</style>
+<canvas id=webglcanvas></canvas>
+<script src='script.js' defer></script>
diff --git a/src/platform_wasm_js_symbols.txt b/src/platform_wasm_js_symbols.txt
@@ -0,0 +1,37 @@
+webglAttachShader
+webglBindBuffer
+webglBindVertexArray
+webglBlendColor
+webglBlendFunc
+webglBufferData
+webglClear
+webglClearColor
+webglCompileShader
+webglCreateBuffer
+webglCreateProgram
+webglCreateShader
+webglCreateVertexArray
+webglDeleteBuffer
+webglDeleteShader
+webglDeleteVertexArray
+webglDepthMask
+webglDisable
+webglDrawElements
+webglEnable
+webglEnableVertexAttribArray
+webglGetProgramInfoLog
+webglGetProgramParameter
+webglGetShaderInfoLog
+webglGetShaderParameter
+webglGetUniformLocation
+webglLinkProgram
+webglShaderSource
+webglUniform1f
+webglUniform1i
+webglUniform3f
+webglUniformMatrix4fv
+webglUseProgram
+webglVertexAttribPointer
+webglViewport
+js_read_entire_file
+js_print
diff --git a/src/platform_wasm_loader.js b/src/platform_wasm_loader.js
@@ -0,0 +1,248 @@
+let utf8decoder = new TextDecoder("utf-8");
+let memory = null;
+let exports = {};
+let imports = {};
+let files = [];
+let gl = null;
+let gl_id_freelist = [];
+let gl_id_map = [null];
+imports["webglAttachShader"] = function(program_id, shader_id) {
+ let program = gl_id_map[program_id];
+ let shader = gl_id_map[shader_id];
+ gl.attachShader(program, shader);
+}
+imports["webglBindBuffer"] = function(target, buffer_id) {
+ let buffer = gl_id_map[buffer_id];
+ gl.bindBuffer(target, buffer);
+}
+imports["webglBindVertexArray"] = function(vao_id) {
+ let vao = gl_id_map[vao_id];
+ gl.bindVertexArray(vao);
+}
+imports["webglBlendColor"] = function(red, green, blue, alpha) {
+ gl.blendColor(red, green, blue, alpha);
+}
+imports["webglBlendFunc"] = function(sfactor, dfactor) {
+ gl.blendFunc(sfactor, dfactor);
+}
+imports["webglBufferData"] = function(target, size, data, usage) {
+ let dataslice = memory.subarray(data, data + size);
+ gl.bufferData(target, dataslice, usage);
+}
+imports["webglClear"] = function(mask) {
+ gl.clear(mask);
+}
+imports["webglClearColor"] = function(red, green, blue, alpha) {
+ gl.clearColor(red, green, blue, alpha);
+}
+imports["webglCompileShader"] = function(shader_id) {
+ let shader = gl_id_map[shader_id];
+ gl.compileShader(shader);
+}
+imports["webglCreateBuffer"] = function() {
+ let buffer = gl.createBuffer();
+ let buffer_id = webgl_id_new(buffer);
+ return buffer_id
+}
+imports["webglCreateProgram"] = function() {
+ let program = gl.createProgram();
+ let program_id = webgl_id_new(program);
+ return program_id;
+}
+imports["webglCreateShader"] = function(type) {
+ let shader = gl.createShader(type);
+ let shader_id = webgl_id_new(shader);
+ return shader_id;
+}
+imports["webglCreateVertexArray"] = function() {
+ let vao = gl.createVertexArray()
+ let vao_id = webgl_id_new(vao);
+ return vao_id
+}
+imports["webglDeleteBuffer"] = function(buffer_id) {
+ let buffer = gl_id_map[buffer_id];
+ gl.deleteBuffer(buffer);
+ webgl_id_remove(buffer_id);
+}
+imports["webglDeleteShader"] = function(shader_id) {
+ let shader = gl_id_map[shader_id];
+ gl.deleteShader(shader);
+ webgl_id_remove(shader_id);
+}
+imports["webglDeleteVertexArray"] = function(vao_id) {
+ let vao = gl_id_map[vao_id];
+ gl.deleteVertexArray(vao);
+ webgl_id_remove(vao_id);
+}
+imports["webglDepthMask"] = function(flag) {
+ gl.depthMask(flag);
+}
+imports["webglDisable"] = function(cap) {
+ gl.disable(cap);
+}
+imports["webglDrawElements"] = function(mode, count, type, offset) {
+ gl.drawElements(mode, count, type, offset);
+}
+imports["webglEnable"] = function(cap) {
+ gl.enable(cap);
+}
+imports["webglEnableVertexAttribArray"] = function(index) {
+ gl.enableVertexAttribArray(index);
+}
+imports["webglGetProgramInfoLog"] = function() {
+}
+imports["webglGetProgramParameter"] = function(program_id, param) {
+ let program = gl_id_map[program_id];
+ return gl.getProgramParameter(program, param);
+}
+imports["webglGetShaderInfoLog"] = function(shader_id, out_buf) {
+ let shader = gl_id_map[shader_id];
+ let info_log = gl.getShaderInfoLog(shader);
+
+ // TODO: remove this once we get sprintf workingk
+ console.log(info_log);
+
+ let arr = memory.subarray(info_log, out_buf + info_log.byteLength);
+ arr.set(new Uint8Array(info_log));
+ return true;
+}
+imports["webglGetShaderParameter"] = function(shader_id, param) {
+ let shader = gl_id_map[shader_id];
+ let result = gl.getShaderParameter(shader, param);
+ return result;
+}
+imports["webglGetUniformLocation"] = function(program_id, name_ptr, name_len) {
+ let program = gl_id_map[program_id];
+ let name = utf8decoder.decode(memory.subarray(name_ptr, name_ptr+name_len));
+ let loc = gl.getUniformLocation(program, name);
+ let location_id = webgl_id_new(loc);
+ return location_id;
+}
+imports["webglLinkProgram"] = function(program_id) {
+ let program = gl_id_map[program_id];
+ gl.linkProgram(program);
+}
+imports["webglShaderSource"] = function(shader_id, source_ptr, source_len) {
+ let shader = gl_id_map[shader_id];
+ let arr = memory.subarray(source_ptr, source_ptr + source_len);
+ let s = utf8decoder.decode(arr);
+ gl.shaderSource(shader, s);
+}
+imports["webglUniform1f"] = function(location_id, value) {
+ let loc = gl_id_map[location_id];
+ gl['uniform1f'](loc, value);
+}
+imports["webglUniform1i"] = function(location_id, value) {
+ let loc = gl_id_map[location_id];
+ gl['uniform1i'](loc, value);
+}
+imports["webglUniform3f"] = function(location_id, x, y, z) {
+ let loc = gl_id_map[location_id];
+ gl['uniform3fv'](loc, [x, y, z]);
+}
+imports["webglUniformMatrix4fv"] = function(location_id, transpose, data) {
+ let loc = gl_id_map[location_id];
+ let dataslice = memory.slice(data, data + 4 * 16);
+ gl.uniformMatrix4fv(loc, transpose, new Float32Array(dataslice.buffer));
+}
+imports["webglUseProgram"] = function(program_id) {
+ let program = gl_id_map[program_id];
+ gl.useProgram(program);
+}
+imports["webglVertexAttribPointer"] = function(index, size, type, normalized, stride, offset) {
+ gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
+}
+imports["webglViewport"] = function(x, y, width, height) {
+ gl.viewport(x, y, width, height);
+}
+imports["js_read_entire_file"] = function(name, name_len, out_buf) {
+ let file_name = utf8decoder.decode(memory.subarray(name, name + name_len))
+ if (file_name == "shader/cube_f.glsl") {
+ var file = files[1];
+ } else if (file_name == "shader/cube_v.glsl") {
+ var file = files[2];
+ } else {
+ return false;
+ }
+ let arr = memory.subarray(out_buf, out_buf + file.byteLength);
+ let s = String.fromCharCode.apply(null, arr);
+ arr.set(new Uint8Array(file));
+ return true;
+}
+imports["js_print"] = function(s, len) {
+ let arr = memory.subarray(s, s + len);
+ console.log(utf8decoder.decode(arr));
+}
+function error_fatal(message) {
+ console.log(message);
+ throw message;
+}
+function webgl_id_new(obj) {
+ if(gl_id_freelist.length == 0) {
+ gl_id_map.push(obj);
+ return gl_id_map.length - 1;
+ } else {
+ let id = gl_id_freelist.shift();
+ gl_id_map[id] = obj;
+ return id;
+ }
+}
+function webgl_id_remove(id) {
+ delete gl_id_map[id];
+ gl_id_freelist.push(id);
+}
+function canvas_resize() {
+ let pr = window.devicePixelRatio;
+ let w = window.innerWidth;
+ let h = window.innerHeight;
+ // Bitwise OR does float truncation
+ let w_pixels = (w * pr) | 0;
+ let h_pixels = (h * pr) | 0;
+ gl.canvas.width = w_pixels;
+ gl.canvas.height = h_pixels
+ exports['window_resize'](w_pixels, h_pixels);
+ console.log("resize: (" + w_pixels + ", " + h_pixels + ")");
+}
+function canvas_render() {
+ exports['render']();
+ window.requestAnimationFrame(canvas_render);
+}
+function file_load(name) {
+ let promise = new Promise((resolve, reject) => {
+ fetch(name).then(resp => {
+ resp.arrayBuffer().then(arr => resolve(arr));
+ });
+ });
+ return promise;
+}
+window.onload = async function() {
+ let ctxopts = {
+ alpha: false,
+ depth: true,
+ stencil: false,
+ antialias: true,
+ preserveDrawingBuffer: false
+ };
+ gl = document.getElementById("webglcanvas").getContext("webgl2", ctxopts);
+ if(!gl) {
+ error_fatal("Your browser does not support WebGL 2.");
+ }
+ files[0] = file_load("binary.wasm");
+ files[1] = file_load("shader/cube_f.glsl");
+ files[2] = file_load("shader/cube_v.glsl");
+ for(var i=0; i<files.length; i++) {
+ files[i] = await files[i];
+ }
+ let binary = files[0];
+ imports['memory'] = new WebAssembly.Memory({'initial':32});
+ memory = new Uint8Array(imports['memory']['buffer']);
+ let program = await WebAssembly.instantiate(binary, {"env":imports});
+ let instance = program['instance'];
+ exports = instance['exports'];
+ canvas_resize();
+ window.addEventListener("resize", canvas_resize);
+ if(!exports['init']()) {
+ error_fatal("Game initialization failed.");
+ }
+ canvas_render();
+}
diff --git a/src/webgl.h b/src/webgl.h
@@ -0,0 +1,286 @@
+#pragma once
+
+typedef int i32;
+typedef float f32;
+typedef double f64;
+
+// NOTE(amin): Since these functions will be implemented in javascript, we can
+// only use i32, f32, and f64 params.
+void webglAttachShader(i32 program, i32 shader);
+void webglBindBuffer(i32 target, i32 buffer);
+void webglBindVertexArray(i32 vao);
+void webglBlendColor(f32 r, f32 g, f32 b, f32 a);
+void webglBlendFunc(i32 sfactor, i32 dfactor);
+void webglBufferData(i32 target, i32 size, i32 data, i32 usage);
+void webglClear(i32 mask);
+void webglClearColor(f32 r, f32 g, f32 b, f32 a);
+void webglCompileShader(i32 shader);
+i32 webglCreateBuffer(void);
+i32 webglCreateProgram(void);
+i32 webglCreateShader(i32 type);
+i32 webglCreateVertexArray(void);
+void webglDeleteBuffer(i32 bo);
+void webglDeleteShader(i32 shader);
+void webglDeleteVertexArray(i32 vao);
+void webglDepthMask(i32 flag);
+void webglDisable(i32 cap);
+void webglDrawElements(i32 mode, i32 count, i32 type, i32 offset);
+void webglEnable(i32 cap);
+void webglEnableVertexAttribArray(i32 index);
+void webglGetProgramInfoLog(void);
+int webglGetProgramParameter(i32 program, i32 param);
+void webglGetShaderInfoLog(i32 shader, char *out_buf);
+int webglGetShaderParameter(i32 shader, i32 param);
+i32 webglGetUniformLocation(i32 program, const char name[static 1], i32 name_len);
+void webglLinkProgram(i32 program);
+void webglShaderSource(i32 shader, const char source[static 1], i32 source_len);
+void webglUniform1f(i32 location, f32 value);
+void webglUniform1i(i32 location, i32 value);
+void webglUniform3f(i32 location, f32 x, f32 y, f32 z);
+void webglUniformMatrix4fv(i32 location, i32 transpose, const f32 data[static 16]);
+void webglUseProgram(i32 program);
+void webglVertexAttribPointer(i32 index, i32 size, i32 type, i32 normalized, i32 stride, i32 offset);
+void webglViewport(i32 x, i32 y, i32 width, i32 height);
+
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_LINES 0x0001
+#define GL_TRIANGLES 0x0004
+#define GL_SRC_ALPHA 0x0302
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_DEPTH_TEST 0x0B71
+#define GL_BLEND 0x0BE2
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FILL 0x1B02
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_STATIC_DRAW 0x88E4
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef void GLvoid;
+typedef int GLint;
+typedef unsigned int GLuint;
+typedef int GLsizei;
+typedef float GLfloat;
+typedef char GLchar;
+typedef long GLsizeiptr;
+
+// TODO: add a version with safety checks
+#define WEBGL_CAST_I32(x) (i32)(x)
+
+static inline i32 _webgl_strlen(const char *str)
+{
+ i32 len = 0;
+ while(str[len] != '\0')
+ {
+ len++;
+ }
+ return len;
+}
+
+inline void glAttachShader(GLuint program, GLuint shader)
+{
+ webglAttachShader(WEBGL_CAST_I32(program), WEBGL_CAST_I32(shader));
+}
+
+inline void glBindBuffer(GLenum target, GLuint buffer)
+{
+ webglBindBuffer(WEBGL_CAST_I32(target), WEBGL_CAST_I32(buffer));
+}
+
+inline void glBindVertexArray(GLuint array)
+{
+ webglBindVertexArray(WEBGL_CAST_I32(array));
+}
+
+inline void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+ webglBlendColor((f32)red, (f32)green, (f32)blue, (f32)alpha);
+}
+
+inline void glBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+ webglBlendFunc(WEBGL_CAST_I32(sfactor), WEBGL_CAST_I32(dfactor));
+}
+
+inline void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
+{
+ webglBufferData(WEBGL_CAST_I32(target), WEBGL_CAST_I32(size), WEBGL_CAST_I32(data), WEBGL_CAST_I32(usage));
+}
+
+inline void glClear(GLbitfield mask)
+{
+ webglClear(WEBGL_CAST_I32(mask));
+}
+
+inline void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+ webglClearColor((f32)red, (f32)green, (f32)blue, (f32)alpha);
+}
+
+inline void glCompileShader(GLuint shader)
+{
+ webglCompileShader(WEBGL_CAST_I32(shader));
+}
+
+inline GLuint glCreateProgram(void)
+{
+ i32 program_id = webglCreateProgram();
+ return (GLuint)program_id;
+}
+
+inline GLuint glCreateShader(GLenum type)
+{
+ return webglCreateShader(WEBGL_CAST_I32(type));
+}
+
+inline void glDeleteBuffers(GLsizei n, const GLuint *buffers)
+{
+ assert(n == 1);
+ i32 the_buffer = WEBGL_CAST_I32(buffers[0]);
+ webglDeleteBuffer(the_buffer);
+}
+
+inline void glDeleteShader(GLuint shader)
+{
+ webglDeleteShader(WEBGL_CAST_I32(shader));
+}
+
+inline void glDeleteVertexArrays(GLsizei n, const GLuint *arrays)
+{
+ assert(n == 1);
+ i32 the_array = WEBGL_CAST_I32(arrays[0]);
+ webglDeleteVertexArray(the_array);
+}
+
+inline void glDepthMask(GLboolean flag)
+{
+ webglDepthMask(WEBGL_CAST_I32(flag));
+}
+
+inline void glDisable(GLenum cap)
+{
+ webglDisable(WEBGL_CAST_I32(cap));
+}
+
+inline void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
+{
+ webglDrawElements(WEBGL_CAST_I32(mode), WEBGL_CAST_I32(count), WEBGL_CAST_I32(type), WEBGL_CAST_I32(indices));
+}
+
+inline void glEnable(GLenum cap)
+{
+ webglEnable(WEBGL_CAST_I32(cap));
+}
+
+inline void glEnableVertexAttribArray(GLuint index)
+{
+ webglEnableVertexAttribArray(WEBGL_CAST_I32(index));
+}
+
+inline void glGenBuffers(GLsizei n, GLuint *buffers)
+{
+ assert(n == 1);
+ i32 buffer_id = webglCreateBuffer();
+ assert(buffer_id >= 0);
+ *buffers = (GLuint)buffer_id;
+}
+
+inline void glGenVertexArrays(GLsizei n, GLuint *arrays)
+{
+ assert(n == 1);
+ i32 vao_id = webglCreateVertexArray();
+ assert(vao_id >= 0);
+ *arrays = (GLuint)vao_id;
+}
+
+inline void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
+{
+ // TODO: implement
+ //webglGetProgramInfoLog(WEBGL_CAST_I32(program), WEBGL_CAST_I32(bufsize), WEBGL_CAST_I32(*length), WEBGL_CAST_I32(*infoLog));
+}
+
+inline void glGetProgramiv(GLuint program, GLenum pname, GLint *params)
+{
+ *params = webglGetProgramParameter(WEBGL_CAST_I32(program), WEBGL_CAST_I32(pname));
+}
+
+inline void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
+{
+ webglGetShaderInfoLog(WEBGL_CAST_I32(shader), infoLog);
+}
+
+inline void glGetShaderiv(GLuint shader, GLenum pname, GLint *params)
+{
+ *params = webglGetShaderParameter(WEBGL_CAST_I32(shader), WEBGL_CAST_I32(pname));
+}
+
+inline GLint glGetUniformLocation(GLuint program, const GLchar *name)
+{
+ i32 name_len = _webgl_strlen(name);
+ return webglGetUniformLocation(WEBGL_CAST_I32(program), name, name_len);
+}
+
+inline void glLinkProgram(GLuint program)
+{
+ webglLinkProgram(WEBGL_CAST_I32(program));
+}
+
+inline void glPolygonMode(GLenum face, GLenum mode)
+{
+ // No Op. This doesn't exist in webgl
+}
+
+inline void glShaderSource(GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length)
+{
+ const GLchar *s = (void *)*string;
+ i32 l = _webgl_strlen(s);
+ webglShaderSource(WEBGL_CAST_I32(shader), s, l);
+}
+
+inline void glUniform1f(GLint location, GLfloat v0)
+{
+ webglUniform1f(WEBGL_CAST_I32(location), (f32)v0);
+}
+
+inline void glUniform1i(GLint location, GLint v0)
+{
+ webglUniform1i(WEBGL_CAST_I32(location), WEBGL_CAST_I32(v0));
+}
+
+inline void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
+{
+ webglUniform3f(WEBGL_CAST_I32(location), (f32)v0, (f32)v1, (f32)v2);
+}
+
+inline void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ webglUniformMatrix4fv(WEBGL_CAST_I32(location), WEBGL_CAST_I32(transpose), value);
+}
+
+inline void glUseProgram(GLuint program)
+{
+ webglUseProgram(WEBGL_CAST_I32(program));
+}
+
+inline void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer)
+{
+ webglVertexAttribPointer(WEBGL_CAST_I32(index), WEBGL_CAST_I32(size), WEBGL_CAST_I32(type), WEBGL_CAST_I32(normalized), WEBGL_CAST_I32(stride), WEBGL_CAST_I32(pointer));
+}
+
+inline void glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ webglViewport(x, y, WEBGL_CAST_I32(width), WEBGL_CAST_I32(height));
+}
+
+#undef WEBGL_CAST_I32