summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--ChangeLog373
-rwxr-xr-xemcc31
-rw-r--r--src/analyzer.js2
-rw-r--r--src/intertyper.js24
-rw-r--r--src/jsifier.js24
-rw-r--r--src/library.js24
-rw-r--r--src/library_egl.js14
-rw-r--r--src/library_fs.js172
-rw-r--r--src/library_gl.js66
-rw-r--r--src/library_glfw.js4
-rw-r--r--src/library_glut.js4
-rw-r--r--src/library_idbfs.js2
-rw-r--r--src/library_memfs.js100
-rw-r--r--src/library_nodefs.js12
-rw-r--r--src/library_path.js22
-rw-r--r--src/library_sdl.js56
-rw-r--r--src/parseTools.js96
-rw-r--r--src/preamble.js10
-rw-r--r--src/runtime.js15
-rw-r--r--src/shell.html7
-rw-r--r--system/include/compat/ctype.h17
-rw-r--r--system/include/compat/wchar.h23
-rw-r--r--system/include/compat/wctype.h23
-rw-r--r--system/include/emscripten/vector.h10
-rw-r--r--tests/aniso.c3
-rw-r--r--tests/cases/2xi40.ll42
-rw-r--r--tests/cases/2xi40.txt1
-rw-r--r--tests/cases/caall.ll2
-rw-r--r--tests/cases/emptyasm_le32.ll16
-rw-r--r--tests/embind/shell.html2
-rw-r--r--tests/hello_world_gles_shell.html2
-rw-r--r--tests/sdl_canvas_size.c191
-rw-r--r--tests/sdl_canvas_size.html93
-rw-r--r--tests/test_browser.py47
-rw-r--r--tests/test_core.py148
-rw-r--r--tests/test_other.py44
-rw-r--r--tests/test_webgl_context_attributes_common.c262
-rw-r--r--tests/test_webgl_context_attributes_glfw.c47
-rw-r--r--tests/test_webgl_context_attributes_glut.c42
-rw-r--r--tests/test_webgl_context_attributes_sdl.c50
-rw-r--r--tools/file_packager.py39
-rw-r--r--tools/js_optimizer.py8
43 files changed, 1826 insertions, 346 deletions
diff --git a/AUTHORS b/AUTHORS
index 75f38f15..5c49e65e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -104,4 +104,6 @@ a license to everyone to use it as detailed in LICENSE.)
* Daniel Aquino <mr.danielaquino@gmail.com>
* Remi Papillie <remi.papillie@gmail.com>
* Fraser Adams <fraser.adams@blueyonder.co.uk>
+* Michael Tirado <icetooth333@gmail.com>
* Ben Noordhuis <info@bnoordhuis.nl>
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..cca1b833
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,373 @@
+This document describes changes between tagged Emscripten SDK versions.
+
+Note that in the compiler, version numbering is used as the mechanism to invalidate internal compiler caches,
+so version numbers do not necessarily reflect the amount of changes between versions.
+
+To browse or download snapshots of old tagged versions, visit https://github.com/kripken/emscripten/releases .
+
+Not all changes are documented here. In particular, new features, user-oriented fixes, options, command-line parameters, usage changes, deprecations, significant internal modifications and optimizations etc. generally deserve a mention. To examine the full set of changes between versions, visit the link to full changeset diff at the end of each section.
+
+v1.7.1: 10/24/2013
+------------------
+ - Remove old call to Runtime.warn in file packager code
+ - Fix bug with parsing of empty types.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.7.0...1.7.1
+
+v1.7.0: 10/23/2013
+------------------
+ - Adds mouse wheel events support in GLUT library.
+ - Adds support for a new link parameter -s CASE_INSENSITIVE_VFS=1 to enable Emscripten virtual filesystem to search files ignoring case.
+ - *Numerous* optimizations in both compilation and runtime stages.
+ - Remove unnecessary whitespace, compact postSets function, and other optimizations in compilation output to save on generated file size.
+ - Fixes float parsing from negative zero.
+ - Removes the -s EMIT_GENERATED_FUNCTIONS link parameter as unneeded.
+ - Fixes an issue where updating subranges of GL uniform arrays was not possible.
+ - asm.js heap size (-s TOTAL_MEMORY=x) no longer needs to be a power of 2. As a relaxed rule, choosing any multiple of 16MB is now possible.
+ - O1 optimization no longer runs the 'simplifyExpressions' optimization pass. This is to improve build iteration times when using -O1. Use -O2 to run that pass.
+ - EM_ASM() can now be used even when compiling to asm.js.
+ - All currently specified non-debugging-related WebGL 1 extensions are now enabled by default on startup, no need to ctx.getExtension() manually to enable them.
+ - Improve readability of uncaught JavaScript exceptions that are thrown all the way up to the web console by printing out the stack trace of where the throw occurred.
+ - Fix an issue when renaming a directory to a subdirectory.
+ - Several compiler stability fixes.
+ - Adds a JavaScript implementation of cxa_demangle function for demangling call stack traces at runtime for easier debugging.
+ - GL context MSAA antialising is now DISABLED by default, to make the GL behavior consistent with desktop usage.
+ - Added support to SDL, GLUT and GLFW libraries to specify MSAA on/off at startup.
+ - Implemented glColor4ubv in GL emulation mode.
+ - Fix an issue with LLVM keyword __attribute__ ((__constructor__)) (#1155).
+ - Fix an issue with va_args and -s UNALIGNED_MEMORY=1 (#1705).
+ - Add initial support code for LLVM SIMD constructs and a JavaScript SIMD polyfill implementation from https://github.com/johnmccutchan/ecmascript_simd/ .
+ - Fixed support for node.js native filesystem API NODEFS on Windows.
+ - Optimize application startup times of Emscripten-compiled programs by enabling the virtual filesystem XHR and asm.js compilation to proceed in parallel when opening a page.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.6.4...1.7.0
+
+v1.6.4: 9/30/2013
+------------------
+ - Implements a new preprocessor tool for preparsing C struct definitions (#1554), useful for Emscripten support library implementors.
+ - Fix parsing issue with sscanf (#1668).
+ - Improved the responsiveness of compiler print output on Windows.
+ - Improved compilation times at link stage.
+ - Added support for new "NODEFS" filesystem that directly accesses files on the native filesystem. Only usable with node.js when compiling to JS.
+ - Added support for new IDBFS filesystem for accessing files in IndexedDB storage (#1601.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.6.3...1.6.4
+
+v1.6.3: 9/26/2013
+------------------
+ - Emscripten CMake toolchain now generates archive files with .a suffix when project target type is static library, instead of generatic .bc files (#1648).
+ - Adds iconv library from the musl project to implement wide functions in C library (#1670).
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.6.2...1.6.3
+
+v1.6.2: 9/25/2013
+------------------
+ - Added support for dprintf() function (#1250).
+ - Fixes several compiler stability issues (#1637, #1166, #1661, #1651 and more).
+ - Enables support for WEBGL_depth_texture.
+ - Adds support for new link flag -s GL_ASSERTIONS=1 which can be used to add extra validation layer to the Emscripten GL library to catch code issues.
+ - Adds support to Web Audio API in SDL audio backend so that SDL audio now works in Chrome and new Opera as well.
+ - Fixes an alpha blending issue with SDL_SetAlpha.
+ - Implemented locale-related code in C library.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.6.1...1.6.2
+
+v1.6.1: 9/22/2013
+------------------
+ - Several optimizations to compiler link stage.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.6.0...1.6.1
+
+v1.6.0: 9/21/2013
+------------------
+ - Enable support for %[] pattern in scanf.
+ - Added dependency tracking support to linked .js files in CMake toolchain.
+ - The hex prefix 0x is now properly handled in sscanf (#1632).
+ - Simplify internal compiler operations by removing the internal framework.js.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.9...1.6.0
+
+v1.5.9: 9/15/2013
+------------------
+ - Add support for SDL_Delay in web workers.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.8...1.5.9
+
+v1.5.8: 9/14/2013
+------------------
+ - Add support for the GCC -E compiler flag.
+ - Update Emscripten libc headers to musl-0.9.13.
+ - Added new utility function emscripten_async_load_script() to asynchronously load a new .js script URL.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.7...1.5.8
+
+v1.5.7: 8/30/2013
+------------------
+ - The script tag in default shell.html is now marked 'async', which enables loading the JS script code asynchronously in Firefox without making the main thread unresponsive.
+ - Implemented new utility function emscripten_get_canvas_size() which returns the current Module <canvas> element size in pixels.
+ - Optimize code size in compiled side modules.
+ - Optimize startup memory usage by avoiding unnecessary copying of VFS data at startup.
+ - Add support for SDL_WM_ToggleFullScreen().
+ - Add support for emscripten_get_now() when running in SpiderMonkey shell.
+ - Added new environment variable EM_BUILD_VERBOSE=0,1,2,3 to set an extra compiler output verbosity level for debugging.
+ - Added better support for dlopen() to simulate dynamic library loading in JavaScript.
+ - Improved support for BSD sockets and networking.
+ - Added new SOCKFS filesystem, which reads files via a network connection.
+ - Avoid issues with long command line limitations in CMake toolchain by using response files.
+ - Fix issues with client-side vertex data rendering in GL emulation mode.
+ - Improved precision of clock_gettime().
+ - Improve function outlining support.
+ - Added support for using NMake generator with CMake toolchain.
+ - Improved support for flexible arrays in structs (#1602).
+ - Added ability to marshal UTF16 and UTF32 strings between C++ <-> JS code.
+ - Added a new commandline tool validate_asms.py to help automating asm.js validation testing.
+ - Improved stability with inline asm() syntax.
+ - Updated libc headers to new version.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.6...1.5.7
+
+v1.5.6: 8/17/2013
+------------------
+ - Improved BSD sockets support.
+ - Added touch events support to GLUT library.
+ - Added new --js-opts=0/1 command line option to control whether JS optimizer is run or not.
+ - Improved OpenAL support.
+ - Added new command line tool tools/find_bigvars.py which can be used on a output file to detect large functions and needs for outlining.
+ - Merged link flags -s FORCE_GL_EMULATION and -s DISABLE_GL_EMULATION to a single opt-in flag -s LEGACY_GL_EMULATION=0/1 to control whether GL emulation is active.
+ - Improved SDL input support.
+ - Several stability-related compiler fixes.
+ - Fixed source mapping generation support on Windows.
+ - Added back the EMSCRIPTEN_KEEPALIVE attribute qualifier to help prevent inlining and to retain symbols in output without dead code elimination occurring.
+ - Fix issues when marshalling UTF8 strings between C<->JS.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.5...1.5.6
+
+v1.5.5: 8/9/2013
+------------------
+ - Update libcxx to revision 187959, 2013-08-08.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.4...1.5.5
+
+v1.5.4: 8/9/2013
+------------------
+ - Fixed multiple issues with C stdlib support.
+ - Fix audio buffer queueing issues with OpenAL.
+ - Improved BSD sockets support.
+ - Added a new compile+link time command line option -Wno-warn-absolute-paths to hide the emscripten compiler warning when absolute paths are passed into the compiler.
+ - Added new link flag -s STB_IMAGE=0/1 and integrate it to SDL image loading to enable synchronous image loading support with SDL.
+ - Several improvements on function outlining support.
+ - Fix issues with GLES2 interop support.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.3...1.5.4
+
+v1.5.3: 6/28/2013
+------------------
+ - Added new optimization level --llvm-lto 3 to run even more aggressive LTO optimizations.
+ - Improve optimizations for libc and other libraries.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.2...1.5.3
+
+v1.5.2: 6/27/2013
+------------------
+ - Added support for generating source maps along the built application when -g is specified. This lets the browser show original .cpp sources when debugging.
+ - GLUT and SDL improvements.
+ - Added new link option -g<level> where level=0-4, which allows controlling various levels of debuggability added to the output.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.1...1.5.2
+
+v1.5.1: 6/22/2013
+------------------
+ - File packager now skips all directories and files starting with '.', and hidden files on Windows.
+ - Fix issues with strnlen, memmove, LDBL_ constants, va_args, float.h, and others.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.0...1.5.1
+
+v1.5.0: 6/17/2013
+------------------
+ - Several compiler optimizations.
+ - Improve SDL key events support.
+ - Increase debug logging when specifying emcc -v.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.9...1.5.0
+
+v1.4.9: 6/8/2013
+------------------
+ - Several compiler optimizations.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.8...1.4.9
+
+v1.4.8: 6/6/2013
+------------------
+ - Add support for webrtc-based sockets.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.7...1.4.8
+
+v1.4.7: 6/2/2013
+------------------
+ - Remove more unneeded break and continue statements in relooper.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.6...1.4.7
+
+v1.4.6: 6/2/2013
+------------------
+ - Improve relooper code.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.5...1.4.6
+
+v1.4.5: 6/1/2013
+------------------
+ - Improve relooper code.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.4...1.4.5
+
+v1.4.4: 6/1/2013
+------------------
+ - Add support for symlinks in source files.
+ - Fix various issues with SDL.
+ - Added -s FORCE_ALIGNED_MEMORY=0/1 link time flag to control whether all loads and stores are assumed to be aligned.
+ - Fix file packager to work with closure.
+ - Major improvements to embind support, and optimizations.
+ - Improve GL emulation.
+ - Optimize VFS usage.
+ - Allow emscripten to compile .m and .mm files.
+ - Added new syntax --preload-file src@dst to file packager command line to allow placing source files to custom destinations in the FS.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.3...1.4.4
+
+v1.4.3: 5/8/2013
+------------------
+ - Fix issue with strcat.
+ - Major embind improvements.
+ - Switch to le32-unknown-nacl LLVM target triple as default build option instead of the old i386-pc-linux-gnu target triple.
+ - Improve compiler logging behavior.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.2...1.4.3
+
+v1.4.2: 5/3/2013
+------------------
+ - Fix issues with le32-unknown-nacl LLVM target triple.
+ - Add some GLEW support.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.4.1...1.4.2
+
+v1.4.1: 4/28/2013
+------------------
+ - Implement support for le32-unknown-nacl LLVM target triple.
+ - Added new cmdline option -s ERROR_ON_UNDEFINED_SYMBOLS=0/1 to give compile-time error on undefined symbols at link time. Default off.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.8...1.4.1
+
+v1.3.8: 4/29/2013
+------------------
+ - Improved 64-bit integer ops codegen.
+ - Added Indexed DB support to vfs.
+ - Improve warning message on dangerous function pointer casts when compiling in asm.js mode.
+ - Added --use-preload-cache command line option to emcc, to be used with the file packager.
+ - Fixes to libcextra.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.7...1.3.8
+
+v1.3.7: 4/24/2013
+------------------
+ - Merge IMVU implementation of embind to emscripten trunk. Embind allows high-level C++ <-> JS types interop.
+ - Enable asm.js compilation in -O1 and higher by default. Fix issues when compiling to asm.js.
+ - Improve libc support with Emscripten with the musl libc headers.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.6...1.3.7
+
+v1.3.6: 4/2/2013
+------------------
+ - Fix hang issue with strtof.
+ - Update libcxx to upstream r178253 from March 29, 2013.
+ - Fix issues with GL emulation.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.5...1.3.6
+
+v1.3.5: 3/25/2013
+------------------
+ - Get exceptions working as they did before.
+ - Remove symbol removing hack.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.4...1.3.5
+
+v1.3.4: 3/24/2013
+------------------
+ - Update to new libcxx and libcxxabi versions from upstream.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.3...1.3.4
+
+v1.3.3: 3/23/2013
+------------------
+ - Remove unneeded check from relooper.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.2...1.3.3
+
+v1.3.2: 3/22/2013
+------------------
+ - Fix issues with fgets.
+ - Add support for non-fullscreen pointer lock.
+ - Improve OpenAL support.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.1...1.3.2
+
+v1.3.1: 3/19/2013
+------------------
+ - Improve SDL audio and mixer support.
+ - Add GLES2 emulation features when -s FULL_ES2=1 is specified.
+ - Add support for OpenAL.
+ - Add new -s OPENAL_DEBUG=0/1 link command line option.
+ - Fixed an issue with mouse coordinate being offset with canvas.
+ - Removed -s UTF_STRING_SUPPORT=0 parameter, this is now always on.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.0...1.3.1
+
+v1.3.0: 3/11/2013
+------------------
+ - Improve GLES2 emulation with -s FULL_ES2=1.
+ - Deprecated -s USE_TYPED_ARRAYS=1 and -s QUANTUM_SIZE=1.
+ - Implement a minifier infrastructure when compiling for asm.js.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.9...1.3.0
+
+v1.2.9: 3/7/2013
+------------------
+ - Improved canvas behavior when transitioning between fullscreen.
+ - Added support for getopt().
+ - Fixed several libc issues.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.8...1.2.9
+
+v1.2.8: 3/6/2013
+------------------
+ - Remove unnecessary recursion in relooper RemoveUnneededFlows.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.7...1.2.8
+
+v1.2.7: 3/6/2013
+------------------
+ - Added SDL_Mixer support.
+ - Implemented stubs for several Unix and threading-related functions.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.6...1.2.7
+
+v1.2.6: 3/5/2013
+------------------
+ - Relooper updates.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.5...1.2.6
+
+v1.2.5: 3/5/2013
+------------------
+ - Greatly improve GL emulation support.
+ - Handle %c in sscanf.
+ - Improve compilation times by optimizing parallel execution in the linker.
+ - Improve several compiler stability issues detected from fuzzing tests.
+ - Implemented emscripten_jcache_printf.
+ - Allow running emscripten.py outside emcc itself.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.4...1.2.5
+
+v1.2.4: 2/2/2013
+------------------
+ - Work on adding support for asm.js compilation.
+ - Improve EGL support.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.3...1.2.4
+
+v1.2.3: 1/9/2013
+------------------
+ - Work on adding support for asm.js compilation.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.2...1.2.3
+
+v1.2.2: 1/8/2013
+------------------
+ - Work on adding support for asm.js compilation.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.1...1.2.2
+
+v1.2.1: 1/8/2013
+------------------
+ - Improvements to GLUT, SDL and BSD sockets headers.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.2.0...1.2.1
+
+v1.2.0: 1/1/2013
+------------------
+ - Work on adding support for asm.js compilation.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.1.0...1.2.0
+
+v1.1.0: 12/12/2012
+------------------
+ - Fix several issues with Windows support.
+ - Added a standalone toolchain for CMake.
+ - Added emscripten_run_script_string().
+ - Optimize compilation times via threading.
+ - Update to requiring Clang 3.2. Older versions may no longer work.
+ - Several improvements to emscripten library support headers.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.0.1a...1.1.0
+
+v1.0.1a: 11/11/2012
+------------------
+ - Add relooper code to repository.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.0.1...1.0.1a
+
+v1.0.1: 11/11/2012
+------------------
+ - First commit that introduced versioning to the Emscripten compiler.
diff --git a/emcc b/emcc
index 4222caa3..3406ff83 100755
--- a/emcc
+++ b/emcc
@@ -397,7 +397,8 @@ Options that are modified or new in %s include:
--shell-file <path> The path name to a skeleton HTML file used
when generating HTML output. The shell file
used needs to have this token inside it:
- {{{ SCRIPT_CODE }}}
+ {{{ SCRIPT }}}
+ (see src/shell.html for an example)
Note that this argument is ignored if a
target other than HTML is specified using
the -o option.
@@ -501,7 +502,8 @@ The target file, if specified (-o <target>), defines what will
be generated:
<name>.js JavaScript
- <name>.html HTML with embedded JavaScript
+ <name>.html HTML + side JavaScript file (<name>.js)
+ (JS on the side improves page load time)
<name>.bc LLVM bitcode (default)
<name>.o LLVM bitcode (same as .bc)
@@ -542,7 +544,7 @@ There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR P
exit(0)
elif len(sys.argv) == 2 and sys.argv[1] == '-v': # -v with no inputs
- print 'emcc (Emscripten GCC-like replacement + linker emulating GNU ld ) 2.0'
+ print 'emcc (Emscripten GCC-like replacement + linker emulating GNU ld ) %s' % shared.EMSCRIPTEN_VERSION
exit(subprocess.call([shared.CLANG, '-v']))
def is_minus_s_for_emcc(newargs,i):
@@ -1818,22 +1820,21 @@ try:
if final_suffix == 'html':
logging.debug('generating HTML')
shell = open(shell_path).read()
+ assert '{{{ SCRIPT }}}' in shell, 'HTML shell must contain {{{ SCRIPT }}} , see src/shell.html for an example'
html = open(target, 'w')
+ js_target = unsuffixed(target) + '.js'
+ base_js_target = os.path.basename(js_target)
if proxy_to_worker:
- html.write(shell.replace('{{{ SCRIPT_CODE }}}', open(shared.path_from_root('src', 'proxyClient.js')).read().replace('{{{ filename }}}', target_basename)))
- js_target = unsuffixed(target) + '.js'
- shutil.copyfile(final, js_target)
+ html.write(shell.replace('{{{ SCRIPT }}}', '<script>' + open(shared.path_from_root('src', 'proxyClient.js')).read().replace('{{{ filename }}}', target_basename) + '</script>'))
+ shutil.move(final, js_target)
elif not Compression.on:
if debug_level >= 4:
- match = re.match('.*?<script[^>]*>{{{ SCRIPT_CODE }}}</script>', shell,
- re.DOTALL)
- if match is None:
- raise RuntimeError('''Could not find script insertion point - make sure you have <script type='text/javascript'>{{{ SCRIPT_CODE }}}</script> in your HTML file (with no newlines)''')
- generate_source_map(target, match.group().count('\n'))
- html.write(shell.replace('{{{ SCRIPT_CODE }}}', open(final).read()))
+ generate_source_map(target)
+ shutil.move(final, js_target)
+ script_tag = '''<script async type="text/javascript" src="%s"></script>''' % base_js_target
+ html.write(shell.replace('{{{ SCRIPT }}}', script_tag))
else:
# Compress the main code
- js_target = unsuffixed(target) + '.js'
shutil.move(final, js_target)
Compression.compress(js_target)
@@ -1881,8 +1882,8 @@ try:
});
};
compiledCodeXHR.send(null);
-''' % Compression.compressed_name(js_target)
- html.write(shell.replace('{{{ SCRIPT_CODE }}}', decoding))
+''' % Compression.compressed_name(base_js_target)
+ html.write(shell.replace('{{{ SCRIPT }}}', '<script>' + decoding + '</script>'))
# Add decompressor with web worker glue code
decompressor = open('decompress.js', 'w')
diff --git a/src/analyzer.js b/src/analyzer.js
index 2b74a83f..253c5505 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -418,7 +418,7 @@ function analyzer(data, sidePass) {
toAdd.push({
intertype: 'value',
assignTo: element.ident,
- type: element.bits,
+ type: 'i' + element.bits,
ident: 'tempRet' + (j - 1)
});
assert(j<10); // TODO: dynamically create more than 10 tempRet-s
diff --git a/src/intertyper.js b/src/intertyper.js
index 96db6966..fceeb38d 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -672,15 +672,17 @@ function intertyper(lines, sidePass, baseLineNums) {
assert((item.tokens[5].text.match(/=/g) || []).length <= 1, 'we only support at most 1 exported variable from inline js: ' + item.ident);
var i = 0;
var params = [], args = [];
- splitTokenList(tokensLeft[3].tokens).map(function(element) {
- var ident = toNiceIdent(element[1].text);
- var type = element[0].text;
- params.push('$' + (i++));
- args.push(ident);
- });
+ if (tokensLeft[3].tokens) {
+ splitTokenList(tokensLeft[3].tokens).map(function(element) {
+ var ident = toNiceIdent(element[1].text);
+ var type = element[0].text;
+ params.push('$' + (i++));
+ args.push(ident);
+ });
+ }
if (item.assignTo) item.ident = 'return ' + item.ident;
item.ident = '(function(' + params + ') { ' + item.ident + ' })(' + args + ');';
- return { forward: null, ret: item, item: item };
+ return { ret: item, item: item };
}
if (item.ident.substr(-2) == '()') {
// See comment in isStructType()
@@ -703,13 +705,12 @@ function intertyper(lines, sidePass, baseLineNums) {
if (item.indent == 2) {
// standalone call - not in assign
item.standalone = true;
- return { forward: null, ret: item, item: item };
+ return { ret: item, item: item };
}
- return { forward: item, ret: null, item: item };
+ return { ret: null, item: item };
}
function callHandler(item) {
var result = makeCall.call(this, item, 'call');
- if (result.forward) this.forwardItem(result.forward, 'Reintegrator');
return result.ret;
}
function invokeHandler(item) {
@@ -719,10 +720,9 @@ function intertyper(lines, sidePass, baseLineNums) {
finalResults.push({
intertype: 'branch',
label: result.item.toLabel,
- lineNum: (result.forward ? item.parentLineNum : item.lineNum) + 0.5
+ lineNum: item.lineNum + 0.5
});
}
- if (result.forward) this.forwardItem(result.forward, 'Reintegrator');
return result.ret;
}
function atomicHandler(item) {
diff --git a/src/jsifier.js b/src/jsifier.js
index b36e11ed..0da48a8c 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -948,11 +948,12 @@ function JSify(data, functionsOnly, givenFunctions) {
}
if (item.valueType[item.valueType.length-1] === '>') {
// vector store TODO: move to makeSetValue?
- var base = getVectorBaseType(item.valueType);
- return '(' + makeSetValue(item.ident, 0, value + '.x', base, 0, 0, item.align) + ',' +
- makeSetValue(item.ident, 4, value + '.y', base, 0, 0, item.align) + ',' +
- makeSetValue(item.ident, 8, value + '.z', base, 0, 0, item.align) + ',' +
- makeSetValue(item.ident, 12, value + '.w', base, 0, 0, item.align) + ')';
+ var native = getVectorNativeType(item.valueType);
+ var base = getSIMDName(native);
+ return '(' + makeSetValue(item.ident, 0, value + '.x', native, 0, 0, item.align) + ',' +
+ makeSetValue(item.ident, 4, value + '.y', native, 0, 0, item.align) + ',' +
+ makeSetValue(item.ident, 8, value + '.z', native, 0, 0, item.align) + ',' +
+ makeSetValue(item.ident, 12, value + '.w', native, 0, 0, item.align) + ');';
}
switch (impl) {
case VAR_NATIVIZED:
@@ -1323,11 +1324,12 @@ function JSify(data, functionsOnly, givenFunctions) {
var value = finalizeLLVMParameter(item.pointer);
if (item.valueType[item.valueType.length-1] === '>') {
// vector load
- var base = getVectorBaseType(item.valueType);
- return base + '32x4(' + makeGetValue(value, 0, base, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 4, base, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 8, base, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 12, base, 0, item.unsigned, 0, item.align) + ')';
+ var native = getVectorNativeType(item.valueType);
+ var base = getSIMDName(native);
+ return base + '32x4(' + makeGetValue(value, 0, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 4, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 8, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 12, native, 0, item.unsigned, 0, item.align) + ');';
}
var impl = item.ident ? getVarImpl(item.funcData, item.ident) : VAR_EMULATED;
switch (impl) {
@@ -1489,7 +1491,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
params.forEach(function(param, i) {
- var val = finalizeParam(param);
+ var val = finalizeLLVMParameter(param);
if (!hasVarArgs || useJSArgs || i < normalArgs) {
args.push(val);
argsTypes.push(param.type);
diff --git a/src/library.js b/src/library.js
index 875d8bab..e3cdc7c3 100644
--- a/src/library.js
+++ b/src/library.js
@@ -1579,12 +1579,12 @@ LibraryManager.library = {
// stdio.h
// ==========================================================================
- _isFloat: function(text) {
- return !!(/^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?$/.exec(text));
+ _getFloat: function(text) {
+ return /^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?/.exec(text);
},
// TODO: Document.
- _scanString__deps: ['_isFloat'],
+ _scanString__deps: ['_getFloat'],
_scanString: function(format, get, unget, varargs) {
if (!__scanString.whiteSpace) {
__scanString.whiteSpace = {};
@@ -1743,15 +1743,13 @@ LibraryManager.library = {
// Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later
if (type == 'f' || type == 'e' || type == 'g' ||
type == 'F' || type == 'E' || type == 'G') {
- var last = 0;
next = get();
- while (next > 0) {
+ while (next > 0 && (!(next in __scanString.whiteSpace))) {
buffer.push(String.fromCharCode(next));
- if (__isFloat(buffer.join(''))) {
- last = buffer.length;
- }
next = get();
}
+ var m = __getFloat(buffer.join(''));
+ var last = m ? m[0].length : 0;
for (var i = 0; i < buffer.length - last + 1; i++) {
unget();
}
@@ -8580,7 +8578,7 @@ LibraryManager.library = {
},
emscripten_run_script_string: function(ptr) {
- var s = eval(Pointer_stringify(ptr));
+ var s = eval(Pointer_stringify(ptr)) + '';
var me = _emscripten_run_script_string;
if (!me.bufferSize || me.bufferSize < s.length+1) {
if (me.bufferSize) _free(me.buffer);
@@ -8623,6 +8621,14 @@ LibraryManager.library = {
},
//============================
+ // emscripten vector ops
+ //============================
+
+ emscripten_float32x4_signmask__inline: function(x) {
+ return x + '.signMask()';
+ },
+
+ //============================
// i64 math
//============================
diff --git a/src/library_egl.js b/src/library_egl.js
index c25dc8ef..cc702fec 100644
--- a/src/library_egl.js
+++ b/src/library_egl.js
@@ -10,6 +10,8 @@ var LibraryEGL = {
$EGL: {
// This variable tracks the success status of the most recently invoked EGL function call.
eglErrorCode: 0x3000 /* EGL_SUCCESS */,
+
+ stringCache: {},
setErrorCode: function(code) {
EGL.eglErrorCode = code;
@@ -416,15 +418,19 @@ var LibraryEGL = {
}
//\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy.
EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ if (EGL.stringCache[name]) return EGL.stringCache[name];
+ var ret;
switch(name) {
- case 0x3053 /* EGL_VENDOR */: return allocate(intArrayFromString("Emscripten"), 'i8', ALLOC_NORMAL);
- case 0x3054 /* EGL_VERSION */: return allocate(intArrayFromString("1.4 Emscripten EGL"), 'i8', ALLOC_NORMAL);
- case 0x3055 /* EGL_EXTENSIONS */: return allocate(intArrayFromString(""), 'i8', ALLOC_NORMAL); // Currently not supporting any EGL extensions.
- case 0x308D /* EGL_CLIENT_APIS */: return allocate(intArrayFromString("OpenGL_ES"), 'i8', ALLOC_NORMAL);
+ case 0x3053 /* EGL_VENDOR */: ret = allocate(intArrayFromString("Emscripten"), 'i8', ALLOC_NORMAL); break;
+ case 0x3054 /* EGL_VERSION */: ret = allocate(intArrayFromString("1.4 Emscripten EGL"), 'i8', ALLOC_NORMAL); break;
+ case 0x3055 /* EGL_EXTENSIONS */: ret = allocate(intArrayFromString(""), 'i8', ALLOC_NORMAL); break; // Currently not supporting any EGL extensions.
+ case 0x308D /* EGL_CLIENT_APIS */: ret = allocate(intArrayFromString("OpenGL_ES"), 'i8', ALLOC_NORMAL); break;
default:
EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */);
return 0;
}
+ EGL.stringCache[name] = ret;
+ return ret;
},
// EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
diff --git a/src/library_fs.js b/src/library_fs.js
index bd1522a8..aece2664 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -28,6 +28,7 @@ mergeInto(LibraryManager.library, {
ignorePermissions: true,
ErrnoError: null, // set during init
+ genericErrors: {},
handleFSError: function(e) {
if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
@@ -62,7 +63,7 @@ mergeInto(LibraryManager.library, {
}
current = FS.lookupNode(current, parts[i]);
- current_path = PATH.join(current_path, parts[i]);
+ current_path = PATH.join2(current_path, parts[i]);
// jump to the mount's root node if this is a mountpoint
if (FS.isMountpoint(current)) {
@@ -94,9 +95,11 @@ mergeInto(LibraryManager.library, {
var path;
while (true) {
if (FS.isRoot(node)) {
- return path ? PATH.join(node.mount.mountpoint, path) : node.mount.mountpoint;
+ var mount = node.mount.mountpoint;
+ if (!path) return mount;
+ return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
}
- path = path ? PATH.join(node.name, path) : node.name;
+ path = path ? node.name + '/' + path : node.name;
node = node.parent;
}
},
@@ -158,44 +161,50 @@ mergeInto(LibraryManager.library, {
return FS.lookup(parent, name);
},
createNode: function(parent, name, mode, rdev) {
- var node = {
- id: FS.nextInode++,
- name: name,
- mode: mode,
- node_ops: {},
- stream_ops: {},
- rdev: rdev,
- parent: null,
- mount: null
- };
- if (!parent) {
- parent = node; // root node sets parent to itself
- }
- node.parent = parent;
- node.mount = parent.mount;
- // compatibility
- var readMode = {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
- var writeMode = {{{ cDefine('S_IWUGO') }}};
- // NOTE we must use Object.defineProperties instead of individual calls to
- // Object.defineProperty in order to make closure compiler happy
- Object.defineProperties(node, {
- read: {
- get: function() { return (node.mode & readMode) === readMode; },
- set: function(val) { val ? node.mode |= readMode : node.mode &= ~readMode; }
- },
- write: {
- get: function() { return (node.mode & writeMode) === writeMode; },
- set: function(val) { val ? node.mode |= writeMode : node.mode &= ~writeMode; }
- },
- isFolder: {
- get: function() { return FS.isDir(node.mode); },
- },
- isDevice: {
- get: function() { return FS.isChrdev(node.mode); },
- },
- });
- FS.hashAddNode(node);
- return node;
+ if (!FS.FSNode) {
+ FS.FSNode = function(parent, name, mode, rdev) {
+ this.id = FS.nextInode++;
+ this.name = name;
+ this.mode = mode;
+ this.node_ops = {};
+ this.stream_ops = {};
+ this.rdev = rdev;
+ this.parent = null;
+ this.mount = null;
+ if (!parent) {
+ parent = this; // root node sets parent to itself
+ }
+ this.parent = parent;
+ this.mount = parent.mount;
+ FS.hashAddNode(this);
+ };
+
+ // compatibility
+ var readMode = {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
+ var writeMode = {{{ cDefine('S_IWUGO') }}};
+
+ FS.FSNode.prototype = {};
+
+ // NOTE we must use Object.defineProperties instead of individual calls to
+ // Object.defineProperty in order to make closure compiler happy
+ Object.defineProperties(FS.FSNode.prototype, {
+ read: {
+ get: function() { return (this.mode & readMode) === readMode; },
+ set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+ },
+ write: {
+ get: function() { return (this.mode & writeMode) === writeMode; },
+ set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+ },
+ isFolder: {
+ get: function() { return FS.isDir(this.mode); },
+ },
+ isDevice: {
+ get: function() { return FS.isChrdev(this.mode); },
+ },
+ });
+ }
+ return new FS.FSNode(parent, name, mode, rdev);
},
destroyNode: function(node) {
FS.hashRemoveNode(node);
@@ -351,24 +360,28 @@ mergeInto(LibraryManager.library, {
// object isn't directly passed in. not possible until
// SOCKFS is completed.
createStream: function(stream, fd_start, fd_end) {
+ if (!FS.FSStream) {
+ FS.FSStream = {};
+ // compatibility
+ Object.defineProperties(FS.FSStream, {
+ object: {
+ get: function() { return this.node; },
+ set: function(val) { this.node = val; }
+ },
+ isRead: {
+ get: function() { return (this.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}; }
+ },
+ isWrite: {
+ get: function() { return (this.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}; }
+ },
+ isAppend: {
+ get: function() { return (this.flags & {{{ cDefine('O_APPEND') }}}); }
+ }
+ });
+ }
+ stream.prototype = FS.FSStream;
var fd = FS.nextfd(fd_start, fd_end);
stream.fd = fd;
- // compatibility
- Object.defineProperties(stream, {
- object: {
- get: function() { return stream.node; },
- set: function(val) { stream.node = val; }
- },
- isRead: {
- get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}; }
- },
- isWrite: {
- get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}; }
- },
- isAppend: {
- get: function() { return (stream.flags & {{{ cDefine('O_APPEND') }}}); }
- }
- });
FS.streams[fd] = stream;
return stream;
},
@@ -771,7 +784,6 @@ mergeInto(LibraryManager.library, {
});
},
open: function(path, flags, mode, fd_start, fd_end) {
- path = PATH.normalize(path);
flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
mode = typeof mode === 'undefined' ? 0666 : mode;
if ((flags & {{{ cDefine('O_CREAT') }}})) {
@@ -780,13 +792,18 @@ mergeInto(LibraryManager.library, {
mode = 0;
}
var node;
- try {
- var lookup = FS.lookupPath(path, {
- follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}})
- });
- node = lookup.node;
- } catch (e) {
- // ignore
+ if (typeof path === 'object') {
+ node = path;
+ } else {
+ path = PATH.normalize(path);
+ try {
+ var lookup = FS.lookupPath(path, {
+ follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}})
+ });
+ node = lookup.node;
+ } catch (e) {
+ // ignore
+ }
}
// perhaps we need to create the node
if ((flags & {{{ cDefine('O_CREAT') }}})) {
@@ -1079,6 +1096,11 @@ mergeInto(LibraryManager.library, {
};
FS.ErrnoError.prototype = new Error();
FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+ // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+ [ERRNO_CODES.ENOENT].forEach(function(code) {
+ FS.genericErrors[code] = new FS.ErrnoError(code);
+ FS.genericErrors[code].stack = '<generic error, no stack>';
+ });
},
staticInit: function() {
FS.ensureErrnoError();
@@ -1173,7 +1195,7 @@ mergeInto(LibraryManager.library, {
return ret;
},
createFolder: function(parent, name, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
var mode = FS.getMode(canRead, canWrite);
return FS.mkdir(path, mode);
},
@@ -1183,7 +1205,7 @@ mergeInto(LibraryManager.library, {
while (parts.length) {
var part = parts.pop();
if (!part) continue;
- var current = PATH.join(parent, part);
+ var current = PATH.join2(parent, part);
try {
FS.mkdir(current);
} catch (e) {
@@ -1194,12 +1216,12 @@ mergeInto(LibraryManager.library, {
return current;
},
createFile: function(parent, name, properties, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
var mode = FS.getMode(canRead, canWrite);
return FS.create(path, mode);
},
createDataFile: function(parent, name, data, canRead, canWrite, canOwn) {
- var path = name ? PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+ var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
var mode = FS.getMode(canRead, canWrite);
var node = FS.create(path, mode);
if (data) {
@@ -1209,16 +1231,16 @@ mergeInto(LibraryManager.library, {
data = arr;
}
// make sure we can write to the file
- FS.chmod(path, mode | {{{ cDefine('S_IWUGO') }}});
- var stream = FS.open(path, 'w');
+ FS.chmod(node, mode | {{{ cDefine('S_IWUGO') }}});
+ var stream = FS.open(node, 'w');
FS.write(stream, data, 0, data.length, 0, canOwn);
FS.close(stream);
- FS.chmod(path, mode);
+ FS.chmod(node, mode);
}
return node;
},
createDevice: function(parent, name, input, output) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
var mode = FS.getMode(!!input, !!output);
if (!FS.createDevice.major) FS.createDevice.major = 64;
var dev = FS.makedev(FS.createDevice.major++, 0);
@@ -1272,7 +1294,7 @@ mergeInto(LibraryManager.library, {
return FS.mkdev(path, mode, dev);
},
createLink: function(parent, name, target, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
return FS.symlink(target, path);
},
// Makes sure a file's contents are loaded. Returns whether the file has
@@ -1462,7 +1484,7 @@ mergeInto(LibraryManager.library, {
Browser.init();
// TODO we should allow people to just pass in a complete filename instead
// of parent and name being that we just join them anyways
- var fullname = name ? PATH.resolve(PATH.join(parent, name)) : parent;
+ var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
function processData(byteArray) {
function finish(byteArray) {
if (!dontCreateFile) {
diff --git a/src/library_gl.js b/src/library_gl.js
index 1ea8efc2..76501111 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -42,6 +42,8 @@ var LibraryGL = {
uniformTable: {}, // name => uniform ID. the uID must be identical until relinking, cannot create a new uID each call to glGetUniformLocation
+ stringCache: {},
+
packAlignment: 4, // default alignment is 4 bytes
unpackAlignment: 4, // default alignment is 4 bytes
@@ -240,7 +242,9 @@ var LibraryGL = {
sizePerPixel = 2;
break;
case 0x1406 /* GL_FLOAT */:
+#if ASSERTIONS
assert(GL.floatExt, 'Must have OES_texture_float to use float textures');
+#endif
switch (format) {
case 0x1907 /* GL_RGB */:
sizePerPixel = 3*4;
@@ -497,11 +501,14 @@ var LibraryGL = {
glGetString__sig: 'ii',
glGetString: function(name_) {
+ if (GL.stringCache[name_]) return GL.stringCache[name_];
+ var ret;
switch(name_) {
case 0x1F00 /* GL_VENDOR */:
case 0x1F01 /* GL_RENDERER */:
case 0x1F02 /* GL_VERSION */:
- return allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
+ ret = allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
+ break;
case 0x1F03 /* GL_EXTENSIONS */:
var exts = Module.ctx.getSupportedExtensions();
var gl_exts = [];
@@ -509,12 +516,16 @@ var LibraryGL = {
gl_exts.push(exts[i]);
gl_exts.push("GL_" + exts[i]);
}
- return allocate(intArrayFromString(gl_exts.join(' ')), 'i8', ALLOC_NORMAL); // XXX this leaks! TODO: Cache all results like this in library_gl.js to be clean and nice and avoid leaking.
+ ret = allocate(intArrayFromString(gl_exts.join(' ')), 'i8', ALLOC_NORMAL);
+ break;
case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */:
- return allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL);
+ ret = allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL);
+ break;
default:
throw 'Failure: Invalid glGetString value: ' + name_;
}
+ GL.stringCache[name_] = ret;
+ return ret;
},
glGetIntegerv__sig: 'vii',
@@ -680,7 +691,9 @@ var LibraryGL = {
glCompressedTexImage2D__sig: 'viiiiiiii',
glCompressedTexImage2D: function(target, level, internalFormat, width, height, border, imageSize, data) {
+#if ASSERTIONS
assert(GL.compressionExt);
+#endif
if (data) {
data = {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}};
} else {
@@ -691,7 +704,9 @@ var LibraryGL = {
glCompressedTexSubImage2D__sig: 'viiiiiiiii',
glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) {
+#if ASSERTIONS
assert(GL.compressionExt);
+#endif
if (data) {
data = {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}};
} else {
@@ -725,7 +740,9 @@ var LibraryGL = {
glReadPixels__sig: 'viiiiiii',
glReadPixels: function(x, y, width, height, format, type, pixels) {
+#if ASSERTIONS
assert(type == 0x1401 /* GL_UNSIGNED_BYTE */);
+#endif
var sizePerPixel;
switch (format) {
case 0x1907 /* GL_RGB */:
@@ -1357,7 +1374,9 @@ var LibraryGL = {
{{{ makeSetValue('count', '0', 'len', 'i32') }}};
for (var i = 0; i < len; ++i) {
var id = GL.shaders.indexOf(result[i]);
+#if ASSERTIONS
assert(id !== -1, 'shader not bound to local id');
+#endif
{{{ makeSetValue('shaders', 'i*4', 'id', 'i32') }}};
}
},
@@ -1794,13 +1813,16 @@ var LibraryGL = {
var glGetString = _glGetString;
_glGetString = function(name_) {
+ if (GL.stringCache[name_]) return GL.stringCache[name_];
switch(name_) {
case 0x1F03 /* GL_EXTENSIONS */: // Add various extensions that we can support
- return allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') +
+ var ret = allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') +
' GL_EXT_texture_env_combine GL_ARB_texture_env_crossbar GL_ATI_texture_env_combine3 GL_NV_texture_env_combine4 GL_EXT_texture_env_dot3 GL_ARB_multitexture GL_ARB_vertex_buffer_object GL_EXT_framebuffer_object GL_ARB_vertex_program GL_ARB_fragment_program GL_ARB_shading_language_100 GL_ARB_shader_objects GL_ARB_vertex_shader GL_ARB_fragment_shader GL_ARB_texture_cube_map GL_EXT_draw_range_elements' +
(GL.compressionExt ? ' GL_ARB_texture_compression GL_EXT_texture_compression_s3tc' : '') +
(GL.anisotropicExt ? ' GL_EXT_texture_filter_anisotropic' : '')
), 'i8', ALLOC_NORMAL);
+ GL.stringCache[name_] = ret;
+ return ret;
}
return glGetString(name_);
};
@@ -2013,7 +2035,9 @@ var LibraryGL = {
glBindBuffer(target, buffer);
if (target == Module.ctx.ARRAY_BUFFER) {
if (GLEmulation.currentVao) {
+#if ASSERTIONS
assert(GLEmulation.currentVao.arrayBuffer == buffer || GLEmulation.currentVao.arrayBuffer == 0 || buffer == 0, 'TODO: support for multiple array buffers in vao');
+#endif
GLEmulation.currentVao.arrayBuffer = buffer;
}
} else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
@@ -2153,7 +2177,9 @@ var LibraryGL = {
glBindProgram__sig: 'vii',
glBindProgram: function(type, id) {
+#if ASSERTIONS
assert(id == 0);
+#endif
},
glGetPointerv: function(name, p) {
@@ -2832,9 +2858,9 @@ var LibraryGL = {
} else if (gl) {
maxTexUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
}
-
+#if ASSERTIONS
assert(maxTexUnits > 0);
-
+#endif
s_texUnits = [];
for (var i = 0; i < maxTexUnits; i++) {
s_texUnits.push(new CTexUnit());
@@ -2893,9 +2919,10 @@ var LibraryGL = {
},
getTexUnitType: function(texUnitID) {
+#if ASSERTIONS
assert(texUnitID >= 0 &&
texUnitID < s_texUnits.length);
-
+#endif
return s_texUnits[texUnitID].getTexType();
},
@@ -3198,9 +3225,13 @@ var LibraryGL = {
if (!GL.immediate.enabledClientAttributes[texAttribName])
continue;
+#if ASSERTIONS
if (!useCurrProgram) {
- assert(GL.immediate.TexEnvJIT.getTexUnitType(i) != 0, "GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline.");
+ if (GL.immediate.TexEnvJIT.getTexUnitType(i) == 0) {
+ Runtime.warnOnce("GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline.");
+ }
}
+#endif
textureSizes[i] = GL.immediate.clientAttributes[texAttribName].size;
textureTypes[i] = GL.immediate.clientAttributes[texAttribName].type;
@@ -3417,7 +3448,9 @@ var LibraryGL = {
if (!GL.currArrayBuffer) {
var start = GL.immediate.firstVertex*GL.immediate.stride;
var end = GL.immediate.lastVertex*GL.immediate.stride;
+#if ASSERTIONS
assert(end <= GL.MAX_TEMP_BUFFER_SIZE, 'too much vertex data');
+#endif
arrayBuffer = GL.tempVertexBuffers[GL.tempBufferIndexLookup[end]];
// TODO: consider using the last buffer we bound, if it was larger. downside is larger buffer, but we might avoid rebinding and preparing
} else {
@@ -3586,10 +3619,10 @@ var LibraryGL = {
Module.ctx.drawElements(mode, count, type, indices);
return;
}
+#if ASSERTIONS
if (!GL.currElementArrayBuffer) {
assert(type == Module.ctx.UNSIGNED_SHORT); // We can only emulate buffers of this kind, for now
}
-#if ASSERTIONS
console.log("DrawElements doesn't actually prepareClientAttributes properly.");
#endif
GL.immediate.prepareClientAttributes(count, false);
@@ -3797,13 +3830,17 @@ var LibraryGL = {
if (!attribute) break;
attribute.offset = attribute.pointer - start;
if (attribute.offset > bytes) { // ensure we start where we should
+#if ASSERTIONS
assert((attribute.offset - bytes)%4 == 0); // XXX assuming 4-alignment
+#endif
bytes += attribute.offset - bytes;
}
bytes += attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot];
if (bytes % 4 != 0) bytes += 4 - (bytes % 4); // XXX assuming 4-alignment
}
+#if ASSERTIONS
assert(beginEnd || bytes <= stride); // if not begin-end, explicit stride should make sense with total byte size
+#endif
if (bytes < stride) { // ensure the size is that of the stride
bytes = stride;
}
@@ -3830,18 +3867,21 @@ var LibraryGL = {
// Generate index data in a format suitable for GLES 2.0/WebGL
var numVertexes = 4 * this.vertexCounter / GL.immediate.stride;
+#if ASSERTIONS
assert(numVertexes % 1 == 0, "`numVertexes` must be an integer.");
-
+#endif
var emulatedElementArrayBuffer = false;
var numIndexes = 0;
if (numProvidedIndexes) {
numIndexes = numProvidedIndexes;
if (!GL.currArrayBuffer && GL.immediate.firstVertex > GL.immediate.lastVertex) {
// Figure out the first and last vertex from the index data
+#if ASSERTIONS
assert(!GL.currElementArrayBuffer); // If we are going to upload array buffer data, we need to find which range to
// upload based on the indices. If they are in a buffer on the GPU, that is very
// inconvenient! So if you do not have an array buffer, you should also not have
// an element array buffer. But best is to use both buffers!
+#endif
for (var i = 0; i < numProvidedIndexes; i++) {
var currIndex = {{{ makeGetValue('ptr', 'i*2', 'i16', null, 1) }}};
GL.immediate.firstVertex = Math.min(GL.immediate.firstVertex, currIndex);
@@ -3850,7 +3890,9 @@ var LibraryGL = {
}
if (!GL.currElementArrayBuffer) {
// If no element array buffer is bound, then indices is a literal pointer to clientside data
+#if ASSERTIONS
assert(numProvidedIndexes << 1 <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (a)');
+#endif
var indexBuffer = GL.tempIndexBuffers[GL.tempBufferIndexLookup[numProvidedIndexes << 1]];
Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, indexBuffer);
Module.ctx.bufferSubData(Module.ctx.ELEMENT_ARRAY_BUFFER, 0, {{{ makeHEAPView('U16', 'ptr', 'ptr + (numProvidedIndexes << 1)') }}});
@@ -3862,11 +3904,15 @@ var LibraryGL = {
// GL.immediate.firstVertex is the first vertex we want. Quad indexes are in the pattern
// 0 1 2, 0 2 3, 4 5 6, 4 6 7, so we need to look at index firstVertex * 1.5 to see it.
// Then since indexes are 2 bytes each, that means 3
+#if ASSERTIONS
assert(GL.immediate.firstVertex % 4 == 0);
+#endif
ptr = GL.immediate.firstVertex*3;
var numQuads = numVertexes / 4;
numIndexes = numQuads * 6; // 0 1 2, 0 2 3 pattern
+#if ASSERTIONS
assert(ptr + (numIndexes << 1) <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (b)');
+#endif
Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer);
emulatedElementArrayBuffer = true;
}
diff --git a/src/library_glfw.js b/src/library_glfw.js
index b0519e39..647d4bb6 100644
--- a/src/library_glfw.js
+++ b/src/library_glfw.js
@@ -355,7 +355,9 @@ var LibraryGLFW = {
}
var contextAttributes = {
- antialias: (GLFW.params[0x00020013] > 1) //GLFW_FSAA_SAMPLES
+ antialias: (GLFW.params[0x00020013] > 1), //GLFW_FSAA_SAMPLES
+ depth: (GLFW.params[0x00020009] > 0), //GLFW_DEPTH_BITS
+ stencil: (GLFW.params[0x0002000A] > 0) //GLFW_STENCIL_BITS
}
Module.ctx = Browser.createContext(Module['canvas'], true, true, contextAttributes);
return 1; //GL_TRUE
diff --git a/src/library_glut.js b/src/library_glut.js
index 722ea85c..fefe7bd3 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -427,7 +427,9 @@ var LibraryGLUT = {
glutCreateWindow__deps: ['$Browser'],
glutCreateWindow: function(name) {
var contextAttributes = {
- antialias: ((GLUT.initDisplayMode & 0x0080 /*GLUT_MULTISAMPLE*/) != 0)
+ antialias: ((GLUT.initDisplayMode & 0x0080 /*GLUT_MULTISAMPLE*/) != 0),
+ depth: ((GLUT.initDisplayMode & 0x0010 /*GLUT_DEPTH*/) != 0),
+ stencil: ((GLUT.initDisplayMode & 0x0020 /*GLUT_STENCIL*/) != 0)
};
Module.ctx = Browser.createContext(Module['canvas'], true, true, contextAttributes);
return Module.ctx ? 1 /* a new GLUT window ID for the created context */ : 0 /* failure */;
diff --git a/src/library_idbfs.js b/src/library_idbfs.js
index 9031bad8..ab55673f 100644
--- a/src/library_idbfs.js
+++ b/src/library_idbfs.js
@@ -130,7 +130,7 @@ mergeInto(LibraryManager.library, {
};
var toAbsolute = function(root) {
return function(p) {
- return PATH.join(root, p);
+ return PATH.join2(root, p);
}
};
diff --git a/src/library_memfs.js b/src/library_memfs.js
index 94fd767e..9f528108 100644
--- a/src/library_memfs.js
+++ b/src/library_memfs.js
@@ -1,6 +1,8 @@
mergeInto(LibraryManager.library, {
$MEMFS__deps: ['$FS'],
$MEMFS: {
+ ops_table: null,
+
// content modes
CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it, without copying (note: someone else needs to free() it, if that is necessary)
CONTENT_FLEXIBLE: 2, // has been modified or never set to anything, and is a flexible js array that can grow/shrink
@@ -13,51 +15,71 @@ mergeInto(LibraryManager.library, {
// no supported
throw new FS.ErrnoError(ERRNO_CODES.EPERM);
}
+ if (!MEMFS.ops_table) {
+ MEMFS.ops_table = {
+ dir: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ lookup: MEMFS.node_ops.lookup,
+ mknod: MEMFS.node_ops.mknod,
+ mknod: MEMFS.node_ops.mknod,
+ rename: MEMFS.node_ops.rename,
+ unlink: MEMFS.node_ops.unlink,
+ rmdir: MEMFS.node_ops.rmdir,
+ readdir: MEMFS.node_ops.readdir,
+ symlink: MEMFS.node_ops.symlink
+ },
+ stream: {
+ llseek: MEMFS.stream_ops.llseek
+ }
+ },
+ file: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ },
+ stream: {
+ llseek: MEMFS.stream_ops.llseek,
+ read: MEMFS.stream_ops.read,
+ write: MEMFS.stream_ops.write,
+ allocate: MEMFS.stream_ops.allocate,
+ mmap: MEMFS.stream_ops.mmap
+ }
+ },
+ link: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ readlink: MEMFS.node_ops.readlink
+ },
+ stream: {}
+ },
+ chrdev: {
+ node: {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ },
+ stream: FS.chrdev_stream_ops
+ },
+ };
+ }
var node = FS.createNode(parent, name, mode, dev);
if (FS.isDir(node.mode)) {
- node.node_ops = {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr,
- lookup: MEMFS.node_ops.lookup,
- mknod: MEMFS.node_ops.mknod,
- mknod: MEMFS.node_ops.mknod,
- rename: MEMFS.node_ops.rename,
- unlink: MEMFS.node_ops.unlink,
- rmdir: MEMFS.node_ops.rmdir,
- readdir: MEMFS.node_ops.readdir,
- symlink: MEMFS.node_ops.symlink
- };
- node.stream_ops = {
- llseek: MEMFS.stream_ops.llseek
- };
+ node.node_ops = MEMFS.ops_table.dir.node;
+ node.stream_ops = MEMFS.ops_table.dir.stream;
node.contents = {};
} else if (FS.isFile(node.mode)) {
- node.node_ops = {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr
- };
- node.stream_ops = {
- llseek: MEMFS.stream_ops.llseek,
- read: MEMFS.stream_ops.read,
- write: MEMFS.stream_ops.write,
- allocate: MEMFS.stream_ops.allocate,
- mmap: MEMFS.stream_ops.mmap
- };
+ node.node_ops = MEMFS.ops_table.file.node;
+ node.stream_ops = MEMFS.ops_table.file.stream;
node.contents = [];
node.contentMode = MEMFS.CONTENT_FLEXIBLE;
} else if (FS.isLink(node.mode)) {
- node.node_ops = {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr,
- readlink: MEMFS.node_ops.readlink
- };
- node.stream_ops = {};
+ node.node_ops = MEMFS.ops_table.link.node;
+ node.stream_ops = MEMFS.ops_table.link.stream;
} else if (FS.isChrdev(node.mode)) {
- node.node_ops = {
- getattr: MEMFS.node_ops.getattr,
- setattr: MEMFS.node_ops.setattr
- };
- node.stream_ops = FS.chrdev_stream_ops;
+ node.node_ops = MEMFS.ops_table.chrdev.node;
+ node.stream_ops = MEMFS.ops_table.chrdev.stream;
}
node.timestamp = Date.now();
// add the new node to the parent
@@ -117,7 +139,7 @@ mergeInto(LibraryManager.library, {
}
},
lookup: function(parent, name) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+ throw FS.genericErrors[ERRNO_CODES.ENOENT];
},
mknod: function(parent, name, mode, dev) {
return MEMFS.createNode(parent, name, mode, dev);
@@ -200,7 +222,9 @@ mergeInto(LibraryManager.library, {
#if USE_TYPED_ARRAYS == 2
if (length && contents.length === 0 && position === 0 && buffer.subarray) {
// just replace it with the new data
+#if ASSERTIONS
assert(buffer.length);
+#endif
if (canOwn && buffer.buffer === HEAP8.buffer && offset === 0) {
node.contents = buffer; // this is a subarray of the heap, and we can own it
node.contentMode = MEMFS.CONTENT_OWNING;
diff --git a/src/library_nodefs.js b/src/library_nodefs.js
index 2be54076..7686f3f2 100644
--- a/src/library_nodefs.js
+++ b/src/library_nodefs.js
@@ -134,7 +134,7 @@ mergeInto(LibraryManager.library, {
}
},
lookup: function (parent, name) {
- var path = PATH.join(NODEFS.realPath(parent), name);
+ var path = PATH.join2(NODEFS.realPath(parent), name);
var mode = NODEFS.getMode(path);
return NODEFS.createNode(parent, name, mode);
},
@@ -156,7 +156,7 @@ mergeInto(LibraryManager.library, {
},
rename: function (oldNode, newDir, newName) {
var oldPath = NODEFS.realPath(oldNode);
- var newPath = PATH.join(NODEFS.realPath(newDir), newName);
+ var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
try {
fs.renameSync(oldPath, newPath);
} catch (e) {
@@ -165,7 +165,7 @@ mergeInto(LibraryManager.library, {
}
},
unlink: function(parent, name) {
- var path = PATH.join(NODEFS.realPath(parent), name);
+ var path = PATH.join2(NODEFS.realPath(parent), name);
try {
fs.unlinkSync(path);
} catch (e) {
@@ -174,7 +174,7 @@ mergeInto(LibraryManager.library, {
}
},
rmdir: function(parent, name) {
- var path = PATH.join(NODEFS.realPath(parent), name);
+ var path = PATH.join2(NODEFS.realPath(parent), name);
try {
fs.rmdirSync(path);
} catch (e) {
@@ -192,7 +192,7 @@ mergeInto(LibraryManager.library, {
}
},
symlink: function(parent, newName, oldPath) {
- var newPath = PATH.join(NODEFS.realPath(parent), newName);
+ var newPath = PATH.join2(NODEFS.realPath(parent), newName);
try {
fs.symlinkSync(oldPath, newPath);
} catch (e) {
@@ -283,4 +283,4 @@ mergeInto(LibraryManager.library, {
}
}
}
-}); \ No newline at end of file
+});
diff --git a/src/library_path.js b/src/library_path.js
index 09808acd..f00a7586 100644
--- a/src/library_path.js
+++ b/src/library_path.js
@@ -59,26 +59,22 @@ mergeInto(LibraryManager.library, {
}
return root + dir;
},
- basename: function(path, ext) {
+ basename: function(path) {
// EMSCRIPTEN return '/'' for '/', not an empty string
if (path === '/') return '/';
- var f = PATH.splitPath(path)[2];
- if (ext && f.substr(-1 * ext.length) === ext) {
- f = f.substr(0, f.length - ext.length);
- }
- return f;
+ var lastSlash = path.lastIndexOf('/');
+ if (lastSlash === -1) return path;
+ return path.substr(lastSlash+1);
},
extname: function(path) {
return PATH.splitPath(path)[3];
},
join: function() {
var paths = Array.prototype.slice.call(arguments, 0);
- return PATH.normalize(paths.filter(function(p, index) {
- if (typeof p !== 'string') {
- throw new TypeError('Arguments to path.join must be strings');
- }
- return p;
- }).join('/'));
+ return PATH.normalize(paths.join('/'));
+ },
+ join2: function(l, r) {
+ return PATH.normalize(l + '/' + r);
},
resolve: function() {
var resolvedPath = '',
@@ -134,4 +130,4 @@ mergeInto(LibraryManager.library, {
return outputParts.join('/');
}
}
-}); \ No newline at end of file
+});
diff --git a/src/library_sdl.js b/src/library_sdl.js
index a0689343..04a66351 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -153,24 +153,30 @@ var LibrarySDL = {
120: 27,
121: 28,
122: 29, // Z
- 44: 54, // comma
- 46: 55, // period
- 47: 56, // slash
- 49: 30, // 1
- 50: 31,
- 51: 32,
- 52: 33,
- 53: 34,
- 54: 35,
- 55: 36,
- 56: 37,
- 57: 38, // 9
- 48: 39, // 0
- 13: 40, // return
- 9: 43, // tab
- 27: 41, // escape
- 32: 44, // space
- 92: 49, // backslash
+ 49: 30, // 1
+ 50: 31,
+ 51: 32,
+ 52: 33,
+ 53: 34,
+ 54: 35,
+ 55: 36,
+ 56: 37,
+ 57: 38, // 9
+ 48: 39, // 0
+ 13: 40, // return
+ 27: 41, // escape
+ 8: 42, // backspace
+ 9: 43, // tab
+ 32: 44, // space
+ 61: 46, // equals
+ 91: 47, // left bracket
+ 93: 48, // right bracket
+ 92: 49, // backslash
+ 59: 51, // ;
+ 96: 52, // apostrophe
+ 44: 54, // comma
+ 46: 55, // period
+ 47: 56, // slash
305: 224, // ctrl
308: 226, // alt
},
@@ -254,9 +260,13 @@ var LibrarySDL = {
}
var webGLContextAttributes = {
- antialias: ((SDL.glAttributes[13 /*SDL_GL_MULTISAMPLEBUFFERS*/] != 0) && (SDL.glAttributes[14 /*SDL_GL_MULTISAMPLESAMPLES*/] > 1))
+ antialias: ((SDL.glAttributes[13 /*SDL_GL_MULTISAMPLEBUFFERS*/] != 0) && (SDL.glAttributes[14 /*SDL_GL_MULTISAMPLESAMPLES*/] > 1)),
+ depth: (SDL.glAttributes[6 /*SDL_GL_DEPTH_SIZE*/] > 0),
+ stencil: (SDL.glAttributes[7 /*SDL_GL_STENCIL_SIZE*/] > 0)
};
+
var ctx = Browser.createContext(canvas, useWebGL, usePageCanvas, webGLContextAttributes);
+
SDL.surfaces[surf] = {
width: width,
height: height,
@@ -786,6 +796,14 @@ var LibrarySDL = {
['mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'mouseout'].forEach(function(event) {
Module['canvas'].addEventListener(event, SDL.receiveEvent, true);
});
+
+ // (0,0) means 'use fullscreen' in native; in Emscripten, use the current canvas size.
+ if (width == 0 && height == 0) {
+ var canvas = Module['canvas'];
+ width = canvas.width;
+ height = canvas.height;
+ }
+
Browser.setCanvasSize(width, height, true);
// Free the old surface first.
if (SDL.screen) {
diff --git a/src/parseTools.js b/src/parseTools.js
index dae386f1..ec907a41 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -157,6 +157,10 @@ function isStructType(type) {
return type[0] == '%';
}
+function isVectorType(type) {
+ return type[type.length-1] === '>';
+}
+
function isStructuralType(type) {
return /^{ ?[^}]* ?}$/.test(type); // { i32, i8 } etc. - anonymous struct types
}
@@ -215,8 +219,22 @@ function isIdenticallyImplemented(type1, type2) {
}
function isIllegalType(type) {
- var bits = getBits(type);
- return bits > 0 && (bits >= 64 || !isPowerOfTwo(bits));
+ switch (type) {
+ case 'i1':
+ case 'i8':
+ case 'i16':
+ case 'i32':
+ case 'float':
+ case 'double':
+ case 'rawJS':
+ case '<2 x float>':
+ case '<4 x float>':
+ case '<2 x i32>':
+ case '<4 x i32>':
+ case 'void': return false;
+ }
+ if (!type || type[type.length-1] === '*') return false;
+ return true;
}
function isVoidType(type) {
@@ -287,6 +305,9 @@ function getReturnType(type) {
if (pointingLevels(type) > 1) return '*'; // the type of a call can be either the return value, or the entire function. ** or more means it is a return value
var lastOpen = type.lastIndexOf('(');
if (lastOpen > 0) {
+ // handle things like void (i32)* (i32, void (i32)*)*
+ var closeStar = type.indexOf(')*');
+ if (closeStar > 0 && closeStar < type.length-2) lastOpen = closeStar+3;
return type.substr(0, lastOpen-1);
}
return type;
@@ -328,28 +349,29 @@ function getVectorSize(type) {
return parseInt(type.substring(1, type.indexOf(' ')));
}
-function getVectorBaseType(type) {
+function getVectorNativeType(type) {
Types.usesSIMD = true;
switch (type) {
case '<2 x float>':
case '<4 x float>': return 'float';
case '<2 x i32>':
- case '<4 x i32>': return 'uint';
+ case '<4 x i32>': return 'i32';
default: throw 'unknown vector type ' + type;
}
}
-function getVectorNativeType(type) {
- Types.usesSIMD = true;
+function getSIMDName(type) {
switch (type) {
- case '<2 x float>':
- case '<4 x float>': return 'float';
- case '<2 x i32>':
- case '<4 x i32>': return 'i32';
- default: throw 'unknown vector type ' + type;
+ case 'i32': return 'uint';
+ case 'float': return 'float';
+ default: throw 'getSIMDName ' + type;
}
}
+function getVectorBaseType(type) {
+ return getSIMDName(getVectorNativeType(type));
+}
+
function addIdent(token) {
token.ident = token.text;
return token;
@@ -465,26 +487,13 @@ function parseParamTokens(params) {
Types.needAnalysis[ret[ret.length-1].type] = 0;
anonymousIndex ++;
}
- } else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) {
- ret.push(parseLLVMFunctionCall(segment));
- } else if (segment[1].text === 'blockaddress') {
- ret.push(parseBlockAddress(segment));
- } else if (segment[1].type && segment[1].type == '{') {
- ret.push(parseLLVMSegment(segment));
} else {
if (segment[2] && segment[2].text == 'to') { // part of bitcast params
segment = segment.slice(0, 2);
}
- while (segment.length > 2) {
- segment[0].text += segment[1].text;
- segment.splice(1, 1); // TODO: merge tokens nicely
- }
- ret.push({
- intertype: 'value',
- type: segment[0].text,
- ident: toNiceIdent(parseNumerical(segment[1].text, segment[0].text))
- });
- Types.needAnalysis[removeAllPointing(ret[ret.length-1].type)] = 0;
+ var parsed = parseLLVMSegment(segment);
+ if (parsed.intertype === 'value' && !isIllegalType(parsed.type)) parsed.ident = parseNumerical(parsed.ident, parsed.type);
+ ret.push(parsed);
}
ret[ret.length-1].byVal = byVal;
}
@@ -558,25 +567,6 @@ function sortGlobals(globals) {
});
}
-function finalizeParam(param) {
- if (param.intertype in PARSABLE_LLVM_FUNCTIONS) {
- return finalizeLLVMFunctionCall(param);
- } else if (param.intertype === 'blockaddress') {
- return finalizeBlockAddress(param);
- } else if (param.intertype === 'jsvalue') {
- return param.ident;
- } else {
- if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) {
- return parseI64Constant(param.ident);
- }
- var ret = toNiceIdent(param.ident);
- if (ret in Variables.globals) {
- ret = makeGlobalUse(ret);
- }
- return ret;
- }
-}
-
// Segment ==> Parameter
function parseLLVMSegment(segment) {
var type;
@@ -1009,11 +999,9 @@ function getOldLabel(label) {
}
function calcAllocatedSize(type) {
- if (pointingLevels(type) == 0 && isStructType(type)) {
- return Types.types[type].flatSize; // makeEmptyStruct(item.allocatedType).length;
- } else {
- return Runtime.getNativeTypeSize(type); // We can really get away with '1', though, at least on the stack...
- }
+ var ret = Runtime.getNativeTypeSize(type);
+ if (ret) return ret;
+ return Types.types[type].flatSize; // known type
}
// Generates the type signature for a structure, for each byte, the type that is there.
@@ -1809,7 +1797,7 @@ function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
switch(type) {
case 'i1': case 'i8': return [unsigned ? 'HEAPU8' : 'HEAP8']; break;
case 'i16': return [unsigned ? 'HEAPU16' : 'HEAP16']; break;
- case '<4 x i32>': case 'uint':
+ case '<4 x i32>':
case 'i32': case 'i64': return [unsigned ? 'HEAPU32' : 'HEAP32']; break;
case 'double': {
if (TARGET_LE32) return ['HEAPF64']; // in le32, we do have the ability to assume 64-bit alignment
@@ -2002,6 +1990,8 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) {
} else if (param.ident == 'zeroinitializer') {
if (isStructType(param.type)) {
return makeLLVMStruct(zeros(Types.types[param.type].fields.length));
+ } else if (isVectorType(param.type)) {
+ return ensureVector(0, getVectorBaseType(param.type));
} else {
return '0';
}
@@ -2024,7 +2014,7 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) {
} else if (param.intertype == 'mathop') {
return processMathop(param);
} else if (param.intertype === 'vector') {
- return 'float32x4(' + param.idents.join(',') + ')';
+ return getVectorBaseType(param.type) + '32x4(' + param.idents.join(',') + ')';
} else {
throw 'invalid llvm parameter: ' + param.intertype;
}
diff --git a/src/preamble.js b/src/preamble.js
index ee273f6a..9e72e7b8 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -1107,19 +1107,21 @@ var Math_min = Math.min;
// it happens right before run - run will be postponed until
// the dependencies are met.
var runDependencies = 0;
-var runDependencyTracking = {};
var runDependencyWatcher = null;
var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+#if ASSERTIONS
+var runDependencyTracking = {};
+#endif
function addRunDependency(id) {
runDependencies++;
if (Module['monitorRunDependencies']) {
Module['monitorRunDependencies'](runDependencies);
}
+#if ASSERTIONS
if (id) {
assert(!runDependencyTracking[id]);
runDependencyTracking[id] = 1;
-#if ASSERTIONS
if (runDependencyWatcher === null && typeof setInterval !== 'undefined') {
// Check for missing dependencies every few seconds
runDependencyWatcher = setInterval(function() {
@@ -1136,10 +1138,10 @@ function addRunDependency(id) {
}
}, 10000);
}
-#endif
} else {
Module.printErr('warning: run dependency added without ID');
}
+#endif
}
Module['addRunDependency'] = addRunDependency;
function removeRunDependency(id) {
@@ -1147,12 +1149,14 @@ function removeRunDependency(id) {
if (Module['monitorRunDependencies']) {
Module['monitorRunDependencies'](runDependencies);
}
+#if ASSERTIONS
if (id) {
assert(runDependencyTracking[id]);
delete runDependencyTracking[id];
} else {
Module.printErr('warning: run dependency removed without ID');
}
+#endif
if (runDependencies == 0) {
if (runDependencyWatcher !== null) {
clearInterval(runDependencyWatcher);
diff --git a/src/runtime.js b/src/runtime.js
index fa127fe7..ca2304da 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -145,7 +145,7 @@ var Runtime = {
//! @param type The type, by name.
getNativeTypeSize: function(type) {
#if QUANTUM_SIZE == 1
- return 1;
+ return 1;
#else
switch (type) {
case 'i1': case 'i8': return 1;
@@ -161,6 +161,8 @@ var Runtime = {
var bits = parseInt(type.substr(1));
assert(bits % 8 === 0);
return bits/8;
+ } else {
+ return 0;
}
}
}
@@ -224,9 +226,16 @@ var Runtime = {
// bN, large number field, like a [N x i8]
size = field.substr(1)|0;
alignSize = 1;
- } else {
- assert(field[0] === '<', field); // assumed to be a vector type, if none of the above
+ } else if (field[0] === '<') {
+ // vector type
size = alignSize = Types.types[field].flatSize; // fully aligned
+ } else if (field[0] === 'i') {
+ // illegal integer field, that could not be legalized because it is an internal structure field
+ // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+ size = alignSize = parseInt(field.substr(1))/8;
+ assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+ } else {
+ assert(false, 'invalid type for calculateStructAlignment');
}
if (type.packed) alignSize = 1;
type.alignSize = Math.max(type.alignSize, alignSize);
diff --git a/src/shell.html b/src/shell.html
index ff5f6e35..53a4fffb 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -63,8 +63,11 @@
},
canvas: document.getElementById('canvas'),
setStatus: function(text) {
- if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
+ if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
+ if (text === Module.setStatus.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
+ var now = Date.now();
+ if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
if (m) {
@@ -87,6 +90,6 @@
};
Module.setStatus('Downloading...');
</script>
- <script async type='text/javascript'>{{{ SCRIPT_CODE }}}</script>
+ {{{ SCRIPT }}}
</body>
</html>
diff --git a/system/include/compat/ctype.h b/system/include/compat/ctype.h
index 891006d9..3f504946 100644
--- a/system/include/compat/ctype.h
+++ b/system/include/compat/ctype.h
@@ -14,4 +14,21 @@
#include_next <ctype.h>
+/* We undef these until libcxx is fixed. Without this,
+ some things can fail to compile correctly, like
+ Boost. Issue #1716. */
+
+#undef isalpha
+#undef isblank
+#undef iscntrl
+#undef isdigit
+#undef isgraph
+#undef islower
+#undef isprint
+#undef ispunct
+#undef isspace
+#undef isupper
+#undef isxdigit
+#undef isctype
+
#endif /* _COMPAT_CTYPE_H_ */
diff --git a/system/include/compat/wchar.h b/system/include/compat/wchar.h
new file mode 100644
index 00000000..42f0bcee
--- /dev/null
+++ b/system/include/compat/wchar.h
@@ -0,0 +1,23 @@
+#ifndef _COMPAT_WCHAR_H_
+#define _COMPAT_WCHAR_H_
+
+#include_next <wchar.h>
+
+/* We undef these until libcxx is fixed. Without this,
+ some things can fail to compile correctly, like
+ Boost. Issue #1716. */
+
+#undef iswalpha
+#undef iswblank
+#undef iswcntrl
+#undef iswdigit
+#undef iswgraph
+#undef iswlower
+#undef iswprint
+#undef iswpunct
+#undef iswspace
+#undef iswupper
+#undef iswxdigit
+#undef iswctype
+
+#endif /* _COMPAT_WCHAR_H_ */
diff --git a/system/include/compat/wctype.h b/system/include/compat/wctype.h
new file mode 100644
index 00000000..0eeaab8b
--- /dev/null
+++ b/system/include/compat/wctype.h
@@ -0,0 +1,23 @@
+#ifndef _COMPAT_WCTYPE_H_
+#define _COMPAT_WCTYPE_H_
+
+#include_next <wctype.h>
+
+/* We undef these until libcxx is fixed. Without this,
+ some things can fail to compile correctly, like
+ Boost. Issue #1716. */
+
+#undef iswalpha
+#undef iswblank
+#undef iswcntrl
+#undef iswdigit
+#undef iswgraph
+#undef iswlower
+#undef iswprint
+#undef iswpunct
+#undef iswspace
+#undef iswupper
+#undef iswxdigit
+#undef iswctype
+
+#endif /* _COMPAT_WCTYPE_H_ */
diff --git a/system/include/emscripten/vector.h b/system/include/emscripten/vector.h
index ea148f0d..938f2369 100644
--- a/system/include/emscripten/vector.h
+++ b/system/include/emscripten/vector.h
@@ -4,3 +4,13 @@
typedef float float32x4 __attribute__((__vector_size__(16)));
typedef unsigned int uint32x4 __attribute__((__vector_size__(16)));
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned int emscripten_float32x4_signmask(float32x4 x);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/tests/aniso.c b/tests/aniso.c
index e8d7bd3f..f1674cad 100644
--- a/tests/aniso.c
+++ b/tests/aniso.c
@@ -66,6 +66,9 @@ int main(int argc, char *argv[])
const char *exts = (const char *)glGetString(GL_EXTENSIONS);
assert(hasext(exts, "GL_EXT_texture_filter_anisotropic"));
+ const char *vendor = (const char *)glGetString(GL_VENDOR);
+ printf("vendor: %s\n", vendor);
+
GLint aniso;
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &aniso);
printf("Max anisotropy: %d (using that)\n", aniso);
diff --git a/tests/cases/2xi40.ll b/tests/cases/2xi40.ll
new file mode 100644
index 00000000..592f1ba4
--- /dev/null
+++ b/tests/cases/2xi40.ll
@@ -0,0 +1,42 @@
+; ModuleID = '/tmp/tmpe4Pk1F/a.out.bc'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32"
+target triple = "le32-unknown-nacl"
+
+%struct.pair = type { [5 x i8], [5 x i8] }
+
+@.str = private unnamed_addr constant [6 x i8] c"|%d|\0A\00", align 1
+@.str1 = private unnamed_addr constant [7 x i8] c"%s,%s\0A\00", align 1
+
+define i32 @main() {
+ %1 = alloca i32, align 4
+ %pp = alloca [2 x i40], align 8
+ %p = bitcast [2 x i40]* %pp to %struct.pair*
+ store i32 0, i32* %1
+ %2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i32 10)
+ %3 = bitcast %struct.pair* %p to i8*
+ call void @llvm.memset.p0i8.i32(i8* %3, i8 120, i32 10, i32 1, i1 false)
+ %4 = getelementptr inbounds [2 x i40]* %pp, i32 0, i32 0
+ %b4 = bitcast i40* %4 to [5 x i8]*
+ %5 = getelementptr inbounds [5 x i8]* %b4, i32 0, i32 2
+ store i8 97, i8* %5, align 1
+ %6 = getelementptr inbounds %struct.pair* %p, i32 0, i32 0
+ %7 = getelementptr inbounds [5 x i8]* %6, i32 0, i32 4
+ store i8 0, i8* %7, align 1
+ %8 = getelementptr inbounds %struct.pair* %p, i32 0, i32 1
+ %9 = getelementptr inbounds [5 x i8]* %8, i32 0, i32 3
+ store i8 98, i8* %9, align 1
+ %10 = getelementptr inbounds [2 x i40]* %pp, i32 0, i32 1
+ %b10 = bitcast i40* %10 to [5 x i8]*
+ %11 = getelementptr inbounds [5 x i8]* %b10, i32 0, i32 4
+ store i8 0, i8* %11, align 1
+ %12 = getelementptr inbounds %struct.pair* %p, i32 0, i32 0
+ %13 = getelementptr inbounds [5 x i8]* %12, i32 0, i32 0
+ %14 = getelementptr inbounds %struct.pair* %p, i32 0, i32 1
+ %15 = getelementptr inbounds [5 x i8]* %14, i32 0, i32 0
+ %16 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([7 x i8]* @.str1, i32 0, i32 0), i8* %13, i8* %15)
+ ret i32 0
+}
+
+declare i32 @printf(i8*, ...)
+
+declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) nounwind
diff --git a/tests/cases/2xi40.txt b/tests/cases/2xi40.txt
new file mode 100644
index 00000000..59a1104e
--- /dev/null
+++ b/tests/cases/2xi40.txt
@@ -0,0 +1 @@
+xxax,xxxb
diff --git a/tests/cases/caall.ll b/tests/cases/caall.ll
index 313116e6..5b8f7f29 100644
--- a/tests/cases/caall.ll
+++ b/tests/cases/caall.ll
@@ -18,7 +18,7 @@ entry:
define (i32*)** @_ZNSt3__13mapINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEPFvP6ObjectENS_4lessIS6_EENS4_INS_4pairIKS6_SA_EEEEEixERSE_(i32 %x) {
entry:
%ret = inttoptr i32 0 to (i32*)**
- ret %ret
+ ret (i32*)** %ret
}
; [#uses=1]
diff --git a/tests/cases/emptyasm_le32.ll b/tests/cases/emptyasm_le32.ll
new file mode 100644
index 00000000..e123d3d5
--- /dev/null
+++ b/tests/cases/emptyasm_le32.ll
@@ -0,0 +1,16 @@
+; ModuleID = 'tests/hello_world.bc'
+
+@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*]
+
+; [#uses=0]
+define i32 @main() {
+entry:
+ %retval = alloca i32, align 4 ; [#uses=1 type=i32*]
+ store i32 0, i32* %retval
+ call void asm sideeffect "", "~{memory}"() nounwind, !srcloc !0
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0 type=i32]
+ ret i32 1
+}
+
+; [#uses=1]
+declare i32 @printf(i8*, ...)
diff --git a/tests/embind/shell.html b/tests/embind/shell.html
index c3655e03..f0ee10f8 100644
--- a/tests/embind/shell.html
+++ b/tests/embind/shell.html
@@ -85,6 +85,6 @@
};
Module.setStatus('Downloading...');
</script>
- <script type='text/javascript'>{{{ SCRIPT_CODE }}}</script>
+ {{{ SCRIPT }}}
</body>
</html>
diff --git a/tests/hello_world_gles_shell.html b/tests/hello_world_gles_shell.html
index 2459d755..22ecee7b 100644
--- a/tests/hello_world_gles_shell.html
+++ b/tests/hello_world_gles_shell.html
@@ -49,7 +49,7 @@
Module.postRun = doTest;
</script>
- <script>{{{ SCRIPT_CODE }}}</script>
+ {{{ SCRIPT }}}
</body>
</html>
diff --git a/tests/sdl_canvas_size.c b/tests/sdl_canvas_size.c
new file mode 100644
index 00000000..923a9014
--- /dev/null
+++ b/tests/sdl_canvas_size.c
@@ -0,0 +1,191 @@
+/*******************************************************************
+ * *
+ * Using SDL With OpenGL *
+ * *
+ * Tutorial by Kyle Foley (sdw) *
+ * *
+ * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL *
+ * *
+ *******************************************************************/
+
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#include "SDL/SDL.h"
+#include "SDL/SDL_image.h"
+#include "SDL/SDL_opengl.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+
+ // Slightly different SDL initialization
+ if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
+ printf("Unable to initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new*
+
+#ifdef EMSCRIPTEN
+ // Test 1: Check that initializing video mode with size (0,0) will use the size from the <canvas> element.
+ screen = SDL_SetVideoMode( 0, 0, 16, SDL_OPENGL ); // *changed*
+
+ // Test 2: Check that getting current canvas size works.
+ int w, h, fs;
+ emscripten_get_canvas_size(&w, &h, &fs);
+ printf("w:%d,h:%d\n", w,h);
+ assert(w == 700);
+ assert(h == 200);
+
+ // Test 3: Check that resizing the canvas works as well.
+ emscripten_set_canvas_size(640, 480);
+ // Set the OpenGL state after creating the context with SDL_SetVideoMode
+#else
+ screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed*
+#endif
+
+ if ( !screen ) {
+ printf("Unable to set video mode: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ glClearColor( 0, 0, 0, 0 );
+
+ glEnable( GL_TEXTURE_2D ); // Needed when we're using the fixed-function pipeline.
+
+ glViewport( 0, 0, 640, 480 );
+
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix(); // just for testing
+ glLoadIdentity();
+
+ glOrtho( 0, 640, 480, 0, -1, 1 );
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ // Load the OpenGL texture
+
+ GLuint texture; // Texture object handle
+ SDL_Surface *surface; // Gives us the information to make the texture
+
+ if ( (surface = IMG_Load("screenshot.png")) ) {
+
+ // Check that the image's width is a power of 2
+ if ( (surface->w & (surface->w - 1)) != 0 ) {
+ printf("warning: image.bmp's width is not a power of 2\n");
+ }
+
+ // Also check if the height is a power of 2
+ if ( (surface->h & (surface->h - 1)) != 0 ) {
+ printf("warning: image.bmp's height is not a power of 2\n");
+ }
+
+ // Have OpenGL generate a texture object handle for us
+ glGenTextures( 1, &texture );
+
+ // Bind the texture object
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ // Set the texture's stretching properties
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ //SDL_LockSurface(surface);
+
+ // Add some greyness
+ memset(surface->pixels, 0x66, surface->w*surface->h);
+
+ // Edit the texture object's image data using the information SDL_Surface gives us
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels );
+
+ //SDL_UnlockSurface(surface);
+ }
+ else {
+ printf("SDL could not load image.bmp: %s\n", SDL_GetError());
+ SDL_Quit();
+ return 1;
+ }
+
+ // Free the SDL_Surface only if it was successfully created
+ if ( surface ) {
+ SDL_FreeSurface( surface );
+ }
+
+ // Clear the screen before drawing
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ // Bind the texture to which subsequent calls refer to
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ glBegin( GL_QUADS );
+ glTexCoord2i( 0, 0 ); glVertex3f( 10, 10, 0 );
+ glTexCoord2i( 1, 0 ); glVertex3f( 300, 10, 0 );
+ glTexCoord2i( 1, 1 ); glVertex3f( 300, 128, 0 );
+ glTexCoord2i( 0, 1 ); glVertex3f( 10, 128, 0 );
+
+ glTexCoord2f( 0, 0.5 ); glVertex3f( 410, 10, 0 );
+ glTexCoord2f( 1, 0.5 ); glVertex3f( 600, 10, 0 );
+ glTexCoord2f( 1, 1 ); glVertex3f( 630, 200, 0 );
+ glTexCoord2f( 0.5, 1 ); glVertex3f( 310, 250, 0 );
+ glEnd();
+
+ glBegin( GL_TRIANGLE_STRIP );
+ glTexCoord2i( 0, 0 ); glVertex3f( 100, 300, 0 );
+ glTexCoord2i( 1, 0 ); glVertex3f( 300, 300, 0 );
+ glTexCoord2i( 1, 1 ); glVertex3f( 300, 400, 0 );
+ glTexCoord2i( 0, 1 ); glVertex3f( 500, 410, 0 );
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+
+ glColor3ub(90, 255, 255);
+ glBegin( GL_QUADS );
+ glVertex3f( 10, 410, 0 );
+ glVertex3f( 300, 410, 0 );
+ glVertex3f( 300, 480, 0 );
+ glVertex3f( 10, 470, 0 );
+ glEnd();
+
+ glBegin( GL_QUADS );
+ glColor3f(1.0, 0, 1.0); glVertex3f( 410, 410, 0 );
+ glColor3f(0, 1.0, 0); glVertex3f( 600, 410, 0 );
+ glColor3f(0, 0, 1.0); glVertex3f( 600, 480, 0 );
+ glColor3f(1.0, 1.0, 1.0); glVertex3f( 410, 470, 0 );
+ glEnd();
+
+ SDL_GL_SwapBuffers();
+
+#if !EMSCRIPTEN
+ // Wait for 3 seconds to give us a chance to see the image
+ SDL_Delay(3000);
+#endif
+
+ // Now we can delete the OpenGL texture and close down SDL
+ glDeleteTextures( 1, &texture );
+
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/tests/sdl_canvas_size.html b/tests/sdl_canvas_size.html
new file mode 100644
index 00000000..50495049
--- /dev/null
+++ b/tests/sdl_canvas_size.html
@@ -0,0 +1,93 @@
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Emscripten-Generated Code</title>
+ <style>
+ .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
+ textarea.emscripten { font-family: monospace; width: 80%; }
+ div.emscripten { text-align: center; }
+ div.emscripten_border { border: 1px solid black; }
+ /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
+ canvas.emscripten { border: 0px none; }
+ </style>
+ </head>
+ <body>
+ <hr/>
+ <div class="emscripten" id="status">Downloading...</div>
+ <div class="emscripten">
+ <progress value="0" max="100" id="progress" hidden=1></progress>
+ </div>
+ <div class="emscripten_border">
+ <!-- Pass custom width/height to test that SDL_SetVideoMode(0,0, ...) will use these. -->
+ <canvas class="emscripten" id="canvas" width="700" height="200" oncontextmenu="event.preventDefault()"></canvas>
+ </div>
+ <hr/>
+ <div class="emscripten">
+ <input type="checkbox" id="resize">Resize canvas
+ <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
+ &nbsp;&nbsp;&nbsp;
+ <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked,
+ document.getElementById('resize').checked)">
+ </div>
+
+ <hr/>
+ <textarea class="emscripten" id="output" rows="8"></textarea>
+ <hr>
+ <script type='text/javascript'>
+ // connect to canvas
+ var Module = {
+ preRun: [],
+ postRun: [],
+ print: (function() {
+ var element = document.getElementById('output');
+ element.value = ''; // clear browser cache
+ return function(text) {
+ text = Array.prototype.slice.call(arguments).join(' ');
+ // These replacements are necessary if you render to raw HTML
+ //text = text.replace(/&/g, "&amp;");
+ //text = text.replace(/</g, "&lt;");
+ //text = text.replace(/>/g, "&gt;");
+ //text = text.replace('\n', '<br>', 'g');
+ element.value += text + "\n";
+ element.scrollTop = 99999; // focus on bottom
+ };
+ })(),
+ printErr: function(text) {
+ text = Array.prototype.slice.call(arguments).join(' ');
+ if (0) { // XXX disabled for safety typeof dump == 'function') {
+ dump(text + '\n'); // fast, straight to the real console
+ } else {
+ console.log(text);
+ }
+ },
+ canvas: document.getElementById('canvas'),
+ setStatus: function(text) {
+ if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
+ var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
+ var statusElement = document.getElementById('status');
+ var progressElement = document.getElementById('progress');
+ if (m) {
+ text = m[1];
+ progressElement.value = parseInt(m[2])*100;
+ progressElement.max = parseInt(m[4])*100;
+ progressElement.hidden = false;
+ } else {
+ progressElement.value = null;
+ progressElement.max = null;
+ progressElement.hidden = true;
+ }
+ statusElement.innerHTML = text;
+ },
+ totalDependencies: 0,
+ monitorRunDependencies: function(left) {
+ this.totalDependencies = Math.max(this.totalDependencies, left);
+ Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
+ }
+ };
+ Module.setStatus('Downloading...');
+ </script>
+ {{{ SCRIPT }}}
+ </body>
+</html>
diff --git a/tests/test_browser.py b/tests/test_browser.py
index ecd331fd..2ff9106b 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -869,6 +869,48 @@ keydown(100);keyup(100); // trigger the end
def test_glut_wheelevents(self):
self.btest('glut_wheelevents.c', '1')
+ def test_webgl_context_attributes(self):
+ # Javascript code to check the attributes support we want to test in the WebGL implementation
+ # (request the attribute, create a context and check its value afterwards in the context attributes).
+ # Tests will succeed when an attribute is not supported.
+ open(os.path.join(self.get_dir(), 'check_webgl_attributes_support.js'), 'w').write('''
+ mergeInto(LibraryManager.library, {
+ webglAntialiasSupported: function() {
+ canvas = document.createElement('canvas');
+ context = canvas.getContext('experimental-webgl', {antialias: true});
+ attributes = context.getContextAttributes();
+ return attributes.antialias;
+ },
+ webglDepthSupported: function() {
+ canvas = document.createElement('canvas');
+ context = canvas.getContext('experimental-webgl', {depth: true});
+ attributes = context.getContextAttributes();
+ return attributes.depth;
+ },
+ webglStencilSupported: function() {
+ canvas = document.createElement('canvas');
+ context = canvas.getContext('experimental-webgl', {stencil: true});
+ attributes = context.getContextAttributes();
+ return attributes.stencil;
+ }
+ });
+ ''')
+
+ # Copy common code file to temporary directory
+ filepath = path_from_root('tests/test_webgl_context_attributes_common.c')
+ temp_filepath = os.path.join(self.get_dir(), os.path.basename(filepath))
+ shutil.copyfile(filepath, temp_filepath)
+
+ # perform tests with attributes activated
+ self.btest('test_webgl_context_attributes_glut.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED'])
+ self.btest('test_webgl_context_attributes_sdl.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED'])
+ self.btest('test_webgl_context_attributes_glfw.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED'])
+
+ # perform tests with attributes desactivated
+ self.btest('test_webgl_context_attributes_glut.c', '1', args=['--js-library', 'check_webgl_attributes_support.js'])
+ self.btest('test_webgl_context_attributes_sdl.c', '1', args=['--js-library', 'check_webgl_attributes_support.js'])
+ self.btest('test_webgl_context_attributes_glfw.c', '1', args=['--js-library', 'check_webgl_attributes_support.js'])
+
def test_emscripten_get_now(self):
self.btest('emscripten_get_now.cpp', '1')
@@ -942,6 +984,11 @@ keydown(100);keyup(100); // trigger the end
Popen([PYTHON, EMCC, '-O2', '--closure', '1', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio_beep.cpp'), '-s', 'DISABLE_EXCEPTION_CATCHING=0', '-o', 'page.html']).communicate()
self.run_browser('page.html', '', '/report_result?1')
+ def test_sdl_canvas_size(self):
+ self.btest('sdl_canvas_size.c', reference='screenshot-gray-purple.png', reference_slack=1,
+ args=['-O2', '--minify', '0', '--shell-file', path_from_root('tests', 'sdl_canvas_size.html'), '--preload-file', path_from_root('tests', 'screenshot.png') + '@/', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with gray at the top.')
+
def test_sdl_gl_read(self):
# SDL, OpenGL, readPixels
open(os.path.join(self.get_dir(), 'sdl_gl_read.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_gl_read.c')).read()))
diff --git a/tests/test_core.py b/tests/test_core.py
index 69fb31f3..c196adf3 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -2949,6 +2949,23 @@ Exiting setjmp function, level: 0, prev_jmp: -1
'''
self.do_run(src, '3.14159')
+ def test_iswdigit(self):
+ if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
+
+ src = '''
+ #include <stdio.h>
+ #include <cctype>
+ #include <cwctype>
+
+ int main() {
+ using namespace std;
+ printf("%d ", isdigit('0'));
+ printf("%d ", iswdigit(L'0'));
+ return 0;
+ }
+ '''
+ self.do_run(src, '1 1')
+
def test_polymorph(self):
if self.emcc_args is None: return self.skip('requires emcc')
src = '''
@@ -7268,6 +7285,18 @@ date: 18.07.2013w; day 18, month 7, year 2013, extra: 201, 3
'''
self.do_run(src, '4779 4779')
+ def test_sscanf_float(self):
+ src = r'''
+ #include "stdio.h"
+
+ int main(){
+ float f1, f2, f3, f4, f5, f6, f7, f8, f9;
+ sscanf("0.512 0.250x5.129_-9.98 1.12*+54.32E3 +54.32E3^87.5E-3 87.5E-3$", "%f %fx%f_%f %f*%f %f^%f %f$", &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8, &f9);
+ printf("\n%f, %f, %f, %f, %f, %f, %f, %f, %f\n", f1, f2, f3, f4, f5, f6, f7, f8, f9);
+ }
+ '''
+ self.do_run(src, '\n0.512000, 0.250000, 5.129000, -9.980000, 1.120000, 54320.000000, 54320.000000, 0.087500, 0.087500\n')
+
def test_langinfo(self):
src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read()
expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read()
@@ -8631,6 +8660,122 @@ void*:16
main = main[:main.find('\n}')]
assert main.count('\n') == 7, 'must not emit too many postSets: %d' % main.count('\n')
+ def test_simd(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
+ if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate
+ src = r'''
+#include <stdio.h>
+
+#include <emscripten/vector.h>
+
+static inline float32x4 __attribute__((always_inline))
+_mm_set_ps(const float __Z, const float __Y, const float __X, const float __W)
+{
+ return (float32x4){ __W, __X, __Y, __Z };
+}
+
+static __inline__ float32x4 __attribute__((__always_inline__))
+_mm_setzero_ps(void)
+{
+ return (float32x4){ 0.0, 0.0, 0.0, 0.0 };
+}
+
+int main(int argc, char **argv) {
+ float data[8];
+ for (int i = 0; i < 32; i++) data[i] = (1+i+argc)*(2+i+argc*argc);
+ {
+ float32x4 *a = (float32x4*)&data[0];
+ float32x4 *b = (float32x4*)&data[4];
+ float32x4 c, d;
+ c = *a;
+ d = *b;
+ printf("1floats! %d, %d, %d, %d %d, %d, %d, %d\n", (int)c[0], (int)c[1], (int)c[2], (int)c[3], (int)d[0], (int)d[1], (int)d[2], (int)d[3]);
+ c = c+d;
+ printf("2floats! %d, %d, %d, %d %d, %d, %d, %d\n", (int)c[0], (int)c[1], (int)c[2], (int)c[3], (int)d[0], (int)d[1], (int)d[2], (int)d[3]);
+ d = c*d;
+ printf("3floats! %d, %d, %d, %d %d, %d, %d, %d\n", (int)c[0], (int)c[1], (int)c[2], (int)c[3], (int)d[0], (int)d[1], (int)d[2], (int)d[3]);
+ c = _mm_setzero_ps();
+ printf("zeros %d, %d, %d, %d\n", (int)c[0], (int)c[1], (int)c[2], (int)c[3]);
+ }
+ {
+ uint32x4 *a = (uint32x4*)&data[0];
+ uint32x4 *b = (uint32x4*)&data[4];
+ uint32x4 c, d, e, f;
+ c = *a;
+ d = *b;
+ printf("4uints! %d, %d, %d, %d %d, %d, %d, %d\n", c[0], c[1], c[2], c[3], d[0], d[1], d[2], d[3]);
+ e = c+d;
+ f = c-d;
+ printf("5uints! %d, %d, %d, %d %d, %d, %d, %d\n", e[0], e[1], e[2], e[3], f[0], f[1], f[2], f[3]);
+ }
+ {
+ float32x4 c, d, e, f;
+ c = _mm_set_ps(9.0, 4.0, 0, -9.0);
+ d = _mm_set_ps(10.0, 14.0, -12, -2.0);
+ printf("6floats! %d, %d, %d, %d %d, %d, %d, %d\n", (int)c[0], (int)c[1], (int)c[2], (int)c[3], (int)d[0], (int)d[1], (int)d[2], (int)d[3]);
+ printf("7calcs: %d\n", emscripten_float32x4_signmask(c)); // TODO: just not just compilation but output as well
+ }
+
+ return 0;
+}
+ '''
+
+ self.do_run(src, '''1floats! 6, 12, 20, 30 42, 56, 72, 90
+2floats! 48, 68, 92, 120 42, 56, 72, 90
+3floats! 48, 68, 92, 120 2016, 3808, 6624, 10800
+zeros 0, 0, 0, 0
+4uints! 1086324736, 1094713344, 1101004800, 1106247680 1109917696, 1113587712, 1116733440, 1119092736
+5uints! -2098724864, -2086666240, -2077229056, -2069626880 -23592960, -18874368, -15728640, -12845056
+6floats! -9, 0, 4, 9 -2, -12, 14, 10
+''')
+
+ def test_simd2(self):
+ if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate
+
+ self.do_run(r'''
+ #include <stdio.h>
+
+ typedef float __m128 __attribute__ ((__vector_size__ (16)));
+
+ static inline __m128 __attribute__((always_inline))
+ _mm_set_ps(const float __Z, const float __Y, const float __X, const float __W)
+ {
+ return (__m128){ __W, __X, __Y, __Z };
+ }
+
+ static inline void __attribute__((always_inline))
+ _mm_store_ps(float *__P, __m128 __A)
+ {
+ *(__m128 *)__P = __A;
+ }
+
+ static inline __m128 __attribute__((always_inline))
+ _mm_add_ps(__m128 __A, __m128 __B)
+ {
+ return __A + __B;
+ }
+
+ using namespace std;
+
+ int main(int argc, char ** argv) {
+ float __attribute__((__aligned__(16))) ar[4];
+ __m128 v1 = _mm_set_ps(9.0, 4.0, 0, -9.0);
+ __m128 v2 = _mm_set_ps(7.0, 3.0, 2.5, 1.0);
+ __m128 v3 = _mm_add_ps(v1, v2);
+ _mm_store_ps(ar, v3);
+
+ for (int i = 0; i < 4; i++) {
+ printf("%f\n", ar[i]);
+ }
+
+ return 0;
+ }
+ ''', '''-8.000000
+2.500000
+7.000000
+16.000000
+''')
+
def test_gcc_unmangler(self):
Settings.NAMED_GLOBALS = 1 # test coverage for this
@@ -9044,6 +9189,9 @@ def process(filename):
if '_noasm' in shortname and Settings.ASM_JS:
print self.skip('case "%s" not relevant for asm.js' % shortname)
continue
+ if '_le32' in shortname and not self.is_le32():
+ print self.skip('case "%s" not relevant for non-le32 target' % shortname)
+ continue
self.emcc_args = emcc_args
if os.path.exists(shortname + '.emcc'):
if not self.emcc_args: continue
diff --git a/tests/test_other.py b/tests/test_other.py
index e251da5d..86e0eadf 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -2015,47 +2015,3 @@ a(int [32], char [5]*)
Popen([PYTHON, EMCC, path_from_root('tests', 'linpack.c'), '-O2', '-DSP', '--llvm-opts', '''['-O3', '-vectorize', '-vectorize-loops', '-bb-vectorize-vector-bits=128', '-force-vector-width=4']''']).communicate()
self.assertContained('Unrolled Single Precision', run_js('a.out.js'))
- def test_simd2(self):
- self.clear()
- open('src.cpp', 'w').write(r'''
-#include <stdio.h>
-
-#include <emscripten/vector.h>
-
-int main(int argc, char **argv) {
- float data[8];
- for (int i = 0; i < 32; i++) data[i] = (1+i+argc)*(2+i+argc*argc);
- {
- float32x4 *a = (float32x4*)&data[0];
- float32x4 *b = (float32x4*)&data[4];
- float32x4 c, d;
- c = *a;
- d = *b;
- printf("floats! %d, %d, %d, %d %d, %d, %d, %d\n", (int)c[0], (int)c[1], (int)c[2], (int)c[3], (int)d[0], (int)d[1], (int)d[2], (int)d[3]);
- c = c+d;
- printf("floats! %d, %d, %d, %d %d, %d, %d, %d\n", (int)c[0], (int)c[1], (int)c[2], (int)c[3], (int)d[0], (int)d[1], (int)d[2], (int)d[3]);
- d = c*d;
- printf("floats! %d, %d, %d, %d %d, %d, %d, %d\n", (int)c[0], (int)c[1], (int)c[2], (int)c[3], (int)d[0], (int)d[1], (int)d[2], (int)d[3]);
- }
- {
- uint32x4 *a = (uint32x4*)&data[0];
- uint32x4 *b = (uint32x4*)&data[4];
- uint32x4 c, d, e, f;
- c = *a;
- d = *b;
- printf("uints! %d, %d, %d, %d %d, %d, %d, %d\n", c[0], c[1], c[2], c[3], d[0], d[1], d[2], d[3]);
- e = c+d;
- f = c-d;
- printf("uints! %d, %d, %d, %d %d, %d, %d, %d\n", e[0], e[1], e[2], e[3], f[0], f[1], f[2], f[3]);
- }
- return 0;
-}
- ''')
- Popen([PYTHON, EMCC, 'src.cpp', '-O2']).communicate()
- self.assertContained('''floats! 6, 12, 20, 30 42, 56, 72, 90
-floats! 48, 68, 92, 120 42, 56, 72, 90
-floats! 48, 68, 92, 120 2016, 3808, 6624, 10800
-uints! 1086324736, 1094713344, 1101004800, 1106247680 1109917696, 1113587712, 1116733440, 1119092736
-uints! -2098724864, -2086666240, -2077229056, -2069626880 -23592960, -18874368, -15728640, -12845056
-''', run_js('a.out.js'))
-
diff --git a/tests/test_webgl_context_attributes_common.c b/tests/test_webgl_context_attributes_common.c
new file mode 100644
index 00000000..7131203b
--- /dev/null
+++ b/tests/test_webgl_context_attributes_common.c
@@ -0,0 +1,262 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <emscripten.h>
+
+#define BUFFER_OFFSET(i) ((char *)NULL + (i))
+
+static const int WINDOWS_SIZE = 500;
+
+static GLfloat vertices[] = { 0.0f, 250.f, 0.0f,
+ -250.f, -250.f, 0.0f,
+ 250.f, -250.f, 0.0f };
+
+static GLfloat vertices2[] = { 0.0f, 250.f, -1.0f,
+ -250.f, -250.f, -1.0f,
+ 250.f, -250.f, -1.0f };
+
+static GLuint shaderProgram = 0;
+static GLuint verticesVBO = 0;
+static GLuint verticesVBO2 = 0;
+
+static unsigned char backgroundColor[4] = {255, 255, 255, 255};
+static unsigned char triangleColor[4] = {255, 0, 0, 255};
+static unsigned char triangleColor2[4] = {0, 255, 0, 255};
+
+static char vertexShaderSrc[] =
+ "precision highp float;"
+ "precision highp int;"
+
+ "uniform mat4 u_mvpMatrix;"
+ "uniform vec4 u_color;"
+
+ "attribute vec3 a_position;"
+
+ "varying vec4 v_color;"
+
+ "void main() {"
+ " gl_Position = u_mvpMatrix * vec4(a_position, 1.0);"
+ " v_color = u_color;"
+ "}"
+ ;
+
+static char fragmentShaderSrc[] =
+ "precision highp float;"
+ "precision highp int;"
+
+ "varying vec4 v_color;"
+
+ "void main() {"
+ " gl_FragColor = v_color;"
+ "}"
+ ;
+
+static GLuint createShader(const char *source, int type) {
+ GLuint shader = glCreateShader(type);
+ glShaderSource(shader, 1, (const GLchar**)(&source), NULL);
+ glCompileShader(shader);
+ return shader;
+}
+
+static GLuint createShaderProgram(const char *vertexShaderSrc, const char *fragmentShaderSrc) {
+ GLuint program = glCreateProgram();
+ glAttachShader(program, createShader(vertexShaderSrc, GL_VERTEX_SHADER));
+ glAttachShader(program, createShader(fragmentShaderSrc, GL_FRAGMENT_SHADER));
+ glLinkProgram(program);
+ return program;
+}
+
+void ortho(float left, float right, float bottom, float top, float nearVal, float farVal, GLfloat *projMatrix) {
+ float tx = -(right+left)/(right-left);
+ float ty = -(top+bottom)/(top-bottom);
+ float tz = -(farVal+nearVal)/(farVal-nearVal);
+ memset(projMatrix, 0, 16 * sizeof(GLfloat));
+ projMatrix[0] = 2.0f / (right-left);
+ projMatrix[3] = tx;
+ projMatrix[1*4+1] = 2.0f / (top-bottom);
+ projMatrix[1*4+3] = ty;
+ projMatrix[2*4+2] = -2.0f / (farVal-nearVal);
+ projMatrix[2*4+3] = tz;
+ projMatrix[3*4+3] = 1.0f;
+}
+
+static void initGlObjects() {
+ glGenBuffers(1, &verticesVBO);
+ glBindBuffer(GL_ARRAY_BUFFER, verticesVBO);
+ glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), vertices, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glGenBuffers(1, &verticesVBO2);
+ glBindBuffer(GL_ARRAY_BUFFER, verticesVBO2);
+ glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), vertices2, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ shaderProgram = createShaderProgram(vertexShaderSrc, fragmentShaderSrc);
+}
+
+static void drawTriangle(GLuint verticesVBO, unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
+ glUseProgram(shaderProgram);
+ GLuint posLoc = glGetAttribLocation(shaderProgram, "a_position");
+ GLuint mvpLoc = glGetUniformLocation(shaderProgram, "u_mvpMatrix");
+ GLuint colorLoc = glGetUniformLocation(shaderProgram, "u_color");
+
+ GLfloat mvpMat[16];
+ ortho(-WINDOWS_SIZE/2, WINDOWS_SIZE/2, -WINDOWS_SIZE/2, WINDOWS_SIZE/2, -100, 100, mvpMat);
+
+ glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvpMat);
+ glUniform4f(colorLoc, r/255.f, g/255.f, b/255.f, a/255.f);
+
+ glBindBuffer(GL_ARRAY_BUFFER, verticesVBO);
+ glEnableVertexAttribArray(posLoc);
+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), BUFFER_OFFSET(0));
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glUseProgram(0);
+}
+
+// Draw a red triangle on a white background. If antialiasing is disabled, resulting pixels
+// will only have white and red colors. If antialiasing is enabled, there will be pixels
+// whose color is different from red and white.
+static int testAntiAliasing(bool activated) {
+ glViewport(0, 0, WINDOWS_SIZE, WINDOWS_SIZE);
+ glClearColor(backgroundColor[0]/255.f, backgroundColor[1]/255.f, backgroundColor[2]/255.f, backgroundColor[3]/255.f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ drawTriangle(verticesVBO, triangleColor[0], triangleColor[1], triangleColor[2], triangleColor[3]);
+
+ bool antialiased = false;
+
+ unsigned char buffer[(WINDOWS_SIZE*WINDOWS_SIZE)*4];
+ glReadPixels(0, 0, WINDOWS_SIZE, WINDOWS_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
+ glFinish();
+ for (unsigned int i = 0 ; i < WINDOWS_SIZE ; ++i) {
+ for (unsigned int j = 0 ; j < WINDOWS_SIZE ; ++j) {
+ unsigned char r = buffer[4*(i*WINDOWS_SIZE+j)];
+ unsigned char g = buffer[4*(i*WINDOWS_SIZE+j)+1];
+ unsigned char b = buffer[4*(i*WINDOWS_SIZE+j)+2];
+ unsigned char a = buffer[4*(i*WINDOWS_SIZE+j)+3];
+ if ((r == backgroundColor[0] && g == backgroundColor[1] && b == backgroundColor[2] && a == backgroundColor[3]) ||
+ (r == triangleColor[0] && g == triangleColor[1] && b == triangleColor[2] && a == triangleColor[3])) {
+ continue;
+ } else {
+ antialiased = true;
+ break;
+ }
+ }
+ }
+
+ return (activated && antialiased) || (!activated && !antialiased);
+}
+
+// Draw a red triangle with depth equals to 0 then a green triangle whose depth equals -1.
+// If there is an attached depth buffer, the resulting image will be a red triangle. If not,
+// the resulting image will be a green triangle.
+static int testDepth(bool activated) {
+ glViewport(0, 0, WINDOWS_SIZE, WINDOWS_SIZE);
+ glClearColor(backgroundColor[0]/255.f, backgroundColor[1]/255.f, backgroundColor[2]/255.f, backgroundColor[3]/255.f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+
+ drawTriangle(verticesVBO, triangleColor[0], triangleColor[1], triangleColor[2], triangleColor[3]);
+ drawTriangle(verticesVBO2, triangleColor2[0], triangleColor2[1], triangleColor2[2], triangleColor2[3]);
+
+ glDisable(GL_DEPTH_TEST);
+
+ // read the pixel at the center of the resulting image.
+ unsigned char buffer[4];
+ glReadPixels(WINDOWS_SIZE/2, WINDOWS_SIZE/2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
+
+ bool frontTriangleColor = (buffer[0] == triangleColor[0] && buffer[1] == triangleColor[1] &&
+ buffer[2] == triangleColor[2] && buffer[3] == triangleColor[3]);
+
+ bool backTriangleColor = (buffer[0] == triangleColor2[0] && buffer[1] == triangleColor2[1] &&
+ buffer[2] == triangleColor2[2] && buffer[3] == triangleColor2[3]);
+
+ return (activated && frontTriangleColor) || (!activated && backTriangleColor);
+}
+
+// The stencil function is set to GL_LEQUAL so fragments will be written to the
+// back buffer only if the ref value is less or equal than the one in the stencil buffer.
+// The content of the stencil buffer is initialized to 0xFF.
+// First draw a red triangle whose stencil ref value is 0x1.
+// Then draw a green triangle whose stencil ref value is 0xFF.
+// If there is an attached stencil buffer, the resulting image will be a red triangle. If not,
+// the resulting image will be a green triangle.
+static int testStencil(bool activated) {
+ glViewport(0, 0, WINDOWS_SIZE, WINDOWS_SIZE);
+ glClearColor(backgroundColor[0]/255.f, backgroundColor[1]/255.f, backgroundColor[2]/255.f, backgroundColor[3]/255.f);
+ glClearStencil(0xFF);
+ glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
+ glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ glEnable(GL_STENCIL_TEST);
+
+ glStencilFunc(GL_LEQUAL, 0x1, 0xFF);
+ drawTriangle(verticesVBO, triangleColor[0], triangleColor[1], triangleColor[2], triangleColor[3]);
+
+ glStencilFunc(GL_LEQUAL, 0xFF, 0xFF);
+ drawTriangle(verticesVBO, triangleColor2[0], triangleColor2[1], triangleColor2[2], triangleColor2[3]);
+
+ glDisable(GL_STENCIL_TEST);
+
+ unsigned char buffer[4];
+ glReadPixels(WINDOWS_SIZE/2, WINDOWS_SIZE/2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
+
+ bool firstTriangleColor = (buffer[0] == triangleColor[0] && buffer[1] == triangleColor[1] &&
+ buffer[2] == triangleColor[2] && buffer[3] == triangleColor[3]);
+
+ bool secondTriangleColor = (buffer[0] == triangleColor2[0] && buffer[1] == triangleColor2[1] &&
+ buffer[2] == triangleColor2[2] && buffer[3] == triangleColor2[3]);
+
+ return (activated && firstTriangleColor) || (!activated && secondTriangleColor);
+}
+
+static bool antiAliasingActivated = false;
+static bool depthActivated = false;
+static bool stencilActivated = false;
+
+static int result = 0;
+static int resultAA = 0;
+static int resultDepth = 0;
+static int resultStencil = 0;
+
+static void draw() {
+
+ if (!resultAA) resultAA = testAntiAliasing(antiAliasingActivated);
+
+ if (!resultDepth) resultDepth = testDepth(depthActivated);
+
+ if (!resultStencil) resultStencil = testStencil(stencilActivated);
+
+ result = resultAA && resultDepth && resultStencil;
+
+}
+
+extern int webglAntialiasSupported();
+extern int webglDepthSupported();
+extern int webglStencilSupported();
+
+// Check attributes support in the WebGL implementation (see test_webgl_context_attributes function in test_browser.py)
+// Tests will succeed if they are not.
+static void checkContextAttributesSupport() {
+ if (!webglAntialiasSupported()) {
+ resultAA = 1;
+ EM_ASM(alert('warning: no antialiasing\n'));
+ }
+ if (!webglDepthSupported()) {
+ resultDepth = 1;
+ EM_ASM(alert('warning: no depth\n'));
+ }
+ if (!webglStencilSupported()) {
+ resultStencil = 1;
+ EM_ASM(alert('warning: no stencil\n'));
+ }
+}
+
+
diff --git a/tests/test_webgl_context_attributes_glfw.c b/tests/test_webgl_context_attributes_glfw.c
new file mode 100644
index 00000000..694236d0
--- /dev/null
+++ b/tests/test_webgl_context_attributes_glfw.c
@@ -0,0 +1,47 @@
+#include <GL/glew.h>
+#include <GL/glfw.h>
+#include <emscripten.h>
+
+#include "test_webgl_context_attributes_common.c"
+
+int nbSamples = 0;
+int nbDepthBits = 0;
+int nbStencilBits = 0;
+
+int main() {
+
+ checkContextAttributesSupport();
+
+ glfwInit();
+
+#ifdef AA_ACTIVATED
+ antiAliasingActivated = true;
+ nbSamples = 4;
+#endif
+
+#ifdef DEPTH_ACTIVATED
+ depthActivated = true;
+ nbDepthBits = 16;
+#endif
+
+#ifdef STENCIL_ACTIVATED
+ stencilActivated = true;
+ nbStencilBits = 8;
+#endif
+
+ glfwOpenWindowHint(GLFW_FSAA_SAMPLES, nbSamples);
+ glfwOpenWindow(WINDOWS_SIZE, WINDOWS_SIZE, 8, 8, 8, 8, nbDepthBits, nbStencilBits, GLFW_WINDOW);
+
+ glewInit();
+ initGlObjects();
+
+ draw();
+
+ glfwTerminate();
+
+ REPORT_RESULT();
+
+ return 0;
+
+}
+ \ No newline at end of file
diff --git a/tests/test_webgl_context_attributes_glut.c b/tests/test_webgl_context_attributes_glut.c
new file mode 100644
index 00000000..3255fc9a
--- /dev/null
+++ b/tests/test_webgl_context_attributes_glut.c
@@ -0,0 +1,42 @@
+#include <GL/glew.h>
+#include <GL/glut.h>
+#include <emscripten.h>
+
+#include "test_webgl_context_attributes_common.c"
+
+int main(int argc, char *argv[]) {
+
+ checkContextAttributesSupport();
+
+ unsigned int glutDisplayMode = GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA;
+
+#ifdef AA_ACTIVATED
+ antiAliasingActivated = true;
+ glutDisplayMode |= GLUT_MULTISAMPLE;
+#endif
+
+#ifdef DEPTH_ACTIVATED
+ depthActivated = true;
+ glutDisplayMode |= GLUT_DEPTH;
+#endif
+
+#ifdef STENCIL_ACTIVATED
+ stencilActivated = true;
+ glutDisplayMode |= GLUT_STENCIL;
+#endif
+
+ glutInit(&argc, argv);
+ glutInitWindowSize(WINDOWS_SIZE, WINDOWS_SIZE);
+ glutInitDisplayMode(glutDisplayMode);
+ glutCreateWindow("WebGL");
+ glutDisplayFunc(draw);
+
+ glewInit();
+ initGlObjects();
+
+ draw();
+
+ REPORT_RESULT();
+
+ return 0;
+}
diff --git a/tests/test_webgl_context_attributes_sdl.c b/tests/test_webgl_context_attributes_sdl.c
new file mode 100644
index 00000000..23ad4378
--- /dev/null
+++ b/tests/test_webgl_context_attributes_sdl.c
@@ -0,0 +1,50 @@
+#include <GL/glew.h>
+#define NO_SDL_GLEXT
+#include <SDL/SDL.h>
+#include <SDL/SDL_opengl.h>
+#include <emscripten.h>
+
+#include "test_webgl_context_attributes_common.c"
+
+int main(int argc, char *argv[]) {
+
+ checkContextAttributesSupport();
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+#ifdef AA_ACTIVATED
+ antiAliasingActivated = true;
+ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
+ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
+#else
+ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
+ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
+#endif
+
+#ifdef DEPTH_ACTIVATED
+ depthActivated = true;
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
+#else
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
+#endif
+
+#ifdef STENCIL_ACTIVATED
+ stencilActivated = true;
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+#else
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
+#endif
+
+ SDL_Surface *screen = SDL_SetVideoMode(WINDOWS_SIZE, WINDOWS_SIZE, 32, SDL_OPENGL);
+
+ glewInit();
+ initGlObjects();
+
+ draw();
+
+ REPORT_RESULT();
+
+ return 0;
+}
diff --git a/tools/file_packager.py b/tools/file_packager.py
index a2349a57..1d0ec447 100644
--- a/tools/file_packager.py
+++ b/tools/file_packager.py
@@ -134,6 +134,11 @@ if (not force) and len(data_files) == 0:
ret = '''
var Module;
if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
+if (!Module.expectedDataFileDownloads) {
+ Module.expectedDataFileDownloads = 0;
+ Module.finishedDataFileDownloads = 0;
+}
+Module.expectedDataFileDownloads++;
(function() {
'''
@@ -338,18 +343,9 @@ if has_preloaded:
send: function() {},
onload: function() {
var byteArray = this.byteArray.subarray(this.start, this.end);
- if (this.crunched) {
- var ddsHeader = byteArray.subarray(0, 128);
- var that = this;
- requestDecrunch(this.name, byteArray.subarray(128), function(ddsData) {
- byteArray = new Uint8Array(ddsHeader.length + ddsData.length);
- byteArray.set(ddsHeader, 0);
- byteArray.set(ddsData, 128);
- that.finish(byteArray);
- });
- } else {
+%s
this.finish(byteArray);
- }
+%s
},
finish: function(byteArray) {
var that = this;
@@ -365,7 +361,20 @@ if has_preloaded:
this.requests[this.name] = null;
},
};
- '''
+ ''' % ('' if not crunch else '''
+ if (this.crunched) {
+ var ddsHeader = byteArray.subarray(0, 128);
+ var that = this;
+ requestDecrunch(this.name, byteArray.subarray(128), function(ddsData) {
+ byteArray = new Uint8Array(ddsHeader.length + ddsData.length);
+ byteArray.set(ddsHeader, 0);
+ byteArray.set(ddsData, 128);
+ that.finish(byteArray);
+ });
+ } else {
+''', '' if not crunch else '''
+ }
+''')
counter = 0
for file_ in data_files:
@@ -427,12 +436,6 @@ if has_preloaded:
package_uuid = uuid.uuid4();
remote_package_name = os.path.basename(Compression.compressed_name(data_target) if Compression.on else data_target)
code += r'''
- if (!Module.expectedDataFileDownloads) {
- Module.expectedDataFileDownloads = 0;
- Module.finishedDataFileDownloads = 0;
- }
- Module.expectedDataFileDownloads++;
-
var PACKAGE_PATH = window['encodeURIComponent'](window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/');
var PACKAGE_NAME = '%s';
var REMOTE_PACKAGE_NAME = '%s';
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index d6f8921c..dcc9cd5f 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -29,13 +29,13 @@ class Minifier:
during registerize perform minification of locals.
'''
- def __init__(self, js, js_engine):
+ def __init__(self, js, js_engine, MAX_NAMES):
self.js = js
self.js_engine = js_engine
+ MAX_NAMES = min(MAX_NAMES, 120000)
# Create list of valid short names
- MAX_NAMES = 80000
INVALID_2 = set(['do', 'if', 'in'])
INVALID_3 = set(['for', 'new', 'try', 'var', 'env', 'let'])
@@ -56,7 +56,6 @@ class Minifier:
if len(self.names) >= MAX_NAMES: break
curr = a + b + c
if curr not in INVALID_3: self.names.append(curr)
- #print >> sys.stderr, self.names
def minify_shell(self, shell, minify_whitespace, source_map=False):
#print >> sys.stderr, "MINIFY SHELL 1111111111", shell, "\n222222222222222"
@@ -187,7 +186,8 @@ EMSCRIPTEN_FUNCS();
''' + js[end_funcs + len(end_funcs_marker):end_asm + len(end_asm_marker)]
js = js[start_funcs + len(start_funcs_marker):end_funcs]
- minifier = Minifier(js, js_engine)
+ # we assume there is a maximum of one new name per line
+ minifier = Minifier(js, js_engine, js.count('\n') + asm_shell.count('\n'))
asm_shell_pre, asm_shell_post = minifier.minify_shell(asm_shell, 'minifyWhitespace' in passes, source_map).split('EMSCRIPTEN_FUNCS();');
asm_shell_post = asm_shell_post.replace('});', '})');
pre += asm_shell_pre + '\n' + start_funcs_marker