diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/jsifier.js | 21 | ||||
-rw-r--r-- | src/library.js | 75 | ||||
-rw-r--r-- | src/library_gl.js | 427 | ||||
-rw-r--r-- | src/library_sdl.js | 80 | ||||
-rw-r--r-- | src/long.js | 1633 | ||||
-rw-r--r-- | src/parseTools.js | 58 | ||||
-rw-r--r-- | src/preamble.js | 22 | ||||
-rw-r--r-- | src/settings.js | 6 |
8 files changed, 2220 insertions, 102 deletions
diff --git a/src/jsifier.js b/src/jsifier.js index 99176fd2..dcc853f2 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -38,6 +38,7 @@ function JSify(data, functionsOnly, givenFunctions) { var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js'; var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()))); print(pre); + if (PRECISE_I64_MATH) print(read('long.js')); Functions.implementedFunctions = set(data.unparsedFunctions.map(function(func) { return func.ident })); } @@ -166,23 +167,27 @@ function JSify(data, functionsOnly, givenFunctions) { ret[index++] = 0; } // Add current value(s) - var currValue = flatten(values[i]); + var currValue = values[i]; if (USE_TYPED_ARRAYS == 2 && typeData.fields[i] == 'i64') { // 'flatten' out the 64-bit value into two 32-bit halves - ret[index++] = currValue>>>0; + var parts = parseI64Constant(currValue, true); + ret[index++] = parts[0]; ret[index++] = 0; ret[index++] = 0; ret[index++] = 0; - ret[index++] = Math.floor(currValue/4294967296); + ret[index++] = parts[1]; ret[index++] = 0; ret[index++] = 0; ret[index++] = 0; - } else if (typeof currValue == 'object') { - for (var j = 0; j < currValue.length; j++) { - ret[index++] = currValue[j]; - } } else { - ret[index++] = currValue; + currValue = flatten(currValue); + if (typeof currValue == 'object') { + for (var j = 0; j < currValue.length; j++) { + ret[index++] = currValue[j]; + } + } else { + ret[index++] = currValue; + } } i += 1; } diff --git a/src/library.js b/src/library.js index 0574bb8d..f49a8a58 100644 --- a/src/library.js +++ b/src/library.js @@ -86,6 +86,23 @@ LibraryManager.library = { parentPath: null, parentObject: null }; +#if FS_LOG + var inputPath = path; + function log() { + print('FS.analyzePath("' + inputPath + '", ' + + dontResolveLastLink + ', ' + + linksVisited + ') => {' + + 'isRoot: ' + ret.isRoot + ', ' + + 'exists: ' + ret.exists + ', ' + + 'error: ' + ret.error + ', ' + + 'name: "' + ret.name + '", ' + + 'path: "' + ret.path + '", ' + + 'object: ' + ret.object + ', ' + + 'parentExists: ' + ret.parentExists + ', ' + + 'parentPath: "' + ret.parentPath + '", ' + + 'parentObject: ' + ret.parentObject + '}'); + } +#endif path = FS.absolutePath(path); if (path == '/') { ret.isRoot = true; @@ -123,8 +140,12 @@ LibraryManager.library = { break; } var link = FS.absolutePath(current.link, traversed.join('/')); - return FS.analyzePath([link].concat(path).join('/'), - dontResolveLastLink, linksVisited + 1); + ret = FS.analyzePath([link].concat(path).join('/'), + dontResolveLastLink, linksVisited + 1); +#if FS_LOG + log(); +#endif + return ret; } traversed.push(target); if (path.length == 0) { @@ -133,8 +154,10 @@ LibraryManager.library = { ret.object = current; } } - return ret; } +#if FS_LOG + log(); +#endif return ret; }, // Finds the file system object at a given path. If dontResolveLastLink is @@ -152,6 +175,13 @@ LibraryManager.library = { }, // Creates a file system record: file, link, device or folder. createObject: function(parent, name, properties, canRead, canWrite) { +#if FS_LOG + print('FS.createObject("' + parent + '", ' + + '"' + name + '", ' + + JSON.stringify(properties) + ', ' + + canRead + ', ' + + canWrite + ')'); +#endif if (!parent) parent = '/'; if (typeof parent === 'string') parent = FS.findObject(parent); @@ -415,6 +445,14 @@ LibraryManager.library = { standardizePath: function(path) { if (path.substr(0, 2) == './') path = path.substr(2); return path; + }, + + deleteFile: function(path) { + var path = FS.analyzePath(path); + if (!path.parentExists || !path.exists) { + throw 'Invalid path ' + path; + } + delete path.parentObject.contents[path.name]; } }, @@ -2449,6 +2487,10 @@ LibraryManager.library = { var signed = next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0); argSize = argSize || 4; var currArg = getNextArg('i' + (argSize * 8)); +#if PRECISE_I64_MATH == 1 + var origArg = currArg; +#endif + var argText; #if USE_TYPED_ARRAYS == 2 // Flatten i64-1 [low, high] into a (slightly rounded) double if (argSize == 8) { @@ -2462,11 +2504,16 @@ LibraryManager.library = { } // Format the number. var currAbsArg = Math.abs(currArg); - var argText; var prefix = ''; if (next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0)) { +#if PRECISE_I64_MATH == 1 + if (argSize == 8) argText = i64Math.stringify(origArg[0], origArg[1]); else +#endif argText = reSign(currArg, 8 * argSize, 1).toString(10); } else if (next == 'u'.charCodeAt(0)) { +#if PRECISE_I64_MATH == 1 + if (argSize == 8) argText = i64Math.stringify(origArg[0], origArg[1], true); else +#endif argText = unSign(currArg, 8 * argSize, 1).toString(10); currArg = Math.abs(currArg); } else if (next == 'o'.charCodeAt(0)) { @@ -4209,11 +4256,19 @@ LibraryManager.library = { isdigit: function(chr) { return chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0); }, + isdigit_l__deps: ['isdigit'], + isdigit_l: function(chr, loc) { + return _isdigit(chr); + }, isxdigit: function(chr) { return (chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0)) || (chr >= 'a'.charCodeAt(0) && chr <= 'f'.charCodeAt(0)) || (chr >= 'A'.charCodeAt(0) && chr <= 'F'.charCodeAt(0)); }, + isxdigit_l__deps: ['isxdigit'], + isxdigit_l: function(chr, loc) { + return _isxdigit(chr); + }, isalnum: function(chr) { return (chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0)) || (chr >= 'a'.charCodeAt(0) && chr <= 'z'.charCodeAt(0)) || @@ -4604,16 +4659,20 @@ LibraryManager.library = { _ZTIPv: [0], llvm_uadd_with_overflow_i32: function(x, y) { + x = x>>>0; + y = y>>>0; return { - f0: x+y, - f1: 0 // We never overflow... for now + f0: (x+y)>>>0, + f1: x+y > 4294967295 }; }, llvm_umul_with_overflow_i32: function(x, y) { + x = x>>>0; + y = y>>>0; return { - f0: x*y, - f1: 0 // We never overflow... for now + f0: (x*y)>>>0, + f1: x*y > 4294967295 }; }, diff --git a/src/library_gl.js b/src/library_gl.js index 91f7d353..99c0f2f1 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -1,6 +1,15 @@ //"use strict"; -// XXX FIXME Hardcoded '4' in many places, here and in library_SDL, for RGBA +// FIXME: +// * glGetUniformLocation should return -1 when the value is not valid, not null +// * glUniform1fi should be glUniform1iv +// * glGetAttribLocation lacks return value (and should be -1 when not valid) +// * single-underscore deps need double underscore (and, just auto-add them all) +// * glGetProgramInfoLog and *shader* should be essentially identical +// * glGetIntegerv set to bool etc needs fixing +// * glVertexAttribPointer - the last param can be an offset or in gles, a raw pointer to clientside data. need some way to +// warn about that since it silently fails in WebGL (it's a huge offset into the last bound buffer, zeros) + var LibraryGL = { $GL: { @@ -24,6 +33,14 @@ var LibraryGL = { #endif return this.table[id]; }, + id: function(obj) { + for (var i = 1; i < this.counter; ++i) { + if (obj == this.table[i]) { + return i; + } + } + return null; + }, remove: function(id) { if( id == 0 ) return; #if ASSERTIONS @@ -45,11 +62,11 @@ var LibraryGL = { glGetString: function(name_) { switch(name_) { - case Module.ctx.VENDOR: - case Module.ctx.RENDERER: - case Module.ctx.VERSION: + case 0x1F00 /* GL_VENDOR */: + case 0x1F01 /* GL_RENDERER */: + case 0x1F02 /* GL_VERSION */: return allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL); - case 0x1F03: // Extensions + case 0x1F03 /* GL_EXTENSIONS */: return allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ')), 'i8', ALLOC_NORMAL); default: throw 'Failure: Invalid glGetString value: ' + name_; @@ -58,17 +75,125 @@ var LibraryGL = { glGenIntegerv__deps: ['$GL'], glGetIntegerv: function(name_, p) { - var v = Module.ctx.getParameter(name_); - if (name_ == Module.ctx.CURRENT_PROGRAM) - v = GL.hashtable("program").lookup(v); - else if (name_ == Module.ctx.VIEWPORT) { - {{{ makeSetValue('p', '0', 'v[0]', 'i32') }}}; - {{{ makeSetValue('p', '4', 'v[1]', 'i32') }}}; - {{{ makeSetValue('p', '8', 'v[2]', 'i32') }}}; - {{{ makeSetValue('p', '12', 'v[3]', 'i32') }}}; + var result = Module.ctx.getParameter(name_); + switch (typeof(result)) { + case "number": + {{{ makeSetValue('p', '0', 'result', 'i32') }}}; + break; + case "boolean": + {{{ makeSetValue('p', '0', 'result ? 1 : 0', 'i32') }}}; + break; + case "string": + throw 'Native code calling glGetIntegerv(' + name_ + ') on a name which returns a string!'; + case "object": + if (result === null) { + {{{ makeSetValue('p', '0', '0', 'i32') }}}; + } else if (result instanceof Float32Array || + result instanceof Uint32Array || + result instanceof Int32Array || + result instanceof Array) { + for (var i = 0; i < result.length; ++i) { + {{{ makeSetValue('p', 'i', 'result[i]', 'i32') }}}; + } + } else if (result instanceof WebGLBuffer) { + {{{ makeSetValue('p', '0', 'GL.hashtable("buffer").id(result)', 'i32') }}}; + } else if (result instanceof WebGLProgram) { + {{{ makeSetValue('p', '0', 'GL.hashtable("program").id(result)', 'i32') }}}; + } else if (result instanceof WebGLFramebuffer) { + {{{ makeSetValue('p', '0', 'GL.hashtable("framebuffer").id(result)', 'i32') }}}; + } else if (result instanceof WebGLRenderbuffer) { + {{{ makeSetValue('p', '0', 'gl.hashtable("renderbuffer").id(result)', 'i32') }}}; + } else if (result instanceof WebGLTexture) { + {{{ makeSetValue('p', '0', 'gl.hashtable("texture").id(result)', 'i32') }}}; + } else { + throw 'Unknown object returned from WebGL getParameter'; + } + break; + case "undefined": + throw 'Native code calling glGetIntegerv(' + name_ + ') and it returns undefined'; + default: + throw 'Why did we hit the default case?'; + } + }, + + glGetFloatv: function(name_, p) { + var result = Module.ctx.getParameter(name_); + switch (typeof(result)) { + case "number": + {{{ makeSetValue('p', '0', 'result', 'float') }}}; + break; + case "boolean": + {{{ makeSetValue('p', '0', 'result ? 1.0 : 0.0', 'float') }}}; + break; + case "string": + {{{ makeSetValue('p', '0', '0', 'float') }}}; + case "object": + if (result === null) { + throw 'Native code calling glGetFloatv(' + name_ + ') and it returns null'; + } else if (result instanceof Float32Array || + result instanceof Uint32Array || + result instanceof Int32Array || + result instanceof Array) { + for (var i = 0; i < result.length; ++i) { + {{{ makeSetValue('p', 'i', 'result[i]', 'float') }}}; + } + } else if (result instanceof WebGLBuffer) { + {{{ makeSetValue('p', '0', 'GL.hashtable("buffer").id(result)', 'float') }}}; + } else if (result instanceof WebGLProgram) { + {{{ makeSetValue('p', '0', 'GL.hashtable("program").id(result)', 'float') }}}; + } else if (result instanceof WebGLFramebuffer) { + {{{ makeSetValue('p', '0', 'GL.hashtable("framebuffer").id(result)', 'float') }}}; + } else if (result instanceof WebGLRenderbuffer) { + {{{ makeSetValue('p', '0', 'gl.hashtable("renderbuffer").id(result)', 'float') }}}; + } else if (result instanceof WebGLTexture) { + {{{ makeSetValue('p', '0', 'gl.hashtable("texture").id(result)', 'float') }}}; + } else { + throw 'Unknown object returned from WebGL getParameter'; + } + break; + case "undefined": + throw 'Native code calling glGetFloatv(' + name_ + ') and it returns undefined'; + default: + throw 'Why did we hit the default case?'; + } + }, + + glGetBooleanv: function(name_, p) { + var result = Module.ctx.getParameter(name_); + switch (typeof(result)) { + case "number": + {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}}; + break; + case "boolean": + {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}}; + break; + case "string": + throw 'Native code calling glGetBooleanv(' + name_ + ') on a name which returns a string!'; + case "object": + if (result === null) { + {{{ makeSetValue('p', '0', '0', 'i8') }}}; + } else if (result instanceof Float32Array || + result instanceof Uint32Array || + result instanceof Int32Array || + result instanceof Array) { + for (var i = 0; i < result.length; ++i) { + {{{ makeSetValue('p', 'i', 'result[i] != 0', 'i8') }}}; + } + } else if (result instanceof WebGLBuffer || + result instanceof WebGLProgram || + result instanceof WebGLFramebuffer || + result instanceof WebGLRenderbuffer || + result instanceof WebGLTexture) { + {{{ makeSetValue('p', '0', '1', 'i8') }}}; // non-zero ID is always 1! + } else { + throw 'Unknown object returned from WebGL getParameter'; + } + break; + case "undefined": + throw 'Unknown object returned from WebGL getParameter'; + default: + throw 'Why did we hit the default case?'; } - // TODO complete - {{{ makeSetValue('p', '0', 'v', 'i32') }}}; }, glGenTextures__deps: ['$GL'], @@ -87,18 +212,98 @@ var LibraryGL = { } }, + glCompressedTexImage2D: function(target, level, internalformat, width, height, border, imageSize, data) { + if (data) { + data = new Uint8Array(Array_copy(data, imageSize)); + } else { + data = null; + } + Module.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, data); + }, + + glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) { + if (data) { + data = new Uint8Array(Array_copy(data, imageSize)); + } else { + data = null; + } + Module.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, data); + }, + glTexImage2D: function(target, level, internalformat, width, height, border, format, type, pixels) { if (pixels) { - pixels = new Uint8Array(Array_copy(pixels, pixels + width*height*4)); // TODO: optimize + var sizePerPixel; + switch (type) { + case 0x1401 /* GL_UNSIGNED_BYTE */: + switch (format) { + case 0x1906 /* GL_ALPHA */: + case 0x1909 /* GL_LUMINANCE */: + sizePerPixel = 1; + break; + case 0x1907 /* GL_RGB */: + sizePerPixel = 3; + break; + case 0x1908 /* GL_RGBA */: + sizePerPixel = 4; + break; + case 0x190A /* GL_LUMINANCE_ALPHA */: + sizePerPixel = 2; + break; + default: + throw 'Invalid format (' + format + ') passed to glTexImage2D'; + } + pixels = new Uint8Array(Array_copy(pixels, width*height*sizePerPixel)); + break; + case 0x8363 /* GL_UNSIGNED_SHORT_5_6_5 */: + case 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4 */: + case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */: + sizePerPixel = 2; + pixels = new Uint16Array(new ArrayBuffer(Array_copy(pixels, width*height*sizePerPixel*2))); + break; + default: + throw 'Invalid type (' + type + ') passed to glTexImage2D'; + } } else { - pixels = new Uint8Array (width*height*4); + pixels = null; } Module.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, pixels); }, glTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, type, pixels) { if (pixels) { - pixels = new Uint8Array(Array_copy(pixels, pixels + width*height*4)); // TODO: optimize + var sizePerPixel; + switch (type) { + case 0x1401 /* GL_UNSIGNED_BYTE */: + switch (format) { + case 0x1906 /* GL_ALPHA */: + case 0x1909 /* GL_LUMINANCE */: + sizePerPixel = 1; + break; + case 0x1907 /* GL_RGB */: + sizePerPixel = 3; + break; + case 0x1908 /* GL_RGBA */: + sizePerPixel = 4; + break; + case 0x190A /* GL_LUMINANCE_ALPHA */: + sizePerPixel = 2; + break; + default: + throw 'Invalid format (' + format + ') passed to glTexSubImage2D'; + } + pixels = new Uint8Array(Array_copy(pixels, (width-xoffset+1)*(height-yoffset+1)*sizePerPixel)); + break; + case 0x8363 /* GL_UNSIGNED_SHORT_5_6_5 */: + case 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4 */: + case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */: + sizePerPixel = 2; + pixels = new Uint16Array(new ArrayBuffer(Array_copy(pixels, (width-xoffset+1)*(height-yoffset+1)*sizePerPixel*2))); + break; + default: + throw 'Invalid type (' + type + ') passed to glTexSubImage2D'; + } + } else { + pixels = null; } Module.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); }, @@ -107,6 +312,23 @@ var LibraryGL = { Module.ctx.bindTexture(target, GL.hashtable("texture").get(texture)); }, + glGetTexParameterfv: function(target, pname, params) { + {{{ makeSetValue('params', '0', 'Module.getTexParameter(target, pname)', 'float') }}}; + }, + + glGetTexParameteriv: function(target, pname, params) { + {{{ makeSetValue('params', '0', 'Module.getTexParameter(target, pname)', 'i32') }}}; + }, + + glIsTexture_deps: ['$GL'], + glIsTexture: function(texture) { + var fb = GL.hashtable("texture").get(texture); + if (typeof(fb) == 'undefined') { + return false; + } + return Module.ctx.isTexture(fb); + }, + glGenBuffers__deps: ['$GL'], glGenBuffers: function(n, buffers) { for (var i = 0; i < n; i++) { @@ -128,6 +350,53 @@ var LibraryGL = { Module.ctx.bufferData(target, floatArray, usage); }, + glBufferSubData: function(target, offset, size, data) { + var floatArray = new Float32Array(TypedArray_copy(data, size, offset)); + Module.ctx.bufferSubData(target, offset, floatArray); + }, + + glIsBuffer_deps: ['$GL'], + glIsBuffer: function(buffer) { + var fb = GL.hashtable("buffer").get(buffer); + if (typeof(fb) == 'undefined') { + return false; + } + return Module.ctx.isBuffer(fb); + }, + + glGenRenderbuffers__deps: ['$GL'], + glGenRenderbuffers: function(n, renderbuffers) { + for (var i = 0; i < n; i++) { + var id = GL.hashtable("renderbuffer").add(Module.ctx.createRenderbuffer()); + {{{ makeSetValue('renderbuffers', 'i', 'id', 'i32') }}}; + } + }, + + glDeleteRenderbuffers: function(n, renderbuffers) { + for (var i = 0; i < n; i++) { + var id = {{{ makeGetValue('renderbuffers', 'i', 'i32') }}}; + Module.ctx.deleteRenderbuffer(GL.hashtable("renderbuffer").get(id)); + GL.hashtable("renderbuffer").remove(id); + } + }, + + glBindRenderbuffer: function(target, renderbuffer) { + Module.ctx.bindRenderbuffer(target, GL.hashtable("renderbuffer").get(renderbuffer)); + }, + + glGetRenderbufferParameteriv: function(target, pname, params) { + {{{ makeSetValue('params', '0', 'Module.ctx.getRenderbufferParameter(target, pname)', 'i32') }}}; + }, + + glIsRenderbuffer_deps: ['$GL'], + glIsRenderbuffer: function(renderbuffer) { + var fb = GL.hashtable("renderbuffer").get(renderbuffer); + if (typeof(fb) == 'undefined') { + return false; + } + return Module.ctx.isRenderbuffer(fb); + }, + glGetUniformLocation_deps: ['$GL'], glGetUniformLocation: function(program, name) { name = Pointer_stringify(name); @@ -288,7 +557,24 @@ var LibraryGL = { glDeleteShader_deps: ['$GL'], glDeleteShader: function(shader) { - return GL.hashtable("shader").remove(shader); + Module.ctx.deleteShader(GL.hashtable("shader").get(shader)); + }, + + glDetachShader: function(program, shader) { + Module.ctx.detachShader(GL.hashtable("program").get(program), + GL.hashtable("shader").get(shader)); + }, + + glGetAttachedShaders: function(program, maxCount, count, shaders) { + var result = Module.ctx.getAttachedShaders(GL.hashtable("program").get(program)); + var len = result.length; + if (len > maxCount) { + len = maxCount; + } + {{{ makeSetValue('count', '0', 'len', 'i32') }}}; + for (var i = 0; i < len; ++i) { + {{{ makeSetValue('shaders', 'i', 'GL.hashtable("shader").get(result[i])', 'i32') }}}; + } }, glShaderSource_deps: ['$GL'], @@ -311,6 +597,15 @@ var LibraryGL = { Module.ctx.shaderSource(GL.hashtable("shader").get(shader), source); }, + glGetShaderSource: function(shader, bufsize, length, source) { + var result = Module.ctx.getShaderSource(GL.hashtable("shader").get(shader)); + result.slice(0, bufsize - 1); + writeStringToMemory(result, source); + if (length) { + {{{ makeSetValue('length', '0', 'result.length', 'i32') }}}; + } + }, + glCompileShader_deps: ['$GL'], glCompileShader: function(shader) { Module.ctx.compileShader(GL.hashtable("shader").get(shader)); @@ -322,18 +617,27 @@ var LibraryGL = { log.slice(0, maxLength - 1); writeStringToMemory(log, infoLog); if (length) { - {{{ makeSetValue('length', 'i', 'log.length', 'i32') }}} + {{{ makeSetValue('length', '0', 'log.length', 'i32') }}} } }, - + glGetShaderiv_deps: ['$GL'], - glGetShaderiv : function(shader, pname, p) { - {{{ makeSetValue('p', '0', 'Module.ctx.getShaderParameter(GL.hashtable("shader").get(shader),pname)', 'i32') }}}; + glGetShaderiv : function(shader, pname, p) { + {{{ makeSetValue('p', '0', 'Module.ctx.getShaderParameter(GL.hashtable("shader").get(shader), pname)', 'i32') }}}; }, glGetProgramiv_deps: ['$GL'], - glGetProgramiv : function(program, pname, p) { - {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.hashtable("program").get(program),pname)', 'i32') }}}; + glGetProgramiv : function(program, pname, p) { + {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.hashtable("program").get(program), pname)', 'i32') }}}; + }, + + glIsShader_deps: ['$GL'], + glIsShader: function(shader) { + var fb = GL.hashtable("shader").get(shader); + if (typeof(fb) == 'undefined') { + return false; + } + return Module.ctx.isShader(fb); }, glCreateProgram_deps: ['$GL'], @@ -343,7 +647,7 @@ var LibraryGL = { glDeleteProgram_deps: ['$GL'], glDeleteProgram: function(program) { - return GL.hashtable("program").remove(program); + Module.ctx.deleteProgram(GL.hashtable("program").get(program)); }, glAttachShader_deps: ['$GL'], @@ -352,6 +656,13 @@ var LibraryGL = { GL.hashtable("shader").get(shader)); }, + glGetShaderPrecisionFormat: function(shaderType, precisionType, range, precision) { + var result = Module.ctx.getShaderPrecisionFormat(shaderType, precisionType); + {{{ makeSetValue('range', '0', 'result.rangeMin', 'i32') }}}; + {{{ makeSetValue('range', '1', 'result.rangeMax', 'i32') }}}; + {{{ makeSetValue('precision', '0', 'result.precision', 'i32') }}}; + }, + glLinkProgram_deps: ['$GL'], glLinkProgram: function(program) { Module.ctx.linkProgram(GL.hashtable("program").get(program)); @@ -367,7 +678,7 @@ var LibraryGL = { log = log.substr(0, maxLength - 1); writeStringToMemory(log, infoLog); if (length) { - {{{ makeSetValue('length', 'i', 'log.length', 'i32') }}} + {{{ makeSetValue('length', '0', 'log.length', 'i32') }}} } }, @@ -376,6 +687,20 @@ var LibraryGL = { Module.ctx.useProgram(GL.hashtable("program").get(program)); }, + glValidateProgram_deps: ['$Gl'], + glValidateProgram: function(program) { + Module.ctx.validateProgram(GL.hashtable("program").get(program)); + }, + + glIsProgram_deps: ['$GL'], + glIsProgram: function(program) { + var fb = GL.hashtable("program").get(program); + if (typeof(fb) == 'undefined') { + return false; + } + return Module.ctx.isProgram(fb); + }, + glBindAttribLocation_deps: ['$GL'], glBindAttribLocation: function(program, index, name) { name = Pointer_stringify(name); @@ -435,12 +760,12 @@ var LibraryGL = { // Simple pass-through functions [[0, 'shadeModel fogi fogfv getError finish flush'], - [1, 'clearDepth depthFunc enable disable frontFace cullFace clear enableVertexAttribArray disableVertexAttribArray lineWidth clearStencil depthMask stencilMask stencilMaskSeparate checkFramebufferStatus activeTexture'], - [2, 'pixelStorei vertexAttrib1f depthRange polygonOffset blendFunc'], + [1, 'clearDepth depthFunc enable disable frontFace cullFace clear enableVertexAttribArray disableVertexAttribArray lineWidth clearStencil depthMask stencilMask stencilMaskSeparate checkFramebufferStatus generateMipmap activeTexture'], [3, 'texParameteri texParameterf drawArrays vertexAttrib2f'], - [4, 'viewport clearColor scissor vertexAttrib3f colorMask drawElements'], + [4, 'viewport clearColor scissor vertexAttrib3f colorMask drawElements renderbufferStorage'], [5, 'vertexAttrib4f'], - [6, 'vertexAttribPointer']].forEach(function(data) { + [6, 'vertexAttribPointer'], + [8, 'copyTexImage2D copyTexSubImage2D']].forEach(function(data) { var num = data[0]; var names = data[1]; var args = range(num).map(function(i) { return 'x' + i }).join(', '); @@ -718,6 +1043,46 @@ var LibraryGLUT = { }; +var LibraryXlib = { + XOpenDisplay: function() { + return 1; // We support 1 display, the canvas + }, + + XCreateWindow: function(display, parent, x, y, width, height, border_width, depth, class_, visual, valuemask, attributes) { + // All we can do is set the width and height + Module['canvas'].width = width; + Module['canvas'].height = height; + return 2; + }, + + XChangeWindowAttributes: function(){}, + XSetWMHints: function(){}, + XMapWindow: function(){}, + XStoreName: function(){}, + XInternAtom: function(display, name_, hmm) { return 0 }, + XSendEvent: function(){}, + XPending: function(display) { return 0 }, +}; + +var LibraryEGL = { + eglGetDisplay: function(x_display) { return 3 }, + eglInitialize: function(display, majorVersion, minorVersion) { return 1 }, + eglGetConfigs: function(display, hmm1, hmm2, numConfigs) { return 1 }, + eglChooseConfig: function(display, attribList, config, hmm, numConfigs) { return 1 }, + eglCreateWindowSurface: function(display, config, hWnd, hmm) { return 4 }, + + eglCreateContext__deps: ['glutCreateWindow', '$GL'], + eglCreateContext: function(display, config, hmm, contextAttribs) { + _glutCreateWindow(); + return 1; + }, + + eglMakeCurrent: function(display, surface, surface, context) { return 1 }, + eglSwapBuffers: function() {}, +}; + mergeInto(LibraryManager.library, LibraryGL); mergeInto(LibraryManager.library, LibraryGLUT); +mergeInto(LibraryManager.library, LibraryXlib); +mergeInto(LibraryManager.library, LibraryEGL); diff --git a/src/library_sdl.js b/src/library_sdl.js index 9d947cd4..631de481 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -90,6 +90,7 @@ mergeInto(LibraryManager.library, { fonts: [null], keyboardState: null, + startTime: null, mouseX: 0, mouseY: 0, @@ -98,6 +99,7 @@ mergeInto(LibraryManager.library, { 40: 1105, // down arrow 37: 1104, // left arrow 39: 1103, // right arrow + 17: 305, // control (right, or left) 18: 308, // alt 109: 45, // minus @@ -378,7 +380,13 @@ mergeInto(LibraryManager.library, { return 0; // success }, - SDL_WasInit: function() { return 0 }, // TODO + SDL_WasInit__deps: ['SDL_Init'], + SDL_WasInit: function() { + if (SDL.startTime === null) { + _SDL_Init(); + } + return 1; + }, SDL_GetVideoInfo: function() { // %struct.SDL_VideoInfo = type { i32, i32, %struct.SDL_PixelFormat*, i32, i32 } - 5 fields of quantum size @@ -409,6 +417,9 @@ mergeInto(LibraryManager.library, { }, SDL_Quit: function() { + for (var i = 0; i < SDL.audios; i++) { + SDL.audios[i].pause(); + } Module.print('SDL_Quit called (and ignored)'); }, @@ -460,13 +471,14 @@ mergeInto(LibraryManager.library, { assert(buffer % 4 == 0, 'Invalid buffer offset: ' + buffer); var src = buffer >> 2; var dst = 0; + var isScreen = surf == SDL.screen; while (dst < num) { // TODO: access underlying data buffer and write in 32-bit chunks or more var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}}; - data[dst] = val & 0xff; + data[dst ] = val & 0xff; data[dst+1] = (val >> 8) & 0xff; data[dst+2] = (val >> 16) & 0xff; - data[dst+3] = (val >> 24) & 0xff; + data[dst+3] = isScreen ? 0xff : ((val >> 24) & 0xff); src++; dst += 4; } @@ -717,15 +729,14 @@ mergeInto(LibraryManager.library, { SDL_CondWait: function() {}, SDL_DestroyCond: function() {}, -//SDL_CreateYUVOverlay -//SDL_CreateThread, SDL_WaitThread etc - // SDL Mixer - Mix_OpenAudio: function() { return 0 }, + Mix_OpenAudio: function(frequency, format, channels, chunksize) { + return 0; + }, Mix_HookMusicFinished: function(func) { - SDL.hookMusicFinished = func; // TODO: use this + SDL.hookMusicFinished = func; }, Mix_VolumeMusic: function(func) { @@ -734,46 +745,39 @@ mergeInto(LibraryManager.library, { Mix_LoadWAV_RW: function(filename, freesrc) { filename = FS.standardizePath(Pointer_stringify(filename)); + var raw = preloadedAudios[filename]; + assert(raw, 'Cannot find preloaded audio ' + filename); var id = SDL.audios.length; SDL.audios.push({ - audio: new Audio(filename) + source: filename, + audio: raw }); return id; }, Mix_FreeChunk: function(id) { - //SDL.audios[id].audio.pause(); - //SDL.audios[id] = null; - return 0; + SDL.audios[id].audio.pause(); + SDL.audios[id] = null; }, Mix_PlayChannel: function(channel, id, loops) { - //var audio = SDL.audios[id].audio; - //audio.play(); - return 0; // XXX should return channel + // TODO: handle loops + var audio = SDL.audios[id].audio; + if (audio.currentTime) audio.src = audio.src; // This hack prevents lags on replaying // TODO: parallel sounds through //cloneNode(true).play() + audio.play(); + return 1; // XXX should return channel }, Mix_PlayChannelTimed: 'Mix_PlayChannel', // XXX ignore Timing - Mix_LoadMUS: function(filename) { - filename = FS.standardizePath(Pointer_stringify(filename)); - var id = SDL.audios.length; - SDL.audios.push({ - audio: new Audio(filename) - }); - return id; - }, - - Mix_FreeMusic: function(id) { - SDL.audios[id].audio.pause(); - SDL.audios[id] = null; - return 0; - }, + Mix_LoadMUS: 'Mix_LoadWAV_RW', + Mix_FreeMusic: 'Mix_FreeChunk', Mix_PlayMusic: function(id, loops) { - if (loops == 0) return; + loops = Math.max(loops, 1); var audio = SDL.audios[id].audio; - audio.loop = loop != 1; // TODO: handle N loops for finite N + audio.loop = loops != 1; // TODO: handle N loops for finite N audio.play(); + SDL.music = audio; return 0; }, @@ -789,15 +793,21 @@ mergeInto(LibraryManager.library, { return 0; }, - Mix_HaltMusic: function(id) { - var audio = SDL.audios[id].audio; - audio.pause(); // TODO: actually rewind to the beginning + Mix_HaltMusic: function() { + var audio = SDL.music; + if (!audio) return 0; + audio.src = audio.src; // rewind + audio.pause(); + SDL.music = null; + if (SDL.hookMusicFinished) { + FUNCTION_TABLE[SDL.hookMusicFinished](); + } return 0; }, Mix_FadeInMusicPos: 'Mix_PlayMusic', // XXX ignore fading in effect - Mix_FadeOutMusic: function(id) {}, // TODO + Mix_FadeOutMusic: 'Mix_HaltMusic', // XXX ignore fading out effect // SDL TTF diff --git a/src/long.js b/src/long.js new file mode 100644 index 00000000..71cffa79 --- /dev/null +++ b/src/long.js @@ -0,0 +1,1633 @@ +// TODO: strip out parts of this we do not need + +//======= begin closure i64 code ======= + +// Copyright 2009 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// |