diff options
Diffstat (limited to 'src/library_sdl.js')
-rw-r--r-- | src/library_sdl.js | 277 |
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 }, |