aboutsummaryrefslogtreecommitdiff
path: root/src/library_sdl.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library_sdl.js')
-rw-r--r--src/library_sdl.js119
1 files changed, 108 insertions, 11 deletions
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();
}