Experiments: Allegro + Emscripten.
Max Savenkov

I decided to give compiling Allegro with Emscripten a try. So far, I got past slight CMake and Emscriptent problems (Emscripten's libc does not have getexecname, so I had to add a stub for it) and managed to produce liballegro_monolith.so and link my test program against it.

A test consisting of a single call to al_init() works, but of course doing anything else requires far more work.

During this weekend, I'll try to see if I can rig up graphic driver which could at least create a display and clear it.

If you are interested or want to help, post here and we'll think of something.

Why am I doing this: well, my good friend is always taunting me with Unity's ability to quickly demonstrate things through browser. I want Allegro to do the same. Also, there is a Game Jam coming up in Russia, where ability to run code in browser is needed, so I want to try to make Allegro work with Emscripten before it starts, but I might be waaaaaay to optimistic.


What is the process you're following right now to convert C code into Javascript code, can we have a demonstration, it's a very interesting feature indeed.

Max Savenkov

Emscripten uses LLVM to compile C/C++ code into bytecode and then transform bytecode into JavaScript. See Emscripten: Building Projects.

The demo of my test is here: http://zxstudio.org/projects/allegro/my.html.

Basically, I did these steps:

1. Install Emscripten base SDK (Since I'm on Windows, there is a ready-made binaries, but there is an instruction on building it from sources on Linux)

2. Run emcmdprompt.bat to get shell with Emscripten added to PATH

3. Install latest SDK elements via:
emsdk update
emsdk install latest
emsdk activate latest

Install MinGW, because Emscriptent does not seem to work with cygwin and Visual Studio support is experimental:
emsdk install mingw-4.6.2-32bit
emsdk activate mingw-4.6.2-32bit

4. Fix the lack of getexecname by adding the following lines to emscripten\1.13.0\src\library.js:

  getexecname: function()
       return "";

5. In Allegro's main CMakeLists.txt, comment out


We should add a real check for Emscripten here instead of just removing this check, but I'm in hurry :)

6. Try to run CMake with

-DCMAKE_TOOLCHAIN_FILE=C:\X\emscripten\emscripten\1.13.0\cmake\Platform\Emscripten.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -G "MinGW Makefiles" .. -DWANT_X11=OFF -DWANT-OPENGLES=ON -DALLEGRO_EXCLUDE_GLX=ON -DWANT_MONOLITH=ON

Note the use of ALLEGRO_EXCLUDE_GLX. We're building for Unix-like environment, but it does not have X11 :)

7. See it fail, mess around with set of flags until everything compiles. Here's my list of WANTs:

1//Enable DLL loading in acodec (Windows) 2WANT_ACODEC_DYNAMIC_LOAD:BOOL=OFF 3 4//Allow compiler to use SSE instructions (x86) 5WANT_ALLOW_SSE:BOOL=OFF 6 7//Enable ALSA digital audio driver (Unix) 8WANT_ALSA:BOOL=OFF 9 10//Build for Android 11WANT_ANDROID:BOOL=OFF 12 13//Build for Android 4 (1.6) 14WANT_ANDROID_LEGACY:BOOL=OFF 15 16//Enable AudioQueue digital audio driver (Mac) 17WANT_AQUEUE:BOOL=OFF 18 19//Enable allegro_audio engine 20WANT_AUDIO:BOOL=OFF 21 22//Enable color addon 23WANT_COLOR:BOOL=ON 24 25//Build ex_curl example 26WANT_CURL_EXAMPLE:BOOL=OFF 27 28//Enable Direct3D graphics driver (Windows) 29WANT_D3D:BOOL=OFF 30 31//Enable Direct3D 9Ex extensions (Vista) 32WANT_D3D9EX:BOOL=OFF 33 34//Build demo programs 35WANT_DEMO:BOOL=OFF 36 37//Force use of DllMain for TLS (Windows) 38WANT_DLL_TLS:BOOL=OFF 39 40//Generate documentation 41WANT_DOCS:BOOL=OFF 42 43//Enable DSound digital audio driver (Windows) 44WANT_DSOUND:BOOL=OFF 45 46//Make frameworks embeddable in application bundles (Mac OS X) 47WANT_EMBED:BOOL=OFF 48 49//Build example programs 50WANT_EXAMPLES:BOOL=ON 51 52//Enable FFMPEG video driver 53WANT_FFMPEG:BOOL=OFF 54 55//Enable FLAC support 56WANT_FLAC:BOOL=OFF 57 58//Enable bitmap font add-on 59WANT_FONT:BOOL=ON 60 61//Want frameworks on Mac OS X 62WANT_FRAMEWORKS:BOOL=OFF 63 64//Compile with GLES2 support 65WANT_GLES2:BOOL=ON 66 67//Enable image load/save addon 68WANT_IMAGE:BOOL=ON 69 70//Enable JPEG support in image addon 71WANT_IMAGE_JPG:BOOL=ON 72 73//Enable PNG support in image addon 74WANT_IMAGE_PNG:BOOL=ON 75 76//Enable memfile addon 77WANT_MEMFILE:BOOL=ON 78 79//Enable MOD Audio support 80WANT_MODAUDIO:BOOL=OFF 81 82//Include all addons in the main library 83WANT_MONOLITH:BOOL=ON 84 85//Enable gcc mudflap (requires gcc 4.0+) 86WANT_MUDFLAP:BOOL=OFF 87 88//Enable native dialog addon 89WANT_NATIVE_DIALOG:BOOL=OFF 90 91//Enable the native platform image loader (if available) 92WANT_NATIVE_IMAGE_LOADER:BOOL=OFF 93 94//Enable Ogg video (requires Theora and Vorbis) 95WANT_OGG_VIDEO:BOOL=OFF 96 97//Enable OpenAL digital audio driver 98WANT_OPENAL:BOOL=ON 99 100//Enable OpenGL graphics driver (Windows, X11, OS X)) 101WANT_OPENGL:BOOL=ON 102 103//Enable OpenSL digital audio driver (Android) 104WANT_OPENSL:BOOL=OFF 105 106//Enable OSS digital audio driver (Unix) 107WANT_OSS:BOOL=OFF 108 109//Enable PhysicsFS addon 110WANT_PHYSFS:BOOL=OFF 111 112//Use popups instead of printf for fatal errors 113WANT_POPUP_EXAMPLES:BOOL=OFF 114 115//Enable primitives addon 116WANT_PRIMITIVES:BOOL=ON 117 118//Enable PulseAudio audio driver (Unix) 119WANT_PULSEAUDIO:BOOL=OFF 120 121//Enable generation of the Python wrapper 122WANT_PYTHON_WRAPPER:BOOL=OFF 123 124//Enable logging even in release mode 125WANT_RELEASE_LOGGING:BOOL=OFF 126 127//Build HLSL shader support (Direct3D) 128WANT_SHADERS_D3D:BOOL=OFF 129 130//Build GLSL shader support (OpenGL) 131WANT_SHADERS_GL:BOOL=ON 132 133//Build test programs 134WANT_TESTS:BOOL=OFF 135 136//Enable Ogg Vorbis support using Tremor 137WANT_TREMOR:BOOL=OFF 138 139//Enable TTF addon 140WANT_TTF:BOOL=OFF 141 142//Enable video player addon 143WANT_VIDEO:BOOL=OFF 144 145//Enable Ogg Vorbis support using libvorbis 146WANT_VORBIS:BOOL=OFF 147 148//X11 support 149WANT_X11:BOOL=OFF 150 151//X11 XF86VidMode Extension support 152WANT_X11_XF86VIDMODE:BOOL=OFF 153 154//X11 Xinerama Extension support 155WANT_X11_XINERAMA:BOOL=OFF 156 157//X11 XRandR Extension support 158WANT_X11_XRANDR:BOOL=OFF

I don't have any dependencies compiled yet, so most of addons won't work. But for now, the goal is to just get Allegro running, so it does not matter.

8. Run make install

9. Compile my own test with:

emcc test.cpp -o test.html -I%PATH_TO_ALLEGRO_INCLUDE% -L%PATH_TO_ALLEGRO_LIB% -lallegro_monolith -g4

Note that there must be a space after "-o" because otherwise it is ignored (emcc isn't as robust as it should be).


The test fails for me. It says "al_init failed: 2".

Max Savenkov

That's normal. I did not check return value of al_init yesterday, and of course al_init cannot succeed since I did not provide a system driver for it!

I'm working on it. I'll update the test to reflect progress when I have it failing later that presently :)


I probably misunderstood you, you said "a single call to al_init() works" which I assumed to mean "al_init() finishes successfully".

Max Savenkov

No, it was my error. Yesterday, I thought it did finish successfully, but today I checked return value and was disappointed :) Which just shows I shouldn't really be coding at 11pm after work.

Thomas Fjellstrom

Either way, progress is progress.


I'm completely ignorant about Emscripten but it seems a lot of work to get Allegro 5 fully supported, the good think is that I think it's possible. I'm not so interested though.

I think it would be nice to have the ability to convert C code into javascript, but I can't stop thinking that if I'm using C and compiling a native game it's because it has some advantages compared to Javascript and a browser based game.

If you think about, if you create a browser game, there is no need to create a native version of it. But if you create a native game you might want to be able to run it on a browser, but if your game is able to run well on a browser why did you made it in native code in the first place? I don't know if you can understand what I'm trying to say.

In my current game for example, I'm not only using Allegro, but protobuf, sqlite, enet, etc... I think it would be impossible to magically convert my game and run it on a browser, so you might argue: "Of course not, this is something for simpler games", and then I would say, why are you using native code and Allegro when you could do it directly with "web software"?

Those are the points that are kind of confusing my about this, and always had actually. If I could just press a button and that's it my game is ready then it would be fine. But I think these tools are great for game-makers software like unity that have everything already integrated. They have the disadvantage that they limit you, but at the same time thanks to this limitations they can compile their projects in multiple formats.

Now, I still think that it would be great for a simple game made with Allegro be able to run it on a browser, but tomorrow when your friend create a game that uses networking and you won't be able to do the same with Allegro it will be reproaching you again about unity being able to do something that Allegro doesn't. :P

Max Savenkov

Well, I can see at least one benefit in compiling Allegro into JS for myself: ability to quickly demo my games via web. So maybe the final game couldn't be ever compiled to JS, but a prototype could, and that's enough for me. I'm not really interested in getting my games to run in browser, because browser games require completely different gameplay.

EDIT: Aaaaand we have working al_init! Example is updated, so you can see it for yourself. I had to write a stub for get_path. Running in browser does not provide you with much access to filesystem, so my implementation just returns "./" for any type of standard path.

Example is uploaded as a debug build, so you can step through it with Firefox web console/debugger.

EDIT2: OK, now I can create a display and even clear it to red color. That's halfway to a complete port! :P (Example updated). On a more serious note, I'll try to load and display a bitmap next.

Also, I get a lot of messages about missing OpenGL extensions from Allegro. I don't know how essential those are... Also, Emscripten does not support any fixed pipeline functions at all, so if Allegro relies on those anywhere it won't fly.


That's nice! You are actually getting somewhere.

Thomas Fjellstrom

Oh wow, I am seriously looking forward to this. I want to try my silly little Canva5 lib on it.

You may have to make a modified GL driver, base it on the generic gl/*.c code. The current mess we have in gl/* with all the ifdefs is getting kinda messy. What we need is someone to go in there and replace most of them with a single #ifdef GLES in only the absolutely required parts, and maybe simplify it into separate drivers for iphone, android and a more generic target. So the gl code should be stripped of any kind of platform specific assumptions. But that could be hard and or complex. Tedious at the very least.

Max Savenkov

I'm mostly basing Emscripten code on Raspberry Pi port, because there are more similarities between them than with Android or iPhone. Maybe I'm wrong to do it, of course, but I know little about OpenGL, desktop or ES, so I mostly copy & paste stuff, for now :)

There had been little progress today. I fixed error in display initialization and loaded a bitmap, but I can't get to appear on screen. So I have a question for those who know a bit more about Allegro internals and/or OpenGL ES.

Presently, I get this error from ogl_flush_vertex_cache -> vert_ptr_on -> glVertexAttribPointer:

Error: WebGL: vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding

It seems that this error happens, because Allegro is attempting to draw something without using VBOs, which is the only way to work with OpenGL ES2. But I have WANT_OPENGLES2 defined, and from what I can see in code, mostly the checks are for OPENGLES && PROGRAMMABLE_PIPELINE, not specifically from OPENGLES2.

Let's have a look at the code for ogl_flush_vertex_cache together:

1static void ogl_flush_vertex_cache(ALLEGRO_DISPLAY *disp) 2{ 3 GLuint current_texture; 4 ALLEGRO_OGL_EXTRAS *o = disp->ogl_extras; 5 (void)o; /* not used in all ports */ 6 7 if (!disp->vertex_cache) 8 return; 9 if (disp->num_cache_vertices == 0) 10 return; 11 12 if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { 13#ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE 14 if (disp->ogl_extras->varlocs.use_tex_loc >= 0) { 15 glUniform1i(disp->ogl_extras->varlocs.use_tex_loc, 1); 16 } 17 if (disp->ogl_extras->varlocs.use_tex_matrix_loc >= 0) { 18 glUniform1i(disp->ogl_extras->varlocs.use_tex_matrix_loc, 0); 19 } 20#endif 21 } 22 else { 23 glEnable(GL_TEXTURE_2D); 24 } 25 26 glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&current_texture); 27 if (current_texture != disp->cache_texture) { 28 if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { 29#ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE 30 /* Use texture unit 0 */ 31 glActiveTexture(GL_TEXTURE0); 32 if (disp->ogl_extras->varlocs.tex_loc >= 0) 33 glUniform1i(disp->ogl_extras->varlocs.tex_loc, 0); 34#endif 35 } 36 glBindTexture(GL_TEXTURE_2D, disp->cache_texture); 37 } 38 39#if !defined(ALLEGRO_CFG_OPENGLES) && !defined(ALLEGRO_MACOSX) 40 if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { 41 int stride = sizeof(ALLEGRO_OGL_BITMAP_VERTEX); 42 int bytes = disp->num_cache_vertices * stride; 43 44 /* We create the VAO and VBO on first use. */ 45 if (o->vao == 0) { 46 glGenVertexArrays(1, &o->vao); 47 ALLEGRO_DEBUG("new VAO: %u\n", o->vao); 48 } 49 glBindVertexArray(o->vao); 50 51 if (o->vbo == 0) { 52 glGenBuffers(1, &o->vbo); 53 ALLEGRO_DEBUG("new VBO: %u\n", o->vbo); 54 } 55 glBindBuffer(GL_ARRAY_BUFFER, o->vbo); 56 57 /* Then we upload data into it. */ 58 glBufferData(GL_ARRAY_BUFFER, bytes, disp->vertex_cache, GL_STREAM_DRAW); 59 60 /* Finally set the "pos", "texccord" and "color" attributes used by our 61 * shader and enable them. 62 */ 63 if (o->varlocs.pos_loc >= 0) { 64 glVertexAttribPointer(o->varlocs.pos_loc, 2, GL_FLOAT, false, stride, 65 (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, x)); 66 glEnableVertexAttribArray(o->varlocs.pos_loc); 67 } 68 69 if (o->varlocs.texcoord_loc >= 0) { 70 glVertexAttribPointer(o->varlocs.texcoord_loc, 2, GL_FLOAT, false, stride, 71 (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, tx)); 72 glEnableVertexAttribArray(o->varlocs.texcoord_loc); 73 } 74 75 if (o->varlocs.color_loc >= 0) { 76 glVertexAttribPointer(o->varlocs.color_loc, 4, GL_FLOAT, false, stride, 77 (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, r)); 78 glEnableVertexAttribArray(o->varlocs.color_loc); 79 } 80 } 81 else 82#endif 83 { 84 vert_ptr_on(disp, 2, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), 85 (char *)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, x)); 86 tex_ptr_on(disp, 2, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), 87 (char*)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, tx)); 88 color_ptr_on(disp, 4, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), 89 (char*)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, r)); 90 91 if (!(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) 92 glDisableClientState(GL_NORMAL_ARRAY); 93 } 94 95 glGetError(); /* clear error */ 96 glDrawArrays(GL_TRIANGLES, 0, disp->num_cache_vertices); 97 98#ifdef DEBUGMODE 99 { 100 int e = glGetError(); 101 if (e) { 102 ALLEGRO_WARN("glDrawArrays failed: %s\n", _al_gl_error_string(e)); 103 } 104 } 105#endif 106 107#if !defined ALLEGRO_CFG_OPENGLES && !defined ALLEGRO_MACOSX 108 if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { 109 if (o->varlocs.pos_loc >= 0) 110 glDisableVertexAttribArray(o->varlocs.pos_loc); 111 if (o->varlocs.texcoord_loc >= 0) 112 glDisableVertexAttribArray(o->varlocs.texcoord_loc); 113 if (o->varlocs.color_loc >= 0) 114 glDisableVertexAttribArray(o->varlocs.color_loc); 115 glBindBuffer(GL_ARRAY_BUFFER, 0); 116 glBindVertexArray(0); 117 } 118 else 119#endif 120 { 121 vert_ptr_off(disp); 122 tex_ptr_off(disp); 123 color_ptr_off(disp); 124 } 125 126 disp->num_cache_vertices = 0; 127 128 if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { 129#ifdef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE 130 if (disp->ogl_extras->varlocs.use_tex_loc >= 0) 131 glUniform1i(disp->ogl_extras->varlocs.use_tex_loc, 0); 132#endif 133 } 134 else { 135 glDisable(GL_TEXTURE_2D); 136 } 137}

All code that deals with VBOs and GL_ARRAY_BUFFER is hidden under ifdefs for desktop OpenGL. I'd like to know if I'm reading things wrong here, or if it's a real problem. I have compiled programs for OpenGL ES2 for mobile devices and they ran just fine. But maybe mobile platforms are more forgiving? Then, I'll need a separate branch specifically from Emscripten? Or one for OpenGL ES2 for all platforms, which will use VBOs?

Thomas Fjellstrom

I think its good to be correct in this case. if ES2 is specified to require Buffer Objects, then they should be used when ES2 is being used.

If possible, it might make sense to have the ES+Prog == ES2, but that could be my GL noobishness showing.

Also anything that helps clean up the GL code is a good thing.

Max Savenkov

Hm. I have to wonder. Peter Wang and Trent Gamblin shuffled these defines around in 2012 and since then they went pretty much untouched. The last comment states that "Even if using the programmable pipeline, on iOS and Android the 'else' block should always be executed.". The reason for this, unfortunately, is not provided :( I think I need Trent or someone with more knowledge than me to understand WHY should be this way, and if it applies to OpenGL ES2/Emscripten too. Anyway, I'm off for the night. I hope someone would pop into this thread to give me an advice.

As far as I can see, Allegro is using OpenGL ES 1 code path to draw things even when OpenGL ES 2 is specified, and it only works on Android/iOS because of backward compatibility or something?


OpenGL ES 2 is used with ALLEGRO_PROGRAMMABLE_PIPELINE. That define decides in general whether classic opengl (OpenGL 2.0, ES 1.0) or shaders (OpenGL 3+, ES 2). So in your case, just make sure that flag is always set.

Max Savenkov

ALLEGRO_PROGRAMMABLE_PIPELINE is set. But I can see 3 paths in this code instead of two:

   Create & use VBOs
   // Inside vert_ptr_on:
      Use shaders, but with Vertex Arrays instead of VBOs?
      Use fixed pipeline

The problem is, code path for OpenGL ES with PORGRAMMABLE_PIPELINE seems to be using Vertex Arrays instead of Vertex Buffer Objects.

Clarification: OK, now I see it. OpenGL ES 2 support using glVertexAttribPointer without bound VBO, so Allegro is right. But WebGL is a subset of ES2 and it does nnot have that ability, so there we should awlays use VBOs, unless emulation is enabled. I'll try to see if things work with emulation first, and then maybe someday think about creating a special code path for WebGL (OPENGLES@ && EMSCRIPTEN).

Edit: with full ES2 emulation enabled, errors are gone, but I still can't get al_draw_bitmap to work, it does not display anything. Off to work, will continue investigation in the evening.


Edit 2: Yay me! Bitmap drawing is working. Example updated. Do you find that hypnotic? I do! Just needs some relaxing music!

Next on "Screwing around with Emscripten": do I have everything to start running Allegro examples? Probably not, but I'll have to try to do it to see what I'm missing!

I had to put a crutch into my code for now: unless I call al_set_target_bitmap( al_get_backbuffer( pDisp ) ); after creating display, default shader is not set for the backbuffer and nothing gets drawn.

Here's a question for those in the know. Why do we first set target bitmap, and only THEN create default shader in the following code (a part of create_display)? As far as I can see, al_set_target_bitmap would be happier if we created default shader before calling it.

1 _al_vector_init(&display->bitmaps, sizeof(ALLEGRO_BITMAP*)); 2 3 if (settings->settings[ALLEGRO_COMPATIBLE_DISPLAY]) 4 al_set_target_bitmap(al_get_backbuffer(display)); 5 else { 6 ALLEGRO_DEBUG("ALLEGRO_COMPATIBLE_DISPLAY not set\n"); 7 _al_set_current_display_only(display); 8 } 9 10 if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { 11 display->default_shader = _al_create_default_shader(display->flags); 12 if (!display->default_shader) { 13 al_destroy_display(display); 14 return NULL; 15 } 16 } 17 18 al_identity_transform(&identity); 19 al_use_transform(&identity);


Edit 3: Hey! Somebody! Post something, so I could write about progress in a new post! :)

Good news: I got a simple keyboard driver working (it returns key codes in events, but not unichars or key names). To celebrate the fact, here's a port of ex_bitmap to Emscripten.

Bad news 1: Unfortunately, I don't see a way to completely abstract away Emscripten from end-user. The problem is, there is simple no way to write things like "while( true ) { // main loop }" in JS. Instead, one must use a callback. This is contrary to Allegro ideology, so I'm afraid here we're gonna let the end-user down...

Bad news 2: Emscripten does not have pthreads, so I'll have to write a new implementation for thread functions. Emscripten provides WebWorkers to do that, but they only support threading: no mutexes, no conditional variables, no nothing. So, Emscripten port is never going to be complete in this respect.

This might mean some problems for timer functions, but to be honest, I never once have used Allegro timers in my life, and Allegro threads only once, so I'll try to postpone implementation of JS threads for now, and do mouse driver next - it should be easy.

What do you think I should try next? I think sound. But sound functions will surely need threads. TTF addon? I know it is possible to compile FreeType with Emscripten, so it's doable.


An update in a separate post would be appreciated.


The problem is, there is simple no way to write things like "while( true ) { // main loop }" in JS.

You could either rely on al_wait_for_event being called by every allegro program and change that to call an update function in the system driver (that would do nothing on other platforms), or just have an explicit al_heart_beat or similar function.

About timers, having a way to insert timer events into an event queue certainly would be nice to make most of the examples work. User threads shouldn't be needed except for the few explicit threading examples.

Max Savenkov
Elias said:

You could either rely on al_wait_for_event being called by every allegro program and change that to call an update function in the system driver (that would do nothing on other platforms), or just have an explicit al_heart_beat or similar function.

I could not rely on that, since my own Allegro-based projects never use al_wait_for_event :) Maybe I should add platform specific al_emscripten_set_frame_callback.


About timers, having a way to insert timer events into an event queue certainly would be nice to make most of the examples work. User threads shouldn't be needed except for the few explicit threading examples.

Thing is, it's very easy to have timers in Emscripten. But Allegro timers explicitly rely on threads. I guess I can simply enclose platform-specific code in #ifdefs, though...


Yes, but you could make a timer driver which does not rely on threads. It's just how the existing ones are implemented. Bit nothing in the timer API itself would require a thread.

Max Savenkov

As far as I can see, Allegro does not have a timer driver per se, just some general functions, which should be platform-independent, like al_start_timer:

1void al_start_timer(ALLEGRO_TIMER *timer) 2{ 3 ASSERT(timer); 4 { 5 size_t new_size; 6 7 if (timer->started) 8 return; 9 10 _al_mutex_lock(&timers_mutex); 11 { 12 ALLEGRO_TIMER **slot; 13 14 timer->started = true; 15 timer->counter = timer->speed_secs; 16 17 slot = _al_vector_alloc_back(&active_timers); 18 *slot = timer; 19 20 new_size = _al_vector_size(&active_timers); 21 } 22 _al_mutex_unlock(&timers_mutex); 23 24 if (new_size == 1) { 25 timer_thread = al_malloc(sizeof(_AL_THREAD)); 26 _al_thread_create(timer_thread, timer_thread_proc, NULL); 27 } 28 } 29}

You can see it calls _al_thread_create to create a thread to watch over timers. I could implement _al_thread_create in a certain specific way, but it wouldn't be right. What if I decided later to add a true threading support? And anyway when I create timer in JS I need a platform-specific function which would be called for each timer. I think Allegro timers are dependent on threads in their present state. The only way to provide a set of platform-specific functions now would be to exclude timernu.c from Emscripten build and add my own file, timernu_ems.c, for example, instead.

On a brighter note:
I have mouse driver now. Enjoy a ex_mouse port to Emscripten :) It's not perfect. I haven't yet found a way to prevent middle mouse button to start scrolling, for example. And of course it does not support setting cursor position. But the basic mouse support is here.

