a-game

2D platformer written from scratch.
git clone git://git.amin.space/a-game.git
Log | Files | Refs | README | LICENSE

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:
Abuild_wasm.sh | 42++++++++++++++++++++++++++++++++++++++++++
Msrc/game.c | 4++++
Msrc/game.h | 40+++++++++++++++++++++++++++++++++++++++-
Msrc/platform.h | 3+--
Asrc/platform_wasm.c | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/platform_wasm.h | 8++++++++
Asrc/platform_wasm_index.html | 15+++++++++++++++
Asrc/platform_wasm_js_symbols.txt | 37+++++++++++++++++++++++++++++++++++++
Asrc/platform_wasm_loader.js | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/webgl.h | 286+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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