diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rwxr-xr-x | emcc | 30 | ||||
-rw-r--r-- | emlink.py | 15 | ||||
-rw-r--r-- | src/library.js | 67 | ||||
-rw-r--r-- | src/library_jansson.js | 2 | ||||
-rw-r--r-- | src/library_openal.js | 596 | ||||
-rw-r--r-- | src/library_sdl.js | 168 | ||||
-rw-r--r-- | src/postamble.js | 94 | ||||
-rw-r--r-- | src/preamble.js | 73 | ||||
-rw-r--r-- | src/settings.js | 1655 | ||||
-rw-r--r-- | system/include/bsd/sys/mman.h | 2 | ||||
-rw-r--r-- | system/include/libc/math.h | 8 | ||||
-rw-r--r-- | tests/cases/i24_mem_ta2.ll (renamed from tests/cases/i32_mem.ll) | 0 | ||||
-rw-r--r-- | tests/cases/i24_mem_ta2.txt (renamed from tests/cases/i32_mem.txt) | 0 | ||||
-rw-r--r-- | tests/openal_buffers.c | 187 | ||||
-rwxr-xr-x | tests/runner.py | 225 | ||||
-rw-r--r-- | tests/sdl_stb_image.c | 49 | ||||
-rw-r--r-- | tests/sdl_stb_image_data.c | 55 | ||||
-rw-r--r-- | tests/sounds/the_entertainer.wav | bin | 0 -> 264644 bytes | |||
-rw-r--r-- | third_party/stb_image.c | 4673 | ||||
-rw-r--r-- | tools/file_packager.py | 11 | ||||
-rw-r--r-- | tools/shared.py | 8 |
22 files changed, 6778 insertions, 1141 deletions
@@ -90,5 +90,6 @@ a license to everyone to use it as detailed in LICENSE.) * Soeren Balko <soeren.balko@gmail.com> * Ryan Kelly (ryan@rfk.id.au) * Michael Lelli <toadking@toadking.com> +* Yu Kobayashi <yukoba@accelart.jp> * Pin Zhang <zhangpin04@gmail.com> @@ -53,6 +53,15 @@ from tools import shared, jsrun from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename from tools.response_file import read_response_file +CXX_SUFFIXES = ('.cpp', '.cxx', '.cc') +SOURCE_SUFFIXES = ('.c', '.cpp', '.cxx', '.cc', '.m', '.mm') +BITCODE_SUFFIXES = ('.bc', '.o', '.obj') +DYNAMICLIB_SUFFIXES = ('.dylib', '.so', '.dll') +STATICLIB_SUFFIXES = ('.a',) +ASSEMBLY_SUFFIXES = ('.ll',) +LIB_PREFIXES = ('', 'lib') +JS_CONTAINING_SUFFIXES = ('js', 'html') + # Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt # levels 2 and 3 (emcc 3 is unsafe opts, so unsuitable for the only level to get # llvm opt level 3, and speed-wise emcc level 2 is already the slowest/most optimizing @@ -532,7 +541,7 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: if debug_configure: open(tempout, 'a').write('============= ' + arg + '\n' + src + '\n=============\n\n') except: pass - if arg.endswith('.s'): + elif arg.endswith('.s'): if debug_configure: open(tempout, 'a').write('(compiling .s assembly, must use clang\n') use_js = 0 @@ -615,15 +624,6 @@ if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += shlex.split(EMMAKEN_CFLAGS) # ---------------- Utilities --------------- -SOURCE_SUFFIXES = ('.c', '.cpp', '.cxx', '.cc', '.m', '.mm') -BITCODE_SUFFIXES = ('.bc', '.o', '.obj') -DYNAMICLIB_SUFFIXES = ('.dylib', '.so', '.dll') -STATICLIB_SUFFIXES = ('.a',) -ASSEMBLY_SUFFIXES = ('.ll',) -LIB_PREFIXES = ('', 'lib') - -JS_CONTAINING_SUFFIXES = ('js', 'html') - seen_names = {} def uniquename(name): if name not in seen_names: @@ -1030,6 +1030,10 @@ try: exec('shared.Settings.' + key + ' = ' + value) # Apply effects from settings + if bind and shared.Settings.ASM_JS: + logging.warning('disabling asm.js since embind is not ready for it yet') + shared.Settings.ASM_JS = 0 + if shared.Settings.ASM_JS: assert opt_level >= 1, 'asm.js requires -O1 or above' @@ -1083,6 +1087,10 @@ try: if shared.Settings.DLOPEN_SUPPORT: shared.Settings.LINKABLE = 1 + if shared.Settings.STB_IMAGE and final_suffix in JS_CONTAINING_SUFFIXES: + input_files.append(shared.path_from_root('third_party', 'stb_image.c')) + shared.Settings.EXPORTED_FUNCTIONS += ['_stbi_load', '_stbi_load_from_memory', '_stbi_image_free'] + ## Compile source code to bitcode logging.debug('compiling to bitcode') @@ -1097,6 +1105,8 @@ try: output_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') temp_files.append(output_file) args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file] + if input_file.endswith(CXX_SUFFIXES): + args += shared.EMSDK_CXX_OPTS logging.debug("running:" + call + ' ' + ' '.join(args)) execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) if not os.path.exists(output_file): @@ -56,7 +56,7 @@ class AsmModule(): self.imports = {} for imp in js_optimizer.import_sig.finditer(self.imports_js): key, value = imp.group(0).split('var ')[1][:-1].split('=', 1) - self.imports[key] = value + self.imports[key.strip()] = value.strip() #print >> sys.stderr, 'imports', self.imports # funcs @@ -124,19 +124,20 @@ class AsmModule(): del all_sendings[key] # import of external value no longer needed main.imports_js = '\n'.join(['var %s = %s;' % (key, value) for key, value in all_imports.iteritems()]) + '\n' - if added_sending: - sendings_js = ', '.join(['%s: %s' % (key, value) for key, value in all_sendings.iteritems()]) - sendings_start = main.post_js.find('}, { ')+5 - sendings_end = main.post_js.find(' }, buffer);') - main.post_js = main.post_js[:sendings_start] + sendings_js + main.post_js[sendings_end:] - # check for undefined references to global variables def check_import(key, value): if value.startswith('+') or value.endswith('|0'): # ignore functions if key not in all_sendings: print >> sys.stderr, 'warning: external variable %s is still not defined after linking' % key + all_sendings[key] = '0' for key, value in all_imports.iteritems(): check_import(key, value) + if added_sending: + sendings_js = ', '.join(['%s: %s' % (key, value) for key, value in all_sendings.iteritems()]) + sendings_start = main.post_js.find('}, { ')+5 + sendings_end = main.post_js.find(' }, buffer);') + main.post_js = main.post_js[:sendings_start] + sendings_js + main.post_js[sendings_end:] + # tables f_bases = {} f_sizes = {} diff --git a/src/library.js b/src/library.js index 28886671..8342decf 100644 --- a/src/library.js +++ b/src/library.js @@ -1165,7 +1165,7 @@ LibraryManager.library = { ['i32', 'f_namemax']]), statvfs__deps: ['$FS', '__statvfs_struct_layout'], statvfs: function(path, buf) { - // http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html + // http://pubs.opengroup.org/onlinepubs/009695399/functions/statvfs.html // int statvfs(const char *restrict path, struct statvfs *restrict buf); var offsets = ___statvfs_struct_layout; // NOTE: None of the constants here are true. We're just returning safe and @@ -2133,20 +2133,7 @@ LibraryManager.library = { _exit: function(status) { // void _exit(int status); // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html - - function ExitStatus() { - this.name = "ExitStatus"; - this.message = "Program terminated with exit(" + status + ")"; - this.status = status; - Module.print('Exit Status: ' + status); - }; - ExitStatus.prototype = new Error(); - ExitStatus.prototype.constructor = ExitStatus; - - exitRuntime(); - ABORT = true; - - throw new ExitStatus(); + Module['exit'](status); }, fork__deps: ['__setErrNo', '$ERRNO_CODES'], fork: function() { @@ -3653,29 +3640,19 @@ LibraryManager.library = { ___setErrNo(ERRNO_CODES.EAGAIN); return -1; }, - fscanf__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', - '_scanString', 'fgetc', 'fseek', 'ftell'], + fscanf__deps: ['$FS', '_scanString', 'fgetc', 'ungetc'], fscanf: function(stream, format, varargs) { // int fscanf(FILE *restrict stream, const char *restrict format, ... ); // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html if (FS.streams[stream]) { - var i = _ftell(stream), SEEK_SET = 0; - // if the stream does not support seeking backwards (e.g. stdin), buffer it here - var buffer = [], bufferIndex = 0; + var buffer = []; var get = function() { - if (bufferIndex < buffer.length) { - return buffer[bufferIndex++]; - } - i++; - bufferIndex++; var c = _fgetc(stream); buffer.push(c); return c; }; var unget = function() { - if (_fseek(stream, --i, SEEK_SET) !== 0) { - bufferIndex--; - } + _ungetc(buffer.pop(), stream); }; return __scanString(format, get, unget, varargs); } else { @@ -3939,8 +3916,7 @@ LibraryManager.library = { __cxa_atexit: 'atexit', abort: function() { - ABORT = true; - throw 'abort() at ' + (new Error().stack); + Module['abort'](); }, bsearch: function(key, base, num, size, compar) { @@ -4463,6 +4439,13 @@ LibraryManager.library = { llvm_memmove_p0i8_p0i8_i32: 'memmove', llvm_memmove_p0i8_p0i8_i64: 'memmove', + bcopy__deps: ['memmove'], + bcopy: function(src, dest, num) { + // void bcopy(const void *s1, void *s2, size_t n); + // http://pubs.opengroup.org/onlinepubs/009695399/functions/bcopy.html + _memmove(dest, src, num); + }, + memset__inline: function(ptr, value, num, align) { return makeSetValues(ptr, 0, value, 'null', num, align); }, @@ -4951,7 +4934,17 @@ LibraryManager.library = { (chr >= {{{ charCode('{') }}} && chr <= {{{ charCode('~') }}}); }, isspace: function(chr) { - return chr in { 32: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0 }; + switch(chr) { + case 32: + case 9: + case 10: + case 11: + case 12: + case 13: + return true; + default: + return false; + }; }, isblank: function(chr) { return chr == {{{ charCode(' ') }}} || chr == {{{ charCode('\t') }}}; @@ -6165,9 +6158,14 @@ LibraryManager.library = { {{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'date.getUTCDay()', 'i32') }}} {{{ makeSetValue('tmPtr', 'offsets.tm_gmtoff', '0', 'i32') }}} {{{ makeSetValue('tmPtr', 'offsets.tm_isdst', '0', 'i32') }}} - - var start = new Date(date.getFullYear(), 0, 1); - var yday = Math.round((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); + var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC + start.setUTCDate(1); + start.setUTCMonth(0); + start.setUTCHours(0); + start.setUTCMinutes(0); + start.setUTCSeconds(0); + start.setUTCMilliseconds(0); + var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); {{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}} var timezone = "GMT"; @@ -6178,7 +6176,6 @@ LibraryManager.library = { return tmPtr; }, - timegm__deps: ['mktime'], timegm: function(tmPtr) { _tzset(); diff --git a/src/library_jansson.js b/src/library_jansson.js index 93f239fc..da8c5aa8 100644 --- a/src/library_jansson.js +++ b/src/library_jansson.js @@ -79,7 +79,7 @@ var LibraryJansson = { load: function(string, flags, error) { // This is potentially a security problem. // TODO: Make sure everything is properly escaped - var json_obj = eval('(' + string + ')'); + var json_obj = JSON.parse(string); if (json_obj != null) { // The context is an array storing all child nodes. diff --git a/src/library_openal.js b/src/library_openal.js index 6a97fce7..d2516559 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -5,6 +5,8 @@ var LibraryOpenAL = { $AL: { contexts: [], currentContext: null, + QUEUE_INTERVAL: 25, + QUEUE_LOOKAHEAD: 100 }, alcProcessContext: function(context) {}, @@ -39,6 +41,7 @@ var LibraryOpenAL = { alcDestroyContext: function(context) { // Stop playback, etc + clearInterval(context.interval); }, alcCloseDevice: function(device) { @@ -54,6 +57,7 @@ var LibraryOpenAL = { } }, + alcCreateContext__deps: ['updateSources'], alcCreateContext: function(device, attrList) { if (device != 1) { return 0; @@ -76,18 +80,152 @@ var LibraryOpenAL = { } if (ctx) { - AL.contexts.push({ctx: ctx, err: 0, src: [], buf: []}); + var context = { + ctx: ctx, + err: 0, + src: [], + buf: [], + interval: setInterval(function () { _updateSources(context); }, AL.QUEUE_INTERVAL) + }; + AL.contexts.push(context); return AL.contexts.length; } else { return 0; } }, + updateSources__deps: ['updateSource'], + updateSources: function (context) { + for (var i = 0; i < context.src.length; i++) { + _updateSource(context.src[i]); + } + }, + + updateSource__deps: ['setSourceState'], + updateSource: function (src) { +#if OPENAL_DEBUG + var idx = AL.currentContext.src.indexOf(src); +#endif + if (src.state !== 0x1012 /* AL_PLAYING */) { + return; + } + + var currentTime = AL.currentContext.ctx.currentTime; + var startTime = src.bufferPosition; + + for (var i = src.buffersPlayed; i < src.queue.length; i++) { + var entry = src.queue[i]; + + var startOffset = startTime - currentTime; + var endTime = startTime + entry.buffer.duration; + + // Clean up old buffers. + if (currentTime >= endTime) { + // Update our location in the queue. + src.bufferPosition = endTime; + src.buffersPlayed = i + 1; + + // Stop / restart the source when we hit the end. + if (src.buffersPlayed >= src.queue.length) { + if (src.loop) { + _setSourceState(src, 0x1012 /* AL_PLAYING */); + } else { + _setSourceState(src, 0x1014 /* AL_STOPPED */); + } + } + } + // Process all buffers that'll be played before the next tick. + else if (startOffset < (AL.QUEUE_LOOKAHEAD / 1000) && !entry.src) { + // If the start offset is negative, we need to offset the actual buffer. + var offset = Math.abs(Math.min(startOffset, 0)); + + entry.src = AL.currentContext.ctx.createBufferSource(); + entry.src.buffer = entry.buffer; + entry.src.connect(src.gain); + entry.src.start(startTime, offset); + +#if OPENAL_DEBUG + console.log('updateSource queuing buffer ' + i + ' for source ' + idx + ' at ' + startTime + ' (offset by ' + offset + ')'); +#endif + } + + startTime = endTime; + } + }, + + setSourceState__deps: ['updateSource', 'stopSourceQueue'], + setSourceState: function (src, state) { +#if OPENAL_DEBUG + var idx = AL.currentContext.src.indexOf(src); +#endif + if (state === 0x1012 /* AL_PLAYING */) { + if (src.state !== 0x1013 /* AL_PAUSED */) { + src.state = 0x1012 /* AL_PLAYING */; + // Reset our position. + src.bufferPosition = AL.currentContext.ctx.currentTime; + src.buffersPlayed = 0; +#if OPENAL_DEBUG + console.log('setSourceState resetting and playing source ' + idx); +#endif + } else { + src.state = 0x1012 /* AL_PLAYING */; + // Use the current offset from src.bufferPosition to resume at the correct point. + src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition; +#if OPENAL_DEBUG + console.log('setSourceState resuming source ' + idx + ' at ' + src.bufferPosition.toFixed(4)); +#endif + } + _stopSourceQueue(src); + _updateSource(src); + } else if (state === 0x1013 /* AL_PAUSED */) { + if (src.state === 0x1012 /* AL_PLAYING */) { + src.state = 0x1013 /* AL_PAUSED */; + // Store off the current offset to restore with on resume. + src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition; + _stopSourceQueue(src); +#if OPENAL_DEBUG + console.log('setSourceState pausing source ' + idx + ' at ' + src.bufferPosition.toFixed(4)); +#endif + } + } else if (state === 0x1014 /* AL_STOPPED */) { + if (src.state !== 0x1011 /* AL_INITIAL */) { + src.state = 0x1014 /* AL_STOPPED */; + src.buffersPlayed = src.queue.length; + _stopSourceQueue(src); +#if OPENAL_DEBUG + console.log('setSourceState stopping source ' + idx); +#endif + } + } else if (state == 0x1011 /* AL_INITIAL */) { + if (src.state !== 0x1011 /* AL_INITIAL */) { + src.state = 0x1011 /* AL_INITIAL */; + src.bufferPosition = 0; + src.buffersPlayed = 0; +#if OPENAL_DEBUG + console.log('setSourceState initializing source ' + idx); +#endif + } + } + }, + + stopSourceQueue: function (src) { + for (var i = 0; i < src.queue.length; i++) { + var entry = src.queue[i]; + if (entry.src) { + entry.src.stop(0); + entry.src = null; + } + } + }, + alGetError: function() { if (!AL.currentContext) { return 0xA004 /* AL_INVALID_OPERATION */; } else { - return AL.currentContext.err; + // Reset error on get. + var err = AL.currentContext.err; + AL.currentContext.err = 0 /* AL_NO_ERROR */; + return err; } }, @@ -97,12 +235,12 @@ var LibraryOpenAL = { return _alGetError(); }, - alDeleteSources: function(count, sources) - { + alDeleteSources: function(count, sources) { if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alDeleteSources called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } for (var i = 0; i < count; ++i) { @@ -116,57 +254,126 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alGenSources called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } for (var i = 0; i < count; ++i) { var gain = AL.currentContext.ctx.createGain(); - var panner = AL.currentContext.ctx.createPanner(); - panner.panningModel = "equalpower"; - panner.distanceModel = "linear"; - panner.rolloffFactor = 0.3; - gain.connect(panner); - panner.connect(AL.currentContext.ctx.destination); + gain.connect(AL.currentContext.ctx.destination); AL.currentContext.src.push({ + state: 0x1011 /* AL_INITIAL */, + queue: [], loop: false, - buffer: null, + get refDistance() { + return this._refDistance || 1; + }, + set refDistance(val) { + this._refDistance = val; + if (this.panner) this.panner.refDistance = val; + }, + get maxDistance() { + return this._maxDistance || 10000; + }, + set maxDistance(val) { + this._maxDistance = val; + if (this.panner) this.panner.maxDistance = val; + }, + get rolloffFactor() { + return this._rolloffFactor || 1; + }, + set rolloffFactor(val) { + this._rolloffFactor = val; + if (this.panner) this.panner.rolloffFactor = val; + }, + get position() { + return this._position || [0, 0, 0]; + }, + set position(val) { + this._position = val; + if (this.panner) this.panner.setPosition(val[0], val[1], val[2]); + }, + get velocity() { + return this._velocity || [0, 0, 0]; + }, + set velocity(val) { + this._velocity = val; + if (this.panner) this.panner.setVelocity(val[0], val[1], val[2]); + }, gain: gain, - panner: panner, - paused: false, - playTime: -1, - pausedTime: 0 + panner: null, + buffersPlayed: 0, + bufferPosition: 0 }); {{{ makeSetValue('sources', 'i*4', 'AL.currentContext.src.length', 'i32') }}}; } }, + alSourcei__deps: ['updateSource'], alSourcei: function(source, param, value) { if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourcei called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG console.error("alSourcei called with an invalid source"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } switch (param) { case 0x1007 /* AL_LOOPING */: - AL.currentContext.src[source - 1].loop = (value != 0 /* AL_FALSE */); + src.loop = (value === 1 /* AL_TRUE */); break; case 0x1009 /* AL_BUFFER */: + var buffer = AL.currentContext.buf[value - 1]; if (value == 0) { - AL.currentContext.src[source - 1].buffer = null; + src.queue = []; + } else { + src.queue = [{ buffer: buffer }]; + } + _updateSource(src); + break; + case 0x202 /* AL_SOURCE_RELATIVE */: + if (value === 1 /* AL_TRUE */) { + if (src.panner) { + src.panner = null; + + // Disconnect from the panner. + src.gain.disconnect(); + + src.gain.connect(AL.currentContext.ctx.destination); + } + } else if (value === 0 /* AL_FALSE */) { + if (!src.panner) { + var panner = src.panner = AL.currentContext.ctx.createPanner(); + panner.panningModel = "equalpower"; + panner.distanceModel = "linear"; + panner.refDistance = src.refDistance; + panner.maxDistance = src.maxDistance; + panner.rolloffFactor = src.rolloffFactor; + panner.setPosition(src.position[0], src.position[1], src.position[2]); + panner.setVelocity(src.velocity[0], src.velocity[1], src.velocity[2]); + panner.connect(AL.currentContext.ctx.destination); + + // Disconnect from the default source. + src.gain.disconnect(); + + src.gain.connect(panner); + } } else { - AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[value - 1].buf; + AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */; } break; default: #if OPENAL_DEBUG console.log("alSourcei with param " + param + " not implemented yet"); #endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; break; } }, @@ -176,130 +383,168 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourcef called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG console.error("alSourcef called with an invalid source"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } switch (param) { - case 0x100A /* AL_GAIN */: - if (AL.currentContext.src[source - 1]) { - AL.currentContext.src[source - 1].gain.gain.value = value; - } - break; case 0x1003 /* AL_PITCH */: #if OPENAL_DEBUG - console.log("alSourcef was called with AL_PITCH, but Web Audio does not support static pitch changes"); + console.log("alSourcef was called with 0x1003 /* AL_PITCH */, but Web Audio does not support static pitch changes"); #endif break; + case 0x100A /* AL_GAIN */: + src.gain.gain.value = value; + break; + // case 0x100D /* AL_MIN_GAIN */: + // break; + // case 0x100E /* AL_MAX_GAIN */: + // break; + case 0x1023 /* AL_MAX_DISTANCE */: + src.maxDistance = value; + break; + case 0x1021 /* AL_ROLLOFF_FACTOR */: + src.rolloffFactor = value; + break; + // case 0x1022 /* AL_CONE_OUTER_GAIN */: + // break; + // case 0x1001 /* AL_CONE_INNER_ANGLE */: + // break; + // case 0x1002 /* AL_CONE_OUTER_ANGLE */: + // break; + case 0x1020 /* AL_REFERENCE_DISTANCE */: + src.refDistance = value; + break; default: #if OPENAL_DEBUG console.log("alSourcef with param " + param + " not implemented yet"); #endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; break; } }, - alSourcefv: function(source, param, value) { + alSource3f: function(source, param, v1, v2, v3) { if (!AL.currentContext) { #if OPENAL_DEBUG - console.error("alSourcefv called without a valid context"); + console.error("alSource3f called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG - console.error("alSourcefv called with an invalid source"); + console.error("alSource3f called with an invalid source"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } switch (param) { case 0x1004 /* AL_POSITION */: - AL.currentContext.src[source - 1].panner.setPosition( - {{{ makeGetValue('value', '0', 'float') }}}, - {{{ makeGetValue('value', '4', 'float') }}}, - {{{ makeGetValue('value', '8', 'float') }}} - ); + src.position = [v1, v2, v3]; break; case 0x1006 /* AL_VELOCITY */: - AL.currentContext.src[source - 1].panner.setVelocity( - {{{ makeGetValue('value', '0', 'float') }}}, - {{{ makeGetValue('value', '4', 'float') }}}, - {{{ makeGetValue('value', '8', 'float') }}} - ); + src.velocity = [v1, v2, v3]; break; default: #if OPENAL_DEBUG - console.log("alSourcefv with param " + param + " not implemented yet"); + console.log("alSource3f with param " + param + " not implemented yet"); #endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; break; } }, + alSourcefv__deps: ['alSource3f'], + alSourcefv: function(source, param, value) { + _alSource3f(source, param, + {{{ makeGetValue('value', '0', 'float') }}}, + {{{ makeGetValue('value', '4', 'float') }}}, + {{{ makeGetValue('value', '8', 'float') }}}); + }, + + alSourceQueueBuffers__deps: ["updateSource"], alSourceQueueBuffers: function(source, count, buffers) { if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called with an invalid source"); #endif - return; - } - if (count != 1) { -#if OPENAL_DEBUG - console.error("Queuing multiple buffers using alSourceQueueBuffers is not supported yet"); -#endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } for (var i = 0; i < count; ++i) { - var buffer = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; - if (buffer > AL.currentContext.buf.length) { + var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; + if (bufferIdx > AL.currentContext.buf.length) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called with an invalid buffer"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } - AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[buffer - 1].buf; } + + for (var i = 0; i < count; ++i) { + var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; + var buffer = AL.currentContext.buf[bufferIdx - 1]; + src.queue.push({ buffer: buffer, src: null }); + } + + _updateSource(src); }, - alSourceUnqueueBuffers: function(source, count, buffers) - { + alSourceUnqueueBuffers__deps: ["updateSource"], + alSourceUnqueueBuffers: function(source, count, buffers) { if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called with an invalid source"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } - if (count != 1) { -#if OPENAL_DEBUG - console.error("Queuing multiple buffers using alSourceUnqueueBuffers is not supported yet"); -#endif + + if (count > src.buffersPlayed) { + AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */; return; } - for (var i = 0; i < count; ++i) { - var buffer = AL.currentContext.src[source - 1].buffer; - for (var j = 0; j < AL.currentContext.buf.length; ++j) { - if (buffer == AL.currentContext.buf[j].buf) { + + for (var i = 0; i < count; i++) { + var entry = src.queue.shift(); + // Write the buffers index out to the return list. + for (var j = 0; j < AL.currentContext.buf.length; j++) { + var b = AL.currentContext.buf[j]; + if (b && b == entry.buffer) { {{{ makeSetValue('buffers', 'i*4', 'j+1', 'i32') }}}; - AL.currentContext.src[source - 1].buffer = null; break; } } + src.buffersPlayed--; } + + _updateSource(src); }, alDeleteBuffers: function(count, buffers) @@ -308,21 +553,43 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alDeleteBuffers called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; + return; + } + if (count > AL.currentContext.buf.length) { + AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */; return; } + for (var i = 0; i < count; ++i) { var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1; - if (bufferIdx < AL.currentContext.buf.length && AL.currentContext.buf[bufferIdx]) { - var buffer = AL.currentContext.buf[bufferIdx].buf; - for (var j = 0; j < AL.currentContext.src.length; ++j) { - if (buffer == AL.currentContext.src[j].buffer) { - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; + + // Make sure the buffer index is valid. + if (bufferIdx >= AL.currentContext.buf.length || !AL.currentContext.buf[bufferIdx]) { + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; + return; + } + + // Make sure the buffer is no longer in use. + var buffer = AL.currentContext.buf[bufferIdx]; + for (var j = 0; j < AL.currentContext.src.length; ++j) { + var src = AL.currentContext.src[j]; + if (!src) { + continue; + } + for (var k = 0; k < src.queue.length; k++) { + if (buffer === src.queue[k].buffer) { + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; |