|
/* |
|
This is free and unencumbered software released into the public domain. |
|
|
|
Anyone is free to copy, modify, publish, use, compile, sell, or |
|
distribute this software, either in source code form or as a compiled |
|
binary, for any purpose, commercial or non-commercial, and by any |
|
means. |
|
|
|
In jurisdictions that recognize copyright laws, the author or authors |
|
of this software dedicate any and all copyright interest in the |
|
software to the public domain. We make this dedication for the benefit |
|
of the public at large and to the detriment of our heirs and |
|
successors. We intend this dedication to be an overt act of |
|
relinquishment in perpetuity of all present and future rights to this |
|
software under copyright law. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
For more information, please refer to <http://unlicense.org/> |
|
*/ |
|
|
|
#include <emscripten/emscripten.h> |
|
#include <emscripten/html5.h> |
|
|
|
#define GL_GLEXT_PROTOTYPES |
|
#define EGL_EGLEXT_PROTOTYPES |
|
#include <GL/gl.h> |
|
#include <GLES2/gl2.h> |
|
#include <math.h> |
|
|
|
static const char* vertex_shader_text = |
|
"precision lowp float;" |
|
"uniform mat4 uMVP;" |
|
"attribute vec4 aPos;" |
|
"attribute vec3 aCol;" |
|
"varying vec3 vCol;" |
|
"void main()" |
|
"{" |
|
"vCol = aCol;" |
|
"gl_Position = uMVP * aPos;" |
|
"}"; |
|
|
|
static const char* fragment_shader_text = |
|
"precision lowp float;" |
|
"varying vec3 vCol;" |
|
"void main()" |
|
"{" |
|
"gl_FragColor = vec4(vCol, 1.0);" |
|
"}"; |
|
|
|
typedef struct Vertex { float x, y, r, g, b; } Vertex; |
|
static GLuint program, vertex_buffer; |
|
static GLint uMVP_location, aPos_location, aCol_location; |
|
|
|
int WAFNDraw(double f, void*); |
|
|
|
// This function is called at startup |
|
int main(int argc, char *argv[]) |
|
{ |
|
emscripten_set_canvas_element_size("canvas", 640, 480); |
|
|
|
EmscriptenWebGLContextAttributes attrs; |
|
emscripten_webgl_init_context_attributes(&attrs); |
|
attrs.alpha = 0; |
|
auto glContext = emscripten_webgl_create_context("canvas", &attrs); |
|
emscripten_webgl_make_context_current(glContext); |
|
|
|
glViewport(0, 0, 640, 480); |
|
|
|
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); |
|
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL); |
|
glCompileShader(vertex_shader); |
|
|
|
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); |
|
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL); |
|
glCompileShader(fragment_shader); |
|
|
|
program = glCreateProgram(); |
|
glAttachShader(program, vertex_shader); |
|
glAttachShader(program, fragment_shader); |
|
glLinkProgram(program); |
|
|
|
uMVP_location = glGetUniformLocation(program, "uMVP"); |
|
aPos_location = glGetAttribLocation(program, "aPos"); |
|
aCol_location = glGetAttribLocation(program, "aCol"); |
|
|
|
glGenBuffers(1, &vertex_buffer); |
|
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); |
|
|
|
glEnableVertexAttribArray(aPos_location); |
|
glVertexAttribPointer(aPos_location, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); |
|
glEnableVertexAttribArray(aCol_location); |
|
glVertexAttribPointer(aCol_location, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 2)); |
|
|
|
emscripten_request_animation_frame_loop(&WAFNDraw, 0); |
|
|
|
return 0; |
|
} |
|
|
|
// This function is called by loader.js every frame |
|
int WAFNDraw(double f, void*) |
|
{ |
|
f /= 1000.0; |
|
|
|
glClear(GL_COLOR_BUFFER_BIT); |
|
|
|
Vertex vertices[3] = |
|
{ |
|
{ -0.6f, -0.4f, 1.f, 0.f, 0.f }, |
|
{ 0.6f, -0.4f, 0.f, 0.f, 1.f }, |
|
{ 0.f, 0.6f, 1.f, 1.f, 1.f }, |
|
}; |
|
vertices[0].r = 0.5f + sinf(f * 3.14159f * 2.0f) * 0.5f; |
|
vertices[1].b = 0.5f + cosf(f * 3.14159f * 2.0f) * 0.5f; |
|
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); |
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
|
|
|
GLfloat mvp[4*4] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 }; |
|
glUseProgram(program); |
|
glUniformMatrix4fv(uMVP_location, 1, GL_FALSE, mvp); |
|
glDrawArrays(GL_TRIANGLES, 0, 3); |
|
|
|
return EM_TRUE; |
|
} |
Here's some of the output that I build for where WASM is one of the build targets:
These are 40 programs that I build each for 10+ targets (WASM, Emscripten (deprecated), NaCl (deprecated), Win32, Win64, Linux32, Linux64, macOS, iOS and Android (up to 4 separate builds for 4 ABIs). So compiling 400 times, linking 400 times, collecting assets and packing gzips/ZIPs/APKs/etc 400 times. And I do that all automated in a few minutes.
Yes those are not giant commercial games, just small things made by me in my spare time. But so are most things on the web.
Now until I switched to building without Emscripten, maintenance of the web target was a big pain. Builds were slow, modifying the JavaScript library meant I had to rerun emcc and updating Emscripten was never smooth (yes I'm on Windows). It also never ran without flaws (scaling the web site resized the canvas incorrectly, fullscreen barely worked, etc.) thus I also deployed NaCl builds for Chrome (never had any problems with both GL rendering and audio output there). Sure web standards and browser support grew along the way, too. But so did WebAssembly.
I still stand by that I think Emscripten should be just one tool not THE tool for running C/C++ on the web. I hoped that with llvm officially gaining support for wasm that the part that Emscripten does (generating the layer between browser APIs and the wasm) would be an optional step. Maybe as one of the Binaryen executables.
And it basically is (the point of my blog post)! Yet the public at large doesn't seem to realize/know that.
Also I think the source code for the SDL2, glfw, OpenAL, etc. JavaScript libraries should by now be in the respective projects source repositories and not in Emscripten's. It feels like this closed platform where these few libraries are chosen to be the supported (and maintained) ones without giving others a clear path how to embrace the web platform. Shoutouts to the ones that still do like the sokol headers by @floooh.
Btw. that last link 'greetings' is 3.7 MB 😉