commit 98c0b5fb0a34fc3eb635b27d19cb49b6e71f2bb3
parent 2a92d937febe092701d1a6aa128961f9c428bf94
Author: amin <dev@aminmesbah.com>
Date: Sat, 28 Jul 2018 04:45:12 +0000
Port to Emscripten
Emscripten [1] allows us to compile c code into wasm, using webGL for
rendering in the browser.
http://kripken.github.io/emscripten-site/
FossilOrigin-Name: aa59e204b0e70e981d08d17f30f77545f803d1882b80063052dbe722fb9a7c38
Diffstat:
9 files changed, 157 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,6 +1,6 @@
CC = clang
CFLAGS = -std=c99 -Ilib -Wall -Wextra -Wshadow -Wswitch-enum -Wno-unused-parameter -Wno-missing-braces
-LDFLAGS = -ldl -lglfw -lGL -lGLEW -lm
+LDFLAGS = -ldl -lglfw -lGL -lm
SRC_FILES = game.c glad.c glmth.c platform_linux.c shader.c
SRC = $(addprefix src/, $(SRC_FILES))
@@ -20,11 +20,17 @@ RELLIB = $(RELDIR)/$(LIB_NAME)
RELLIBTMP = $(RELLIB).tmp
RELCFLAGS = -DPLATFORM_HOTLOAD_GAME_CODE -O2 -Os
-.PHONY: default all build_debug build_lib build_release clean debug dir_debug dir_release memcheck run todo
+EMS_FILES = game.c glmth.c platform_emscripten.c shader.c
+EMSSRC = $(addprefix src/, $(EMS_FILES))
+EMSDIR = build/emscripten
+EMSEXE = $(EMSDIR)/$(EXE_FILE).html
+EMSCFLAGS = --preload-file shader -s USE_GLFW=3 -s USE_WEBGL2=1
+
+.PHONY: default all build_debug build_lib build_release clean debug dir_debug dir_release emscripten memcheck run todo
default: build_release
-all: build_debug build_release
+all: build_debug build_release emscripten
build_debug: dir_debug
$(CC) $(CFLAGS) $(DBGCFLAGS) $(SRC) -o $(DBGEXE) $(LDFLAGS)
@@ -54,6 +60,10 @@ memcheck: build_debug
run: build_release
./$(RELEXE)
+emscripten:
+ @mkdir -p $(EMSDIR)
+ emcc $(CFLAGS) $(EMSCFLAGS) -O2 -Os $(EMSSRC) -o $(EMSEXE) $(LDFLAGS)
+
todo:
@grep -FIR --colour=never --ignore-case --line-number todo src/ \
| sed -re 's/^([^:]+):[[:space:]]*(.*)/\1\x01\2/' \
diff --git a/shader/pyramid_f.glsl b/shader/pyramid_f.glsl
@@ -1,4 +1,6 @@
-#version 330 core
+#version 300 es
+
+precision highp float;
uniform vec3 pyramid_color;
diff --git a/shader/pyramid_v.glsl b/shader/pyramid_v.glsl
@@ -1,4 +1,4 @@
-#version 330 core
+#version 300 es
layout (location = 0) in vec3 a_position;
diff --git a/src/game.c b/src/game.c
@@ -3,7 +3,11 @@
#include <assert.h>
#include <math.h>
-#include <glad/glad.h>
+#ifdef __EMSCRIPTEN__
+#include <GLES3/gl3.h>
+#else
+#include "glad/glad.h"
+#endif
#ifdef PLATFORM_HOTLOAD_GAME_CODE
@@ -108,7 +112,7 @@ void game_update_and_render(struct GameState *game_state, float dt, uint32_t scr
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
shader_use(&game_state->pyramid_shader);
diff --git a/src/game.h b/src/game.h
@@ -1,7 +1,12 @@
#ifndef GAME_H
#define GAME_H
+#ifdef __EMSCRIPTEN__
+#include <GLES3/gl3.h>
+#else
#include "glad/glad.h"
+#endif
+
#include "glmth.h"
#include "shader.h"
diff --git a/src/platform_emscripten.c b/src/platform_emscripten.c
@@ -0,0 +1,99 @@
+#include "platform_emscripten.h"
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <emscripten.h>
+
+#define GLFW_INCLUDE_ES3
+#include <GLFW/glfw3.h>
+
+
+void error_callback(int error, const char *description);
+void framebuffer_size_callback(GLFWwindow *window, int width, int height);
+void platform_main_loop(void *data);
+
+
+int main(void)
+{
+ glfwSetErrorCallback(error_callback);
+
+ if (!glfwInit())
+ {
+ fprintf(stderr, "GLFW initialization failed\n");
+ return -1;
+ }
+
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
+
+ GLFWwindow* window = glfwCreateWindow(PLATFORM_SCR_WIDTH, PLATFORM_SCR_HEIGHT, "Quaternion Demo", NULL, NULL);
+ if (!window)
+ {
+ fprintf(stderr, "GLFW window creation failed\n");
+ glfwTerminate();
+ return -1;
+ }
+ glfwMakeContextCurrent(window);
+ glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
+
+ struct GameState game_state = {0};
+ game_init(&game_state, PLATFORM_SCR_WIDTH, PLATFORM_SCR_HEIGHT);
+
+ struct LoopArgs loop_args = {
+ .counter = 0,
+ .previous_s = 0.0f,
+ .lag = 0.0f,
+ .game_state = &game_state,
+ .window = window,
+ };
+ void *args = &loop_args;
+
+ emscripten_set_main_loop_arg(platform_main_loop, args, 0, 1);
+
+ game_cleanup(&game_state);
+
+ glfwDestroyWindow(window);
+ glfwTerminate();
+
+ return 0;
+}
+
+
+void platform_main_loop(void *data)
+{
+ struct LoopArgs *args = (struct LoopArgs *)(data);
+
+ // glfwGetTimerValue() is not currently implemented in Emscripten.
+ double current_s = glfwGetTime();
+ double elapsed_s = current_s - args->previous_s;
+ args->previous_s = current_s;
+ args->lag += elapsed_s;
+ //printf("%f, %f\n", elapsed_s, args->lag);
+
+ int32_t framebuffer_width = PLATFORM_SCR_WIDTH;
+ int32_t framebuffer_height = PLATFORM_SCR_HEIGHT;
+ glfwGetFramebufferSize(args->window, &framebuffer_width, &framebuffer_height);
+
+ // TODO: args->lag just increases forever. Fix that.
+ game_update_and_render(args->game_state, args->lag, framebuffer_width, framebuffer_height);
+
+ glfwSwapBuffers(args->window);
+ glfwPollEvents();
+}
+
+
+void error_callback(int error, const char *description)
+{
+ fprintf(stderr, "Error: %s\n", description);
+}
+
+
+void framebuffer_size_callback(GLFWwindow *window, int width, int height)
+{
+ glViewport(0, 0, width, height);
+}
diff --git a/src/platform_emscripten.h b/src/platform_emscripten.h
@@ -0,0 +1,22 @@
+#ifndef PLATFORM_EMSCRIPTEN_H
+#define PLATFORM_EMSCRIPTEN_H
+
+#include <stdbool.h>
+#include <time.h>
+
+#include <GLFW/glfw3.h>
+#include "game.h"
+
+#define PLATFORM_SCR_WIDTH 600
+#define PLATFORM_SCR_HEIGHT 600
+
+struct LoopArgs
+{
+ int counter;
+ struct GameState *game_state;
+ double previous_s;
+ double lag;
+ GLFWwindow* window;
+};
+
+#endif // PLATFORM_EMSCRIPTEN_H
diff --git a/src/shader.c b/src/shader.c
@@ -1,5 +1,11 @@
#include "shader.h"
+#ifdef __EMSCRIPTEN__
+#include <GLES3/gl3.h>
+#else
+#include "glad/glad.h"
+#endif
+
char *read_file(char *file_path)
{
@@ -36,7 +42,7 @@ char *read_file(char *file_path)
}
-struct Shader shader_compile(GLchar *vertex_path, GLchar *fragment_path)
+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);
diff --git a/src/shader.h b/src/shader.h
@@ -1,7 +1,6 @@
#ifndef SHADER_H
#define SHADER_H
-#include <glad/glad.h> // get opengl headers
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -14,7 +13,7 @@ struct Shader
};
char *read_file(char *file_path);
-struct Shader shader_compile(GLchar *vertex_path, GLchar *fragment_path);
+struct Shader shader_compile(char *vertex_path, char *fragment_path);
void shader_use(struct Shader *s);
void shader_setb(struct Shader *s, char *name, bool value);
void shader_seti(struct Shader *s, char *name, int value);