Buckets:
| /** | |
| * @license | |
| * Copyright 2010 The Emscripten Authors | |
| * SPDX-License-Identifier: MIT | |
| */ | |
| var LibraryWebGL2 = { | |
| glGetStringi__deps: ['$webglGetExtensions', '$stringToNewUTF8'], | |
| glGetStringi: (name, index) => { | |
| if (GL.currentContext.version < 2) { | |
| GL.recordError(0x502 /* GL_INVALID_OPERATION */); // Calling GLES3/WebGL2 function with a GLES2/WebGL1 context | |
| return 0; | |
| } | |
| var stringiCache = GL.stringiCache[name]; | |
| if (stringiCache) { | |
| if (index < 0 || index >= stringiCache.length) { | |
| GL.recordError(0x501/*GL_INVALID_VALUE*/); | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetStringi: index out of range (${index})!`); | |
| #endif | |
| return 0; | |
| } | |
| return stringiCache[index]; | |
| } | |
| switch (name) { | |
| case 0x1F03 /* GL_EXTENSIONS */: | |
| var exts = webglGetExtensions().map(stringToNewUTF8); | |
| stringiCache = GL.stringiCache[name] = exts; | |
| if (index < 0 || index >= stringiCache.length) { | |
| GL.recordError(0x501/*GL_INVALID_VALUE*/); | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetStringi: index out of range (${index}) in a call to GL_EXTENSIONS!`); | |
| #endif | |
| return 0; | |
| } | |
| return stringiCache[index]; | |
| default: | |
| GL.recordError(0x500/*GL_INVALID_ENUM*/); | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_ENUM in glGetStringi: Unknown parameter ${name}!`); | |
| #endif | |
| return 0; | |
| } | |
| }, | |
| glGetInteger64v__deps: ['$emscriptenWebGLGet'], | |
| glGetInteger64v: (name_, p) => { | |
| emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_J }}}); | |
| }, | |
| glGetInternalformativ: (target, internalformat, pname, bufSize, params) => { | |
| #if GL_TRACK_ERRORS | |
| if (bufSize < 0) { | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetInternalformativ(target=${target}, internalformat=${internalformat}, pname=${pname}, bufSize=${bufSize}, params=${params}): Function called with bufSize < 0!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| if (!params) { | |
| // GLES3 specification does not specify how to behave if values is a null pointer. Since calling this function does not make sense | |
| // if values == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetInternalformativ(target=${target}, internalformat=${internalformat}, pname=${pname}, bufSize=${bufSize}, params=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| var ret = GLctx.getInternalformatParameter(target, internalformat, pname); | |
| if (ret === null) return; | |
| for (var i = 0; i < ret.length && i < bufSize; ++i) { | |
| {{{ makeSetValue('params', 'i*4', 'ret[i]', 'i32') }}}; | |
| } | |
| }, | |
| glCompressedTexImage3D: (target, level, internalFormat, width, height, depth, border, imageSize, data) => { | |
| if (GLctx.currentPixelUnpackBufferBinding) { | |
| GLctx.compressedTexImage3D(target, level, internalFormat, width, height, depth, border, imageSize, data); | |
| } else { | |
| GLctx.compressedTexImage3D(target, level, internalFormat, width, height, depth, border, HEAPU8, data, imageSize); | |
| } | |
| }, | |
| glCompressedTexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) => { | |
| if (GLctx.currentPixelUnpackBufferBinding) { | |
| GLctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); | |
| } else { | |
| GLctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, HEAPU8, data, imageSize); | |
| } | |
| }, | |
| glGetBufferParameteri64v__deps: ['$writeI53ToI64'], | |
| glGetBufferParameteri64v: (target, value, data) => { | |
| #if GL_TRACK_ERRORS | |
| if (!data) { | |
| // GLES2 specification does not specify how to behave if data is a null pointer. Since calling this function does not make sense | |
| // if data == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetBufferParameteri64v(target=${target}, value=${value}, data=0): Function called with null out data pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| writeI53ToI64(data, GLctx.getBufferParameter(target, value)); | |
| }, | |
| glGetBufferSubData: (target, offset, size, data) => { | |
| #if GL_TRACK_ERRORS | |
| if (!data) { | |
| // GLES2 specification does not specify how to behave if data is a null pointer. Since calling this function does not make sense | |
| // if data == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetBufferSubData(target=${target}, offset=${offset}, size=${size}, data=0): Function called with null out data pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| #if WEBGL_USE_GARBAGE_FREE_APIS | |
| size && GLctx.getBufferSubData(target, offset, HEAPU8, data, size); | |
| #else | |
| size && GLctx.getBufferSubData(target, offset, HEAPU8.subarray(data, data+size)); | |
| #endif | |
| }, | |
| glInvalidateFramebuffer__deps: ['$tempFixedLengthArray'], | |
| glInvalidateFramebuffer: (target, numAttachments, attachments) => { | |
| #if GL_ASSERTIONS | |
| assert(numAttachments < tempFixedLengthArray.length, `Invalid count of numAttachments=${numAttachments} passed to glInvalidateFramebuffer (that many attachment points do not exist in GL)`); | |
| #endif | |
| var list = tempFixedLengthArray[numAttachments]; | |
| for (var i = 0; i < numAttachments; i++) { | |
| list[i] = {{{ makeGetValue('attachments', 'i*4', 'i32') }}}; | |
| } | |
| GLctx.invalidateFramebuffer(target, list); | |
| }, | |
| glInvalidateSubFramebuffer__deps: ['$tempFixedLengthArray'], | |
| glInvalidateSubFramebuffer: (target, numAttachments, attachments, x, y, width, height) => { | |
| #if GL_ASSERTIONS | |
| assert(numAttachments < tempFixedLengthArray.length, `Invalid count of numAttachments=${numAttachments} passed to glInvalidateSubFramebuffer (that many attachment points do not exist in GL)`); | |
| #endif | |
| var list = tempFixedLengthArray[numAttachments]; | |
| for (var i = 0; i < numAttachments; i++) { | |
| list[i] = {{{ makeGetValue('attachments', 'i*4', 'i32') }}}; | |
| } | |
| GLctx.invalidateSubFramebuffer(target, list, x, y, width, height); | |
| }, | |
| glTexImage3D__deps: ['$heapObjectForWebGLType', '$toTypedArrayIndex', | |
| #if !WEBGL_USE_GARBAGE_FREE_APIS | |
| '$emscriptenWebGLGetTexPixelData', | |
| #endif | |
| ], | |
| glTexImage3D: (target, level, internalFormat, width, height, depth, border, format, type, pixels) => { | |
| if (GLctx.currentPixelUnpackBufferBinding) { | |
| GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixels); | |
| } else if (pixels) { | |
| var heap = heapObjectForWebGLType(type); | |
| #if WEBGL_USE_GARBAGE_FREE_APIS | |
| GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, heap, toTypedArrayIndex(pixels, heap)); | |
| #else | |
| var pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height * depth, pixels, internalFormat); | |
| GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixelData); | |
| #endif | |
| } else { | |
| GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, null); | |
| } | |
| }, | |
| glTexSubImage3D__deps: ['$heapObjectForWebGLType', '$toTypedArrayIndex'], | |
| glTexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) => { | |
| if (GLctx.currentPixelUnpackBufferBinding) { | |
| GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); | |
| } else if (pixels) { | |
| var heap = heapObjectForWebGLType(type); | |
| GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, heap, toTypedArrayIndex(pixels, heap)); | |
| } else { | |
| GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, null); | |
| } | |
| }, | |
| // Queries | |
| glGenQueries: (n, ids) => { | |
| GL.genObject(n, ids, 'createQuery', GL.queries | |
| #if GL_ASSERTIONS | |
| , 'glGenQueries' | |
| #endif | |
| ); | |
| }, | |
| glDeleteQueries: (n, ids) => { | |
| for (var i = 0; i < n; i++) { | |
| var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; | |
| var query = GL.queries[id]; | |
| if (!query) continue; // GL spec: "unused names in ids are ignored, as is the name zero." | |
| GLctx.deleteQuery(query); | |
| GL.queries[id] = null; | |
| } | |
| }, | |
| glIsQuery: (id) => { | |
| var query = GL.queries[id]; | |
| if (!query) return 0; | |
| return GLctx.isQuery(query); | |
| }, | |
| glBeginQuery: (target, id) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.queries, id, 'glBeginQuery', 'id'); | |
| #endif | |
| GLctx.beginQuery(target, GL.queries[id]); | |
| }, | |
| glGetQueryiv: (target, pname, params) => { | |
| #if GL_TRACK_ERRORS | |
| if (!params) { | |
| // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense | |
| // if p == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetQueryiv(target=${target}, pname=${pname}, params=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| {{{ makeSetValue('params', '0', 'GLctx.getQuery(target, pname)', 'i32') }}}; | |
| }, | |
| glGetQueryObjectuiv: (id, pname, params) => { | |
| #if GL_TRACK_ERRORS | |
| if (!params) { | |
| // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense | |
| // if p == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetQueryObjectuiv(id=${id}, pname=${pname}, params=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.queries, id, 'glGetQueryObjectuiv', 'id'); | |
| #endif | |
| var query = GL.queries[id]; | |
| var param = GLctx.getQueryParameter(query, pname); | |
| var ret; | |
| if (typeof param == 'boolean') { | |
| ret = param ? 1 : 0; | |
| } else { | |
| ret = param; | |
| } | |
| {{{ makeSetValue('params', '0', 'ret', 'i32') }}}; | |
| }, | |
| // Sampler objects | |
| glGenSamplers: (n, samplers) => { | |
| GL.genObject(n, samplers, 'createSampler', GL.samplers | |
| #if GL_ASSERTIONS | |
| , 'glGenSamplers' | |
| #endif | |
| ); | |
| }, | |
| glDeleteSamplers: (n, samplers) => { | |
| for (var i = 0; i < n; i++) { | |
| var id = {{{ makeGetValue('samplers', 'i*4', 'i32') }}}; | |
| var sampler = GL.samplers[id]; | |
| if (!sampler) continue; | |
| GLctx.deleteSampler(sampler); | |
| sampler.name = 0; | |
| GL.samplers[id] = null; | |
| } | |
| }, | |
| glIsSampler: (id) => { | |
| var sampler = GL.samplers[id]; | |
| if (!sampler) return 0; | |
| return GLctx.isSampler(sampler); | |
| }, | |
| glBindSampler: (unit, sampler) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); | |
| #endif | |
| GLctx.bindSampler(unit, GL.samplers[sampler]); | |
| }, | |
| glSamplerParameterf: (sampler, pname, param) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); | |
| #endif | |
| GLctx.samplerParameterf(GL.samplers[sampler], pname, param); | |
| }, | |
| glSamplerParameteri: (sampler, pname, param) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); | |
| #endif | |
| GLctx.samplerParameteri(GL.samplers[sampler], pname, param); | |
| }, | |
| glSamplerParameterfv: (sampler, pname, params) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); | |
| #endif | |
| var param = {{{ makeGetValue('params', '0', 'float') }}}; | |
| GLctx.samplerParameterf(GL.samplers[sampler], pname, param); | |
| }, | |
| glSamplerParameteriv: (sampler, pname, params) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); | |
| #endif | |
| var param = {{{ makeGetValue('params', '0', 'i32') }}}; | |
| GLctx.samplerParameteri(GL.samplers[sampler], pname, param); | |
| }, | |
| glGetSamplerParameterfv: (sampler, pname, params) => { | |
| #if GL_TRACK_ERRORS | |
| if (!params) { | |
| // GLES3 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense | |
| // if p == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetSamplerParameterfv(sampler=${sampler}, pname=${pname}, params=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| {{{ makeSetValue('params', '0', 'GLctx.getSamplerParameter(GL.samplers[sampler], pname)', 'float') }}}; | |
| }, | |
| glGetSamplerParameteriv: (sampler, pname, params) => { | |
| #if GL_TRACK_ERRORS | |
| if (!params) { | |
| // GLES3 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense | |
| // if p == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetSamplerParameteriv(sampler=${sampler}, pname=${pname}, params=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| {{{ makeSetValue('params', '0', 'GLctx.getSamplerParameter(GL.samplers[sampler], pname)', 'i32') }}}; | |
| }, | |
| // Transform Feedback | |
| glGenTransformFeedbacks: (n, ids) => { | |
| GL.genObject(n, ids, 'createTransformFeedback', GL.transformFeedbacks | |
| #if GL_ASSERTIONS | |
| , 'glGenTransformFeedbacks' | |
| #endif | |
| ); | |
| }, | |
| glDeleteTransformFeedbacks: (n, ids) => { | |
| for (var i = 0; i < n; i++) { | |
| var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; | |
| var transformFeedback = GL.transformFeedbacks[id]; | |
| if (!transformFeedback) continue; // GL spec: "unused names in ids are ignored, as is the name zero." | |
| GLctx.deleteTransformFeedback(transformFeedback); | |
| transformFeedback.name = 0; | |
| GL.transformFeedbacks[id] = null; | |
| } | |
| }, | |
| glIsTransformFeedback: (id) => GLctx.isTransformFeedback(GL.transformFeedbacks[id]), | |
| glBindTransformFeedback: (target, id) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.transformFeedbacks, id, 'glBindTransformFeedback', 'id'); | |
| #endif | |
| GLctx.bindTransformFeedback(target, GL.transformFeedbacks[id]); | |
| }, | |
| glTransformFeedbackVaryings: (program, count, varyings, bufferMode) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glTransformFeedbackVaryings', 'program'); | |
| #endif | |
| program = GL.programs[program]; | |
| var vars = []; | |
| for (var i = 0; i < count; i++) | |
| vars.push(UTF8ToString({{{ makeGetValue('varyings', 'i*' + POINTER_SIZE, '*') }}})); | |
| GLctx.transformFeedbackVaryings(program, vars, bufferMode); | |
| }, | |
| glGetTransformFeedbackVarying: (program, index, bufSize, length, size, type, name) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glGetTransformFeedbackVarying', 'program'); | |
| #endif | |
| program = GL.programs[program]; | |
| var info = GLctx.getTransformFeedbackVarying(program, index); | |
| if (!info) return; // If an error occurred, the return parameters length, size, type and name will be unmodified. | |
| if (name && bufSize > 0) { | |
| var numBytesWrittenExclNull = stringToUTF8(info.name, name, bufSize); | |
| if (length) {{{ makeSetValue('length', '0', 'numBytesWrittenExclNull', 'i32') }}}; | |
| } else { | |
| if (length) {{{ makeSetValue('length', '0', 0, 'i32') }}}; | |
| } | |
| if (size) {{{ makeSetValue('size', '0', 'info.size', 'i32') }}}; | |
| if (type) {{{ makeSetValue('type', '0', 'info.type', 'i32') }}}; | |
| }, | |
| $emscriptenWebGLGetIndexed__deps: ['$writeI53ToI64'], | |
| $emscriptenWebGLGetIndexed: (target, index, data, type) => { | |
| #if GL_TRACK_ERRORS | |
| if (!data) { | |
| // GLES2 specification does not specify how to behave if data is a null pointer. Since calling this function does not make sense | |
| // if data == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetInteger(64)i_v(target=${target}, index=${index}, data=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| var result = GLctx.getIndexedParameter(target, index); | |
| var ret; | |
| switch (typeof result) { | |
| case 'boolean': | |
| ret = result ? 1 : 0; | |
| break; | |
| case 'number': | |
| ret = result; | |
| break; | |
| case 'object': | |
| if (result === null) { | |
| switch (target) { | |
| case 0x8C8F: // TRANSFORM_FEEDBACK_BUFFER_BINDING | |
| case 0x8A28: // UNIFORM_BUFFER_BINDING | |
| ret = 0; | |
| break; | |
| default: { | |
| GL.recordError(0x500); // GL_INVALID_ENUM | |
| #if GL_ASSERTIONS | |
| err('GL_INVALID_ENUM in glGetInteger(64)i_v(' + target + ') and it returns null!'); | |
| #endif | |
| return; | |
| } | |
| } | |
| } else if (result instanceof WebGLBuffer) { | |
| ret = result.name | 0; | |
| } else { | |
| GL.recordError(0x500); // GL_INVALID_ENUM | |
| #if GL_ASSERTIONS | |
| err('GL_INVALID_ENUM in glGetInteger(64)i_v: Unknown object returned from WebGL getIndexedParameter(' + target + ')!'); | |
| #endif | |
| return; | |
| } | |
| break; | |
| default: | |
| GL.recordError(0x500); // GL_INVALID_ENUM | |
| #if GL_ASSERTIONS | |
| err('GL_INVALID_ENUM in glGetInteger(64)i_v: Native code calling glGetInteger(64)i_v(' + target + ') and it returns ' + result + ' of type ' + typeof(result) + '!'); | |
| #endif | |
| return; | |
| } | |
| switch (type) { | |
| case {{{ cDefs.EM_FUNC_SIG_PARAM_J }}}: writeI53ToI64(data, ret); break; | |
| case {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}: {{{ makeSetValue('data', '0', 'ret', 'i32') }}}; break; | |
| case {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}: {{{ makeSetValue('data', '0', 'ret', 'float') }}}; break; | |
| case {{{ cDefs.EM_FUNC_SIG_PARAM_B }}}: {{{ makeSetValue('data', '0', 'ret ? 1 : 0', 'i8') }}}; break; | |
| default: abort('internal emscriptenWebGLGetIndexed() error, bad type: ' + type); | |
| } | |
| }, | |
| glGetIntegeri_v__deps: ['$emscriptenWebGLGetIndexed'], | |
| glGetIntegeri_v: (target, index, data) => | |
| emscriptenWebGLGetIndexed(target, index, data, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}), | |
| glGetInteger64i_v__deps: ['$emscriptenWebGLGetIndexed'], | |
| glGetInteger64i_v: (target, index, data) => | |
| emscriptenWebGLGetIndexed(target, index, data, {{{ cDefs.EM_FUNC_SIG_PARAM_J }}}), | |
| // Uniform Buffer objects | |
| glBindBufferBase: (target, index, buffer) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferBase', 'buffer'); | |
| #endif | |
| GLctx.bindBufferBase(target, index, GL.buffers[buffer]); | |
| }, | |
| glBindBufferRange: (target, index, buffer, offset, ptrsize) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferRange', 'buffer'); | |
| #endif | |
| GLctx.bindBufferRange(target, index, GL.buffers[buffer], offset, ptrsize); | |
| }, | |
| glGetUniformIndices: (program, uniformCount, uniformNames, uniformIndices) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glGetUniformIndices', 'program'); | |
| #endif | |
| #if GL_TRACK_ERRORS | |
| if (!uniformIndices) { | |
| // GLES2 specification does not specify how to behave if uniformIndices is a null pointer. Since calling this function does not make sense | |
| // if uniformIndices == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetUniformIndices(program=${program}, uniformCount=${uniformCount}, uniformNames=${uniformNames}, uniformIndices=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| if (uniformCount > 0 && (uniformNames == 0 || uniformIndices == 0)) { | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| program = GL.programs[program]; | |
| var names = []; | |
| for (var i = 0; i < uniformCount; i++) | |
| names.push(UTF8ToString({{{ makeGetValue('uniformNames', 'i*' + POINTER_SIZE, '*') }}})); | |
| var result = GLctx.getUniformIndices(program, names); | |
| if (!result) return; // GL spec: If an error is generated, nothing is written out to uniformIndices. | |
| var len = result.length; | |
| for (var i = 0; i < len; i++) { | |
| {{{ makeSetValue('uniformIndices', 'i*4', 'result[i]', 'i32') }}}; | |
| } | |
| }, | |
| glGetActiveUniformsiv: (program, uniformCount, uniformIndices, pname, params) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniformsiv', 'program'); | |
| #endif | |
| #if GL_TRACK_ERRORS | |
| if (!params) { | |
| // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense | |
| // if params == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetActiveUniformsiv(program=${program}, uniformCount=${uniformCount}, uniformIndices=${uniformIndices}, pname=${pname}, params=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| if (uniformCount > 0 && uniformIndices == 0) { | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| program = GL.programs[program]; | |
| var ids = []; | |
| for (var i = 0; i < uniformCount; i++) { | |
| ids.push({{{ makeGetValue('uniformIndices', 'i*4', 'i32') }}}); | |
| } | |
| var result = GLctx.getActiveUniforms(program, ids, pname); | |
| if (!result) return; // GL spec: If an error is generated, nothing is written out to params. | |
| var len = result.length; | |
| for (var i = 0; i < len; i++) { | |
| {{{ makeSetValue('params', 'i*4', 'result[i]', 'i32') }}}; | |
| } | |
| }, | |
| glGetUniformBlockIndex: (program, uniformBlockName) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glGetUniformBlockIndex', 'program'); | |
| #endif | |
| return GLctx.getUniformBlockIndex(GL.programs[program], UTF8ToString(uniformBlockName)); | |
| }, | |
| glGetActiveUniformBlockiv: (program, uniformBlockIndex, pname, params) => { | |
| #if GL_TRACK_ERRORS | |
| if (!params) { | |
| // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense | |
| // if params == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetActiveUniformBlockiv(program=${program}, uniformBlockIndex=${uniformBlockIndex}, pname=${pname}, params=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniformBlockiv', 'program'); | |
| #endif | |
| program = GL.programs[program]; | |
| if (pname == 0x8A41 /* GL_UNIFORM_BLOCK_NAME_LENGTH */) { | |
| var name = GLctx.getActiveUniformBlockName(program, uniformBlockIndex); | |
| {{{ makeSetValue('params', 0, 'name.length+1', 'i32') }}}; | |
| return; | |
| } | |
| var result = GLctx.getActiveUniformBlockParameter(program, uniformBlockIndex, pname); | |
| if (result === null) return; // If an error occurs, nothing should be written to params. | |
| if (pname == 0x8A43 /*GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES*/) { | |
| for (var i = 0; i < result.length; i++) { | |
| {{{ makeSetValue('params', 'i*4', 'result[i]', 'i32') }}}; | |
| } | |
| } else { | |
| {{{ makeSetValue('params', '0', 'result', 'i32') }}}; | |
| } | |
| }, | |
| glGetActiveUniformBlockName: (program, uniformBlockIndex, bufSize, length, uniformBlockName) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniformBlockName', 'program'); | |
| #endif | |
| program = GL.programs[program]; | |
| var result = GLctx.getActiveUniformBlockName(program, uniformBlockIndex); | |
| if (!result) return; // If an error occurs, nothing will be written to uniformBlockName or length. | |
| if (uniformBlockName && bufSize > 0) { | |
| var numBytesWrittenExclNull = stringToUTF8(result, uniformBlockName, bufSize); | |
| if (length) {{{ makeSetValue('length', '0', 'numBytesWrittenExclNull', 'i32') }}}; | |
| } else { | |
| if (length) {{{ makeSetValue('length', '0', 0, 'i32') }}}; | |
| } | |
| }, | |
| glUniformBlockBinding: (program, uniformBlockIndex, uniformBlockBinding) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glUniformBlockBinding', 'program'); | |
| #endif | |
| program = GL.programs[program]; | |
| GLctx.uniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); | |
| }, | |
| glClearBufferiv: (buffer, drawbuffer, value) => { | |
| #if GL_ASSERTIONS | |
| assert((value & 3) == 0, 'pointer passed to glClearBufferiv must be 4-byte aligned'); | |
| #endif | |
| GLctx.clearBufferiv(buffer, drawbuffer, HEAP32, {{{ getHeapOffset('value', 'i32') }}}); | |
| }, | |
| glClearBufferuiv: (buffer, drawbuffer, value) => { | |
| #if GL_ASSERTIONS | |
| assert((value & 3) == 0, 'pointer passed to glClearBufferuiv must be 4-byte aligned'); | |
| #endif | |
| GLctx.clearBufferuiv(buffer, drawbuffer, HEAPU32, {{{ getHeapOffset('value', 'u32') }}}); | |
| }, | |
| glClearBufferfv: (buffer, drawbuffer, value) => { | |
| #if GL_ASSERTIONS | |
| assert((value & 3) == 0, 'pointer passed to glClearBufferfv must be 4-byte aligned'); | |
| #endif | |
| GLctx.clearBufferfv(buffer, drawbuffer, HEAPF32, {{{ getHeapOffset('value', 'float') }}}); | |
| }, | |
| glFenceSync: (condition, flags) => { | |
| var sync = GLctx.fenceSync(condition, flags); | |
| if (sync) { | |
| var id = GL.getNewId(GL.syncs); | |
| sync.name = id; | |
| GL.syncs[id] = sync; | |
| return id; | |
| } | |
| return 0; // Failed to create a sync object | |
| }, | |
| glDeleteSync: (id) => { | |
| if (!id) return; | |
| var sync = GL.syncs[id]; | |
| if (!sync) { // glDeleteSync signals an error when deleting a nonexisting object, unlike some other GL delete functions. | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| GLctx.deleteSync(sync); | |
| sync.name = 0; | |
| GL.syncs[id] = null; | |
| }, | |
| #if !WASM_BIGINT | |
| glClientWaitSync__deps: ['$convertI32PairToI53'], | |
| #endif | |
| glClientWaitSync: (sync, flags, {{{ defineI64Param('timeout') }}}) => { | |
| // WebGL2 vs GLES3 differences: in GLES3, the timeout parameter is a uint64, where 0xFFFFFFFFFFFFFFFFULL means GL_TIMEOUT_IGNORED. | |
| // In JS, there's no 64-bit value types, so instead timeout is taken to be signed, and GL_TIMEOUT_IGNORED is given value -1. | |
| // Inherently the value accepted in the timeout is lossy, and can't take in arbitrary u64 bit pattern (but most likely doesn't matter) | |
| // See https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.15 | |
| {{{ receiveI64ParamAsI53Unchecked('timeout'); }}} | |
| return GLctx.clientWaitSync(GL.syncs[sync], flags, timeout); | |
| }, | |
| #if !WASM_BIGINT | |
| glWaitSync__deps: ['$convertI32PairToI53'], | |
| #endif | |
| glWaitSync: (sync, flags, {{{ defineI64Param('timeout') }}}) => { | |
| // See WebGL2 vs GLES3 difference on GL_TIMEOUT_IGNORED above (https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.15) | |
| {{{ receiveI64ParamAsI53Unchecked('timeout'); }}} | |
| GLctx.waitSync(GL.syncs[sync], flags, timeout); | |
| }, | |
| glGetSynciv: (sync, pname, bufSize, length, values) => { | |
| #if GL_TRACK_ERRORS | |
| if (bufSize < 0) { | |
| // GLES3 specification does not specify how to behave if bufSize < 0, however in the spec wording for glGetInternalformativ, it does say that GL_INVALID_VALUE should be raised, | |
| // so raise GL_INVALID_VALUE here as well. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetSynciv(sync=${sync}, pname=${pname}, bufSize=${bufSize}, length=${length}, values=${values}): Function called with bufSize < 0!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| if (!values) { | |
| // GLES3 specification does not specify how to behave if values is a null pointer. Since calling this function does not make sense | |
| // if values == null, issue a GL error to notify user about it. | |
| #if GL_ASSERTIONS | |
| err(`GL_INVALID_VALUE in glGetSynciv(sync=${sync}, pname=${pname}, bufSize=${bufSize}, length=${length}, values=0): Function called with null out pointer!`); | |
| #endif | |
| GL.recordError(0x501 /* GL_INVALID_VALUE */); | |
| return; | |
| } | |
| #endif | |
| var ret = GLctx.getSyncParameter(GL.syncs[sync], pname); | |
| if (ret !== null) { | |
| {{{ makeSetValue('values', '0', 'ret', 'i32') }}}; | |
| if (length) {{{ makeSetValue('length', '0', '1', 'i32') }}}; // Report a single value outputted. | |
| } | |
| }, | |
| glIsSync: (sync) => GLctx.isSync(GL.syncs[sync]), | |
| glGetUniformuiv__deps: ['$emscriptenWebGLGetUniform'], | |
| glGetUniformuiv: (program, location, params) => | |
| emscriptenWebGLGetUniform(program, location, params, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}), | |
| glGetFragDataLocation: (program, name) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.programs, program, 'glGetFragDataLocation', 'program'); | |
| #endif | |
| return GLctx.getFragDataLocation(GL.programs[program], UTF8ToString(name)); | |
| }, | |
| glGetVertexAttribIiv__deps: ['$emscriptenWebGLGetVertexAttrib'], | |
| glGetVertexAttribIiv: (index, pname, params) => { | |
| // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttribI4iv(), | |
| // otherwise the results are undefined. (GLES3 spec 6.1.12) | |
| emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); | |
| }, | |
| // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttribI4uiv(), | |
| // otherwise the results are undefined. (GLES3 spec 6.1.12) | |
| glGetVertexAttribIuiv__deps: ['$emscriptenWebGLGetVertexAttrib'], | |
| glGetVertexAttribIuiv: 'glGetVertexAttribIiv', | |
| glUniform1ui__deps: ['$webglGetUniformLocation'], | |
| glUniform1ui: (location, v0) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform1ui', 'location'); | |
| #endif | |
| GLctx.uniform1ui(webglGetUniformLocation(location), v0); | |
| }, | |
| glUniform2ui__deps: ['$webglGetUniformLocation'], | |
| glUniform2ui: (location, v0, v1) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform2ui', 'location'); | |
| #endif | |
| GLctx.uniform2ui(webglGetUniformLocation(location), v0, v1); | |
| }, | |
| glUniform3ui__deps: ['$webglGetUniformLocation'], | |
| glUniform3ui: (location, v0, v1, v2) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform3ui', 'location'); | |
| #endif | |
| GLctx.uniform3ui(webglGetUniformLocation(location), v0, v1, v2); | |
| }, | |
| glUniform4ui__deps: ['$webglGetUniformLocation'], | |
| glUniform4ui: (location, v0, v1, v2, v3) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform4ui', 'location'); | |
| #endif | |
| GLctx.uniform4ui(webglGetUniformLocation(location), v0, v1, v2, v3); | |
| }, | |
| glUniform1uiv__deps: ['$webglGetUniformLocation'], | |
| glUniform1uiv: (location, count, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform1uiv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniform1uiv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniform1uiv(webglGetUniformLocation(location), HEAPU32, {{{ getHeapOffset('value', 'u32') }}}, count); | |
| }, | |
| glUniform2uiv__deps: ['$webglGetUniformLocation'], | |
| glUniform2uiv: (location, count, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform2uiv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniform2uiv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniform2uiv(webglGetUniformLocation(location), HEAPU32, {{{ getHeapOffset('value', 'u32') }}}, count*2); | |
| }, | |
| glUniform3uiv__deps: ['$webglGetUniformLocation'], | |
| glUniform3uiv: (location, count, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform3uiv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniform3uiv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniform3uiv(webglGetUniformLocation(location), HEAPU32, {{{ getHeapOffset('value', 'u32') }}}, count*3); | |
| }, | |
| glUniform4uiv__deps: ['$webglGetUniformLocation'], | |
| glUniform4uiv: (location, count, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform4uiv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniform4uiv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniform4uiv(webglGetUniformLocation(location), HEAPU32, {{{ getHeapOffset('value', 'u32') }}}, count*4); | |
| }, | |
| glUniformMatrix2x3fv__deps: ['$webglGetUniformLocation'], | |
| glUniformMatrix2x3fv: (location, count, transpose, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix2x3fv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniformMatrix2x3fv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniformMatrix2x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*6); | |
| }, | |
| glUniformMatrix3x2fv__deps: ['$webglGetUniformLocation'], | |
| glUniformMatrix3x2fv: (location, count, transpose, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix3x2fv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniformMatrix3x2fv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniformMatrix3x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*6); | |
| }, | |
| glUniformMatrix2x4fv__deps: ['$webglGetUniformLocation'], | |
| glUniformMatrix2x4fv: (location, count, transpose, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix2x4fv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniformMatrix2x4fv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniformMatrix2x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*8); | |
| }, | |
| glUniformMatrix4x2fv__deps: ['$webglGetUniformLocation'], | |
| glUniformMatrix4x2fv: (location, count, transpose, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix4x2fv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniformMatrix4x2fv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniformMatrix4x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*8); | |
| }, | |
| glUniformMatrix3x4fv__deps: ['$webglGetUniformLocation'], | |
| glUniformMatrix3x4fv: (location, count, transpose, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix3x4fv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniformMatrix3x4fv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniformMatrix3x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*12); | |
| }, | |
| glUniformMatrix4x3fv__deps: ['$webglGetUniformLocation'], | |
| glUniformMatrix4x3fv: (location, count, transpose, value) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix4x3fv', 'location'); | |
| assert((value & 3) == 0, 'pointer passed to glUniformMatrix4x3fv must be 4-byte aligned'); | |
| #endif | |
| count && GLctx.uniformMatrix4x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*12); | |
| }, | |
| glVertexAttribI4iv: (index, v) => { | |
| #if GL_ASSERTIONS | |
| assert((v & 3) == 0, 'pointer passed to glVertexAttribI4iv must be 4-byte aligned'); | |
| assert(v != 0, 'null pointer passed to glVertexAttribI4iv'); | |
| #endif | |
| GLctx.vertexAttribI4i(index, HEAP32[v>>2], HEAP32[v+4>>2], HEAP32[v+8>>2], HEAP32[v+12>>2]); | |
| }, | |
| glVertexAttribI4uiv: (index, v) => { | |
| #if GL_ASSERTIONS | |
| assert((v & 3) == 0, 'pointer passed to glVertexAttribI4uiv must be 4-byte aligned'); | |
| assert(v != 0, 'null pointer passed to glVertexAttribI4uiv'); | |
| #endif | |
| GLctx.vertexAttribI4ui(index, HEAPU32[v>>2], HEAPU32[v+4>>2], HEAPU32[v+8>>2], HEAPU32[v+12>>2]); | |
| }, | |
| glProgramParameteri: (program, pname, value) => { | |
| GL.recordError(0x500/*GL_INVALID_ENUM*/); | |
| #if GL_ASSERTIONS | |
| err("GL_INVALID_ENUM in glProgramParameteri: WebGL does not support binary shader formats! Calls to glProgramParameteri always fail. See https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.4"); | |
| #endif | |
| }, | |
| glGetProgramBinary: (program, bufSize, length, binaryFormat, binary) => { | |
| GL.recordError(0x502/*GL_INVALID_OPERATION*/); | |
| #if GL_ASSERTIONS | |
| err("GL_INVALID_OPERATION in glGetProgramBinary: WebGL does not support binary shader formats! Calls to glGetProgramBinary always fail. See https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.4"); | |
| #endif | |
| }, | |
| glProgramBinary: (program, binaryFormat, binary, length) => { | |
| GL.recordError(0x500/*GL_INVALID_ENUM*/); | |
| #if GL_ASSERTIONS | |
| err("GL_INVALID_ENUM in glProgramBinary: WebGL does not support binary shader formats! Calls to glProgramBinary always fail. See https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.4"); | |
| #endif | |
| }, | |
| glFramebufferTextureLayer: (target, attachment, texture, level, layer) => { | |
| #if GL_ASSERTIONS | |
| GL.validateGLObjectID(GL.textures, texture, 'glFramebufferTextureLayer', 'texture'); | |
| #endif | |
| GLctx.framebufferTextureLayer(target, attachment, GL.textures[texture], level, layer); | |
| }, | |
| glVertexAttribIPointer: (index, size, type, stride, ptr) => { | |
| #if FULL_ES3 | |
| var cb = GL.currentContext.clientBuffers[index]; | |
| #if GL_ASSERTIONS | |
| assert(cb, index); | |
| #endif | |
| if (!GLctx.currentArrayBufferBinding) { | |
| cb.size = size; | |
| cb.type = type; | |
| cb.normalized = false; | |
| cb.stride = stride; | |
| cb.ptr = ptr; | |
| cb.clientside = true; | |
| cb.vertexAttribPointerAdaptor = function(index, size, type, normalized, stride, ptr) { | |
| this.vertexAttribIPointer(index, size, type, stride, ptr); | |
| }; | |
| return; | |
| } | |
| cb.clientside = false; | |
| #endif | |
| #if GL_ASSERTIONS | |
| GL.validateVertexAttribPointer(size, type, stride, ptr); | |
| #endif | |
| GLctx.vertexAttribIPointer(index, size, type, stride, ptr); | |
| }, | |
| #if !LEGACY_GL_EMULATION | |
| // Defined in library_glemu.js when LEGACY_GL_EMULATION is set | |
| glDrawRangeElements__deps: ['glDrawElements'], | |
| glDrawRangeElements: (mode, start, end, count, type, indices) => { | |
| // TODO: This should be a trivial pass-through function registered at the bottom of this page as | |
| // glFuncs[6][1] += ' drawRangeElements'; | |
| // but due to https://bugzil.la/1202427, | |
| // we work around by ignoring the range. | |
| _glDrawElements(mode, count, type, indices); | |
| }, | |
| #endif | |
| glDrawArraysInstancedBaseInstanceWEBGL__sig: 'viiiii', | |
| glDrawArraysInstancedBaseInstanceWEBGL: (mode, first, count, instanceCount, baseInstance) => { | |
| GLctx.dibvbi['drawArraysInstancedBaseInstanceWEBGL'](mode, first, count, instanceCount, baseInstance); | |
| }, | |
| glDrawArraysInstancedBaseInstance: 'glDrawArraysInstancedBaseInstanceWEBGL', | |
| glDrawArraysInstancedBaseInstanceANGLE: 'glDrawArraysInstancedBaseInstanceWEBGL', | |
| glDrawElementsInstancedBaseVertexBaseInstanceWEBGL__sig: 'viiiiiii', | |
| glDrawElementsInstancedBaseVertexBaseInstanceWEBGL: (mode, count, type, offset, instanceCount, baseVertex, baseinstance) => { | |
| GLctx.dibvbi['drawElementsInstancedBaseVertexBaseInstanceWEBGL'](mode, count, type, offset, instanceCount, baseVertex, baseinstance); | |
| }, | |
| glDrawElementsInstancedBaseVertexBaseInstanceANGLE: 'glDrawElementsInstancedBaseVertexBaseInstanceWEBGL', | |
| $webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance: (ctx) => | |
| // Closure is expected to be allowed to minify the '.dibvbi' property, so not accessing it quoted. | |
| !!(ctx.dibvbi = ctx.getExtension('WEBGL_draw_instanced_base_vertex_base_instance')), | |
| emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance__deps: ['$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance'], | |
| emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance: (ctx) => | |
| webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx), | |
| glMultiDrawArraysInstancedBaseInstanceWEBGL__sig: 'viiiiii', | |
| glMultiDrawArraysInstancedBaseInstanceWEBGL: (mode, firsts, counts, instanceCounts, baseInstances, drawCount) => { | |
| GLctx.mdibvbi['multiDrawArraysInstancedBaseInstanceWEBGL']( | |
| mode, | |
| HEAP32, | |
| {{{ getHeapOffset('firsts', 'i32') }}}, | |
| HEAP32, | |
| {{{ getHeapOffset('counts', 'i32') }}}, | |
| HEAP32, | |
| {{{ getHeapOffset('instanceCounts', 'i32') }}}, | |
| HEAPU32, | |
| {{{ getHeapOffset('baseInstances', 'i32') }}}, | |
| drawCount); | |
| }, | |
| glMultiDrawArraysInstancedBaseInstanceANGLE: 'glMultiDrawArraysInstancedBaseInstanceWEBGL', | |
| glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL__sig: 'viiiiiiii', | |
| glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL: (mode, counts, type, offsets, instanceCounts, baseVertices, baseInstances, drawCount) => { | |
| GLctx.mdibvbi['multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL']( | |
| mode, | |
| HEAP32, | |
| {{{ getHeapOffset('counts', 'i32') }}}, | |
| type, | |
| HEAP32, | |
| {{{ getHeapOffset('offsets', 'i32') }}}, | |
| HEAP32, | |
| {{{ getHeapOffset('instanceCounts', 'i32') }}}, | |
| HEAP32, | |
| {{{ getHeapOffset('baseVertices', 'i32') }}}, | |
| HEAPU32, | |
| {{{ getHeapOffset('baseInstances', 'i32') }}}, | |
| drawCount); | |
| }, | |
| glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE: 'glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL', | |
| $webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance: (ctx) => { | |
| // Closure is expected to be allowed to minify the '.mdibvbi' property, so not accessing it quoted. | |
| return !!(ctx.mdibvbi = ctx.getExtension('WEBGL_multi_draw_instanced_base_vertex_base_instance')); | |
| }, | |
| emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance__deps: ['$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance'], | |
| emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance: (ctx) => | |
| webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx), | |
| }; | |
| #if MAX_WEBGL_VERSION >= 2 | |
| // Simple pass-through functions. | |
| // - Starred ones have return values. | |
| // - [X] ones have X in the C name but not in the JS name | |
| var webgl2PassthroughFuncs = [ | |
| [0, 'endTransformFeedback pauseTransformFeedback resumeTransformFeedback'], | |
| [1, 'beginTransformFeedback readBuffer endQuery'], | |
| [4, 'clearBufferfi'], | |
| [5, 'vertexAttribI4i vertexAttribI4ui copyBufferSubData texStorage2D renderbufferStorageMultisample'], | |
| [6, 'texStorage3D'], | |
| [9, 'copyTexSubImage3D'], | |
| [10, 'blitFramebuffer'] | |
| ]; | |
| // If user passes -sMAX_WEBGL_VERSION >= 2 -sSTRICT but not -lGL (to link in | |
| // WebGL 1), then WebGL2 library should not be linked in as well. | |
| if (typeof createGLPassthroughFunctions == 'undefined') { | |
| error('In order to use WebGL 2 in strict mode with -sMAX_WEBGL_VERSION=2, you need to link in WebGL support with -lGL'); | |
| } | |
| createGLPassthroughFunctions(LibraryWebGL2, webgl2PassthroughFuncs); | |
| recordGLProcAddressGet(LibraryWebGL2); | |
| addToLibrary(LibraryWebGL2); | |
| #endif | |
Xet Storage Details
- Size:
- 43.5 kB
- Xet hash:
- 922b0d84c91620bc8a3bd6418b0016f06953c5eb4b50210c51f307aa509d1bc3
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.