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
+
+ Threads (there is some experimentation with adatpting pthread but due to the Spectre vulnerability, support of this does depend a little on browser builders)
+ PBOs
+ Multi-window support (with some trickery you could perhaps simulate multi-screen support but given the strictness with how things are sandboxed on the web the possibility remains very low.)
+ Compute shaders are currently not useable in WebGL
+ SSBOs
+ It is also currently not possible to bind buffers for use in shaders for uses other than Transform Feedback or UBOs.
+
+ 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
+
+ Install Cmake (at least version 3.10 but may work on older versions as well)
+
+ You'll also need a *nix style terminal window as well as make
or something similar if you happen to be on Windows
+
+ This has been tested on WSL, specifically using Ubuntu as the backend
+ Emscripten has been known to work with Git bash; though as of version 1.39.16 of Emscripten, support seems suspect. Some things work fine, some things seem to fail. That said, assuming you can get things built, you will also need
+ a make program and things have been known to work with MinGW64.
+
+
+ Of course, you'll need to install Emscripten. Make sure to follow the directions found on the official site as the method of installation has changed since Emscripten was originally conceived.
+
+
+ Once you have all that...
+
+ Building Cinder
+
+ First, run emsdk activate latest
, then run source emsdk_env.sh
+
+
+ Just like you would on the desktop if you were building Cinder for Linux, make a build folder at the root of your Cinder
+ installation and run
+ emcmake cmake ..
(plus any other CMake flags you'd like to set)
+
+
+
+ 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
+
+
+ Windows 10
+
+
+ WSL
+
+ Emscripten version 1.39.16
+
+
+ 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)
+
+ run emcmake cmake ..
+ run make
(or mingw32-make
etc if on Windows or not using WSL)
+ When the build is done, everything you need to upload will end up in your build folder.
+
+
+
+
+ Note that resource and asset bundling/copying is not automatically done because builds will fail if the compiler can't find the
+ resources directory. To add your asset folders :
+
+ For Resources
+ If you're not using ci_emscripten_app(which will be talked about later on) you can add the flag
+ --preload-file ../(path to your resources folder)@
+
+ For Assets
+ If you're not using ci_emscripten_app, unless your CMake file is already set up to copy it over, you will have to manually copy your assets folder into your output directory.
+ Otherwise your assets will be copied automatically.
+
+
+
+
+ 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
+
+
+ if on Python 2, from within your build directory, run python -m SimpleHTTPServer
+ if on Python 3, your command is python -m http.server
+ Note that for both commands you can specify a port after typing in the command, otherwise things will default to port 8000
+ Currently, while your project should still run, it won't technically be running in it's WebAssembly form since the python server does not support WebAssembly at the moment.
+ There is a provided alternative server you can use called wasm-server . You can of course choose to roll your own as well if you wish.
+
+
+
+
+
+ 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
+
+
+
+ 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!`
+
+
+
+ Shaders are currently not detached after creation due to a possible bug Emscripten that essentially sets the shader handle to null.
+
+
+
+
+ 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.
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
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.
+
+ You cannot pass complex types to a thread, only standard Javascript types. When it comes to C++, you can only pass a char*
and a void*
You will not have access to the DOM.
+
+ 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.
+
+
+ Currently, the only built-in support is for basic audio playback. See Audioplayer.h
+
+
+
+ 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
+
+
+
+
+
+
+
+ It may be beneficial to run emcc --clear-cache
now and then to ensure you get a clean build.
+
+
+ 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
+
+
+
+ You can of course, use your own HTML shell for building your app.
+ See here for details
+
+
+
+
+
+ If you're curious about what other flags you can add when building your Emscripten project
+
+
+
+ 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.
+
+
+
+
+
+ For faster load times, assuming you don't need to examine the output, it may be a good idea to just do release builds.
+
+
+
+
+
+ For Transform Feedback - you must unbind your data buffer(s) after the Transform Feedback stage.
+
+
+
+
+ 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.
+
+
+
+
+ Also remember to specify precision in your fragment shaders.
+
+
+
+
+ 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
.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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.
+
+
+
+ My application works in one browser but not in another.
+
+ Despite the fact that there is technically a standard for how everything works,
+ browser builders have thus far decided to implement things differently or roll things out
+ on different timelines. For example, Apple's Safari STILL does not support WebGL 2.
+ Chrome and Firefox are the recommended browsers though you may have luck with other ones.
+
+
+
+
+
+ I can't load files hosted on another server.
+
+ Browsers operate on the principle that all content loaded must be on the same server as the page you're
+ requesting. The process of making a request for content on another server is called a Cross-Origin Request Sharing ,
+ or CORS for short.
+
+
+
+
+ CORS is not enabled by default. If you must load content from another server, it is possible to get around this restriction by enabling CORS handling on your server which is
+ a pretty basic option these days on common open-source server software. If you don't have access to the server, then you'll have to contact someone that does.
+
+
+
+
+
+ How do I deploy my project?
+
+ Assuming you're using ci_emscripten_app
, Cinder Emscripten is set up so that when you build, depending on your build type (the default is "Debug"), you'll have either a
+ "Debug" or "Release" folder inside of your build directory. You should be able to just copy and drop the contents of this folder
+ onto your server.
+
+
+
+ If you're writing your own CMakeLists file - well then, that's up to you to figure out but in general, your output should come out in the build area that you specify.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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
+
+
+ emscripten::val::global("window")
- This will give you the global window
object.
+
+
+ emscripten::val::global("document")
- This will give you the global document
object.
+
+
+
+ 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
+
+
+
+ .call<T>
- this will call a function on the object. It takes the function name as a string,
+ and a variable number of arguments depending on what function you are calling. Note that only very simple types will work
+ as parameters as they will get transliterated into their Javascript equivalants. If you want to pass something more complex, you will need to
+ make use of the
+ EMSCRIPTEN_BINDINGS
+ function first in order to expose your object to the Javascript side of things.
+ Cinder has built in support for lambdas that accept a emscripten::val
object as a function parameter.
+
+ To call a function that returns a value, remember to specify the value type expected back within the angled brackets or
+ specify void if you are not expecting a value.
+
+
+
+ .new_()
- This will call the constructor of a Javascript object.
+
+
+
+ .as<T>
- This will extract the value of the Javascript object in question into the specified format.
+ On a similar note, it is possible to also get values using array syntax, for example
+
+
+
+ emscripten::val domElement = "code to grab domElement";
+
+ auto id = domElement["id"];
+
+
+
+
+ The difference though with using array syntax is that you will get another emscripten::val
instead of a C++ type.
+
+
+
+ .set
- This will set a paramter on the Javascript object in question, for example, to set the ID of a DOM element, it would look something like :
+
+
+ emscripten::val domElement = "...whatever code to get a reference to a dom element";
+ domElement.set("id","nodeId");
+
+
+
+
+
+
+ Some notes
+
+
+ Note that the emscripten::val
object does not have a default constructor. You will need to pre-set it to a value if
+ you want to keep a reference to it for later use. The easiset way is to just make it "undefined" which can be done by calling
+ emscripten::val::undefined()
+
+
+
+ Though rare, depending on how you structure your project, you may run into into the garbage collector
+ clearing your object references.
+
+
+
+
+
+ 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.
+
+
+ CINDER_PATH
- the path to where you downloaded Cinder. This is important
+ as otherwise your code will not compile correctly. In general a relative path from where your CMakeLists.txt file is
+ is expected, but it should work with an absolute path as well.
+
+
+
+
+ SOURCES
- specify a path to all of your .cpp files. Your main app file should be the first item in the list.
+ Multiple paths should be seperated by spaces and un-quoted.
+
+
+
+
+
+
+ INCLUDES
- specify a path to all of your .h files here. Formatting should be same as source files.
+
+
+
+
+ LIBRARIES
- specify a path to all of your library files here. Formatting for different paths is the same as your source code. Note that Emscripten only supports .a or .bc library files.
+
+
+
+
+ FLAGS
- by default, some common flags will get used to build your application; that being said,
+ Emscripten has a number of other flags in addition to the ones you can manipulate with ci_emscripten_app that can be used to build
+ your project. Specify any other flags you want to use as a single string with this parameter. See here for more details.
+
+
+
+
+ ASSETS
- the path to your assets directory if you have one. When your code is built, this
+ directory will get copied to your build directory. Note that if the NO_ASYNC parameter is specified you will have to rely on the loadAssetAsync function
+ or write your own function in order to access items in the assets folder.
+
+
+
+
+ RESOURCES
- the path to your resources directory if you have one. When your application is built,
+ all of the files in the resources folder will get bundled into a binary file called "index.binary". Note that
+ if specified, you need to make sure that the folder really does exist or your build will fail. ci_emscripten_app guards against
+ this by only adding the necessary flags if the parameter is set. Also note that if NO_ASYNC is set - you will loose access to the bundle.
+
+
+
+
+ THREADS
- enables threading support (via pthread) for your application. Note that due to the Spectre vulnerability, your browser will likely have disabled the SharedArrayBuffer
object
+ which is necessary for this to function correctly. If you're using Chrome, you do have the option of re-enabling support for SharedArrayBuffers which can be done from chrome://flags .
+ It's currently unknkown if other browser's will allow support down the line.
+ If you're interested in learning more about threads with Emscripten, Google recently put out a good introduction on the topic.
+
+
+ As far as deployment when building a threaded application, Chrome appears to be the only browser offering support.The presenter in the video above talks a little bit about it here.
+
+
+
+
+ THREAD_POOL_SIZE
- this tells the compiler how many threads you definetly plan on using in your application. It's better to specify
+ this value ahead of time so things can be pre-alocated ahead of time, though it is possible to dynamically generate new threads as well.
+
+
+
+
+ HTML_TEMPLATE
- by default, a there is a default template has a lot of branding already associated with it.
+ You do have the option to use your own template though by specifiying a path to your template with this paramter.
+ See here for how to specify your own template.
+
+
+
+
+ BUILD_TYPE
- specify the type of build you would like to do, either "Debug" (which is the default) or "Release".
+ The difference between the two is that in "Release", optimizations are done to help things run better. If you pass in another value, your build will default to "Debug"
+
+
+
+
+ BUILD_AS_WORKER
- this will build your code as a Web Worker, which is slightly different than a regular application bundle.
+
+
+
+
+ EXPORT_FROM_WORKER
- This tells Emscripten what functions you want to expose to your main application within your worker.
+ The parameter should be a single quoted string with all functions separated by a comma ie '_onmessage,_postmessage'
+
+
+
+ NO_ASYNC
- by default, some Emscripten libraries are included that deal with http requests among other things.
+ This is necessary because of the lack of a filesystem api on the web(well, technically it does exist but will be/has been deprecated) and because
+ Cinder Emscripten attempts to emulate ci::app::loadAsset
as closely as possible.
+
+ In addition, another reason for including Emscripten's async libraries is to
+ make it possible to load larger files like videos, audio, etc; currently, while you can bundle them into the emulated filesystem(which can be accessed using ci::app::loadResource
),
+ it seems that at the moment, there is an issue with Emscripten and how it will read those larger files. Also, including those larger files will add to your page load time.
+
+
+
+ The tradeoff for including these libraries though is that it will roughly double your compile time(based on early estimates on an i7 7700) and increase your final wasm size(which could be important depending on your project).
+
+
+ If you feel comfortable with asynchronous functions, you can disable inclusion of these libraries by
+ passing TRUE
to the NO_ASYNC
parameter. Note that this of course will disable ci::app::loadAsset
.
+ In CinderEmscripten.h
, there is the function ci::app::loadAssetAsync
. It works just like the normal loadAsset
function with
+ 2 exceptions.
+
+
+ There is no return value so you don't pass it into another function(ie loadImage, etc)
+ You need to pass it a lamda as a second parameter that has a ci::DataSourceRef as the parameter for the function.
+
+
+ If you know a little Javascript, you can write your own async request handler as well.
+
+
+
+
+
+
+ OUTPUT_NAME
- By default, the name "index" is used as the output name as it makes it simpler when deploying projects.
+ If you'd like to specify something specific, this parameter will allow you to do so.
+
+
+
+ OUTPUT_DIRECTORY
- By default, all output should go into your build folder, but if there is another
+ folder you wish to deploy to, you can specify that path here.
+
+
+
+ PRE_JS
- Pass in paths to any javascript files you want to include in your build. The JS will get included before your
+ your main compiled code.
+
+
+
+ POST_JS
- Pass in paths to any javascript files you want to include in your build. The JS will get included after your
+ your main compiled code.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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
diff --git a/emscripten/cmake/Cinder.cmake b/emscripten/cmake/Cinder.cmake
new file mode 100644
index 0000000000..9341799753
--- /dev/null
+++ b/emscripten/cmake/Cinder.cmake
@@ -0,0 +1,70 @@
+
+# Assume Debug if a build type isn't specified
+if( "" STREQUAL "${CMAKE_BUILD_TYPE}" )
+ set( CMAKE_BUILD_TYPE "Debug" CACHE FILEPATH "" FORCE )
+endif()
+
+### Force some Emscripten CMake variables. CMake seems to be really particular
+### about when these vars show up. They need to come after project.
+set( CMAKE_AR "emcc" CACHE FILEPATH "" FORCE)
+set( CMAKE_STATIC_LIBRARY_SUFFIX ".bc" )
+set( CMAKE_C_CREATE_STATIC_LIBRARY " -o " )
+set( CMAKE_CXX_CREATE_STATIC_LIBRARY " -o " )
+
+# set basic flags for Emscripten
+set( CINDER_GL_ES_FLAGS "-DCINDER_GL_ES_3 -s USE_WEBGL2=1 -s FULL_ES3=1" )
+
+# C Flags
+set( C_FLAGS "-fvisibility=default -D_UNIX ${CINDER_GL_ES_FLAGS} -s USE_GLFW=3 -s NO_EXIT_RUNTIME=1 -s DISABLE_EXCEPTION_CATCHING=0" )
+set( CMAKE_C_FLAGS_DEBUG "${C_FLAGS} -g -O0" )
+set( CMAKE_C_FLAGS_RELEASE "${C_FLAGS} -Os" )
+
+# CPP Flags
+set( CXX_FLAGS "-stdlib=libc++ -std=c++11 -fvisibility=default -D_UNIX ${CINDER_GL_ES_FLAGS} -s USE_GLFW=3 -s DEMANGLE_SUPPORT=1 -s DISABLE_EXCEPTION_CATCHING=0" )
+set( CMAKE_CXX_FLAGS_DEBUG "${CXX_FLAGS} -g -O0 -fexceptions -frtti" )
+set( CMAKE_CXX_FLAGS_RELEASE "${CXX_FLAGS} -Os -fexceptions -frtti")
+
+get_filename_component( CINDER_INC_DIR "${CINDER_DIR}/include" ABSOLUTE )
+get_filename_component( CINDER_LIB_DIR "${CINDER_DIR}/lib" ABSOLUTE )
+
+# we need an externs file to get around closure compiler mangling names(or is it UglifyJS ? I see references to both!¯\_(ツ)_/¯ )
+list(APPEND EMCC_CLOSURE_ARGS "--externs ${CINDER_INC_DIR}/cinder/emscripten/externs.js")
+################### HELPER VARIABLES ##################################
+
+set(ALLOW_MEMORY_GROWTH "-s ALLOW_MEMORY_GROWTH=1")
+
+# set variable for helper file when handling DOM related stuff. This should be a part of the --pre-js Emscripten flag
+set( CINDER_JS_HELPERS "--pre-js ${CINDER_INC_DIR}/cinder/emscripten/helpers.js")
+
+set( CINDER_VIDEO "${CINDER_JS_HELPERS} ${CINDER_USE_EMBIND}")
+
+# add to your project flags to build your file as a WebWorker.
+# note that you apparently need the --bind flag when building workers
+set( BUILD_AS_WORKER "-s BUILD_AS_WORKER=1")
+
+# the flag to set when you want to include an assets folder and it's contents.
+# this assumes that your assets directory is one directory behind. Note that
+# this may not work for samples
+set( INCLUDE_RESOURCES_FOLDER "--preload-file ../resources@")
+
+# simple function to allow you to re-set the resources path - just pass in a new path relative to your build directory
+function(SET_RESOURCES_PATH path)
+set( INCLUDE_RESOURCES_FOLDER "--preload-file ${path}@" PARENT_SCOPE)
+endfunction()
+
+# this flag tells Emscripten to use the browser to decode media assets whenever possible, when used
+# in conjunction with a related API function.
+set( USE_BROWSER_FOR_DECODING "--use-preload-plugins")
+
+# adds optimizations to the final output
+set( ADD_OPTIMIZATIONS "-s WASM=1 -Os -g0")
+
+# enables use of pthreads
+set(USE_THREADS "-s USE_PTHREADS=1")
+
+
+# note - release command would be
+# emcmake cmake .. -DCMAKE_BUILD_TYPE=Release
+if( "Debug" STREQUAL "${CMAKE_BUILD_TYPE}" )
+ set( CINDER_LIB_SUFFIX "_d" CACHE FILEPATH "" FORCE )
+endif()
diff --git a/include/cinder/Cinder.h b/include/cinder/Cinder.h
index 69e944d7aa..393031f455 100644
--- a/include/cinder/Cinder.h
+++ b/include/cinder/Cinder.h
@@ -92,6 +92,8 @@ using std::uint64_t;
#define CINDER_POSIX
#define CINDER_ANDROID
#include
+#elif defined( __EMSCRIPTEN__ )
+ #define CINDER_EMSCRIPTEN
#else
#error "cinder compile error: Unknown platform"
#endif
diff --git a/include/cinder/Font.h b/include/cinder/Font.h
index 99ea9840cb..b5981ce42f 100644
--- a/include/cinder/Font.h
+++ b/include/cinder/Font.h
@@ -43,7 +43,7 @@
namespace Gdiplus {
class Font;
}
-#elif defined( CINDER_UWP ) || defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+#elif defined( CINDER_UWP ) || defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
typedef struct FT_FaceRec_* FT_Face;
#endif
@@ -54,7 +54,7 @@ class FontObj;
//! Represents an instance of a font at a point size. \ImplShared
class CI_API Font {
public:
-#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
typedef uint32_t Glyph;
struct GlyphMetrics {
ivec2 advance;
@@ -77,7 +77,7 @@ class CI_API Font {
std::string getFullName() const;
float getSize() const;
-#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
float getLinespace() const;
#endif
float getLeading() const;
@@ -93,7 +93,7 @@ class CI_API Font {
//! Returns the bounding box of a Glyph, relative to the baseline as the origin
Rectf getGlyphBoundingBox( Glyph glyph ) const;
-#if defined( CINDER_UWP ) || defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+#if defined( CINDER_UWP ) || defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
FT_Face getFreetypeFace() const;
#endif
diff --git a/include/cinder/Log.h b/include/cinder/Log.h
index 8df4699892..2f2035ec85 100644
--- a/include/cinder/Log.h
+++ b/include/cinder/Log.h
@@ -176,7 +176,7 @@ class CI_API LoggerSystem : public Logger {
protected:
Level mMinLevel;
-#if defined( CINDER_COCOA ) || defined( CINDER_LINUX )
+#if defined( CINDER_COCOA ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
class ImplSysLog;
std::unique_ptr mImpl;
#elif defined( CINDER_MSW_DESKTOP )
diff --git a/include/cinder/Text.h b/include/cinder/Text.h
index 0e11d70f61..35a25065c8 100644
--- a/include/cinder/Text.h
+++ b/include/cinder/Text.h
@@ -132,7 +132,7 @@ class CI_API TextBox {
vec2 measure() const;
/** Returns a vector of pairs of glyph indices and the position of their left baselines
\warning Does not support word wrapping on Windows. **/
-#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
std::vector> measureGlyphs( const std::map* cachedGlyphMetrics = nullptr ) const;
#else
std::vector> measureGlyphs() const;
@@ -160,7 +160,7 @@ class CI_API TextBox {
void calculate() const;
mutable std::u16string mWideText;
-#elif defined( CINDER_UWP ) || defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+#elif defined( CINDER_UWP ) || defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
std::vector calculateLineBreaks( const std::map* cachedGlyphMetrics = nullptr ) const;
void calculate() const;
#endif
diff --git a/include/cinder/Timer.h b/include/cinder/Timer.h
index 53044d8ad4..152db97eb2 100644
--- a/include/cinder/Timer.h
+++ b/include/cinder/Timer.h
@@ -54,7 +54,7 @@ class CI_API Timer {
double mStartTime, mEndTime;
#elif defined( CINDER_MSW )
double mStartTime, mEndTime, mInvNativeFreq;
-#elif defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+#elif defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
double mStartTime, mEndTime;
#endif
};
diff --git a/include/cinder/app/App.h b/include/cinder/app/App.h
index 5b4c4cf233..9ea4ca5b93 100644
--- a/include/cinder/app/App.h
+++ b/include/cinder/app/App.h
@@ -61,4 +61,10 @@
typedef AppLinux App;
} } // namespace cinder::app
#define CINDER_APP( APP, RENDERER, ... ) CINDER_APP_LINUX( APP, RENDERER, ##__VA_ARGS__ )
-#endif
+#elif defined ( CINDER_EMSCRIPTEN )
+ #include "cinder/app/emscripten/AppEmscripten.h"
+ namespace cinder { namespace app {
+ typedef AppEmscripten App;
+ } } // namespace cinder::app
+ #define CINDER_APP( APP, RENDERER, ... ) CINDER_APP_EMSCRIPTEN( APP, RENDERER, ##__VA_ARGS__ )
+#endif
\ No newline at end of file
diff --git a/include/cinder/app/Renderer.h b/include/cinder/app/Renderer.h
index d119454060..08fa3e5dae 100644
--- a/include/cinder/app/Renderer.h
+++ b/include/cinder/app/Renderer.h
@@ -115,7 +115,9 @@ class CI_API Renderer {
#else
virtual void setup( void* nativeWindow, RendererRef sharedRenderer ) = 0;
#endif
-#endif
+#elif defined( CINDER_EMSCRIPTEN )
+ virtual void setup( void* nativeWindow, RendererRef sharedRenderer ) = 0;
+#endif
virtual Surface8u copyWindowSurface( const Area &area, int32_t windowHeightPixels ) = 0;
diff --git a/include/cinder/app/RendererGl.h b/include/cinder/app/RendererGl.h
index 320b0c992c..b337af7054 100644
--- a/include/cinder/app/RendererGl.h
+++ b/include/cinder/app/RendererGl.h
@@ -209,7 +209,9 @@ class CI_API RendererGl : public Renderer {
#else
virtual void setup( void* nativeWindow, RendererRef sharedRenderer ) override;
#endif
-#endif
+#elif defined( CINDER_EMSCRIPTEN )
+ virtual void setup( void* nativeWindow, RendererRef sharedRenderer ) override;
+#endif
const Options& getOptions() const { return mOptions; }
@@ -254,7 +256,11 @@ class CI_API RendererGl : public Renderer {
class RendererGlLinux *mImpl;
RendererGlLinux *getImpl() { return mImpl; }
friend class WindowImplLinux;
-#endif
+#elif defined( CINDER_EMSCRIPTEN )
+ class RendererImplGlEmscripten *mImpl;
+ RendererImplGlEmscripten *getImpl() { return mImpl; }
+ friend class WindowImplEmscripten;
+#endif
std::function mStartDrawFn;
std::function mFinishDrawFn;
diff --git a/include/cinder/app/Window.h b/include/cinder/app/Window.h
index 5db53340ac..bba408290f 100644
--- a/include/cinder/app/Window.h
+++ b/include/cinder/app/Window.h
@@ -99,7 +99,11 @@ typedef std::shared_ptr WindowRef;
namespace cinder { namespace app {
class WindowImplLinux;
} } // namespace cinder::app
-#endif
+#elif defined( CINDER_EMSCRIPTEN )
+ namespace cinder { namespace app {
+ class WindowImplEmscripten;
+ } } // namespace cinder::app
+#endif
namespace cinder { namespace app {
@@ -444,7 +448,9 @@ class CI_API Window : public std::enable_shared_from_this {
static WindowRef privateCreate__( WindowImplAndroid *impl, AppBase *app )
#elif defined( CINDER_LINUX )
static WindowRef privateCreate__( WindowImplLinux *impl, AppBase *app )
-#else
+#elif defined (CINDER_EMSCRIPTEN )
+ static WindowRef privateCreate__( WindowImplEmscripten *impl, AppBase *app )
+#else
static WindowRef privateCreate__( WindowImplCocoa *impl, AppBase *app )
#endif
{
@@ -483,7 +489,10 @@ class CI_API Window : public std::enable_shared_from_this {
void setImpl( WindowImplAndroid *impl ) { mImpl = impl; }
#elif defined( CINDER_LINUX )
void setImpl( WindowImplLinux *impl ) { mImpl = impl; }
-#endif
+#elif defined( CINDER_EMSCRIPTEN )
+void setImpl( WindowImplEmscripten *impl ) { mImpl = impl; }
+
+#endif
AppBase *mApp;
bool mValid;
@@ -509,7 +518,9 @@ class CI_API Window : public std::enable_shared_from_this {
WindowImplAndroid *mImpl;
#elif defined( CINDER_LINUX )
WindowImplLinux *mImpl;
-#endif
+#elif defined ( CINDER_EMSCRIPTEN )
+ WindowImplEmscripten * mImpl;
+#endif
private:
#if defined( CINDER_ANDROID )
@@ -518,7 +529,10 @@ class CI_API Window : public std::enable_shared_from_this {
#elif defined( CINDER_LINUX )
friend class AppImplLinux;
WindowImplLinux *getImpl() { return mImpl; }
-#endif
+#elif defined ( CINDER_EMSCRIPTEN )
+ friend class AppImplEmscripten;
+ WindowImplEmscripten *getImpl() { return mImpl; }
+#endif
};
} } // namespace cinder::app
diff --git a/include/cinder/app/emscripten/AppEmscripten.h b/include/cinder/app/emscripten/AppEmscripten.h
new file mode 100644
index 0000000000..a3088d403c
--- /dev/null
+++ b/include/cinder/app/emscripten/AppEmscripten.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (c) 2012, The Cinder Project, All rights reserved.
+
+ This code is intended for use with the Cinder C++ library: http://libcinder.org
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "cinder/app/AppBase.h"
+
+namespace cinder { namespace app {
+
+class AppImplEmscripten;
+
+class AppEmscripten : public AppBase {
+ public:
+ typedef std::function SettingsFn;
+
+ AppEmscripten();
+ virtual ~AppEmscripten();
+
+ WindowRef createWindow( const Window::Format &format = Window::Format() ) override;
+ void quit() override;
+
+ float getFrameRate() const override;
+ void setFrameRate( float frameRate ) override;
+ void disableFrameRate() override;
+ bool isFrameRateEnabled() const override;
+
+ WindowRef getWindow() const override;
+ WindowRef getWindowIndex( size_t index ) const override;
+ size_t getNumWindows() const override;
+
+ WindowRef getForegroundWindow() const override;
+
+ void hideCursor() override;
+ void showCursor() override;
+ ivec2 getMousePos() const override;
+
+ //! \cond
+ // Called during application instanciation via CINDER_APP_LINUX macro
+ template
+ static void main( const RendererRef &defaultRenderer, const char *title, int argc, char * const argv[], const SettingsFn &settingsFn = SettingsFn() );
+ //! \endcond
+
+ protected:
+ void launch() override;
+
+ private:
+ AppImplEmscripten* mImpl = nullptr;
+};
+
+template
+void AppEmscripten::main( const RendererRef &defaultRenderer, const char *title, int argc, char * const argv[], const SettingsFn &settingsFn )
+{
+ AppBase::prepareLaunch();
+
+ Settings settings;
+ AppBase::initialize( &settings, defaultRenderer, title, argc, argv );
+
+ if( settingsFn )
+ settingsFn( &settings );
+
+ if( settings.getShouldQuit() )
+ return;
+
+ AppEmscripten *app = static_cast( new AppT );
+ app->executeLaunch();
+ delete app;
+
+ AppBase::cleanupLaunch();
+}
+
+#define CINDER_APP_EMSCRIPTEN( APP, RENDERER, ... ) \
+int main( int argc, char* argv[] ) \
+{ \
+ cinder::app::RendererRef renderer( new RENDERER ); \
+ cinder::app::AppEmscripten::main( renderer, #APP, argc, argv, ##__VA_ARGS__ ); \
+ return 0; \
+}
+
+}} // namespace cinder::app
diff --git a/include/cinder/app/emscripten/AppImplEmscripten.h b/include/cinder/app/emscripten/AppImplEmscripten.h
new file mode 100644
index 0000000000..90412c992e
--- /dev/null
+++ b/include/cinder/app/emscripten/AppImplEmscripten.h
@@ -0,0 +1,100 @@
+/*
+ Copyright (c) 2012, The Cinder Project, All rights reserved.
+
+ This code is intended for use with the Cinder C++ library: http://libcinder.org
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "cinder/app/emscripten/AppEmscripten.h"
+
+// Use the system version, not the one that ships with Cinder.
+#include
+#include
+#include
+namespace cinder { namespace app {
+
+class AppEmscripten;
+class WindowImplEmscripten;
+
+class AppImplEmscripten {
+ public:
+
+ AppImplEmscripten( AppEmscripten *aApp, const AppEmscripten::Settings &settings );
+ virtual ~AppImplEmscripten();
+
+ AppEmscripten *getApp();
+
+ protected:
+ RendererRef findSharedRenderer( const RendererRef &searchRenderer );
+
+ WindowRef createWindow( Window::Format format );
+ void quit();
+
+ float getFrameRate() const;
+ void setFrameRate( float aFrameRate );
+ void disableFrameRate();
+ bool isFrameRateEnabled() const;
+
+
+ WindowRef getWindow() const;
+ void setWindow( WindowRef window );
+ size_t getNumWindows() const;
+ WindowRef getWindowIndex( size_t index ) const;
+ WindowRef getForegroundWindow() const;
+ void setForegroundWindow( WindowRef window );
+
+ void hideCursor();
+ void showCursor();
+ ivec2 getMousePos() const;
+
+
+private:
+ AppEmscripten *mApp = nullptr;
+ WindowRef mMainWindow;
+
+ std::list mWindows;
+ WindowRef mActiveWindow;
+ WindowRef mForegroundWindow;
+
+ float mFrameRate;
+ bool mFrameRateEnabled;
+ bool mShouldQuit = false;
+
+ bool mSetupHasBeenCalled = false;
+
+ double mNextFrameTime;
+
+ void sleepUntilNextFrame();
+ void run();
+
+ void registerWindowEvents( WindowImplEmscripten* window );
+ void unregisterWindowEvents( WindowImplEmscripten* window );
+
+ friend class AppEmscripten;
+ friend class WindowImplEmscripten;
+ friend class GlfwCallbacks;
+
+public:
+ // This has to be static so we can call it from the callback.
+ void updateAndDraw();
+};
+
+}} // namespace cinder::app
diff --git a/include/cinder/app/emscripten/PlatformEmscripten.h b/include/cinder/app/emscripten/PlatformEmscripten.h
new file mode 100644
index 0000000000..a66b201678
--- /dev/null
+++ b/include/cinder/app/emscripten/PlatformEmscripten.h
@@ -0,0 +1,72 @@
+/*
+ Copyright (c) 2012, The Cinder Project, All rights reserved.
+
+ This code is intended for use with the Cinder C++ library: http://libcinder.org
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "cinder/app/Platform.h"
+
+namespace cinder { namespace app {
+
+class PlatformEmscripten : public Platform
+{
+ public:
+
+ PlatformEmscripten();
+ virtual ~PlatformEmscripten();
+
+ static PlatformEmscripten* get();
+
+ virtual void cleanupLaunch() override;
+
+ virtual DataSourceRef loadResource( const fs::path &resourcePath ) override;
+ virtual DataSourceRef loadAsset( const fs::path &resourcePath ) override;
+
+ virtual fs::path getResourceDirectory() const override;
+ virtual fs::path getResourcePath( const fs::path &rsrcRelativePath ) const override;
+
+ virtual fs::path getOpenFilePath( const fs::path &initialPath, const std::vector &extensions ) override;
+ virtual fs::path getFolderPath( const fs::path &initialPath ) override;
+ virtual fs::path getSaveFilePath( const fs::path &initialPath, const std::vector &extensions ) override;
+
+ virtual std::map getEnvironmentVariables() override;
+
+ virtual fs::path expandPath( const fs::path &path ) override;
+ virtual fs::path getHomeDirectory() const override;
+ virtual fs::path getDocumentsDirectory() const override;
+ virtual fs::path getDefaultExecutablePath() const override;
+
+ virtual void sleep( float milliseconds ) override;
+ void setThreadName( const std::string &name ) override;
+ virtual void launchWebBrowser( const Url &url ) override;
+
+ virtual std::vector stackTrace() override;
+ virtual const std::vector& getDisplays() override;
+
+ private:
+ bool mDisplaysInitialized = false;
+ std::vector mDisplays;
+ mutable std::vector mResourceDirectories;
+ mutable bool mResourceDirsInitialized = false;
+};
+
+}} // namespace cinder::app
diff --git a/include/cinder/app/emscripten/RendererImplGlEmscripten.h b/include/cinder/app/emscripten/RendererImplGlEmscripten.h
new file mode 100644
index 0000000000..26ed19b1b0
--- /dev/null
+++ b/include/cinder/app/emscripten/RendererImplGlEmscripten.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (c) 2015, The Cinder Project, All rights reserved.
+
+ This code is intended for use with the Cinder C++ library: http://libcinder.org
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "cinder/app/AppBase.h"
+
+typedef struct GLFWwindow GLFWwindow;
+
+namespace cinder { namespace gl {
+
+class Context;
+using ContextRef = std::shared_ptr;
+
+}} // namespace cinder::gl
+
+namespace cinder { namespace app {
+
+class RendererImplGlEmscripten {
+ public:
+
+
+ RendererImplGlEmscripten( class RendererGl *aRenderer );
+ virtual ~RendererImplGlEmscripten();
+
+ virtual bool initialize( void *window, RendererRef sharedRenderer );
+ virtual void kill();
+ virtual void defaultResize() const;
+ virtual void swapBuffers() const;
+ virtual void makeCurrentContext( bool force = false );
+
+ private:
+ class RendererGl *mRenderer = nullptr;
+ gl::ContextRef mCinderContext;
+
+ GLFWwindow *mContext = nullptr;
+};
+
+}} // namespace cinder::app
diff --git a/include/cinder/app/emscripten/WindowImplEmscripten.h b/include/cinder/app/emscripten/WindowImplEmscripten.h
new file mode 100644
index 0000000000..6d029232b3
--- /dev/null
+++ b/include/cinder/app/emscripten/WindowImplEmscripten.h
@@ -0,0 +1,97 @@
+/*
+ Copyright (c) 2012, The Cinder Project, All rights reserved.
+
+ This code is intended for use with the Cinder C++ library: http://libcinder.org
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "cinder/app/emscripten/AppEmscripten.h"
+#include "cinder/app/Window.h"
+#include "cinder/Display.h"
+
+#include "glfw/glfw3.h"
+
+namespace cinder { namespace app {
+
+class AppImplEmscripten;
+
+class WindowImplEmscripten {
+public:
+
+ WindowImplEmscripten( const Window::Format &format, RendererRef sharedRenderer, AppImplEmscripten *appImpl );
+ virtual ~WindowImplEmscripten();
+
+ virtual bool isFullScreen() { return true; }
+ virtual void setFullScreen( bool fullScreen, const app::FullScreenOptions &options );
+ virtual ivec2 getSize() const;
+ virtual void setSize( const ivec2 &size );
+ virtual ivec2 getPos() const;
+ virtual void setPos( const ivec2 &pos );
+ virtual void close();
+ virtual std::string getTitle() const { return mTitle; }
+ virtual void setTitle( const std::string &title );
+ virtual void hide();
+ virtual void show();
+ virtual bool isHidden() const { return false; }
+ virtual DisplayRef getDisplay() const { return mDisplay; }
+ virtual RendererRef getRenderer() const { return mRenderer; }
+ virtual const std::vector& getActiveTouches() const;
+
+ virtual GLFWwindow *getNative() { return mGlfwWindow; }
+ virtual GLFWwindow *getNative() const { return mGlfwWindow; }
+
+ bool isBorderless() const { return mBorderless; }
+ void setBorderless( bool borderless );
+ bool isAlwaysOnTop() const { return mAlwayOnTop; }
+ void setAlwaysOnTop( bool alwaysOnTop );
+
+ AppImplEmscripten* getAppImpl() { return mAppImpl; }
+ WindowRef getWindow() { return mWindowRef; }
+
+ virtual void keyDown( const KeyEvent &event );
+ virtual void draw();
+ virtual void resize();
+
+
+ void hideCursor();
+ void showCursor();
+ ivec2 getMousePos() const;
+
+protected:
+ AppImplEmscripten *mAppImpl = nullptr;
+ WindowRef mWindowRef;
+
+ GLFWwindow *mGlfwWindow = nullptr;
+
+ std::string mTitle;
+ bool mBorderless = false;
+ bool mAlwayOnTop = false;
+
+ DisplayRef mDisplay;
+ RendererRef mRenderer;
+
+ // Always empty for now
+ std::vector mActiveTouches;
+
+ friend class AppImplEmscripten;
+};
+
+}} // namespace cinder::app
diff --git a/include/cinder/emscripten/AudioPlayer.h b/include/cinder/emscripten/AudioPlayer.h
new file mode 100644
index 0000000000..4be544f925
--- /dev/null
+++ b/include/cinder/emscripten/AudioPlayer.h
@@ -0,0 +1,43 @@
+
+#include
+#include
+#include
+#include
+#include "cinder/emscripten/CinderEmscripten.h"
+
+namespace cinder { namespace em {
+
+ typedef std::shared_ptrAudioPlayerRef;
+
+ /**
+ * This is a very basic audio playback class utilizing the html tag.
+ * It's purpose is solely playing back audio and has no built-in mechanism to
+ * allow you to extract the audio information.
+ */
+ class AudioPlayer
+ {
+
+ //! Represents the DOM tag
+ emscripten::val audioNode;
+
+ public:
+
+ AudioPlayer( std::string src, bool useControls, bool loop);
+
+ static AudioPlayerRef create( std::string src, bool useControls=false, bool loop=false){
+ return AudioPlayerRef( new AudioPlayer( src, useControls, loop ) );
+ }
+
+ //! Starts playback
+ void play();
+
+ //! Pauses playback
+ void pause();
+
+ //! Adds an additional source to the player. If the browser doesn't support
+ //! a particular file format, the browser will cycle through any additional sources
+ //! until a suitable one is found, or simply not play.
+ //! Note that this currently only supports either a string based asset path or a blob source.
+ AudioPlayer& addSource(std::string src);
+ };
+}}
\ No newline at end of file
diff --git a/include/cinder/emscripten/CinderEmscripten.h b/include/cinder/emscripten/CinderEmscripten.h
new file mode 100644
index 0000000000..b815ee7887
--- /dev/null
+++ b/include/cinder/emscripten/CinderEmscripten.h
@@ -0,0 +1,197 @@
+/*
+ Copyright (c) 2018, The Barbarian Group
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include "cinder/app/App.h"
+#include "cinder/Log.h"
+#include "cinder/Filesystem.h"
+#include "cinder/Utilities.h"
+#include "cinder/DataSource.h"
+#include "cinder/Surface.h"
+#include "cinder/Url.h"
+#include "cinder/Timer.h"
+
+/**
+ * A file of different functions that are likely going to be used or are helpful
+ * in some manner.
+ */
+
+namespace cinder { namespace em { namespace helpers {
+
+ //! A helper function to add an event listener to an element in a more simplified form.
+ template
+ static void addEventListener( emscripten::val element,std::string eventName,std::function functor ) {
+ auto window = emscripten::val::global( "window" );
+
+ // this basically transforms your callback function so you don't have to call .onload
+ auto functor_adapter = emscripten::val( functor )[ "onload" ].call( "bind", emscripten::val(functor) );
+
+ // add the listener to the element
+ element.call( "addEventListener", emscripten::val( eventName ), functor_adapter );
+ }
+
+ //! Retrieve helper JS functions
+ static emscripten::val getCinderHelpers()
+ {
+ return emscripten::val::global( "window" )[ "CINDER_HELPERS" ];
+ }
+
+ //! retrieve audio JS helpers
+ static emscripten::val getAudioHelpers()
+ {
+ return emscripten::val::global( "window" )[ "CINDER_AUDIO" ];
+ }
+
+ //! retrieve video JS helpers
+ static emscripten::val getVideoHelpers()
+ {
+ return emscripten::val::global( "window" )[ "CINDER_VIDEO" ];
+ }
+
+ // TODO get rid of this since functions mostly un-needed - keeping to ensure we don't break anything.
+ static emscripten::val getFileHelpers()
+ {
+ return emscripten::val::global( "window" )[ "CINDER_FILEIO" ];
+ }
+
+ /**
+ Copies a JS TypedArray to a C++ vector
+ https://github.com/kripken/emscripten/issues/5519
+ */
+ template
+ static void copyToVector( const emscripten::val &typedArray,std::vector &vec ) {
+
+ const auto l = typedArray[ "length" ].as();
+ vec.resize( l );
+
+ emscripten::val memoryView{ emscripten::typed_memory_view(l, vec.data() ) };
+ memoryView.call( "set" ,typedArray );
+ }
+
+ /**
+ * Same as copyToVector but works with regular arrays and floating point data.
+ */
+ template
+ static void copyFloatArrayToVector(const emscripten::val &typedArray,std::vector &vec)
+ {
+ unsigned int length = typedArray["length"].as();
+ emscripten::val memory = emscripten::val::module_property( "buffer" );
+ vec.reserve( length );
+ vec.resize( length );
+ emscripten::val memoryView = emscripten::val::global( "Float32Array" ).new_( memory, reinterpret_cast(vec.data() ), length);
+ memoryView.call( "set", typedArray );
+ }
+
+ //! Converts an std::function into a suitable value to use as a callback in the Javascript context.
+ //! Note that this only works with std::functions that have been declared in cinder/emscripten/globalbindings.cpp (or elsewhere)
+ //! that utilize the string "onload" as their function name.
+ static emscripten::val generateCallback( std::function functor )
+ {
+ return emscripten::val( functor )[ "onload" ].call( "bind", emscripten::val(functor) );
+ }
+
+ //! Returns reference to Worklet helpers
+ static emscripten::val getWorkletHelpers()
+ {
+ return emscripten::val::global( "window" )[ "CINDER_WORKLETS" ];
+ }
+
+ //! Returns the current width of the browser window.
+ static int getWindowWidth()
+ {
+ return emscripten::val::global( "window" ) ["innerWidth" ].as();
+ }
+
+ //! Returns the current height of the browser window.
+ static int getWindowHeight()
+ {
+ return emscripten::val::global( "window" )[ "innerHeight" ].as();
+ }
+
+ //! Queries the current DOM tree for the desired element based on either it's id or classname.
+ //! Note that if specifying a class name, this will only return the first item.
+ static emscripten::val querySelector( std::string selector )
+ {
+ return emscripten::val::global( "document" ).call( "querySelector", emscripten::val( selector ) );
+ }
+
+ //! Returns an image. Assumes you don't need specialized processing.
+ //! TODO return a Surface or something.
+ static char * getImage( DataSourceRef url )
+ {
+ // determine the file type.
+ fs::path filename = fs::path( url->getUrl().str() );
+
+ // fetch the file - put it in the assets directory after it loads.
+ emscripten_wget( url->getUrl().c_str(),filename.c_str() );
+
+ int width, height;
+
+ char *data = emscripten_get_preloaded_image_data( filename.c_str(), &width, &height );
+
+ return data;
+ }
+}}}
+
+extern "C" {
+ extern void loadAsync(const char * url, void * data, int * size);
+}
+
+namespace cinder { namespace app {
+
+ //! Loads an asset asyncronously.
+ //! Pass in a string url as well as a lambda that accepts a DataSourceRef as a parameter.
+ static void loadAssetAsync( std::string url,std::function cb )
+ {
+ auto helpers = emscripten::val::global("window")["CINDER_ASYNC"];
+
+ // callback that will construct the DataSourceRef
+ std::function sourceConstructor = [=]( emscripten::val byteArray )-> void
+ {
+ // turn emscripten::val into something more c++ friendly
+ std::vector data;
+ em::helpers::copyToVector(byteArray,data);
+
+ // construct data source
+ ci::BufferRef rawBuff = ci::Buffer::create( static_cast( data.data() ),data.size() );
+ ci::DataSourceBufferRef dbuff = ci::DataSourceBuffer::create( rawBuff );
+ cb( dbuff );
+ };
+
+ // generate javascript friendly callback
+ emscripten::val _cb = em::helpers::generateCallback( sourceConstructor );
+
+ // prefix with "assets"
+ auto finalPath = "assets/" + url;
+
+ helpers.call( "loadAssetAsync",emscripten::val( finalPath ),_cb );
+ }
+ }
+}
+
diff --git a/include/cinder/emscripten/EmscriptenVideo.h b/include/cinder/emscripten/EmscriptenVideo.h
new file mode 100644
index 0000000000..70a10ad96b
--- /dev/null
+++ b/include/cinder/emscripten/EmscriptenVideo.h
@@ -0,0 +1,114 @@
+/*
+ Copyright (c) 2018, The Barbarian Group
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include
+#include
+#include
+#include "cinder/Log.h"
+#include "cinder/gl/Texture.h"
+#include "cinder/gl/gl.h"
+
+namespace cinder { namespace em {
+
+ typedef std::shared_ptr< class EmscriptenVideo >EmscriptenVideoRef;
+
+ /**
+ * Basic handling of elements within Emscripten. Note that this needs companion Javascript functions
+ * declared in helpers.js
+ */
+ class EmscriptenVideo
+ {
+
+ public:
+ EmscriptenVideo();
+ EmscriptenVideo( std::string source ) ;
+ EmscriptenVideo( ci::DataSourceRef source );
+
+ static EmscriptenVideoRef create()
+ {
+ return EmscriptenVideoRef( new EmscriptenVideo );
+ }
+
+ static EmscriptenVideoRef create( std::string source )
+ {
+ return EmscriptenVideoRef( new EmscriptenVideo( source ) );
+ }
+
+ static EmscriptenVideoRef create( ci::DataSourceRef source )
+ {
+ return EmscriptenVideoRef( new EmscriptenVideo( source ) );
+ }
+
+ void setTextureFormat( ci::gl::Texture::Format fmt );
+
+ //! Returns the texture for the video
+ ci::gl::TextureRef getTexture();
+
+ //! Returns whether or not there is enough data to qualifiy that the video has loaded.
+ //! Note that this DOES NOT indicate that the video has completely downloaded.
+ bool hasVideoLoaded();
+
+ //! Returns the width of the video
+ int getWidth();
+
+ //! Returns the height of the video.
+ int getHeight();
+
+ //! Plays the video
+ void play();
+
+ //! Pauses the video
+ void pause();
+
+ //! Sets the source for the video element. When the video is done loading and we
+ //! have the metadata for the video, the function onLoadMetadata gets called.
+ void setSource( std::string url );
+
+ //! Returns whether or not the video is playing.
+ bool isPlaying();
+
+ //! Updates texture for the video.
+ void updateTexture();
+
+ private:
+ bool mCustomFormatSet;
+
+ // video texture settings
+ ci::gl::Texture::Format mVideoTextureFormat;
+
+ //! The element to hold the the html element
+ emscripten::val mElement = emscripten::val::undefined();
+
+ //! Texture used to display the video
+ ci::gl::TextureRef mTexture;
+
+ //! Whether or not the video has loaded
+ bool mIsLoaded;
+
+ //! Internal callback - handles texture creation and setup when enough of the
+ //! video has downloaded.
+ void onLoadMetadata( emscripten::val e );
+ };
+
+ }}
diff --git a/include/cinder/emscripten/HTML.h b/include/cinder/emscripten/HTML.h
new file mode 100644
index 0000000000..dc3e708eca
--- /dev/null
+++ b/include/cinder/emscripten/HTML.h
@@ -0,0 +1,116 @@
+#include
+#include
+#include
+
+/**
+ * Some potentially helpful functions if you wish to interact with the DOM
+ */
+
+namespace cinder { namespace em { namespace html {
+
+
+ //! creates an HTML element. Pass in the tag name as the parameter.
+ //! Note that you could technically pass in anything so there will be no error
+ //! if you pass in something that isn't an actual tag as according to the current
+ //! HTML spec.
+ static emscripten::val createElement( std::string el )
+ {
+ return emscripten::val::global( "document" ).call( "createElement", emscripten::val(el) );
+ }
+
+ //! Helper to return the document object.
+ static emscripten::val getDocument()
+ {
+ return emscripten::val::global( "document" );
+ }
+
+ //! helper to return the window object
+ static emscripten::val getWindow()
+ {
+ return emscripten::val::global( "window" );
+ }
+
+ static emscripten::val querySelector( std::string selector )
+ {
+ emscripten::val document = getDocument();
+ return document.call( "querySelector",emscripten::val( selector ) );
+ }
+
+ //! appends one element to another. Pass in the selector (can be id or className) of the parent element
+ //! and the emscripten::val element you want to append to the parent.
+ static void appendTo( std::string selector,emscripten::val el )
+ {
+ // note - will throw error in console if element doesn't exist.
+ emscripten::val node = getDocument().call( "querySelector",emscripten::val( selector ) );
+ node.call( "appendChild",el );
+ }
+
+ //! same as above but parent is assumed to have already been found
+ static void appendTo( emscripten::val parent ,emscripten::val el )
+ {
+
+ parent.call( "appendChild",el );
+ }
+
+ /**
+ * Small wrapper around some of the workings of the emscripten::val object to
+ * allow you to easily add HTML elements.
+ */
+ class HTMLElement
+ {
+
+
+ public:
+ HTMLElement( std::string el="" ):mElement( emscripten::val::undefined() )
+ {
+ // TODO maybe do querySelector if we know the el parameter is an id or classname?
+ if( el != "" )
+ {
+ mElement = createElement( el) ;
+ }
+ }
+
+ //! sets classname property on the element
+ void setClassName( std::string id )
+ {
+ mElement.set( "className" ,emscripten::val( id ) );
+ }
+
+ //! sets id property on the element
+ void setId( std::string id )
+ {
+ mElement.set( "id" ,emscripten::val( id ) );
+ }
+
+ //! sets the style property on the element
+ void css( std::string styles )
+ {
+ mElement.set( "style", emscripten::val( styles ) );
+ }
+
+ //! sets an attribute on the element.
+ //! note that you should only pass in types that are appropriate or you may
+ //! get un-expected behavior.
+ template
+ void setAttribute( std::string name, T value )
+ {
+ mElement.set( name, emscripten::val( value ) );
+ }
+
+ //! appends a child element to this element.
+ void appendChild( emscripten::val el )
+ {
+ mElement.call( "appendChild",el );
+ }
+
+ //! appends this element to another element
+ void appendToEl( std::string el )
+ {
+ appendTo(el,mElement);
+ }
+
+ private:
+ emscripten::val mElement;
+
+ };
+}}}
\ No newline at end of file
diff --git a/include/cinder/emscripten/JSObject.h b/include/cinder/emscripten/JSObject.h
new file mode 100644
index 0000000000..1af2c44388
--- /dev/null
+++ b/include/cinder/emscripten/JSObject.h
@@ -0,0 +1,97 @@
+#pragma once
+
+#include
+#include
+#include
+#include "cinder/Log.h"
+#include "cinder/gl/Texture.h"
+#include "cinder/gl/gl.h"
+
+
+namespace cinder { namespace em {
+
+ typedef std::shared_ptr JSObjRef;
+
+ class JSObject {
+ public:
+ JSObject():obj( emscripten::val::undefined() ){
+
+ auto Object = emscripten::val::global( "window" )[ "Object" ];
+ obj = Object.new_();
+ }
+ ~JSObject(){}
+
+ static JSObjRef create() {
+ return JSObjRef( new JSObject() );
+ }
+
+ template
+ void set(std::string prop, T value ) {
+ if( std::is_same< T, std::string >::value||
+ std::is_same< T, int>::value ||
+ std::is_same< T, float >::value ||
+ std::is_same< T, emscripten::val>::value ) {
+ obj.set( prop, value );
+ } else {
+ // otherwise we return because we can't handle values other than simple types.
+ // you can technically add more handlers through the EMSCRIPTEN_BINDINGS macro.
+ return;
+ }
+ }
+
+ // Returns a value on the JSObject in
+ int getIntValue( std::string prop ) {
+ return obj[ prop ].as();
+ }
+
+ float getFloatValue( std::string prop ) {
+ return obj[ prop ].as();
+ }
+
+ std::string getStringValue( std::string prop ) {
+ return obj[ prop ].as();
+ }
+
+ //! Returns either the representation of the Javascript object or
+ // if the optional property name is passed, it will return the property value
+ // that is on the JSObject.
+ emscripten::val get( std::string prop="" ) {
+ if( prop != "" ) {
+ return obj[ prop ];
+ }else {
+ return obj;
+ }
+ }
+
+ void log(){
+ auto helpers = emscripten::val::global( "window" )[ "CINDER_HELPERS" ];
+ helpers.call( "logNode", obj );
+ }
+
+ void log( std::string prop ) {
+ auto helpers = emscripten::val::global( "window" )[ "CINDER_HELPERS" ];
+ helpers.call( "logNode",obj[ prop ]);
+ }
+
+ //! returns an emscripten::val object referencing the document global
+ static emscripten::val document() {
+ return emscripten::val::global( "document" );
+ }
+
+ //! returns an emscripten::val object referencing the window global
+ static emscripten::val window() {
+ return emscripten::val::global( "window" );
+ }
+
+ static emscripten::val JSON(){
+ return emscripten::val::global("JSON");
+ }
+
+
+
+ protected:
+ emscripten::val obj;
+
+ };
+
+}}
\ No newline at end of file
diff --git a/include/cinder/emscripten/UrlImplEmscripten.h b/include/cinder/emscripten/UrlImplEmscripten.h
new file mode 100644
index 0000000000..17c63d71ef
--- /dev/null
+++ b/include/cinder/emscripten/UrlImplEmscripten.h
@@ -0,0 +1,96 @@
+/*
+ Copyright (c) 2015, The Cinder Project (http://libcinder.org)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "cinder/Url.h"
+#include "cinder/Buffer.h"
+#include
+#include "cinder/Log.h"
+
+namespace cinder {
+
+/**
+ * A UrlImpl implementation for Emscripten.
+ * Uses native emscripten function to fetch content from a remote source.
+ */
+class IStreamUrlImplEmscripten : public IStreamUrlImpl
+{
+ public:
+ IStreamUrlImplEmscripten( const std::string &url, const std::string &user, const std::string &password, const UrlOptions &options )
+ : IStreamUrlImpl( user, password, options )
+ {
+
+ int size,error;
+ void *tmpBuffer;
+ emscripten_wget_data( url.c_str(), &tmpBuffer, &size, &error );
+
+ if( error == 0 )
+ {
+ // create buffer
+ mData = ci::Buffer::create( size );
+
+ // write to BufferRef
+ mData->copyFrom( tmpBuffer,size );
+
+ free( tmpBuffer );
+ }
+ else {
+ //CI_LOG_I("IStreamUrlImplEmscripten constructor called - an error occured");
+ }
+ }
+
+ virtual ~IStreamUrlImplEmscripten() {}
+
+ size_t readDataAvailable( void *dest, size_t maxSize ) override
+ {
+ size_t numBytesRead = 0;
+ if( mData )
+ {
+ size_t readSize = std::min( mData->getSize(), maxSize );
+ if( readSize > 0 )
+ {
+ memcpy( dest, (const void *)mData->getData(), readSize );
+ numBytesRead = readSize;
+ }
+ }
+ return numBytesRead;
+ }
+
+ void seekAbsolute( off_t absoluteOffset ) override {}
+ void seekRelative( off_t relativeOffset ) override {}
+ off_t tell() const override { return -1; }
+ off_t size() const override
+ {
+ off_t result = mData ? mData->getSize() : 0;
+ return result;
+ }
+
+ bool isEof() const override { return true; }
+ void IORead( void *t, size_t size ) override {}
+
+ private:
+ ci::BufferRef mData;
+ off_t mOffset;
+};
+
+} // namespace cinder
diff --git a/include/cinder/emscripten/Worker.h b/include/cinder/emscripten/Worker.h
new file mode 100644
index 0000000000..b197b433d4
--- /dev/null
+++ b/include/cinder/emscripten/Worker.h
@@ -0,0 +1,60 @@
+#pragma once
+#include
+#include
+#include
+#include
+
+namespace cinder { namespace em {
+
+ /**
+ * A basic implementation for interfacing with WebWorkers. This is assuming you've already made a
+ * separate WebWorker project and have it compiled within your app.
+ * Note that this may not work with WebWorkers that were compiled normally and written in native Javascript.
+ */
+ class Worker
+ {
+
+ //! handle to the web worker.
+ worker_handle worker;
+
+ //! handle to callback function for the worker.
+ em_worker_callback_func callback;
+
+ public:
+ Worker(){}
+
+ //! Loads the worker. Pass in the path to the compiled worker script.
+ void loadWorker( std::string path )
+ {
+ worker = emscripten_create_worker( path.c_str() );
+ }
+
+ //! Sets the callback function to use when a message is received from the worker.
+ void setOnMessageCallback( em_worker_callback_func callback )
+ {
+ this->callback = callback;
+ }
+
+ //! Posts a message to the web worker.
+ //! It assumes the function you want to send information to is called "onmessage"
+ //! Accepts some user arguments.
+ //! Takes in an char * of data used to transfer data back and forth.
+ //! Needs the size of that data ( sizeof() (and if necessary * numItems)).
+ void postMessage( const char * funcname="onmessage", char * data=0, int size=0, void* args = ( void* )0 )
+ {
+ emscripten_call_worker( worker,funcname,data,size,callback,args );
+ }
+
+ //! Posts a message to the web worker.
+ //! It assumes the function you want to send information to is called "onmessage"
+ //! Accepts some user arguments.
+ //! Takes in an char * of data used to transfer data back and forth.
+ //! Needs the size of that data ( sizeof() (and if necessary * numItems)).
+ //! This version also allows you to specify a different callback to run as opposed to the main one in the class.
+ void postMessageWithCallback( const char * funcname="onmessage", char * data=0, int size=0,em_worker_callback_func _callback=nullptr,void* args = (void*)0)
+ {
+ emscripten_call_worker( worker,funcname,data,size,_callback,args );
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/include/cinder/emscripten/externs.js b/include/cinder/emscripten/externs.js
new file mode 100644
index 0000000000..aa9d9bf1cf
--- /dev/null
+++ b/include/cinder/emscripten/externs.js
@@ -0,0 +1,4 @@
+// externs are needed when doing production minified builds as the naming will get mangled.
+// this acts like a lookup table to figure out which mangled names belong where.
+window.CINDER_VIDEO = {};
+window.CINDER_HELPERS = {};
diff --git a/include/cinder/emscripten/helpers.js b/include/cinder/emscripten/helpers.js
new file mode 100644
index 0000000000..9dc1b051fe
--- /dev/null
+++ b/include/cinder/emscripten/helpers.js
@@ -0,0 +1,483 @@
+/**
+ Defines some additional javascript to make some video related things easier.
+ */
+window.CINDER_ASYNC = {
+
+ /**
+ * An async loading function to use in place of ci::app::loadAsset
+ * Pass in a string for the url and a callback function.
+ * @param {String} url the url of the asset you want to load
+ * @param {Function} cb the callback function to call once the asset is done loading.
+ */
+ loadAssetAsync:function( url,cb )
+ {
+
+ // =========== DETERMINE FILE TYPE ================ //
+
+ // we can't decode video into raw info on the web without a lot of potentially time
+ // consuming manuvers so direct users to use Emscriptenvideo object instead.
+ var videoExtensions = [ ".mp4", ".mov",".webm" ]
+ videoExtensions.forEach( function( itm )
+ {
+ if( url.search( itm ) !== -1 )
+ {
+ console.error( "loadAsync was called seemingly with the intention of loading video. Please use EmscriptenVideo object instead. \n The path was " + url );
+ return;
+ }
+ });
+
+ // if audio file, load with existing helpers.
+ // TODO not sure if things work similarly to WebGL where contexts are tied to specific contexts as in this case we'd make a new AudioContext.
+ var audioExtensions = [ ".mp3",".ogg",".wav" ];
+ var isAudio = false;
+ audioExtensions.forEach( function( itm ) {
+ if( url.search( itm ) !== -1)
+ {
+ CINDER_AUDIO.loadAudioFile( url,undefined,cb );
+ isAudio = true;
+ }
+ });
+
+
+ if( isAudio )
+ {
+ return;
+ }
+
+
+ var isImage = false;
+ var imgExtensions = [ ".png",".jpg",".gif",".webp",".jpeg" ];
+ imgExtensions.forEach( function( itm )
+ {
+ if( url.search( itm ) !== -1 )
+ {
+ isImage = true;
+ }
+ });
+
+ // if image, use XMLHttpRequest to load binary data, otherwise use
+ // fetch to load textual data.
+ if( isImage )
+ {
+ var req = new XMLHttpRequest();
+ req.open( 'GET', url );
+ req.responseType = "arraybuffer"
+ req.onload = function( e )
+ {
+ var byteArray = req.response;
+
+ byteArray = new Uint8Array( byteArray );
+ if( byteArray )
+ {
+ cb( byteArray );
+ }
+ }
+
+ req.onerror = function()
+ {
+ console.error( "Unable to load file at ",url );
+ }
+
+ req.send();
+ }
+ else {
+
+ fetch( url ).then( function( res )
+ {
+ return res.text();
+ }).then( function( data )
+ {
+ cb( data );
+ }).catch( function()
+ {
+ console.error( "Issue loading ", url );
+ })
+ }
+ }
+};
+
+window.CINDER_HELPERS = {
+
+ /**
+ * Logs the node to the console if you need to examine any attributes / values
+ * @param {emscripten::val} e
+ */
+ logNode:function( e ) {
+ console.log(e);
+ },
+
+ // returns the browser you're using. Looking for Firefox / Chrome since those
+ // present the best experiences. If it's not Firefox / Chrome, return full user agent string
+ getBrowser:function()
+ {
+ //TODO
+ if( navigator.userAgent.indexOf( 'FireFox' ) !== -1 )
+ {
+ return "Firefox";
+ }
+ else if( navigator.userAgent.indexOf( 'Chrome' ) !== -1 )
+ {
+ return "Chrome";
+ }
+ else {
+ return navigator.userAgent;
+ }
+ },
+
+ /**
+ * Helper to quickly load data binary. Should be used when constructing
+ * your own html shell and you require a custom configuration that
+ * can't be met by just including {{SCRIPT}} - a similar function is included already when using
+ * default emscripten shell.
+ * @param {String} filename filename to load
+ * @param {String} srcFile path to js that will initiate asm.js/wasm load
+ */
+ loadEmterpreterBinary:function( filename,srcFile )
+ {
+
+ var emterpretURL = filename;
+ var emterpretXHR = new XMLHttpRequest();
+ emterpretXHR.open( 'GET', emterpretURL, true );
+ emterpretXHR.responseType = 'arraybuffer';
+
+ emterpretXHR.onload = function()
+ {
+ if ( emterpretXHR.status === 200 || emterpretXHR.status === 0 )
+ {
+ Module.emterpreterFile = emterpretXHR.response;
+ }
+ else {
+ var emterpretURLBytes = tryParseAsDataURI( emterpretURL );
+
+ if ( emterpretURLBytes )
+ {
+ Module.emterpreterFile = emterpretURLBytes.buffer;
+ }
+ }
+
+ var script = document.createElement( 'script' );
+ script.src = srcFile;
+ document.body.appendChild( script );
+ };
+
+ emterpretXHR.send( null );
+
+ },
+
+ /**
+ * Returns a new emscripten::val value representing a TypedArray buffer.
+ * @param {Number} size - the size for the array.
+ */
+ getFloatArray:function( size )
+ {
+ return new Float32Array( size );
+ }
+ };
+
+// all audio related functionality
+window.CINDER_AUDIO = {
+
+ //! all of the nodes
+ workletNodes:[],
+
+ // creates an AudioContext - does so to take into account of situations where
+ // things deviate from the norm, ie safari requiring "webkitAudioContext" instead of just "AudioContext"
+ createContext:function()
+ {
+ return new ( window.AudioContext || window.webkitAudioContext )();
+ },
+
+ /**
+ * This is a helper function used by NativeWebAudioNodes to disconnect a script processor
+ * from the context when it's done converting it's data to something c++ compatible
+ * @param {ScriptProcessorNode} processor an emscripten::val reference to the node's ScriptProcessorNode
+ * @param {Number} delay the number of seconds to delay prior to disconnection to ensure all the data is processed.
+ */
+ disconnectScriptFromDestination:function( processor,delay )
+ {
+ delay = delay !== undefined ? delay : 0;
+ setTimeout(function()
+ {
+ processor.onaudioprocess = null;
+ processor.disconnect( window.CINDER_AUDIO.globalContext[ "destination" ] );
+ },delay);
+ },
+
+ /**
+ * Connects 2 nodes to each other .
+ * TODO probably should check to make sure they are both audio nodes.
+ */
+ connectNodes:function( node1,node2 )
+ {
+ if( node1 instanceof AudioNode && node2 instanceof AudioNode )
+ {
+ node1.connect( node2 );
+ }
+ },
+
+ /**
+ * Obtains an input audio stream to a microphone.
+ * @param {Function} callback - a callback value that is used to receive the stream when available
+ * @param {string} deviceId - an optional device id that can be used to select a particular device.
+ */
+ loadAudioInput:function( callback,deviceId )
+ {
+ if( navigator.mediaDevices.getUserMedia )
+ {
+
+ // get a stream to the specified device, if one isn't stated,
+ // get stream to default input device.
+ navigator.mediaDevices.getUserMedia({
+ audio: deviceId !== undefined || deviceId !== "" ? {deviceId:deviceId} : true,
+ video:false
+ }).then( function( stream )
+ {
+ // note that "stream" will be received as an emscripten::val object.
+ callback( stream );
+ }).catch( function( err )
+ {
+
+ if( err )
+ {
+ console.error( "There was an issue obtaining a media stream ",err );
+ throw err;
+ }
+ });
+ }
+ else{
+ alert( "Your browser does not support getUserMedia :( so unfortunately we're unable to obtain audio input " );
+ }
+ },
+
+ /**
+ * Returns the list of available input devices
+ * @param {Function} callback - the function to use to receive the list of available callback devices.
+ */
+ getAvailableDevices:function( callback )
+ {
+ navigator.mediaDevices.enumerateDevices().then(function( devices )
+ {
+ callback( devices );
+ })
+ },
+
+ // the global context for all audio processing
+ // This is done due to the issue of the audio context reference being
+ // devared when attempted to use outside of the class.
+ globalContext:new AudioContext(),
+
+ /**
+ * Loads an audio file and parses it's audio information.
+ * If for some reason something goes wrong, will log error to the dev tools console.
+ * @param {string} path - path to the audio file.
+ * @param {AudioContext} context - an emscripten::val representing a WebAudio context(aka AudioContext object)
+ * @param {Function} callback - an emscripten::val representing a callback function that will receive the decoded audio information.
+ */
+ loadAudioFile:function( path,context,callback )
+ {
+ // use a new audio context if user did not pass one in.
+ context = context !== undefined ? context : new AudioContext();
+
+ fetch( path ).then(function( res )
+ {
+ //perhaps one of the great failings of the fetch api - need to
+ // return audio as an ArrayBuffer first.
+ return res.arrayBuffer();
+ }).then(function( buffer )
+ {
+ // decode the audio data
+ context.decodeAudioData( buffer,function( data )
+ {
+ callback(data);
+ },function( err )
+ {
+ console.error( "error decoding audio information - ",err );
+ });
+
+ }).catch(function( err )
+ {
+ console.log("\n");
+ console.error("There was an error fetching the audio file at " + path);
+ console.error("The error message was ",err);
+ console.log("\n");
+ })
+ },
+
+ // alias for the loadAudioFile
+ loadAudio:function( path,context,callback )
+ {
+ window.CINDER_AUDIO.loadAudioFile( path,context,callback );
+ }
+ }
+
+ // for all video related functionality.
+window.CINDER_VIDEO = {
+ // some css to style warnings
+ warnCSS:[
+ "font-size:15px",
+ "color:red",
+ "background:yellow"
+ ],
+
+ /**
+ * Creates an HTML5 Video element
+ * @return {} an HTML5 Video element.
+ */
+ createVideo:function()
+ {
+
+ // =========== BUILD OUT OUR SPECIAL VIDEO ELEMENT ================= //
+
+ // normally bad practice but for convinience sake, gonna augment a video object with
+ // some extra methods and helpers.
+
+ var video = document.createElement( "video" );
+
+ // get the width of the texture
+ video.getWidth = function()
+ {
+ return video.videoWidth;
+ }
+
+ // get the height of the texture
+ video.getHeight = function()
+ {
+ return video.videoHeight;
+ };
+
+ // sets the texture onto the video object for easy access.
+ // Note that GL.textures is populated by Emscripten.
+ // All ci::Texture::create calls will make textures that get populated into
+ // that array.
+ video.setTexture = function( id )
+ {
+ this.texture = GL.textures[ id ];
+ }
+
+ // Call to update the video element's texture with new information.
+ video.updateTexture = function()
+ {
+ var texture = this.texture;
+ var gl = GLctx;
+
+ gl.bindTexture( gl.TEXTURE_2D,texture );
+ gl.texImage2D( gl.TEXTURE_2D,0,gl.RGBA,this.videoWidth,this.videoHeight,0,gl.RGBA,gl.UNSIGNED_BYTE,this );
+ gl.bindTexture (gl.TEXTURE_2D,null );
+ }
+
+ // allow cross-origin videos to be able to play.
+ // Note that you will have to set up external servers to handle cross-origin requests.
+ video.crossOrigin = "anonymous";
+
+ return video;
+ }
+}
+
+/**
+ * Deals with .
+ */
+window.CINDER_FILEIO = {
+
+ /**
+ * Converts a source string into a Blob object that's suitable for
+ * passing into new WebWorker and Audioworklet instances.
+ * @param {String} source the source string that you want to make into a blob.
+ */
+ sourceToBlob:function(source){
+ var blob = new Blob([source],{
+ type:'application/javascript'
+ });
+
+ return URL.createObjectURL(blob);
+
+ },
+
+ /**
+ * Loads a WebWorker.
+ * @param {String} source Pass in the source for that web worker.
+ * @returns {WebWorker} returns an emscripten::val instance of the WebWorker object.
+ */
+ loadWorker:function(source){
+ return new Worker(this.sourceToBlob(source));
+ },
+
+ /**
+ * Loads an Audioworklet processor script
+ * @param {String} source The source for the script
+ * @param {Function} cb a function to run when the script has been instantiated and registered.
+ */
+ loadProcessor:function(source,cb){
+ var context = window.CINDER_AUDIO.globalContext;
+
+ context.audioworklet.addModule(this.sourceToBlob(source)).then(cb)
+ .catch( function() {
+ console.error("There was an error loading the processor");
+ });
+ }
+}
+
+
+// =================== TESTING =======================//
+
+
+window.CINDER_WORKLETS = {
+
+ // an array holding the chain of nodes to string together.
+ // will start out reversed, but eventually re-order itself properly
+ graph:[],
+
+ /**
+ * Creates a AudioworkletNode that is used to handle custom processing.
+ * @param {Function} processFunc
+ */
+ createworkletNode:function(processFunc){
+
+ this.graph.push(processFunc);
+
+ },
+
+ /**
+ * Removes all items in the graph;
+ */
+ clearGraph:function(){
+ this.graph = [];
+ },
+
+
+ /**
+ * Goes through the graph and executes commands where necessary
+ * to finish initializing everything. Afterwards things get connected.
+ */
+ sortGraph:function()
+ {
+ // first reverse graph cause things are gonna get inserted in the wrong order for
+ // ease of use
+ var graph = this.graph.reverse();
+
+ // gotta remove the first item for some reason - probably cause we aren't setting AudioContext as "enabled"
+ graph.shift();
+
+ // check graph to see if any items are just functions, if they are we they are custom nodes and we need to instantiate
+ // a custom AudioWorketNode
+ graph = graph.map(function(itm) {
+ if(itm !== undefined){
+ if(typeof itm === "function"){
+ return new CustomNode(itm);
+
+ }else{
+ return itm;
+ }
+ }
+ });
+
+ // connect all the nodes together.
+ for(var i = 0; i < graph.length-1; ++i){
+ if(i !== graph.length - 1){
+ var start = graph[i];
+ var next = graph[i + 1];
+ start.connect(next);
+ }
+ }
+ }
+
+};
\ No newline at end of file
diff --git a/include/cinder/gl/BufferObj.h b/include/cinder/gl/BufferObj.h
index 63061526f5..689353219d 100644
--- a/include/cinder/gl/BufferObj.h
+++ b/include/cinder/gl/BufferObj.h
@@ -64,8 +64,11 @@ class CI_API BufferObj {
#endif
#if defined( CINDER_GL_HAS_MAP_BUFFER ) || defined( CINDER_GL_HAS_MAP_BUFFER_RANGE )
+ #if ! defined( CINDER_EMSCRIPTEN )
//! Maps the Buffer for writing, but does not invalidate the Buffer's existing contents. Slower than mapReplace(). Abstracts glMapBuffer() vs. glMapBufferRange() with appropriate write-only parameters for the platform.
void* mapWriteOnly();
+ #endif
+
//! Invalidates the Buffer's existing contents and maps it for writing. Preferable to mapWriteOnly() when invalidation is acceptable. Abstracts glMapBuffer() vs. glMapBufferRange() with appropriate write-only parameters for the platform.
void* mapReplace();
#endif
diff --git a/include/cinder/gl/Environment.h b/include/cinder/gl/Environment.h
index ff9fc824c2..7e38b421af 100644
--- a/include/cinder/gl/Environment.h
+++ b/include/cinder/gl/Environment.h
@@ -60,7 +60,9 @@
#else
typedef struct GLFWwindow GLFWwindow;
#endif
-#endif
+#elif defined (CINDER_EMSCRIPTEN )
+ typedef struct GLFWwindow GLFWwindow;
+#endif
namespace cinder { namespace gl {
@@ -193,6 +195,15 @@ struct PlatformDataAndroid : public Context::PlatformData {
GLFWwindow *mContext = nullptr;
};
#endif
-#endif
+#elif defined( CINDER_EMSCRIPTEN )
+
+struct PlatformDataEmscripten : public Context::PlatformData {
+ PlatformDataEmscripten( GLFWwindow *context )
+ : mContext( context )
+ {};
+
+ GLFWwindow *mContext = nullptr;
+};
+#endif
} } // namespace cinder::gl
diff --git a/include/cinder/gl/TextureFont.h b/include/cinder/gl/TextureFont.h
index 1669811f31..5b43b14ac7 100644
--- a/include/cinder/gl/TextureFont.h
+++ b/include/cinder/gl/TextureFont.h
@@ -145,7 +145,7 @@ class CI_API TextureFont {
bool isPremultiplied() const { return mFormat.getPremultiply(); }
//! Returns the default set of characters for a TextureFont, suitable for most English text, including some common ligatures and accented vowels.
- //! \c "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890().?!,:;'\"&*=+-/\\@#_[]<>%^llflfiphrids"
+ //! \c "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890().?!,:;'\"&*=+-/\\@#_[]<>%^llflfiphrids����"
static std::string defaultChars() { return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890().?!,:;'\"&*=+-/\\@#_[]<>%^llflfiphrids\303\251\303\241\303\250\303\240"; }
struct CI_API GlyphInfo {
@@ -167,7 +167,7 @@ class CI_API TextureFont {
Font mFont;
Format mFormat;
-#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
std::map mCachedGlyphMetrics;
const std::map* getCachedGlyphMetrics() const
{ return mCachedGlyphMetrics.empty() ? nullptr : &mCachedGlyphMetrics; }
diff --git a/include/cinder/gl/platform.h b/include/cinder/gl/platform.h
index f0576b99ad..080fc30dc9 100644
--- a/include/cinder/gl/platform.h
+++ b/include/cinder/gl/platform.h
@@ -94,6 +94,12 @@
#else
#include "glad/glad.h"
#endif
+#elif defined( CINDER_EMSCRIPTEN)
+ #define GL_GLEXT_PROTOTYPES
+ #include
+ #define CINDER_GL_ES
+ #define CINDER_GL_ES_VERSION CINDER_GL_ES_VERSION_3
+
#elif ! defined( CINDER_COCOA_TOUCH ) // OS X
#if defined( __clang__ )
#pragma clang diagnostic push
@@ -120,15 +126,19 @@
// OpenGL ES
#if defined( CINDER_GL_ES )
- #if defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+ #if defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
#define GL_ES_EXT_VERSION_2_0
#endif
- #if ! defined( CINDER_COCOA_TOUCH ) && ! defined( CINDER_GL_ANGLE )
+ #if ! defined( CINDER_COCOA_TOUCH ) && ! defined( CINDER_GL_ANGLE ) && ! defined( CINDER_EMSCRIPTEN )
#include "glad/glad_es.h"
#endif
+ #ifdef CINDER_EMSCRIPTEN
+ #include
+ #endif
+
// Android and Linux
- #if defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+ #if defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
#if ! defined( CINDER_GL_ES_3_RPI )
#define CINDER_GL_HAS_DRAW_INSTANCED
#define CINDER_GL_HAS_TEXTURE_NORM16
@@ -160,7 +170,7 @@
#define CINDER_GL_HAS_MAP_BUFFER_RANGE
#endif
#define CINDER_GL_HAS_MAP_BUFFER
- #if defined( CINDER_ANDROID ) || defined( CINDER_LINUX )
+ #if defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
#define CINDER_GL_HAS_RENDER_SNORM
#define CINDER_GL_HAS_REQUIRED_INTERNALFORMAT
#endif
@@ -219,7 +229,7 @@
#if defined( CINDER_GL_ES )
#if defined( GL_KHR_debug ) && ( CINDER_GL_ES_VERSION <= CINDER_GL_ES_VERSION_3_1 ) && ( ! defined( CINDER_GL_ANGLE ) )
#define CINDER_GL_HAS_KHR_DEBUG
- #if ! defined( CINDER_GL_ANGLE )
+ #if ! defined( CINDER_GL_ANGLE ) && ! defined( CIDNER_EMSCRIPTEN )
#define GL_BUFFER GL_BUFFER_KHR
#define GL_SHADER GL_SHADER_KHR
#define GL_PROGRAM GL_PROGRAM_KHR
diff --git a/include/cinder/linux/gl_es_load.h b/include/cinder/linux/gl_es_load.h
new file mode 100644
index 0000000000..123619f3b3
--- /dev/null
+++ b/include/cinder/linux/gl_es_load.h
@@ -0,0 +1,1495 @@
+/*
+ Copyright (c) 2015, The Cinder Project, All rights reserved.
+
+ This code is intended for use with the Cinder C++ library: http://libcinder.org
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+#pragma once
+
+// -----------------------------------------------------------------------------
+// iOS
+// -----------------------------------------------------------------------------
+#if defined( CINDER_COCOA_TOUCH )
+ #if defined( CINDER_GL_ES_2 )
+ // GL_OES_texture_half_float
+ #define GL_HALF_FLOAT GL_HALF_FLOAT_OES
+
+ // GL_EXT_texture_rg
+ #define GL_RED GL_RED_EXT
+ #define GL_RG GL_RG_EXT
+ #define GL_R8 GL_R8_EXT
+ #define GL_RG8 GL_RG8_EXT
+
+ // GL_OES_rgb8_rgba8
+ #define GL_RGB8 GL_RGB8_OES
+ #define GL_RGBA8 GL_RGBA8_OES
+
+ // GL_EXT_color_buffer_half_float
+ #define GL_RGBA16F GL_RGBA16F_EXT
+ #define GL_RGB16F GL_RGB16F_EXT
+ #define GL_RG16F GL_RG16F_EXT
+ #define GL_R16F GL_R16F_EXT
+ #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT
+ #define GL_UNSIGNED_NORMALIZED GL_UNSIGNED_NORMALIZED_EXT
+
+ // GL_EXT_texture_storage
+ #define GL_RGBA32F GL_RGBA32F_EXT
+ #define GL_RGB32F GL_RGB32F_EXT
+ #define GL_RG32F GL_RG32F_EXT
+ #define GL_R32F GL_R32F_EXT
+
+ // GL_APPLE_texture_packed_float
+ #define GL_UNSIGNED_INT_10F_11F_11F_REV GL_UNSIGNED_INT_10F_11F_11F_REV_APPLE
+ #define GL_UNSIGNED_INT_5_9_9_9_REV GL_UNSIGNED_INT_5_9_9_9_REV_APPLE
+ #define GL_R11F_G11F_B10F GL_R11F_G11F_B10F_APPLE
+ #define GL_RGB9_E5 GL_RGB9_E5_APPLE
+
+ // GL_EXT_sRGB
+ #define GL_SRGB GL_SRGB_EXT
+ #define GL_SRGB_ALPHA GL_SRGB_ALPHA_EXT
+ #define GL_SRGB8_ALPHA8 GL_SRGB8_ALPHA8_EXT
+ #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT
+
+ // GL_OES_depth24
+ #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
+
+ #define GL_WRITE_ONLY GL_WRITE_ONLY_OES
+ #define GL_BUFFER_ACCESS GL_BUFFER_ACCESS_OES
+ #define GL_BUFFER_MAPPED GL_BUFFER_MAPPED_OES
+ #define GL_BUFFER_MAP_POINTER GL_BUFFER_MAP_POINTER_OES
+
+ #define GL_MAP_READ_BIT GL_MAP_READ_BIT_EXT
+ #define GL_MAP_WRITE_BIT GL_MAP_WRITE_BIT_EXT
+ #define GL_MAP_INVALIDATE_RANGE_BIT GL_MAP_INVALIDATE_RANGE_BIT_EXT
+ #define GL_MAP_INVALIDATE_BUFFER_BIT GL_MAP_INVALIDATE_BUFFER_BIT_EXT
+ #define GL_MAP_FLUSH_EXPLICIT_BIT GL_MAP_FLUSH_EXPLICIT_BIT_EXT
+ #define GL_MAP_UNSYNCHRONIZED_BIT GL_MAP_UNSYNCHRONIZED_BIT_EXT
+
+ #define GL_READ_FRAMEBUFFER GL_READ_FRAMEBUFFER_APPLE
+ #define GL_DRAW_FRAMEBUFFER GL_DRAW_FRAMEBUFFER_APPLE
+ #define GL_READ_FRAMEBUFFER_BINDING GL_READ_FRAMEBUFFER_BINDING_APPLE
+ #define GL_DRAW_FRAMEBUFFER_BINDING GL_DRAW_FRAMEBUFFER_BINDING_APPLE
+
+ #define glBindVertexArray glBindVertexArrayOES
+ #define glDeleteVertexArrays glDeleteVertexArraysOES
+ #define glGenVertexArrays glGenVertexArraysOES
+ #define glIsVertexArray glIsVertexArrayOES
+
+ #define glMapBuffer glMapBufferOES
+ #define glUnmapBuffer glUnmapBufferOES
+
+ #define glMapBufferRange glMapBufferRangeEXT
+
+ #define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE
+ #define glResolveMultisampleFramebuffer glResolveMultisampleFramebufferAPPLE
+
+ #define glVertexAttribDivisor glVertexAttribDivisorEXT
+ #endif
+
+// -----------------------------------------------------------------------------
+// Android and Linux
+// -----------------------------------------------------------------------------
+#elif ( defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN ) )
+ // ----------------------------------------------------------------------------
+ // OpenGL ES 3.0
+ // ----------------------------------------------------------------------------
+ #if defined( CINDER_LINUX ) && ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_3 )
+ extern PFNGLREADBUFFERPROC fnptr_ci_glReadBuffer;
+ extern PFNGLDRAWRANGEELEMENTSPROC fnptr_ci_glDrawRangeElements;
+ extern PFNGLTEXIMAGE3DPROC fnptr_ci_glTexImage3D;
+ extern PFNGLTEXSUBIMAGE3DPROC fnptr_ci_glTexSubImage3D;
+ extern PFNGLCOPYTEXSUBIMAGE3DPROC fnptr_ci_glCopyTexSubImage3D;
+ extern PFNGLCOMPRESSEDTEXIMAGE3DPROC fnptr_ci_glCompressedTexImage3D;
+ extern PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC fnptr_ci_glCompressedTexSubImage3D;
+ extern PFNGLGENQUERIESPROC fnptr_ci_glGenQueries;
+ extern PFNGLDELETEQUERIESPROC fnptr_ci_glDeleteQueries;
+ extern PFNGLISQUERYPROC fnptr_ci_glIsQuery;
+ extern PFNGLBEGINQUERYPROC fnptr_ci_glBeginQuery;
+ extern PFNGLENDQUERYPROC fnptr_ci_glEndQuery;
+ extern PFNGLGETQUERYIVPROC fnptr_ci_glGetQueryiv;
+ extern PFNGLGETQUERYOBJECTUIVPROC fnptr_ci_glGetQueryObjectuiv;
+ extern PFNGLUNMAPBUFFERPROC fnptr_ci_glUnmapBuffer;
+ extern PFNGLGETBUFFERPOINTERVPROC fnptr_ci_glGetBufferPointerv;
+ extern PFNGLDRAWBUFFERSPROC fnptr_ci_glDrawBuffers;
+ extern PFNGLUNIFORMMATRIX2X3FVPROC fnptr_ci_glUniformMatrix2x3fv;
+ extern PFNGLUNIFORMMATRIX3X2FVPROC fnptr_ci_glUniformMatrix3x2fv;
+ extern PFNGLUNIFORMMATRIX2X4FVPROC fnptr_ci_glUniformMatrix2x4fv;
+ extern PFNGLUNIFORMMATRIX4X2FVPROC fnptr_ci_glUniformMatrix4x2fv;
+ extern PFNGLUNIFORMMATRIX3X4FVPROC fnptr_ci_glUniformMatrix3x4fv;
+ extern PFNGLUNIFORMMATRIX4X3FVPROC fnptr_ci_glUniformMatrix4x3fv;
+ extern PFNGLBLITFRAMEBUFFERPROC fnptr_ci_glBlitFramebuffer;
+ extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC fnptr_ci_glRenderbufferStorageMultisample;
+ extern PFNGLFRAMEBUFFERTEXTURELAYERPROC fnptr_ci_glFramebufferTextureLayer;
+ extern PFNGLMAPBUFFERRANGEPROC fnptr_ci_glMapBufferRange;
+ extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC fnptr_ci_glFlushMappedBufferRange;
+ extern PFNGLBINDVERTEXARRAYPROC fnptr_ci_glBindVertexArray;
+ extern PFNGLDELETEVERTEXARRAYSPROC fnptr_ci_glDeleteVertexArrays;
+ extern PFNGLGENVERTEXARRAYSPROC fnptr_ci_glGenVertexArrays;
+ extern PFNGLISVERTEXARRAYPROC fnptr_ci_glIsVertexArray;
+ extern PFNGLGETINTEGERI_VPROC fnptr_ci_glGetIntegeri_v;
+ extern PFNGLBEGINTRANSFORMFEEDBACKPROC fnptr_ci_glBeginTransformFeedback;
+ extern PFNGLENDTRANSFORMFEEDBACKPROC fnptr_ci_glEndTransformFeedback;
+ extern PFNGLBINDBUFFERRANGEPROC fnptr_ci_glBindBufferRange;
+ extern PFNGLBINDBUFFERBASEPROC fnptr_ci_glBindBufferBase;
+ extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC fnptr_ci_glTransformFeedbackVaryings;
+ extern PFNGLGETTRANSFORMFEEDBACKVARYINGPROC fnptr_ci_glGetTransformFeedbackVarying;
+ extern PFNGLVERTEXATTRIBIPOINTERPROC fnptr_ci_glVertexAttribIPointer;
+ extern PFNGLGETVERTEXATTRIBIIVPROC fnptr_ci_glGetVertexAttribIiv;
+ extern PFNGLGETVERTEXATTRIBIUIVPROC fnptr_ci_glGetVertexAttribIuiv;
+ extern PFNGLVERTEXATTRIBI4IPROC fnptr_ci_glVertexAttribI4i;
+ extern PFNGLVERTEXATTRIBI4UIPROC fnptr_ci_glVertexAttribI4ui;
+ extern PFNGLVERTEXATTRIBI4IVPROC fnptr_ci_glVertexAttribI4iv;
+ extern PFNGLVERTEXATTRIBI4UIVPROC fnptr_ci_glVertexAttribI4uiv;
+ extern PFNGLGETUNIFORMUIVPROC fnptr_ci_glGetUniformuiv;
+ extern PFNGLGETFRAGDATALOCATIONPROC fnptr_ci_glGetFragDataLocation;
+ extern PFNGLUNIFORM1UIPROC fnptr_ci_glUniform1ui;
+ extern PFNGLUNIFORM2UIPROC fnptr_ci_glUniform2ui;
+ extern PFNGLUNIFORM3UIPROC fnptr_ci_glUniform3ui;
+ extern PFNGLUNIFORM4UIPROC fnptr_ci_glUniform4ui;
+ extern PFNGLUNIFORM1UIVPROC fnptr_ci_glUniform1uiv;
+ extern PFNGLUNIFORM2UIVPROC fnptr_ci_glUniform2uiv;
+ extern PFNGLUNIFORM3UIVPROC fnptr_ci_glUniform3uiv;
+ extern PFNGLUNIFORM4UIVPROC fnptr_ci_glUniform4uiv;
+ extern PFNGLCLEARBUFFERIVPROC fnptr_ci_glClearBufferiv;
+ extern PFNGLCLEARBUFFERUIVPROC fnptr_ci_glClearBufferuiv;
+ extern PFNGLCLEARBUFFERFVPROC fnptr_ci_glClearBufferfv;
+ extern PFNGLCLEARBUFFERFIPROC fnptr_ci_glClearBufferfi;
+ extern PFNGLGETSTRINGIPROC fnptr_ci_glGetStringi;
+ extern PFNGLCOPYBUFFERSUBDATAPROC fnptr_ci_glCopyBufferSubData;
+ extern PFNGLGETUNIFORMINDICESPROC fnptr_ci_glGetUniformIndices;
+ extern PFNGLGETACTIVEUNIFORMSIVPROC fnptr_ci_glGetActiveUniformsiv;
+ extern PFNGLGETUNIFORMBLOCKINDEXPROC fnptr_ci_glGetUniformBlockIndex;
+ extern PFNGLGETACTIVEUNIFORMBLOCKIVPROC fnptr_ci_glGetActiveUniformBlockiv;
+ extern PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC fnptr_ci_glGetActiveUniformBlockName;
+ extern PFNGLUNIFORMBLOCKBINDINGPROC fnptr_ci_glUniformBlockBinding;
+ extern PFNGLDRAWARRAYSINSTANCEDPROC fnptr_ci_glDrawArraysInstanced;
+ extern PFNGLDRAWELEMENTSINSTANCEDPROC fnptr_ci_glDrawElementsInstanced;
+ extern PFNGLFENCESYNCPROC fnptr_ci_glFenceSync;
+ extern PFNGLISSYNCPROC fnptr_ci_glIsSync;
+ extern PFNGLDELETESYNCPROC fnptr_ci_glDeleteSync;
+ extern PFNGLCLIENTWAITSYNCPROC fnptr_ci_glClientWaitSync;
+ extern PFNGLWAITSYNCPROC fnptr_ci_glWaitSync;
+ extern PFNGLGETINTEGER64VPROC fnptr_ci_glGetInteger64v;
+ extern PFNGLGETSYNCIVPROC fnptr_ci_glGetSynciv;
+ extern PFNGLGETINTEGER64I_VPROC fnptr_ci_glGetInteger64i_v;
+ extern PFNGLGETBUFFERPARAMETERI64VPROC fnptr_ci_glGetBufferParameteri64v;
+ extern PFNGLGENSAMPLERSPROC fnptr_ci_glGenSamplers;
+ extern PFNGLDELETESAMPLERSPROC fnptr_ci_glDeleteSamplers;
+ extern PFNGLISSAMPLERPROC fnptr_ci_glIsSampler;
+ extern PFNGLBINDSAMPLERPROC fnptr_ci_glBindSampler;
+ extern PFNGLSAMPLERPARAMETERIPROC fnptr_ci_glSamplerParameteri;
+ extern PFNGLSAMPLERPARAMETERIVPROC fnptr_ci_glSamplerParameteriv;
+ extern PFNGLSAMPLERPARAMETERFPROC fnptr_ci_glSamplerParameterf;
+ extern PFNGLSAMPLERPARAMETERFVPROC fnptr_ci_glSamplerParameterfv;
+ extern PFNGLGETSAMPLERPARAMETERIVPROC fnptr_ci_glGetSamplerParameteriv;
+ extern PFNGLGETSAMPLERPARAMETERFVPROC fnptr_ci_glGetSamplerParameterfv;
+ extern PFNGLVERTEXATTRIBDIVISORPROC fnptr_ci_glVertexAttribDivisor;
+ extern PFNGLBINDTRANSFORMFEEDBACKPROC fnptr_ci_glBindTransformFeedback;
+ extern PFNGLDELETETRANSFORMFEEDBACKSPROC fnptr_ci_glDeleteTransformFeedbacks;
+ extern PFNGLGENTRANSFORMFEEDBACKSPROC fnptr_ci_glGenTransformFeedbacks;
+ extern PFNGLISTRANSFORMFEEDBACKPROC fnptr_ci_glIsTransformFeedback;
+ extern PFNGLPAUSETRANSFORMFEEDBACKPROC fnptr_ci_glPauseTransformFeedback;
+ extern PFNGLRESUMETRANSFORMFEEDBACKPROC fnptr_ci_glResumeTransformFeedback;
+ extern PFNGLGETPROGRAMBINARYPROC fnptr_ci_glGetProgramBinary;
+ extern PFNGLPROGRAMBINARYPROC fnptr_ci_glProgramBinary;
+ extern PFNGLPROGRAMPARAMETERIPROC fnptr_ci_glProgramParameteri;
+ extern PFNGLINVALIDATEFRAMEBUFFERPROC fnptr_ci_glInvalidateFramebuffer;
+ extern PFNGLINVALIDATESUBFRAMEBUFFERPROC fnptr_ci_glInvalidateSubFramebuffer;
+ extern PFNGLTEXSTORAGE2DPROC fnptr_ci_glTexStorage2D;
+ extern PFNGLTEXSTORAGE3DPROC fnptr_ci_glTexStorage3D;
+ extern PFNGLGETINTERNALFORMATIVPROC fnptr_ci_glGetInternalformativ;
+
+ #define glReadBuffer fnptr_ci_glReadBuffer
+ #define glDrawRangeElements fnptr_ci_glDrawRangeElements
+ #define glTexImage3D fnptr_ci_glTexImage3D
+ #define glTexSubImage3D fnptr_ci_glTexSubImage3D
+ #define glCopyTexSubImage3D fnptr_ci_glCopyTexSubImage3D
+ #define glCompressedTexImage3D fnptr_ci_glCompressedTexImage3D
+ #define glCompressedTexSubImage3D fnptr_ci_glCompressedTexSubImage3D
+ #define glGenQueries fnptr_ci_glGenQueries
+ #define glDeleteQueries fnptr_ci_glDeleteQueries
+ #define glIsQuery fnptr_ci_glIsQuery
+ #define glBeginQuery fnptr_ci_glBeginQuery
+ #define glEndQuery fnptr_ci_glEndQuery
+ #define glGetQueryiv fnptr_ci_glGetQueryiv
+ #define glGetQueryObjectuiv fnptr_ci_glGetQueryObjectuiv
+ #define glUnmapBuffer fnptr_ci_glUnmapBuffer
+ #define glGetBufferPointerv fnptr_ci_glGetBufferPointerv
+ #define glDrawBuffers fnptr_ci_glDrawBuffers
+ #define glUniformMatrix2x3fv fnptr_ci_glUniformMatrix2x3fv
+ #define glUniformMatrix3x2fv fnptr_ci_glUniformMatrix3x2fv
+ #define glUniformMatrix2x4fv fnptr_ci_glUniformMatrix2x4fv
+ #define glUniformMatrix4x2fv fnptr_ci_glUniformMatrix4x2fv
+ #define glUniformMatrix3x4fv fnptr_ci_glUniformMatrix3x4fv
+ #define glUniformMatrix4x3fv fnptr_ci_glUniformMatrix4x3fv
+ #define glBlitFramebuffer fnptr_ci_glBlitFramebuffer
+ #define glRenderbufferStorageMultisample fnptr_ci_glRenderbufferStorageMultisample
+ #define glFramebufferTextureLayer fnptr_ci_glFramebufferTextureLayer
+ #define glMapBufferRange fnptr_ci_glMapBufferRange
+ #define glFlushMappedBufferRange fnptr_ci_glFlushMappedBufferRange
+ #define glBindVertexArray fnptr_ci_glBindVertexArray
+ #define glDeleteVertexArrays fnptr_ci_glDeleteVertexArrays
+ #define glGenVertexArrays fnptr_ci_glGenVertexArrays
+ #define glIsVertexArray fnptr_ci_glIsVertexArray
+ #define glGetIntegeri_v fnptr_ci_glGetIntegeri_v
+ #define glBeginTransformFeedback fnptr_ci_glBeginTransformFeedback
+ #define glEndTransformFeedback fnptr_ci_glEndTransformFeedback
+ #define glBindBufferRange fnptr_ci_glBindBufferRange
+ #define glBindBufferBase fnptr_ci_glBindBufferBase
+ #define glTransformFeedbackVaryings fnptr_ci_glTransformFeedbackVaryings
+ #define glGetTransformFeedbackVarying fnptr_ci_glGetTransformFeedbackVarying
+ #define glVertexAttribIPointer fnptr_ci_glVertexAttribIPointer
+ #define glGetVertexAttribIiv fnptr_ci_glGetVertexAttribIiv
+ #define glGetVertexAttribIuiv fnptr_ci_glGetVertexAttribIuiv
+ #define glVertexAttribI4i fnptr_ci_glVertexAttribI4i
+ #define glVertexAttribI4ui fnptr_ci_glVertexAttribI4ui
+ #define glVertexAttribI4iv fnptr_ci_glVertexAttribI4iv
+ #define glVertexAttribI4uiv fnptr_ci_glVertexAttribI4uiv
+ #define glGetUniformuiv fnptr_ci_glGetUniformuiv
+ #define glGetFragDataLocation fnptr_ci_glGetFragDataLocation
+ #define glUniform1ui fnptr_ci_glUniform1ui
+ #define glUniform2ui fnptr_ci_glUniform2ui
+ #define glUniform3ui fnptr_ci_glUniform3ui
+ #define glUniform4ui fnptr_ci_glUniform4ui
+ #define glUniform1uiv fnptr_ci_glUniform1uiv
+ #define glUniform2uiv fnptr_ci_glUniform2uiv
+ #define glUniform3uiv fnptr_ci_glUniform3uiv
+ #define glUniform4uiv fnptr_ci_glUniform4uiv
+ #define glClearBufferiv fnptr_ci_glClearBufferiv
+ #define glClearBufferuiv fnptr_ci_glClearBufferuiv
+ #define glClearBufferfv fnptr_ci_glClearBufferfv
+ #define glClearBufferfi fnptr_ci_glClearBufferfi
+ #define glGetStringi fnptr_ci_glGetStringi
+ #define glCopyBufferSubData fnptr_ci_glCopyBufferSubData
+ #define glGetUniformIndices fnptr_ci_glGetUniformIndices
+ #define glGetActiveUniformsiv fnptr_ci_glGetActiveUniformsiv
+ #define glGetUniformBlockIndex fnptr_ci_glGetUniformBlockIndex
+ #define glGetActiveUniformBlockiv fnptr_ci_glGetActiveUniformBlockiv
+ #define glGetActiveUniformBlockName fnptr_ci_glGetActiveUniformBlockName
+ #define glUniformBlockBinding fnptr_ci_glUniformBlockBinding
+ #define glDrawArraysInstanced fnptr_ci_glDrawArraysInstanced
+ #define glDrawElementsInstanced fnptr_ci_glDrawElementsInstanced
+ #define glFenceSync fnptr_ci_glFenceSync
+ #define glIsSync fnptr_ci_glIsSync
+ #define glDeleteSync fnptr_ci_glDeleteSync
+ #define glClientWaitSync fnptr_ci_glClientWaitSync
+ #define glWaitSync fnptr_ci_glWaitSync
+ #define glGetInteger64v fnptr_ci_glGetInteger64v
+ #define glGetSynciv fnptr_ci_glGetSynciv
+ #define glGetInteger64i_v fnptr_ci_glGetInteger64i_v
+ #define glGetBufferParameteri64v fnptr_ci_glGetBufferParameteri64v
+ #define glGenSamplers fnptr_ci_glGenSamplers
+ #define glDeleteSamplers fnptr_ci_glDeleteSamplers
+ #define glIsSampler fnptr_ci_glIsSampler
+ #define glBindSampler fnptr_ci_glBindSampler
+ #define glSamplerParameteri fnptr_ci_glSamplerParameteri
+ #define glSamplerParameteriv fnptr_ci_glSamplerParameteriv
+ #define glSamplerParameterf fnptr_ci_glSamplerParameterf
+ #define glSamplerParameterfv fnptr_ci_glSamplerParameterfv
+ #define glGetSamplerParameteriv fnptr_ci_glGetSamplerParameteriv
+ #define glGetSamplerParameterfv fnptr_ci_glGetSamplerParameterfv
+ #define glVertexAttribDivisor fnptr_ci_glVertexAttribDivisor
+ #define glBindTransformFeedback fnptr_ci_glBindTransformFeedback
+ #define glDeleteTransformFeedbacks fnptr_ci_glDeleteTransformFeedbacks
+ #define glGenTransformFeedbacks fnptr_ci_glGenTransformFeedbacks
+ #define glIsTransformFeedback fnptr_ci_glIsTransformFeedback
+ #define glPauseTransformFeedback fnptr_ci_glPauseTransformFeedback
+ #define glResumeTransformFeedback fnptr_ci_glResumeTransformFeedback
+ #define glGetProgramBinary fnptr_ci_glGetProgramBinary
+ #define glProgramBinary fnptr_ci_glProgramBinary
+ #define glProgramParameteri fnptr_ci_glProgramParameteri
+ #define glInvalidateFramebuffer fnptr_ci_glInvalidateFramebuffer
+ #define glInvalidateSubFramebuffer fnptr_ci_glInvalidateSubFramebuffer
+ #define glTexStorage2D fnptr_ci_glTexStorage2D
+ #define glTexStorage3D fnptr_ci_glTexStorage3D
+ #define glGetInternalformativ fnptr_ci_glGetInternalformativ
+ #endif // defined( CINDER_LINUX ) && ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_3 )
+
+ // ----------------------------------------------------------------------------
+ // OpenGL ES 3.1
+ // ----------------------------------------------------------------------------
+ #if defined( CINDER_LINUX ) && ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_3_1 )
+ extern PFNGLDISPATCHCOMPUTEPROC fnptr_ci_glDispatchCompute;
+ extern PFNGLDISPATCHCOMPUTEINDIRECTPROC fnptr_ci_glDispatchComputeIndirect;
+ extern PFNGLDRAWARRAYSINDIRECTPROC fnptr_ci_glDrawArraysIndirect;
+ extern PFNGLDRAWELEMENTSINDIRECTPROC fnptr_ci_glDrawElementsIndirect;
+ extern PFNGLFRAMEBUFFERPARAMETERIPROC fnptr_ci_glFramebufferParameteri;
+ extern PFNGLGETFRAMEBUFFERPARAMETERIVPROC fnptr_ci_glGetFramebufferParameteriv;
+ extern PFNGLGETPROGRAMINTERFACEIVPROC fnptr_ci_glGetProgramInterfaceiv;
+ extern PFNGLGETPROGRAMRESOURCEINDEXPROC fnptr_ci_glGetProgramResourceIndex;
+ extern PFNGLGETPROGRAMRESOURCENAMEPROC fnptr_ci_glGetProgramResourceName;
+ extern PFNGLGETPROGRAMRESOURCEIVPROC fnptr_ci_glGetProgramResourceiv;
+ extern PFNGLGETPROGRAMRESOURCELOCATIONPROC fnptr_ci_glGetProgramResourceLocation;
+ extern PFNGLUSEPROGRAMSTAGESPROC fnptr_ci_glUseProgramStages;
+ extern PFNGLACTIVESHADERPROGRAMPROC fnptr_ci_glActiveShaderProgram;
+ extern PFNGLCREATESHADERPROGRAMVPROC fnptr_ci_glCreateShaderProgramv;
+ extern PFNGLBINDPROGRAMPIPELINEPROC fnptr_ci_glBindProgramPipeline;
+ extern PFNGLDELETEPROGRAMPIPELINESPROC fnptr_ci_glDeleteProgramPipelines;
+ extern PFNGLGENPROGRAMPIPELINESPROC fnptr_ci_glGenProgramPipelines;
+ extern PFNGLISPROGRAMPIPELINEPROC fnptr_ci_glIsProgramPipeline;
+ extern PFNGLGETPROGRAMPIPELINEIVPROC fnptr_ci_glGetProgramPipelineiv;
+ extern PFNGLPROGRAMUNIFORM1IPROC fnptr_ci_glProgramUniform1i;
+ extern PFNGLPROGRAMUNIFORM2IPROC fnptr_ci_glProgramUniform2i;
+ extern PFNGLPROGRAMUNIFORM3IPROC fnptr_ci_glProgramUniform3i;
+ extern PFNGLPROGRAMUNIFORM4IPROC fnptr_ci_glProgramUniform4i;
+ extern PFNGLPROGRAMUNIFORM1UIPROC fnptr_ci_glProgramUniform1ui;
+ extern PFNGLPROGRAMUNIFORM2UIPROC fnptr_ci_glProgramUniform2ui;
+ extern PFNGLPROGRAMUNIFORM3UIPROC fnptr_ci_glProgramUniform3ui;
+ extern PFNGLPROGRAMUNIFORM4UIPROC fnptr_ci_glProgramUniform4ui;
+ extern PFNGLPROGRAMUNIFORM1FPROC fnptr_ci_glProgramUniform1f;
+ extern PFNGLPROGRAMUNIFORM2FPROC fnptr_ci_glProgramUniform2f;
+ extern PFNGLPROGRAMUNIFORM3FPROC fnptr_ci_glProgramUniform3f;
+ extern PFNGLPROGRAMUNIFORM4FPROC fnptr_ci_glProgramUniform4f;
+ extern PFNGLPROGRAMUNIFORM1IVPROC fnptr_ci_glProgramUniform1iv;
+ extern PFNGLPROGRAMUNIFORM2IVPROC fnptr_ci_glProgramUniform2iv;
+ extern PFNGLPROGRAMUNIFORM3IVPROC fnptr_ci_glProgramUniform3iv;
+ extern PFNGLPROGRAMUNIFORM4IVPROC fnptr_ci_glProgramUniform4iv;
+ extern PFNGLPROGRAMUNIFORM1UIVPROC fnptr_ci_glProgramUniform1uiv;
+ extern PFNGLPROGRAMUNIFORM2UIVPROC fnptr_ci_glProgramUniform2uiv;
+ extern PFNGLPROGRAMUNIFORM3UIVPROC fnptr_ci_glProgramUniform3uiv;
+ extern PFNGLPROGRAMUNIFORM4UIVPROC fnptr_ci_glProgramUniform4uiv;
+ extern PFNGLPROGRAMUNIFORM1FVPROC fnptr_ci_glProgramUniform1fv;
+ extern PFNGLPROGRAMUNIFORM2FVPROC fnptr_ci_glProgramUniform2fv;
+ extern PFNGLPROGRAMUNIFORM3FVPROC fnptr_ci_glProgramUniform3fv;
+ extern PFNGLPROGRAMUNIFORM4FVPROC fnptr_ci_glProgramUniform4fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX2FVPROC fnptr_ci_glProgramUniformMatrix2fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX3FVPROC fnptr_ci_glProgramUniformMatrix3fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX4FVPROC fnptr_ci_glProgramUniformMatrix4fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC fnptr_ci_glProgramUniformMatrix2x3fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC fnptr_ci_glProgramUniformMatrix3x2fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC fnptr_ci_glProgramUniformMatrix2x4fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC fnptr_ci_glProgramUniformMatrix4x2fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC fnptr_ci_glProgramUniformMatrix3x4fv;
+ extern PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC fnptr_ci_glProgramUniformMatrix4x3fv;
+ extern PFNGLVALIDATEPROGRAMPIPELINEPROC fnptr_ci_glValidateProgramPipeline;
+ extern PFNGLGETPROGRAMPIPELINEINFOLOGPROC fnptr_ci_glGetProgramPipelineInfoLog;
+ extern PFNGLBINDIMAGETEXTUREPROC fnptr_ci_glBindImageTexture;
+ extern PFNGLGETBOOLEANI_VPROC fnptr_ci_glGetBooleani_v;
+ extern PFNGLMEMORYBARRIERPROC fnptr_ci_glMemoryBarrier;
+ extern PFNGLMEMORYBARRIERBYREGIONPROC fnptr_ci_glMemoryBarrierByRegion;
+ extern PFNGLTEXSTORAGE2DMULTISAMPLEPROC fnptr_ci_glTexStorage2DMultisample;
+ extern PFNGLGETMULTISAMPLEFVPROC fnptr_ci_glGetMultisamplefv;
+ extern PFNGLSAMPLEMASKIPROC fnptr_ci_glSampleMaski;
+ extern PFNGLGETTEXLEVELPARAMETERIVPROC fnptr_ci_glGetTexLevelParameteriv;
+ extern PFNGLGETTEXLEVELPARAMETERFVPROC fnptr_ci_glGetTexLevelParameterfv;
+ extern PFNGLBINDVERTEXBUFFERPROC fnptr_ci_glBindVertexBuffer;
+ extern PFNGLVERTEXATTRIBFORMATPROC fnptr_ci_glVertexAttribFormat;
+ extern PFNGLVERTEXATTRIBIFORMATPROC fnptr_ci_glVertexAttribIFormat;
+ extern PFNGLVERTEXATTRIBBINDINGPROC fnptr_ci_glVertexAttribBinding;
+ extern PFNGLVERTEXBINDINGDIVISORPROC fnptr_ci_glVertexBindingDivisor;
+
+ #define glDispatchCompute fnptr_ci_glDispatchCompute
+ #define glDispatchComputeIndirect fnptr_ci_glDispatchComputeIndirect
+ #define glDrawArraysIndirect fnptr_ci_glDrawArraysIndirect
+ #define glDrawElementsIndirect fnptr_ci_glDrawElementsIndirect
+ #define glFramebufferParameteri fnptr_ci_glFramebufferParameteri
+ #define glGetFramebufferParameteriv fnptr_ci_glGetFramebufferParameteriv
+ #define glGetProgramInterfaceiv fnptr_ci_glGetProgramInterfaceiv
+ #define glGetProgramResourceIndex fnptr_ci_glGetProgramResourceIndex
+ #define glGetProgramResourceName fnptr_ci_glGetProgramResourceName
+ #define glGetProgramResourceiv fnptr_ci_glGetProgramResourceiv
+ #define glGetProgramResourceLocation fnptr_ci_glGetProgramResourceLocation
+ #define glUseProgramStages fnptr_ci_glUseProgramStages
+ #define glActiveShaderProgram fnptr_ci_glActiveShaderProgram
+ #define glCreateShaderProgramv fnptr_ci_glCreateShaderProgramv
+ #define glBindProgramPipeline fnptr_ci_glBindProgramPipeline
+ #define glDeleteProgramPipelines fnptr_ci_glDeleteProgramPipelines
+ #define glGenProgramPipelines fnptr_ci_glGenProgramPipelines
+ #define glIsProgramPipeline fnptr_ci_glIsProgramPipeline
+ #define glGetProgramPipelineiv fnptr_ci_glGetProgramPipelineiv
+ #define glProgramUniform1i fnptr_ci_glProgramUniform1i
+ #define glProgramUniform2i fnptr_ci_glProgramUniform2i
+ #define glProgramUniform3i fnptr_ci_glProgramUniform3i
+ #define glProgramUniform4i fnptr_ci_glProgramUniform4i
+ #define glProgramUniform1ui fnptr_ci_glProgramUniform1ui
+ #define glProgramUniform2ui fnptr_ci_glProgramUniform2ui
+ #define glProgramUniform3ui fnptr_ci_glProgramUniform3ui
+ #define glProgramUniform4ui fnptr_ci_glProgramUniform4ui
+ #define glProgramUniform1f fnptr_ci_glProgramUniform1f
+ #define glProgramUniform2f fnptr_ci_glProgramUniform2f
+ #define glProgramUniform3f fnptr_ci_glProgramUniform3f
+ #define glProgramUniform4f fnptr_ci_glProgramUniform4f
+ #define glProgramUniform1iv fnptr_ci_glProgramUniform1iv
+ #define glProgramUniform2iv fnptr_ci_glProgramUniform2iv
+ #define glProgramUniform3iv fnptr_ci_glProgramUniform3iv
+ #define glProgramUniform4iv fnptr_ci_glProgramUniform4iv
+ #define glProgramUniform1uiv fnptr_ci_glProgramUniform1uiv
+ #define glProgramUniform2uiv fnptr_ci_glProgramUniform2uiv
+ #define glProgramUniform3uiv fnptr_ci_glProgramUniform3uiv
+ #define glProgramUniform4uiv fnptr_ci_glProgramUniform4uiv
+ #define glProgramUniform1fv fnptr_ci_glProgramUniform1fv
+ #define glProgramUniform2fv fnptr_ci_glProgramUniform2fv
+ #define glProgramUniform3fv fnptr_ci_glProgramUniform3fv
+ #define glProgramUniform4fv fnptr_ci_glProgramUniform4fv
+ #define glProgramUniformMatrix2fv fnptr_ci_glProgramUniformMatrix2fv
+ #define glProgramUniformMatrix3fv fnptr_ci_glProgramUniformMatrix3fv
+ #define glProgramUniformMatrix4fv fnptr_ci_glProgramUniformMatrix4fv
+ #define glProgramUniformMatrix2x3fv fnptr_ci_glProgramUniformMatrix2x3fv
+ #define glProgramUniformMatrix3x2fv fnptr_ci_glProgramUniformMatrix3x2fv
+ #define glProgramUniformMatrix2x4fv fnptr_ci_glProgramUniformMatrix2x4fv
+ #define glProgramUniformMatrix4x2fv fnptr_ci_glProgramUniformMatrix4x2fv
+ #define glProgramUniformMatrix3x4fv fnptr_ci_glProgramUniformMatrix3x4fv
+ #define glProgramUniformMatrix4x3fv fnptr_ci_glProgramUniformMatrix4x3fv
+ #define glValidateProgramPipeline fnptr_ci_glValidateProgramPipeline
+ #define glGetProgramPipelineInfoLog fnptr_ci_glGetProgramPipelineInfoLog
+ #define glBindImageTexture fnptr_ci_glBindImageTexture
+ #define glGetBooleani_v fnptr_ci_glGetBooleani_v
+ #define glMemoryBarrier fnptr_ci_glMemoryBarrier
+ #define glMemoryBarrierByRegion fnptr_ci_glMemoryBarrierByRegion
+ #define glTexStorage2DMultisample fnptr_ci_glTexStorage2DMultisample
+ #define glGetMultisamplefv fnptr_ci_glGetMultisamplefv
+ #define glSampleMaski fnptr_ci_glSampleMaski
+ #define glGetTexLevelParameteriv fnptr_ci_glGetTexLevelParameteriv
+ #define glGetTexLevelParameterfv fnptr_ci_glGetTexLevelParameterfv
+ #define glBindVertexBuffer fnptr_ci_glBindVertexBuffer
+ #define glVertexAttribFormat fnptr_ci_glVertexAttribFormat
+ #define glVertexAttribIFormat fnptr_ci_glVertexAttribIFormat
+ #define glVertexAttribBinding fnptr_ci_glVertexAttribBinding
+ #define glVertexBindingDivisor fnptr_ci_glVertexBindingDivisor
+ #endif // defined( CINDER_LINUX ) && ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_3_1 )
+
+ // ----------------------------------------------------------------------------
+ // OpenGL ES 3.2
+ // ----------------------------------------------------------------------------
+ #if defined( CINDER_LINUX ) && ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_3_2 )
+ extern PFNGLBLENDBARRIERPROC fnptr_ci_glBlendBarrier;
+ extern PFNGLCOPYIMAGESUBDATAPROC fnptr_ci_glCopyImageSubData;
+ extern PFNGLDEBUGMESSAGECONTROLPROC fnptr_ci_glDebugMessageControl;
+ extern PFNGLDEBUGMESSAGEINSERTPROC fnptr_ci_glDebugMessageInsert;
+ extern PFNGLDEBUGMESSAGECALLBACKPROC fnptr_ci_glDebugMessageCallback;
+ extern PFNGLGETDEBUGMESSAGELOGPROC fnptr_ci_glGetDebugMessageLog;
+ extern PFNGLPUSHDEBUGGROUPPROC fnptr_ci_glPushDebugGroup;
+ extern PFNGLPOPDEBUGGROUPPROC fnptr_ci_glPopDebugGroup;
+ extern PFNGLOBJECTLABELPROC fnptr_ci_glObjectLabel;
+ extern PFNGLGETOBJECTLABELPROC fnptr_ci_glGetObjectLabel;
+ extern PFNGLOBJECTPTRLABELPROC fnptr_ci_glObjectPtrLabel;
+ extern PFNGLGETOBJECTPTRLABELPROC fnptr_ci_glGetObjectPtrLabel;
+ extern PFNGLGETPOINTERVPROC fnptr_ci_glGetPointerv;
+ extern PFNGLENABLEIPROC fnptr_ci_glEnablei;
+ extern PFNGLDISABLEIPROC fnptr_ci_glDisablei;
+ extern PFNGLBLENDEQUATIONIPROC fnptr_ci_glBlendEquationi;
+ extern PFNGLBLENDEQUATIONSEPARATEIPROC fnptr_ci_glBlendEquationSeparatei;
+ extern PFNGLBLENDFUNCIPROC fnptr_ci_glBlendFunci;
+ extern PFNGLBLENDFUNCSEPARATEIPROC fnptr_ci_glBlendFuncSeparatei;
+ extern PFNGLCOLORMASKIPROC fnptr_ci_glColorMaski;
+ extern PFNGLISENABLEDIPROC fnptr_ci_glIsEnabledi;
+ extern PFNGLDRAWELEMENTSBASEVERTEXPROC fnptr_ci_glDrawElementsBaseVertex;
+ extern PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC fnptr_ci_glDrawRangeElementsBaseVertex;
+ extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC fnptr_ci_glDrawElementsInstancedBaseVertex;
+ extern PFNGLFRAMEBUFFERTEXTUREPROC fnptr_ci_glFramebufferTexture;
+ extern PFNGLPRIMITIVEBOUNDINGBOXPROC fnptr_ci_glPrimitiveBoundingBox;
+ extern PFNGLGETGRAPHICSRESETSTATUSPROC fnptr_ci_glGetGraphicsResetStatus;
+ extern PFNGLREADNPIXELSPROC fnptr_ci_glReadnPixels;
+ extern PFNGLGETNUNIFORMFVPROC fnptr_ci_glGetnUniformfv;
+ extern PFNGLGETNUNIFORMIVPROC fnptr_ci_glGetnUniformiv;
+ extern PFNGLGETNUNIFORMUIVPROC fnptr_ci_glGetnUniformuiv;
+ extern PFNGLMINSAMPLESHADINGPROC fnptr_ci_glMinSampleShading;
+ extern PFNGLPATCHPARAMETERIPROC fnptr_ci_glPatchParameteri;
+ extern PFNGLTEXPARAMETERIIVPROC fnptr_ci_glTexParameterIiv;
+ extern PFNGLTEXPARAMETERIUIVPROC fnptr_ci_glTexParameterIuiv;
+ extern PFNGLGETTEXPARAMETERIIVPROC fnptr_ci_glGetTexParameterIiv;
+ extern PFNGLGETTEXPARAMETERIUIVPROC fnptr_ci_glGetTexParameterIuiv;
+ extern PFNGLSAMPLERPARAMETERIIVPROC fnptr_ci_glSamplerParameterIiv;
+ extern PFNGLSAMPLERPARAMETERIUIVPROC fnptr_ci_glSamplerParameterIuiv;
+ extern PFNGLGETSAMPLERPARAMETERIIVPROC fnptr_ci_glGetSamplerParameterIiv;
+ extern PFNGLGETSAMPLERPARAMETERIUIVPROC fnptr_ci_glGetSamplerParameterIuiv;
+ extern PFNGLTEXBUFFERPROC fnptr_ci_glTexBuffer;
+ extern PFNGLTEXBUFFERRANGEPROC fnptr_ci_glTexBufferRange;
+ extern PFNGLTEXSTORAGE3DMULTISAMPLEPROC fnptr_ci_glTexStorage3DMultisample;
+
+ #define glBlendBarrier fnptr_ci_glBlendBarrier
+ #define glCopyImageSubData fnptr_ci_glCopyImageSubData
+ #define glDebugMessageControl fnptr_ci_glDebugMessageControl
+ #define glDebugMessageInsert fnptr_ci_glDebugMessageInsert
+ #define glDebugMessageCallback fnptr_ci_glDebugMessageCallback
+ #define glGetDebugMessageLog fnptr_ci_glGetDebugMessageLog
+ #define glPushDebugGroup fnptr_ci_glPushDebugGroup
+ #define glPopDebugGroup fnptr_ci_glPopDebugGroup
+ #define glObjectLabel fnptr_ci_glObjectLabel
+ #define glGetObjectLabel fnptr_ci_glGetObjectLabel
+ #define glObjectPtrLabel fnptr_ci_glObjectPtrLabel
+ #define glGetObjectPtrLabel fnptr_ci_glGetObjectPtrLabel
+ #define glGetPointerv fnptr_ci_glGetPointerv
+ #define glEnablei fnptr_ci_glEnablei
+ #define glDisablei fnptr_ci_glDisablei
+ #define glBlendEquationi fnptr_ci_glBlendEquationi
+ #define glBlendEquationSeparatei fnptr_ci_glBlendEquationSeparatei
+ #define glBlendFunci fnptr_ci_glBlendFunci
+ #define glBlendFuncSeparatei fnptr_ci_glBlendFuncSeparatei
+ #define glColorMaski fnptr_ci_glColorMaski
+ #define glIsEnabledi fnptr_ci_glIsEnabledi
+ #define glDrawElementsBaseVertex fnptr_ci_glDrawElementsBaseVertex
+ #define glDrawRangeElementsBaseVertex fnptr_ci_glDrawRangeElementsBaseVertex
+ #define glDrawElementsInstancedBaseVertex fnptr_ci_glDrawElementsInstancedBaseVertex
+ #define glFramebufferTexture fnptr_ci_glFramebufferTexture
+ #define glPrimitiveBoundingBox fnptr_ci_glPrimitiveBoundingBox
+ #define glGetGraphicsResetStatus fnptr_ci_glGetGraphicsResetStatus
+ #define glReadnPixels fnptr_ci_glReadnPixels
+ #define glGetnUniformfv fnptr_ci_glGetnUniformfv
+ #define glGetnUniformiv fnptr_ci_glGetnUniformiv
+ #define glGetnUniformuiv fnptr_ci_glGetnUniformuiv
+ #define glMinSampleShading fnptr_ci_glMinSampleShading
+ #define glPatchParameteri fnptr_ci_glPatchParameteri
+ #define glTexParameterIiv fnptr_ci_glTexParameterIiv
+ #define glTexParameterIuiv fnptr_ci_glTexParameterIuiv
+ #define glGetTexParameterIiv fnptr_ci_glGetTexParameterIiv
+ #define glGetTexParameterIuiv fnptr_ci_glGetTexParameterIuiv
+ #define glSamplerParameterIiv fnptr_ci_glSamplerParameterIiv
+ #define glSamplerParameterIuiv fnptr_ci_glSamplerParameterIuiv
+ #define glGetSamplerParameterIiv fnptr_ci_glGetSamplerParameterIiv
+ #define glGetSamplerParameterIuiv fnptr_ci_glGetSamplerParameterIuiv
+ #define glTexBuffer fnptr_ci_glTexBuffer
+ #define glTexBufferRange fnptr_ci_glTexBufferRange
+ #define glTexStorage3DMultisample fnptr_ci_glTexStorage3DMultisample
+ #endif // defined( CINDER_LINUX ) && ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_3_2 )
+
+ // -------------------------------------------------------------------------
+ // OpenGL ES 2.0 Extensions
+ // -------------------------------------------------------------------------
+ #if ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_2 )
+ extern PFNGLBLENDBARRIERKHRPROC fnptr_ci_glBlendBarrierKHR;
+ extern PFNGLDEBUGMESSAGECONTROLKHRPROC fnptr_ci_glDebugMessageControlKHR;
+ extern PFNGLDEBUGMESSAGEINSERTKHRPROC fnptr_ci_glDebugMessageInsertKHR;
+ extern PFNGLDEBUGMESSAGECALLBACKKHRPROC fnptr_ci_glDebugMessageCallbackKHR;
+ extern PFNGLGETDEBUGMESSAGELOGKHRPROC fnptr_ci_glGetDebugMessageLogKHR;
+ extern PFNGLPUSHDEBUGGROUPKHRPROC fnptr_ci_glPushDebugGroupKHR;
+ extern PFNGLPOPDEBUGGROUPKHRPROC fnptr_ci_glPopDebugGroupKHR;
+ extern PFNGLOBJECTLABELKHRPROC fnptr_ci_glObjectLabelKHR;
+ extern PFNGLGETOBJECTLABELKHRPROC fnptr_ci_glGetObjectLabelKHR;
+ extern PFNGLOBJECTPTRLABELKHRPROC fnptr_ci_glObjectPtrLabelKHR;
+ extern PFNGLGETOBJECTPTRLABELKHRPROC fnptr_ci_glGetObjectPtrLabelKHR;
+ extern PFNGLGETPOINTERVKHRPROC fnptr_ci_glGetPointervKHR;
+ extern PFNGLGETGRAPHICSRESETSTATUSKHRPROC fnptr_ci_glGetGraphicsResetStatusKHR;
+ extern PFNGLREADNPIXELSKHRPROC fnptr_ci_glReadnPixelsKHR;
+ extern PFNGLGETNUNIFORMFVKHRPROC fnptr_ci_glGetnUniformfvKHR;
+ extern PFNGLGETNUNIFORMIVKHRPROC fnptr_ci_glGetnUniformivKHR;
+ extern PFNGLGETNUNIFORMUIVKHRPROC fnptr_ci_glGetnUniformuivKHR;
+ extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC fnptr_ci_glEGLImageTargetTexture2DOES;
+ extern PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC fnptr_ci_glEGLImageTargetRenderbufferStorageOES;
+ extern PFNGLCOPYIMAGESUBDATAOESPROC fnptr_ci_glCopyImageSubDataOES;
+ extern PFNGLENABLEIOESPROC fnptr_ci_glEnableiOES;
+ extern PFNGLDISABLEIOESPROC fnptr_ci_glDisableiOES;
+ extern PFNGLBLENDEQUATIONIOESPROC fnptr_ci_glBlendEquationiOES;
+ extern PFNGLBLENDEQUATIONSEPARATEIOESPROC fnptr_ci_glBlendEquationSeparateiOES;
+ extern PFNGLBLENDFUNCIOESPROC fnptr_ci_glBlendFunciOES;
+ extern PFNGLBLENDFUNCSEPARATEIOESPROC fnptr_ci_glBlendFuncSeparateiOES;
+ extern PFNGLCOLORMASKIOESPROC fnptr_ci_glColorMaskiOES;
+ extern PFNGLISENABLEDIOESPROC fnptr_ci_glIsEnablediOES;
+ extern PFNGLDRAWELEMENTSBASEVERTEXOESPROC fnptr_ci_glDrawElementsBaseVertexOES;
+ extern PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC fnptr_ci_glDrawRangeElementsBaseVertexOES;
+ extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC fnptr_ci_glDrawElementsInstancedBaseVertexOES;
+ extern PFNGLMULTIDRAWELEMENTSBASEVERTEXOESPROC fnptr_ci_glMultiDrawElementsBaseVertexOES;
+ extern PFNGLFRAMEBUFFERTEXTUREOESPROC fnptr_ci_glFramebufferTextureOES;
+ extern PFNGLGETPROGRAMBINARYOESPROC fnptr_ci_glGetProgramBinaryOES;
+ extern PFNGLPROGRAMBINARYOESPROC fnptr_ci_glProgramBinaryOES;
+ extern PFNGLGETBUFFERPOINTERVOESPROC fnptr_ci_glGetBufferPointervOES;
+ extern PFNGLPRIMITIVEBOUNDINGBOXOESPROC fnptr_ci_glPrimitiveBoundingBoxOES;
+ extern PFNGLMINSAMPLESHADINGOESPROC fnptr_ci_glMinSampleShadingOES;
+ extern PFNGLTEXIMAGE3DOESPROC fnptr_ci_glTexImage3DOES;
+ extern PFNGLTEXSUBIMAGE3DOESPROC fnptr_ci_glTexSubImage3DOES;
+ extern PFNGLCOPYTEXSUBIMAGE3DOESPROC fnptr_ci_glCopyTexSubImage3DOES;
+ extern PFNGLCOMPRESSEDTEXIMAGE3DOESPROC fnptr_ci_glCompressedTexImage3DOES;
+ extern PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC fnptr_ci_glCompressedTexSubImage3DOES;
+ extern PFNGLFRAMEBUFFERTEXTURE3DOESPROC fnptr_ci_glFramebufferTexture3DOES;
+ extern PFNGLTEXPARAMETERIIVOESPROC fnptr_ci_glTexParameterIivOES;
+ extern PFNGLTEXPARAMETERIUIVOESPROC fnptr_ci_glTexParameterIuivOES;
+ extern PFNGLGETTEXPARAMETERIIVOESPROC fnptr_ci_glGetTexParameterIivOES;
+ extern PFNGLGETTEXPARAMETERIUIVOESPROC fnptr_ci_glGetTexParameterIuivOES;
+ extern PFNGLSAMPLERPARAMETERIIVOESPROC fnptr_ci_glSamplerParameterIivOES;
+ extern PFNGLSAMPLERPARAMETERIUIVOESPROC fnptr_ci_glSamplerParameterIuivOES;
+ extern PFNGLGETSAMPLERPARAMETERIIVOESPROC fnptr_ci_glGetSamplerParameterIivOES;
+ extern PFNGLGETSAMPLERPARAMETERIUIVOESPROC fnptr_ci_glGetSamplerParameterIuivOES;
+ extern PFNGLTEXBUFFEROESPROC fnptr_ci_glTexBufferOES;
+ extern PFNGLTEXBUFFERRANGEOESPROC fnptr_ci_glTexBufferRangeOES;
+ extern PFNGLTEXSTORAGE3DMULTISAMPLEOESPROC fnptr_ci_glTexStorage3DMultisampleOES;
+ extern PFNGLTEXTUREVIEWOESPROC fnptr_ci_glTextureViewOES;
+ extern PFNGLGETPERFMONITORGROUPSAMDPROC fnptr_ci_glGetPerfMonitorGroupsAMD;
+ extern PFNGLGETPERFMONITORCOUNTERSAMDPROC fnptr_ci_glGetPerfMonitorCountersAMD;
+ extern PFNGLGETPERFMONITORGROUPSTRINGAMDPROC fnptr_ci_glGetPerfMonitorGroupStringAMD;
+ extern PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC fnptr_ci_glGetPerfMonitorCounterStringAMD;
+ extern PFNGLGETPERFMONITORCOUNTERINFOAMDPROC fnptr_ci_glGetPerfMonitorCounterInfoAMD;
+ extern PFNGLGENPERFMONITORSAMDPROC fnptr_ci_glGenPerfMonitorsAMD;
+ extern PFNGLDELETEPERFMONITORSAMDPROC fnptr_ci_glDeletePerfMonitorsAMD;
+ extern PFNGLSELECTPERFMONITORCOUNTERSAMDPROC fnptr_ci_glSelectPerfMonitorCountersAMD;
+ extern PFNGLBEGINPERFMONITORAMDPROC fnptr_ci_glBeginPerfMonitorAMD;
+ extern PFNGLENDPERFMONITORAMDPROC fnptr_ci_glEndPerfMonitorAMD;
+ extern PFNGLGETPERFMONITORCOUNTERDATAAMDPROC fnptr_ci_glGetPerfMonitorCounterDataAMD;
+ extern PFNGLBLITFRAMEBUFFERANGLEPROC fnptr_ci_glBlitFramebufferANGLE;
+ extern PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC fnptr_ci_glGetTranslatedShaderSourceANGLE;
+ extern PFNGLCOPYTEXTURELEVELSAPPLEPROC fnptr_ci_glCopyTextureLevelsAPPLE;
+ extern PFNGLFENCESYNCAPPLEPROC fnptr_ci_glFenceSyncAPPLE;
+ extern PFNGLISSYNCAPPLEPROC fnptr_ci_glIsSyncAPPLE;
+ extern PFNGLDELETESYNCAPPLEPROC fnptr_ci_glDeleteSyncAPPLE;
+ extern PFNGLCLIENTWAITSYNCAPPLEPROC fnptr_ci_glClientWaitSyncAPPLE;
+ extern PFNGLWAITSYNCAPPLEPROC fnptr_ci_glWaitSyncAPPLE;
+ extern PFNGLGETINTEGER64VAPPLEPROC fnptr_ci_glGetInteger64vAPPLE;
+ extern PFNGLGETSYNCIVAPPLEPROC fnptr_ci_glGetSyncivAPPLE;
+ extern PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC fnptr_ci_glDrawArraysInstancedBaseInstanceEXT;
+ extern PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC fnptr_ci_glDrawElementsInstancedBaseInstanceEXT;
+ extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC fnptr_ci_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
+ extern PFNGLBINDFRAGDATALOCATIONINDEXEDEXTPROC fnptr_ci_glBindFragDataLocationIndexedEXT;
+ extern PFNGLBINDFRAGDATALOCATIONEXTPROC fnptr_ci_glBindFragDataLocationEXT;
+ extern PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC fnptr_ci_glGetProgramResourceLocationIndexEXT;
+ extern PFNGLGETFRAGDATAINDEXEXTPROC fnptr_ci_glGetFragDataIndexEXT;
+ extern PFNGLCOPYIMAGESUBDATAEXTPROC fnptr_ci_glCopyImageSubDataEXT;
+ extern PFNGLLABELOBJECTEXTPROC fnptr_ci_glLabelObjectEXT;
+ extern PFNGLGETOBJECTLABELEXTPROC fnptr_ci_glGetObjectLabelEXT;
+ extern PFNGLINSERTEVENTMARKEREXTPROC fnptr_ci_glInsertEventMarkerEXT;
+ extern PFNGLPUSHGROUPMARKEREXTPROC fnptr_ci_glPushGroupMarkerEXT;
+ extern PFNGLPOPGROUPMARKEREXTPROC fnptr_ci_glPopGroupMarkerEXT;
+ extern PFNGLDISCARDFRAMEBUFFEREXTPROC fnptr_ci_glDiscardFramebufferEXT;
+ extern PFNGLGENQUERIESEXTPROC fnptr_ci_glGenQueriesEXT;
+ extern PFNGLDELETEQUERIESEXTPROC fnptr_ci_glDeleteQueriesEXT;
+ extern PFNGLISQUERYEXTPROC fnptr_ci_glIsQueryEXT;
+ extern PFNGLBEGINQUERYEXTPROC fnptr_ci_glBeginQueryEXT;
+ extern PFNGLENDQUERYEXTPROC fnptr_ci_glEndQueryEXT;
+ extern PFNGLQUERYCOUNTEREXTPROC fnptr_ci_glQueryCounterEXT;
+ extern PFNGLGETQUERYIVEXTPROC fnptr_ci_glGetQueryivEXT;
+ extern PFNGLGETQUERYOBJECTIVEXTPROC fnptr_ci_glGetQueryObjectivEXT;
+ extern PFNGLGETQUERYOBJECTUIVEXTPROC fnptr_ci_glGetQueryObjectuivEXT;
+ extern PFNGLGETQUERYOBJECTI64VEXTPROC fnptr_ci_glGetQueryObjecti64vEXT;
+ extern PFNGLGETQUERYOBJECTUI64VEXTPROC fnptr_ci_glGetQueryObjectui64vEXT;
+ extern PFNGLDRAWBUFFERSEXTPROC fnptr_ci_glDrawBuffersEXT;
+ extern PFNGLENABLEIEXTPROC fnptr_ci_glEnableiEXT;
+ extern PFNGLDISABLEIEXTPROC fnptr_ci_glDisableiEXT;
+ extern PFNGLBLENDEQUATIONIEXTPROC fnptr_ci_glBlendEquationiEXT;
+ extern PFNGLBLENDEQUATIONSEPARATEIEXTPROC fnptr_ci_glBlendEquationSeparateiEXT;
+ extern PFNGLBLENDFUNCIEXTPROC fnptr_ci_glBlendFunciEXT;
+ extern PFNGLBLENDFUNCSEPARATEIEXTPROC fnptr_ci_glBlendFuncSeparateiEXT;
+ extern PFNGLCOLORMASKIEXTPROC fnptr_ci_glColorMaskiEXT;
+ extern PFNGLISENABLEDIEXTPROC fnptr_ci_glIsEnablediEXT;
+ extern PFNGLDRAWELEMENTSBASEVERTEXEXTPROC fnptr_ci_glDrawElementsBaseVertexEXT;
+ extern PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC fnptr_ci_glDrawRangeElementsBaseVertexEXT;
+ extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC fnptr_ci_glDrawElementsInstancedBaseVertexEXT;
+ extern PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC fnptr_ci_glMultiDrawElementsBaseVertexEXT;
+ extern PFNGLMULTIDRAWARRAYSEXTPROC fnptr_ci_glMultiDrawArraysEXT;
+ extern PFNGLMULTIDRAWELEMENTSEXTPROC fnptr_ci_glMultiDrawElementsEXT;
+ extern PFNGLMULTIDRAWARRAYSINDIRECTEXTPROC fnptr_ci_glMultiDrawArraysIndirectEXT;
+ extern PFNGLMULTIDRAWELEMENTSINDIRECTEXTPROC fnptr_ci_glMultiDrawElementsIndirectEXT;
+ extern PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC fnptr_ci_glFramebufferTexture2DMultisampleEXT;
+ extern PFNGLREADBUFFERINDEXEDEXTPROC fnptr_ci_glReadBufferIndexedEXT;
+ extern PFNGLDRAWBUFFERSINDEXEDEXTPROC fnptr_ci_glDrawBuffersIndexedEXT;
+ extern PFNGLGETINTEGERI_VEXTPROC fnptr_ci_glGetIntegeri_vEXT;
+ extern PFNGLPRIMITIVEBOUNDINGBOXEXTPROC fnptr_ci_glPrimitiveBoundingBoxEXT;
+ extern PFNGLRASTERSAMPLESEXTPROC fnptr_ci_glRasterSamplesEXT;
+ extern PFNGLGETGRAPHICSRESETSTATUSEXTPROC fnptr_ci_glGetGraphicsResetStatusEXT;
+ extern PFNGLREADNPIXELSEXTPROC fnptr_ci_glReadnPixelsEXT;
+ extern PFNGLGETNUNIFORMFVEXTPROC fnptr_ci_glGetnUniformfvEXT;
+ extern PFNGLGETNUNIFORMIVEXTPROC fnptr_ci_glGetnUniformivEXT;
+ extern PFNGLACTIVESHADERPROGRAMEXTPROC fnptr_ci_glActiveShaderProgramEXT;
+ extern PFNGLBINDPROGRAMPIPELINEEXTPROC fnptr_ci_glBindProgramPipelineEXT;
+ extern PFNGLCREATESHADERPROGRAMVEXTPROC fnptr_ci_glCreateShaderProgramvEXT;
+ extern PFNGLDELETEPROGRAMPIPELINESEXTPROC fnptr_ci_glDeleteProgramPipelinesEXT;
+ extern PFNGLGENPROGRAMPIPELINESEXTPROC fnptr_ci_glGenProgramPipelinesEXT;
+ extern PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC fnptr_ci_glGetProgramPipelineInfoLogEXT;
+ extern PFNGLGETPROGRAMPIPELINEIVEXTPROC fnptr_ci_glGetProgramPipelineivEXT;
+ extern PFNGLISPROGRAMPIPELINEEXTPROC fnptr_ci_glIsProgramPipelineEXT;
+ extern PFNGLPROGRAMPARAMETERIEXTPROC fnptr_ci_glProgramParameteriEXT;
+ extern PFNGLPROGRAMUNIFORM1FEXTPROC fnptr_ci_glProgramUniform1fEXT;
+ extern PFNGLPROGRAMUNIFORM1FVEXTPROC fnptr_ci_glProgramUniform1fvEXT;
+ extern PFNGLPROGRAMUNIFORM1IEXTPROC fnptr_ci_glProgramUniform1iEXT;
+ extern PFNGLPROGRAMUNIFORM1IVEXTPROC fnptr_ci_glProgramUniform1ivEXT;
+ extern PFNGLPROGRAMUNIFORM2FEXTPROC fnptr_ci_glProgramUniform2fEXT;
+ extern PFNGLPROGRAMUNIFORM2FVEXTPROC fnptr_ci_glProgramUniform2fvEXT;
+ extern PFNGLPROGRAMUNIFORM2IEXTPROC fnptr_ci_glProgramUniform2iEXT;
+ extern PFNGLPROGRAMUNIFORM2IVEXTPROC fnptr_ci_glProgramUniform2ivEXT;
+ extern PFNGLPROGRAMUNIFORM3FEXTPROC fnptr_ci_glProgramUniform3fEXT;
+ extern PFNGLPROGRAMUNIFORM3FVEXTPROC fnptr_ci_glProgramUniform3fvEXT;
+ extern PFNGLPROGRAMUNIFORM3IEXTPROC fnptr_ci_glProgramUniform3iEXT;
+ extern PFNGLPROGRAMUNIFORM3IVEXTPROC fnptr_ci_glProgramUniform3ivEXT;
+ extern PFNGLPROGRAMUNIFORM4FEXTPROC fnptr_ci_glProgramUniform4fEXT;
+ extern PFNGLPROGRAMUNIFORM4FVEXTPROC fnptr_ci_glProgramUniform4fvEXT;
+ extern PFNGLPROGRAMUNIFORM4IEXTPROC fnptr_ci_glProgramUniform4iEXT;
+ extern PFNGLPROGRAMUNIFORM4IVEXTPROC fnptr_ci_glProgramUniform4ivEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC fnptr_ci_glProgramUniformMatrix2fvEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC fnptr_ci_glProgramUniformMatrix3fvEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC fnptr_ci_glProgramUniformMatrix4fvEXT;
+ extern PFNGLUSEPROGRAMSTAGESEXTPROC fnptr_ci_glUseProgramStagesEXT;
+ extern PFNGLVALIDATEPROGRAMPIPELINEEXTPROC fnptr_ci_glValidateProgramPipelineEXT;
+ extern PFNGLPROGRAMUNIFORM1UIEXTPROC fnptr_ci_glProgramUniform1uiEXT;
+ extern PFNGLPROGRAMUNIFORM2UIEXTPROC fnptr_ci_glProgramUniform2uiEXT;
+ extern PFNGLPROGRAMUNIFORM3UIEXTPROC fnptr_ci_glProgramUniform3uiEXT;
+ extern PFNGLPROGRAMUNIFORM4UIEXTPROC fnptr_ci_glProgramUniform4uiEXT;
+ extern PFNGLPROGRAMUNIFORM1UIVEXTPROC fnptr_ci_glProgramUniform1uivEXT;
+ extern PFNGLPROGRAMUNIFORM2UIVEXTPROC fnptr_ci_glProgramUniform2uivEXT;
+ extern PFNGLPROGRAMUNIFORM3UIVEXTPROC fnptr_ci_glProgramUniform3uivEXT;
+ extern PFNGLPROGRAMUNIFORM4UIVEXTPROC fnptr_ci_glProgramUniform4uivEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC fnptr_ci_glProgramUniformMatrix2x3fvEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC fnptr_ci_glProgramUniformMatrix3x2fvEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC fnptr_ci_glProgramUniformMatrix2x4fvEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC fnptr_ci_glProgramUniformMatrix4x2fvEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC fnptr_ci_glProgramUniformMatrix3x4fvEXT;
+ extern PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC fnptr_ci_glProgramUniformMatrix4x3fvEXT;
+ extern PFNGLTEXPAGECOMMITMENTEXTPROC fnptr_ci_glTexPageCommitmentEXT;
+ extern PFNGLTEXPARAMETERIIVEXTPROC fnptr_ci_glTexParameterIivEXT;
+ extern PFNGLTEXPARAMETERIUIVEXTPROC fnptr_ci_glTexParameterIuivEXT;
+ extern PFNGLGETTEXPARAMETERIIVEXTPROC fnptr_ci_glGetTexParameterIivEXT;
+ extern PFNGLGETTEXPARAMETERIUIVEXTPROC fnptr_ci_glGetTexParameterIuivEXT;
+ extern PFNGLSAMPLERPARAMETERIIVEXTPROC fnptr_ci_glSamplerParameterIivEXT;
+ extern PFNGLSAMPLERPARAMETERIUIVEXTPROC fnptr_ci_glSamplerParameterIuivEXT;
+ extern PFNGLGETSAMPLERPARAMETERIIVEXTPROC fnptr_ci_glGetSamplerParameterIivEXT;
+ extern PFNGLGETSAMPLERPARAMETERIUIVEXTPROC fnptr_ci_glGetSamplerParameterIuivEXT;
+ extern PFNGLTEXBUFFEREXTPROC fnptr_ci_glTexBufferEXT;
+ extern PFNGLTEXBUFFERRANGEEXTPROC fnptr_ci_glTexBufferRangeEXT;
+ extern PFNGLTEXSTORAGE1DEXTPROC fnptr_ci_glTexStorage1DEXT;
+ extern PFNGLTEXSTORAGE2DEXTPROC fnptr_ci_glTexStorage2DEXT;
+ extern PFNGLTEXSTORAGE3DEXTPROC fnptr_ci_glTexStorage3DEXT;
+ extern PFNGLTEXTURESTORAGE1DEXTPROC fnptr_ci_glTextureStorage1DEXT;
+ extern PFNGLTEXTURESTORAGE2DEXTPROC fnptr_ci_glTextureStorage2DEXT;
+ extern PFNGLTEXTURESTORAGE3DEXTPROC fnptr_ci_glTextureStorage3DEXT;
+ extern PFNGLTEXTUREVIEWEXTPROC fnptr_ci_glTextureViewEXT;
+ extern PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC fnptr_ci_glFramebufferTexture2DMultisampleIMG;
+ extern PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC fnptr_ci_glApplyFramebufferAttachmentCMAAINTEL;
+ extern PFNGLBEGINPERFQUERYINTELPROC fnptr_ci_glBeginPerfQueryINTEL;
+ extern PFNGLCREATEPERFQUERYINTELPROC fnptr_ci_glCreatePerfQueryINTEL;
+ extern PFNGLDELETEPERFQUERYINTELPROC fnptr_ci_glDeletePerfQueryINTEL;
+ extern PFNGLENDPERFQUERYINTELPROC fnptr_ci_glEndPerfQueryINTEL;
+ extern PFNGLGETFIRSTPERFQUERYIDINTELPROC fnptr_ci_glGetFirstPerfQueryIdINTEL;
+ extern PFNGLGETNEXTPERFQUERYIDINTELPROC fnptr_ci_glGetNextPerfQueryIdINTEL;
+ extern PFNGLGETPERFCOUNTERINFOINTELPROC fnptr_ci_glGetPerfCounterInfoINTEL;
+ extern PFNGLGETPERFQUERYDATAINTELPROC fnptr_ci_glGetPerfQueryDataINTEL;
+ extern PFNGLGETPERFQUERYIDBYNAMEINTELPROC fnptr_ci_glGetPerfQueryIdByNameINTEL;
+ extern PFNGLGETPERFQUERYINFOINTELPROC fnptr_ci_glGetPerfQueryInfoINTEL;
+ extern PFNGLGETTEXTUREHANDLENVPROC fnptr_ci_glGetTextureHandleNV;
+ extern PFNGLGETTEXTURESAMPLERHANDLENVPROC fnptr_ci_glGetTextureSamplerHandleNV;
+ extern PFNGLMAKETEXTUREHANDLERESIDENTNVPROC fnptr_ci_glMakeTextureHandleResidentNV;
+ extern PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC fnptr_ci_glMakeTextureHandleNonResidentNV;
+ extern PFNGLGETIMAGEHANDLENVPROC fnptr_ci_glGetImageHandleNV;
+ extern PFNGLMAKEIMAGEHANDLERESIDENTNVPROC fnptr_ci_glMakeImageHandleResidentNV;
+ extern PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC fnptr_ci_glMakeImageHandleNonResidentNV;
+ extern PFNGLUNIFORMHANDLEUI64NVPROC fnptr_ci_glUniformHandleui64NV;
+ extern PFNGLUNIFORMHANDLEUI64VNVPROC fnptr_ci_glUniformHandleui64vNV;
+ extern PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC fnptr_ci_glProgramUniformHandleui64NV;
+ extern PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC fnptr_ci_glProgramUniformHandleui64vNV;
+ extern PFNGLISTEXTUREHANDLERESIDENTNVPROC fnptr_ci_glIsTextureHandleResidentNV;
+ extern PFNGLISIMAGEHANDLERESIDENTNVPROC fnptr_ci_glIsImageHandleResidentNV;
+ extern PFNGLBLENDPARAMETERINVPROC fnptr_ci_glBlendParameteriNV;
+ extern PFNGLBLENDBARRIERNVPROC fnptr_ci_glBlendBarrierNV;
+ extern PFNGLBEGINCONDITIONALRENDERNVPROC fnptr_ci_glBeginConditionalRenderNV;
+ extern PFNGLENDCONDITIONALRENDERNVPROC fnptr_ci_glEndConditionalRenderNV;
+ extern PFNGLSUBPIXELPRECISIONBIASNVPROC fnptr_ci_glSubpixelPrecisionBiasNV;
+ extern PFNGLCOPYBUFFERSUBDATANVPROC fnptr_ci_glCopyBufferSubDataNV;
+ extern PFNGLCOVERAGEMASKNVPROC fnptr_ci_glCoverageMaskNV;
+ extern PFNGLCOVERAGEOPERATIONNVPROC fnptr_ci_glCoverageOperationNV;
+ extern PFNGLDRAWBUFFERSNVPROC fnptr_ci_glDrawBuffersNV;
+ extern PFNGLDELETEFENCESNVPROC fnptr_ci_glDeleteFencesNV;
+ extern PFNGLGENFENCESNVPROC fnptr_ci_glGenFencesNV;
+ extern PFNGLISFENCENVPROC fnptr_ci_glIsFenceNV;
+ extern PFNGLTESTFENCENVPROC fnptr_ci_glTestFenceNV;
+ extern PFNGLGETFENCEIVNVPROC fnptr_ci_glGetFenceivNV;
+ extern PFNGLFINISHFENCENVPROC fnptr_ci_glFinishFenceNV;
+ extern PFNGLSETFENCENVPROC fnptr_ci_glSetFenceNV;
+ extern PFNGLFRAGMENTCOVERAGECOLORNVPROC fnptr_ci_glFragmentCoverageColorNV;
+ extern PFNGLBLITFRAMEBUFFERNVPROC fnptr_ci_glBlitFramebufferNV;
+ extern PFNGLCOVERAGEMODULATIONTABLENVPROC fnptr_ci_glCoverageModulationTableNV;
+ extern PFNGLGETCOVERAGEMODULATIONTABLENVPROC fnptr_ci_glGetCoverageModulationTableNV;
+ extern PFNGLCOVERAGEMODULATIONNVPROC fnptr_ci_glCoverageModulationNV;
+ extern PFNGLGETINTERNALFORMATSAMPLEIVNVPROC fnptr_ci_glGetInternalformatSampleivNV;
+ extern PFNGLUNIFORMMATRIX2X3FVNVPROC fnptr_ci_glUniformMatrix2x3fvNV;
+ extern PFNGLUNIFORMMATRIX3X2FVNVPROC fnptr_ci_glUniformMatrix3x2fvNV;
+ extern PFNGLUNIFORMMATRIX2X4FVNVPROC fnptr_ci_glUniformMatrix2x4fvNV;
+ extern PFNGLUNIFORMMATRIX4X2FVNVPROC fnptr_ci_glUniformMatrix4x2fvNV;
+ extern PFNGLUNIFORMMATRIX3X4FVNVPROC fnptr_ci_glUniformMatrix3x4fvNV;
+ extern PFNGLUNIFORMMATRIX4X3FVNVPROC fnptr_ci_glUniformMatrix4x3fvNV;
+ extern PFNGLGENPATHSNVPROC fnptr_ci_glGenPathsNV;
+ extern PFNGLDELETEPATHSNVPROC fnptr_ci_glDeletePathsNV;
+ extern PFNGLISPATHNVPROC fnptr_ci_glIsPathNV;
+ extern PFNGLPATHCOMMANDSNVPROC fnptr_ci_glPathCommandsNV;
+ extern PFNGLPATHCOORDSNVPROC fnptr_ci_glPathCoordsNV;
+ extern PFNGLPATHSUBCOMMANDSNVPROC fnptr_ci_glPathSubCommandsNV;
+ extern PFNGLPATHSUBCOORDSNVPROC fnptr_ci_glPathSubCoordsNV;
+ extern PFNGLPATHSTRINGNVPROC fnptr_ci_glPathStringNV;
+ extern PFNGLPATHGLYPHSNVPROC fnptr_ci_glPathGlyphsNV;
+ extern PFNGLPATHGLYPHRANGENVPROC fnptr_ci_glPathGlyphRangeNV;
+ extern PFNGLWEIGHTPATHSNVPROC fnptr_ci_glWeightPathsNV;
+ extern PFNGLCOPYPATHNVPROC fnptr_ci_glCopyPathNV;
+ extern PFNGLINTERPOLATEPATHSNVPROC fnptr_ci_glInterpolatePathsNV;
+ extern PFNGLTRANSFORMPATHNVPROC fnptr_ci_glTransformPathNV;
+ extern PFNGLPATHPARAMETERIVNVPROC fnptr_ci_glPathParameterivNV;
+ extern PFNGLPATHPARAMETERINVPROC fnptr_ci_glPathParameteriNV;
+ extern PFNGLPATHPARAMETERFVNVPROC fnptr_ci_glPathParameterfvNV;
+ extern PFNGLPATHPARAMETERFNVPROC fnptr_ci_glPathParameterfNV;
+ extern PFNGLPATHDASHARRAYNVPROC fnptr_ci_glPathDashArrayNV;
+ extern PFNGLPATHSTENCILFUNCNVPROC fnptr_ci_glPathStencilFuncNV;
+ extern PFNGLPATHSTENCILDEPTHOFFSETNVPROC fnptr_ci_glPathStencilDepthOffsetNV;
+ extern PFNGLSTENCILFILLPATHNVPROC fnptr_ci_glStencilFillPathNV;
+ extern PFNGLSTENCILSTROKEPATHNVPROC fnptr_ci_glStencilStrokePathNV;
+ extern PFNGLSTENCILFILLPATHINSTANCEDNVPROC fnptr_ci_glStencilFillPathInstancedNV;
+ extern PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC fnptr_ci_glStencilStrokePathInstancedNV;
+ extern PFNGLPATHCOVERDEPTHFUNCNVPROC fnptr_ci_glPathCoverDepthFuncNV;
+ extern PFNGLCOVERFILLPATHNVPROC fnptr_ci_glCoverFillPathNV;
+ extern PFNGLCOVERSTROKEPATHNVPROC fnptr_ci_glCoverStrokePathNV;
+ extern PFNGLCOVERFILLPATHINSTANCEDNVPROC fnptr_ci_glCoverFillPathInstancedNV;
+ extern PFNGLCOVERSTROKEPATHINSTANCEDNVPROC fnptr_ci_glCoverStrokePathInstancedNV;
+ extern PFNGLGETPATHPARAMETERIVNVPROC fnptr_ci_glGetPathParameterivNV;
+ extern PFNGLGETPATHPARAMETERFVNVPROC fnptr_ci_glGetPathParameterfvNV;
+ extern PFNGLGETPATHCOMMANDSNVPROC fnptr_ci_glGetPathCommandsNV;
+ extern PFNGLGETPATHCOORDSNVPROC fnptr_ci_glGetPathCoordsNV;
+ extern PFNGLGETPATHDASHARRAYNVPROC fnptr_ci_glGetPathDashArrayNV;
+ extern PFNGLGETPATHMETRICSNVPROC fnptr_ci_glGetPathMetricsNV;
+ extern PFNGLGETPATHMETRICRANGENVPROC fnptr_ci_glGetPathMetricRangeNV;
+ extern PFNGLGETPATHSPACINGNVPROC fnptr_ci_glGetPathSpacingNV;
+ extern PFNGLISPOINTINFILLPATHNVPROC fnptr_ci_glIsPointInFillPathNV;
+ extern PFNGLISPOINTINSTROKEPATHNVPROC fnptr_ci_glIsPointInStrokePathNV;
+ extern PFNGLGETPATHLENGTHNVPROC fnptr_ci_glGetPathLengthNV;
+ extern PFNGLPOINTALONGPATHNVPROC fnptr_ci_glPointAlongPathNV;
+ extern PFNGLMATRIXLOAD3X2FNVPROC fnptr_ci_glMatrixLoad3x2fNV;
+ extern PFNGLMATRIXLOAD3X3FNVPROC fnptr_ci_glMatrixLoad3x3fNV;
+ extern PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC fnptr_ci_glMatrixLoadTranspose3x3fNV;
+ extern PFNGLMATRIXMULT3X2FNVPROC fnptr_ci_glMatrixMult3x2fNV;
+ extern PFNGLMATRIXMULT3X3FNVPROC fnptr_ci_glMatrixMult3x3fNV;
+ extern PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC fnptr_ci_glMatrixMultTranspose3x3fNV;
+ extern PFNGLSTENCILTHENCOVERFILLPATHNVPROC fnptr_ci_glStencilThenCoverFillPathNV;
+ extern PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC fnptr_ci_glStencilThenCoverStrokePathNV;
+ extern PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC fnptr_ci_glStencilThenCoverFillPathInstancedNV;
+ extern PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC fnptr_ci_glStencilThenCoverStrokePathInstancedNV;
+ extern PFNGLPATHGLYPHINDEXRANGENVPROC fnptr_ci_glPathGlyphIndexRangeNV;
+ extern PFNGLPATHGLYPHINDEXARRAYNVPROC fnptr_ci_glPathGlyphIndexArrayNV;
+ extern PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC fnptr_ci_glPathMemoryGlyphIndexArrayNV;
+ extern PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC fnptr_ci_glProgramPathFragmentInputGenNV;
+ extern PFNGLGETPROGRAMRESOURCEFVNVPROC fnptr_ci_glGetProgramResourcefvNV;
+ extern PFNGLPOLYGONMODENVPROC fnptr_ci_glPolygonModeNV;
+ extern PFNGLREADBUFFERNVPROC fnptr_ci_glReadBufferNV;
+ extern PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC fnptr_ci_glFramebufferSampleLocationsfvNV;
+ extern PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC fnptr_ci_glNamedFramebufferSampleLocationsfvNV;
+ extern PFNGLRESOLVEDEPTHVALUESNVPROC fnptr_ci_glResolveDepthValuesNV;
+ extern PFNGLVIEWPORTARRAYVNVPROC fnptr_ci_glViewportArrayvNV;
+ extern PFNGLVIEWPORTINDEXEDFNVPROC fnptr_ci_glViewportIndexedfNV;
+ extern PFNGLVIEWPORTINDEXEDFVNVPROC fnptr_ci_glViewportIndexedfvNV;
+ extern PFNGLSCISSORARRAYVNVPROC fnptr_ci_glScissorArrayvNV;
+ extern PFNGLSCISSORINDEXEDNVPROC fnptr_ci_glScissorIndexedNV;
+ extern PFNGLSCISSORINDEXEDVNVPROC fnptr_ci_glScissorIndexedvNV;
+ extern PFNGLDEPTHRANGEARRAYFVNVPROC fnptr_ci_glDepthRangeArrayfvNV;
+ extern PFNGLDEPTHRANGEINDEXEDFNVPROC fnptr_ci_glDepthRangeIndexedfNV;
+ extern PFNGLGETFLOATI_VNVPROC fnptr_ci_glGetFloati_vNV;
+ extern PFNGLENABLEINVPROC fnptr_ci_glEnableiNV;
+ extern PFNGLDISABLEINVPROC fnptr_ci_glDisableiNV;
+ extern PFNGLISENABLEDINVPROC fnptr_ci_glIsEnablediNV;
+ extern PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC fnptr_ci_glFramebufferTextureMultiviewOVR;
+ extern PFNGLALPHAFUNCQCOMPROC fnptr_ci_glAlphaFuncQCOM;
+ extern PFNGLGETDRIVERCONTROLSQCOMPROC fnptr_ci_glGetDriverControlsQCOM;
+ extern PFNGLGETDRIVERCONTROLSTRINGQCOMPROC fnptr_ci_glGetDriverControlStringQCOM;
+ extern PFNGLENABLEDRIVERCONTROLQCOMPROC fnptr_ci_glEnableDriverControlQCOM;
+ extern PFNGLDISABLEDRIVERCONTROLQCOMPROC fnptr_ci_glDisableDriverControlQCOM;
+ extern PFNGLEXTGETTEXTURESQCOMPROC fnptr_ci_glExtGetTexturesQCOM;
+ extern PFNGLEXTGETBUFFERSQCOMPROC fnptr_ci_glExtGetBuffersQCOM;
+ extern PFNGLEXTGETRENDERBUFFERSQCOMPROC fnptr_ci_glExtGetRenderbuffersQCOM;
+ extern PFNGLEXTGETFRAMEBUFFERSQCOMPROC fnptr_ci_glExtGetFramebuffersQCOM;
+ extern PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC fnptr_ci_glExtGetTexLevelParameterivQCOM;
+ extern PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC fnptr_ci_glExtTexObjectStateOverrideiQCOM;
+ extern PFNGLEXTGETTEXSUBIMAGEQCOMPROC fnptr_ci_glExtGetTexSubImageQCOM;
+ extern PFNGLEXTGETBUFFERPOINTERVQCOMPROC fnptr_ci_glExtGetBufferPointervQCOM;
+ extern PFNGLEXTGETSHADERSQCOMPROC fnptr_ci_glExtGetShadersQCOM;
+ extern PFNGLEXTGETPROGRAMSQCOMPROC fnptr_ci_glExtGetProgramsQCOM;
+ extern PFNGLEXTISPROGRAMBINARYQCOMPROC fnptr_ci_glExtIsProgramBinaryQCOM;
+ extern PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC fnptr_ci_glExtGetProgramBinarySourceQCOM;
+ extern PFNGLSTARTTILINGQCOMPROC fnptr_ci_glStartTilingQCOM;
+ extern PFNGLENDTILINGQCOMPROC fnptr_ci_glEndTilingQCOM;
+
+ #define glBlendBarrierKHR fnptr_ci_glBlendBarrierKHR
+ #define glDebugMessageControlKHR fnptr_ci_glDebugMessageControlKHR
+ #define glDebugMessageInsertKHR fnptr_ci_glDebugMessageInsertKHR
+ #define glDebugMessageCallbackKHR fnptr_ci_glDebugMessageCallbackKHR
+ #define glGetDebugMessageLogKHR fnptr_ci_glGetDebugMessageLogKHR
+ #define glPushDebugGroupKHR fnptr_ci_glPushDebugGroupKHR
+ #define glPopDebugGroupKHR fnptr_ci_glPopDebugGroupKHR
+ #define glObjectLabelKHR fnptr_ci_glObjectLabelKHR
+ #define glGetObjectLabelKHR fnptr_ci_glGetObjectLabelKHR
+ #define glObjectPtrLabelKHR fnptr_ci_glObjectPtrLabelKHR
+ #define glGetObjectPtrLabelKHR fnptr_ci_glGetObjectPtrLabelKHR
+ #define glGetPointervKHR fnptr_ci_glGetPointervKHR
+ #define glGetGraphicsResetStatusKHR fnptr_ci_glGetGraphicsResetStatusKHR
+ #define glReadnPixelsKHR fnptr_ci_glReadnPixelsKHR
+ #define glGetnUniformfvKHR fnptr_ci_glGetnUniformfvKHR
+ #define glGetnUniformivKHR fnptr_ci_glGetnUniformivKHR
+ #define glGetnUniformuivKHR fnptr_ci_glGetnUniformuivKHR
+ #define glEGLImageTargetTexture2DOES fnptr_ci_glEGLImageTargetTexture2DOES
+ #define glEGLImageTargetRenderbufferStorageOES fnptr_ci_glEGLImageTargetRenderbufferStorageOES
+ #define glCopyImageSubDataOES fnptr_ci_glCopyImageSubDataOES
+ #define glEnableiOES fnptr_ci_glEnableiOES
+ #define glDisableiOES fnptr_ci_glDisableiOES
+ #define glBlendEquationiOES fnptr_ci_glBlendEquationiOES
+ #define glBlendEquationSeparateiOES fnptr_ci_glBlendEquationSeparateiOES
+ #define glBlendFunciOES fnptr_ci_glBlendFunciOES
+ #define glBlendFuncSeparateiOES fnptr_ci_glBlendFuncSeparateiOES
+ #define glColorMaskiOES fnptr_ci_glColorMaskiOES
+ #define glIsEnablediOES fnptr_ci_glIsEnablediOES
+ #define glDrawElementsBaseVertexOES fnptr_ci_glDrawElementsBaseVertexOES
+ #define glDrawRangeElementsBaseVertexOES fnptr_ci_glDrawRangeElementsBaseVertexOES
+ #define glDrawElementsInstancedBaseVertexOES fnptr_ci_glDrawElementsInstancedBaseVertexOES
+ #define glMultiDrawElementsBaseVertexOES fnptr_ci_glMultiDrawElementsBaseVertexOES
+ #define glFramebufferTextureOES fnptr_ci_glFramebufferTextureOES
+ #define glGetProgramBinaryOES fnptr_ci_glGetProgramBinaryOES
+ #define glProgramBinaryOES fnptr_ci_glProgramBinaryOES
+ #define glGetBufferPointervOES fnptr_ci_glGetBufferPointervOES
+ #define glPrimitiveBoundingBoxOES fnptr_ci_glPrimitiveBoundingBoxOES
+ #define glMinSampleShadingOES fnptr_ci_glMinSampleShadingOES
+ #define glTexImage3DOES fnptr_ci_glTexImage3DOES
+ #define glTexSubImage3DOES fnptr_ci_glTexSubImage3DOES
+ #define glCopyTexSubImage3DOES fnptr_ci_glCopyTexSubImage3DOES
+ #define glCompressedTexImage3DOES fnptr_ci_glCompressedTexImage3DOES
+ #define glCompressedTexSubImage3DOES fnptr_ci_glCompressedTexSubImage3DOES
+ #define glFramebufferTexture3DOES fnptr_ci_glFramebufferTexture3DOES
+ #define glTexParameterIivOES fnptr_ci_glTexParameterIivOES
+ #define glTexParameterIuivOES fnptr_ci_glTexParameterIuivOES
+ #define glGetTexParameterIivOES fnptr_ci_glGetTexParameterIivOES
+ #define glGetTexParameterIuivOES fnptr_ci_glGetTexParameterIuivOES
+ #define glSamplerParameterIivOES fnptr_ci_glSamplerParameterIivOES
+ #define glSamplerParameterIuivOES fnptr_ci_glSamplerParameterIuivOES
+ #define glGetSamplerParameterIivOES fnptr_ci_glGetSamplerParameterIivOES
+ #define glGetSamplerParameterIuivOES fnptr_ci_glGetSamplerParameterIuivOES
+ #define glTexBufferOES fnptr_ci_glTexBufferOES
+ #define glTexBufferRangeOES fnptr_ci_glTexBufferRangeOES
+ #define glTexStorage3DMultisampleOES fnptr_ci_glTexStorage3DMultisampleOES
+ #define glTextureViewOES fnptr_ci_glTextureViewOES
+ #define glGetPerfMonitorGroupsAMD fnptr_ci_glGetPerfMonitorGroupsAMD
+ #define glGetPerfMonitorCountersAMD fnptr_ci_glGetPerfMonitorCountersAMD
+ #define glGetPerfMonitorGroupStringAMD fnptr_ci_glGetPerfMonitorGroupStringAMD
+ #define glGetPerfMonitorCounterStringAMD fnptr_ci_glGetPerfMonitorCounterStringAMD
+ #define glGetPerfMonitorCounterInfoAMD fnptr_ci_glGetPerfMonitorCounterInfoAMD
+ #define glGenPerfMonitorsAMD fnptr_ci_glGenPerfMonitorsAMD
+ #define glDeletePerfMonitorsAMD fnptr_ci_glDeletePerfMonitorsAMD
+ #define glSelectPerfMonitorCountersAMD fnptr_ci_glSelectPerfMonitorCountersAMD
+ #define glBeginPerfMonitorAMD fnptr_ci_glBeginPerfMonitorAMD
+ #define glEndPerfMonitorAMD fnptr_ci_glEndPerfMonitorAMD
+ #define glGetPerfMonitorCounterDataAMD fnptr_ci_glGetPerfMonitorCounterDataAMD
+ #define glBlitFramebufferANGLE fnptr_ci_glBlitFramebufferANGLE
+ #define glDrawArraysInstancedANGLE fnptr_ci_glDrawArraysInstancedANGLE
+ #define glDrawElementsInstancedANGLE fnptr_ci_glDrawElementsInstancedANGLE
+ #define glGetTranslatedShaderSourceANGLE fnptr_ci_glGetTranslatedShaderSourceANGLE
+ #define glCopyTextureLevelsAPPLE fnptr_ci_glCopyTextureLevelsAPPLE
+ #define glResolveMultisampleFramebufferAPPLE fnptr_ci_glResolveMultisampleFramebufferAPPLE
+ #define glFenceSyncAPPLE fnptr_ci_glFenceSyncAPPLE
+ #define glIsSyncAPPLE fnptr_ci_glIsSyncAPPLE
+ #define glDeleteSyncAPPLE fnptr_ci_glDeleteSyncAPPLE
+ #define glClientWaitSyncAPPLE fnptr_ci_glClientWaitSyncAPPLE
+ #define glWaitSyncAPPLE fnptr_ci_glWaitSyncAPPLE
+ #define glGetInteger64vAPPLE fnptr_ci_glGetInteger64vAPPLE
+ #define glGetSyncivAPPLE fnptr_ci_glGetSyncivAPPLE
+ #define glDrawArraysInstancedBaseInstanceEXT fnptr_ci_glDrawArraysInstancedBaseInstanceEXT
+ #define glDrawElementsInstancedBaseInstanceEXT fnptr_ci_glDrawElementsInstancedBaseInstanceEXT
+ #define glDrawElementsInstancedBaseVertexBaseInstanceEXT fnptr_ci_glDrawElementsInstancedBaseVertexBaseInstanceEXT
+ #define glBindFragDataLocationIndexedEXT fnptr_ci_glBindFragDataLocationIndexedEXT
+ #define glBindFragDataLocationEXT fnptr_ci_glBindFragDataLocationEXT
+ #define glGetProgramResourceLocationIndexEXT fnptr_ci_glGetProgramResourceLocationIndexEXT
+ #define glGetFragDataIndexEXT fnptr_ci_glGetFragDataIndexEXT
+ #define glCopyImageSubDataEXT fnptr_ci_glCopyImageSubDataEXT
+ #define glLabelObjectEXT fnptr_ci_glLabelObjectEXT
+ #define glGetObjectLabelEXT fnptr_ci_glGetObjectLabelEXT
+ #define glInsertEventMarkerEXT fnptr_ci_glInsertEventMarkerEXT
+ #define glPushGroupMarkerEXT fnptr_ci_glPushGroupMarkerEXT
+ #define glPopGroupMarkerEXT fnptr_ci_glPopGroupMarkerEXT
+ #define glDiscardFramebufferEXT fnptr_ci_glDiscardFramebufferEXT
+ #define glGenQueriesEXT fnptr_ci_glGenQueriesEXT
+ #define glDeleteQueriesEXT fnptr_ci_glDeleteQueriesEXT
+ #define glIsQueryEXT fnptr_ci_glIsQueryEXT
+ #define glBeginQueryEXT fnptr_ci_glBeginQueryEXT
+ #define glEndQueryEXT fnptr_ci_glEndQueryEXT
+ #define glQueryCounterEXT fnptr_ci_glQueryCounterEXT
+ #define glGetQueryivEXT fnptr_ci_glGetQueryivEXT
+ #define glGetQueryObjectivEXT fnptr_ci_glGetQueryObjectivEXT
+ #define glGetQueryObjectuivEXT fnptr_ci_glGetQueryObjectuivEXT
+ #define glGetQueryObjecti64vEXT fnptr_ci_glGetQueryObjecti64vEXT
+ #define glGetQueryObjectui64vEXT fnptr_ci_glGetQueryObjectui64vEXT
+ #define glEnableiEXT fnptr_ci_glEnableiEXT
+ #define glDisableiEXT fnptr_ci_glDisableiEXT
+ #define glBlendEquationiEXT fnptr_ci_glBlendEquationiEXT
+ #define glBlendEquationSeparateiEXT fnptr_ci_glBlendEquationSeparateiEXT
+ #define glBlendFunciEXT fnptr_ci_glBlendFunciEXT
+ #define glBlendFuncSeparateiEXT fnptr_ci_glBlendFuncSeparateiEXT
+ #define glColorMaskiEXT fnptr_ci_glColorMaskiEXT
+ #define glIsEnablediEXT fnptr_ci_glIsEnablediEXT
+ #define glDrawElementsBaseVertexEXT fnptr_ci_glDrawElementsBaseVertexEXT
+ #define glDrawRangeElementsBaseVertexEXT fnptr_ci_glDrawRangeElementsBaseVertexEXT
+ #define glDrawElementsInstancedBaseVertexEXT fnptr_ci_glDrawElementsInstancedBaseVertexEXT
+ #define glMultiDrawElementsBaseVertexEXT fnptr_ci_glMultiDrawElementsBaseVertexEXT
+ #define glDrawArraysInstancedEXT fnptr_ci_glDrawArraysInstancedEXT
+ #define glDrawElementsInstancedEXT fnptr_ci_glDrawElementsInstancedEXT
+ #define glMapBufferRangeEXT fnptr_ci_glMapBufferRangeEXT
+ #define glMultiDrawArraysEXT fnptr_ci_glMultiDrawArraysEXT
+ #define glMultiDrawElementsEXT fnptr_ci_glMultiDrawElementsEXT
+ #define glMultiDrawArraysIndirectEXT fnptr_ci_glMultiDrawArraysIndirectEXT
+ #define glMultiDrawElementsIndirectEXT fnptr_ci_glMultiDrawElementsIndirectEXT
+ #define glFramebufferTexture2DMultisampleEXT fnptr_ci_glFramebufferTexture2DMultisampleEXT
+ #define glReadBufferIndexedEXT fnptr_ci_glReadBufferIndexedEXT
+ #define glDrawBuffersIndexedEXT fnptr_ci_glDrawBuffersIndexedEXT
+ #define glGetIntegeri_vEXT fnptr_ci_glGetIntegeri_vEXT
+ #define glPrimitiveBoundingBoxEXT fnptr_ci_glPrimitiveBoundingBoxEXT
+ #define glRasterSamplesEXT fnptr_ci_glRasterSamplesEXT
+ #define glGetGraphicsResetStatusEXT fnptr_ci_glGetGraphicsResetStatusEXT
+ #define glReadnPixelsEXT fnptr_ci_glReadnPixelsEXT
+ #define glGetnUniformfvEXT fnptr_ci_glGetnUniformfvEXT
+ #define glGetnUniformivEXT fnptr_ci_glGetnUniformivEXT
+ #define glActiveShaderProgramEXT fnptr_ci_glActiveShaderProgramEXT
+ #define glBindProgramPipelineEXT fnptr_ci_glBindProgramPipelineEXT
+ #define glCreateShaderProgramvEXT fnptr_ci_glCreateShaderProgramvEXT
+ #define glDeleteProgramPipelinesEXT fnptr_ci_glDeleteProgramPipelinesEXT
+ #define glGenProgramPipelinesEXT fnptr_ci_glGenProgramPipelinesEXT
+ #define glGetProgramPipelineInfoLogEXT fnptr_ci_glGetProgramPipelineInfoLogEXT
+ #define glGetProgramPipelineivEXT fnptr_ci_glGetProgramPipelineivEXT
+ #define glIsProgramPipelineEXT fnptr_ci_glIsProgramPipelineEXT
+ #define glProgramParameteriEXT fnptr_ci_glProgramParameteriEXT
+ #define glProgramUniform1fEXT fnptr_ci_glProgramUniform1fEXT
+ #define glProgramUniform1fvEXT fnptr_ci_glProgramUniform1fvEXT
+ #define glProgramUniform1iEXT fnptr_ci_glProgramUniform1iEXT
+ #define glProgramUniform1ivEXT fnptr_ci_glProgramUniform1ivEXT
+ #define glProgramUniform2fEXT fnptr_ci_glProgramUniform2fEXT
+ #define glProgramUniform2fvEXT fnptr_ci_glProgramUniform2fvEXT
+ #define glProgramUniform2iEXT fnptr_ci_glProgramUniform2iEXT
+ #define glProgramUniform2ivEXT fnptr_ci_glProgramUniform2ivEXT
+ #define glProgramUniform3fEXT fnptr_ci_glProgramUniform3fEXT
+ #define glProgramUniform3fvEXT fnptr_ci_glProgramUniform3fvEXT
+ #define glProgramUniform3iEXT fnptr_ci_glProgramUniform3iEXT
+ #define glProgramUniform3ivEXT fnptr_ci_glProgramUniform3ivEXT
+ #define glProgramUniform4fEXT fnptr_ci_glProgramUniform4fEXT
+ #define glProgramUniform4fvEXT fnptr_ci_glProgramUniform4fvEXT
+ #define glProgramUniform4iEXT fnptr_ci_glProgramUniform4iEXT
+ #define glProgramUniform4ivEXT fnptr_ci_glProgramUniform4ivEXT
+ #define glProgramUniformMatrix2fvEXT fnptr_ci_glProgramUniformMatrix2fvEXT
+ #define glProgramUniformMatrix3fvEXT fnptr_ci_glProgramUniformMatrix3fvEXT
+ #define glProgramUniformMatrix4fvEXT fnptr_ci_glProgramUniformMatrix4fvEXT
+ #define glUseProgramStagesEXT fnptr_ci_glUseProgramStagesEXT
+ #define glValidateProgramPipelineEXT fnptr_ci_glValidateProgramPipelineEXT
+ #define glProgramUniform1uiEXT fnptr_ci_glProgramUniform1uiEXT
+ #define glProgramUniform2uiEXT fnptr_ci_glProgramUniform2uiEXT
+ #define glProgramUniform3uiEXT fnptr_ci_glProgramUniform3uiEXT
+ #define glProgramUniform4uiEXT fnptr_ci_glProgramUniform4uiEXT
+ #define glProgramUniform1uivEXT fnptr_ci_glProgramUniform1uivEXT
+ #define glProgramUniform2uivEXT fnptr_ci_glProgramUniform2uivEXT
+ #define glProgramUniform3uivEXT fnptr_ci_glProgramUniform3uivEXT
+ #define glProgramUniform4uivEXT fnptr_ci_glProgramUniform4uivEXT
+ #define glProgramUniformMatrix2x3fvEXT fnptr_ci_glProgramUniformMatrix2x3fvEXT
+ #define glProgramUniformMatrix3x2fvEXT fnptr_ci_glProgramUniformMatrix3x2fvEXT
+ #define glProgramUniformMatrix2x4fvEXT fnptr_ci_glProgramUniformMatrix2x4fvEXT
+ #define glProgramUniformMatrix4x2fvEXT fnptr_ci_glProgramUniformMatrix4x2fvEXT
+ #define glProgramUniformMatrix3x4fvEXT fnptr_ci_glProgramUniformMatrix3x4fvEXT
+ #define glProgramUniformMatrix4x3fvEXT fnptr_ci_glProgramUniformMatrix4x3fvEXT
+ #define glTexPageCommitmentEXT fnptr_ci_glTexPageCommitmentEXT
+ #define glTexParameterIivEXT fnptr_ci_glTexParameterIivEXT
+ #define glTexParameterIuivEXT fnptr_ci_glTexParameterIuivEXT
+ #define glGetTexParameterIivEXT fnptr_ci_glGetTexParameterIivEXT
+ #define glGetTexParameterIuivEXT fnptr_ci_glGetTexParameterIuivEXT
+ #define glSamplerParameterIivEXT fnptr_ci_glSamplerParameterIivEXT
+ #define glSamplerParameterIuivEXT fnptr_ci_glSamplerParameterIuivEXT
+ #define glGetSamplerParameterIivEXT fnptr_ci_glGetSamplerParameterIivEXT
+ #define glGetSamplerParameterIuivEXT fnptr_ci_glGetSamplerParameterIuivEXT
+ #define glTexBufferEXT fnptr_ci_glTexBufferEXT
+ #define glTexBufferRangeEXT fnptr_ci_glTexBufferRangeEXT
+ #define glTexStorage1DEXT fnptr_ci_glTexStorage1DEXT
+ #define glTexStorage2DEXT fnptr_ci_glTexStorage2DEXT
+ #define glTexStorage3DEXT fnptr_ci_glTexStorage3DEXT
+ #define glTextureStorage1DEXT fnptr_ci_glTextureStorage1DEXT
+ #define glTextureStorage2DEXT fnptr_ci_glTextureStorage2DEXT
+ #define glTextureStorage3DEXT fnptr_ci_glTextureStorage3DEXT
+ #define glTextureViewEXT fnptr_ci_glTextureViewEXT
+ #define glFramebufferTexture2DMultisampleIMG fnptr_ci_glFramebufferTexture2DMultisampleIMG
+ #define glApplyFramebufferAttachmentCMAAINTEL fnptr_ci_glApplyFramebufferAttachmentCMAAINTEL
+ #define glBeginPerfQueryINTEL fnptr_ci_glBeginPerfQueryINTEL
+ #define glCreatePerfQueryINTEL fnptr_ci_glCreatePerfQueryINTEL
+ #define glDeletePerfQueryINTEL fnptr_ci_glDeletePerfQueryINTEL
+ #define glEndPerfQueryINTEL fnptr_ci_glEndPerfQueryINTEL
+ #define glGetFirstPerfQueryIdINTEL fnptr_ci_glGetFirstPerfQueryIdINTEL
+ #define glGetNextPerfQueryIdINTEL fnptr_ci_glGetNextPerfQueryIdINTEL
+ #define glGetPerfCounterInfoINTEL fnptr_ci_glGetPerfCounterInfoINTEL
+ #define glGetPerfQueryDataINTEL fnptr_ci_glGetPerfQueryDataINTEL
+ #define glGetPerfQueryIdByNameINTEL fnptr_ci_glGetPerfQueryIdByNameINTEL
+ #define glGetPerfQueryInfoINTEL fnptr_ci_glGetPerfQueryInfoINTEL
+ #define glGetTextureHandleNV fnptr_ci_glGetTextureHandleNV
+ #define glGetTextureSamplerHandleNV fnptr_ci_glGetTextureSamplerHandleNV
+ #define glMakeTextureHandleResidentNV fnptr_ci_glMakeTextureHandleResidentNV
+ #define glMakeTextureHandleNonResidentNV fnptr_ci_glMakeTextureHandleNonResidentNV
+ #define glGetImageHandleNV fnptr_ci_glGetImageHandleNV
+ #define glMakeImageHandleResidentNV fnptr_ci_glMakeImageHandleResidentNV
+ #define glMakeImageHandleNonResidentNV fnptr_ci_glMakeImageHandleNonResidentNV
+ #define glUniformHandleui64NV fnptr_ci_glUniformHandleui64NV
+ #define glUniformHandleui64vNV fnptr_ci_glUniformHandleui64vNV
+ #define glProgramUniformHandleui64NV fnptr_ci_glProgramUniformHandleui64NV
+ #define glProgramUniformHandleui64vNV fnptr_ci_glProgramUniformHandleui64vNV
+ #define glIsTextureHandleResidentNV fnptr_ci_glIsTextureHandleResidentNV
+ #define glIsImageHandleResidentNV fnptr_ci_glIsImageHandleResidentNV
+ #define glBlendParameteriNV fnptr_ci_glBlendParameteriNV
+ #define glBlendBarrierNV fnptr_ci_glBlendBarrierNV
+ #define glBeginConditionalRenderNV fnptr_ci_glBeginConditionalRenderNV
+ #define glEndConditionalRenderNV fnptr_ci_glEndConditionalRenderNV
+ #define glSubpixelPrecisionBiasNV fnptr_ci_glSubpixelPrecisionBiasNV
+ #define glCopyBufferSubDataNV fnptr_ci_glCopyBufferSubDataNV
+ #define glCoverageMaskNV fnptr_ci_glCoverageMaskNV
+ #define glCoverageOperationNV fnptr_ci_glCoverageOperationNV
+ #define glDrawBuffersNV fnptr_ci_glDrawBuffersNV
+ #define glDrawArraysInstancedNV fnptr_ci_glDrawArraysInstancedNV
+ #define glDrawElementsInstancedNV fnptr_ci_glDrawElementsInstancedNV
+ #define glDeleteFencesNV fnptr_ci_glDeleteFencesNV
+ #define glGenFencesNV fnptr_ci_glGenFencesNV
+ #define glIsFenceNV fnptr_ci_glIsFenceNV
+ #define glTestFenceNV fnptr_ci_glTestFenceNV
+ #define glGetFenceivNV fnptr_ci_glGetFenceivNV
+ #define glFinishFenceNV fnptr_ci_glFinishFenceNV
+ #define glSetFenceNV fnptr_ci_glSetFenceNV
+ #define glFragmentCoverageColorNV fnptr_ci_glFragmentCoverageColorNV
+ #define glBlitFramebufferNV fnptr_ci_glBlitFramebufferNV
+ #define glCoverageModulationTableNV fnptr_ci_glCoverageModulationTableNV
+ #define glGetCoverageModulationTableNV fnptr_ci_glGetCoverageModulationTableNV
+ #define glCoverageModulationNV fnptr_ci_glCoverageModulationNV
+ #define glGetInternalformatSampleivNV fnptr_ci_glGetInternalformatSampleivNV
+ #define glUniformMatrix2x3fvNV fnptr_ci_glUniformMatrix2x3fvNV
+ #define glUniformMatrix3x2fvNV fnptr_ci_glUniformMatrix3x2fvNV
+ #define glUniformMatrix2x4fvNV fnptr_ci_glUniformMatrix2x4fvNV
+ #define glUniformMatrix4x2fvNV fnptr_ci_glUniformMatrix4x2fvNV
+ #define glUniformMatrix3x4fvNV fnptr_ci_glUniformMatrix3x4fvNV
+ #define glUniformMatrix4x3fvNV fnptr_ci_glUniformMatrix4x3fvNV
+ #define glGenPathsNV fnptr_ci_glGenPathsNV
+ #define glDeletePathsNV fnptr_ci_glDeletePathsNV
+ #define glIsPathNV fnptr_ci_glIsPathNV
+ #define glPathCommandsNV fnptr_ci_glPathCommandsNV
+ #define glPathCoordsNV fnptr_ci_glPathCoordsNV
+ #define glPathSubCommandsNV fnptr_ci_glPathSubCommandsNV
+ #define glPathSubCoordsNV fnptr_ci_glPathSubCoordsNV
+ #define glPathStringNV fnptr_ci_glPathStringNV
+ #define glPathGlyphsNV fnptr_ci_glPathGlyphsNV
+ #define glPathGlyphRangeNV fnptr_ci_glPathGlyphRangeNV
+ #define glWeightPathsNV fnptr_ci_glWeightPathsNV
+ #define glCopyPathNV fnptr_ci_glCopyPathNV
+ #define glInterpolatePathsNV fnptr_ci_glInterpolatePathsNV
+ #define glTransformPathNV fnptr_ci_glTransformPathNV
+ #define glPathParameterivNV fnptr_ci_glPathParameterivNV
+ #define glPathParameteriNV fnptr_ci_glPathParameteriNV
+ #define glPathParameterfvNV fnptr_ci_glPathParameterfvNV
+ #define glPathParameterfNV fnptr_ci_glPathParameterfNV
+ #define glPathDashArrayNV fnptr_ci_glPathDashArrayNV
+ #define glPathStencilFuncNV fnptr_ci_glPathStencilFuncNV
+ #define glPathStencilDepthOffsetNV fnptr_ci_glPathStencilDepthOffsetNV
+ #define glStencilFillPathNV fnptr_ci_glStencilFillPathNV
+ #define glStencilStrokePathNV fnptr_ci_glStencilStrokePathNV
+ #define glStencilFillPathInstancedNV fnptr_ci_glStencilFillPathInstancedNV
+ #define glStencilStrokePathInstancedNV fnptr_ci_glStencilStrokePathInstancedNV
+ #define glPathCoverDepthFuncNV fnptr_ci_glPathCoverDepthFuncNV
+ #define glCoverFillPathNV fnptr_ci_glCoverFillPathNV
+ #define glCoverStrokePathNV fnptr_ci_glCoverStrokePathNV
+ #define glCoverFillPathInstancedNV fnptr_ci_glCoverFillPathInstancedNV
+ #define glCoverStrokePathInstancedNV fnptr_ci_glCoverStrokePathInstancedNV
+ #define glGetPathParameterivNV fnptr_ci_glGetPathParameterivNV
+ #define glGetPathParameterfvNV fnptr_ci_glGetPathParameterfvNV
+ #define glGetPathCommandsNV fnptr_ci_glGetPathCommandsNV
+ #define glGetPathCoordsNV fnptr_ci_glGetPathCoordsNV
+ #define glGetPathDashArrayNV fnptr_ci_glGetPathDashArrayNV
+ #define glGetPathMetricsNV fnptr_ci_glGetPathMetricsNV
+ #define glGetPathMetricRangeNV fnptr_ci_glGetPathMetricRangeNV
+ #define glGetPathSpacingNV fnptr_ci_glGetPathSpacingNV
+ #define glIsPointInFillPathNV fnptr_ci_glIsPointInFillPathNV
+ #define glIsPointInStrokePathNV fnptr_ci_glIsPointInStrokePathNV
+ #define glGetPathLengthNV fnptr_ci_glGetPathLengthNV
+ #define glPointAlongPathNV fnptr_ci_glPointAlongPathNV
+ #define glMatrixLoad3x2fNV fnptr_ci_glMatrixLoad3x2fNV
+ #define glMatrixLoad3x3fNV fnptr_ci_glMatrixLoad3x3fNV
+ #define glMatrixLoadTranspose3x3fNV fnptr_ci_glMatrixLoadTranspose3x3fNV
+ #define glMatrixMult3x2fNV fnptr_ci_glMatrixMult3x2fNV
+ #define glMatrixMult3x3fNV fnptr_ci_glMatrixMult3x3fNV
+ #define glMatrixMultTranspose3x3fNV fnptr_ci_glMatrixMultTranspose3x3fNV
+ #define glStencilThenCoverFillPathNV fnptr_ci_glStencilThenCoverFillPathNV
+ #define glStencilThenCoverStrokePathNV fnptr_ci_glStencilThenCoverStrokePathNV
+ #define glStencilThenCoverFillPathInstancedNV fnptr_ci_glStencilThenCoverFillPathInstancedNV
+ #define glStencilThenCoverStrokePathInstancedNV fnptr_ci_glStencilThenCoverStrokePathInstancedNV
+ #define glPathGlyphIndexRangeNV fnptr_ci_glPathGlyphIndexRangeNV
+ #define glPathGlyphIndexArrayNV fnptr_ci_glPathGlyphIndexArrayNV
+ #define glPathMemoryGlyphIndexArrayNV fnptr_ci_glPathMemoryGlyphIndexArrayNV
+ #define glProgramPathFragmentInputGenNV fnptr_ci_glProgramPathFragmentInputGenNV
+ #define glGetProgramResourcefvNV fnptr_ci_glGetProgramResourcefvNV
+ #define glPolygonModeNV fnptr_ci_glPolygonModeNV
+ #define glFramebufferSampleLocationsfvNV fnptr_ci_glFramebufferSampleLocationsfvNV
+ #define glNamedFramebufferSampleLocationsfvNV fnptr_ci_glNamedFramebufferSampleLocationsfvNV
+ #define glResolveDepthValuesNV fnptr_ci_glResolveDepthValuesNV
+ #define glViewportArrayvNV fnptr_ci_glViewportArrayvNV
+ #define glViewportIndexedfNV fnptr_ci_glViewportIndexedfNV
+ #define glViewportIndexedfvNV fnptr_ci_glViewportIndexedfvNV
+ #define glScissorArrayvNV fnptr_ci_glScissorArrayvNV
+ #define glScissorIndexedNV fnptr_ci_glScissorIndexedNV
+ #define glScissorIndexedvNV fnptr_ci_glScissorIndexedvNV
+ #define glDepthRangeArrayfvNV fnptr_ci_glDepthRangeArrayfvNV
+ #define glDepthRangeIndexedfNV fnptr_ci_glDepthRangeIndexedfNV
+ #define glGetFloati_vNV fnptr_ci_glGetFloati_vNV
+ #define glEnableiNV fnptr_ci_glEnableiNV
+ #define glDisableiNV fnptr_ci_glDisableiNV
+ #define glIsEnablediNV fnptr_ci_glIsEnablediNV
+ #define glFramebufferTextureMultiviewOVR fnptr_ci_glFramebufferTextureMultiviewOVR
+ #define glAlphaFuncQCOM fnptr_ci_glAlphaFuncQCOM
+ #define glGetDriverControlsQCOM fnptr_ci_glGetDriverControlsQCOM
+ #define glGetDriverControlStringQCOM fnptr_ci_glGetDriverControlStringQCOM
+ #define glEnableDriverControlQCOM fnptr_ci_glEnableDriverControlQCOM
+ #define glDisableDriverControlQCOM fnptr_ci_glDisableDriverControlQCOM
+ #define glExtGetTexturesQCOM fnptr_ci_glExtGetTexturesQCOM
+ #define glExtGetBuffersQCOM fnptr_ci_glExtGetBuffersQCOM
+ #define glExtGetRenderbuffersQCOM fnptr_ci_glExtGetRenderbuffersQCOM
+ #define glExtGetFramebuffersQCOM fnptr_ci_glExtGetFramebuffersQCOM
+ #define glExtGetTexLevelParameterivQCOM fnptr_ci_glExtGetTexLevelParameterivQCOM
+ #define glExtTexObjectStateOverrideiQCOM fnptr_ci_glExtTexObjectStateOverrideiQCOM
+ #define glExtGetTexSubImageQCOM fnptr_ci_glExtGetTexSubImageQCOM
+ #define glExtGetBufferPointervQCOM fnptr_ci_glExtGetBufferPointervQCOM
+ #define glExtGetShadersQCOM fnptr_ci_glExtGetShadersQCOM
+ #define glExtGetProgramsQCOM fnptr_ci_glExtGetProgramsQCOM
+ #define glExtIsProgramBinaryQCOM fnptr_ci_glExtIsProgramBinaryQCOM
+ #define glExtGetProgramBinarySourceQCOM fnptr_ci_glExtGetProgramBinarySourceQCOM
+ #define glStartTilingQCOM fnptr_ci_glStartTilingQCOM
+ #define glEndTilingQCOM fnptr_ci_glEndTilingQCOM
+
+ #if ( CINDER_GL_ES_VERSION == CINDER_GL_ES_VERSION_2 )
+ // GL_OES_required_internalformat
+ #define GL_ALPHA8 GL_ALPHA8_OES
+ //#define GL_DEPTH_COMPONENT16 GL_DEPTH_COMPONENT16_OES
+ #define GL_LUMINANCE4_ALPHA4 GL_LUMINANCE4_ALPHA4_OES
+ #define GL_LUMINANCE8_ALPHA8 GL_LUMINANCE8_ALPHA8_OES
+ #define GL_LUMINANCE8 GL_LUMINANCE8_OES
+ //#define GL_RGBA4 GL_RGBA4_OES
+ //#define GL_RGB5_A1 GL_RGB5_A1_OES
+ //#define GL_RGB565 GL_RGB565_OES
+ #define GL_RGB8 GL_RGB8_OES
+ #define GL_RGBA8 GL_RGBA8_OES
+ #define GL_RGB10 GL_RGB10_EXT
+ #define GL_RGB10_A2 GL_RGB10_A2_EXT
+
+ // GL_EXT_texture_rg
+ #define GL_RED GL_RED_EXT
+ #define GL_RG GL_RG_EXT
+ #define GL_R8 GL_R8_EXT
+ #define GL_RG8 GL_RG8_EXT
+
+ // GL_OES_texture_half_float
+ #define GL_HALF_FLOAT GL_HALF_FLOAT_OES
+
+ // GL_EXT_color_buffer_half_float
+ #define GL_RGBA16F GL_RGBA16F_EXT
+ #define GL_RGB16F GL_RGB16F_EXT
+ #define GL_RG16F GL_RG16F_EXT
+ #define GL_R16F GL_R16F_EXT
+ #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT
+ #define GL_UNSIGNED_NORMALIZED GL_UNSIGNED_NORMALIZED_EXT
+
+ // GL_EXT_texture_storage
+ #define GL_RGBA32F GL_RGBA32F_EXT
+ #define GL_RGB32F GL_RGB32F_EXT
+ #define GL_RG32F GL_RG32F_EXT
+ #define GL_R32F GL_R32F_EXT
+
+ // GL_APPLE_texture_packed_float
+ #define GL_UNSIGNED_INT_10F_11F_11F_REV GL_UNSIGNED_INT_10F_11F_11F_REV_APPLE
+ #define GL_UNSIGNED_INT_5_9_9_9_REV GL_UNSIGNED_INT_5_9_9_9_REV_APPLE
+ #define GL_R11F_G11F_B10F GL_R11F_G11F_B10F_APPLE
+ #define GL_RGB9_E5 GL_RGB9_E5_APPLE
+
+ // GL_OES_depth24
+ #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
+
+ // GL_OES_mapbuffer
+ #define GL_WRITE_ONLY GL_WRITE_ONLY_OES
+ extern PFNGLMAPBUFFEROESPROC fnptr_ci_glMapBufferOES;
+ extern PFNGLUNMAPBUFFEROESPROC fnptr_ci_glUnmapBufferOES;
+ #define glMapBuffer fnptr_ci_glMapBufferOES
+ #define glUnmapBuffer fnptr_ci_glUnmapBufferOES
+
+ // GL_OES_vertex_array_object
+ extern PFNGLBINDVERTEXARRAYOESPROC fnptr_ci_glBindVertexArrayOES;
+ extern PFNGLDELETEVERTEXARRAYSOESPROC fnptr_ci_glDeleteVertexArraysOES;
+ extern PFNGLGENVERTEXARRAYSOESPROC fnptr_ci_glGenVertexArraysOES;
+ extern PFNGLISVERTEXARRAYOESPROC fnptr_ci_glIsVertexArrayOES;
+ #define glBindVertexArray fnptr_ci_glBindVertexArrayOES
+ #define glDeleteVertexArrays fnptr_ci_glDeleteVertexArraysOES
+ #define glGenVertexArrays fnptr_ci_glGenVertexArraysOES
+ #define glIsVertexArray fnptr_ci_glIsVertexArrayOES
+
+ // GL_EXT_map_buffer_range
+ #if ! defined( GL_MAP_READ_BIT )
+ #define GL_MAP_READ_BIT GL_MAP_READ_BIT_EXT
+ #define GL_MAP_WRITE_BIT GL_MAP_WRITE_BIT_EXT
+ #endif
+ #define GL_MAP_INVALIDATE_RANGE_BIT GL_MAP_INVALIDATE_RANGE_BIT_EXT
+ #define GL_MAP_INVALIDATE_BUFFER_BIT GL_MAP_INVALIDATE_BUFFER_BIT_EXT
+ #define GL_MAP_FLUSH_EXPLICIT_BIT GL_MAP_FLUSH_EXPLICIT_BIT_EXT
+ #define GL_MAP_UNSYNCHRONIZED_BIT GL_MAP_UNSYNCHRONIZED_BIT_EXT
+ extern PFNGLMAPBUFFERRANGEEXTPROC fnptr_ci_glMapBufferRangeEXT;
+ extern PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC fnptr_ci_glFlushMappedBufferRangeEXT;
+ #define glMapBufferRange fnptr_ci_glMapBufferRangeEXT
+ #define glFlushMappedBufferRangeEXT fnptr_ci_glFlushMappedBufferRangeEXT
+
+ // GL_EXT_multisampled_render_to_texture and the like
+ //
+ // fnptr_ci_glRenderbufferStorageMultisample maps to one of the following:
+ // glRenderbufferStorageMultisampleANGLE
+ // glRenderbufferStorageMultisampleAPPLE
+ // glRenderbufferStorageMultisampleEXT
+ // glRenderbufferStorageMultisampleIMG
+ // glRenderbufferStorageMultisampleNV
+ //
+ #define GL_READ_FRAMEBUFFER 0x8CA8
+ #define GL_DRAW_FRAMEBUFFER 0x8CA9
+ #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
+ #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
+ typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+ extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC fnptr_ci_glRenderbufferStorageMultisample;
+ #define glRenderbufferStorageMultisample fnptr_ci_glRenderbufferStorageMultisample
+
+ // GL_NV_framebuffer_blit, GL_ANGLE_framebuffer_blit
+ typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+ extern PFNGLBLITFRAMEBUFFERPROC fnptr_ci_glBlitFramebuffer;
+ #define glBlitFramebuffer fnptr_ci_glBlitFramebuffer
+
+ // GL_EXT_draw_buffers
+ #define glDrawBuffers fnptr_ci_glDrawBuffersEXT
+
+ // GL_NV_read_buffer
+ #define glReadBuffer fnptr_ci_glReadBufferNV
+
+ // GL_ANGLE_instanced_arrays, GL_EXT_draw_instanced, GL_NV_draw_instanced
+ typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+ typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+ extern PFNGLDRAWARRAYSINSTANCEDPROC fnptr_ci_glDrawArraysInstanced;
+ extern PFNGLDRAWELEMENTSINSTANCEDPROC fnptr_ci_glDrawElementsInstanced;
+ #define glDrawArraysInstanced fnptr_ci_glDrawArraysInstanced
+ #define glDrawElementsInstanced fnptr_ci_glDrawElementsInstanced
+
+ // GL_ANGLE_instanced_arrays, GL_EXT_instanced_arrays, GL_NV_instanced_arrays
+ typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
+ extern PFNGLVERTEXATTRIBDIVISORPROC fnptr_ci_glVertexAttribDivisor;
+ #define glVertexAttribDivisor fnptr_ci_glVertexAttribDivisor
+
+ // GL_EXT_shadow_samplers
+ #define GL_TEXTURE_COMPARE_MODE 0x884C
+ #define GL_TEXTURE_COMPARE_FUNC 0x884D
+ #define GL_COMPARE_REF_TO_TEXTURE 0x884E
+ #define GL_SAMPLER_2D_SHADOW 0x8B62
+ #endif
+ #endif // ( CINDER_GL_ES_VERSION == CINDER_GL_ES_VERSION_2 )
+
+ #if ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_2 )
+ // GL_EXT_render_snorm, GL_EXT_texture_norm16 (GL_RGB16_SNORM_EXT)
+ #define GL_R16_SNORM GL_R16_SNORM_EXT
+ #define GL_RG16_SNORM GL_RG16_SNORM_EXT
+ #define GL_RGB16_SNORM GL_RGB16_SNORM_EXT
+ #define GL_RGBA16_SNORM GL_RGBA16_SNORM_EXT
+
+ // GL_EXT_texture_norm16
+ #define GL_R16 GL_R16_EXT
+ #define GL_RG16 GL_RG16_EXT
+ #define GL_RGB16 GL_RGB16_EXT
+ #define GL_RGBA16 GL_RGBA16_EXT
+
+ // GL_EXT_buffer_storage
+ typedef void (GL_APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+ extern PFNGLBUFFERSTORAGEPROC fnptr_ci_glBufferStorage;
+ #define glBufferStorage fnptr_ci_glBufferStorage
+ #endif
+
+ #if ( CINDER_GL_ES_VERSION >= CINDER_GL_ES_VERSION_3 )
+ // GL_OES_required_internalformat
+ #define GL_RGB10 GL_RGB10_EXT
+ #endif
+
+ // Android Extension Pack
+ #if ( CINDER_GL_ES_VERSION == CINDER_GL_ES_VERSION_3_1 )
+ #define GL_GEOMETRY_SHADER GL_GEOMETRY_SHADER_EXT
+ #define GL_GEOMETRY_SHADER_BIT GL_GEOMETRY_SHADER_BIT_EXT
+ #define GL_GEOMETRY_LINKED_VERTICES_OUT GL_GEOMETRY_LINKED_VERTICES_OUT_EXT
+ #define GL_GEOMETRY_LINKED_INPUT_TYPE GL_GEOMETRY_LINKED_INPUT_TYPE_EXT
+ #define GL_GEOMETRY_LINKED_OUTPUT_TYPE GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT
+ #define GL_GEOMETRY_SHADER_INVOCATIONS GL_GEOMETRY_SHADER_INVOCATIONS_EXT
+ #define GL_LAYER_PROVOKING_VERTEX GL_LAYER_PROVOKING_VERTEX_EXT
+ #define GL_LINES_ADJACENCY GL_LINES_ADJACENCY_EXT
+ #define GL_LINE_STRIP_ADJACENCY GL_LINE_STRIP_ADJACENCY_EXT
+ #define GL_TRIANGLES_ADJACENCY GL_TRIANGLES_ADJACENCY_EXT
+ #define GL_TRIANGLE_STRIP_ADJACENCY GL_TRIANGLE_STRIP_ADJACENCY_EXT
+ #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT
+ #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT
+ #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT
+ #define GL_MAX_GEOMETRY_INPUT_COMPONENTS GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT
+ #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT
+ #define GL_MAX_GEOMETRY_OUTPUT_VERTICES GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT
+ #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT
+ #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT
+ #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT
+ #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT
+ #define GL_MAX_GEOMETRY_ATOMIC_COUNTERS GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT
+ #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT
+ #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT
+ #define GL_FIRST_VERTEX_CONVENTION GL_FIRST_VERTEX_CONVENTION_EXT
+ #define GL_LAST_VERTEX_CONVENTION GL_LAST_VERTEX_CONVENTION_EXT
+ #define GL_UNDEFINED_VERTEX GL_UNDEFINED_VERTEX_EXT
+ #define GL_PRIMITIVES_GENERATED GL_PRIMITIVES_GENERATED_EXT
+ #define GL_FRAMEBUFFER_DEFAULT_LAYERS GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT
+ #define GL_MAX_FRAMEBUFFER_LAYERS GL_MAX_FRAMEBUFFER_LAYERS_EXT
+ #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT
+ #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT
+ #define GL_REFERENCED_BY_GEOMETRY_SHADER GL_REFERENCED_BY_GEOMETRY_SHADER_EXT
+
+ #define GL_PATCHES GL_PATCHES_EXT
+ #define GL_PATCH_VERTICES GL_PATCH_VERTICES_EXT
+ #define GL_TESS_CONTROL_OUTPUT_VERTICES GL_TESS_CONTROL_OUTPUT_VERTICES_EXT
+ #define GL_TESS_GEN_MODE GL_TESS_GEN_MODE_EXT
+ #define GL_TESS_GEN_SPACING GL_TESS_GEN_SPACING_EXT
+ #define GL_TESS_GEN_VERTEX_ORDER GL_TESS_GEN_VERTEX_ORDER_EXT
+ #define GL_TESS_GEN_POINT_MODE GL_TESS_GEN_POINT_MODE_EXT
+ #define GL_ISOLINES GL_ISOLINES_EXT
+ #define GL_QUADS GL_QUADS_EXT
+ #define GL_FRACTIONAL_ODD GL_FRACTIONAL_ODD_EXT
+ #define GL_FRACTIONAL_EVEN GL_FRACTIONAL_EVEN_EXT
+ #define GL_MAX_PATCH_VERTICES GL_MAX_PATCH_VERTICES_EXT
+ #define GL_MAX_TESS_GEN_LEVEL GL_MAX_TESS_GEN_LEVEL_EXT
+ #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT
+ #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT
+ #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT
+ #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT
+ #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT
+ #define GL_MAX_TESS_PATCH_COMPONENTS GL_MAX_TESS_PATCH_COMPONENTS_EXT
+ #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT
+ #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT
+ #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT
+ #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT
+ #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT
+ #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT
+ #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT
+ #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT
+ #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT
+ #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT
+ #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT
+ #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT
+ #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT
+ #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT
+ #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT
+ #define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT
+ #define GL_IS_PER_PATCH GL_IS_PER_PATCH_EXT
+ #define GL_REFERENCED_BY_TESS_CONTROL_SHADER GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT
+ #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT
+ #define GL_TESS_CONTROL_SHADER GL_TESS_CONTROL_SHADER_EXT
+ #define GL_TESS_EVALUATION_SHADER GL_TESS_EVALUATION_SHADER_EXT
+ #define GL_TESS_CONTROL_SHADER_BIT GL_TESS_CONTROL_SHADER_BIT_EXT
+ #define GL_TESS_EVALUATION_SHADER_BIT GL_TESS_EVALUATION_SHADER_BIT_EXT
+
+ typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+ typedef void (GL_APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);
+ extern PFNGLFRAMEBUFFERTEXTUREPROC fnptr_ci_glFramebufferTexture;
+ extern PFNGLPATCHPARAMETERIPROC fnptr_ci_glPatchParameteri;
+ #define glFramebufferTexture fnptr_ci_glFramebufferTexture
+ #define glPatchParameteri fnptr_ci_glPatchParameteri
+ #endif
+#endif
+
+// ----------------------------------------------------------------------------
+// gl_es_load
+// ----------------------------------------------------------------------------
+#if defined( CINDER_ANDROID ) || defined( CINDER_LINUX ) || defined( CINDER_EMSCRIPTEN )
+void gl_es_load();
+#endif
+
diff --git a/lib/emscripten/libboost_filesystem.bc b/lib/emscripten/libboost_filesystem.bc
new file mode 100644
index 0000000000..644a8e316c
Binary files /dev/null and b/lib/emscripten/libboost_filesystem.bc differ
diff --git a/lib/emscripten/libboost_system.bc b/lib/emscripten/libboost_system.bc
new file mode 100644
index 0000000000..8c7ec94d4e
Binary files /dev/null and b/lib/emscripten/libboost_system.bc differ
diff --git a/proj/cmake/configure.cmake b/proj/cmake/configure.cmake
index 708e84ed26..b28e3ac2fe 100644
--- a/proj/cmake/configure.cmake
+++ b/proj/cmake/configure.cmake
@@ -22,7 +22,9 @@ endif()
ci_log_v( "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}" )
# Set default target to build for
-if( CMAKE_SYSTEM_NAME MATCHES "Darwin" )
+if( CMAKE_SYSTEM_NAME MATCHES "Emscripten" )
+ set( CINDER_TARGET_DEFAULT "emscripten" )
+elseif( CMAKE_SYSTEM_NAME MATCHES "Darwin" )
set( CINDER_TARGET_DEFAULT "macosx" )
elseif( CMAKE_SYSTEM_NAME MATCHES "Linux" )
set( CINDER_TARGET_DEFAULT "linux" )
@@ -46,6 +48,14 @@ if( CINDER_TARGET )
set( CINDER_MAC TRUE )
elseif( "msw" STREQUAL "${CINDER_TARGET_LOWER}" )
set( CINDER_MSW TRUE )
+ elseif( "emscripten" STREQUAL "${CINDER_TARGET_LOWER}" )
+ if( NOT DEFINED ENV{EMSCRIPTEN} )
+ message( FATAL_ERROR "Requested to build Cinder for Emscripten but the environment does not seem to be set. \
+ Forgot to run 'emsdk_set_env.sh' ?" )
+ endif()
+ set( CINDER_DISABLE_VIDEO ON )
+ set( CINDER_DISABLE_CAPTURE ON )
+ set( CINDER_EMSCRIPTEN TRUE )
else()
message( FATAL_ERROR "unexpected CINDER_TARGET '${CINDER_TARGET}'." )
endif()
@@ -56,6 +66,8 @@ endif()
# Configure which gl target to build for, currently only used on linux.
if( CINDER_LINUX )
set( CINDER_TARGET_GL_DEFAULT "ogl" )
+elseif( CINDER_EMSCRIPTEN )
+ set( CINDER_TARGET_GL_DEFAULT "es3" )
else()
set( CINDER_TARGET_GL_DEFAULT "" )
endif()
@@ -131,6 +143,8 @@ elseif( CINDER_MSW )
set( CINDER_ARCH "x64" )
endif()
set( CINDER_TARGET_SUBFOLDER "msw/${CINDER_ARCH}" ) # TODO: place in msw/arch folder (x64 or x86)
+elseif( CINDER_EMSCRIPTEN )
+ set( CINDER_TARGET_SUBFOLDER "emscripten" )
endif()
# CINDER_LIB_DIRECTORY is the platform-specific, relative path that will be used to define
diff --git a/proj/cmake/emscripten/shell.html b/proj/cmake/emscripten/shell.html
new file mode 100644
index 0000000000..1812fc4016
--- /dev/null
+++ b/proj/cmake/emscripten/shell.html
@@ -0,0 +1,293 @@
+
+
+
+
+
+ Emscripten-Generated Code
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{{ SCRIPT }}}
+
+
\ No newline at end of file
diff --git a/proj/cmake/libcinder_configure.cmake b/proj/cmake/libcinder_configure.cmake
index ac35bf1510..6b498268f6 100644
--- a/proj/cmake/libcinder_configure.cmake
+++ b/proj/cmake/libcinder_configure.cmake
@@ -21,25 +21,58 @@ list( APPEND CINDER_INCLUDE_SYSTEM_INTERFACE
)
# *_PRIVATE includes are used by cinder internally, user apps explicitly add these as needed.
-list( APPEND CINDER_INCLUDE_USER_PRIVATE
- ${CINDER_INC_DIR}
- ${CINDER_INC_DIR}/jsoncpp
- ${CINDER_INC_DIR}/tinyexr
- ${CINDER_INC_DIR}/imgui
- ${CINDER_SRC_DIR}/linebreak
- ${CINDER_SRC_DIR}/oggvorbis/vorbis
- ${CINDER_SRC_DIR}/r8brain
-)
+
+# Remove vorbis stuff when on web, include eotherwise.
+if( CINDER_EMSCRIPTEN )
+ list( APPEND CINDER_INCLUDE_USER_PRIVATE
+ ${CINDER_INC_DIR}
+ ${CINDER_INC_DIR}/jsoncpp
+ ${CINDER_INC_DIR}/tinyexr
+ ${CINDER_INC_DIR}/imgui
+ ${CINDER_SRC_DIR}/linebreak
+ ${CINDER_SRC_DIR}/r8brain
+ )
+
+else()
+
+ list( APPEND CINDER_INCLUDE_USER_PRIVATE
+ ${CINDER_INC_DIR}
+ ${CINDER_INC_DIR}/jsoncpp
+ ${CINDER_INC_DIR}/tinyexr
+ ${CINDER_INC_DIR}/imgui
+ ${CINDER_SRC_DIR}/linebreak
+ ${CINDER_SRC_DIR}/oggvorbis/vorbis
+ ${CINDER_SRC_DIR}/r8brain
+ )
+
+endif()
if( CINDER_HEADLESS_GL_EGL )
list( APPEND CINDER_INCLUDE_USER_PRIVATE ${CINDER_INC_DIR}/EGL-Registry )
endif()
-list( APPEND CINDER_INCLUDE_SYSTEM_PRIVATE
- ${CINDER_INC_DIR}
- ${CINDER_INC_DIR}/oggvorbis
- ${CINDER_SRC_DIR}/AntTweakBar
-)
+# zlib seems to need to be included at around this point. Also take out some stuff we won't need on the Web.
+if( CINDER_EMSCRIPTEN )
+ list( APPEND CINDER_INCLUDE_SYSTEM_PRIVATE
+ ${CINDER_INC_DIR}
+ ${CINDER_INC_DIR}/emscripten
+ ${CINDER_SRC_DIR}/zlib
+ )
+
+ # on Emscripten, set to no audio as we'll rely on native capabilities as much as possible which unfortunately
+ # requires a ton of JS
+ set( CINDER_DISABLE_AUDIO TRUE)
+
+else()
+
+ list( APPEND CINDER_INCLUDE_SYSTEM_PRIVATE
+ ${CINDER_INC_DIR}
+ ${CINDER_INC_DIR}/oggvorbis
+ ${CINDER_SRC_DIR}/AntTweakBar
+ )
+
+endif()
+
# find cross-platform packages
diff --git a/proj/cmake/libcinder_source_files.cmake b/proj/cmake/libcinder_source_files.cmake
index 4d3bbc5910..33c2cb54fe 100644
--- a/proj/cmake/libcinder_source_files.cmake
+++ b/proj/cmake/libcinder_source_files.cmake
@@ -64,12 +64,12 @@ list( APPEND SRC_SET_CINDER
${CINDER_SRC_DIR}/cinder/Xml.cpp
)
-if( ( NOT CINDER_LINUX ) AND ( NOT CINDER_ANDROID ) )
+if( ( NOT CINDER_LINUX ) AND ( NOT CINDER_ANDROID ) AND ( NOT CINDER_EMSCRIPTEN ) )
list( APPEND SRC_SET_CINDER
${CINDER_SRC_DIR}/cinder/Capture.cpp
)
endif()
-if( ( NOT CINDER_COCOA_TOUCH ) AND ( NOT CINDER_ANDROID ) )
+if( ( NOT CINDER_COCOA_TOUCH ) AND ( NOT CINDER_ANDROID ) AND (NOT CINDER_EMSCRIPTEN ) )
list( APPEND SRC_SET_CINDER
${CINDER_SRC_DIR}/cinder/Serial.cpp
)
diff --git a/proj/cmake/libcinder_target.cmake b/proj/cmake/libcinder_target.cmake
index fd59aeb389..a8d1acd1a5 100644
--- a/proj/cmake/libcinder_target.cmake
+++ b/proj/cmake/libcinder_target.cmake
@@ -70,6 +70,8 @@ elseif( CINDER_MAC )
)
elseif( CINDER_COCOA_TOUCH )
elseif( CINDER_LINUX )
+elseif( CINDER_EMSCRIPTEN )
+ set_target_properties( cinder PROPERTIES LINK_FLAGS ${CINDER_EMSCRIPTEN_LINK_FLAGS} )
endif()
# Check compiler support for enabling c++11 or c++14.
diff --git a/proj/cmake/modules/Emscripten.cmake b/proj/cmake/modules/Emscripten.cmake
new file mode 100644
index 0000000000..f281dd965f
--- /dev/null
+++ b/proj/cmake/modules/Emscripten.cmake
@@ -0,0 +1,361 @@
+# This file is a 'toolchain description file' for CMake.
+# It teaches CMake about the Emscripten compiler, so that CMake can generate makefiles
+# from CMakeLists.txt that invoke emcc.
+
+# At the moment this required minimum version is not exact (i.e. we do not know of a feature that needs CMake 3.0.0 specifically)
+# It is possible that CMake 3.0.0 is too old and will not actually work. If you do find such a case, please report it at Emscripten
+# bug tracker to revise the minimum requirement. See also https://github.com/juj/emsdk/issues/108
+cmake_minimum_required(VERSION 3.0.0)
+
+# To use this toolchain file with CMake, invoke CMake with the following command line parameters
+# cmake -DCMAKE_TOOLCHAIN_FILE=/cmake/Modules/Platform/Emscripten.cmake
+# -DCMAKE_BUILD_TYPE=
+# -G "Unix Makefiles" (Linux and OSX)
+# -G "MinGW Makefiles" (Windows)
+# # Note, pass in here ONLY the path to the file, not the filename 'CMakeLists.txt' itself.
+
+# After that, build the generated Makefile with the command 'make'. On Windows, you may download and use 'mingw32-make' instead.
+
+# The following variable describes the target OS we are building to.
+set(CMAKE_SYSTEM_NAME Emscripten)
+set(CMAKE_SYSTEM_VERSION 1)
+
+set(CMAKE_CROSSCOMPILING TRUE)
+
+# Advertise Emscripten as a 32-bit platform (as opposed to CMAKE_SYSTEM_PROCESSOR=x86_64 for 64-bit platform),
+# since some projects (e.g. OpenCV) use this to detect bitness.
+set(CMAKE_SYSTEM_PROCESSOR x86)
+
+# Tell CMake how it should instruct the compiler to generate multiple versions of an outputted .so library: e.g. "libfoo.so, libfoo.so.1, libfoo.so.1.4" etc.
+# This feature is activated if a shared library project has the property SOVERSION defined.
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+
+# In CMake, CMAKE_HOST_WIN32 is set when we are cross-compiling from Win32 to Emscripten: http://www.cmake.org/cmake/help/v2.8.12/cmake.html#variable:CMAKE_HOST_WIN32
+# The variable WIN32 is set only when the target arch that will run the code will be WIN32, so unset WIN32 when cross-compiling.
+set(WIN32)
+
+# The same logic as above applies for APPLE and CMAKE_HOST_APPLE, so unset APPLE.
+set(APPLE)
+
+# And for UNIX and CMAKE_HOST_UNIX. However, Emscripten is often able to mimic being a Linux/Unix system, in which case a lot of existing CMakeLists.txt files can be configured for Emscripten while assuming UNIX build, so this is left enabled.
+set(UNIX 1)
+
+# Do a no-op access on the CMAKE_TOOLCHAIN_FILE variable so that CMake will not issue a warning on it being unused.
+if (CMAKE_TOOLCHAIN_FILE)
+endif()
+
+# In order for check_function_exists() detection to work, we must signal it to pass an additional flag, which causes the compilation
+# to abort if linking results in any undefined symbols. The CMake detection mechanism depends on the undefined symbol error to be raised.
+# Disable wasm in cmake checks so that (1) we do not depend on wasm support just for configuration (perhaps the user does not intend
+# to build to wasm; using asm.js only depends on js which we need anyhow), and (2) we don't have issues with a separate .wasm file
+# on the side, async startup, etc..
+set(CMAKE_REQUIRED_FLAGS "-s WASM=0")
+
+# Locate where the Emscripten compiler resides in relative to this toolchain file.
+if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "")
+ get_filename_component(GUESS_EMSCRIPTEN_ROOT_PATH "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
+ if (EXISTS "${GUESS_EMSCRIPTEN_ROOT_PATH}/emranlib")
+ set(EMSCRIPTEN_ROOT_PATH "${GUESS_EMSCRIPTEN_ROOT_PATH}")
+ endif()
+endif()
+
+# If not found by above search, locate using the EMSCRIPTEN environment variable.
+if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "")
+ set(EMSCRIPTEN_ROOT_PATH "$ENV{EMSCRIPTEN}")
+endif()
+
+# Abort if not found.
+if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "")
+ message(FATAL_ERROR "Could not locate the Emscripten compiler toolchain directory! Either set the EMSCRIPTEN environment variable, or pass -DEMSCRIPTEN_ROOT_PATH=xxx to CMake to explicitly specify the location of the compiler!")
+endif()
+
+# Normalize, convert Windows backslashes to forward slashes or CMake will crash.
+get_filename_component(EMSCRIPTEN_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}" ABSOLUTE)
+
+list(APPEND CMAKE_MODULE_PATH "${EMSCRIPTEN_ROOT_PATH}/cmake/Modules")
+
+list(APPEND CMAKE_FIND_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}/system")
+
+if (CMAKE_HOST_WIN32)
+ set(EMCC_SUFFIX ".bat")
+else()
+ set(EMCC_SUFFIX "")
+endif()
+
+# Specify the compilers to use for C and C++
+if ("${CMAKE_C_COMPILER}" STREQUAL "")
+ set(CMAKE_C_COMPILER "${EMSCRIPTEN_ROOT_PATH}/emcc${EMCC_SUFFIX}")
+endif()
+if ("${CMAKE_CXX_COMPILER}" STREQUAL "")
+ set(CMAKE_CXX_COMPILER "${EMSCRIPTEN_ROOT_PATH}/em++${EMCC_SUFFIX}")
+endif()
+
+if ("${CMAKE_AR}" STREQUAL "")
+ set(CMAKE_AR "${EMSCRIPTEN_ROOT_PATH}/emar${EMCC_SUFFIX}" CACHE FILEPATH "Emscripten ar")
+endif()
+
+if ("${CMAKE_RANLIB}" STREQUAL "")
+ set(CMAKE_RANLIB "${EMSCRIPTEN_ROOT_PATH}/emranlib${EMCC_SUFFIX}" CACHE FILEPATH "Emscripten ranlib")
+endif()
+
+# Don't allow CMake to autodetect the compiler, since it does not understand Emscripten.
+# Pass -DEMSCRIPTEN_FORCE_COMPILERS=OFF to disable (sensible mostly only for testing/debugging purposes).
+option(EMSCRIPTEN_FORCE_COMPILERS "Force C/C++ compiler" ON)
+if (EMSCRIPTEN_FORCE_COMPILERS)
+
+ # Detect version of the 'emcc' executable. Note that for CMake, we tell it the version of the Clang compiler and not the version of Emscripten,
+ # because CMake understands Clang better.
+ if (NOT CMAKE_C_COMPILER_VERSION) # Toolchain script is interpreted multiple times, so don't rerun the check if already done before.
+ execute_process(COMMAND "${CMAKE_C_COMPILER}" "-v" RESULT_VARIABLE _cmake_compiler_result ERROR_VARIABLE _cmake_compiler_output OUTPUT_QUIET)
+ if (NOT _cmake_compiler_result EQUAL 0)
+ message(FATAL_ERROR "Failed to fetch compiler version information with command \"'${CMAKE_C_COMPILER}' -v\"! Process returned with error code ${_cmake_compiler_result}.")
+ endif()
+ if (NOT "${_cmake_compiler_output}" MATCHES "[Ee]mscripten")
+ message(FATAL_ERROR "System LLVM compiler cannot be used to build with Emscripten! Check Emscripten's LLVM toolchain location in .emscripten configuration file, and make sure to point CMAKE_C_COMPILER to where emcc is located. (was pointing to \"${CMAKE_C_COMPILER}\")")
+ endif()
+ string(REGEX MATCH "clang version ([0-9\\.]+)" _dummy_unused "${_cmake_compiler_output}")
+ if (NOT CMAKE_MATCH_1)
+ message(FATAL_ERROR "Failed to regex parse Clang compiler version from version string: ${_cmake_compiler_output}")
+ endif()
+
+ set(CMAKE_C_COMPILER_VERSION "${CMAKE_MATCH_1}")
+ set(CMAKE_CXX_COMPILER_VERSION "${CMAKE_MATCH_1}")
+ if (${CMAKE_C_COMPILER_VERSION} VERSION_LESS 3.9.0)
+ message(WARNING "CMAKE_C_COMPILER version looks too old. Was ${CMAKE_C_COMPILER_VERSION}, should be at least 3.9.0.")
+ endif()
+ endif()
+
+ # Capture the Emscripten version to EMSCRIPTEN_VERSION variable.
+ if (NOT EMSCRIPTEN_VERSION)
+ execute_process(COMMAND "${CMAKE_C_COMPILER}" "-v" RESULT_VARIABLE _cmake_compiler_result ERROR_VARIABLE _cmake_compiler_output OUTPUT_QUIET)
+ if (NOT _cmake_compiler_result EQUAL 0)
+ message(FATAL_ERROR "Failed to fetch Emscripten version information with command \"'${CMAKE_C_COMPILER}' -v\"! Process returned with error code ${_cmake_compiler_result}.")
+ endif()
+ string(REGEX MATCH "emcc \\(.*\\) ([0-9\\.]+)" _dummy_unused "${_cmake_compiler_output}")
+ if (NOT CMAKE_MATCH_1)
+ message(FATAL_ERROR "Failed to regex parse Emscripten compiler version from version string: ${_cmake_compiler_output}")
+ endif()
+
+ set(EMSCRIPTEN_VERSION "${CMAKE_MATCH_1}")
+ endif()
+
+ set(CMAKE_C_COMPILER_ID_RUN TRUE)
+ set(CMAKE_C_COMPILER_FORCED TRUE)
+ set(CMAKE_C_COMPILER_WORKS TRUE)
+ set(CMAKE_C_COMPILER_ID Clang)
+ set(CMAKE_C_STANDARD_COMPUTED_DEFAULT 11)
+
+ set(CMAKE_CXX_COMPILER_ID_RUN TRUE)
+ set(CMAKE_CXX_COMPILER_FORCED TRUE)
+ set(CMAKE_CXX_COMPILER_WORKS TRUE)
+ set(CMAKE_CXX_COMPILER_ID Clang)
+ set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT 98)
+
+ set(CMAKE_C_PLATFORM_ID "emscripten")
+ set(CMAKE_CXX_PLATFORM_ID "emscripten")
+
+ if ("${CMAKE_VERSION}" VERSION_LESS "3.8")
+ set(CMAKE_C_COMPILE_FEATURES "c_function_prototypes;c_restrict;c_variadic_macros;c_static_assert")
+ set(CMAKE_C90_COMPILE_FEATURES "c_function_prototypes")
+ set(CMAKE_C99_COMPILE_FEATURES "c_restrict;c_variadic_macros")
+ set(CMAKE_C11_COMPILE_FEATURES "c_static_assert")
+
+ set(CMAKE_CXX_COMPILE_FEATURES "cxx_template_template_parameters;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates")
+ set(CMAKE_CXX98_COMPILE_FEATURES "cxx_template_template_parameters")
+ set(CMAKE_CXX11_COMPILE_FEATURES "cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates")
+ set(CMAKE_CXX14_COMPILE_FEATURES "cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates")
+ else()
+ set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert")
+ set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes")
+ set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros")
+ set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert")
+
+ set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17")
+ set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters")
+ set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates")
+ set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates")
+ endif()
+endif()
+
+# To find programs to execute during CMake run time with find_program(), e.g. 'git' or so, we allow looking
+# into system paths.
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# Since Emscripten is a cross-compiler, we should never look at the system-provided directories like /usr/include and so on.
+# Therefore only CMAKE_FIND_ROOT_PATH should be used as a find directory. See http://www.cmake.org/cmake/help/v3.0/variable/CMAKE_FIND_ROOT_PATH_MODE_INCLUDE.html
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+
+set(CMAKE_SYSTEM_INCLUDE_PATH "${EMSCRIPTEN_ROOT_PATH}/system/include")
+
+# We would prefer to specify a standard set of Clang+Emscripten-friendly common convention for suffix files, especially for CMake executable files,
+# but if these are adjusted, ${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake will fail, since it depends on being able to compile output files with predefined names.
+#SET(CMAKE_LINK_LIBRARY_SUFFIX "")
+#SET(CMAKE_STATIC_LIBRARY_PREFIX "")
+#SET(CMAKE_SHARED_LIBRARY_PREFIX "")
+#SET(CMAKE_FIND_LIBRARY_PREFIXES "")
+#SET(CMAKE_FIND_LIBRARY_SUFFIXES ".bc")
+#SET(CMAKE_SHARED_LIBRARY_SUFFIX ".bc")
+
+option(EMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES "If set ( default for Cinder ), static library targets generate LLVM bitcode files (.bc). If disabled, UNIX ar archives (.a) are generated." ON)
+if (EMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES)
+ SET(CMAKE_STATIC_LIBRARY_SUFFIX ".bc")
+
+ SET(CMAKE_C_CREATE_STATIC_LIBRARY " -o ")
+ SET(CMAKE_CXX_CREATE_STATIC_LIBRARY " -o ")
+else()
+ # Specify the program to use when building static libraries. Force Emscripten-related command line options to clang.
+ SET(CMAKE_C_CREATE_STATIC_LIBRARY " rc ")
+ SET(CMAKE_CXX_CREATE_STATIC_LIBRARY " rc ")
+endif()
+
+SET(CMAKE_EXECUTABLE_SUFFIX ".js")
+
+SET(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+SET(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+
+set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@")
+set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@")
+
+# Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten.
+set(EMSCRIPTEN 1 CACHE BOOL "If true, we are targeting Emscripten output.")
+
+# Hardwire support for cmake-2.8/Modules/CMakeBackwardsCompatibilityC.cmake without having CMake to try complex things
+# to autodetect these:
+set(CMAKE_SKIP_COMPATIBILITY_TESTS 1)
+set(CMAKE_SIZEOF_CHAR 1)
+set(CMAKE_SIZEOF_UNSIGNED_SHORT 2)
+set(CMAKE_SIZEOF_SHORT 2)
+set(CMAKE_SIZEOF_INT 4)
+set(CMAKE_SIZEOF_UNSIGNED_LONG 4)
+set(CMAKE_SIZEOF_UNSIGNED_INT 4)
+set(CMAKE_SIZEOF_LONG 4)
+set(CMAKE_SIZEOF_VOID_P 4)
+set(CMAKE_SIZEOF_FLOAT 4)
+set(CMAKE_SIZEOF_DOUBLE 8)
+set(CMAKE_C_SIZEOF_DATA_PTR 4)
+set(CMAKE_CXX_SIZEOF_DATA_PTR 4)
+set(CMAKE_HAVE_LIMITS_H 1)
+set(CMAKE_HAVE_UNISTD_H 1)
+set(CMAKE_HAVE_PTHREAD_H 1)
+set(CMAKE_HAVE_SYS_PRCTL_H 1)
+set(CMAKE_WORDS_BIGENDIAN 0)
+set(CMAKE_DL_LIBS)
+
+set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE")
+set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO")
+set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELEASE")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -Os" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_MINSIZEREL")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELWITHDEBINFO")
+
+set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELEASE")
+set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Os" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_MINSIZEREL")
+set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO")
+set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELEASE")
+set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "-Os" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL")
+set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO")
+set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELEASE")
+set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "-Os" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL")
+set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO")
+
+function(em_validate_asmjs_after_build target)
+ add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo Validating build output for asm.js... COMMAND "python" ARGS "${EMSCRIPTEN_ROOT_PATH}/tools/validate_asmjs.py" "$")
+endfunction()
+
+# A global counter to guarantee unique names for js library files.
+set(link_js_counter 1)
+
+# Internal function: Do not call from user CMakeLists.txt files. Use one of em_link_js_library()/em_link_pre_js()/em_link_post_js() instead.
+function(em_add_tracked_link_flag target flagname)
+
+ # User can input list of JS files either as a single list, or as variable arguments to this function, so iterate over varargs, and treat each
+ # item in varargs as a list itself, to support both syntax forms.
+ foreach(jsFileList ${ARGN})
+ foreach(jsfile ${jsFileList})
+ # If the user edits the JS file, we want to relink the emscripten application, but unfortunately it is not possible to make a link step
+ # depend directly on a source file. Instead, we must make a dummy no-op build target on that source file, and make the project depend on
+ # that target.
+
+ # Sanitate the source .js filename to a good symbol name to use as a dummy filename.
+ get_filename_component(jsname "${jsfile}" NAME)
+ string(REGEX REPLACE "[/:\\\\.\ ]" "_" dummy_js_target ${jsname})
+ set(dummy_lib_name ${target}_${link_js_counter}_${dummy_js_target})
+ set(dummy_c_name "${CMAKE_BINARY_DIR}/${dummy_js_target}_tracker.c")
+
+ # Create a new static library target that with a single dummy .c file.
+ add_library(${dummy_lib_name} STATIC ${dummy_c_name})
+ # Make the dummy .c file depend on the .js file we are linking, so that if the .js file is edited, the dummy .c file, and hence the static library will be rebuild (no-op). This causes the main application to be relinked, which is what we want.
+ # This approach was recommended by http://www.cmake.org/pipermail/cmake/2010-May/037206.html
+ add_custom_command(OUTPUT ${dummy_c_name} COMMAND ${CMAKE_COMMAND} -E touch ${dummy_c_name} DEPENDS ${jsfile})
+ target_link_libraries(${target} ${dummy_lib_name})
+
+ # Link the js-library to the target
+ # When a linked library starts with a "-" cmake will just add it to the linker command line as it is.
+ # The advantage of doing it this way is that the js-library will also be automatically linked to targets
+ # that depend on this target.
+ get_filename_component(js_file_absolute_path "${jsfile}" ABSOLUTE )
+ target_link_libraries(${target} "${flagname} \"${js_file_absolute_path}\"")
+
+ math(EXPR link_js_counter "${link_js_counter} + 1")
+ endforeach()
+ endforeach()
+endfunction()
+
+# This function links a (list of ) .js library file(s) to the given CMake project.
+# Example: em_link_js_library(my_executable "lib1.js" "lib2.js")
+# will result in emcc passing --js-library lib1.js --js-library lib2.js to the emscripten linker, as well as
+# tracking the modification timestamp between the linked .js files and the main project, so that editing the .js file
+# will cause the target project to be relinked.
+function(em_link_js_library target)
+ em_add_tracked_link_flag(${target} "--js-library" ${ARGN})
+endfunction()
+
+# This function is identical to em_link_js_library(), except the .js files will be added with '--pre-js file.js' command line flag,
+# which is generally used to add some preamble .js code to a generated output file.
+function(em_link_pre_js target)
+ em_add_tracked_link_flag(${target} "--pre-js" ${ARGN})
+endfunction()
+
+# This function is identical to em_link_js_library(), except the .js files will be added with '--post-js file.js' command line flag,
+# which is generally used to add some postamble .js code to a generated output file.
+function(em_link_post_js target)
+ em_add_tracked_link_flag(${target} "--post-js" ${ARGN})
+endfunction()
+
+# Experimental support for targeting generation of Visual Studio project files (vs-tool) of Emscripten projects for Windows.
+# To use this, pass the combination -G "Visual Studio 10" -DCMAKE_TOOLCHAIN_FILE=Emscripten.cmake
+if ("${CMAKE_GENERATOR}" MATCHES "^Visual Studio.*")
+ # By default, CMake generates VS project files with a true directive.
+ # This causes VS to attempt to invoke rc.exe during the build, which will fail since app manifests are meaningless for Emscripten.
+ # To disable this, add the following linker flag. This flag will not go to emcc, since the Visual Studio CMake generator will swallow it.
+ set(EMSCRIPTEN_VS_LINKER_FLAGS "/MANIFEST:NO")
+ # CMake is hardcoded to write a ClCompile directive $(IntDir) in all VS project files it generates.
+ # This makes VS pass emcc a -o param that points to a directory instead of a file, which causes emcc autogenerate the output filename.
+ # CMake is hardcoded to assume all object files have the suffix .obj, so adjust the emcc-autogenerated default suffix name to match.
+ set(EMSCRIPTEN_VS_LINKER_FLAGS "${EMSCRIPTEN_VS_LINKER_FLAGS} --default-obj-ext .obj")
+ # Also hint CMake that it should not hardcode generation. Requires a custom CMake build for this to work (ignored on others)
+ # See http://www.cmake.org/Bug/view.php?id=14673 and https://github.com/juj/CMake
+ set(CMAKE_VS_NO_DEFAULT_OBJECTFILENAME 1)
+
+ # Apply and cache Emscripten Visual Studio IDE-specific linker flags.
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "")
+endif()
+
+if (NOT DEFINED CMAKE_CROSSCOMPILING_EMULATOR)
+ find_program(NODE_JS_EXECUTABLE NAMES nodejs node)
+ if(NODE_JS_EXECUTABLE)
+ set(CMAKE_CROSSCOMPILING_EMULATOR "${NODE_JS_EXECUTABLE}" CACHE FILEPATH "Path to the emulator for the target system.")
+ endif()
+endif()
+# No-op on CMAKE_CROSSCOMPILING_EMULATOR so older versions of cmake do not
+# complain about unused CMake variable.
+if(CMAKE_CROSSCOMPILING_EMULATOR)
+endif()
diff --git a/proj/cmake/modules/cinderEmscriptenApp.cmake b/proj/cmake/modules/cinderEmscriptenApp.cmake
new file mode 100644
index 0000000000..be33399839
--- /dev/null
+++ b/proj/cmake/modules/cinderEmscriptenApp.cmake
@@ -0,0 +1,292 @@
+# TODO
+# 1. Add CinderBlock support - not sure what the best way is at the moment.
+
+function(ci_emscripten_app)
+ set( oneValueArgs
+
+ # the path to Cinder installation
+ CINDER_PATH
+
+ # path to your assets folder.
+ ASSETS
+
+ MEMORY_DEBUG
+
+ )
+ set( multiValueArgs
+
+ # a path to a custom HTML template
+ # See https://kripken.github.io/emscripten-site/docs/tools_reference/emcc.html#emcc-shell-file for details.
+ HTML_TEMPLATE
+
+ # a list of source files to use in the build. Typically you'll only need to list your main app file.
+ SOURCES
+
+ # a list of header files to include in the build
+ INCLUDES
+
+ # a list of library paths that you would like to include in the build.
+ LIBRARIES
+
+ # any additional non-standard flags you may want to include
+ FLAGS
+
+ # tells emscripten to include use of threads. Note that this requires use of SharedArrayBuffers - check your
+ # browser for how to enable, if it's possible.
+ THREADS
+
+ # Thread pool size - this indicates the number of threads you'd like to pre-allocate.
+ # note that it is apparently better to pre-allocate then dynamically generate.
+ THREAD_POOL_SIZE
+
+ # Thread hint num cores
+ THREAD_NUM_CORES
+
+ # tells emscripten to use browser decoding
+ BROWSER_DECODE
+
+ # if your project is intended to be a web worker, this adds the necessary flags.
+ BUILD_AS_WORKER
+
+ # tells Emscripten what functions you want to expose to your main application within your worker.
+ # the parameter should be a single quoted string with all functions separated by a comma ie
+ # '_onmessage,_postmessage'
+ EXPORT_FROM_WORKER
+
+ # Tells Emscripten to not build with async libraries bundled.
+ # note that this will disable ci::app::loadAsset and you will have to rely on async functions, native emscripten functions or write your own JS.
+ NO_ASYNC
+
+ # Sepecifies the type of build you want to do, either "Debug" or "Release"
+ BUILD_TYPE
+
+ # argument to tell emscripten to bundle resources
+ RESOURCES
+
+ # argument to tell what to name all the files it will output
+ OUTPUT_NAME
+
+ # in case you want to override the default output directory
+ OUTPUT_DIRECTORY
+ )
+
+ cmake_parse_arguments( ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ if( ARG_UNPARSED_ARGUMENTS )
+ message( WARNING "unhandled arguments: ${ARG_UNPARSED_ARGUMENTS}" )
+ endif()
+
+ # https://blog.kitware.com/cmake-and-the-default-build-type/
+ #
+ # Set a default build type if none was specified
+ set( default_build_type "Debug" )
+ if( NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES )
+ message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
+ set( CMAKE_BUILD_TYPE "${default_build_type}" CACHE
+ STRING "Choose the type of build." FORCE )
+ # Set the possible values of build type for cmake-gui
+ set_property( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
+ "Debug" "Release" "MinSizeRel" "RelWithDebInfo" )
+ endif()
+
+ # Set CMAKE_RUNTIME_OUTPUT_DIRECTORY based on build type for single-config generator ( i.e Makefile ) otherwise ( i.e Xcode, VS ) use CMAKE_BINARY_DIR
+ if( "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" STREQUAL "" )
+ if( ( "${CMAKE_GENERATOR}" MATCHES "Visual Studio.+" ) OR ( "Xcode" STREQUAL "${CMAKE_GENERATOR}" ) )
+ set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} )
+ else()
+ # Append the build type to the output dir
+ set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE} )
+ endif()
+ endif()
+
+ if (ARG_OUTPUT_DIRECTORY)
+ set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY} )
+ endif()
+
+ if(ARG_BUILD_AS_WORKER)
+ set(WORKER_MESSAGE "YES")
+ endif()
+
+
+ # Log current settings
+ message("\nCURRENT SETTINGS\n======")
+ message( "APP_NAME: ${ARG_OUTPUT_NAME}" )
+ message( "SOURCES: ${ARG_SOURCES}" )
+ message( "INCLUDES: ${ARG_INCLUDES}" )
+ message( "LIBRARIES: ${ARG_LIBRARIES}" )
+ message( "CINDER_PATH: ${ARG_CINDER_PATH}" )
+ message( "CMAKE_RUNTIME_OUTPUT_DIRECTORY: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" )
+ message( "CINDER_BUILD_TYPE: ${CMAKE_BUILD_TYPE}" )
+ message( "BUILDING AS WEB WORKER: ${WORKER_MESSAGE}" )
+
+ if (ARG_RESOURCES)
+ message( "RESOURCES FOLDER IS SET TO ${ARG_RESOURCES}" )
+ endif ()
+
+ if (ARG_ASSETS)
+ message("Assets folder is set to ${ARG_ASSETS}")
+ endif ()
+ message("\n")
+
+ # ========= SETUP BUILD ============== #
+ get_filename_component( CINDER_PATH "${ARG_CINDER_PATH}" ABSOLUTE PARENT_SCOPE)
+
+ # Include Cinder and Emscripten variables
+ include( "${CINDER_PATH}/proj/cmake/configure.cmake" )
+ include( "${CINDER_PATH}/proj/cmake/platform_emscripten.cmake" )
+
+ # set variable for helper file when handling DOM related stuff. This should be a part of the --pre-js Emscripten flag
+ set( CINDER_JS_HELPERS "--pre-js ${CINDER_PATH}/include/cinder/emscripten/helpers.js" )
+
+ # this is important, if not set you will only get JS files.
+ if(NOT ARG_BUILD_AS_WORKER)
+ set(CMAKE_EXECUTABLE_SUFFIX ".html" PARENT_SCOPE)
+ endif()
+
+ # append core flags
+ set(CXX_FLAGS "${CXX_FLAGS} --bind")
+
+ if(NOT ARG_BUILD_AS_WORKER)
+ set(CXX_FLAGS "${CXX_FLAGS} ${CINDER_JS_HELPERS}")
+ endif()
+
+ # if user wants to build as a worker
+ if (ARG_BUILD_AS_WORKER)
+
+ set(CXX_FLAGS "${CXX_FLAGS} -s BUILD_AS_WORKER=1")
+ endif()
+
+ # trying to set memory growth to be on by default.
+ set(CXX_FLAGS "${CXX_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
+
+ if(ARG_BUILD_AS_WORKER)
+ if(ARG_EXPORT_FROM_WORKER)
+ set(CXX_FLAGS "${CXX_FLAGS} -s EXPORTED_FUNCTIONS=[${ARG_EXPORT_FROM_WORKER}]")
+ else()
+ message(ERROR " In order to use web workers, you need to expose functions from your worker to your main application" )
+ endif()
+ endif()
+
+
+ # New WASM oriented backend(as of 10/2019) for Emscripten requires you to set stack size to something at least greater than 10000
+ # TODO may need to experiement to find a more logical value, currently can't seem to find information regarding what the value is measured in.
+ if(ARG_BUILD_AS_WORKER OR ARG_NO_ASYNC)
+ set( CXX_FLAGS "${CXX_FLAGS} -s ASYNCIFY=0 -s ASYNCIFY_STACK_SIZE=0" )
+ elseif( NOT ARG_NO_ASYNC )
+ set( CXX_FLAGS "${CXX_FLAGS} -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=60000" )
+ endif()
+
+ # if custom html template is wanted, use that, otherwise, use default
+ if(ARG_HTML_TEMPLATE)
+ set(CXX_FLAGS "${CXX_FLAGS} --shell-file ${ARG_HTML_TEMPLATE}")
+ else()
+ set( CXX_FLAGS "${CXX_FLAGS} --shell-file ${CINDER_PATH}/proj/cmake/emscripten/shell.html" )
+ endif()
+
+ # if we need assertations set flags
+ if(ARG_MEMORY_DEBUG)
+ set(CXX_FLAGS "${CXX_FLAGS} -s ASSERTIONS=1 -s SAFE_HEAP=1")
+ endif()
+
+ # if FLAGS parameter is set, append additional flags.
+ if(ARG_FLAGS)
+ set(CXX_FLAGS "${CXX_FLAGS} ${ARG_FLAGS}")
+ endif()
+
+ # if building release add some extra flags to optimize final bundle.
+ # see https://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html for other tips on optimizing code.
+ if( "Release" STREQUAL "${CMAKE_BUILD_TYPE}" )
+ set( CXX_FLAGS "${CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}" )
+ set( CXX_FLAGS "${CXX_FLAGS} ${ADD_OPTIMIZATIONS}" )
+ set( CXX_FLAGS "${CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}" )
+ list( APPEND EMCC_CLOSURE_ARGS "--externs ${CINDER_PATH}/include/cinder/emscripten/externs.js" )
+ endif()
+
+ # =========== ADD OTHER OPTIONAL FLAGS ================ #
+
+ # if we have resources to bundle, build and append flags for that
+ if (ARG_RESOURCES)
+ message(WARNING "Note that some resources(really large media files), while it is possible to bundle, they may not load as expected. It would be better to use native JS based methods to load instead." )
+ set(CXX_FLAGS "${CXX_FLAGS} --preload-file ${ARG_RESOURCES}@")
+ endif ()
+
+
+ # if user wants to use browser for decoding media.
+ if(ARG_BROWSER_DECODE)
+ set(CXX_FLAGS "${CXX_FLAGS} ${USE_BROWSER_FOR_DECODING}")
+ endif()
+
+
+ # if user wants threading support.
+ if(ARG_THREADS)
+ message(STATUS "Note that threads require SharedArrayBuffer object which may/may not be disabled in your browser. \n See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html for more information.")
+ set(CXX_FLAGS "${CXX_FLAGS} ${USE_THREADS}")
+
+ if( NOT ARG_THREAD_POOL_SIZE )
+ set(CXX_FLAGS "${CXX_FLAGS} -s PTHREAD_POOL_SIZE=-1")
+ endif()
+
+ if( NOT ARG_THREAD_NUM_CORES )
+ set(CXX_FLAGS "${CXX_FLAGS} -s PTHREAD_HINT_NUM_CORES=-1")
+ endif()
+ endif()
+
+ message("Current flags for build are : \n ${CXX_FLAGS} \n")
+
+
+ # ========== COMPILE ALL FLAGS TOGETHER ============== #
+
+ # compile all necessary flags
+ set(CMAKE_EXE_LINKER_FLAGS "${CXX_FLAGS} ${CINDER_EMSCRIPTEN_LINK_FLAGS}" PARENT_SCOPE)
+
+ # This ensures that the application will link with the correct version of Cinder
+ # based on the current build type without the need to remove the entire build folder
+ # when switching build type after an initial configuration. See PR #1518 for more info.
+ if( cinder_DIR )
+ unset( cinder_DIR CACHE )
+ endif()
+
+ # ========= COMPILE ALL BUILD PARAMETERS TOGETHER ============= #
+ if( NOT TARGET cinder )
+ find_package( cinder REQUIRED PATHS
+ "${CINDER_PATH}/${CINDER_LIB_DIRECTORY}"
+ "$ENV{CINDER_PATH}/${CINDER_LIB_DIRECTORY}"
+ NO_CMAKE_FIND_ROOT_PATH
+ )
+ endif()
+
+ if(ARG_OUTPUT_NAME)
+ set(OUTPUT_NAME "${ARG_OUTPUT_NAME}")
+ else()
+ set(OUTPUT_NAME "index")
+ endif()
+
+ add_executable(${OUTPUT_NAME} ${ARG_SOURCES} )
+
+ target_include_directories(
+ ${OUTPUT_NAME}
+ # TODO check to if PUBLIC specifier works if multiple files are specified, otherwise we'll need to manually do this.
+ PUBLIC ${ARG_INCLUDES}
+ )
+
+ # if a specific output directory is specified make sure to tell cmake
+ if(ARG_OUTPUT_DIRECTORY)
+ set_target_properties(${OUTPUT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY})
+ endif()
+
+
+ target_link_libraries(
+ ${OUTPUT_NAME}
+ #${EMSCRIPTEN_LIB_DIRECTORY}/libboost_filesystem.bc
+ #${EMSCRIPTEN_LIB_DIRECTORY}/libboost_system.bc
+ cinder
+ ${ARG_LIBRARIES}
+ )
+
+ # copy assets to build folder.
+ if( ARG_ASSETS )
+ file( INSTALL ${ARG_ASSETS} DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" )
+ endif()
+
+
+endfunction()
diff --git a/proj/cmake/platform_emscripten.cmake b/proj/cmake/platform_emscripten.cmake
new file mode 100644
index 0000000000..ac295aa827
--- /dev/null
+++ b/proj/cmake/platform_emscripten.cmake
@@ -0,0 +1,58 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+
+set( CINDER_PLATFORM "Emscripten" )
+
+set(CINDER_SRC_DIR ../src)
+
+list( APPEND SRC_SET_CINDER_APP_EMSCRIPTEN
+ ${CINDER_SRC_DIR}/cinder/app/emscripten/AppEmscripten.cpp
+ ${CINDER_SRC_DIR}/cinder/app/emscripten/AppImplEmscripten.cpp
+ ${CINDER_SRC_DIR}/cinder/app/emscripten/PlatformEmscripten.cpp
+
+)
+
+list( APPEND SRC_SET_CINDER_EMSCRIPTEN
+ ${CINDER_SRC_DIR}/cinder/app/emscripten/RendererImplGlEmscripten.cpp
+ ${CINDER_SRC_DIR}/cinder/app/emscripten/WindowImplEmscripten.cpp
+ ${CINDER_SRC_DIR}/cinder/emscripten/EmscriptenVideo.cpp
+ ${CINDER_SRC_DIR}/cinder/emscripten/AudioPlayer.cpp
+)
+
+
+list( APPEND CINDER_SRC_FILES
+ ${SRC_SET_CINDER_APP_EMSCRIPTEN}
+ ${SRC_SET_CINDER_EMSCRIPTEN}
+)
+
+set( CINDER_EMSCRIPTEN_LINK_FLAGS "-s ERROR_ON_UNDEFINED_SYMBOLS=0 -s USE_WEBGL2=1 -s FULL_ES3=1 -s USE_GLFW=3 -s DISABLE_EXCEPTION_CATCHING=0 -s DEMANGLE_SUPPORT=1" )
+list( APPEND CINDER_CXX_FLAGS -stdlib=c++ )
+list( APPEND CINDER_DEFINES "-DGLFW_INCLUDE_ES3;-DCINDER_EMSCRIPTEN;-DCINDER_GL_ES_3;-DCINDER_GL_ES" )
+
+set( EMSCRIPTEN_LIB_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../../lib/emscripten/" )
+
+################### HELPER VARIABLES ##################################
+set(ALLOW_MEMORY_GROWTH "-s ALLOW_MEMORY_GROWTH=1" )
+
+# add to your project flags to build your file as a WebWorker.
+# note that you apparently need the --bind flag when building workers
+# set( BUILD_AS_WORKER "-s BUILD_AS_WORKER=1" )
+
+# the flag to set when you want to include an assets folder and it's contents.
+# this assumes that your assets directory is one directory behind. Note that
+# this may not work for samples
+set( INCLUDE_RESOURCES_FOLDER "--preload-file ../resources@" )
+
+# simple function to allow you to re-set the resources path - just pass in a new path relative to your build directory
+function(SET_RESOURCES_PATH path )
+set( INCLUDE_RESOURCES_FOLDER "--preload-file ${path}@" PARENT_SCOPE )
+endfunction()
+
+# this flag tells Emscripten to use the browser to decode media assets whenever possible, when used
+# in conjunction with a related API function.
+set( USE_BROWSER_FOR_DECODING "--use-preload-plugins" )
+
+# adds optimizations to the final output
+set( ADD_OPTIMIZATIONS "-s WASM=1 -Os -g0" )
+
+# enables use of pthreads
+set( USE_THREADS "-s USE_PTHREADS=1" )
diff --git a/samples/BasicApp/CMakeLists.txt b/samples/BasicApp/CMakeLists.txt
new file mode 100644
index 0000000000..3fa4867075
--- /dev/null
+++ b/samples/BasicApp/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE ON )
+
+project( BasicApp )
+
+get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../" ABSOLUTE )
+get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE )
+message(${APP_PATH})
+include( "${CINDER_PATH}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+
+ci_emscripten_app(
+ SOURCES src/BasicApp.cpp
+ CINDER_PATH ${CINDER_PATH}
+ FLAGS "-s ASSERTIONS=1 -s SAFE_HEAP=1 -s DISABLE_EXCEPTION_CATCHING=0"
+)
+
diff --git a/samples/_emscripten/AssetLoading/assets/loadAsync.jpg b/samples/_emscripten/AssetLoading/assets/loadAsync.jpg
new file mode 100644
index 0000000000..a0f2198273
Binary files /dev/null and b/samples/_emscripten/AssetLoading/assets/loadAsync.jpg differ
diff --git a/samples/_emscripten/AssetLoading/assets/loadSync.jpg b/samples/_emscripten/AssetLoading/assets/loadSync.jpg
new file mode 100644
index 0000000000..cb2f4fda5c
Binary files /dev/null and b/samples/_emscripten/AssetLoading/assets/loadSync.jpg differ
diff --git a/samples/_emscripten/AssetLoading/assets/sintel.ogv b/samples/_emscripten/AssetLoading/assets/sintel.ogv
new file mode 100644
index 0000000000..5924dbad4c
Binary files /dev/null and b/samples/_emscripten/AssetLoading/assets/sintel.ogv differ
diff --git a/samples/_emscripten/AssetLoading/emscripten/CMakeLists.txt b/samples/_emscripten/AssetLoading/emscripten/CMakeLists.txt
new file mode 100644
index 0000000000..d41ce27874
--- /dev/null
+++ b/samples/_emscripten/AssetLoading/emscripten/CMakeLists.txt
@@ -0,0 +1,17 @@
+# AssetLoading example
+cmake_minimum_required( VERSION 3.1 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE on )
+
+get_filename_component( CINDER_DIR "${CMAKE_CURRENT_SOURCE_DIR}../../../../../" ABSOLUTE )
+
+include( "${CINDER_DIR}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+set( SRC_FILES
+ ../src/AssetLoading.cpp
+)
+
+ci_emscripten_app(
+ SOURCES ${SRC_FILES}
+ CINDER_PATH ${CINDER_DIR}
+ ASSETS ../assets
+)
\ No newline at end of file
diff --git a/samples/_emscripten/AssetLoading/include/Resources.h b/samples/_emscripten/AssetLoading/include/Resources.h
new file mode 100644
index 0000000000..3164745b1c
--- /dev/null
+++ b/samples/_emscripten/AssetLoading/include/Resources.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "cinder/CinderResources.h"
+
+//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE )
+
+
+
+
+
+
+
+
diff --git a/samples/_emscripten/AssetLoading/src/AssetLoading.cpp b/samples/_emscripten/AssetLoading/src/AssetLoading.cpp
new file mode 100644
index 0000000000..c26f274e86
--- /dev/null
+++ b/samples/_emscripten/AssetLoading/src/AssetLoading.cpp
@@ -0,0 +1,111 @@
+#include "cinder/app/App.h"
+#include "cinder/app/RendererGl.h"
+#include "cinder/gl/gl.h"
+#include "cinder/emscripten/CinderEmscripten.h"
+#include "cinder/Log.h"
+#include "cinder/gl/GlslProg.h"
+#include "cinder/gl/Texture.h"
+#include "cinder/ImageIo.h"
+#include "cinder/emscripten/EmscriptenVideo.h"
+
+using namespace ci;
+using namespace ci::app;
+using namespace ci::em;
+using namespace emscripten;
+
+
+/**
+ * This is just a simple test of loading images and a video while demonstrating
+ * examples of how loading assets would work.
+ *
+ * If you're loading from the resources folder, those items will get packaged into a binary file and things should work like normal.
+ *
+ * The difference being that, loading resources will be much faster as that will be ready and all loaded when
+ * your project starts.
+ *
+ * The downside is that bundling your assets with your build WASM file can result in a much larger bundle size resulting in a longer time to screeen.
+ *
+ * When loading assets, unfortunately, that will require an http request which can slow things down a bit depending
+ * on the size and where you're loading from.
+ *
+ * To make for an even greater headache - testing seems to indicate that bundling larger files into resources
+ * will not quite work(in addition to greatly increasing your project's load time.) though this
+ * may have changed in newer versions.
+ *
+ * It's recommended to just use an assets folder and use the various loadAsset methods, especially the async one.
+ *
+ */
+class AssetLoadTest : public App
+{
+ gl::TextureRef mAsyncTest,mSyncTest;
+ EmscriptenVideoRef mVideo;
+
+ public:
+ void draw() override;
+ void setup() override;
+};
+
+void prepareSettings( AssetLoadTest::Settings* settings )
+{
+ settings->setWindowSize (1024,768 );
+}
+
+void AssetLoadTest::setup()
+{
+ // this is an example of syncronous loading - should work exactly like normal but may block other things while
+ // it's loading.
+ mSyncTest = gl::Texture::create( loadImage( loadAsset( "loadSync.jpg" ) ) );
+
+ // example of loading assets asyncronously. Pass in a lambda that will receive a DataSourceRef
+ app::loadAssetAsync( "loadAsync.jpg",[=]( ci::DataSourceRef ref )->void {
+ mAsyncTest = gl::Texture::create( loadImage( ref ) );
+ });
+
+ // example of loading something a bit larger like a video. Should work normally. This happens to be
+ // async as well technically because it's using Javascript under the hood to load the video.
+ mVideo = EmscriptenVideo::create( loadAsset( "sintel.ogv" ) );
+
+}
+
+
+void AssetLoadTest::draw()
+{
+ // Clear the contents of the window. This call will clear
+ // both the color and depth buffers.
+ gl::clear( Color::gray( 0.1f ) );
+
+ if( mAsyncTest )
+ {
+ gl::draw( mAsyncTest,Rectf( 0,0,341,app::getWindowHeight() ) );
+ }
+
+ if( mVideo->hasVideoLoaded() )
+ {
+ if( mVideo->isPlaying() )
+ {
+ mVideo->updateTexture();
+ }
+ else {
+ mVideo->play();
+ }
+
+ gl::pushMatrices();
+ gl::translate( vec2( 341,0) );
+ gl::draw( mVideo->getTexture(),Rectf( 0,0,341,app::getWindowHeight() ) );
+ gl::popMatrices();
+ }
+
+ if( mSyncTest )
+ {
+ gl::pushMatrices();
+ gl::translate( vec2(341 * 2,0) );
+ gl::draw( mSyncTest,Rectf( 0,0,341,app::getWindowHeight() ) );
+ gl::popMatrices();
+ }
+}
+
+// This line tells Cinder to actually create and run the application.
+CINDER_APP( AssetLoadTest, RendererGl, prepareSettings )
+
+
+
diff --git a/samples/_emscripten/HTML/emscripten/CMakeLists.txt b/samples/_emscripten/HTML/emscripten/CMakeLists.txt
new file mode 100644
index 0000000000..9ae9a4b05a
--- /dev/null
+++ b/samples/_emscripten/HTML/emscripten/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE ON )
+
+project( HTMLApp )
+
+get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../" ABSOLUTE )
+get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../" ABSOLUTE )
+
+include( "${CINDER_PATH}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+
+ci_emscripten_app(
+ SOURCES ${APP_PATH}/src/HTMLApp.cpp
+ CINDER_PATH ${CINDER_PATH}
+)
diff --git a/samples/_emscripten/HTML/include/Resources.h b/samples/_emscripten/HTML/include/Resources.h
new file mode 100644
index 0000000000..3164745b1c
--- /dev/null
+++ b/samples/_emscripten/HTML/include/Resources.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "cinder/CinderResources.h"
+
+//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE )
+
+
+
+
+
+
+
+
diff --git a/samples/_emscripten/HTML/src/HTMLApp.cpp b/samples/_emscripten/HTML/src/HTMLApp.cpp
new file mode 100644
index 0000000000..847855c7a1
--- /dev/null
+++ b/samples/_emscripten/HTML/src/HTMLApp.cpp
@@ -0,0 +1,59 @@
+#include "cinder/app/App.h"
+#include "cinder/app/RendererGl.h"
+#include "cinder/gl/gl.h"
+#include
+#include "cinder/emscripten/HTML.h"
+#include "cinder/emscripten/AudioPlayer.h"
+
+using namespace ci;
+using namespace ci::app;
+using namespace em;
+using namespace em::html;
+using namespace emscripten;
+
+
+class HTMLApp : public App
+{
+
+ public:
+ void draw() override;
+ void setup() override;
+ void onLoad();
+
+ HTMLElement img;
+ AudioPlayerRef player;
+};
+
+void prepareSettings( HTMLApp::Settings* settings )
+{
+ settings->setMultiTouchEnabled( false );
+}
+
+void HTMLApp::setup()
+{
+
+ CI_LOG_I( "This example tests the HTMLElement and AudioPlayer classes." );
+ CI_LOG_I( "The AudioPlayer class adds a bit of audio using the tag. Scroll to the bottome to see the controls." );
+ CI_LOG_I( "The HTMLElement class makes it easy to add HTML to your project if needed." );
+ CI_LOG_I( "For the audio, controls can be turned off but the browser will need user interaction before the audio plays if you don't use the controls." );
+
+ img = HTMLElement( "img" );
+ img.setAttribute( "src", "https://www.html5rocks.com/static/images/html5rocks-logo-wings.png" );
+
+ img.appendToEl( ".emscripten_border" );
+ img.setAttribute( "style", "left: 50%;position: relative;transform: translateX(-50%);" );
+
+
+ auto el = emscripten::val::global( "document" );
+ player = AudioPlayer::create( "https://ia802900.us.archive.org/16/items/mythium/PVD_TSOWA.mp3", true );
+
+ player->play();
+
+}
+
+void HTMLApp::draw()
+{
+ gl::clear( Color( 0,0,0 ));
+}
+
+CINDER_APP( HTMLApp, RendererGl, prepareSettings )
diff --git a/samples/_emscripten/JSObject/emscripten/CMakeLists.txt b/samples/_emscripten/JSObject/emscripten/CMakeLists.txt
new file mode 100644
index 0000000000..32e39e309e
--- /dev/null
+++ b/samples/_emscripten/JSObject/emscripten/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE ON )
+
+project( JSObjectApp )
+
+get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../" ABSOLUTE )
+get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../" ABSOLUTE )
+
+include( "${CINDER_PATH}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+
+ci_emscripten_app(
+ SOURCES ${APP_PATH}/src/JSObjectApp.cpp
+ CINDER_PATH ${CINDER_PATH}
+)
diff --git a/samples/_emscripten/JSObject/include/Resources.h b/samples/_emscripten/JSObject/include/Resources.h
new file mode 100644
index 0000000000..3164745b1c
--- /dev/null
+++ b/samples/_emscripten/JSObject/include/Resources.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "cinder/CinderResources.h"
+
+//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE )
+
+
+
+
+
+
+
+
diff --git a/samples/_emscripten/JSObject/src/JSObjectApp.cpp b/samples/_emscripten/JSObject/src/JSObjectApp.cpp
new file mode 100644
index 0000000000..33ccdf8316
--- /dev/null
+++ b/samples/_emscripten/JSObject/src/JSObjectApp.cpp
@@ -0,0 +1,64 @@
+#include "cinder/app/App.h"
+#include "cinder/app/RendererGl.h"
+#include "cinder/gl/gl.h"
+#include
+#include "cinder/Log.h"
+#include "cinder/emscripten/JSObject.h"
+
+#define STRINGIFY(A) #A
+
+using namespace ci;
+using namespace ci::app;
+using namespace em;
+using namespace emscripten;
+
+/**
+ * This sample demonstrates how to work with the JSObject class, essentially
+ * a wrapper to help try and make it easier to work with DOM objects.
+ * It uses emscripten::val behind the scenes.
+ */
+class JSObjectApp : public App
+{
+
+ public:
+ void draw() override;
+ void setup() override;
+ void onLoad();
+
+ JSObjRef obj;
+ int x,y;
+
+};
+
+void prepareSettings( JSObjectApp::Settings* settings )
+{
+ settings->setMultiTouchEnabled( false );
+}
+
+void JSObjectApp::setup()
+{
+
+ obj = JSObject::create();
+ obj->set("xPos",app::getWindowWidth() / 2);
+ obj->set("yPos",app::getWindowHeight() / 2);
+
+ // right-click and click on inspect to bring up dev-tools (should be a menu item as well.)
+ // you'll see a breakdown of the object in the Console tab.
+ obj->log();
+
+ x = obj->getIntValue("xPos");
+ y = obj->getIntValue("yPos");
+ CI_LOG_I(x);
+}
+
+void JSObjectApp::draw()
+{
+ gl::clear( Color( 0,0,0 ));
+
+ gl::setMatricesWindow(app::getWindowSize());
+ gl::viewport(app::getWindowSize());
+
+ gl::drawSolidCircle(vec2(x,y),10);
+}
+
+CINDER_APP( JSObjectApp, RendererGl, prepareSettings )
diff --git a/samples/_emscripten/WebWorker/cworker/emscripten/CMakeLists.txt b/samples/_emscripten/WebWorker/cworker/emscripten/CMakeLists.txt
new file mode 100644
index 0000000000..56cde2e1a8
--- /dev/null
+++ b/samples/_emscripten/WebWorker/cworker/emscripten/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE ON )
+
+project( CppWebWorker )
+
+get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../" ABSOLUTE )
+get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../" ABSOLUTE )
+
+include( "${CINDER_PATH}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+ci_emscripten_app(
+ SOURCES ${APP_PATH}/src/worker.cpp
+ CINDER_PATH ${CINDER_PATH}
+ EXPORT_FROM_WORKER '_onmessage'
+ BUILD_AS_WORKER TRUE
+ OUTPUT_NAME worker
+ OUTPUT_DIRECTORY ../../../emscripten/build/Debug
+)
diff --git a/samples/_emscripten/WebWorker/cworker/readme.md b/samples/_emscripten/WebWorker/cworker/readme.md
new file mode 100644
index 0000000000..a62c503568
--- /dev/null
+++ b/samples/_emscripten/WebWorker/cworker/readme.md
@@ -0,0 +1,6 @@
+Web Worker example
+===
+
+This is a sub-project of how to build a web worker with c++.
+The process is the same as any other cmake project, when built, the
+output will be sent to the build directory of the main project.
diff --git a/samples/_emscripten/WebWorker/cworker/src/worker.cpp b/samples/_emscripten/WebWorker/cworker/src/worker.cpp
new file mode 100644
index 0000000000..95824e59ba
--- /dev/null
+++ b/samples/_emscripten/WebWorker/cworker/src/worker.cpp
@@ -0,0 +1,41 @@
+#include
+#include
+#include
+#include
+#include "cinder/Log.h"
+#include "cinder/Vector.h"
+#include "cinder/Rand.h"
+
+
+
+/**
+ * A very simple worker. It's only goal is to update the vec3 we pass in
+ * and shift the values along a sphere.
+ */
+
+
+extern "C" {
+
+ float theta = 0.0f;
+ float phi = 0.0f;
+ float thetaSpeed = ci::randFloat( -0.01,0.01 );
+ float phiSpeed = ci::randFloat( -0.01,0.01 );
+ float radius = 50.0f;
+
+ void onmessage( char* data, int size)
+ {
+
+ ci::vec3 * pt = ( ci::vec3* )data;
+ ci::vec3 v = *pt;
+
+ v.x = cos( theta ) * sin( phi ) * radius;
+ v.y = sin( theta ) * sin( phi ) * radius;
+ v.z = cos( phi ) * radius;
+
+ theta += thetaSpeed;
+ phi += phiSpeed;
+
+ // send back to callback passing the data through.
+ emscripten_worker_respond( ( char* )glm::value_ptr( v ),size );
+ }
+}
diff --git a/samples/_emscripten/WebWorker/emscripten/CMakeLists.txt b/samples/_emscripten/WebWorker/emscripten/CMakeLists.txt
new file mode 100644
index 0000000000..86c1b5da2c
--- /dev/null
+++ b/samples/_emscripten/WebWorker/emscripten/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE ON )
+
+project( WebWorkerApp )
+
+get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../" ABSOLUTE )
+get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../" ABSOLUTE )
+message(${APP_PATH})
+include( "${CINDER_PATH}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+ci_emscripten_app(
+ SOURCES ${APP_PATH}/src/WebWorkerApp.cpp
+ CINDER_PATH ${CINDER_PATH}
+ INCLUDES ../include
+)
diff --git a/samples/_emscripten/WebWorker/include/Resources.h b/samples/_emscripten/WebWorker/include/Resources.h
new file mode 100644
index 0000000000..3164745b1c
--- /dev/null
+++ b/samples/_emscripten/WebWorker/include/Resources.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "cinder/CinderResources.h"
+
+//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE )
+
+
+
+
+
+
+
+
diff --git a/samples/_emscripten/WebWorker/include/cube.h b/samples/_emscripten/WebWorker/include/cube.h
new file mode 100644
index 0000000000..7438571ab7
--- /dev/null
+++ b/samples/_emscripten/WebWorker/include/cube.h
@@ -0,0 +1,54 @@
+
+#pragma once
+
+class Cube {
+public:
+
+ constexpr static float vertices[72] = {
+
+ // Front face
+ -1.0, -1.0, 1.0,
+ 1.0, -1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ -1.0, 1.0, 1.0,
+
+ // Back face
+ -1.0, -1.0, -1.0,
+ -1.0, 1.0, -1.0,
+ 1.0, 1.0, -1.0,
+ 1.0, -1.0, -1.0,
+
+ // Top face
+ -1.0, 1.0, -1.0,
+ -1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ 1.0, 1.0, -1.0,
+
+ // Bottom face
+ -1.0, -1.0, -1.0,
+ 1.0, -1.0, -1.0,
+ 1.0, -1.0, 1.0,
+ -1.0, -1.0, 1.0,
+
+ // Right face
+ 1.0, -1.0, -1.0,
+ 1.0, 1.0, -1.0,
+ 1.0, 1.0, 1.0,
+ 1.0, -1.0, 1.0,
+
+ // Left face
+ -1.0, -1.0, -1.0,
+ -1.0, -1.0, 1.0,
+ -1.0, 1.0, 1.0,
+ -1.0, 1.0, -1.0,
+
+ };
+ constexpr static unsigned int indices[36] = {
+ 0, 1, 2, 0, 2, 3, // Front face
+ 4, 5, 6, 4, 6, 7, // Back face
+ 8, 9, 10, 8, 10, 11, // Top face
+ 12, 13, 14, 12, 14, 15, // Bottom face
+ 16, 17, 18, 16, 18, 19, // Right face
+ 20, 21, 22, 20, 22, 23 // Left face
+ };
+};
diff --git a/samples/_emscripten/WebWorker/src/WebWorkerApp.cpp b/samples/_emscripten/WebWorker/src/WebWorkerApp.cpp
new file mode 100644
index 0000000000..5656d91484
--- /dev/null
+++ b/samples/_emscripten/WebWorker/src/WebWorkerApp.cpp
@@ -0,0 +1,97 @@
+#include "cinder/emscripten/Worker.h"
+#include "cinder/app/App.h"
+#include "cinder/app/RendererGl.h"
+#include "cinder/gl/gl.h"
+#include "cinder/Log.h"
+#include "cinder/Camera.h"
+#include "cinder/CameraUi.h"
+#include "cinder/gl/VboMesh.h"
+#include "cinder/gl/Batch.h"
+#include "cinder/gl/GlslProg.h"
+#include "cube.h"
+
+using namespace ci;
+using namespace ci::app;
+using namespace ci::em;
+using namespace std;
+
+
+/**
+ A perhaps inefficent but nevertheless hopefully simple
+ demonstration of how WebWorkers could be utilized.
+
+ A Cube's position is updated along a sphere with the new
+ position being calculated inside of a Web Worker.
+
+ Note that this makes use of C++ based workers though you could theoretically
+ write your own in Javascript as well via the embind api.
+*/
+
+
+vec3 cubePosition;
+
+class WorkerApp : public App
+{
+
+ public:
+ vector positions;
+ vector indices;
+ void draw() override;
+ void setup() override;
+ void onLoad();
+ CameraPersp mCam;
+ CameraUi mCamUi;
+ ci::gl::BatchRef mBatch;
+ ci::gl::GlslProgRef mShader;
+ ci::gl::VboMeshRef mMesh;
+ Worker worker;
+};
+
+void prepareSettings( WorkerApp::Settings* settings )
+{
+ settings->setMultiTouchEnabled( false );
+}
+
+void workerCallback( char*data,int size,void* args )
+{
+ ci::vec3 * vec = ( ci::vec3* )data;
+ auto pt = *vec;
+ cubePosition = *vec;
+}
+
+void WorkerApp::setup()
+{
+ float fov = 45 * ( 3.14149 / 10 );
+ float aspect = ci::app::getWindowAspectRatio();
+ float near = 0.1;
+ float far = 40000.0;
+ ci::vec3 eye = ci::vec3( 0, 0, 500 );
+ ci::vec3 target = ci::vec3( 0, 0, 0 );
+
+ mCam = CameraPersp( getWindowWidth(), getWindowHeight(), fov, near, far );
+ mCam.lookAt( eye, target );
+ mCamUi = CameraUi( &mCam );
+
+ mMesh = gl::VboMesh::create( geom::Cube().size( vec3( 10 ) ) );
+
+ mShader = gl::getStockShader( gl::ShaderDef().color() );
+ mBatch = gl::Batch::create( mMesh,mShader );
+
+ worker.loadWorker("worker.js");
+ worker.setOnMessageCallback(workerCallback);
+ worker.postMessage( "onmessage",( char* )glm::value_ptr( cubePosition ),sizeof( vec3 ) );
+}
+
+void WorkerApp::draw()
+{
+ gl::clear( Color( 0,0,0 ) );
+ gl::setMatrices( mCam );
+ worker.postMessage( "onmessage",( char* )glm::value_ptr( cubePosition ),sizeof( vec3 ) );
+
+ gl::translate( cubePosition );
+ mBatch->draw();
+}
+
+
+// This line tells Cinder to actually create and run the application.
+CINDER_APP( WorkerApp, RendererGl, prepareSettings )
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/AudioContext.cpp b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioContext.cpp
new file mode 100644
index 0000000000..38890483d9
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioContext.cpp
@@ -0,0 +1,60 @@
+#include "AudioContext.h"
+
+using namespace ci;
+using namespace std;
+
+namespace cinder { namespace audio {
+
+ void AudioContext::enable( AudioNodeRef node = nullptr ){
+ // just go through and push into js graph
+ emscripten::val helpers = ci::em::helpers::getWorkletHelpers();
+ emscripten::val graph = helpers["graph"];
+
+ // if the graph has no items, we start by injecting the output
+ if( graph[ "length" ].as() == 0 )
+ {
+
+ graph.call( "push",emscripten::val::global("window")["CINDER_AUDIO"]["globalContext"]["destination"] );
+
+ // push the connected node and recurse the function until we have no nodes left that have connections.
+ enable( this->mConnectedTo );
+ }
+ else {
+ // there are only 2 possible derivations from the base class of AudioNode - if NativeNode cast fails,
+ // then it must be an instance of a CustomNode
+ NativeNode * n = dynamic_cast(node.get());
+ if( n != nullptr )
+ {
+ // push the native node onto the stack
+ graph.call( "push",n->getNode() );
+ n->setEnabled();
+
+ if( !n->getConnectedNode()->isEnabled() )
+ {
+ // push the connected node and recurse the function until we have no nodes left that have connections.
+ enable(n->getConnectedNode());
+ }
+ }
+ else {
+ CustomNode * n = dynamic_cast( node.get() );
+ graph.call( "push",n->getProcessFunction() );
+ n->setEnabled();
+
+ if( n->getConnectedNode() != nullptr )
+ {
+
+ if(!n->getConnectedNode()->isEnabled()){
+ // push the connected node and recurse the function until we have no nodes left that have connections.
+ enable(n->getConnectedNode());
+ }
+
+ }
+ }
+
+ if( !mProcessorLoaded ){
+ load_processor(processor.c_str());
+ mProcessorLoaded = true;
+ }
+ }
+ }
+}}
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/AudioContext.h b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioContext.h
new file mode 100644
index 0000000000..86354014f2
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioContext.h
@@ -0,0 +1,135 @@
+
+#include
+#include "AudioJSFunctions.h"
+#include "AudioNode.h"
+#include "cinder/emscripten/CinderEmscripten.h"
+#include "NativeNode.h"
+#include "CustomNode.h"
+#define STRINGIFY(A) #A
+#define quote(x) #x
+
+namespace cinder {
+
+ typedef std::shared_ptrAudioContextRef;
+
+
+ /**
+ * A class representing an audio worklet.
+ * Analagous to an audio context in this case
+ */
+ class AudioContext : public AudioNode
+ {
+ public:
+
+ static AudioContextRef Instance()
+ {
+ static AudioContextRef instance( new AudioContext );
+ return instance;
+ }
+
+ template
+ std::shared_ptr makeNode( T *node )
+ {
+ static_assert( std::is_base_of::value, "AudioNode must inherit from audio::Node" );
+
+ std::shared_ptr result( node );
+ return result;
+ }
+
+ //! builds and chains the graph together according to
+ //! the order in which nodes were added.
+ void enable( AudioNodeRef node=nullptr )
+ {
+ // just go through and push into js graph
+ emscripten::val helpers = ci::em::helpers::getWorkletHelpers();
+ emscripten::val graph = helpers["graph"];
+
+ // if the graph has no items, we start by injecting the output
+ if( graph[ "length" ].as() == 0 )
+ {
+ graph.call( "push",emscripten::val::global("window")["CINDER_AUDIO"]["globalContext"]["destination"] );
+
+ // push the connected node and recurse the function until we have no nodes left that have connections.
+ enable( this->mConnectedTo );
+ }
+ else {
+ // there are only 2 possible derivations from the base class of AudioNode - if NativeNode cast fails,
+ // then it must be an instance of a CustomNode
+ NativeNode * n = dynamic_cast(node.get());
+ if( n != nullptr )
+ {
+ // push the native node onto the stack
+ graph.call( "push",n->getNode() );
+ n->setEnabled();
+
+ if( !n->getConnectedNode()->isEnabled() )
+ {
+ // push the connected node and recurse the function until we have no nodes left that have connections.
+ enable(n->getConnectedNode());
+ }
+ }
+ else {
+ CustomNode * n = dynamic_cast( node.get() );
+ graph.call( "push",n->getProcessFunction() );
+ n->setEnabled();
+
+ if( n->getConnectedNode() != nullptr )
+ {
+
+ if(!n->getConnectedNode()->isEnabled()){
+ // push the connected node and recurse the function until we have no nodes left that have connections.
+ enable(n->getConnectedNode());
+ }
+
+ }
+ }
+
+ }
+
+ if( !mProcessorLoaded )
+ {
+ // load audio processor
+ load_processor(processor.c_str());
+ mProcessorLoaded = true;
+ }
+ }
+
+ AudioContext(AudioContext const&) = delete;
+ void operator=(AudioContext const&) = delete;
+
+
+ private:
+ AudioContext(){}
+
+ bool mProcessorLoaded = false;
+
+ //! The AudioContextProcessor - receives inputs, sends changes via outputs.
+ std::string processor = STRINGIFY(
+ class CinderAudioProcessor extends AudioWorkletProcessor {
+ constructor() {
+ super();
+ }
+
+ process(inputs, outputs, parameters) {
+
+ // this should send a message to all connected
+ // AudioContextNodes with this data.
+ this.port.postMessage({
+ inputs:inputs,
+ outputs:outputs,
+ channelCount:inputs.length
+ });
+
+
+ // return true to keep this AudioWorkletProcessor running.
+ return true;
+ }
+ }
+
+ registerProcessor("CinderAudioProcessor",CinderAudioProcessor);
+ );
+
+};
+
+
+}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/AudioJSFunctions.h b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioJSFunctions.h
new file mode 100644
index 0000000000..87bf37a0cf
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioJSFunctions.h
@@ -0,0 +1,35 @@
+#pragma once
+#include
+
+
+
+/**
+ * This loads the audio worklet processor. The graph gets generated by Cinder, converted and executed with the appropriate
+ * JS calls, and then attached to the output here when the context's enable() function is called. .
+ * Note - if something is wrong errors are thus far un-helpful :(
+ *
+ * Also note that you must use semi-colons :/
+ * For some reason, EM_JS requires them.
+ */
+EM_JS(void,load_processor,(const char * source),{
+
+
+ let ctx = CINDER_AUDIO.globalContext;
+ source = UTF8ToString( source );
+ source = CINDER_FILEIO.sourceToBlob( source );
+
+ // initialize the AudioWorkletProcessor. This will handle all custom node processing and
+ // feed the inputs and outputs to our CustomNode objects.
+ ctx.audioWorklet.addModule( source ).then(() => {
+
+ // sort graph into the correct order
+ CINDER_WORKLETS.sortGraph();
+
+ }).catch(function(e){
+ console.log("An error occured - ",e);
+ });
+});
+EM_JS(void,check_graph,(),{
+
+ console.log(window.CINDER_WORKLETS.graph);
+});
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/AudioNode.h b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioNode.h
new file mode 100644
index 0000000000..be301ab4d5
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioNode.h
@@ -0,0 +1,49 @@
+
+#pragma once
+#include
+#include
+#include
+
+namespace cinder {
+
+typedef std::shared_ptr AudioNodeRef;
+
+class AudioNode {
+ public:
+ AudioNode():mConnectionEnabled(false){}
+
+ virtual void connect(const AudioNodeRef input){
+ mConnectedTo = input;
+ }
+
+ //! Logs node to the console.
+ void logNode(){
+
+ }
+
+ AudioNodeRef getConnectedNode(){
+ return mConnectedTo;
+ }
+
+ void setEnabled(){
+ mConnectionEnabled = true;
+ }
+
+ bool isEnabled(){
+ return mConnectionEnabled;
+ }
+
+ protected:
+ AudioNodeRef mConnectedTo;
+
+ //! Used to serve as a marker of when this node is connected during the AudioContext's enable() call
+ bool mConnectionEnabled;
+
+};
+
+inline const AudioNodeRef& operator>>( const AudioNodeRef &input, const AudioNodeRef &output )
+{
+ output->connect(input);
+ return output;
+}
+}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/AudioWorkletNode.js b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioWorkletNode.js
new file mode 100644
index 0000000000..0fb015b81b
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/AudioWorkletNode.js
@@ -0,0 +1,22 @@
+/**
+ * A custom AudioWorklet node. When the main AudioWorkletProcessor receives information,
+ * the _handleMessage function will get called which in turn will call the process() function
+ * of your CustomNode instance.
+ */
+class CustomNode extends AudioWorkletNode {
+ constructor(processingFunction){
+ super(CINDER_AUDIO.globalContext,"CinderAudioProcessor");
+ this.port.onmessage = this._handleMessage.bind(this);
+ this.processingFunction = processingFunction;
+ }
+ /**
+ * When a message is received from the procesor - send the inputs and outputs
+ * to our C++ function which should have been passed in as the "processingFunction"
+ * in the constructor
+ */
+ _handleMessage( e )
+ {
+
+ this.processingFunction( e.data );
+ }
+ }
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/CustomNode.h b/samples/_emscripten/_tests/AudioAPI/audioapi/CustomNode.h
new file mode 100644
index 0000000000..d1b9cd363a
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/CustomNode.h
@@ -0,0 +1,77 @@
+#pragma once
+#include "AudioNode.h"
+
+#include "cinder/emscripten/CinderEmscripten.h"
+#include
+#include
+#include "cinder/Log.h"
+
+
+namespace cinder {
+
+
+/**
+ * A type of node that allows for custom processing of the audio stream.
+ * The idea with this to keep things compatible with C++, is that users will
+ * override this node and it's process() function.
+ *
+ * When the final audio graph is built - a custom AudioWorkletNode class is created and
+ * the process function is passed to that AudioWorkletNode instance and called whenever the
+ * main AudioWorkletProcessor triggers an update.
+ */
+typedef std::shared_ptrCustomNodeRef;
+
+class CustomNode : public AudioNode
+{
+ public:
+ CustomNode():mProcessFunction( emscripten::val::undefined() )
+ {
+
+
+ // generate a JS compatible callback function that will get passed to auto-generated instances of
+ // AudioWorkletNode on the JS side.
+ std::function func = std::bind( &CustomNode::process,this,std::placeholders::_1 );
+ mProcessFunction = em::helpers::generateCallback( func );
+ }
+
+ //! returns the processing function for this CustomNode
+ emscripten::val getProcessFunction(){
+ return mProcessFunction;
+ }
+
+
+ //! A function to run to process the input and output buffers from the AudioWorkletProcessor.
+ //! JS side will send data in the following manner.
+ //! {inputs : [Float32Array], outputs:[Float32Array], channelCount:int }
+ //! Note the [] brackets denote a potential array
+ virtual void process( emscripten::val jsdata )
+ {
+ int channel_count = jsdata["channelCount"].as();
+
+ for( int i = 0; i < channel_count; ++i )
+ {
+ emscripten::val inputs = jsdata["inputs"];
+ emscripten::val outputs = jsdata["outputs"];
+
+ int size = inputs["length"].as();
+
+ // loop through arrays of each channel
+ for( int a = 0; a < size; ++a )
+ {
+ float inValue = inputs[a].as();
+
+ // just pass through here - users should override CustomNode object.
+ outputs[a].set(i,inValue);
+
+ }
+ }
+ }
+
+ protected:
+
+ unsigned mRenderQuantumFrames = 128;
+ unsigned mKBytedPerChannel = mRenderQuantumFrames * sizeof(float);
+ emscripten::val mProcessFunction;
+
+};
+}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/NativeNode.h b/samples/_emscripten/_tests/AudioAPI/audioapi/NativeNode.h
new file mode 100644
index 0000000000..80bda37886
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/NativeNode.h
@@ -0,0 +1,100 @@
+
+#pragma once
+#include
+#include
+#include "cinder/Log.h"
+#include "AudioNode.h"
+#include "cinder/emscripten/CinderEmscripten.h"
+
+
+
+ enum WebAudioApiNode
+ {
+ BiquadFilterNode,
+ ConvolverNode,
+ DelayNode,
+ DynamicsCompressorNode,
+ IIRFilterNode,
+ PeriodicWaveNode,
+ WaveShaperNode,
+ ChannelMergerNode,
+ ChannelSplitterNode,
+ StereoPannerNode,
+ GainNode,
+ AnalyserNode,
+ OscillatorNode
+ };
+ const static std::map NativeWebTypes =
+ {
+ { AnalyserNode,"createAnalyser" },
+ { BiquadFilterNode,"createBiquadFilter" },
+ { ChannelMergerNode, "createChannelMerger" },
+ { ChannelSplitterNode,"createChannelSplitter" },
+ { DelayNode,"createDelay" },
+ { ConvolverNode,"createConvolver" },
+ { GainNode,"createGain" },
+ { PeriodicWaveNode,"createPeriodicWave" },
+ { WaveShaperNode,"createWaveSharper" },
+ { StereoPannerNode,"createStereoPanner" },
+ { DynamicsCompressorNode,"createDynamicsCompressor" },
+ { OscillatorNode , "createOscillator" }
+ };
+
+
+namespace cinder {
+
+
+typedef std::shared_ptr NativeNodeRef;
+class NativeNode : public AudioNode
+{
+ public:
+ NativeNode(WebAudioApiNode type=GainNode):mNode(emscripten::val::undefined()){
+
+
+ auto it = NativeWebTypes.find(type);
+ if(it != NativeWebTypes.end()){
+
+ // get audio helpers
+ emscripten::val ctx = ci::em::helpers::getAudioHelpers()["globalContext"];
+
+ std::string command = it->second;
+
+ // create the node.
+ mNode = ctx.call(command.c_str());
+ }
+
+ }
+
+ std::string getName(){
+ return "NativeNode";
+ }
+ //! Returns a property on the native audio node (usually a AudioParam object)
+ emscripten::val getAudioParam(std::string name){
+ return mNode[name];
+ }
+
+ //! Returns reference to JS element for native node
+ emscripten::val getNode(){
+ return mNode;
+ }
+
+ /**
+ *
+ */
+ template
+ void setAudioParam
+ (std::string paramName,T value){
+ mNode[paramName].set("value",emscripten::val(value));
+ }
+
+ template
+ void setParam(std::string paramName,T value){
+ mNode.set(paramName,emscripten::val(value));
+ }
+
+ private:
+ emscripten::val mNode;
+
+
+};
+}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/audiojs.js b/samples/_emscripten/_tests/AudioAPI/audioapi/audiojs.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/nodes/GainNode.h b/samples/_emscripten/_tests/AudioAPI/audioapi/nodes/GainNode.h
new file mode 100644
index 0000000000..5d90a029a6
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/nodes/GainNode.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "CustomNode.h"
+
+
+namespace cinder {
+
+
+
+class CustomGainNode : public CustomNode {
+
+ public:
+ CustomGainNode(){}
+
+ void process( emscripten::val jsData )
+ {
+ try {
+ int v = jsData["channelCount"].as();
+ }catch(...){
+ CI_LOG_E("Unable to get info");
+ }
+ }
+};
+}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/AudioAPI/audioapi/readme.md b/samples/_emscripten/_tests/AudioAPI/audioapi/readme.md
new file mode 100644
index 0000000000..fdba9fdb4e
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/audioapi/readme.md
@@ -0,0 +1,37 @@
+
+This is a bit of a re-thinking of one possibility of how audio could be re-done for the web
+once ScriptProcessorNode is finally not useable anywhere.
+
+
+Essentially the basic idea is that, unlike the current implementation, everything is as native as possible and centered around the idea of the AudioWorklet; this is a new way to process audio on the web and offers advantages that the ScriptProcessorNode does not, for example, the ability to run things on a separate thread.
+
+
+The disadvantage however is that it is a bit tedious to set up due to the face that there aren't any native Emscripten apis and a lot of things are designed to be asyncrounous. Also in this context, things are especially complicated for any kind of custom work that someone might want to do.
+
+This hopefully presents one path to implementing an api on the C++ side while keeping a fairly similar api.
+
+
+The basic idea
+=====
+
+There is an audio context and 2 types of nodes that can be used.
+
+__Audio Node Type 1 : NativeNode__
+The first type of node would be called a `NativeNode`. Essentially this would reference any kind of buit-in node within the WebAudio API like a delay node.
+
+__Audio node Type 2 : CustomNode__
+The second type of node would be called a `CustomNode`. This would refer to a node that users can create and do custom processing on.
+
+Note that in this case, there is no output object on the context, the context itself serves as the output object and knows how to grab the global AudioContext's destination attribute.
+
+Things that still need to be thought out
+===
+* It doesn't look like it's possible to extract any kind of a buffer out of built-in nodes, making it hard to custom tweak the output.
+* ~~Can we just pass a function to a custom AudioWorkletNode that gets bound to the process function?~~ Solved!
+
+
+References
+===
+* [https://developer.mozilla.org/en-US/docs/Web/API/ScriptProcessorNode](https://developer.mozilla.org/en-US/docs/Web/API/ScriptProcessorNode)
+* [https://developers.google.com/web/updates/2017/12/audio-worklet](https://developers.google.com/web/updates/2017/12/audio-worklet)
+* [https://googlechromelabs.github.io/web-audio-samples/audio-worklet/](https://googlechromelabs.github.io/web-audio-samples/audio-worklet/)
diff --git a/samples/_emscripten/_tests/AudioAPI/emscripten/CMakeLists.txt b/samples/_emscripten/_tests/AudioAPI/emscripten/CMakeLists.txt
new file mode 100644
index 0000000000..d1eb7be9c6
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/emscripten/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE ON )
+
+# NOTE - this can only be built in Debug mode for the time being
+
+project( AudioAPI )
+
+get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../" ABSOLUTE )
+get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../" ABSOLUTE )
+
+include( "${CINDER_PATH}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+
+ci_emscripten_app(
+ SOURCES ${APP_PATH}/src/Audioapi.cpp
+ CINDER_PATH ${CINDER_PATH}
+ INCLUDES ${APP_PATH}/include ${APP_PATH}/audioapi
+ FLAGS "-s ASSERTIONS=0 -O0 --pre-js ${APP_PATH}/audioapi/AudioWorkletNode.js"
+)
diff --git a/samples/_emscripten/_tests/AudioAPI/include/Resources.h b/samples/_emscripten/_tests/AudioAPI/include/Resources.h
new file mode 100644
index 0000000000..3164745b1c
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/include/Resources.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "cinder/CinderResources.h"
+
+//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE )
+
+
+
+
+
+
+
+
diff --git a/samples/_emscripten/_tests/AudioAPI/src/Audioapi.cpp b/samples/_emscripten/_tests/AudioAPI/src/Audioapi.cpp
new file mode 100644
index 0000000000..555b745703
--- /dev/null
+++ b/samples/_emscripten/_tests/AudioAPI/src/Audioapi.cpp
@@ -0,0 +1,60 @@
+#include "cinder/app/App.h"
+#include "cinder/app/RendererGl.h"
+#include "cinder/gl/gl.h"
+#include "cinder/Log.h"
+#include
+#include
+#include
+#include "cinder/emscripten/CinderEmscripten.h"
+#include "AudioContext.h"
+#include "CustomNode.h"
+
+using namespace std;
+using namespace ci;
+using namespace ci::app;
+
+#define STRINGIFY(A) #A
+
+
+/**
+ * Test to see if it might be possible to build a filewatcher which can then let you know if a
+ * file was changed.
+ */
+class AudioApi : public App
+{
+
+ public:
+ void draw() override;
+ void setup() override;
+ void onLoad();
+
+ NativeNodeRef osc;
+
+};
+
+void prepareSettings( AudioApi::Settings* settings )
+{
+ settings->setMultiTouchEnabled( false );
+}
+
+void AudioApi::setup()
+{
+ emscripten::val helpers = em::helpers::getFileHelpers();
+ auto ctx = AudioContext::Instance();
+
+ osc = ctx->makeNode(new NativeNode(WebAudioApiNode::OscillatorNode));
+
+ osc->setParam("frequency",255);
+ osc >> ctx;
+
+ ctx->enable();
+}
+
+void AudioApi::draw()
+{
+ gl::clear( Color( 0,0,0 )) ;
+
+}
+
+
+CINDER_APP( AudioApi, RendererGl, prepareSettings )
diff --git a/samples/_emscripten/_tests/Filewatcher/assets/colors.glsl b/samples/_emscripten/_tests/Filewatcher/assets/colors.glsl
new file mode 100644
index 0000000000..fd0c5817d9
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/assets/colors.glsl
@@ -0,0 +1,17 @@
+precision highp float;
+in vec2 vUv;
+uniform vec2 resolution;
+uniform float time;
+out vec4 glFragColor;
+
+void main( )
+{
+ // Normalized pixel coordinates (from 0 to 1)
+ vec2 uv = gl_FragCoord.xy/resolution.xy;
+
+ // Time varying pixel color
+ vec3 col = 0.5 + 0.5*cos(time+vUv.xyx+vec3(0,2,4));
+
+ // Output to screen
+ glFragColor = vec4(col,1.0);
+}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/Filewatcher/assets/quad.glsl b/samples/_emscripten/_tests/Filewatcher/assets/quad.glsl
new file mode 100644
index 0000000000..4703b1175e
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/assets/quad.glsl
@@ -0,0 +1,11 @@
+
+uniform mat4 ciModelViewProjection;
+in vec3 ciPosition;
+in vec2 ciTexCoord0;
+
+out vec2 vUv;
+
+void main(){
+ vUv = ciTexCoord0;
+ gl_Position = ciModelViewProjection * vec4(ciPosition,1.);
+}
diff --git a/samples/_emscripten/_tests/Filewatcher/emscripten/CMakeLists.txt b/samples/_emscripten/_tests/Filewatcher/emscripten/CMakeLists.txt
new file mode 100644
index 0000000000..13566308ef
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/emscripten/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE ON )
+
+project( Filewatcher )
+
+get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../" ABSOLUTE )
+get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../" ABSOLUTE )
+
+include( "${CINDER_PATH}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+
+ci_emscripten_app(
+ SOURCES ${APP_PATH}/src/Filewatcher.cpp
+ CINDER_PATH ${CINDER_PATH}
+ INCLUDES ${APP_PATH}/include
+ FLAGS "--pre-js ${APP_PATH}/src/watcher.js"
+ ASSETS ../assets
+)
diff --git a/samples/_emscripten/_tests/Filewatcher/include/Filewatcher.h b/samples/_emscripten/_tests/Filewatcher/include/Filewatcher.h
new file mode 100644
index 0000000000..e824ced560
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/include/Filewatcher.h
@@ -0,0 +1,56 @@
+#include
+#include
+#include "WatcherFunctions.h"
+#include "cinder/emscripten/CinderEmscripten.h"
+
+using namespace ci::em::watcher;
+/**
+ * A basic file watcher for Cinder Emscripten.
+ * Note that this will not be suitable for .cpp files and other lower-level source code but
+ * is instead intended for any higher level sort files you might want to keep an eye on.
+ */
+class Filewatcher
+{
+
+
+ //! string url of the socket server to connect to.
+ std::string url;
+
+ public:
+ Filewatcher( int port=3400 )
+ {
+ url = "ws://localhost:" + std::to_string( port );
+
+ // we connect to the server right away assuming that the server is already running.
+ connect_to_server( url.c_str() );
+ }
+
+ void addFile( std::string path,std::function cb )
+ {
+ // add file to callbacks so we can lookup the
+ emscripten::val watcher = emscripten::val::global( "window" )[ "CINDER_WATCHER" ];
+
+ // add entry to global callbacks array so we can trigger different functions
+ // depending on which file was changed.
+ watcher.call( "addFile",emscripten::val( path ),ci::em::helpers::generateCallback( cb ) );
+
+ // add file to chokidar(the filewatcher)
+ add_file_to_watcher( path.c_str() );
+ }
+
+ //! For when you want to add a bunch of files to watch.
+ void addFiles( std::vector files,std::function cb )
+ {
+ // add file to callbacks so we can lookup the
+ emscripten::val watcher = emscripten::val::global( "window" )["CINDER_WATCHER"];
+
+ for( std::string &path : files )
+ {
+ // add entry to global callbacks array so we can trigger different functions
+ // depending on which file was changed.
+ watcher.call( "addFile",emscripten::val( path ),ci::em::helpers::generateCallback( cb ) );
+ // add file to chokidar(the filewatcher)
+ add_file_to_watcher( path.c_str() );
+ }
+ }
+};
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/Filewatcher/include/Resources.h b/samples/_emscripten/_tests/Filewatcher/include/Resources.h
new file mode 100644
index 0000000000..3164745b1c
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/include/Resources.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "cinder/CinderResources.h"
+
+//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE )
+
+
+
+
+
+
+
+
diff --git a/samples/_emscripten/_tests/Filewatcher/include/WatcherFunctions.h b/samples/_emscripten/_tests/Filewatcher/include/WatcherFunctions.h
new file mode 100644
index 0000000000..1407a16628
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/include/WatcherFunctions.h
@@ -0,0 +1,52 @@
+#include
+
+/**
+ * note - websocket packet should look like
+ * {
+ * type:
+ * data:
+ * }
+ */
+
+namespace cinder { namespace em { namespace watcher {
+
+ // server connection function. Call to connect to the server.
+ // note that it assumes the server is already running.
+ EM_JS( void,connect_to_server,( const char * serverurl ), {
+
+ // note that we can only have one client at a time any new instances will just overwrite the
+ // current socket client.
+ window.CINDER_WATCHER.client = new WebSocket( UTF8ToString( serverurl ) );
+
+ // messages should be passed back and forth as a type / data pair. something like
+ // {type:"this is my message type" , data:"this is my payload"}
+ window.CINDER_WATCHER.client.onmessage = function( msg ){
+ msg = JSON.parse( msg.data );
+
+ switch( msg.type ){
+ case "FILE_CHANGED":
+ window.CINDER_WATCHER.processServerResponse( msg.data );
+ break;
+ }
+ }
+ });
+
+ // add file function - tells server to add a file to the watch list.
+ EM_JS( void,add_file_to_watcher,( const char * filepath ), {
+ let file = UTF8ToString( filepath) ;
+ let client = window.CINDER_WATCHER.client;
+
+ let timer = setInterval(() => {
+ if( client.readyState === 1 )
+ {
+ client.send( JSON.stringify({
+ type:"ADD_FILE",
+ data:file
+ }));
+
+ clearInterval( timer );
+ }
+
+ });
+ });
+}}}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/Filewatcher/src/Filewatcher.cpp b/samples/_emscripten/_tests/Filewatcher/src/Filewatcher.cpp
new file mode 100644
index 0000000000..d3049f32ea
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/src/Filewatcher.cpp
@@ -0,0 +1,73 @@
+#include "cinder/app/App.h"
+#include "cinder/app/RendererGl.h"
+#include "cinder/gl/gl.h"
+#include "cinder/Log.h"
+#include
+#include
+#include
+#include "cinder/emscripten/CinderEmscripten.h"
+#include "Filewatcher.h"
+
+using namespace std;
+using namespace ci;
+using namespace ci::app;
+
+#define STRINGIFY(A) #A
+
+/**
+ * Test to see if it might be possible to build a filewatcher which can then let you know if a
+ * file was changed.
+ */
+class FilewatcherApp : public App
+{
+
+ public:
+ void draw() override;
+ void setup() override;
+ void onLoad();
+
+ Filewatcher watcher;
+
+ gl::GlslProgRef mShader;
+
+};
+
+void prepareSettings( FilewatcherApp::Settings* settings )
+{
+ settings->setMultiTouchEnabled( false );
+}
+
+void FilewatcherApp::setup()
+{
+ emscripten::val helpers = em::helpers::getFileHelpers();
+ gl::GlslProg::Format fmt;
+ fmt.vertex( app::loadAsset("quad.glsl") );
+ fmt.fragment( app::loadAsset("colors.glsl") );
+
+ mShader = gl::GlslProg::create( fmt );
+
+
+ // note - paths to files will be relative to where you run the server.
+ watcher.addFile( "../emscripten/build/Debug/assets/colors.glsl",[=]( emscripten::val e )->void
+ {
+
+ // note - you have to completely re-init, not sure why.
+ gl::GlslProg::Format fmt;
+ fmt.vertex(app::loadAsset("quad.glsl"));
+ fmt.fragment(app::loadAsset("colors.glsl"));
+
+ mShader = gl::GlslProg::create(fmt);
+
+ });
+}
+
+void FilewatcherApp::draw()
+{
+ gl::clear( Color( 0,0,0 )) ;
+ gl::ScopedGlslProg shader( mShader );
+ mShader->uniform( "time", ( float )app::getElapsedSeconds() );
+ mShader->uniform( "resolution",vec2( app::getWindowWidth(),app::getWindowHeight() ) );
+ gl::drawSolidRect(sapp::getWindowBounds() );
+}
+
+CINDER_APP( FilewatcherApp, RendererGl, prepareSettings )
diff --git a/samples/_emscripten/_tests/Filewatcher/src/watcher.js b/samples/_emscripten/_tests/Filewatcher/src/watcher.js
new file mode 100644
index 0000000000..54350784cf
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/src/watcher.js
@@ -0,0 +1,32 @@
+
+window.CINDER_WATCHER = {
+
+ callbacks:{},
+
+ /**
+ * Adds
+ * @param {string} id an id identifying the file you want to watch. Can be a full path, will get quashed down to filename
+ * @param {*} fn the callback function to run when the file is changed.
+ */
+ addFile:function( id,fn )
+ {
+ // first construct an id if necessary
+ id = id.split("/");
+
+ id = id[id.length - 1];
+
+ this.callbacks[id] = fn;
+ },
+
+ /**
+ * Processes the server response.
+ * @param {string} id the id to look up so we know which callback function to run.
+ */
+ processServerResponse:function( id )
+ {
+
+ let cb = this.callbacks[id];
+ cb(id);
+ }
+
+};
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/Filewatcher/watcher-server/bin/cli.js b/samples/_emscripten/_tests/Filewatcher/watcher-server/bin/cli.js
new file mode 100644
index 0000000000..ecba30fd22
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/watcher-server/bin/cli.js
@@ -0,0 +1,22 @@
+const argv = require('minimist')(process.argv.slice(2));
+const server = require('../index')
+
+let files = [];
+if(argv.files){
+ // look for any files we know we want to watch right away.
+ // files parameter should take a string seperated by commas
+ files = argv.files.split(",");
+}
+
+// set the port on which to operate the server
+let port = argv.port !== undefined ? argv.port : 3400;
+
+// the root path to where your files ought to be. if not specified,
+// the root defaults to wherever your script is being run from.
+let root = argv.root !== undefined ? argv.root : "./"
+
+// start the server.
+server({
+ files:files,
+ port:port
+});
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/Filewatcher/watcher-server/index.js b/samples/_emscripten/_tests/Filewatcher/watcher-server/index.js
new file mode 100644
index 0000000000..8234ddac3d
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/watcher-server/index.js
@@ -0,0 +1,62 @@
+const chokidar = require( "chokidar" );
+const ws = require( "ws" );
+
+module.exports = function( options )
+{
+ let files = options.files;
+ let port = options.port;
+ let root = options.root;
+ let watcher = null;
+
+ // start watching known files
+ if( files.length > 0 )
+ {
+ //start watcher.
+ watcher = chokidar.watch( files );
+ }
+ else {
+ // if no initial dataset, pass in blank array and start watcher.
+ watcher = chokidar.watch( [] );
+ }
+
+ // start socket server
+ console.log( "starting server on port ", port )
+
+ // start Socket server
+ let wss = new ws.Server({
+ port:port
+ })
+
+
+ wss.on('connection', socket => {
+
+ // when we get a message from client, process.
+ socket.on('message', msg => {
+ msg = JSON.parse( msg );
+
+ switch(msg.type)
+ {
+ case "ADD_FILE":
+ // add path to watcher
+ watcher.add(msg.data);
+ break;
+ }
+ });
+
+ // when the file changes ...
+ watcher.on('change', path => {
+ let id = path.split("/");
+ id = id[id.length - 1];
+
+ console.log("file changed", path);
+
+ // send a message back saying which file changed.
+ // so we can lookup the appropriate callback.
+ socket.send(JSON.stringify({
+ type:"FILE_CHANGED",
+ data:id
+ }))
+ });
+ console.log("A connection was made");
+ })
+}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/Filewatcher/watcher-server/package-lock.json b/samples/_emscripten/_tests/Filewatcher/watcher-server/package-lock.json
new file mode 100644
index 0000000000..4705864706
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/watcher-server/package-lock.json
@@ -0,0 +1,1836 @@
+{
+ "name": "watcher-server",
+ "version": "0.0.1",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "dev": true,
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+ "dev": true
+ },
+ "async-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
+ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
+ "dev": true
+ },
+ "async-limiter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
+ "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
+ "dev": true
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "binary-extensions": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz",
+ "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==",
+ "dev": true
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "chokidar": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
+ "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==",
+ "dev": true,
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.0",
+ "braces": "^2.3.0",
+ "fsevents": "^1.2.2",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.1",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "lodash.debounce": "^4.0.8",
+ "normalize-path": "^2.1.1",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.0.0",
+ "upath": "^1.0.5"
+ }
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": true,
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "dev": true,
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fsevents": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
+ "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "nan": "^2.9.2",
+ "node-pre-gyp": "^0.10.0"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true,
+ "dev": true
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chownr": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.5.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "fs-minipass": {
+ "version": "1.2.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "iconv-lite": {
+ "version": "0.4.21",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "minipass": {
+ "version": "2.2.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "^5.1.1",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "needle": {
+ "version": "2.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "debug": "^2.1.2",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
+ },
+ "node-pre-gyp": {
+ "version": "0.10.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.0",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.1.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.0.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "npm-packlist": {
+ "version": "1.1.10",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "rc": {
+ "version": "1.2.7",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "deep-extend": "^0.5.1",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "glob": "^7.0.5"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.1",
+ "bundled": true,
+ "dev": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "semver": {
+ "version": "5.5.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "tar": {
+ "version": "4.4.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "chownr": "^1.0.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.2.4",
+ "minizlib": "^1.1.0",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.1",
+ "yallist": "^3.0.2"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "wide-align": {
+ "version": "1.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "string-width": "^1.0.2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "yallist": {
+ "version": "3.0.2",
+ "bundled": true,
+ "dev": true
+ }
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
+ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ },
+ "lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
+ "dev": true
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "dev": true,
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ },
+ "mixin-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "nan": {
+ "version": "2.11.1",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz",
+ "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==",
+ "dev": true,
+ "optional": true
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": true,
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "set-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "source-map-resolve": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+ "dev": true,
+ "requires": {
+ "atob": "^2.1.1",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+ "dev": true
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "dev": true,
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "union-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^0.4.3"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "set-value": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.1",
+ "to-object-path": "^0.3.0"
+ }
+ }
+ }
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true
+ }
+ }
+ },
+ "upath": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
+ "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==",
+ "dev": true
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "ws": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz",
+ "integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==",
+ "dev": true,
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ }
+ }
+}
diff --git a/samples/_emscripten/_tests/Filewatcher/watcher-server/package.json b/samples/_emscripten/_tests/Filewatcher/watcher-server/package.json
new file mode 100644
index 0000000000..6f3d53e2ca
--- /dev/null
+++ b/samples/_emscripten/_tests/Filewatcher/watcher-server/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "ci_emscripten_watch_server",
+ "version": "0.0.1",
+ "description": "Filewatcher server for live-reload of non-compiled assets",
+ "main": "index.js",
+ "scripts": {
+ "start": "node bin/cli.js"
+ },
+ "author": "RareVolume",
+ "license": "ISC",
+ "devDependencies": {
+ "chokidar": "^2.0.4",
+ "minimist": "^1.2.0",
+ "ws": "^6.1.2"
+ }
+}
diff --git a/samples/_emscripten/_tests/TmpFileWrite/emscripten/CMakeLists.txt b/samples/_emscripten/_tests/TmpFileWrite/emscripten/CMakeLists.txt
new file mode 100644
index 0000000000..6edf8e10f8
--- /dev/null
+++ b/samples/_emscripten/_tests/TmpFileWrite/emscripten/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required( VERSION 2.8 FATAL_ERROR )
+set( CMAKE_VERBOSE_MAKEFILE ON )
+
+project( TmpFileWrite )
+
+get_filename_component( CINDER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../" ABSOLUTE )
+get_filename_component( APP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../" ABSOLUTE )
+
+include( "${CINDER_PATH}/proj/cmake/modules/cinderEmscriptenApp.cmake" )
+
+
+ci_emscripten_app(
+ SOURCES ${APP_PATH}/src/TmpFileWrite.cpp
+ CINDER_PATH ${CINDER_PATH}
+)
diff --git a/samples/_emscripten/_tests/TmpFileWrite/include/Resources.h b/samples/_emscripten/_tests/TmpFileWrite/include/Resources.h
new file mode 100644
index 0000000000..3164745b1c
--- /dev/null
+++ b/samples/_emscripten/_tests/TmpFileWrite/include/Resources.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "cinder/CinderResources.h"
+
+//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE )
+
+
+
+
+
+
+
+
diff --git a/samples/_emscripten/_tests/TmpFileWrite/include/Worklet.h b/samples/_emscripten/_tests/TmpFileWrite/include/Worklet.h
new file mode 100644
index 0000000000..a677f4f18e
--- /dev/null
+++ b/samples/_emscripten/_tests/TmpFileWrite/include/Worklet.h
@@ -0,0 +1,18 @@
+#include
+#include
+
+class Worklet {
+
+ emscripten::val mWorklet;
+ std::string mWorkletSource;
+public:
+ Worklet( std::string workletSource ):
+ mWorkletSource(workletSource),
+ mWorklet( emscripten::val::undefined() )
+ {}
+
+ void loadWorklet(std::string source){
+
+ }
+
+};
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/TmpFileWrite/src/TmpFileWrite.cpp b/samples/_emscripten/_tests/TmpFileWrite/src/TmpFileWrite.cpp
new file mode 100644
index 0000000000..f544f8a261
--- /dev/null
+++ b/samples/_emscripten/_tests/TmpFileWrite/src/TmpFileWrite.cpp
@@ -0,0 +1,92 @@
+#include "cinder/app/App.h"
+#include "cinder/app/RendererGl.h"
+#include "cinder/gl/gl.h"
+#include "cinder/Log.h"
+#include
+#include
+#include
+#include "cinder/emscripten/CinderEmscripten.h"
+
+using namespace std;
+using namespace ci;
+using namespace ci::app;
+
+#define STRINGIFY(A) #A
+
+EM_JS(void,mountFS,(),{
+ FS.mkdir('/cinder');
+ FS.mount(MEMFS,{},'/cinder');
+});
+
+EM_JS(void,writeFile,(const char * filename, const char * contents),{
+ var file = UTF8ToString(contents);
+
+ FS.writeFile('/cinder/' + filename,file);
+
+});
+
+
+
+/**
+ * Testing if it's possible to write a file to tmp memory filesystem with the Filesystem api,
+ * then load it on JS side. Possibly useful for AudioWorklets in the future.
+ *
+ * Conclusions on 11/30
+ * - Not possible :(
+ * - but it looks like it's possible to use Blob urls to load Worklets and Workers!
+ */
+class TmpFileWrite : public App
+{
+
+ public:
+ void draw() override;
+ void setup() override;
+ void onLoad();
+
+
+ std::string worklet = STRINGIFY(
+ class Processor extends AudioWorkletProcessor {
+ constructor(){
+ super();
+ }
+
+ process(inputs,outputs,parameters){
+
+ }
+ }
+
+ registerProcessor('cinder-worklet',Processor);
+ );
+
+ std::string worker = STRINGIFY(
+
+ onmessage = function(e){
+ console.log(e.status);
+ }
+ );
+
+};
+
+void prepareSettings( TmpFileWrite::Settings* settings )
+{
+ settings->setMultiTouchEnabled( false );
+}
+
+void TmpFileWrite::setup()
+{
+ emscripten::val helpers = em::helpers::getFileHelpers();
+
+
+ helpers.call("loadProcessor",emscripten::val(worklet));
+ //helpers.call("loadWorker",emscripten::val(worker));
+}
+
+void TmpFileWrite::draw()
+
+{
+ gl::clear( Color( 0,0,0 ));
+
+
+}
+
+CINDER_APP( TmpFileWrite, RendererGl, prepareSettings )
diff --git a/samples/_emscripten/_tests/_audio/EmscriptenAudio/ContextWebAudio.cpp b/samples/_emscripten/_tests/_audio/EmscriptenAudio/ContextWebAudio.cpp
new file mode 100644
index 0000000000..2e1569909d
--- /dev/null
+++ b/samples/_emscripten/_tests/_audio/EmscriptenAudio/ContextWebAudio.cpp
@@ -0,0 +1,324 @@
+
+//#include "cinder/audio/emscripten/ContextWebAudio.h"
+#include "ContextWebAudio.h"
+#include "cinder/audio/dsp/Dsp.h"
+
+using namespace emscripten;
+using namespace std;
+
+namespace cinder { namespace audio { namespace em {
+
+ // ============ CONTEXT ============== //
+ ContextWebAudio::ContextWebAudio():
+ mScriptNode( emscripten::val::undefined() ),
+ mOscNode( emscripten::val::undefined() ),
+ mBufferSize( 0 ),
+ mCallbackFunction( emscripten::val::undefined() )
+ {
+ emscripten::val mAudioContext = getGlobalContext();
+ mScriptNode = mAudioContext.call( "createScriptProcessor",0,1,mAudioContext["destination"]["channelCount"].as() );
+
+ }
+
+ emscripten::val ContextWebAudio::getGlobalContext()
+ {
+ return val::global( "window" )[ "CINDER_AUDIO" ][ "globalContext" ];
+ }
+
+ emscripten::val ContextWebAudio::getRawContext()
+ {
+ return getGlobalContext();
+ }
+
+ void ContextWebAudio::setOutputBufferSize( int size )
+ {
+ emscripten::val mAudioContext = getGlobalContext();
+
+ // if the bufferSize prop is wrong, disconnect, then re-connect with the correct size
+ if(size != mScriptNode[ "bufferSize" ].as())
+ {
+
+ mBufferSize = size;
+
+ // disconnect ScriptProcessorNode from Oscillator.
+ //mOscNode.call("disconnect",mScriptNode);
+
+ // disconnect script node to output
+ mScriptNode.call("disconnect",mAudioContext["destination"]);
+
+ // rebuild ScriptProcessorNode with the correct buffer size.
+ mScriptNode = mAudioContext.call( "createScriptProcessor",size,1,1 );
+
+ // re-init all connections
+ setRenderFunction();
+ }
+ }
+
+ int ContextWebAudio::getChannelCount()
+ {
+ return getRawContext()[ "destination" ][ "channelCount" ].as();
+ }
+
+ int ContextWebAudio::getBufferSize()
+ {
+ return mBufferSize;
+ }
+
+ void ContextWebAudio::connectNativeNode( emscripten::val input )
+ {
+ //getGlobalContext().call("connect",input);
+ input.call( "connect",mScriptNode );
+ }
+
+ void ContextWebAudio::setRenderFunction()
+ {
+ emscripten::val mAudioContext = getGlobalContext();
+
+ // set callback of script node
+ mScriptNode.set( "onaudioprocess",mCallbackFunction );
+
+ // create oscillator object to play back script node
+ //mOscNode = mAudioContext.call("createOscillator");
+
+ // connect script node to oscillator
+ //mOscNode.call("connect",mScriptNode);
+
+ // connect script node to output
+ mScriptNode.call( "connect",mAudioContext[ "destination" ] );
+
+ // start script node
+ //mOscNode.call("start");
+ }
+
+ void ContextWebAudio::setRenderFunction( std::function functor )
+ {
+ mCallbackFunction = ci::em::helpers::generateCallback( functor );
+ setRenderFunction();
+ }
+
+ ContextWebAudio::~ContextWebAudio(){}
+
+ OutputDeviceNodeRef ContextWebAudio::createOutputDeviceNode( const DeviceRef &device, const Node::Format &format )
+ {
+ auto thisRef = std::dynamic_pointer_cast( shared_from_this() );
+ auto result = makeNode( new OutputDeviceNodeWebAudio( device, format, thisRef ) );
+ mDeviceNodes.push_back( result );
+ return result;
+ }
+
+ InputDeviceNodeRef ContextWebAudio::createInputDeviceNode( const DeviceRef &device, const Node::Format &format )
+ {
+ auto thisRef = std::dynamic_pointer_cast( shared_from_this() );
+ auto result = makeNode( new InputDeviceNodeWebAudio( device, format, thisRef ) );
+ mDeviceNodes.push_back( result );
+ return result;
+ }
+
+ // ==============================
+
+ // TODO this may technically not end up really being needed.
+ struct OutputDeviceNodeWebAudioImpl
+ {
+
+ OutputDeviceNodeWebAudioImpl( OutputDeviceNodeWebAudio* parent, const std::shared_ptr& context )
+ :mParent( parent ), mCinderContext( context )
+ {}
+
+ void connectNativeNode( emscripten::val node )
+ {
+ mCinderContext->connectNativeNode( node );
+ }
+
+ void setOutputBufferSize( int size )
+ {
+ mCinderContext->setOutputBufferSize( size) ;
+ }
+
+ void setRenderFunction( std::function functor )
+ {
+ mCinderContext->setRenderFunction( functor );
+ }
+
+ emscripten::val getRawContext()
+ {
+ return mCinderContext->getRawContext();
+ }
+
+ OutputDeviceNodeWebAudio * mParent = nullptr;
+ std::shared_ptr mCinderContext;
+ };
+ // ===============================
+
+ InputDeviceNodeWebAudio::InputDeviceNodeWebAudio( const DeviceRef &device, const Format &format, const std::shared_ptr &context ):
+ InputDeviceNode( device, format ),
+ mStreamRef( emscripten::val::undefined() ),
+ mInputStreamAquired( false ),
+ mMediaStream( emscripten::val::undefined() ),
+ mAudioContext( context )
+ {
+
+ // initialize stream
+ auto utils = ci::em::helpers::getAudioHelpers();
+ std::function cb = [this]( emscripten::val e )->void
+ {
+ // save stream reference
+ mStreamRef = e;
+
+ auto ctx = mAudioContext->getRawContext();
+
+ // turn stream we aquired into something consumable by the output.
+ mMediaStream = ctx.call( "createMediaStreamSource",mStreamRef );
+
+ // signal that we have an input stream.
+ mInputStreamAquired = true;
+ };
+
+ // get and check device id / name - if it matches default then pass in blank string.
+ std::string name = device->getName();
+ if( name == "WebAudioInputDevice" )
+ {
+ name = "";
+ }
+
+ // indicate that this is a native node and thus, needs slightly different processing.
+ //mIsNativeWebNode = true;
+
+ // initialize stream - returns emscripten::val object
+ mStreamRef = utils.call( "loadAudioInput",ci::em::helpers::generateCallback( cb ),val( name ) );
+ }
+
+ void InputDeviceNodeWebAudio::initialize()
+ {
+ //CI_LOG_I("InputDeviceNode :: initialize was triggered - note that you don't have to call 'enable'");
+ // nothing to do here - we already initialize things when we create the media stream.
+ }
+ // ===============================
+ OutputDeviceNodeWebAudio::OutputDeviceNodeWebAudio( const DeviceRef &device, const Format &format, const std::shared_ptr &context ):
+ OutputDeviceNode( device, format )
+ {
+ mIsOutputDevice = true;
+ mImpl = std::unique_ptr( new OutputDeviceNodeWebAudioImpl( this,context ) );
+ }
+
+ emscripten::val OutputDeviceNodeWebAudio::getRawContext()
+ {
+ return mImpl->getRawContext();
+ }
+
+ void OutputDeviceNodeWebAudio::connectNativeNodeToOutput( emscripten::val node )
+ {
+ mImpl->connectNativeNode(node);
+ }
+
+ void OutputDeviceNodeWebAudio::renderInputs( emscripten::val e )
+ {
+ auto outputBuffer = e["outputBuffer"];
+ auto inputBuffer = e["inputBuffer"];
+
+ auto ctx = getContext();
+ if( ! ctx )
+ {
+ CI_LOG_I( "can't get context" );
+ return;
+ }
+
+ // this technically doesn't do anything but leave it here for now.
+ lock_guard lock( ctx->getMutex() );
+
+ ctx->preProcess();
+
+
+ auto internalBuffer = getInternalBuffer();
+ internalBuffer->zero();
+ pullInputs( internalBuffer );
+
+ if( checkNotClipping() )
+ {
+ internalBuffer->zero();
+ }
+
+ const size_t numFrames = internalBuffer->getNumFrames();
+ const size_t numChannels = internalBuffer->getNumChannels();
+
+ //dsp::interleave( internalBuffer->getData(), outputBuffer, numFrames, numChannels, numFrames );
+
+ ctx->postProcess();
+
+ // =========================================== //
+
+ // make sure that the ScriptNodeProcessor's bufferSize prop is set properly.
+ mImpl->setOutputBufferSize( numFrames );
+
+ // output array is what gets directed towards speakers
+ val output = outputBuffer.call( "getChannelData", 0 );
+
+ // input is only going to be populated when using native WebAudio nodes.
+ val input = inputBuffer.call( "getChannelData",0 );
+
+ // check first 100 values to see if input buffer is filled or empty(aka the value is 0). If empty, we won't bother processing,
+ bool mInputIsEmpty = true;
+ for( int a = 0; a < 100; ++a )
+ {
+ if( input[a].as() != 0.0 )
+ {
+ mInputIsEmpty = false;
+ }
+ }
+
+ // get internal cinder data
+ float * data = static_cast( internalBuffer->getData() );
+ float * finalData;
+ float * idata;
+
+
+ if( !mInputIsEmpty )
+ {
+
+ // will hold input data
+ std::vector _inputData;
+
+ // copy Float32Array(aka "input") into _inputData vector
+ ci::em::helpers::copyToVector( input,_inputData );
+
+ // convert to float* so we can pass information to dsp methods
+ idata = &_inputData[0];
+
+ // add input data to any cinder data
+ dsp::add(idata,data,finalData,numFrames);
+
+ }
+ else{
+
+ // if no input data just pass through
+ finalData = data;
+ }
+
+ // loop through and set all info from finalData pointer onto the output buffer.
+ for( int i = 0; i < numFrames; ++i )
+ {
+ output.set( i,finalData[i] );
+ }
+
+
+ // release finalData pointer.
+ // releasing these causes things to crash :(
+ //free(finalData);
+ //free(idata);
+
+ }
+
+ void OutputDeviceNodeWebAudio::initialize()
+ {
+ CI_LOG_I( "OutputDevicenode :: Initialize called" );
+
+ const size_t sampleRate = getOutputSampleRate();
+ const size_t framesPerBlock = getOutputFramesPerBlock();
+ const size_t numChannels = getNumChannels();
+
+ mInterleavedBuffer = BufferInterleaved( framesPerBlock, numChannels );
+
+ auto functor = std::bind( &OutputDeviceNodeWebAudio::renderInputs,this,std::placeholders::_1 );
+ mImpl->setRenderFunction( functor );
+
+ }
+}}}
\ No newline at end of file
diff --git a/samples/_emscripten/_tests/_audio/EmscriptenAudio/ContextWebAudio.h b/samples/_emscripten/_tests/_audio/EmscriptenAudio/ContextWebAudio.h
new file mode 100644
index 0000000000..1938851405
--- /dev/null
+++ b/samples/_emscripten/_tests/_audio/EmscriptenAudio/ContextWebAudio.h
@@ -0,0 +1,191 @@
+/*
+ Copyright (c) 2018, The Cinder Project
+
+ This code is intended to be used with the Cinder C++ library, http://libcinder.org
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+// for some reason - original defines doesn't reach Node.h - refeine here
+#define CINDER_EMSCRIPTEN
+#include
+#include "cinder/audio/Context.h"
+#include "cinder/audio/dsp/Converter.h"
+#include "cinder/audio/dsp/RingBuffer.h"
+#include "cinder/Log.h"
+#include "cinder/emscripten/CinderEmscripten.h"
+#include
+
+
+using namespace emscripten;
+
+namespace cinder { namespace audio { namespace em {
+
+
+ class ContextWebAudio;
+ struct OutputDeviceNodeWebAudioImpl;
+
+ class OutputDeviceNodeWebAudio : public OutputDeviceNode {
+ public:
+ OutputDeviceNodeWebAudio( const DeviceRef &device, const Format &format, const std::shared_ptr &context );
+
+ //! Confirms that this is indeed an output device.
+ //! Used to help determine when an output device is at the end of a chain and mixing
+ //! Cinder and web audio nodes.
+ bool isOutputDevice(){ return mIsOutputDevice; }
+
+ //! Provides compatibility for when we want to connect a
+ //! native Web Audio node to the output device directly
+ void connectNativeNodeToOutput(emscripten::val node);
+
+ protected:
+ void initialize() override;
+ void uninitialize() override{}
+ void enableProcessing() override{}
+ void disableProcessing() override{}
+ bool supportsProcessInPlace() const override { return false; }
+ emscripten::val getRawContext();
+
+
+
+ private:
+ //! a flag to determine whether or not this is an output device.
+ //! Used in testing when chaining a mix of native web and non native audio nodes
+ //! to help ensure we're calling the correct classes.
+ bool mIsOutputDevice;
+
+ void renderInputs(emscripten::val e);
+
+ //! all of the outputs that need to be summed and written out.
+ std::vector mOutputInputs;
+
+ std::unique_ptr mImpl;
+ BufferInterleaved mInterleavedBuffer;
+
+ friend struct OutputDeviceNodeWebAudioImpl;
+ };
+
+ // class for defining an audio input.
+ class InputDeviceNodeWebAudio : public InputDeviceNode {
+
+ //! A reference to the raw stream
+ emscripten::val mStreamRef;
+
+ //! A reference to a MediaStream(part of native web audio api) object that can be fed
+ //! to the output and processed.
+ emscripten::val mMediaStream;
+
+ //! Aquiring the stream is an async process + a user-dependent process - this helps keep
+ //! track of when we have the actual stream available.
+ bool mInputStreamAquired;
+
+ public:
+ InputDeviceNodeWebAudio( const DeviceRef &device, const Format &format, const std::shared_ptr &context );
+ virtual ~InputDeviceNodeWebAudio(){}
+
+
+
+ emscripten::val getRawStream(){
+ return mStreamRef;
+ }
+ emscripten::val getMediaStream(){
+ return mMediaStream;
+ }
+ bool isStreamAvailable(){
+ return mInputStreamAquired;
+ }
+ protected:
+
+ void initialize() override;
+ void uninitialize() override{}
+ void enableProcessing() override{}
+ void disableProcessing() override{}
+ void process( Buffer *buffer ) override{}
+
+ private:
+ std::shared_ptr mAudioContext;
+ };
+
+
+ /**
+ TODO one issue to solve with this is how to handle JS garbage collection. When used outside of the class,
+ main WebAudio context appears to have been deleted
+
+ Could be helpful
+ https://github.com/kripken/emscripten/issues/4268
+ */
+ class ContextWebAudio : public Context {
+
+ //! Emscripten value representing a browser's ScriptProcessorNode object. This is used
+ //! to "render" the internal buffer calculated by the Cinder audio API.
+ //! IMPORTANT - note that the bufferSize property needs to match the frame size of the context's internal buffer.
+ //! TODO a replacement for this will have to be thought through at some point as this is set to be deprecated at some point.
+ emscripten::val mScriptNode;
+
+ //! Emscripten value representing a browser's Oscillator object. This is used to process and playback the ScriptNodeProcessor information
+ emscripten::val mOscNode;
+
+ //! Emscripten value that holds the callback function to do the audio processing.
+ emscripten::val mCallbackFunction;
+
+ public:
+ ContextWebAudio();
+ virtual ~ContextWebAudio();
+
+ int getChannelCount();
+
+ //! Creates an output device for the web and beings setting up everything to get processed.
+ OutputDeviceNodeRef createOutputDeviceNode( const DeviceRef &device = Device::getDefaultOutput(), const Node::Format &format = Node::Format() ) override;
+
+ // TODO input not implemented yet.
+ InputDeviceNodeRef createInputDeviceNode( const DeviceRef &device = Device::getDefaultInput(), const Node::Format &format = Node::Format() ) override;
+
+ //! Sets the ScriptProcessorNode's bufferSize property.
+ void setOutputBufferSize(int size);
+
+ int getBufferSize();
+
+ //! Sets the callback function to use to process audio data.
+ void setRenderFunction();
+
+ //! Sets the callback function to use to process audio data.
+ void setRenderFunction(std::function functor);
+
+ //! Connects a native web based node to the context
+ void connectNativeNode(emscripten::val input);
+
+ //! Retrieves the global audio context to use for nodes.
+ //! this is done to avoid garbage collection issues that arise from
+ //! the JS engine / emscripten combo.
+ emscripten::val getGlobalContext();
+
+ //! alias to getGlobalContext()
+ emscripten::val getRawContext();
+
+
+
+ private:
+ int mBufferSize;
+ std::vector> mDeviceNodes;
+ };
+
+
+
+}}}
diff --git a/samples/_emscripten/_tests/_audio/EmscriptenAudio/DeviceManagerWebAudio.h b/samples/_emscripten/_tests/_audio/EmscriptenAudio/DeviceManagerWebAudio.h
new file mode 100644
index 0000000000..94da3dd168
--- /dev/null
+++ b/samples/_emscripten/_tests/_audio/EmscriptenAudio/DeviceManagerWebAudio.h
@@ -0,0 +1,140 @@
+/*
+ Copyright (c) 2014, The Cinder Project
+
+ This code is intended to be used with the Cinder C++ library, http://libcinder.org
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+ the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "cinder/audio/Device.h"
+#include
+#include
+#include
+
+using namespace emscripten;
+
+namespace cinder { namespace audio { namespace em {
+ struct DeviceInfo {
+ enum Usage { INPUT, OUTPUT };
+
+ std::string mKey;
+ std::string mName;
+ int32_t mIndex = -1;
+ uint32_t mCard = (uint32_t)-1;
+ Usage mUsage;
+ size_t mNumChannels;
+ size_t mSampleRate;
+ size_t mFramesPerBlock;
+ std::string mDescription;
+ };
+
+class DeviceManagerWebAudio : public DeviceManager
+{
+ DeviceRef mDefaultDevice;
+ DeviceInfo mDeviceInfo,mInputDeviceInfo;
+ std::map mDeviceInfoSet;
+
+ public:
+ DeviceManagerWebAudio()
+ {
+
+
+ // tmp value to grab device specified parameters. This should end up getting
+ // garbage collected by the browser.
+ emscripten::val context = val::global( "window" )[ "CINDER_AUDIO" ]["globalContext"];
+
+ int channelCount = context["destination"]["channelCount"].as();
+ int sampleRate = context["sampleRate"].as();
+
+ mDeviceInfo.mName = "WebAudioDevice";
+ mDeviceInfo.mIndex = 1;
+ mDeviceInfo.mNumChannels = channelCount;
+ mDeviceInfo.mFramesPerBlock = 512;
+ mDeviceInfo.mSampleRate = sampleRate;
+
+ mInputDeviceInfo.mName = "WebAudioInputDevice";
+ mInputDeviceInfo.mIndex = 1;
+ mInputDeviceInfo.mNumChannels = 1;
+ mInputDeviceInfo.mFramesPerBlock = 512;
+ mInputDeviceInfo.mSampleRate = sampleRate;
+
+ addDevice(mDeviceInfo.mName);
+ addDevice(mInputDeviceInfo.mName);
+ }
+
+ // It seems multiple outputs is an ongoing issue
+ // https://github.com/WebAudio/web-audio-api/issues/445
+ // gonna focus on one output for now.
+ const std::vector