Next: timers and sound and threads?


I don't see a problem with having a different al_start_thread implementation for emscripten.

Max Savenkov

I'll see about al_start_thread later.

For now, I wrote special implementation of timer API for Emscripten. Results are... Less than stellar. Accuracy of my timers is very shitty and they seems to experience random slow-downs and speed-ups. Later, I'll try to see if I can do anything about it, but for now, you all can check out ex_timer port.

I'm moving on to sound. My goal now is to have at least one demo project functional by the end of the weekend. I have already tried to compile "speed", but it uses some functionality of graphic subsystem which is not yet supported, and so it does not show anything but OpenGL errors in console...

By the way, makefile which is provided with speed is broken, because it does not include a4_aux in list of sources :) I realize there is a CMakeLists.txt there, but then we should either delete or fix provided makefile.


Ah, sorry, I meant al_start_timer. So exactly what you did I guess :)

Not sure why performance is so bad. Here it seems to take the event 5 seconds to get handled. I hope it's just some problem with how al_get_next_event works.

[edit2:] Actually, not at all sure what those numbers mean, that seems to be some cumulative error as it keeps rising.

Still, amazing progress.

[edit:] And thanks, I removed the speed makefile.

Max Savenkov

I have read up a bit on JS timers and I think I can do slightly better by using requestAnimationFrame mechanism. While this helps with precision, reliability remains low, because of random 200ms lags. I guess it has to be garbage collector running or something like that. I will try to investigate further later.

