aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-01-28 21:29:02 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-01-28 21:29:02 -0800
commit687b8cfa3d105a634b3c9cfbc5fc287f1517fae3 (patch)
treeeea2952d7673296ba6a8cd2384061fc3ad270473
parentc516fa7758636e15a7077c658db3c74533c7ee38 (diff)
parentb6ebeed2cfcebb220f2ce700c7cbe484e62cd2e2 (diff)
Merge branch 'master' into llvmopts
-rwxr-xr-xemcc15
-rw-r--r--src/library.js42
-rw-r--r--src/library_gl.js481
-rw-r--r--src/library_sdl.js15
-rw-r--r--src/preamble.js39
-rw-r--r--src/shell.html5
-rw-r--r--system/include/GL/freeglut_std.h628
-rw-r--r--system/include/GL/glut.h21
-rw-r--r--system/include/GLES2/gl2.h621
-rw-r--r--system/include/GLES2/gl2platform.h30
-rw-r--r--system/include/KHR/khrplatform.h277
-rw-r--r--tests/hello_world_gles.c729
-rw-r--r--tests/hello_world_gles_shell.html55
-rwxr-xr-xtests/runner.py140
14 files changed, 3028 insertions, 70 deletions
diff --git a/emcc b/emcc
index 42200428..8d4a3205 100755
--- a/emcc
+++ b/emcc
@@ -169,6 +169,13 @@ Options that are modified or new in %s include:
will be run). Note that this by itself
will not minify the code (closure does
that)
+ --shell-path <path> The path name to a skeleton HTML file used
+ when generating HTML output. The shell file
+ used needs to have this token inside it:
+ {{{ SCRIPT_CODE }}}
+ Note that this argument is ignored if a
+ target other than HTML is specified using
+ the -o option.
The target file, if specified (-o <target>), defines what will
be generated:
@@ -285,6 +292,7 @@ try:
closure = None
js_transform = None
compress_whitespace = None
+ shell_path = shared.path_from_root('src', 'shell.html')
def check_bad_eq(arg):
assert '=' not in arg, 'Invalid parameter (do not use "=" with "--" options)'
@@ -323,6 +331,11 @@ try:
f.close()
newargs[i] = ''
newargs[i+1] = ''
+ elif newargs[i].startswith('--shell-file'):
+ check_bad_eq(newargs[i])
+ shell_path = newargs[i+1]
+ newargs[i] = ''
+ newargs[i+1] = ''
newargs = [ arg for arg in newargs if arg is not '' ]
if llvm_opts is None: llvm_opts = 1 if opt_level >= 1 else 0
@@ -634,7 +647,7 @@ try:
# If we were asked to also generate HTML, do that
if final_suffix == 'html':
if DEBUG: print >> sys.stderr, 'emcc: generating HTML'
- shell = open(shared.path_from_root('src', 'shell.html')).read()
+ shell = open(shell_path).read()
html = open(target, 'w')
html.write(shell.replace('{{{ SCRIPT_CODE }}}', open(final).read()))
html.close()
diff --git a/src/library.js b/src/library.js
index ad1ff696..47e15aae 100644
--- a/src/library.js
+++ b/src/library.js
@@ -4687,6 +4687,34 @@ LibraryManager.library = {
},
nanf: 'nan',
+ sincos: function(x, sine, cosine) {
+ var sineVal = Math.sin(x),
+ cosineVal = Math.cos(x);
+ {{{ makeSetValue('sine', '0', 'sineVal', 'double') }}};
+ {{{ makeSetValue('cosine', '0', 'cosineVal', 'double') }}};
+ },
+
+ sincosf: function(x, sine, cosine) {
+ var sineVal = Math.sin(x),
+ cosineVal = Math.cos(x);
+ {{{ makeSetValue('sine', '0', 'sineVal', 'float') }}};
+ {{{ makeSetValue('cosine', '0', 'cosineVal', 'float') }}};
+ },
+
+ __div_t_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'quot'],
+ ['i32', 'rem'],
+ ]),
+ div__deps: ['__div_t_struct_layout'],
+ div: function(divt, numer, denom) {
+ var quot = Math.floor(numer / denom);
+ var rem = numer - quot * denom;
+ var offset = ___div_t_struct_layout.rem;
+ {{{ makeSetValue('divt', '0', 'quot', 'i32') }}};
+ {{{ makeSetValue('divt', 'offset', 'rem', 'i32') }}};
+ return divt;
+ },
+
__fpclassifyf: function(x) {
if (isNaN(x)) return {{{ cDefine('FP_NAN') }}};
if (!isFinite(x)) return {{{ cDefine('FP_INFINITE') }}};
@@ -5720,6 +5748,20 @@ LibraryManager.library = {
},
// ==========================================================================
+ // arpa/inet.h
+ // ==========================================================================
+
+ htonl: function(value) {
+ return ((value & 0xff) << 24) + ((value & 0xff00) << 8) +
+ ((value & 0xff0000) >> 8) + ((value & 0xff000000) >> 24);
+ },
+ htons: function(value) {
+ return ((value & 0xff) << 8) + ((value & 0xff00) >> 8);
+ },
+ ntohl: 'htonl',
+ ntohs: 'htons',
+
+ // ==========================================================================
// emscripten.h
// ==========================================================================
diff --git a/src/library_gl.js b/src/library_gl.js
index 2be881df..e1a7c73b 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -4,8 +4,35 @@
var LibraryGL = {
$GL: {
- textures: {},
- textureCounter: 0,
+ hashtable: function(name) {
+ if (!this._hashtables) {
+ this._hashtables = {};
+ }
+ if (!(name in this._hashtables)) {
+ this._hashtables[name] = {
+ table: {},
+ counter: 0,
+ add: function(obj) {
+ var id = this.counter++;
+ this.table[id] = obj;
+ return id;
+ },
+ get: function(id) {
+#if ASSERTIONS
+ assert(id < this.counter, "Invalid id " + id + " for the hashtable " + name);
+#endif
+ return this.table[id];
+ },
+ remove: function(id) {
+#if ASSERTIONS
+ assert(id < this.counter, "Invalid id " + id + " for the hashtable " + name);
+#endif
+ delete this.table[id];
+ }
+ };
+ }
+ return this._hashtables[name];
+ },
},
glGetString: function(name_) {
@@ -24,7 +51,7 @@ var LibraryGL = {
glGetIntegerv: function(name_, p) {
switch(name_) {
case Module.ctx.MAX_TEXTURE_SIZE:
- IHEAP[p] = Module.ctx.getParameter(name_);
+ {{{ makeSetValue('p', '0', 'Module.ctx.getParameter(name_)', 'i32') }}};
break;
default:
throw 'Failure: Invalid glGetIntegerv value: ' + name_;
@@ -34,78 +61,476 @@ var LibraryGL = {
glGenTextures__deps: ['$GL'],
glGenTextures: function(n, textures) {
for (var i = 0; i < n; i++) {
- var id = GL.textureCounter++;
- GL.textures[id] = Module.ctx.createTexture();
- IHEAP[textures+QUANTUM_SIZE*i] = id;
+ var id = GL.hashtable("texture").add(Module.ctx.createTexture());
+ {{{ makeSetValue('textures', 'i', 'id', 'i32') }}};
}
},
glDeleteTextures: function(n, textures) {
for (var i = 0; i < n; i++) {
- var id = IHEAP[textures+QUANTUM_SIZE*i];
- Module.ctx.deleteTexture(GL.textures[id]);
- delete GL.textures[id];
+ var id = {{{ makeGetValue('textures', 'i', 'i32') }}};
+ Module.ctx.deleteTexture(GL.hashtable("texture").get(id));
+ GL.hashtable("texture").remove(id);
}
},
glTexImage2D: function(target, level, internalformat, width, height, border, format, type, pixels) {
if (pixels) {
- pixels = new Uint8Array(IHEAP.slice(pixels, pixels + width*height*4)); // TODO: optimize
+ pixels = new Uint8Array(Array_copy(pixels, pixels + width*height*4)); // TODO: optimize
}
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(IHEAP.slice(pixels, pixels + width*height*4)); // TODO: optimize
+ pixels = new Uint8Array(Array_copy(pixels, pixels + width*height*4)); // TODO: optimize
}
Module.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
},
glBindTexture: function(target, texture) {
- Module.ctx.bindTexture(target, GL.textures[texture]);
+ Module.ctx.bindTexture(target, GL.hashtable("texture").get(texture));
},
- glClearColor: function(red, green, blue, alpha) {
- Module.ctx.clearColor(red, green, blue, alpha);
+ glGenBuffers__deps: ['$GL'],
+ glGenBuffers: function(n, buffers) {
+ for (var i = 0; i < n; i++) {
+ var id = GL.hashtable("buffer").add(Module.ctx.createBuffer());
+ {{{ makeSetValue('buffers', 'i', 'id', 'i32') }}};
+ }
+ },
+
+ glDeleteBuffers: function(n, buffers) {
+ for (var i = 0; i < n; i++) {
+ var id = {{{ makeGetValue('buffers', 'i', 'i32') }}};
+ Module.ctx.deleteBuffer(GL.hashtable("buffer").get(id));
+ GL.hashtable("buffer").remove(id);
+ }
+ },
+
+ glBufferData: function(target, size, data, usage) {
+ var floatArray = new Float32Array(TypedArray_copy(data, size));
+ Module.ctx.bufferData(target, floatArray, usage);
+ },
+
+ glBindAttribLocation_deps: ['$GL'],
+ glGetUniformLocation: function(program, name) {
+ name = Pointer_stringify(name);
+ return GL.hashtable("uniform").add(
+ Module.ctx.getUniformLocation(GL.hashtable("program").get(program), name));
+ },
+
+ glUniform1f: function(Location, v0) {
+ Location = GL.hashtable("uniform").get(Location);
+ Module.ctx.uniform1f(Location, v0);
+ },
+
+ glUniform2f: function(Location, v0, v1) {
+ Location = GL.hashtable("uniform").get(Location);
+ Module.ctx.uniform2f(Location, v0, v1);
+ },
+
+ glUniform3f: function(Location, v0, v1, v2) {
+ Location = GL.hashtable("uniform").get(Location);
+ Module.ctx.uniform3f(Location, v0, v1, v2);
},
- glClear: function(mask) {
- Module.ctx.clear(mask);
+ glUniform4f: function(Location, v0, v1, v2, v3) {
+ Location = GL.hashtable("uniform").get(Location);
+ Module.ctx.uniform4f(Location, v0, v1, v2, v3);
},
- glEnable: function(cap) {
- Module.ctx.enable(cap);
+ glUniform1i: function(Location, v0) {
+ Location = GL.hashtable("uniform").get(Location);
+ Module.ctx.uniform1i(Location, v0);
},
- glScissor: function(x, y, width, height) {
- Module.ctx.scissor(x, y, width, height);
+ glUniform2i: function(Location, v0, v1) {
+ Location = GL.hashtable("uniform").get(Location);
+ Module.ctx.uniform2i(Location, v0, v1);
+ },
+
+ glUniform3i: function(Location, v0, v1, v2) {
+ Location = GL.hashtable("uniform").get(Location);
+ Module.ctx.uniform3i(Location, v0, v1, v2);
+ },
+
+ glUniform4i: function(Location, v0, v1, v2, v3) {
+ Location = GL.hashtable("uniform").get(Location);
+ Module.ctx.uniform4i(Location, v0, v1, v2, v3);
+ },
+
+ glUniform1fv: function(Location, count, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniform1fv(Location, value);
+ },
+
+ glUniform2fv: function(Location, count, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 2;
+ value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniform2fv(Location, value);
+ },
+
+ glUniform3fv: function(Location, count, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 3;
+ value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniform3fv(Location, value);
+ },
+
+ glUniform4fv: function(Location, count, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 4;
+ value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniform4fv(Location, value);
+ },
+
+ glUniform1fi: function(Location, count, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ value = new Uint32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniform1fi(Location, value);
+ },
+
+ glUniform2fi: function(Location, count, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 2;
+ value = new Uint32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniform2fi(Location, value);
+ },
+
+ glUniform3fi: function(Location, count, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 3;
+ value = new Uint32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniform3fi(Location, value);
+ },
+
+ glUniform4fi: function(Location, count, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 4;
+ value = new Uint32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniform4fi(Location, value);
+ },
+
+ glUniformMatrix2fv: function(Location, count, transpose, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 4;
+ value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniformMatrix2fv(Location, transpose, value);
+ },
+
+ glUniformMatrix3fv: function(Location, count, transpose, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 9;
+ value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniformMatrix3fv(Location, transpose, value);
+ },
+
+ glUniformMatrix4fv: function(Location, count, transpose, value) {
+ Location = GL.hashtable("uniform").get(Location);
+ count *= 16;
+ value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
+ Module.ctx.uniformMatrix4fv(Location, transpose, value);
+ },
+
+ glBindBuffer: function(target, buffer) {
+ Module.ctx.bindBuffer(target, GL.hashtable("buffer").get(buffer));
+ },
+
+ glVertexAttrib1f: function(index, v0) {
+ Module.ctx.vertexAttrib1f(index, v0);
+ },
+
+ glVertexAttrib2f: function(index, v0, v1) {
+ Module.ctx.vertexAttrib2f(index, v0, v1);
+ },
+
+ glVertexAttrib3f: function(index, v0, v1, v2) {
+ Module.ctx.vertexAttrib3f(index, v0, v1, v2);
+ },
+
+ glVertexAttrib4f: function(index, v0, v1, v2, v3) {
+ Module.ctx.vertexAttrib4f(index, v0, v1, v2, v3);
+ },
+
+ glVertexAttrib1fv: function(index, v) {
+ v = new Float32Array(TypedArray_copy(v, 1*4)); // TODO: optimize
+ Module.ctx.vertexAttrib1fv(index, v);
+ },
+
+ glVertexAttrib2fv: function(index, v) {
+ v = new Float32Array(TypedArray_copy(v, 2*4)); // TODO: optimize
+ Module.ctx.vertexAttrib2fv(index, v);
+ },
+
+ glVertexAttrib3fv: function(index, v) {
+ v = new Float32Array(TypedArray_copy(v, 3*4)); // TODO: optimize
+ Module.ctx.vertexAttrib3fv(index, v);
+ },
+
+ glVertexAttrib4fv: function(index, v) {
+ v = new Float32Array(TypedArray_copy(v, 4*4)); // TODO: optimize
+ Module.ctx.vertexAttrib4fv(index, v);
+ },
+
+ glVertexAttribPointer: function(index, size, type, normalized, stride, pointer) {
+ Module.ctx.vertexAttribPointer(index, size, type, normalized, stride, pointer);
+ },
+
+ glEnableVertexAttribArray: function(index) {
+ Module.ctx.enableVertexAttribArray(index);
+ },
+
+ glDisableVertexAttribArray: function(index) {
+ Module.ctx.disableVertexAttribArray(index);
+ },
+
+ glDrawArrays: function(mode, first, count) {
+ Module.ctx.drawArrays(mode, first, count);
+ },
+
+ glGetAttribLocation: function(program, name) {
+ program = GL.hashtable("program").get(program);
+ name = Pointer_stringify(name);
+ Module.ctx.getAttribLocation(program, name);
+ },
+
+ glCreateShader_deps: ['$GL'],
+ glCreateShader: function(shaderType) {
+ var shader = Module.ctx.createShader(shaderType);
+ return GL.hashtable("shader").add(shader);
+ },
+
+ glShaderSource_deps: ['$GL'],
+ glShaderSource: function(shader, count, string, length) {
+ var source = "";
+ for (var i = 0; i < count; ++i) {
+ var frag = string[i];
+ if (length) {
+ var len = {{{ makeGetValue('length', 'i', 'i32') }}};
+ if (len < 0) {
+ frag = Pointer_stringify({{{ makeGetValue('string', 'i', 'i32') }}});
+ } else {
+ frag = Pointer_stringify({{{ makeGetValue('string', 'i', 'i32') }}}, len);
+ }
+ } else {
+ frag = Pointer_stringify({{{ makeGetValue('string', 'i', 'i32') }}});
+ }
+ if (source.length) {
+ source += "\n";
+ }
+ source += frag;
+ }
+ Module.ctx.shaderSource(GL.hashtable("shader").get(shader), source);
+ },
+
+ glCompileShader_deps: ['$GL'],
+ glCompileShader: function(shader) {
+ Module.ctx.compileShader(GL.hashtable("shader").get(shader));
+ },
+
+ glGetShaderInfoLog_deps: ['$GL'],
+ glGetShaderInfoLog: function(shader, maxLength, length, infoLog) {
+ var log = Module.ctx.getShaderInfoLog(GL.hashtable("shader").get(shader));
+ log.slice(0, maxLength - 1);
+ writeStringToMemory(log, infoLog);
+ if (length) {
+ {{{ makeSetValue('length', 'i', 'log.length', 'i32') }}}
+ }
+ },
+
+ glCreateProgram_deps: ['$GL'],
+ glCreateProgram: function() {
+ return GL.hashtable("program").add(Module.ctx.createProgram());
+ },
+
+ glAttachShader_deps: ['$GL'],
+ glAttachShader: function(program, shader) {
+ Module.ctx.attachShader(GL.hashtable("program").get(program),
+ GL.hashtable("shader").get(shader));
+ },
+
+ glLinkProgram_deps: ['$GL'],
+ glLinkProgram: function(program) {
+ Module.ctx.linkProgram(GL.hashtable("program").get(program));
+ },
+
+ glGetProgramInfoLog_deps: ['$GL'],
+ glGetProgramInfoLog: function(program, maxLength, length, infoLog) {
+ var log = Module.ctx.getProgramInfoLog(GL.hashtable("program").get(program));
+ // Work around a bug in Chromium which causes getProgramInfoLog to return null
+ if (!log) {
+ log = "";
+ }
+ log = log.substr(0, maxLength - 1);
+ writeStringToMemory(log, infoLog);
+ if (length) {
+ {{{ makeSetValue('length', 'i', 'log.length', 'i32') }}}
+ }
+ },
+
+ glUseProgram_deps: ['$Gl'],
+ glUseProgram: function(program) {
+ Module.ctx.useProgram(GL.hashtable("program").get(program));
+ },
+
+ glBindAttribLocation_deps: ['$GL'],
+ glBindAttribLocation: function(program, index, name) {
+ name = Pointer_stringify(name);
+ Module.ctx.bindAttribLocation(GL.hashtable("program").get(program), index, name);
},
};
-// Ignored stubs for fixed-function pipeline. We will need to emulate this
-'begin end matrixMode loadIdentity ortho color3f texCoord2f vertex2f blendFunc pushMatrix popMatrix translatef scalef color4ub enableClientState disableClientState vertexPointer colorPointer normalPointer texCoordPointer drawArrays clientActiveTexture_'.split(' ').forEach(function(name_) {
- var cName = 'gl' + name_[0].toUpperCase() + name_.substr(1);
- LibraryGL[cName] = function(){};
-});
// Simple pass-through functions
-[[0, 'shadeModel fogi fogfv'],
- [1, 'clearDepth depthFunc enable disable frontFace cullFace'],
+[[0, 'shadeModel fogi fogfv getError'],
+ [1, 'clearDepth depthFunc enable disable frontFace cullFace clear'],
[2, 'pixelStorei'],
[3, 'texParameteri texParameterf'],
- [4, 'viewport clearColor']].forEach(function(data) {
+ [4, 'viewport clearColor scissor']].forEach(function(data) {
var num = data[0];
var names = data[1];
var args = range(num).map(function(i) { return 'x' + i }).join(', ');
var stub = '(function(' + args + ') { ' + (num > 0 ? 'Module.ctx.NAME(' + args + ')' : '') + ' })';
names.split(' ').forEach(function(name_) {
var cName = 'gl' + name_[0].toUpperCase() + name_.substr(1);
+#if ASSERTIONS
+ assert(!(cName in LibraryGL), "Cannot reimplement the existing function " + cName);
+#endif
LibraryGL[cName] = eval(stub.replace('NAME', name_));
//print(cName + ': ' + LibraryGL[cName]);
});
});
+var LibraryGLUT = {
+ $GLUT: {
+ initTime: null,
+ idleFunc: null,
+ keyboardFunc: null,
+ reshapeFunc: null,
+ lastX: 0,
+ lastY: 0,
+
+ onMousemove: function(event) {
+ GLUT.lastX = event['clientX'];
+ GLUT.lastY = event['clientY'];
+ },
+
+ onKeydown: function(event) {
+ if (GLUT.keyboardFunc) {
+ var key = null;
+ switch (event['keyCode']) {
+ case 0x70 /*DOM_VK_F1*/: key = 1 /* GLUT_KEY_F1 */; break;
+ case 0x71 /*DOM_VK_F2*/: key = 2 /* GLUT_KEY_F2 */; break;
+ case 0x72 /*DOM_VK_F3*/: key = 3 /* GLUT_KEY_F3 */; break;
+ case 0x73 /*DOM_VK_F4*/: key = 4 /* GLUT_KEY_F4 */; break;
+ case 0x74 /*DOM_VK_F5*/: key = 5 /* GLUT_KEY_F5 */; break;
+ case 0x75 /*DOM_VK_F6*/: key = 6 /* GLUT_KEY_F6 */; break;
+ case 0x76 /*DOM_VK_F7*/: key = 7 /* GLUT_KEY_F7 */; break;
+ case 0x77 /*DOM_VK_F8*/: key = 8 /* GLUT_KEY_F8 */; break;
+ case 0x78 /*DOM_VK_F9*/: key = 9 /* GLUT_KEY_F9 */; break;
+ case 0x79 /*DOM_VK_F10*/: key = 10 /* GLUT_KEY_F10 */; break;
+ case 0x7a /*DOM_VK_F11*/: key = 11 /* GLUT_KEY_F11 */; break;
+ case 0x7b /*DOM_VK_F12*/: key = 12 /* GLUT_KEY_F12 */; break;
+ case 0x25 /*DOM_VK_LEFT*/: key = 100 /* GLUT_KEY_LEFT */; break;
+ case 0x26 /*DOM_VK_UP*/: key = 101 /* GLUT_KEY_UP */; break;
+ case 0x27 /*DOM_VK_RIGHT*/: key = 102 /* GLUT_KEY_RIGHT */; break;
+ case 0x28 /*DOM_VK_DOWN*/: key = 103 /* GLUT_KEY_DOWN */; break;
+ case 0x21 /*DOM_VK_PAGE_UP*/: key = 104 /* GLUT_KEY_PAGE_UP */; break;
+ case 0x22 /*DOM_VK_PAGE_DOWN*/: key = 105 /* GLUT_KEY_PAGE_DOWN */; break;
+ case 0x24 /*DOM_VK_HOME*/: key = 106 /* GLUT_KEY_HOME */; break;
+ case 0x23 /*DOM_VK_END*/: key = 107 /* GLUT_KEY_END */; break;
+ case 0x2d /*DOM_VK_INSERT*/: key = 108 /* GLUT_KEY_INSERT */; break;
+ default: return;
+ };
+ if (key !== null) {
+ FUNCTION_TABLE[GLUT.keyboardFunc](key, GLUT.lastX, GLUT.lastY);
+ }
+ }
+ },
+ },
+
+ glutInit__deps: ['$GLUT'],
+ glutInit: function(argcp, argv) {
+ // Ignore arguments
+ GLUT.initTime = Date.now();
+ window.addEventListener("keydown", GLUT.onKeydown, true);
+ window.addEventListener("mousemove", GLUT.onMousemove, true);
+ },
+
+ glutInitWindowSize: function(width, height) {
+ Module['canvas'].width = width;
+ Module['canvas'].height = height;
+ },
+
+ glutGet: function(type) {
+ switch (type) {
+ case 700: /* GLUT_ELAPSED_TIME */
+ var now = Date.now();
+ return now - GLUT.initTime;
+ default:
+ throw "glutGet(" + type + ") not implemented yet";
+ }
+ },
+
+ glutDisplayFunc: function(func) {
+ var RAF = window['setTimeout'];
+ if (window['requestAnimationFrame']) {
+ RAF = window['requestAnimationFrame'];
+ } else if (window['mozRequestAnimationFrame']) {
+ RAF = window['mozRequestAnimationFrame'];
+ } else if (window['webkitRequestAnimationFrame']) {
+ RAF = window['webkitRequestAnimationFrame'];
+ } else if (window['msRequestAnimationFrame']) {
+ RAF = window['msRequestAnimationFrame'];
+ }
+ RAF.apply(window, [function() {
+ if (GLUT.reshapeFunc) {
+ FUNCTION_TABLE[GLUT.reshapeFunc](Module['canvas'].width,
+ Module['canvas'].height);
+ }
+ if (GLUT.idleFunc) {
+ FUNCTION_TABLE[GLUT.idleFunc]();
+ }
+ FUNCTION_TABLE[func]();
+ _glutDisplayFunc(func);
+ }]);
+ },
+
+ glutIdleFunc: function(func) {
+ GLUT.idleFunc = func;
+ },
+
+ glutSpecialFunc: function(func) {
+ GLUT.keyboardFunc = func;
+ },
+
+ glutReshapeFunc: function(func) {
+ GLUT.reshapeFunc = func;
+ },
+
+ glutCreateWindow: function(name) {
+ try {
+ var ctx = Module.canvas.getContext('experimental-webgl');
+ if (!ctx) throw 'Could not create canvas :(';
+ Module.ctx = ctx;
+ // Set the background of the canvas to black, because glut gives us a
+ // window which has a black background by default.
+ Module.canvas.style.backgroundColor = "black";
+ } catch (e) {
+ Module.print('(canvas not available)');
+ }
+ },
+
+ glutInitDisplayMode: function(mode) {},
+ glutMainLoop: function() {},
+ glutSwapBuffers: function() {},
+ glutPostRedisplay: function() {},
+};
+
mergeInto(LibraryManager.library, LibraryGL);
+mergeInto(LibraryManager.library, LibraryGLUT);
diff --git a/src/library_sdl.js b/src/library_sdl.js
index ce26a106..d438fc23 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -176,6 +176,11 @@ mergeInto(LibraryManager.library, {
try {
var ctx = Module.canvas.getContext(useWebGL ? 'experimental-webgl' : '2d');
if (!ctx) throw 'Could not create canvas :(';
+ if (useWebGL) {
+ // Set the background of the WebGL canvas to black, because SDL gives us a
+ // window which has a black background by default.
+ Module.canvas.style.backgroundColor = "black";
+ }
return Module.ctx = ctx;
} catch (e) {
Module.print('(canvas not available)');
@@ -555,5 +560,15 @@ mergeInto(LibraryManager.library, {
// SDL Mixer
Mix_OpenAudio: function() { return -1 },
+
+ SDL_AddTimer: function(interval, callback, param) {
+ return window.setTimeout(function() {
+ FUNCTION_TABLE[callback](interval, param);
+ }, interval);
+ },
+ SDL_RemoveTimer: function(id) {
+ window.clearTimeout(id);
+ return true;
+ },
});
diff --git a/src/preamble.js b/src/preamble.js
index 94add7f4..d0391af5 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -490,16 +490,18 @@ function allocate(slab, types, allocator) {
}
Module['allocate'] = allocate;
-function Pointer_stringify(ptr) {
+function Pointer_stringify(ptr, /* optional */ length) {
+ var nullTerminated = typeof(length) == "undefined";
var ret = "";
var i = 0;
var t;
var nullByte = String.fromCharCode(0);
while (1) {
t = String.fromCharCode({{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}});
- if (t == nullByte) { break; } else {}
+ if (nullTerminated && t == nullByte) { break; } else {}
ret += t;
i += 1;
+ if (!nullTerminated && i == length) { break; }
}
return ret;
}
@@ -711,6 +713,20 @@ function Array_copy(ptr, num) {
}
Module['Array_copy'] = Array_copy;
+#if USE_TYPED_ARRAYS
+// Copies a list of num items on the HEAP into a
+// JavaScript typed array.
+function TypedArray_copy(ptr, num) {
+ // TODO: optimize this!
+ var arr = new Uint8Array(num);
+ for (var i = 0; i < num; ++i) {
+ arr[i] = {{{ makeGetValue('ptr', 'i', 'i8') }}};
+ }
+ return arr.buffer;
+}
+Module['TypedArray_copy'] = TypedArray_copy;
+#endif
+
function String_len(ptr) {
var i = 0;
while ({{{ makeGetValue('ptr', 'i', 'i8') }}}) i++; // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds
@@ -771,6 +787,25 @@ function intArrayToString(array) {
}
Module['intArrayToString'] = intArrayToString;
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+ var i = 0;
+ while (i < string.length) {
+ var chr = string.charCodeAt(i);
+ if (chr > 0xFF) {
+#if ASSERTIONS
+ assert(false, 'Character code ' + chr + ' (' + string[i] + ') at offset ' + i + ' not in 0x00-0xFF.');
+#endif
+ chr &= 0xFF;
+ }
+ {{{ makeSetValue('buffer', 'i', 'chr', 'i8') }}}
+ i = i + 1;
+ }
+ if (!dontAddNull) {
+ {{{ makeSetValue('buffer', 'i', '0', 'i8') }}}
+ }
+}
+
var STRING_TABLE = [];
{{{ unSign }}}
diff --git a/src/shell.html b/src/shell.html
index 6b6bbdad..69217b18 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -9,6 +9,11 @@
<div id='output'></div>
<hr>
<script type='text/javascript'>
+ /**
+ * TODO: Encapsulate this part in a reusable token such as
+ * EMSCRIPTEN_ENVIRONMENT so that we can share code
+ * between the default shell and custom ones.
+ */
// connect to canvas
var Module = {
print: (function() {
diff --git a/system/include/GL/freeglut_std.h b/system/include/GL/freeglut_std.h
new file mode 100644
index 00000000..ba1b7165
--- /dev/null
+++ b/system/include/GL/freeglut_std.h
@@ -0,0 +1,628 @@
+#ifndef __FREEGLUT_STD_H__
+#define __FREEGLUT_STD_H__
+
+/*
+ * freeglut_std.h
+ *
+ * The GLUT-compatible part of the freeglut library include file
+ *
+ * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
+ * Written by Pawel W. Olszta, <olszta@sourceforge.net>
+ * Creation date: Thu Dec 2 1999
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*
+ * Under windows, we have to differentiate between static and dynamic libraries
+ */
+#ifdef _WIN32
+/* #pragma may not be supported by some compilers.
+ * Discussion by FreeGLUT developers suggests that
+ * Visual C++ specific code involving pragmas may
+ * need to move to a separate header. 24th Dec 2003
+ */
+
+/* Define FREEGLUT_LIB_PRAGMAS to 1 to include library
+ * pragmas or to 0 to exclude library pragmas.
+ * The default behavior depends on the compiler/platform.
+ */
+# ifndef FREEGLUT_LIB_PRAGMAS
+# if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(_WIN32_WCE)
+# define FREEGLUT_LIB_PRAGMAS 1
+# else
+# define FREEGLUT_LIB_PRAGMAS 0
+# endif
+# endif
+
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# include <windows.h>
+
+/* Windows static library */
+# ifdef FREEGLUT_STATIC
+
+# define FGAPI
+# define FGAPIENTRY
+
+ /* Link with Win32 static freeglut lib */
+# if FREEGLUT_LIB_PRAGMAS
+# pragma comment (lib, "freeglut_static.lib")
+# endif
+
+/* Windows shared library (DLL) */
+# else
+
+# define FGAPIENTRY __stdcall
+# if defined(FREEGLUT_EXPORTS)
+# define FGAPI __declspec(dllexport)
+# else
+# define FGAPI __declspec(dllimport)
+
+ /* Link with Win32 shared freeglut lib */
+# if FREEGLUT_LIB_PRAGMAS
+# pragma comment (lib, "freeglut.lib")
+# endif
+
+# endif
+
+# endif
+
+/* Drag in other Windows libraries as required by FreeGLUT */
+# if FREEGLUT_LIB_PRAGMAS
+# pragma comment (lib, "glu32.lib") /* link OpenGL Utility lib */
+# pragma comment (lib, "opengl32.lib") /* link Microsoft OpenGL lib */
+# pragma comment (lib, "gdi32.lib") /* link Windows GDI lib */
+# pragma comment (lib, "winmm.lib") /* link Windows MultiMedia lib */
+# pragma comment (lib, "user32.lib") /* link Windows user lib */
+# endif
+
+#else
+
+/* Non-Windows definition of FGAPI and FGAPIENTRY */
+# define FGAPI
+# define FGAPIENTRY
+
+#endif
+
+/*
+ * The freeglut and GLUT API versions
+ */
+#define FREEGLUT 1
+#define GLUT_API_VERSION 4
+#define FREEGLUT_VERSION_2_0 1
+#define GLUT_XLIB_IMPLEMENTATION 13
+
+/*
+ * Always include OpenGL and GLU headers
+ */
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+/*
+ * GLUT API macro definitions -- the special key codes:
+ */
+#define GLUT_KEY_F1 0x0001
+#define GLUT_KEY_F2 0x0002
+#define GLUT_KEY_F3 0x0003
+#define GLUT_KEY_F4 0x0004
+#define GLUT_KEY_F5 0x0005
+#define GLUT_KEY_F6 0x0006
+#define GLUT_KEY_F7 0x0007
+#define GLUT_KEY_F8 0x0008
+#define GLUT_KEY_F9 0x0009
+#define GLUT_KEY_F10 0x000A
+#define GLUT_KEY_F11 0x000B
+#define GLUT_KEY_F12 0x000C
+#define GLUT_KEY_LEFT 0x0064
+#define GLUT_KEY_UP 0x0065
+#define GLUT_KEY_RIGHT 0x0066
+#define GLUT_KEY_DOWN 0x0067
+#define GLUT_KEY_PAGE_UP 0x0068
+#define GLUT_KEY_PAGE_DOWN 0x0069
+#define GLUT_KEY_HOME 0x006A
+#define GLUT_KEY_END 0x006B
+#define GLUT_KEY_INSERT 0x006C
+
+/*
+ * GLUT API macro definitions -- mouse state definitions
+ */
+#define GLUT_LEFT_BUTTON 0x0000
+#define GLUT_MIDDLE_BUTTON 0x0001
+#define GLUT_RIGHT_BUTTON