Friday, May 24, 2013

Calling a C function from Javascript in your Emscripten program

One thing you may want to do is pass dynamic content into your Emscripten program. This is possible! I'll show in a little bit.

A little background

I am in the process of writing a program in emscripten - this is a little different then what most people do, which is port an existing project into emscripten. When you port into emscripten, you can package all of your content (images, soundes, etc) into the build. This works out pretty well for most C programs as they tend not to interact with external pieces. Say you write a notepad app - it is just interacting with the file system or if you write an asteroid game, all of the content is static and doesn't rely on external dynamic content. For my program, I want to access an image that can change and isn't bundled with the app.

When emscripten was first released I could lazy load it. Lazy loading loads it byte per byte on demand from a location on the web. This is no longer supported though. For me lazy loading isn't really ideal either for a couple of reasons. First it would be syncronous which would stop other parts of my program from loading while it fetched a chunk of the image. Secondly I don't want to deal with writing code to decode an image! It's not 1995 all over again! I'd prefer the browser to decode the image and send me the data in rgb32. So my solution is to have javascript load the image, map it to a canvas object, then use the canvas to pass into my program the rgb32 array. Simple enough right!

Let's dig in and figure out how to call a C function from js, pass it some paramaters and have the program react to those arguements!

Calling a C function from Javascript

1) First, create a function in a .c file or tag a function with extern "C". This is what you will be allowing to be called from javascript. Extern "C" will prevent name mangling c++ does. All exported functions need to retain their original names to be called from javascript.

Here is a function I exported:















2) Second, you'll need to create some variable to interact that is global. For an archery game, I created a CGame object that is accessible everywhere. You may have a CApplication object. Whatever makes sense for you, but somehow you need to interact with the state of the app before you leave your C style function.

3) The build command must export the function. If you don't do this, the compiler will see it is not used and remove the function. When you export this function, the hidden gotcha is you need to export your main() function as well to continue to allow your program to work as it was before - that is assuming you have an application. Here is what I added to my build command to export main and imageloaded:


~/emscripten/emscripten/emcc main.cpp javascriptmapper.c game.cpp ShootingScreen.cpp drawing.cpp mainmenu.cpp -o /var/www/html/archery.html -s EXPORTED_FUNCTIONS="['_imageloaded','_main']"

Note! The magic emscripten is doing in the background is prefixing functions with an _ so they don't collide with other function names. That is why when you export them you add an _.

4) Call the function in javascript. The easy way to test this is load up your html program, then run the debugger in your browser using the f12 key. Go to the console, and run this javascript:













That's how you can call your function in javascript code. I changed imageloaded to return the integer 5 and you can see that result.

There is another way to call functions that is more performent when calling a function lots of times. I would check out the emscripten documentation for how to do this and also check out  the documentations for  how to send in parameters.

Here is a link:
https://github.com/kripken/emscripten/wiki/Interacting-with-code





1 comment:

  1. Link updated:
    http://kripken.github.io/emscripten-site/docs/coding/connecting_cpp_and_javascript/Interacting-with-code.html

    ReplyDelete