My current problem is with running audio update thread. Since there is no threading support in JS, there are only two things to do:

1) Run it with the same mechanism I use for timers
2) Provide a function to update audio from game's main code

After work, I'll try them both, I guess, to see which one will lead to less lags in audio output.

Edit: huh. My whole browser seem to lag randomly even when JS is not running. So it's not my code, but rather my system :) OK then, maybe someone could check out updated timer example? I'm now using more precise mechanism for it, but my computer's lags are throwing it off completely :(


Just writing to note that I would also be interested in seeing Allegro5 compile with Emscripten. Mostly in simple graphics and mouse interaction. I hope to be able to help test things starting from next week. Can't offer more for now, sorry!


On my system, the total error and event overhead are always approximately the same number. If I don't do anything but have it running, they are approximately zero, but as soon as I start moving my mouse they both skyrocket and take a long while to get back down.

Append: This is probably due to how firefox handles javascript, but they also both steadily rise while I'm on another tab.

Max Savenkov

Gassa, thanks, I'll try to put up more working examples during weekend for testing.

J-Gamer, I can't see a direct correlation between mouse movements and timer lags, although there could it something in it. According to this numbers, event overhead grows too much. I'll have to look into it.

So, for today, I have nothing to show you, because I wasn't able to get OpenAL to work. Example compiles and runs, but no sound is produced. I'll try to get it working tomorrow or the day after (tomorrow is a D&D day, so I'll be away for quite a while :) ).


Are you using emscripten_get_now() for timing?

If I'm not mistaken that makes use of Date.now rather than Performance.now.

Max Savenkov

I was using al_get_time, which called gettimeofday, which is implemented through Date.now in emscripten.

I wrote a Emscripten-specific implementation of al_get_time(), which now calls emscripten_get_now().

It improves things, but precision is still bad: instead of steady 20ms ticks, I'm getting from 10-40ms, but I guess that's just the way with browsers...

Also, another problem appeared, and it's a bigger one: now I'm getting several timer events per one call to the main function. With unmodified ex_timer, that leads to freeze, because it tries to repaint screen several times per one frame function call, and JS simply can't stand it. I added code to only repaint screen once (but update statistic correctly). The result is here: ex_timer_r.

Edit: OK, we have sound. As with everything else, it seems a bit off, with little glitches here and there, but it works. Check out port of ex_audio_simple. Web Audio API seems yet to be not-quite supported by everybody, but it should work in Firefox and probably Chrome.

Getting sound to work was an exercise in heroically overcoming problems I have created for myself. Several hours were to lost to the simple fact I have not been passing further argument when restarting timer...

Anyway, with graphics, primitives, mouse, keyboard, timers and sound more-or-less working, I thought it would be time to move on to something more complex, namely demo projects.

My first idea was to port Speed demo. But it does not really lend itself to Emscripten, because it has A LOT of function with endless loops inside. Also, its init_sound crashes JS runtime with out-of-memory exception for reasons I can't discover from a quick look.

So, I'll try to get Cosmic Protector or Skater to compile and run tomorrow. It seems that Cosmic Protector at least have less endless loops to take care of, although it's still not just one. I'll have to compile libpng, libjpeg and probably libzip into Emscripten to do it.

If all else fails, I'll try to write a simple game myself, maybe a Tetris variant :) Just to demonstrate to myself and everyone else that everything works (and fix things that do not work).

Edit2: Cosmic Protector proved to be not very portable either, but Skater is a very well-written game and I was able to get it running in browser! Unfortunately, I ran into problems with sound. It uses streaming, and streaming relies on general-purpose threads. I could just replace threaded code with timed function calls, like I done in other cases, but there are too many places to fix. So now I'm thinking about writing threads implementation (via timed functions, of course). An acquaintance of mine who knows somebody in Mozilla dev team told me they are going to add full pthread support in Emscripten, but I'm not even sure how they could do it.


I tried ex_timer_r, here is the stats text at the top - I don't know what to look for in there.

Firefox 28: {"name":"timer_r.firefox28.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/7\/77df60eeb568d77acb7baef65da7c177.png","w":785,"h":109,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/7\/77df60eeb568d77acb7baef65da7c177"}timer_r.firefox28.png

Chrome 34: {"name":"timer_r.chrome34.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/c\/1cb1d053b923050a0af2574f85e9486a.png","w":548,"h":94,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/c\/1cb1d053b923050a0af2574f85e9486a"}timer_r.chrome34.png (apparently the resolution is lower here)

The lines appear jagged sometimes (bottom one step ahead of top). That may be the monitor (60Hz LCD) syncing in the wrong moment.

By the way, if there is any relevant textual debug information (such as max error), it would be nice to dump it in the text console below, making it easy to copy and paste.

ex_audio_simple seems to correctly play several sounds in parallel when I press "1" a few times.

Max Savenkov

Thank you. There will be more troubles with timers, I guess, but for now they are good enough.

Anyway. I have an ANNOUNCEMENT! Ready? Aw-right! I have a (nearly) fully-functional Skater demo for you to try. The first Allegro game to run in browser. Controls, sound, music and graphics, everything should work. Just don't try to change graphic parameters in Options :) Oh, and another thing. I haven't yet found a way to let KeyPressed event happen, unless I let the browser process KeyDown event after I'm done with it. And I need KeyPressed, because it's the only event that has unicode value of key in it, and Skater, somewhat strangely, relies on those for menu navigation instead of keycodes. This means that the browser would scroll the window when you press up, down, left or right, which could be a big problem if you have lower resolution monitor and a lot to scroll. This couldn't be helped for now, but know that I'm aware of the problem is working on it.

Go on, try it: Skater demo (14Mb).

Implementation details: I had to write universal thread emulator which implements custom _al_create_thread function to insert a new timer into browser's queue, which calls thread procedure. This requires modification in thread's procedure, as it can no longer run in an endless loop. I have modified _al_kcm_feed_stream to work in this manner and it seems to be more or less OK.

Arthur Kalliokoski

I just tried it in FF 24.1.0 on Linux and nothing happened. Then I told NoScript to allow the entire page, and besides taking up 200Mb memory, even more nothing happened. OTOH, this FF can't even render the wiki properly. :-[

Max Savenkov

It is possible that FF 24 is not supported. HTML5 is evolving standard, and version 24 may not have everything this game requires :( I only tested in on the latest version (28.0) and latest Chrome. Also, this things eats up a LOT of memory. My Firefox's footprint grows to as much as 1.5Gb when the game is running.


Amazing work! It works fine here in Firefox 25.0 - only strange thing is that it runs in a tiny square area. Still, works really well, including music and sound. I get close to 60 FPS if there's no water and about 30 FPS if there's a lot of water.


Works fine on my FF 28.0, good job!
It feels like it is leaking some resources though since the framerate gets progressively worse the longer you play.


MAN! Yhea! it works pretty well here on Chrome, sound and everything.

As Elias says only on a small rectangle but yhea! Good work!

Matthew Leverton

Wasn't expecting to see this much progress. >:(

Max Savenkov
Elias said:

only strange thing is that it runs in a tiny square area. Still, works really well, including music and sound.

I had a feeling something was wrong with canvas size, but only now I understood it is square instead of rectangle! :) Ain't I'm a sharp-eyed little Indian... From a quick look, I can't see why is that (everywhere, width AND height are passed correctly as far as I can see), so I'll have to look further into it. This will be the first priority.

It feels like it is leaking some resources though since the framerate gets progressively worse the longer you play.

I'll check this out. Haven't noticed this myself, but maybe I just didn't play for any prolonged period of time.

Wasn't expecting to see this much progress. >:(

Yeah, man, I'm on roll! :) (and I have a deadline: this game jam I want to use Allegro in starts the next week)

So the plans for the nearest future:

  • Fix keyboard problem

  • Find out why canvas is rectangular

  • Find out why Fullscreen button does not work (if it should)

  • Check out performance problems and possible resources leaks

  • Compile Freetype and make TTF addon work

  • Compile libjpeg or learn to use native browser's image loaders (maybe a sound loader too)


W00t! I am also amazed at this rate of progress, REALLY good job, here on Win7 Firefox 28.0 work nicely well, with occasional glitches and an hung script (which I stopped, then all ran fine.


Also, this things eats up a LOT of memory. My Firefox's footprint grows to as much as 1.5Gb when the game is running.

...makes me wonder, is it worth it?

Everybody says that game in browser means instant universal portability [warning: actually an hyperbole], but a 1.5GB memory footprint for skater.....hmmmm....


Yay, Skater example is working!

Chrome 34: ~300 Mb per tab (my Chrome runs a separate process for each). ~60 FPS with a single tab, but 10-30 FPS when I open the game in two tabs simultaneously.

Firefox 28: 100-200 Mb per tab. ~60 FPS in active tab, 0 FPS in other tabs. Occasional stumbles in generally smooth reaction.

What's the name of that game jam, by the way?

Also, do you already have some instructions beyond these to share with people on this path?


Superb, seems to run fine in FF28.0 under Xubuntu

Max Savenkov
pkrcel said:

Everybody says that game in browser means instant universal portability [warning: actually an hyperbole], but a 1.5GB memory footprint for skater.....hmmmm....

I might have quoted a figure for debug build with excessive debug information (line numbers). Just the js file is ~14Mb in that case. Or maybe there is a resource leak... Anyway, Gassa here reports a far more reasonable 300Mb per instance of game. There is a param build process which controls how much memory will be allocated for application. I have set it to 128Mb for Skater (which might be excessive).

Gassa said:

What's the name of that game jam, by the way?

GamesJamGAMM (page in Russian). I do not have high hopes for myself in it, because I will not be able to take a break from my day job during the jam, but I thought I still should give it a try, make something small and hopefully interesting.


Also, do you already have some instructions beyond these to share with people on this path?

Instructions alone won't help. I had to write some new code for Allegro and also modify some existing code. After I have ironed out the worst bugs, I hope to submit my work to Allegro developers list and see if it can be integrated as one of "official" platforms for Allegro.

I'm not sure if it really can be a part of main Allegro distribution, because it will not be possible to just take any old Allegro-based game and compile it for web, so it kind of break Allegro's abstraction (unless I can find a way to fix this). Even then, I can distribute my modifications separately, if necessary, for those who want them, in the same way Allegro bindings for other languages are distributed.

In any case, I will make my code available for everyone as soon as I'm not ashamed of it :)

Edit: I haven't touched the code much in the last two days due to a visit to a dentist and overall laziness, but I fixed two issues: arrow keys no longer scroll browser window when pressed and canvas is now rectangular instead of square.

The first issue is a problematic one. To prevent browser from reacting to its own set of keys/hotkeys, I must filter them out inside KeyDown handler. But which hotkeys should I filter? For example, F5 usually reloads page. I don't want to filter it, because it might be useful for a developer, or confusing to user. On the other hand, what if you REALLY want to use that key in your game, and so need to prevent browser from reacting to it?!

The only way to handle this properly that I can see is to block some browser keys (namely, arrow keys and maybe backspace, which acts as a hotkey for Back button) by default, but add a platform-specific function which will allow user to expand list of filtered keys as needed by his game. Something like al_emscripten_filter_key( int keycode, bool onoff );

The second issue was, actually, a bug in Skater! Code in globals.c (read_global_config)

   window_width = get_config_int(c, "GFX", "window_width", window_height);
   window_height = get_config_int(c, "GFX", "window_height", screen_height);

should instead read

   window_width = get_config_int(c, "GFX", "window_width", window_width);
   window_height = get_config_int(c, "GFX", "window_height", window_height);

Also, I have reduced reserved memory size from 128Mb to 32Mb for this demo. I could find no evidences of memory leaks, so I think we're safe on this from for now.

Skater demo is updated. That's all for tonight.


Now the Skater demo takes more than my full screen height (1920x1080 here; it may do with the fact I have 148% Windows display scale - Set custom text size in display options). And it gets twitchy. Approximately around when I get to the letters "Allegro", it feels like 10 FPS at times, but still reports 55-60 FPS. Firefox 28.

In Chrome, all is still well.

Anyway, thank you for sharing what you have so far, and for the game jam link.

Edgar Reynaldo

Can't get the latest skater demo to run in SeaMonkey. May have to do with the fact only OpenGL 2.0 is supported by this laptop.

Really impressed with all you've put together so far. The times they are a changin...

Max Savenkov

Edgar, could you look at output in Developers Console (If SeaMonkey has one)? What does it say? The usual Allegro log output goes there, as well as browser errors.

Thomas Fjellstrom

Sound is choppy here (to be expected), but it seems to play pretty good! Nice work Max!

Trent Gamblin

Sounds work here. It starts off at 60FPS then if you go deeper into the level it goes down to 30 and in some spots 20. Core i7 2.0GHz with Nvidia 740m. I don't know what's the point, but I guess it's cool?

EDIT: I'm researching this some more, and ya, it is kind of cool. You said games can't be ported as-is, what does that mean? What kind of changes are involved?

Edgar Reynaldo

Max, here's the console output when I run it on my laptop :


change_gfx_mode1: 1024 768
change_gfx_mode2: 1024 768
Initialized canvas 1024 768
Could not create canvas: ?,:(

Edit - you meant the error console. Here :

Max Savenkov

Sorry for late answers, everyone, I've been busy for a while.

EDIT: I'm researching this some more, and ya, it is kind of cool. You said games can't be ported as-is, what does that mean? What kind of changes are involved?

I wrote about this before, but I'll repeat it here: because of nature of JavaScript, you can't write endless loops.

Most Allegro games are structured like that (simplified):

    while( !exit )

In JS, you'll have to replace endless loop with a call to emscripten_set_main_loop, which will set it up so browser will call your frame function whenever it's going to draw a frame. The code, therefore, will look like this:

1frame_func() 2{ 3 do_game_stuff(); 4} 5 6main() 7{ 8 init(); 9 10 // if the last argument is 1, this call will not be finished until 11 // the game stops (via call to emscripten_cancel_main_loop), so the 12 // cleanup code after it won't be executed too early. 13 emscripten_set_main_loop( frame_func, 0, 1 ); 14 15 cleanup(); 16}

If your game is set up in this way, it will be very easy to port it, only a small change required. But if you have multiple nested endless loops, like Cosmic Protector demo, for example, then you're in trouble. Such code would be very troublesome to port:

1 2void doMenu() 3{ 4 while( !exitMenu ) 5 { 6 al_wait_next_event( &queue, &event ); 7 ... 8 } 9} 10 11void doLevel() 12{ 13 // A lot of other nested stuff. 14} 15 16void doGame() 17{ 18 if ( doMenu() ) 19 { 20 doLevel(); 21 } 22 23 doRestartTransition(); 24} 25 26main() 27{ 28 init(); 29 while( !exitGame ) 30 { 31 doGame(); 32 } 33}

Max, here's the console output when I run it on my laptop :

Oh, yes, indeed it can't initialize OpenGL. Windows laptops aren't known for good OpenGL support, unfortunately.

For the last few days, I've been busy with one task only: compiling FreeType for Esmcripten. This was the worst piece of experience with a combination of open-source software I've had in a long while. Anyway, I have a result. Namely, ex_ttf running in browser. Take your time to enjoy, I've sweated for it :)

If you want some details (and even if you don't), I'll oblige. What went wrong: everything. For one, FreeType is the only Allegro dependency I know that absolutely HAS to use ./configure and does not have even a 3rd-party CMake file (this saved me with Ogg/Vorbis and libpng).

You can't run ./configure script in Windows, of course, unless you use MinGW or cygwin. Unfortunately, they do not help in this case, because we're cross-compiling for a system that is unknown to ./configure (and therefore we can't easily specify it via --host=tiple). This leads to a problem whenever ./configure tries to compile a native executable and run it (for FreeType, there are around 3 such calls).

The only way I found was to completely remove this checks from ./configure. As you may know, editing a ./configure script by hand is not a job for weak of heart. Anyway, I've done it and it didn't help me much. Now I had a Makefile, but it was a broken one. I suppose that was because it was generated by MinGW, but used by Emscripten's Python scripts, and they couldn't agree on slashes/backward slashes. Or something. At this point, I gave up on compiling FreeType on Windows and decided to try to compile in under Linux instead (here's a magic of JavaScript: I could easily use resulting file under Windows!).

I had two distros installed in VirtualBox: Mint 12 and Mageia 2. Both quite old, from my previous attempts at compiling pet projects for Linux (successful, but ultimately abandoned). I've downloaded and compiled all necessary tools... And hit a brick wall. In both distros, clang compiler was broken! It could not find some gcc libraries (libgcc.a and some others), because it tried to use hard-coded paths or something like that. There were bugs filled in both distros' trackers, but they weren't conclusively resolved.

To cut the story short, I've deleted both VMs and installed one with KUbuntu. After that, it was only a matter of few hours to compile Clang with fastcomp support (which is needed for emscripten, but isn't in upstream Clang yet) and then finally compile FreeType.

So there you have my story of woe and troubles.

Game Jam I was porting Allegro for begins tomorrow, so I do not expect to have much free time to post new examples here or port features, or for anything, really, but I promise to be back after that with sources and a patch for GIT version of Allegro.

Trent Gamblin

Thanks for the explanation. That's not too bad of a restriction. It's good to structure your code like that anyway. It might be hard to make a game that has both web and desktop versions that share the same code... if you started out with the intention of making a web-based game then both would work but it's not ideal. Anyhow, I think this is pretty cool...

EDIT: I don't think it's a good idea to put in Allegro git right now. I think we need a feature freeze for 5.2, then we can consider it for 5.3.


Nah, just let's put it into git, that's what it is for. We're very far away from 5.2 after all, at least a few years.

But only if the code is clean of course. Last thing we need is any more code where someone just made something work quickly instead of doing it properly and at least documenting what everything is for.


Good luck at the Game Jam!

Max Savenkov

EDIT: I don't think it's a good idea to put in Allegro git right now. I think we need a feature freeze for 5.2, then we can consider it for 5.3.

Elias said:

Nah, just let's put it into git, that's what it is for. We're very far away from 5.2 after all, at least a few years.

But only if the code is clean of course. Last thing we need is any more code where someone just made something work quickly instead of doing it properly and at least documenting what everything is for.

I'll get the patch ready anyway, so it could be applied now or later. I'll need to clean up code some, and fix build system. But I was hoping that maybe if it was in git other people would help to fix things I don't know how to fix (like usage of vertex arrays and newly-discovered absence of support for mipmap generation - which SHOULD be there, so there is a problem with detection of OpenGL extensions somewhere, I think). Of course, I'll defer to community judgement on the exact moment of inclusion into git.

Gassa said:

Good luck at the Game Jam!


Trent Gamblin

We can have 5.2 out within months if anybody would help with it. This is definitely not a 5.2 feature if you ask me, but Peter is the release manager so it's up to him. I most definitely don't want to maintain this feature.

That said, what you mention about "working quickly" is definitely right and this doesn't work well at all. I get 400 FPS in the worst parts of Skater in a real program and 20 FPS with this. The whole thing is entirely a hack (running C code compiled to JavaScript) and should be considered much lower priority than a stable 5.2 release.

Max Savenkov

I actually agree that this is not for 5.2. As far as I understand, the main focus for 5.2 was support for mobile platforms (especially Android), and there is no need to take away manpower from it (such as it is). Emscripten support certainly isn't ready for prime-time right now.

As for 5.2... Could anyone point me to List Of Things That Absolutely Have To Be Done For 5.2? I've checked out some bugs in tracker, but I'm not sure how to help.

I'm quite good at debugging things, no so good at architecture.


Here's the planned features for 5.2, although they're not completely set into stone:


As for this Emscripten port, it is a hack but it's a potentially useful one. We can import it on an "experimental-emscripten" branch of the 5.2 develop branch and leave it in the repo like that for future reference. Then we can get started on the real 5.2 work.

Edit: sorry to bring this up again, if you work on Windows and/or OSX, then please help me with the port of the force feedback (haptics) to those platforms. I'll send you a free haptics enabled joystick for testing and to reward your efforts if you do. You could take a look at the SDL haptics implementation and adjust that to the Allegro internals and API requirements.

Arthur Kalliokoski

I rebooted to Mint, FF28 worked ok (video noticeably choppy but not irritating, sound choppy, 30'ish FPS, used about 20Mb memory), then I tried Chrome 34. Chrome took a minute to actually start downloading, then the download rate became rather sparse and erratic. I noticed both cores were just about maxed out, one was Chrome itself and the other didn't associate to a process so it was some kernel thing. Killing Chrome left one core still grinding, killing FF brought CPU down to normal. Then starting up Chrome to try it without FF running brought up a "He's dead, Jim" out of memory error even though the system monitor thing said I was only using ~1 of the 2 gigs memory I have. I tried it one more time in FF without Chrome and the CPU went back down to normal after closing the skater tab.

TL;DR Chrome ran out of memory.

Max Savenkov

My GameJamGAMM entry. It's yet in early stage (as of 24.04.14), and there is not much gameplay :)

Also, I've hit a bug with TTF handling (different font sizes do not seem to work and the last letter of text seems to be chopped of sometimes).

Development period ended, final build uploaded. Check it out! There are some bug already, but I hope nothing too critical... Developing an RPG in 7 days of which I had only 2 to work full-time was an... interesting exercise. I do not have hight hopes of winning (other projects offer much better visuals, at least, and far more casual-friendly gameplay; I might overdid hardcore a bit, or, to say the truth, borked up the balance some), but it's all right. At least, I have tested some of my gameplay ideas. Next week: back to Allegro Emscripten development!

A small update: With help from FreeType and Emscripten developers, I have found a fix for error in drawing TTF fonts. This is a problem with FreeType which was found about a year ago (function signatures do not match, but C compiler allows this; Emscripten, not so much), but still hasn't been fixed in current version. It's quite easy to fix with a simple patch. Which means I can continue my work on the rest of the port.

Thread #614119. Printed from Allegro.cc