commit 62426a5e951917871d7280f60c87360f24e93b22
parent 0f78c5c0fc6764dbd0e5760c510273c2a145797b
Author: amin <dev@aminmesbah.com>
Date: Sat, 15 Jun 2019 22:19:46 +0000
Add header translating gl calls to webgl calls
The webgl* functions will be implemented in javascript. This technique
is based on this excellent article:
https://aransentin.github.io/cwasm/
FossilOrigin-Name: 16d708b7c1ba8101936cf0087816377cc5aecb4dc5280bd3643d173d426c2b5b
Diffstat:
9 files changed, 352 insertions(+), 47 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,6 +1,9 @@
*.out
*.swp
+*.bc
+*.o
+
build/*
tags
diff --git a/build_wasm.sh b/build_wasm.sh
@@ -0,0 +1,7 @@
+mkdir -p ./out/wasm
+clang -cc1 -Ofast -emit-llvm-bc -triple=wasm32-unknown-unknown-unknown-wasm -std=c11 \
+ -DGAME_WEBGL \
+ src/game.c
+llvm-link -o wasm.bc src/*.bc
+llc -O3 -filetype=obj wasm.bc -o wasm.o
+wasm-ld --no-entry wasm.o -o binary.wasm --strip-all -allow-undefined-file wasm_js_implemented_symbols.txt --import-memory
diff --git a/src/game.c b/src/game.c
@@ -1,24 +1,16 @@
#include "game.h"
-// TODO: remove references to emscripten
-#ifndef __EMSCRIPTEN__
+#ifndef GAME_WEBGL
#include "glad.c"
#endif
#include "shader.c"
-#ifdef PLATFORM_HOTLOAD_GAME_CODE
-void game_load_opengl_symbols(void)
-{
- gladLoadGL();
-}
-#endif
-
void game_init(struct GameState *game_state, uint32_t screen_width, uint32_t screen_height)
{
// load cube vertex data
{
- GLfloat cube_vertices[] = {
+ f32 cube_vertices[] = {
// positions // colors
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
@@ -30,7 +22,7 @@ void game_init(struct GameState *game_state, uint32_t screen_width, uint32_t scr
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,
};
- GLuint elements[] = {
+ u32 elements[] = {
0, 4, 6, 6, 2, 0,
1, 5, 7, 7, 3, 1,
3, 2, 0, 0, 1, 3,
@@ -39,11 +31,11 @@ void game_init(struct GameState *game_state, uint32_t screen_width, uint32_t scr
2, 6, 7, 7, 3, 2,
};
- GLuint cube_vao;
+ u32 cube_vao;
glGenVertexArrays(1, &cube_vao);
glBindVertexArray(cube_vao);
- GLuint cube_vbo;
+ u32 cube_vbo;
glGenBuffers(1, &cube_vbo);
glBindBuffer(GL_ARRAY_BUFFER, cube_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_vertices), cube_vertices, GL_STATIC_DRAW);
@@ -55,7 +47,7 @@ void game_init(struct GameState *game_state, uint32_t screen_width, uint32_t scr
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*cube_vertices), (GLvoid*)(3 * sizeof(*cube_vertices)));
glEnableVertexAttribArray(1);
- GLuint cube_ebo;
+ u32 cube_ebo;
glGenBuffers(1, &cube_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
@@ -71,8 +63,7 @@ void game_init(struct GameState *game_state, uint32_t screen_width, uint32_t scr
glEnable(GL_DEPTH_TEST);
- // TODO: remove references to emscripten
-#ifndef __EMSCRIPTEN__
+#ifndef GAME_WEBGL
glEnable(GL_MULTISAMPLE);
#endif
}
@@ -130,3 +121,10 @@ void game_cleanup(struct GameState *game_state)
glDeleteBuffers(1, &game_state->cube_vbo);
glDeleteBuffers(1, &game_state->cube_ebo);
}
+
+#ifdef PLATFORM_HOTLOAD_GAME_CODE
+void game_load_opengl_symbols(void)
+{
+ gladLoadGL();
+}
+#endif
diff --git a/src/game.h b/src/game.h
@@ -7,25 +7,30 @@
#include <stdio.h>
#include <stdlib.h>
-// TODO: remove references to emscripten
-#ifdef __EMSCRIPTEN__
-#include <GLES3/gl3.h>
+#include "glmth.h"
+
+#ifdef GAME_WEBGL
+#include "webgl.h"
#else
#include "glad/glad.h"
#endif
-#include "glmth.h"
#include "shader.h"
-
struct GameState
{
- GLuint cube_vao;
- GLuint cube_vbo;
- GLuint cube_ebo;
+ u32 cube_vao;
+ u32 cube_vbo;
+ u32 cube_ebo;
struct Shader cube_shader;
};
+typedef void (game_update_and_render_func)(struct GameState *game_state, float dt, u32 screen_width, u32 screen_height);
+void game_update_and_render(struct GameState *game_state, float dt, u32 screen_width, u32 screen_height);
+
+void game_init(struct GameState *game_state, u32 screen_width, u32 screen_height);
+void game_cleanup(struct GameState *game_state);
+
#ifdef PLATFORM_HOTLOAD_GAME_CODE
// 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.
@@ -33,9 +38,3 @@ struct GameState
typedef void (game_load_opengl_symbols_func)(void);
void game_load_opengl_symbols(void);
#endif // PLATFORM_HOTLOAD_GAME_CODE
-
-typedef void (game_update_and_render_func)(struct GameState *game_state, float dt, uint32_t screen_width, uint32_t screen_height);
-void game_update_and_render(struct GameState *game_state, float dt, uint32_t screen_width, uint32_t screen_height);
-
-void game_init(struct GameState *game_state, uint32_t screen_width, uint32_t screen_height);
-void game_cleanup(struct GameState *game_state);
diff --git a/src/glmth.h b/src/glmth.h
@@ -4,16 +4,16 @@
#define M_PI 3.14159265359f
#endif
-typedef uint8_t u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-typedef int8_t s8;
-typedef int16_t s16;
-typedef int32_t s32;
-typedef int64_t s64;
-typedef float f32;
-typedef double r64;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+typedef signed char i8;
+typedef signed short i16;
+typedef signed int i32;
+typedef signed long long i64;
+typedef float f32;
+typedef double f64;
typedef union
{
diff --git a/src/shader.c b/src/shader.c
@@ -9,12 +9,12 @@ char *read_file(char *file_path)
{
// get file size
fseek(handle, 0, SEEK_END);
- uint32_t num_bytes_in_file = ftell(handle);
+ u32 num_bytes_in_file = ftell(handle);
rewind(handle);
buffer = (char*) malloc(sizeof(char) * (num_bytes_in_file + 1) );
- uint32_t bytes_read = fread(buffer, sizeof(char), num_bytes_in_file, handle);
+ u32 bytes_read = fread(buffer, sizeof(char), num_bytes_in_file, handle);
// IMPORTANT! fread() doesn't add the '\0'
buffer[num_bytes_in_file] = '\0';
@@ -40,10 +40,10 @@ struct Shader shader_compile(char *vertex_path, char *fragment_path)
const GLchar *vertex_shader_source = read_file(vertex_path);
const GLchar *fragment_shader_source = read_file(fragment_path);
- GLint success;
- GLchar info_log[512];
+ i32 success;
+ char info_log[512];
- GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ u32 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
@@ -53,7 +53,7 @@ struct Shader shader_compile(char *vertex_path, char *fragment_path)
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n %s\n", info_log);
}
- GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ u32 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
diff --git a/src/shader.h b/src/shader.h
@@ -2,7 +2,7 @@
struct Shader
{
- uint32_t program;
+ u32 program;
};
char *read_file(char *file_path);
diff --git a/src/webgl.h b/src/webgl.h
@@ -0,0 +1,264 @@
+#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 shader, i32 program);
+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 webglCreateProgram(void);
+i32 webglCreateShader(i32 type);
+void webglDeleteBuffers(i32 bo);
+void webglDeleteShader(i32 shader);
+void webglDeleteVertexArrays(i32 vao);
+void webglDepthMask(i32 b);
+void webglDisable(i32 cap);
+void webglDrawElements(i32 mode, i32 count, i32 type, i32 offset);
+void webglEnable(i32 cap);
+void webglEnableVertexAttribArray(i32 index);
+void webglGenBuffers(i32 n, i32 buffers);
+void webglGenVertexArrays(i32 n, i32 arrays);
+void webglGetProgramInfoLog(void);
+int webglGetProgramiv(i32 program, i32 param);
+void webglGetShaderInfoLog(void);
+int webglGetShaderiv(i32 shader, i32 param);
+i32 webglGetUniformLocation(i32 program, const char name[static 1], i32 name_len);
+void webglLinkProgram(i32 program);
+void webglShaderSource(i32 shader, i32 count, 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, const f32 data[static 16]);
+void webglUseProgram(i32 program);
+void webglVertexAttribPointer(i32 index, i32 size, i32 type, i32 normalized, i32 stride, i32 offset);
+
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_TRIANGLES 0x0004
+#define GL_SRC_ALPHA 0x0302
+#define GL_DEPTH_TEST 0x0B71
+#define GL_BLEND 0x0BE2
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#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(WEBGL_CAST_I32(red), WEBGL_CAST_I32(green), WEBGL_CAST_I32(blue), WEBGL_CAST_I32(alpha));
+}
+
+inline void glCompileShader(GLuint shader)
+{
+ webglCompileShader(WEBGL_CAST_I32(shader));
+}
+
+inline GLuint glCreateProgram(void)
+{
+ return webglCreateProgram();
+}
+
+inline GLuint glCreateShader(GLenum type)
+{
+ return webglCreateShader(WEBGL_CAST_I32(type));
+}
+
+inline void glDeleteBuffers(GLsizei n, const GLuint *buffers)
+{
+ // TODO: assert n == 1
+ i32 the_buffer = WEBGL_CAST_I32(buffers[0]);
+ webglDeleteBuffers(the_buffer);
+}
+
+inline void glDeleteShader(GLuint shader)
+{
+ webglDeleteShader(WEBGL_CAST_I32(shader));
+}
+
+inline void glDeleteVertexArrays(GLsizei n, const GLuint *arrays)
+{
+ // TODO: assert n == 1
+ i32 the_array = WEBGL_CAST_I32(arrays[0]);
+ webglDeleteVertexArrays(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)
+{
+ webglGenBuffers(WEBGL_CAST_I32(n), WEBGL_CAST_I32(*buffers));
+}
+
+inline void glGenVertexArrays(GLsizei n, GLuint *arrays)
+{
+ webglGenVertexArrays(WEBGL_CAST_I32(n), WEBGL_CAST_I32(*arrays));
+}
+
+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 = webglGetProgramiv(WEBGL_CAST_I32(program), WEBGL_CAST_I32(pname));
+}
+
+inline void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
+{
+ // TODO: implement
+ //webglGetShaderInfoLog
+}
+
+inline void glGetShaderiv(GLuint shader, GLenum pname, GLint *params)
+{
+ *params = webglGetShaderiv(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 glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length)
+{
+ webglShaderSource(WEBGL_CAST_I32(shader), WEBGL_CAST_I32(count), *string, WEBGL_CAST_I32(*length));
+}
+
+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), 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));
+}
+
+#undef WEBGL_CAST_I32
diff --git a/wasm_js_implemented_symbols.txt b/wasm_js_implemented_symbols.txt
@@ -0,0 +1,34 @@
+webglAttachShader
+webglBindBuffer
+webglBindVertexArray
+webglBlendColor
+webglBlendFunc
+webglBufferData
+webglClear
+webglClearColor
+webglCompileShader
+webglCreateProgram
+webglCreateShader
+webglDeleteBuffers
+webglDeleteShader
+webglDeleteVertexArrays
+webglDepthMask
+webglDisable
+webglDrawElements
+webglEnable
+webglEnableVertexAttribArray
+webglGenBuffers
+webglGenVertexArrays
+webglGetProgramInfoLog
+webglGetProgramiv
+webglGetShaderInfoLog
+webglGetShaderiv
+webglGetUniformLocation
+webglLinkProgram
+webglShaderSource
+webglUniform1f
+webglUniform1i
+webglUniform3f
+webglUniformMatrix4fv
+webglUseProgram
+webglVertexAttribPointer