Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » Experiments: Allegro + Emscripten.

This thread is locked; no one can reply to it. rss feed Print
 1   2   3 
Experiments: Allegro + Emscripten.
Max Savenkov
Member #4,613
May 2004
avatar

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.

AMCerasoli
Member #11,955
May 2010
avatar

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
Member #4,613
May 2004
avatar

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

if(NOT IPHONE)
    test_big_endian(ALLEGRO_BIG_ENDIAN)
endif(NOT IPHONE)

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:

#SelectExpand
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).

Aikei_c
Member #14,871
January 2013
avatar

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

Max Savenkov
Member #4,613
May 2004
avatar

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 :)

Aikei_c
Member #14,871
January 2013
avatar

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

Max Savenkov
Member #4,613
May 2004
avatar

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
Member #476
June 2000
avatar

Either way, progress is progress.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

AMCerasoli
Member #11,955
May 2010
avatar

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
Member #4,613
May 2004
avatar

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.

Aikei_c
Member #14,871
January 2013
avatar

That's nice! You are actually getting somewhere.

Thomas Fjellstrom
Member #476
June 2000
avatar

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.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Max Savenkov
Member #4,613
May 2004
avatar

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:

#SelectExpand
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
Member #476
June 2000
avatar

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.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Max Savenkov
Member #4,613
May 2004
avatar

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?

Elias
Member #358
May 2000

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.

--
"Either help out or stop whining" - Evert

Max Savenkov
Member #4,613
May 2004
avatar

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

if (!OPENGLES && !MACOSX) && PROGRAMABLE_PIPELINE
{
   Create & use VBOs
}
else
{
   // Inside vert_ptr_on:
   if PROGRAMMABLE_PIPELINE
      Use shaders, but with Vertex Arrays instead of VBOs?
   else
      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.

#SelectExpand
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.

ks
Member #1,086
March 2001

An update in a separate post would be appreciated.

Elias
Member #358
May 2000

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.

--
"Either help out or stop whining" - Evert

Max Savenkov
Member #4,613
May 2004
avatar

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.

Quote:

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...

Elias
Member #358
May 2000

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.

--
"Either help out or stop whining" - Evert

Max Savenkov
Member #4,613
May 2004
avatar

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:

#SelectExpand
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?

Elias
Member #358
May 2000

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

--
"Either help out or stop whining" - Evert

Max Savenkov
Member #4,613
May 2004
avatar

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.

Elias
Member #358
May 2000

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.

--
"Either help out or stop whining" - Evert

 1   2   3 


Go to: