diff --git a/.gitignore b/.gitignore index eaa1ecef0e..d7b5b447ef 100644 --- a/.gitignore +++ b/.gitignore @@ -71,5 +71,11 @@ cinderConfig.cmake blocks/ !blocks/[__AppTemplates,Box2D,Cairo,FMOD,LocationManager,MotionManager,OSC,QuickTime,TUIO] +# Emscripten +lib/emscripten/libcinder_d.bc +#lib/emscripten/libboost_system.bc +#lib/emscripten/libboost_filesystem.bc +.vscode/settings.json +node_modules #ImGui stored settings -imgui.ini +imgui.ini \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 11f60981cd..f407906f9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,8 @@ elseif( CINDER_ANDROID ) include( "${CINDER_CMAKE_DIR}/platform_android.cmake" ) elseif( CINDER_MSW ) include( "${CINDER_CMAKE_DIR}/platform_msw.cmake" ) +elseif( CINDER_EMSCRIPTEN ) + include( "${CINDER_CMAKE_DIR}/platform_emscripten.cmake" ) else() message( FATAL_ERROR "no target defined for system: '${CMAKE_SYSTEM_NAME}.'" ) endif() diff --git a/docs/htmlsrc/guides/emscripten/config.json b/docs/htmlsrc/guides/emscripten/config.json new file mode 100644 index 0000000000..fdcab920f1 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/config.json @@ -0,0 +1,83 @@ +{ + "data":{ + "metadata": + { + "keywords": ["guide, emscripten"] + }, + "nav":[ + { + "label": "Introduction", + "link": "index.html", + "pagenav":[ + + ] + }, + { + "label": "Installation", + "link": "part1.html", + "pagenav":[ + + ] + }, + { + "label": "Getting started", + "link": "part2.html", + "pagenav":[ + + ] + }, + { + "label": "Possible issues", + "link": "part3.html", + "pagenav":[ + + ] + }, + { + "label": "Deployment", + "link": "part4.html", + "pagenav":[ + + ] + }, + { + "label": "Working with the Web", + "link": "part5.html", + "pagenav":[ + + ] + }, + { + "label": "Interesting Web technologies", + "link": "part6.html", + "pagenav":[ + + ] + }, + { + "label": "Tips", + "link": "part7.html", + "pagenav":[ + + ] + }, + { + "label":"FAQs", + "link":"part8.html" + }, + { + "label":"ci_emscripten_app", + "link":"part9.html" + }, + { + "label":"emscripten::val", + "link":"part9.5.html" + } + ], + "seealso": + { + + } + } + +} diff --git a/docs/htmlsrc/guides/emscripten/index.html b/docs/htmlsrc/guides/emscripten/index.html new file mode 100644 index 0000000000..9fe414539f --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/index.html @@ -0,0 +1,64 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+ + +

Cinder Emscripten Guide

+

Cinder now supports building for Emscripten as of version (todo : add version number ). This allows users to open up their Cinder applications to the world wide web!

+ +

But what is Emscripten exactly?

+

Emscripten is a toolchain for compiling to asm.js and WebAssembly, built using LLVM, that lets you run C and C++ on the web at near-native speed without plugins.

+

In essence, it's simply a tool that lets you treat the web as another compilation target. A large chunk of the work was already done thanks to the efforts of Hai Nguyen (@chaoticbob), this latest version builds on top of that by adding some additional features such as video support.

+ +

How it works

+

You can treat your Emscripten project pretty much like any other CMake based Cinder project, you just need to run a slightly different command than what you might be used to.

+ +

Whats known to (not)work

+

A large chunk of what you know about Cinder should mostly be transferable directly when building with Emscripten in mind, so with that said, it is perhaps easier to instead list all currently known un-supported features

+ +

Demos

+

You can find some of the original demos here

+

To get started continue on to installation instructions.

+
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part1.html b/docs/htmlsrc/guides/emscripten/part1.html new file mode 100644 index 0000000000..2c54613d16 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part1.html @@ -0,0 +1,115 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+

Getting things set up

+

There are number of things you'll need to do in order to get things set up to build with Emscripten. If you're already familiar with CMake projects and how those work, then this will likely not be new for you as the process for running an Emscripten project is nearly identical.

+

System requirements

+

In terms of hardware requirements, this should work on any system that supports Cinder and Emscripten.

+ +

Browser support

+

Browser support can be a little tricker. You technically just need a browser that can support WebGL 2 but even if there is support, sometimes different browser developers enable/disable different things. That being said the recommended browsers are Firefox or Chrome.

+

+ When running your application
+ To run your Cinder applications, while not strictly necessary, it's recommended to host on a server that can serve files with the mime type application/wasm +

+

If your server does not support that mime type, you will still be able to run your app, but your bundle won't be able to compile things as efficiently.

+ + +

Downloading the essentials

+ + +

Once you have all that...

+ +

Building Cinder

+ + +

Updating your systems PATH variable

+

This isn't entirely necessary it will be useful to add the path to your emsdk folder to your system's PATH variable to make it easier to run commands.

+

Now we can start on to building an actual projecct.

+ + +

Known working configurations

+

This has been tested with the following configuration

+ + +

In the initial explorations of the Emscripten codebase, an older version was used; as of roughly 10/2019, a newer compilation engine was developed and integrated.

+

If you would like to try the older version, remember to add -fastcomp to your emsdk commands

+

The emsdk help command will mention fastcomp as well.

+
+ + + + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part2.html b/docs/htmlsrc/guides/emscripten/part2.html new file mode 100644 index 0000000000..f80e42f809 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part2.html @@ -0,0 +1,93 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+

Building an Emscripten project.

+

Building a project that targets Emscripten is a lot like building a project that builds with CMake. That being said, there are some very subtle differences.

+ +

Creating a project structure.

+

You can start off by generating your project with Tinderbox, like you might already be doing. Now if you haven't worked with Cmake before, you'll also have to make some kind of "build" folder, basically a place where your compiled files will get output to; the common practice is to just have a folder called build at the root of your project(note you can name it something other than build if you want)

+

Next, you'll need a CMakeLists.txt file that will describe how to build your project. If you've never worked with CMake before, you can check out any of the samples in samples/_emscripten which will have CMake files available. If you're familiar + with CMake and want to write everything by hand, grabbing the CMakeLists file that builds Cinder is a good starting point to see what flags and settings need to applied to build for Emscripten.

+

Now we can move onto actually building a project.

+ +

Building a project

+

To build your project, from within your build folder(note I'm assuming it's within the root of your project)

+ + +

Running your project

+

Running your project is fairly straightforward. You'll need to serve your project from a server somehow, one that can support the mime type application/wasm(though note this kind of server is not strictly necessary but it may provide better performance)

+

There are a multitude of ways to do so, but perhaps the simplist solution is to borrow the built-in server on good ol' Python

+ + + + + +

ci_emscripten_app

+

See the ci_emscripten_app section for a more in-depth look as to the options and other functionality + it can provide.

+

If you've been using ci_make_app, the functionality and usage is very similar. + Check out /proj/cmake/cinderEmscriptenApp.cmake to see what the function looks like. All options have comments describing what they are for.

+ +
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part3.html b/docs/htmlsrc/guides/emscripten/part3.html new file mode 100644 index 0000000000..d26d479699 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part3.html @@ -0,0 +1,62 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+

Potential issues

+

While things do basically appear to be working, there are some things that could potentially break things depending on what you're doing

+ +
    +
  1. +

    Including Freetype's ftlcdfil.c file will cause a link error when building Cinder which states `ERROR: Linking globals named 'ft_lcd_padding': symbol multiply defined!`

    +
  2. +
  3. +

    + Shaders are currently not detached after creation due to a possible bug Emscripten that essentially sets the shader handle to null. +

    +
  4. + +
  5. +

    Due to changes in the WebAudio ecosystem and the preference of the web world for using the AudioWorklet api, there is currently no built-in audio support as the + AudioWorklet api relies heavily on writing Javascript which does make it more difficult to fully integrate. Please see part 6 for more information. +

    +
  6. + +
  7. +

    When doing TransformFeedback, you have to remember to unbind your transform feedback buffers. It is unclear as to why this is a requirement but it appears to be an underlying Emscripten issue.

    +
  8. +
+
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part4.html b/docs/htmlsrc/guides/emscripten/part4.html new file mode 100644 index 0000000000..4472e325e5 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part4.html @@ -0,0 +1,71 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+

Javascript

+ +

If you're including any Javascript support files for your project, keep in mind that when building in release, the currently shipped version of Uglifyjs that comes with Emscripten appears to not like some ES6 semantics like the arrow function (()=>{})

+ +

In addition to that, if you add supplementary Javascript to your project and compile a release build, you'll likely need to add an externs file. In your CMakeLists.txt file you can add

+ +

+ list(APPEND EMCC_CLOSURE_ARGS "<path to your externs file›") + +

+

+ If you've never used an externs file, the idea is pretty straightforward. For every function and variable and object in your project you just need to add the basic definition. You could think of it as Javascript's forward declaration mechanism.

