diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-09-09 18:33:48 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-09-09 18:33:48 -0700 |
commit | 24e61522f29d3796c0a1d2736d6008006b2e4ad6 (patch) | |
tree | 8f730aba89278f06856275a4c6f7c226d8082f5a /src | |
parent | b12e4059465169ae9302c3565b08fc30e9132781 (diff) | |
parent | 953ebf768763fe93a0af76f5007d1f69f91d6440 (diff) |
Merge branch 'incoming'
Diffstat (limited to 'src')
-rw-r--r-- | src/experimental/sdl_key_forwarding.diff | 57 | ||||
-rw-r--r-- | src/library.js | 45 | ||||
-rw-r--r-- | src/library_browser.js | 31 | ||||
-rw-r--r-- | src/library_sdl.js | 119 | ||||
-rw-r--r-- | src/postamble.js | 26 | ||||
-rw-r--r-- | src/settings.js | 12 |
6 files changed, 229 insertions, 61 deletions
diff --git a/src/experimental/sdl_key_forwarding.diff b/src/experimental/sdl_key_forwarding.diff new file mode 100644 index 00000000..395dc110 --- /dev/null +++ b/src/experimental/sdl_key_forwarding.diff @@ -0,0 +1,57 @@ +diff --git a/src/library_sdl.js b/src/library_sdl.js +index 8cb8db7..d46a089 100644 +--- a/src/library_sdl.js ++++ b/src/library_sdl.js +@@ -43,6 +43,7 @@ var LibrarySDL = { + DOMButtons: [0, 0, 0], + + DOMEventToSDLEvent: {}, ++ forwardedDOMKeys: {}, + + keyCodes: { // DOM code ==> SDL code. See https://developer.mozilla.org/en/Document_Object_Model_%28DOM%29/KeyboardEvent and SDL_keycode.h + 46: 127, // SDLK_DEL == '\177' +@@ -372,6 +373,11 @@ var LibrarySDL = { + if (!SDL.DOMButtons[event.button]) return false; // ignore extra ups, can happen if we leave the canvas while pressing down, then return, + // since we add a mouseup in that case + SDL.DOMButtons[event.button] = 0; ++ } else if (event.type == 'keydown' || event.type == 'keyup') { ++ // whitelist a few keycodes that we do want to let the browser handle ++ if (event.keyCode in SDL.forwardedDOMKeys) { ++ return true; ++ } + } + + SDL.events.push(event); +@@ -399,6 +405,10 @@ var LibrarySDL = { + // Force-run a main event loop, since otherwise this event will never be caught! + Browser.mainLoop.runner(); + return true; ++ case 'keypress': ++ if (event.ctrlKey) { ++ return true; // forward control-X events, see SDL.forwardedDOMKeys ++ } + } + return false; + }, +@@ -569,13 +579,20 @@ var LibrarySDL = { + window.onunload = SDL.receiveEvent; + SDL.keyboardState = _malloc(0x10000); + _memset(SDL.keyboardState, 0, 0x10000); +- // Initialize this structure carefully for closure ++ // Initialize these structures carefully for closure + SDL.DOMEventToSDLEvent['keydown'] = 0x300 /* SDL_KEYDOWN */; + SDL.DOMEventToSDLEvent['keyup'] = 0x301 /* SDL_KEYUP */; + SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */; + SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */; + SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */; + SDL.DOMEventToSDLEvent['unload'] = 0x100 /* SDL_QUIT */; ++ SDL.forwardedDOMKeys[17] = 1; // control - forward control-X to keep the page responsive ++ SDL.forwardedDOMKeys[173] = 1; // minus (shrink view) ++ SDL.forwardedDOMKeys[61] = 1; // plus (expand view) ++ SDL.forwardedDOMKeys[48] = 1; // 0 (return view to normal) ++ SDL.forwardedDOMKeys[84] = 1; // t (new tab) ++ SDL.forwardedDOMKeys[87] = 1; // w (close tab) ++ SDL.forwardedDOMKeys[82] = 1; // r (reload) + return 0; // success + }, + diff --git a/src/library.js b/src/library.js index 0eefea84..d2d61867 100644 --- a/src/library.js +++ b/src/library.js @@ -4755,10 +4755,19 @@ LibraryManager.library = { __cxa_is_number_type: function(type) { var isNumber = false; try { if (type == __ZTIi) isNumber = true } catch(e){} + try { if (type == __ZTIj) isNumber = true } catch(e){} try { if (type == __ZTIl) isNumber = true } catch(e){} + try { if (type == __ZTIm) isNumber = true } catch(e){} try { if (type == __ZTIx) isNumber = true } catch(e){} + try { if (type == __ZTIy) isNumber = true } catch(e){} try { if (type == __ZTIf) isNumber = true } catch(e){} try { if (type == __ZTId) isNumber = true } catch(e){} + try { if (type == __ZTIe) isNumber = true } catch(e){} + try { if (type == __ZTIc) isNumber = true } catch(e){} + try { if (type == __ZTIa) isNumber = true } catch(e){} + try { if (type == __ZTIh) isNumber = true } catch(e){} + try { if (type == __ZTIs) isNumber = true } catch(e){} + try { if (type == __ZTIt) isNumber = true } catch(e){} return isNumber; }, @@ -4839,22 +4848,22 @@ LibraryManager.library = { // RTTI hacks for exception handling, defining type_infos for common types. // The values are dummies. We simply use the addresses of these statically // allocated variables as unique identifiers. - // type_info for int. - _ZTIi: [0], - // type_info for long. - _ZTIl: [0], - // type_info for long long. - _ZTIx: [0], - // type_info for float. - _ZTIf: [0], - // type_info for double. - _ZTId: [0], - // type_info for char. - _ZTIc: [0], - // type_info for void. - _ZTIv: [0], - // type_info for void*. - _ZTIPv: [0], + _ZTIi: [0], // int + _ZTIj: [0], // unsigned int + _ZTIl: [0], // long + _ZTIm: [0], // unsigned long + _ZTIx: [0], // long long + _ZTIy: [0], // unsigned long long + _ZTIf: [0], // float + _ZTId: [0], // double + _ZTIe: [0], // long double + _ZTIc: [0], // char + _ZTIa: [0], // signed char + _ZTIh: [0], // unsigned char + _ZTIs: [0], // short + _ZTIt: [0], // signed short + _ZTIv: [0], // void + _ZTIPv: [0], // void* llvm_uadd_with_overflow_i8: function(x, y) { x = x & 0xff; @@ -5669,7 +5678,7 @@ LibraryManager.library = { // http://pubs.opengroup.org/onlinepubs/009695399/functions/times.html // NOTE: This is fake, since we can't calculate real CPU time usage in JS. if (buffer !== 0) { - memset(buffer, 0, ___tms_struct_layout.__size__); + _memset(buffer, 0, ___tms_struct_layout.__size__); } return 0; }, @@ -6295,7 +6304,7 @@ LibraryManager.library = { htonl: function(value) { return ((value & 0xff) << 24) + ((value & 0xff00) << 8) + - ((value & 0xff0000) >> 8) + ((value & 0xff000000) >> 24); + ((value & 0xff0000) >>> 8) + ((value & 0xff000000) >>> 24); }, htons: function(value) { return ((value & 0xff) << 8) + ((value & 0xff00) >> 8); diff --git a/src/library_browser.js b/src/library_browser.js index e6a8b7c6..bf235493 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -10,10 +10,6 @@ mergeInto(LibraryManager.library, { $Browser: { mainLoop: { scheduler: null, -#if PROFILE_MAIN_LOOP - meanTime: 0, - lastReport: 0, -#endif shouldPause: false, paused: false, queue: [], @@ -383,8 +379,14 @@ mergeInto(LibraryManager.library, { emscripten_set_main_loop: function(func, fps) { Module['noExitRuntime'] = true; +#if PROFILE_MAIN_LOOP + Module['totalTime'] = 0; + Module['iterations'] = 0; + Module['maxTime'] = 0; +#endif + var jsFunc = FUNCTION_TABLE[func]; - var wrapper = function() { + Browser.mainLoop.runner = function() { if (Browser.mainLoop.queue.length > 0) { var start = Date.now(); var blocker = Browser.mainLoop.queue.shift(); @@ -402,7 +404,7 @@ mergeInto(LibraryManager.library, { } console.log('main loop blocker "' + blocker.name + '" took ' + (Date.now() - start) + ' ms'); //, left: ' + Browser.mainLoop.remainingBlockers); Browser.mainLoop.updateStatus(); - setTimeout(wrapper, 0); + setTimeout(Browser.mainLoop.runner, 0); return; } if (Browser.mainLoop.shouldPause) { @@ -415,15 +417,14 @@ mergeInto(LibraryManager.library, { #if PROFILE_MAIN_LOOP var start = performance.now(); #endif + jsFunc(); + #if PROFILE_MAIN_LOOP - var now = performance.now(); - var time = now - start; - Browser.mainLoop.meanTime = (Browser.mainLoop.meanTime*9 + time)/10; - if (now - Browser.mainLoop.lastReport > 1000) { - console.log('main loop time: ' + Browser.mainLoop.meanTime); - Browser.mainLoop.lastReport = now; - } + var time = performance.now() - start; + Module['totalTime'] += time; + Module['iterations']++; + Module['maxTime'] = Math.max(Module['maxTime'], time); #endif if (Browser.mainLoop.shouldPause) { @@ -436,11 +437,11 @@ mergeInto(LibraryManager.library, { } if (fps && fps > 0) { Browser.mainLoop.scheduler = function() { - setTimeout(wrapper, 1000/fps); // doing this each time means that on exception, we stop + setTimeout(Browser.mainLoop.runner, 1000/fps); // doing this each time means that on exception, we stop } } else { Browser.mainLoop.scheduler = function() { - Browser.requestAnimationFrame(wrapper); + Browser.requestAnimationFrame(Browser.mainLoop.runner); } } Browser.mainLoop.scheduler(); diff --git a/src/library_sdl.js b/src/library_sdl.js index 48c18c8b..da1e88af 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -18,7 +18,9 @@ var LibrarySDL = { events: [], fonts: [null], + // The currently preloaded audio elements ready to be played audios: [null], + // The currently playing audio element. There's only one music track. music: { audio: null, volume: 1.0 @@ -346,9 +348,19 @@ var LibrarySDL = { receiveEvent: function(event) { switch(event.type) { case 'mousemove': - // workaround for firefox bug 750111 - event['movementX'] = event['mozMovementX']; - event['movementY'] = event['mozMovementY']; + if (Browser.pointerLock) { + // workaround for firefox bug 750111 + if ('mozMovementX' in event) { + event['movementX'] = event['mozMovementX']; + event['movementY'] = event['mozMovementY']; + } + // workaround for Firefox bug 782777 + if (event['movementX'] == 0 && event['movementY'] == 0) { + // ignore a mousemove event if it doesn't contain any movement info + // (without pointer lock, we infer movement from pageX/pageY, so this check is unnecessary) + return false; + } + } // fall through case 'keydown': case 'keyup': case 'mousedown': case 'mouseup': case 'DOMMouseScroll': case 'mousewheel': if (event.type == 'DOMMouseScroll' || event.type == 'mousewheel') { @@ -394,6 +406,11 @@ var LibrarySDL = { } } break; + case 'unload': + SDL.events.push(event); + // Force-run a main event loop, since otherwise this event will never be caught! + Browser.mainLoop.runner(); + return true; } return false; }, @@ -457,8 +474,14 @@ var LibrarySDL = { if (Browser.pointerLock) { // When the pointer is locked, calculate the coordinates // based on the movement of the mouse. - var movementX = Browser.getMovementX(event); - var movementY = Browser.getMovementY(event); + // Workaround for Firefox bug 764498 + if (event.type != 'mousemove' && + ('mozMovementX' in event)) { + var movementX = 0, movementY = 0; + } else { + var movementX = Browser.getMovementX(event); + var movementY = Browser.getMovementY(event); + } var x = SDL.mouseX + movementX; var y = SDL.mouseY + movementY; } else { @@ -488,6 +511,10 @@ var LibrarySDL = { SDL.mouseY = y; break; } + case 'unload': { + {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}; + break; + } default: throw 'Unhandled SDL event: ' + event.type; } }, @@ -506,6 +533,10 @@ var LibrarySDL = { // Sound + // Channels are a SDL abstraction for allowing multiple sound tracks to be + // played at the same time. We don't need to actually implement the mixing + // since the browser engine handles that for us. Therefore, in JS we just + // maintain a list of channels and return IDs for them to the SDL consumer. allocateChannels: function(num) { // called from Mix_AllocateChannels and init if (SDL.numChannels && SDL.numChannels >= num) return; SDL.numChannels = num; @@ -557,6 +588,7 @@ var LibrarySDL = { document.onkeydown = SDL.receiveEvent; document.onkeyup = SDL.receiveEvent; document.onkeypress = SDL.receiveEvent; + window.onunload = SDL.receiveEvent; SDL.keyboardState = _malloc(0x10000); _memset(SDL.keyboardState, 0, 0x10000); // Initialize this structure carefully for closure @@ -565,6 +597,7 @@ var LibrarySDL = { SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */; SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */; SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */; + SDL.DOMEventToSDLEvent['unload'] = 0x100 /* SDL_QUIT */; return 0; // success }, @@ -640,8 +673,11 @@ var LibrarySDL = { }, SDL_Quit: function() { - for (var i = 0; i < SDL.audios; i++) { - SDL.audios[i].pause(); + for (var i = 0; i < SDL.numChannels; ++i) { + SDL.channels[i].audio.pause(); + } + if (SDL.music.audio) { + SDL.music.audio.pause(); } Module.print('SDL_Quit called (and ignored)'); }, @@ -1015,6 +1051,7 @@ var LibrarySDL = { // SDL_Audio + // TODO fix SDL_OpenAudio, and add some tests for it. It's currently broken. SDL_OpenAudio: function(desired, obtained) { SDL.allocateChannels(32); @@ -1065,6 +1102,7 @@ var LibrarySDL = { SDL.audio.paused = pauseOn; }, + SDL_CloseAudio__deps: ['SDL_PauseAudio', 'free'], SDL_CloseAudio: function() { if (SDL.audio) { _SDL_PauseAudio(1); @@ -1093,6 +1131,7 @@ var LibrarySDL = { Mix_OpenAudio: function(frequency, format, channels, chunksize) { SDL.allocateChannels(32); + // Just record the values for a later call to Mix_QuickLoad_RAW SDL.mixerFrequency = frequency; SDL.mixerFormat = format; SDL.mixerNumChannels = channels; @@ -1137,6 +1176,7 @@ var LibrarySDL = { Module["preloadedAudios"][filename] = null; } var id = SDL.audios.length; + // Keep the loaded audio in the audio arrays, ready for playback SDL.audios.push({ source: filename, audio: raw @@ -1146,12 +1186,15 @@ var LibrarySDL = { Mix_QuickLoad_RAW: function(mem, len) { var audio = new Audio(); - audio['mozSetup'](SDL.mixerNumChannels, SDL.mixerFrequency); - var numSamples = (len / (SDL.mixerNumChannels * 2)) | 0; + // Record the number of channels and frequency for later usage + audio.numChannels = SDL.mixerNumChannels; + audio.frequency = SDL.mixerFrequency; + var numSamples = len >> 1; // len is the length in bytes, and the array contains 16-bit PCM values var buffer = new Float32Array(numSamples); for (var i = 0; i < numSamples; ++i) { buffer[i] = ({{{ makeGetValue('mem', 'i*2', 'i16', 0, 0) }}}) / 0x8000; // hardcoded 16-bit audio, signed (TODO: reSign if not ta2?) } + // FIXME: doesn't make sense to keep the audio element in the buffer var id = SDL.audios.length; SDL.audios.push({ source: '', @@ -1167,10 +1210,15 @@ var LibrarySDL = { Mix_PlayChannel: function(channel, id, loops) { // TODO: handle loops + + // Get the audio element associated with the ID var info = SDL.audios[id]; if (!info) return 0; var audio = info.audio; if (!audio) return 0; + + // If the user asks us to allocate a channel automatically, get the first + // free one. if (channel == -1) { channel = 0; for (var i = 0; i < SDL.numChannels; i++) { @@ -1180,6 +1228,9 @@ var LibrarySDL = { } } } + + // We clone the audio node to utilize the preloaded audio buffer, since + // the browser has already preloaded the audio file. var channelInfo = SDL.channels[channel]; channelInfo.audio = audio = audio.cloneNode(true); if (SDL.channelFinished) { @@ -1187,9 +1238,55 @@ var LibrarySDL = { Runtime.getFuncWrapper(SDL.channelFinished)(channel); } } + // Either play the element, or load the dynamic data into it if (info.buffer) { - audio['mozSetup'](SDL.mixerNumChannels, SDL.mixerFrequency); - audio["mozWriteAudio"](info.buffer); + var contextCtor = null; + if (audio && ('mozSetup' in audio)) { // Audio Data API + try { + audio['mozSetup'](audio.numChannels, audio.frequency); + audio["mozWriteAudio"](info.buffer); + } catch (e) { + // Workaround for Firefox bug 783052 + // ignore this exception! + } + /* + } else if (contextCtor = (window.AudioContext || // WebAudio API + window.webkitAudioContext)) { + var currentIndex = 0; + var numChannels = parseInt(audio.numChannels); + var context = new contextCtor(); + var source = context.createBufferSource(); + source.loop = false; + source.buffer = context.createBuffer(numChannels, 1, audio.frequency); + var jsNode = context.createJavaScriptNode(2048, numChannels, numChannels); + jsNode.onaudioprocess = function(event) { + var buffers = new Array(numChannels); + for (var i = 0; i < numChannels; ++i) { + buffers[i] = event.outputBuffer.getChannelData(i); + } + var remaining = info.buffer.length - currentIndex; + if (remaining > 2048) { + remaining = 2048; + } + for (var i = 0; i < remaining;) { + for (var j = 0; j < numChannels; ++j) { + buffers[j][i] = info.buffer[currentIndex + i + j] * audio.volume; + } + i += j; + } + currentIndex += remaining * numChannels; + for (var i = remaining; i < 2048;) { + for (var j = 0; j < numChannels; ++j) { + buffers[j][i] = 0; // silence + } + i += j; + } + }; + source.connect(jsNode); + jsNode.connect(context.destination); + source.noteOn(0); + */ + } } else { audio.play(); } diff --git a/src/postamble.js b/src/postamble.js index e1dd495a..d164f049 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -32,14 +32,21 @@ Module.callMain = function callMain(args) { function run(args) { args = args || Module['arguments']; + if (runDependencies > 0) { + Module.printErr('run() called, but dependencies remain, so not running'); + return 0; + } + if (Module['preRun']) { if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; - while (Module['preRun'].length > 0) { - Module['preRun'].pop()(); - if (runDependencies > 0) { - // preRun added a dependency, run will be called later - return 0; - } + var toRun = Module['preRun']; + Module['preRun'] = []; + for (var i = toRun.length-1; i >= 0; i--) { + toRun[i](); + } + if (runDependencies > 0) { + // a preRun added a dependency, run will be called later + return 0; } } @@ -89,14 +96,15 @@ if (Module['preInit']) { initRuntime(); #if INVOKE_RUN +var shouldRunNow = true; #else -addRunDependency(); +var shouldRunNow = false; #endif if (Module['noInitialRun']) { - addRunDependency(); + shouldRunNow = false; } -if (runDependencies == 0) { +if (shouldRunNow) { var ret = run(); #if CATCH_EXIT_CODE Module.print('Exit Status: ' + ret); diff --git a/src/settings.js b/src/settings.js index cf329568..9f63622d 100644 --- a/src/settings.js +++ b/src/settings.js @@ -5,6 +5,7 @@ // // emcc -s OPTION1=VALUE1 -s OPTION2=VALUE2 [..other stuff..] // +// See https://github.com/kripken/emscripten/wiki/Code-Generation-Modes/ // Tuning var QUANTUM_SIZE = 4; // This is the size of an individual field in a structure. 1 would @@ -51,15 +52,10 @@ var FAST_MEMORY = 2*1024*1024; // The amount of memory to initialize to 0. This // Code embetterments var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables var RELOOP = 0; // Recreate js native loops from llvm data -var USE_TYPED_ARRAYS = 2; // Use typed arrays for the heap +var USE_TYPED_ARRAYS = 2; // Use typed arrays for the heap. See https://github.com/kripken/emscripten/wiki/Code-Generation-Modes/ // 1 has two heaps, IHEAP (int32) and FHEAP (double), - // and addresses there are a match for normal addresses. This wastes memory but can be fast. - // 2 is a single heap, accessible through views as int8, int32, etc. This saves memory but - // has more overhead of pointer calculations. It also is limited to storing doubles as floats, - // simply because double stores are not necessarily 64-bit aligned, and we can only access - // 64-bit aligned values with a 64-bit typed array. Likewise int64s are stored as int32's, - // which is potentially very dangerous! - // TODO: require compiling with -malign-double, which does align doubles + // and addresses there are a match for normal addresses. + // 2 is a single heap, accessible through views as int8, int32, etc. var USE_FHEAP = 1; // Relevant in USE_TYPED_ARRAYS == 1. If this is disabled, only IHEAP will be used, and FHEAP // not generated at all. This is useful if your code is 100% ints without floats or doubles var DOUBLE_MODE = 1; // How to load and store 64-bit doubles. Without typed arrays or in typed array mode 1, |