a-game

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

commit 45d442fea9b43b5915264741259f95482c903d7a
parent 8246212e7d5347ce89650b53576cdbdd4a120aff
Author: amin <dev@aminmesbah.com>
Date:   Sun,  7 Jul 2019 01:59:12 +0000

Mostly fix wasm platform layer

It just expects the texture image to be RGBA, not BGRA.

FossilOrigin-Name: 8a0eb6e17015af74537f89f648facd72eb43f54d3c7e68503ea24c1c4036249c
Diffstat:
Mbuild_wasm.sh | 1+
Msrc/platform_wasm.c | 8+++++---
Msrc/platform_wasm.h | 4++--
Msrc/platform_wasm_js_symbols.txt | 6++++++
Msrc/platform_wasm_loader.js | 35++++++++++++++++++++++++++++++++---
Msrc/webgl.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 111 insertions(+), 8 deletions(-)

diff --git a/build_wasm.sh b/build_wasm.sh @@ -12,6 +12,7 @@ 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 +cp -r assets/ $wasm_dir clang \ -cc1 \ diff --git a/src/platform_wasm.c b/src/platform_wasm.c @@ -30,7 +30,8 @@ global_variable struct GameInput game_input = {0}; global_variable i32 g_width = PLATFORM_SCR_WIDTH; global_variable i32 g_height = PLATFORM_SCR_HEIGHT; // TODO: replace with allocator -global_variable char g_mem_buffer[1000] = {0}; +// NOTE: If this buffer is too small, the browser will freeze up +global_variable u8 g_mem_buffer[10000] = {0}; global_variable i32 g_mem_buffer_i = 0; global_variable u32 previous_time = 0; @@ -120,9 +121,10 @@ PLATFORM_READ_ENTIRE_FILE(wasm_read_entire_file) { g_mem_buffer_i++; u8 *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 = js_read_entire_file((i32)file_path, str_length(file_path), buf); + if(file_data_length) { - i32 file_data_length = str_length(buf); + *out_num_bytes = file_data_length; g_mem_buffer_i += file_data_length; g_mem_buffer[g_mem_buffer_i] = '\0'; wasm_print("Succeeded in reading file."); diff --git a/src/platform_wasm.h b/src/platform_wasm.h @@ -5,5 +5,5 @@ PLATFORM_READ_ENTIRE_FILE(wasm_read_entire_file); PLATFORM_MEMORY_FREE(wasm_memory_free); // 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); +i32 js_read_entire_file(i32 file_path, i32 name_len, u8 *file_data); +i32 js_print(i32 string, i32 len); diff --git a/src/platform_wasm_js_symbols.txt b/src/platform_wasm_js_symbols.txt @@ -1,6 +1,8 @@ +webglActiveTexture webglAttachShader webglBindBuffer webglBindVertexArray +webglBindTexture webglBlendColor webglBlendFunc webglBufferData @@ -10,6 +12,7 @@ webglCompileShader webglCreateBuffer webglCreateProgram webglCreateShader +webglCreateTexture webglCreateVertexArray webglDeleteBuffer webglDeleteShader @@ -19,6 +22,7 @@ webglDisable webglDrawElements webglEnable webglEnableVertexAttribArray +webglGenerateMipmap webglGetProgramInfoLog webglGetProgramParameter webglGetShaderInfoLog @@ -26,6 +30,8 @@ webglGetShaderParameter webglGetUniformLocation webglLinkProgram webglShaderSource +webglTexImage2D +webglTexParameteri webglUniform1f webglUniform1i webglUniform3f diff --git a/src/platform_wasm_loader.js b/src/platform_wasm_loader.js @@ -1,3 +1,4 @@ +'use strict'; let utf8decoder = new TextDecoder("utf-8"); let memory = null; let exports = {}; @@ -20,6 +21,9 @@ const key_numeric_codes = { KeyS: 4, F11: 5, }; +imports["webglActiveTexture"] = function(texture) { + gl.activeTexture(texture); +} imports["webglAttachShader"] = function(program_id, shader_id) { let program = gl_id_map[program_id]; let shader = gl_id_map[shader_id]; @@ -29,6 +33,10 @@ imports["webglBindBuffer"] = function(target, buffer_id) { let buffer = gl_id_map[buffer_id]; gl.bindBuffer(target, buffer); } +imports["webglBindTexture"] = function(target, texture_id) { + let texture = gl_id_map[texture_id]; + gl.bindTexture(target, texture); +} imports["webglBindVertexArray"] = function(vao_id) { let vao = gl_id_map[vao_id]; gl.bindVertexArray(vao); @@ -68,6 +76,11 @@ imports["webglCreateShader"] = function(type) { let shader_id = webgl_id_new(shader); return shader_id; } +imports["webglCreateTexture"] = function(type) { + let texture = gl.createTexture(); + let texture_id = webgl_id_new(texture); + return texture_id; +} imports["webglCreateVertexArray"] = function() { let vao = gl.createVertexArray() let vao_id = webgl_id_new(vao); @@ -103,6 +116,9 @@ imports["webglEnable"] = function(cap) { imports["webglEnableVertexAttribArray"] = function(index) { gl.enableVertexAttribArray(index); } +imports["webglGenerateMipmap"] = function(target) { + gl.generateMipmap(target); +} imports["webglGetProgramInfoLog"] = function() { } imports["webglGetProgramParameter"] = function(program_id, param) { @@ -142,6 +158,14 @@ imports["webglShaderSource"] = function(shader_id, source_ptr, source_len) { let s = utf8decoder.decode(arr); gl.shaderSource(shader, s); } +imports["webglTexImage2D"] = function(target, level, internalformat, width, height, border, format, type, pixels) { + const bytes_per_pixel = 4; + let dataslice = memory.subarray(pixels, pixels + (width * height * bytes_per_pixel)); + gl.texImage2D(target, level, internalformat, width, height, border, format, type, dataslice); +} +imports["webglTexParameteri"] = function(target, pname, param) { + gl.texParameteri(target, pname, param); +} imports["webglUniform1f"] = function(location_id, value) { let loc = gl_id_map[location_id]; gl['uniform1f'](loc, value); @@ -169,19 +193,23 @@ imports["webglVertexAttribPointer"] = function(index, size, type, normalized, st imports["webglViewport"] = function(x, y, width, height) { gl.viewport(x, y, width, height); } -imports["js_read_entire_file"] = function(name, name_len, out_buf) { +imports["js_read_entire_file"] = function(name, name_len, out_buf, out_len) { let file_name = utf8decoder.decode(memory.subarray(name, name + name_len)) + let file_size = 0; if (file_name == "shader/main_f.glsl") { var file = files[1]; } else if (file_name == "shader/main_v.glsl") { var file = files[2]; + } else if (file_name == "assets/tile0.tga") { + var file = files[3]; } else { - return false; + return 0; } let arr = memory.subarray(out_buf, out_buf + file.byteLength); + file_size = arr.length * arr.BYTES_PER_ELEMENT; let s = String.fromCharCode.apply(null, arr); arr.set(new Uint8Array(file)); - return true; + return file_size; } imports["js_print"] = function(s, len) { let arr = memory.subarray(s, s + len); @@ -251,6 +279,7 @@ window.onload = async function() { files[0] = file_load("binary.wasm"); files[1] = file_load("shader/main_f.glsl"); files[2] = file_load("shader/main_v.glsl"); + files[3] = file_load("assets/tile0.tga"); for(var i = 0; i < files.length; i++) { files[i] = await files[i]; } diff --git a/src/webgl.h b/src/webgl.h @@ -6,8 +6,10 @@ typedef double f64; // NOTE(amin): Since these functions will be implemented in javascript, we can // only use i32, f32, and f64 params. +void webglActiveTexture(i32 texture); void webglAttachShader(i32 program, i32 shader); void webglBindBuffer(i32 target, i32 buffer); +void webglBindTexture(i32 target, i32 texture); void webglBindVertexArray(i32 vao); void webglBlendColor(f32 r, f32 g, f32 b, f32 a); void webglBlendFunc(i32 sfactor, i32 dfactor); @@ -18,6 +20,7 @@ void webglCompileShader(i32 shader); i32 webglCreateBuffer(void); i32 webglCreateProgram(void); i32 webglCreateShader(i32 type); +i32 webglCreateTexture(void); i32 webglCreateVertexArray(void); void webglDeleteBuffer(i32 bo); void webglDeleteShader(i32 shader); @@ -27,6 +30,7 @@ void webglDisable(i32 cap); void webglDrawElements(i32 mode, i32 count, i32 type, i32 offset); void webglEnable(i32 cap); void webglEnableVertexAttribArray(i32 index); +void webglGenerateMipmap(i32 target); void webglGetProgramInfoLog(void); int webglGetProgramParameter(i32 program, i32 param); void webglGetShaderInfoLog(i32 shader, char *out_buf); @@ -34,6 +38,8 @@ 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 webglTexImage2D(i32 target, i32 level, i32 internalformat, i32 width, i32 height, i32 border, i32 format, i32 type, i32 pixels); +void webglTexParameteri(i32 target, i32 pname, i32 param); void webglUniform1f(i32 location, f32 value); void webglUniform1i(i32 location, i32 value); void webglUniform3f(i32 location, f32 x, f32 y, f32 z); @@ -49,13 +55,31 @@ void webglViewport(i32 x, i32 y, i32 width, i32 height); #define GL_LINES 0x0001 #define GL_TRIANGLES 0x0004 #define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_FRONT_AND_BACK 0x0408 #define GL_DEPTH_TEST 0x0B71 #define GL_BLEND 0x0BE2 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_UNSIGNED_BYTE 0x1401 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 +#define GL_RGBA 0x1908 #define GL_FILL 0x1B02 +#define GL_LINEAR 0x2601 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 #define GL_CONSTANT_ALPHA 0x8003 +// NOTE(amin): this should normally be: `#define GL_BGRA 0x80E1`, however +// OpenGL ES 3.0, and consequently WebGL 2.0, doesn't support GL_BGRA, so we +// resort to this hideous hack just to get things working, along with a texture +// swizzle in the shader. +// TODO(amin): fix this in a better way +#define GL_BGRA GL_RGBA +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE0 0x84C0 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_STATIC_DRAW 0x88E4 @@ -88,6 +112,11 @@ static inline i32 _webgl_strlen(const char *str) return len; } +void glActiveTexture(GLenum texture) +{ + webglActiveTexture(WEBGL_CAST_I32(texture)); +} + inline void glAttachShader(GLuint program, GLuint shader) { webglAttachShader(WEBGL_CAST_I32(program), WEBGL_CAST_I32(shader)); @@ -98,6 +127,11 @@ inline void glBindBuffer(GLenum target, GLuint buffer) webglBindBuffer(WEBGL_CAST_I32(target), WEBGL_CAST_I32(buffer)); } +void glBindTexture(GLenum target, GLuint texture) +{ + webglBindTexture(WEBGL_CAST_I32(target), WEBGL_CAST_I32(texture)); +} + inline void glBindVertexArray(GLuint array) { webglBindVertexArray(WEBGL_CAST_I32(array)); @@ -196,6 +230,18 @@ inline void glGenBuffers(GLsizei n, GLuint *buffers) *buffers = (GLuint)buffer_id; } +void glGenerateMipmap(GLenum target) +{ + webglGenerateMipmap(WEBGL_CAST_I32(target)); +} + +void glGenTextures(GLsizei n, GLuint *textures) +{ + assert(n == 1); + i32 texture_id = webglCreateTexture(); + *textures = (GLuint)texture_id; +} + inline void glGenVertexArrays(GLsizei n, GLuint *arrays) { assert(n == 1); @@ -248,6 +294,25 @@ inline void glShaderSource(GLuint shader, GLsizei count, const GLchar *const *st webglShaderSource(WEBGL_CAST_I32(shader), s, l); } +void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) +{ + webglTexImage2D( + WEBGL_CAST_I32(target), + WEBGL_CAST_I32(level), + WEBGL_CAST_I32(internalformat), + WEBGL_CAST_I32(width), + WEBGL_CAST_I32(height), + WEBGL_CAST_I32(border), + WEBGL_CAST_I32(format), + WEBGL_CAST_I32(type), + WEBGL_CAST_I32(pixels)); +} + +void glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + webglTexParameteri(WEBGL_CAST_I32(target), WEBGL_CAST_I32(pname), WEBGL_CAST_I32(param)); +} + inline void glUniform1f(GLint location, GLfloat v0) { webglUniform1f(WEBGL_CAST_I32(location), (f32)v0);