+ +

Cinder for example, includes a helpers.js file when dealing with video. In it there is a variable called window.CINDER_VIDEO which looks like

+ +

+ + createVideo:function(){ + ... more code + +

+

In the externs file, all I would need to declare is window.CINDER_VIDEO = {} since window.CINDER_VIDEO is a Javascript object. If it were a function it would look like window.CINDER_VIDEO = function(){}

+ + +

Autoplaying media in Chrome

+ +

In Chrome - auto-playing of media was disabled in May / 2018. + See + this article from ArsTechnica + as well as this tweet from Twitter user Cabibbo

+ +

You'll have to do some sort of interaction before things will start playing.

+
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part5.html b/docs/htmlsrc/guides/emscripten/part5.html new file mode 100644 index 0000000000..8eccc698c9 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part5.html @@ -0,0 +1,69 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+

Things to remember when deploying to the web

+

The web is ultimately a different world altogether compared to the world of desktop and mobile development. There are some special things to take care to remember when dealing with Cinder Emscripten.

+ +

Output file size and how to serve smaller files over the web.

+ +

The output of WebAssembly files is generally quite large. It's probably not going to be a big deal if you're just doing an installation but if you intend to distribute your project to the world, it could be worth thinking about.

+ +

The most common way of reducing the file size of your output is to ensure that you build your WebAssembly bundle with optimizations, which can be included by adding -s WASM=1 -Os -g0 flags to your project's CMake file. + (if you're using ci_emscripten_app, this will happen automatically when building in Release mode)

+ +

See here for more information

+ +

Re: External media that's not on the URL / server you're deploying on

+ +

Note that due to how browsers work, with the exception of some built-in elements like the image tag, by default, you cannot grab assets directly from another server different from the one you're deploying on. This is known as a Cross Origin Resource Sharing and it is normally not allowed.

+ +

If for some reason you must absolutely store your content on another server, you'll need to ensure that that server is set up to accept CORS requests, only then will you be able to pull content from elsewhere. It should not be difficult to do and most common place server + software packages usually include a simple way of enabling this feature.

+ +

Dealing With video

+ +

There is a special object called EmscriptenVideo that is availble whose sole purpose + is to playback video. While there are other techniques to stream video data, + using EmscriptenVideo is the easiset way as it just takes advantage of the browser's built-in + video tag. It even provides a texture you can use!

+ +

Multi-window projects

+ +

Note that you likely won't be able to port over any multi-window projects. On the web, each <canvas> element's WebGL context, and all of the content that it creates, is only available to that context's canvas element.

+ +
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part6.html b/docs/htmlsrc/guides/emscripten/part6.html new file mode 100644 index 0000000000..b13e1a3e43 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part6.html @@ -0,0 +1,90 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+ +

Web Workers

+ +

Web workers can essentially be thought of as the threads of the web. That being said though there are some limitations to what you can do in a Web Worker.

+ + + +

That being said , there are 2 ways of writing web workers.

+ +

As a Cpp program

+ +

You can write Web Workers as a C++ program. Unfortuantely you will have to treat it essentially as a separate project as in order to build a worker, + you will need to add the flag -s BUILD_AS_WORKER=1 + Note that you will also have to add another flag separately called EXPORTED_FUNCTIONS in which you make it equal to an array like object with all the method names in your worker file that you want to expose prefixed with underscores, IE : ['_onmessage']

+ +

It currently appears you can add as many functions as you'd like and use your libraries the same way you might a regular project.

+

You could conceptually write the setup for this in the same CMake file as your main application but it is advised to seperate your worker into a new project for clarity.

+ +

As Javascript

+ +

The potentially easier alternative might be to write your worker directly as JS. The CINDER_HELPERS namespace contains a function called sourceToBlob + which will convert any string source into a format suitable for instantiating a WebWorker in Javascript. + + Note that going this route and trying to use C++ to talk to the worker is a bit of a pain as you'll have to use the rather verbose emscripten::val api or proxy a global Javascript function + but it is possible to go this route if you'd like. +

+ +

Offscreen canvas

+

Something interesting that Emscripten supports is the ability to use OffscreenCanvas. + Currently - only Firefox has good support for OffscreenCanvas but it has been rumored that Chrome is set to get better support in the next version

+ See this article for more information. + +
+
+ +

Audio Support

+

Currently there is very limited built-in audio support when it comes to Emscripten. As you might expect, this is primarily due to the nature of the web and + how Javascript is the primarily language for the web. +

+ + +

