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.js277
1 files changed, 234 insertions, 43 deletions
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 33a33c09..73848502 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -16,9 +16,18 @@ var LibrarySDL = {
surfaces: {},
events: [],
- audios: [null],
fonts: [null],
+ audios: [null],
+ music: {
+ audio: null,
+ volume: 1.0
+ },
+ mixerFrequency: 22050,
+ mixerFormat: 0x8010, // AUDIO_S16LSB
+ mixerNumChannels: 2,
+ mixerChunkSize: 1024,
+
keyboardState: null,
shiftKey: false,
ctrlKey: false,
@@ -218,6 +227,10 @@ var LibrarySDL = {
return 'rgba(' + r + ',' + g + ',' + b + ',' + (a/255) + ')';
},
+ translateRGBAToColor: function(r, g, b, a) {
+ return (r << 24) + (g << 16) + (b << 8) + a;
+ },
+
makeSurface: function(width, height, flags, usePageCanvas, source, rmask, gmask, bmask, amask) {
flags = flags || 0;
var surf = _malloc(14*Runtime.QUANTUM_SIZE); // SDL_Surface has 14 fields of quantum size
@@ -225,19 +238,23 @@ var LibrarySDL = {
var pixelFormat = _malloc(18*Runtime.QUANTUM_SIZE);
flags |= 1; // SDL_HWSURFACE - this tells SDL_MUSTLOCK that this needs to be locked
+ //surface with SDL_HWPALETTE flag is 8bpp surface (1 byte)
+ var is_SDL_HWPALETTE = flags & 0x00200000;
+ var bpp = is_SDL_HWPALETTE ? 1 : 4;
+
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}} // SDL_Surface.flags
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*1', '0', 'pixelFormat', 'void*') }}} // SDL_Surface.format TODO
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*2', '0', 'width', 'i32') }}} // SDL_Surface.w
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*3', '0', 'height', 'i32') }}} // SDL_Surface.h
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*4', '0', 'width*4', 'i32') }}} // SDL_Surface.pitch, assuming RGBA for now,
+ {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*4', '0', 'width * bpp', 'i32') }}} // SDL_Surface.pitch, assuming RGBA or indexed for now,
// since that is what ImageData gives us in browsers
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*5', '0', 'buffer', 'void*') }}} // SDL_Surface.pixels
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*6', '0', '0', 'i32*') }}} // SDL_Surface.offset
{{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.format', '0', '-2042224636', 'i32') }}} // SDL_PIXELFORMAT_RGBA8888
{{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.palette', '0', '0', 'i32') }}} // TODO
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BitsPerPixel', '0', '32', 'i8') }}} // TODO
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BytesPerPixel', '0', '4', 'i8') }}} // TODO
+ {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BitsPerPixel', '0', 'bpp * 8', 'i8') }}}
+ {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BytesPerPixel', '0', 'bpp', 'i8') }}}
{{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.Rmask', '0', 'rmask || 0x000000ff', 'i32') }}}
{{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.Gmask', '0', 'gmask || 0x0000ff00', 'i32') }}}
@@ -267,11 +284,54 @@ var LibrarySDL = {
flags: flags,
locked: 0,
usePageCanvas: usePageCanvas,
- source: source
+ source: source,
+
+ isFlagSet: function (flag) {
+ return flags & flag;
+ }
};
+
return surf;
},
+ // Copy data from the C++-accessible storage to the canvas backing
+ // for surface with HWPALETTE flag(8bpp depth)
+ copyIndexedColorData: function(surfData, rX, rY, rW, rH) {
+ // HWPALETTE works with palette
+ // setted by SDL_SetColors
+ if (!surfData.colors) {
+ return;
+ }
+
+ var fullWidth = Module['canvas'].width;
+ var fullHeight = Module['canvas'].height;
+
+ var startX = rX || 0;
+ var startY = rY || 0;
+ var endX = (rW || (fullWidth - startX)) + startX;
+ var endY = (rH || (fullHeight - startY)) + startY;
+
+ var buffer = surfData.buffer;
+ var data = surfData.image.data;
+ var colors = surfData.colors;
+
+ for (var y = startY; y < endY; ++y) {
+ var indexBase = y * fullWidth;
+ var colorBase = indexBase * 4;
+ for (var x = startX; x < endX; ++x) {
+ // HWPALETTE have only 256 colors (not rgba)
+ var index = {{{ makeGetValue('buffer + indexBase + x', '0', 'i8', null, true) }}};
+ var color = colors[index] || [Math.floor(Math.random()*255),Math.floor(Math.random()*255),Math.floor(Math.random()*255)]; // XXX
+ var colorOffset = colorBase + x * 4;
+
+ data[colorOffset ] = color[0];
+ data[colorOffset +1] = color[1];
+ data[colorOffset +2] = color[2];
+ //unused: data[colorOffset +3] = color[3];
+ }
+ }
+ },
+
freeSurface: function(surf) {
_free(SDL.surfaces[surf].buffer);
_free(SDL.surfaces[surf].pixelFormat);
@@ -383,8 +443,21 @@ var LibrarySDL = {
}
// fall through
case 'mousemove': {
- var x = event.pageX - Module['canvas'].offsetLeft;
- var y = event.pageY - Module['canvas'].offsetTop;
+ 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);
+ var x = SDL.mouseX + movementX;
+ var y = SDL.mouseY + movementY;
+ } else {
+ // Otherwise, calculate the movement based on the changes
+ // in the coordinates.
+ var x = event.pageX - Module["canvas"].offsetLeft;
+ var y = event.pageY - Module["canvas"].offsetTop;
+ var movementX = x - SDL.mouseX;
+ var movementY = y - SDL.mouseY;
+ }
if (event.type != 'mousemove') {
var down = event.type === 'mousedown';
{{{ makeSetValue('ptr', 'SDL.structs.MouseButtonEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
@@ -397,8 +470,8 @@ var LibrarySDL = {
{{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.state', 'SDL.buttonState', 'i8') }}};
{{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.x', 'x', 'i32') }}};
{{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.y', 'y', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.xrel', 'Browser.getMovementX(x - SDL.mouseX, event)', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.yrel', 'Browser.getMovementY(y - SDL.mouseY, event)', 'i32') }}};
+ {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.xrel', 'movementX', 'i32') }}};
+ {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.yrel', 'movementY', 'i32') }}};
}
SDL.mouseX = x;
SDL.mouseY = y;
@@ -434,6 +507,16 @@ var LibrarySDL = {
}
},
+ setGetVolume: function(info, volume) {
+ if (!info) return 0;
+ var ret = info.volume * 128; // MIX_MAX_VOLUME
+ if (volume != -1) {
+ info.volume = volume / 128;
+ if (info.audio) info.audio.volume = info.volume;
+ }
+ return ret;
+ },
+
// Debugging
debugSurface: function(surfData) {
@@ -536,6 +619,10 @@ var LibrarySDL = {
return SDL.screen = SDL.makeSurface(width, height, flags, true, 'screen');
},
+ SDL_GetVideoSurface: function() {
+ return SDL.screen;
+ },
+
SDL_QuitSubSystem: function(flags) {
Module.print('SDL_QuitSubSystem called (and ignored)');
},
@@ -566,6 +653,26 @@ var LibrarySDL = {
}
if (SDL.defaults.copyOnLock) {
// Copy pixel data to somewhere accessible to 'C/C++'
+ if (surfData.isFlagSet(0x00200000 /* SDL_HWPALETTE */)) {
+ // If this is neaded then
+ // we should compact the data from 32bpp to 8bpp index.
+ // I think best way to implement this is use
+ // additional colorMap hash (color->index).
+ // Something like this:
+ //
+ // var size = surfData.width * surfData.height;
+ // var data = '';
+ // for (var i = 0; i<size; i++) {
+ // var color = SDL.translateRGBAToColor(
+ // surfData.image.data[i*4 ],
+ // surfData.image.data[i*4 +1],
+ // surfData.image.data[i*4 +2],
+ // 255);
+ // var index = surfData.colorMap[color];
+ // {{{ makeSetValue('surfData.buffer', 'i', 'index', 'i8') }}};
+ // }
+ throw 'CopyOnLock is not supported for SDL_LockSurface with SDL_HWPALETTE flag set' + new Error().stack;
+ } else {
#if USE_TYPED_ARRAYS == 2
HEAPU8.set(surfData.image.data, surfData.buffer);
#else
@@ -574,7 +681,9 @@ var LibrarySDL = {
{{{ makeSetValue('surfData.buffer', 'i', 'surfData.image.data[i]', 'i8') }}};
}
#endif
+ }
}
+
// Mark in C/C++-accessible SDL structure
// SDL_Surface has the following fields: Uint32 flags, SDL_PixelFormat *format; int w, h; Uint16 pitch; void *pixels; ...
// So we have fields all of the same size, and 5 of them before us.
@@ -592,8 +701,10 @@ var LibrarySDL = {
if (surfData.locked > 0) return;
// Copy pixel data to image
- var num = surfData.image.data.length;
- if (!surfData.colors) {
+ if (surfData.isFlagSet(0x00200000 /* SDL_HWPALETTE */)) {
+ SDL.copyIndexedColorData(surfData);
+ } else if (!surfData.colors) {
+ var num = surfData.image.data.length;
var data = surfData.image.data;
var buffer = surfData.buffer;
#if USE_TYPED_ARRAYS == 2
@@ -615,7 +726,7 @@ var LibrarySDL = {
for (var i = 0; i < num; i++) {
// We may need to correct signs here. Potentially you can hardcode a write of 255 to alpha, say, and
// the compiler may decide to write -1 in the llvm bitcode...
- data[i] = {{{ makeGetValue('buffer', 'i', 'i8') + (CORRECT_SIGNS ? '&0xff' : '') }}};
+ data[i] = {{{ makeGetValue('buffer', 'i', 'i8', null, true) }}};
if (i % 4 == 3) data[i] = 0xff;
}
#endif
@@ -629,7 +740,7 @@ var LibrarySDL = {
var base = y*width*4;
for (var x = 0; x < width; x++) {
// See comment above about signs
- var val = {{{ makeGetValue('s++', '0', 'i8') + (CORRECT_SIGNS ? '&0xff' : '') }}};
+ var val = {{{ makeGetValue('s++', '0', 'i8', null, true) }}};
var color = colors[val] || [Math.floor(Math.random()*255),Math.floor(Math.random()*255),Math.floor(Math.random()*255)]; // XXX
var start = base + x*4;
data[start] = color[0];
@@ -753,7 +864,16 @@ var LibrarySDL = {
SDL_FillRect: function(surf, rect, color) {
var surfData = SDL.surfaces[surf];
assert(!surfData.locked); // but we could unlock and re-lock if we must..
- var r = SDL.loadRect(rect);
+
+ if (surfData.isFlagSet(0x00200000 /* SDL_HWPALETTE */)) {
+ //in SDL_HWPALETTE color is index (0..255)
+ //so we should translate 1 byte value to
+ //32 bit canvas
+ color = surfData.colors[color] || [0, 0, 0, 255];
+ color = SDL.translateRGBAToColor(color[0], color[1], color[2], 255);
+ }
+
+ var r = rect ? SDL.loadRect(rect) : { x: 0, y: 0, w: surfData.width, h: surfData.height };
surfData.ctx.save();
surfData.ctx.fillStyle = SDL.translateColorToCSSRGBA(color);
surfData.ctx.fillRect(r.x, r.y, r.w, r.h);
@@ -809,16 +929,35 @@ var LibrarySDL = {
SDL_SetColors: function(surf, colors, firstColor, nColors) {
var surfData = SDL.surfaces[surf];
- surfData.colors = [];
- for (var i = firstColor; i < nColors; i++) {
- surfData.colors[i] = Array_copy(colors + i*4, colors + i*4 + 4);
+
+ // we should create colors array
+ // only once cause client code
+ // often wants to change portion
+ // of palette not all palette.
+ if (!surfData.colors) {
+ surfData.colors = [];
+ }
+
+ for (var i = firstColor; i < firstColor + nColors; i++) {
+ surfData.colors[i] = [
+ {{{ makeGetValue('colors', 'i*4', 'i8', null, true) }}},
+ {{{ makeGetValue('colors', 'i*4 + 1', 'i8', null, true) }}},
+ {{{ makeGetValue('colors', 'i*4 + 2', 'i8', null, true) }}},
+ {{{ makeGetValue('colors', 'i*4 + 3', 'i8', null, true) }}}
+ ];
}
+
return 1;
},
SDL_MapRGB: function(fmt, r, g, b) {
// Canvas screens are always RGBA
- return r + (g << 8) + (b << 16);
+ return 0xff+((b&0xff)<<8)+((g&0xff)<<16)+((r&0xff)<<24)
+ },
+
+ SDL_MapRGBA: function(fmt, r, g, b, a) {
+ // Canvas screens are always RGBA
+ return (a&0xff)+((b&0xff)<<8)+((g&0xff)<<16)+((r&0xff)<<24)
},
SDL_WM_GrabInput: function() {},
@@ -836,7 +975,7 @@ var LibrarySDL = {
// Convert the path to relative
filename = filename.substr(1);
}
- var raw = preloadedImages[filename];
+ var raw = Module["preloadedImages"][filename];
if (!raw) {
Runtime.warnOnce('Cannot find preloaded image ' + filename);
return 0;
@@ -928,10 +1067,17 @@ var LibrarySDL = {
SDL_CondWait: function() {},
SDL_DestroyCond: function() {},
+ SDL_StartTextInput: function() {}, // TODO
+ SDL_StopTextInput: function() {}, // TODO
+
// SDL Mixer
Mix_OpenAudio: function(frequency, format, channels, chunksize) {
SDL.allocateChannels(32);
+ SDL.mixerFrequency = frequency;
+ SDL.mixerFormat = format;
+ SDL.mixerNumChannels = channels;
+ SDL.mixerChunkSize = chunksize;
return 0;
},
@@ -947,11 +1093,13 @@ var LibrarySDL = {
},
Mix_Volume: function(channel, volume) {
- var info = SDL.channels[channel];
- var ret = info.volume * 128;
- info.volume = volume / 128;
- if (info.audio) info.audio.volume = info.volume;
- return ret;
+ if (channel == -1) {
+ for (var i = 0; i < SDL.numChannels-1; i++) {
+ _Mix_Volume(i, volume);
+ }
+ return _Mix_Volume(SDL.numChannels-1, volume);
+ }
+ return SDL.setGetVolume(SDL.channels[channel], volume);
},
Mix_SetPanning: function() {
@@ -960,7 +1108,7 @@ var LibrarySDL = {
Mix_LoadWAV_RW: function(filename, freesrc) {
filename = FS.standardizePath(Pointer_stringify(filename));
- var raw = preloadedAudios[filename];
+ var raw = Module["preloadedAudios"][filename];
if (!raw) {
Runtime.warnOnce('Cannot find preloaded audio ' + filename);
return 0;
@@ -973,13 +1121,32 @@ var LibrarySDL = {
return id;
},
+ Mix_QuickLoad_RAW: function(mem, len) {
+ var audio = new Audio();
+ audio['mozSetup'](SDL.mixerNumChannels, SDL.mixerFrequency);
+ var numSamples = (len / (SDL.mixerNumChannels * 2)) | 0;
+ 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?)
+ }
+ var id = SDL.audios.length;
+ SDL.audios.push({
+ source: '',
+ audio: audio,
+ buffer: buffer
+ });
+ return id;
+ },
+
Mix_FreeChunk: function(id) {
SDL.audios[id] = null;
},
Mix_PlayChannel: function(channel, id, loops) {
// TODO: handle loops
- var audio = SDL.audios[id].audio;
+ var info = SDL.audios[id];
+ if (!info) return 0;
+ var audio = info.audio;
if (!audio) return 0;
if (channel == -1) {
channel = 0;
@@ -990,15 +1157,20 @@ var LibrarySDL = {
}
}
}
- var info = SDL.channels[channel];
- info.audio = audio.cloneNode(true);
+ var channelInfo = SDL.channels[channel];
+ channelInfo.audio = audio = audio.cloneNode(true);
if (SDL.channelFinished) {
- info.audio['onended'] = function() { // TODO: cache these
+ audio['onended'] = function() { // TODO: cache these
Runtime.getFuncWrapper(SDL.channelFinished)(channel);
}
}
- info.audio.play();
- info.audio.volume = info.volume;
+ if (info.buffer) {
+ audio['mozSetup'](SDL.mixerNumChannels, SDL.mixerFrequency);
+ audio["mozWriteAudio"](info.buffer);
+ } else {
+ audio.play();
+ }
+ audio.volume = channelInfo.volume;
return channel;
},
Mix_PlayChannelTimed: 'Mix_PlayChannel', // XXX ignore Timing
@@ -1019,48 +1191,59 @@ var LibrarySDL = {
return 0;
},
+ Mix_HookMusicFinished__deps: ['Mix_HaltMusic'],
Mix_HookMusicFinished: function(func) {
SDL.hookMusicFinished = func;
+ if (SDL.music.audio) { // ensure the callback will be called, if a music is already playing
+ SDL.music.audio['onended'] = _Mix_HaltMusic;
+ }
},
- Mix_VolumeMusic: function(func) {
- return 0; // TODO
+ Mix_VolumeMusic: function(volume) {
+ return SDL.setGetVolume(SDL.music, volume);
},
Mix_LoadMUS: 'Mix_LoadWAV_RW',
Mix_FreeMusic: 'Mix_FreeChunk',
+ Mix_PlayMusic__deps: ['Mix_HaltMusic'],
Mix_PlayMusic: function(id, loops) {
loops = Math.max(loops, 1);
var audio = SDL.audios[id].audio;
if (!audio) return 0;
audio.loop = loops != 1; // TODO: handle N loops for finite N
- audio.play();
- SDL.music = audio;
+ if (SDL.audios[id].buffer) {
+ audio["mozWriteAudio"](SDL.audios[id].buffer);
+ } else {
+ audio.play();
+ }
+ audio.volume = SDL.music.volume;
+ audio['onended'] = _Mix_HaltMusic; // will send callback
+ SDL.music.audio = audio;
return 0;
},
- Mix_PauseMusic: function(id) {
- var audio = SDL.audios[id];
+ Mix_PauseMusic: function() {
+ var audio = SDL.music.audio;
if (!audio) return 0;
- audio.audio.pause();
+ audio.pause();
return 0;
},
- Mix_ResumeMusic: function(id) {
- var audio = SDL.audios[id];
+ Mix_ResumeMusic: function() {
+ var audio = SDL.music.audio;
if (!audio) return 0;
- audio.audio.play();
+ audio.play();
return 0;
},
Mix_HaltMusic: function() {
- var audio = SDL.music;
+ var audio = SDL.music.audio;
if (!audio) return 0;
audio.src = audio.src; // rewind
audio.pause();
- SDL.music = null;
+ SDL.music.audio = null;
if (SDL.hookMusicFinished) {
FUNCTION_TABLE[SDL.hookMusicFinished]();
}
@@ -1071,6 +1254,14 @@ var LibrarySDL = {
Mix_FadeOutMusic: 'Mix_HaltMusic', // XXX ignore fading out effect
+ Mix_PlayingMusic: function() {
+ return (SDL.music.audio && !SDL.music.audio.paused) ? 1 : 0;
+ },
+
+ Mix_PausedMusic: function() {
+ return (SDL.music.audio && SDL.music.audio.paused) ? 1 : 0;
+ },
+
// SDL TTF
TTF_Init: function() { return 0 },