+ Why the lack of support? To do proper audio analysis, the current recommendedation is to use the AudioWorklet standard. That being said, that is easier said than done as initial explorations, some parts of the workflow + are difficult to do in C++ alone and require Javascript to run properly. + If you would like to experiment regardless, there is the older ScriptProcessorNode which is known to be working + with C++ but keep in mind that it is due to be deprecated at some point. +

+
+ + + + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part7.html b/docs/htmlsrc/guides/emscripten/part7.html new file mode 100644 index 0000000000..a95012d756 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part7.html @@ -0,0 +1,98 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + +

Additional potentially helpful information

+ + + +
+ +
    +
  1. + It may be beneficial to run emcc --clear-cache now and then to ensure you get a clean build. +
  2. +
  3. +

    Run export EMCC_DEBUG=1 before building to tell Emscripten to spit out it's own debugging information. + You can optionally pass in -v as an Emscripten flag +

    +
  4. +
  5. +

    You can of course, use your own HTML shell for building your app. + See here for details +

    +
  6. +
  7. + + + If you're curious about what other flags you can add when building your Emscripten project + +
  8. +
  9. +

    From time to time, you may notice that Emscripten has stopped compiling new changes, which can be a pain. You'll have to remember to + make a small tweak in one of your main specified source files to get things to re-compile. +

    +
  10. + +
  11. +

    + For faster load times, assuming you don't need to examine the output, it may be a good idea to just do release builds. +

    +
  12. + +
  13. + +

    For Transform Feedback - you must unbind your data buffer(s) after the Transform Feedback stage.

    + +
  14. + +
  15. + When dealing with GL_POINTS - there's no need to specifically enable GL_PROGRAM_POINT_SIZE; in fact doing so will cause a compilation error. + Point size is already enabled automatically, you just need to set th epoint size in your shader. +
  16. + +
  17. +

    + Also remember to specify precision in your fragment shaders. +

    +
  18. + +
  19. +

    Though it does exist in the WebGL 2 spec, for some reason trying to create a GL_RGB16F format texture will cause an exception. + The cause is currently unknown - the workaround for now is to use GL_RGBA16F. +

    +
  20. +
+
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part8.html b/docs/htmlsrc/guides/emscripten/part8.html new file mode 100644 index 0000000000..a75c539d7c --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part8.html @@ -0,0 +1,85 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+

Faq

+

While building projects targeting WebAssembly, you can potentially run into some issues. +

+ +
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part9.5.html b/docs/htmlsrc/guides/emscripten/part9.5.html new file mode 100644 index 0000000000..0e90260c99 --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part9.5.html @@ -0,0 +1,125 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+

emscripten::val

+

It's probbaly worth talking about how emscripten::val works since there's a good chunk of code that + utilizes the functionality.

+ +

Essentially, you can think of it as a JSON parser for Javascript. While there are differences of course, if you've used JsonCpp before, + a lot of this will probably feel familiar. +

+ +

Basic usage

+

As a starting point, it is perhaps valuable to know how to access global values

+ + +

Both of these calls will return an emscripten::val object. This is an all encompassing object for every possible type of + Javascript value. The api for this object is pretty simple

+ + + +

Some notes

+ + +

+ You can read more here. + >

+
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/emscripten/part9.html b/docs/htmlsrc/guides/emscripten/part9.html new file mode 100644 index 0000000000..f05de3fb3b --- /dev/null +++ b/docs/htmlsrc/guides/emscripten/part9.html @@ -0,0 +1,193 @@ + + + + + Cinder with Emscripten + + + + + + + + + + + + + + + + + + + + + + +
+

ci_emscripten_app

+

ci_emscripten_app is a helper function to make your CMakeLists.txt files easier to write.

+

It is designed to more or less mimic ci_make_app for desktop apps but with some Emscripten specific parameters

+

While you can still hand-write your CMakeLists.txt file, it is recommended to use ci_emscripten_app instead.

+ + +

ci_emscripten_app takes a number of options. At the very least, you'll need to specify the options: +
+ * CINDER_PATH +
+ * SOURCES(and the path to your main app file) +

+

+ There are a number of other options you can pass in as well. +

+ +
+ + + + + + + + + + diff --git a/docs/htmlsrc/guides/index.html b/docs/htmlsrc/guides/index.html index 9119ffa25b..e892a4d34a 100644 --- a/docs/htmlsrc/guides/index.html +++ b/docs/htmlsrc/guides/index.html @@ -26,7 +26,8 @@
  • Linux Platform Notes
  • iOS Platform Notes
  • Android Platform Notes
  • -
  • UWP Platform Notes
  • +
  • UWP Platform Notes
  • +
  • Emscripten Notes