diff --git a/binding.gyp b/binding.gyp index 92ceb69f..c58ff8cc 100644 --- a/binding.gyp +++ b/binding.gyp @@ -11,7 +11,8 @@ { 'target_name': 'webgl', 'defines': [ - 'VERSION=1.0.0' + 'VERSION=1.0.0', + 'NAPI_VERSION=8' ], 'sources': [ 'src/native/bindings.cc', @@ -21,10 +22,11 @@ 'src/native/angle-loader/gles_loader.cc' ], 'include_dirs': [ - "=20.0.0" @@ -513,9 +515,9 @@ "license": "MIT" }, "node_modules/@stackgl/gl-conformance/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -591,7 +593,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -616,6 +618,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "20.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", + "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -639,7 +651,6 @@ "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2356,15 +2367,15 @@ "license": "MIT" }, "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", "dev": true, "license": "MIT", "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", - "minimatch": "9.0.1", + "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { @@ -2375,9 +2386,9 @@ } }, "node_modules/editorconfig/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -2385,13 +2396,13 @@ } }, "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -2733,7 +2744,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -2941,7 +2951,6 @@ "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -3022,7 +3031,6 @@ "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", @@ -3062,7 +3070,6 @@ "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", "dev": true, "license": "ISC", - "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -3079,7 +3086,6 @@ "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -5093,9 +5099,9 @@ } }, "node_modules/js-beautify/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -5103,9 +5109,10 @@ } }, "node_modules/js-beautify/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -5124,13 +5131,13 @@ } }, "node_modules/js-beautify/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -5729,12 +5736,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/nan": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.24.0.tgz", - "integrity": "sha512-Vpf9qnVW1RaDkoNKFUvfxqAbtI8ncb8OJlqZ9wwpXzWPEsvsB1nvdUi6oYrHIkQ1Y/tMDnr1h4nczS0VB9Xykg==", - "license": "MIT" - }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -5777,6 +5778,15 @@ "node": ">=10" } }, + "node_modules/node-addon-api": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz", + "integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/node-api-headers": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/node-api-headers/-/node-api-headers-1.5.0.tgz", @@ -6728,7 +6738,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -9251,6 +9260,20 @@ "dev": true, "license": "MIT" }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -9270,6 +9293,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, "node_modules/unique-filename": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz", diff --git a/package.json b/package.json index ece16947..76964304 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,14 @@ "version": "9.0.0-rc.9", "description": "Creates a WebGL context without a window", "main": "index.js", - "browser": "src/javascript/browser-index.js", + "browser": "src/browser-index.ts", + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./index.mjs", + "require": "./index.js" + } + }, "directories": { "test": "test" }, @@ -11,6 +18,7 @@ "node": ">=20.0.0" }, "scripts": { + "build": "tsc", "test": "standard | snazzy && tape test/*.js | faucet", "rebuild": "node-gyp rebuild --verbose", "prebuild": "prebuild --all --strip", @@ -20,19 +28,21 @@ "bindings": "^1.5.0", "bit-twiddle": "^1.0.2", "glsl-tokenizer": "^2.1.5", - "nan": "^2.24.0", + "node-addon-api": "^8.3.1", "node-gyp": "^12.1.0", "prebuild-install": "^7.1.3" }, "devDependencies": { - "@stackgl/gl-conformance": "2.1.3", + "@stackgl/gl-conformance": "^2.1.3", + "@types/node": "^20.19.39", "angle-normals": "^1.0.0", "bunny": "^1.0.1", "faucet": "^0.0.4", "prebuild": "^13.0.1", "snazzy": "^9.0.0", "standard": "^17.1.2", - "tape": "^5.9.0" + "tape": "^5.9.0", + "typescript": "^5.7.2" }, "repository": { "type": "git", diff --git a/src/browser-index.ts b/src/browser-index.ts new file mode 100644 index 00000000..5ad73a62 --- /dev/null +++ b/src/browser-index.ts @@ -0,0 +1,65 @@ +export function createContext( + width: number, + height: number, + options?: WebGLContextAttributes, +): WebGLRenderingContext | null { + width = width | 0; + height = height | 0; + if (!(width > 0 && height > 0)) return null; + + const canvas = document.createElement('canvas'); + if (!canvas) return null; + + let gl: WebGLRenderingContext | null = null; + canvas.width = width; + canvas.height = height; + + try { + gl = canvas.getContext('webgl', options); + } catch { + try { + gl = canvas.getContext( + 'experimental-webgl', + options, + ) as WebGLRenderingContext | null; + } catch { + return null; + } + } + + if (!gl) return null; + + const _getExtension = gl.getExtension.bind(gl); + const extDestroy = { + destroy: function () { + const loseContext = _getExtension('WEBGL_lose_context'); + if (loseContext) loseContext.loseContext(); + }, + }; + + const extResize = { + resize: function (w: number, h: number) { + canvas.width = w; + canvas.height = h; + }, + }; + + const _supportedExtensions = gl.getSupportedExtensions()!.slice(); + _supportedExtensions.push( + 'STACKGL_destroy_context', + 'STACKGL_resize_drawingbuffer', + ); + + gl.getSupportedExtensions = function () { + return _supportedExtensions.slice(); + }; + + gl.getExtension = function (extName: string): any { + const name = extName.toLowerCase(); + if (name === 'stackgl_resize_drawingbuffer') return extResize; + if (name === 'stackgl_destroy_context') return extDestroy; + return _getExtension(extName); + }; + + return gl; +} diff --git a/src/extensions/angle-instanced-arrays.ts b/src/extensions/angle-instanced-arrays.ts new file mode 100644 index 00000000..429ba95a --- /dev/null +++ b/src/extensions/angle-instanced-arrays.ts @@ -0,0 +1,44 @@ +import { gl } from '../native-gl'; + +export class ANGLEInstancedArrays { + VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: number; + ctx: any; + private _drawArraysInstancedANGLE: (...args: any[]) => any; + private _drawElementsInstancedANGLE: (...args: any[]) => any; + private _vertexAttribDivisorANGLE: (...args: any[]) => any; + + constructor(ctx: any) { + this.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88fe; + this.ctx = ctx; + this._drawArraysInstancedANGLE = gl._drawArraysInstancedANGLE.bind(ctx); + this._drawElementsInstancedANGLE = gl._drawElementsInstancedANGLE.bind(ctx); + this._vertexAttribDivisorANGLE = gl._vertexAttribDivisorANGLE.bind(ctx); + } + + drawArraysInstancedANGLE( + mode: number, + first: number, + count: number, + primCount: number, + ): void { + this._drawArraysInstancedANGLE(mode, first, count, primCount); + } + + drawElementsInstancedANGLE( + mode: number, + count: number, + type: number, + ioffset: number, + primCount: number, + ): void { + this._drawElementsInstancedANGLE(mode, count, type, ioffset, primCount); + } + + vertexAttribDivisorANGLE(index: number, divisor: number): void { + this._vertexAttribDivisorANGLE(index, divisor); + } +} + +export function getANGLEInstancedArrays(ctx: any): ANGLEInstancedArrays { + return new ANGLEInstancedArrays(ctx); +} diff --git a/src/extensions/ext-blend-minmax.ts b/src/extensions/ext-blend-minmax.ts new file mode 100644 index 00000000..b645df26 --- /dev/null +++ b/src/extensions/ext-blend-minmax.ts @@ -0,0 +1,17 @@ +export class EXTBlendMinMax { + MIN_EXT: number; + MAX_EXT: number; + + constructor() { + this.MIN_EXT = 0x8007; + this.MAX_EXT = 0x8008; + } +} + +export function getEXTBlendMinMax(context: any): EXTBlendMinMax | null { + const exts = context.getSupportedExtensions(); + if (exts && exts.indexOf('EXT_blend_minmax') >= 0) { + return new EXTBlendMinMax(); + } + return null; +} diff --git a/src/extensions/ext-color-buffer-float.ts b/src/extensions/ext-color-buffer-float.ts new file mode 100644 index 00000000..3086300b --- /dev/null +++ b/src/extensions/ext-color-buffer-float.ts @@ -0,0 +1,11 @@ +export class EXTColorBufferFloat {} + +export function getEXTColorBufferFloat( + context: any, +): EXTColorBufferFloat | null { + const exts = context.getSupportedExtensions(); + if (exts && exts.indexOf('EXT_color_buffer_float') >= 0) { + return new EXTColorBufferFloat(); + } + return null; +} diff --git a/src/extensions/ext-shader-texture-lod.ts b/src/extensions/ext-shader-texture-lod.ts new file mode 100644 index 00000000..a36c10b6 --- /dev/null +++ b/src/extensions/ext-shader-texture-lod.ts @@ -0,0 +1,11 @@ +export class EXTShaderTextureLod {} + +export function getEXTShaderTextureLod( + context: any, +): EXTShaderTextureLod | null { + const exts = context.getSupportedExtensions(); + if (exts && exts.indexOf('EXT_shader_texture_lod') >= 0) { + return new EXTShaderTextureLod(); + } + return null; +} diff --git a/src/extensions/ext-texture-filter-anisotropic.ts b/src/extensions/ext-texture-filter-anisotropic.ts new file mode 100644 index 00000000..f02fbbd3 --- /dev/null +++ b/src/extensions/ext-texture-filter-anisotropic.ts @@ -0,0 +1,19 @@ +export class EXTTextureFilterAnisotropic { + TEXTURE_MAX_ANISOTROPY_EXT: number; + MAX_TEXTURE_MAX_ANISOTROPY_EXT: number; + + constructor() { + this.TEXTURE_MAX_ANISOTROPY_EXT = 0x84fe; + this.MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84ff; + } +} + +export function getEXTTextureFilterAnisotropic( + context: any, +): EXTTextureFilterAnisotropic | null { + const exts = context.getSupportedExtensions(); + if (exts && exts.indexOf('EXT_texture_filter_anisotropic') >= 0) { + return new EXTTextureFilterAnisotropic(); + } + return null; +} diff --git a/src/extensions/oes-element-index-unit.ts b/src/extensions/oes-element-index-unit.ts new file mode 100644 index 00000000..098575a2 --- /dev/null +++ b/src/extensions/oes-element-index-unit.ts @@ -0,0 +1,11 @@ +export class OESElementIndexUint {} + +export function getOESElementIndexUint( + context: any, +): OESElementIndexUint | null { + const exts = context.getSupportedExtensions(); + if (exts && exts.indexOf('OES_element_index_uint') >= 0) { + return new OESElementIndexUint(); + } + return null; +} diff --git a/src/extensions/oes-standard-derivatives.ts b/src/extensions/oes-standard-derivatives.ts new file mode 100644 index 00000000..84226e64 --- /dev/null +++ b/src/extensions/oes-standard-derivatives.ts @@ -0,0 +1,17 @@ +export class OESStandardDerivatives { + FRAGMENT_SHADER_DERIVATIVE_HINT_OES: number; + + constructor() { + this.FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8b8b; + } +} + +export function getOESStandardDerivatives( + context: any, +): OESStandardDerivatives | null { + const exts = context.getSupportedExtensions(); + if (exts && exts.indexOf('OES_standard_derivatives') >= 0) { + return new OESStandardDerivatives(); + } + return null; +} diff --git a/src/extensions/oes-texture-float-linear.ts b/src/extensions/oes-texture-float-linear.ts new file mode 100644 index 00000000..1aa0a94e --- /dev/null +++ b/src/extensions/oes-texture-float-linear.ts @@ -0,0 +1,11 @@ +export class OESTextureFloatLinear {} + +export function getOESTextureFloatLinear( + context: any, +): OESTextureFloatLinear | null { + const exts = context.getSupportedExtensions(); + if (exts && exts.indexOf('OES_texture_float_linear') >= 0) { + return new OESTextureFloatLinear(); + } + return null; +} diff --git a/src/extensions/oes-texture-float.ts b/src/extensions/oes-texture-float.ts new file mode 100644 index 00000000..2a7004db --- /dev/null +++ b/src/extensions/oes-texture-float.ts @@ -0,0 +1,9 @@ +export class OESTextureFloat {} + +export function getOESTextureFloat(context: any): OESTextureFloat | null { + const exts = context.getSupportedExtensions(); + if (exts && exts.indexOf('OES_texture_float') >= 0) { + return new OESTextureFloat(); + } + return null; +} diff --git a/src/extensions/oes-vertex-array-object.ts b/src/extensions/oes-vertex-array-object.ts new file mode 100644 index 00000000..e6559c4b --- /dev/null +++ b/src/extensions/oes-vertex-array-object.ts @@ -0,0 +1,122 @@ +import { Linkable } from '../linkable'; +import { gl } from '../native-gl'; +import { checkObject } from '../utils'; +import { WebGLVertexArrayObjectState } from '../webgl-vertex-attribute'; + +export class WebGLVertexArrayObjectOES extends Linkable { + _ctx: any; + _ext: OESVertexArrayObject; + _vertexState: WebGLVertexArrayObjectState; + + constructor(_: number, ctx: any, ext: OESVertexArrayObject) { + super(_); + this._ctx = ctx; + this._ext = ext; + this._vertexState = new WebGLVertexArrayObjectState(ctx); + } + + _performDelete(): void { + this._vertexState.cleanUp(); + delete (this as any)._vertexState; + delete this._ext._vaos[this._]; + gl.deleteVertexArrayOES.call(this._ctx, this._ | 0); + } +} + +export class OESVertexArrayObject { + VERTEX_ARRAY_BINDING_OES: number; + _ctx: any; + _vaos: Record; + _activeVertexArrayObject: WebGLVertexArrayObjectOES | null; + + constructor(ctx: any) { + this.VERTEX_ARRAY_BINDING_OES = 0x85b5; + this._ctx = ctx; + this._vaos = {}; + this._activeVertexArrayObject = null; + } + + createVertexArrayOES(): WebGLVertexArrayObjectOES | null { + const { _ctx: ctx } = this; + const arrayId = gl.createVertexArrayOES.call(ctx); + if (arrayId <= 0) return null; + const array = new WebGLVertexArrayObjectOES(arrayId, ctx, this); + this._vaos[arrayId] = array; + return array; + } + + deleteVertexArrayOES(array: WebGLVertexArrayObjectOES | null): void { + const { _ctx: ctx } = this; + if (!checkObject(array)) { + throw new TypeError('deleteVertexArrayOES(WebGLVertexArrayObjectOES)'); + } + if ( + !(array instanceof WebGLVertexArrayObjectOES && ctx._checkOwns(array)) + ) { + ctx.setError(gl.INVALID_OPERATION); + return; + } + if (array._pendingDelete) return; + if (this._activeVertexArrayObject === array) { + this.bindVertexArrayOES(null); + } + array._pendingDelete = true; + array._checkDelete(); + } + + bindVertexArrayOES(array: WebGLVertexArrayObjectOES | null): void { + const { _ctx: ctx, _activeVertexArrayObject: activeVertexArrayObject } = + this; + if (!checkObject(array)) { + throw new TypeError('bindVertexArrayOES(WebGLVertexArrayObjectOES)'); + } + + if (!array) { + array = null; + gl.bindVertexArrayOES.call(ctx, null); + } else if ( + array instanceof WebGLVertexArrayObjectOES && + array._pendingDelete + ) { + ctx.setError(gl.INVALID_OPERATION); + return; + } else if (ctx._checkWrapper(array, WebGLVertexArrayObjectOES)) { + gl.bindVertexArrayOES.call(ctx, array._); + } else { + return; + } + + if (activeVertexArrayObject !== array) { + if (activeVertexArrayObject) { + activeVertexArrayObject._refCount -= 1; + activeVertexArrayObject._checkDelete(); + } + if (array) { + array._refCount += 1; + } + } + + if (array === null) { + ctx._vertexObjectState = ctx._defaultVertexObjectState; + } else { + ctx._vertexObjectState = array._vertexState; + } + + this._activeVertexArrayObject = array; + } + + isVertexArrayOES(object: any): boolean { + const { _ctx: ctx } = this; + if (!ctx._isObject(object, 'isVertexArrayOES', WebGLVertexArrayObjectOES)) + return false; + return gl.isVertexArrayOES.call(ctx, object._ | 0); + } +} + +export function getOESVertexArrayObject(ctx: any): OESVertexArrayObject | null { + const exts = ctx.getSupportedExtensions(); + if (exts && exts.indexOf('OES_vertex_array_object') >= 0) { + return new OESVertexArrayObject(ctx); + } + return null; +} diff --git a/src/extensions/stackgl-destroy-context.ts b/src/extensions/stackgl-destroy-context.ts new file mode 100644 index 00000000..17a41d89 --- /dev/null +++ b/src/extensions/stackgl-destroy-context.ts @@ -0,0 +1,11 @@ +export class STACKGLDestroyContext { + destroy: () => void; + + constructor(ctx: any) { + this.destroy = ctx.destroy.bind(ctx); + } +} + +export function getSTACKGLDestroyContext(ctx: any): STACKGLDestroyContext { + return new STACKGLDestroyContext(ctx); +} diff --git a/src/extensions/stackgl-resize-drawing-buffer.ts b/src/extensions/stackgl-resize-drawing-buffer.ts new file mode 100644 index 00000000..e4c3eaad --- /dev/null +++ b/src/extensions/stackgl-resize-drawing-buffer.ts @@ -0,0 +1,13 @@ +export class STACKGLResizeDrawingBuffer { + resize: (w: number, h: number) => void; + + constructor(ctx: any) { + this.resize = ctx.resize.bind(ctx); + } +} + +export function getSTACKGLResizeDrawingBuffer( + ctx: any, +): STACKGLResizeDrawingBuffer { + return new STACKGLResizeDrawingBuffer(ctx); +} diff --git a/src/extensions/webgl-draw-buffers.ts b/src/extensions/webgl-draw-buffers.ts new file mode 100644 index 00000000..f6f744e5 --- /dev/null +++ b/src/extensions/webgl-draw-buffers.ts @@ -0,0 +1,89 @@ +import { gl } from '../native-gl'; + +export class WebGLDrawBuffers { + ctx: any; + _buffersState: number[]; + _maxDrawBuffers: number; + _ALL_ATTACHMENTS: number[]; + _ALL_COLOR_ATTACHMENTS: number[]; + [key: string]: any; + + constructor(ctx: any) { + this.ctx = ctx; + this._buffersState = []; + this._maxDrawBuffers = 0; + this._ALL_ATTACHMENTS = []; + this._ALL_COLOR_ATTACHMENTS = []; + + const exts = ctx.getSupportedExtensions(); + if (exts && exts.indexOf('WEBGL_draw_buffers') >= 0) { + Object.assign(this, ctx.extWEBGL_draw_buffers()); + this._buffersState = [ctx.BACK]; + this._maxDrawBuffers = ctx._getParameterDirect( + this.MAX_DRAW_BUFFERS_WEBGL, + ); + const allColorAttachments = [ + this.COLOR_ATTACHMENT0_WEBGL, + this.COLOR_ATTACHMENT1_WEBGL, + this.COLOR_ATTACHMENT2_WEBGL, + this.COLOR_ATTACHMENT3_WEBGL, + this.COLOR_ATTACHMENT4_WEBGL, + this.COLOR_ATTACHMENT5_WEBGL, + this.COLOR_ATTACHMENT6_WEBGL, + this.COLOR_ATTACHMENT7_WEBGL, + this.COLOR_ATTACHMENT8_WEBGL, + this.COLOR_ATTACHMENT9_WEBGL, + this.COLOR_ATTACHMENT10_WEBGL, + this.COLOR_ATTACHMENT11_WEBGL, + this.COLOR_ATTACHMENT12_WEBGL, + this.COLOR_ATTACHMENT13_WEBGL, + this.COLOR_ATTACHMENT14_WEBGL, + this.COLOR_ATTACHMENT15_WEBGL, + ]; + while (this._ALL_ATTACHMENTS.length < this._maxDrawBuffers) { + const colorAttachment = allColorAttachments.shift()!; + this._ALL_ATTACHMENTS.push(colorAttachment); + this._ALL_COLOR_ATTACHMENTS.push(colorAttachment); + } + this._ALL_ATTACHMENTS.push( + gl.DEPTH_ATTACHMENT, + gl.STENCIL_ATTACHMENT, + gl.DEPTH_STENCIL_ATTACHMENT, + ); + } + } + + drawBuffersWEBGL(buffers: number[]): void { + const { ctx } = this; + if (buffers.length < 1) { + ctx.setError(gl.INVALID_OPERATION); + return; + } + if (buffers.length === 1 && buffers[0] === gl.BACK) { + this._buffersState = buffers; + ctx.drawBuffersWEBGL([this.COLOR_ATTACHMENT0_WEBGL]); + return; + } else if (!ctx._activeFramebuffers.draw) { + if (buffers.length > 1) { + ctx.setError(gl.INVALID_OPERATION); + return; + } + for (let i = 0; i < buffers.length; i++) { + if (buffers[i] > gl.NONE) { + ctx.setError(gl.INVALID_OPERATION); + return; + } + } + } + this._buffersState = buffers; + ctx.drawBuffersWEBGL(buffers); + } +} + +export function getWebGLDrawBuffers(ctx: any): WebGLDrawBuffers | null { + const exts = ctx.getSupportedExtensions(); + if (exts && exts.indexOf('WEBGL_draw_buffers') >= 0) { + return new WebGLDrawBuffers(ctx); + } + return null; +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..3d68d766 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,8 @@ +import { createContext } from './node-index'; +export { + WebGLRenderingContext, + WebGL2RenderingContext, +} from './webgl-rendering-context'; + +export const createHeadlessGL = createContext; +export { createContext }; diff --git a/src/javascript/browser-index.js b/src/javascript/browser-index.js index c5fb0e11..7329a222 100644 --- a/src/javascript/browser-index.js +++ b/src/javascript/browser-index.js @@ -47,7 +47,8 @@ function createContext (width, height, options) { const _supportedExtensions = gl.getSupportedExtensions().slice() _supportedExtensions.push( 'STACKGL_destroy_context', - 'STACKGL_resize_drawingbuffer') + 'STACKGL_resize_drawingbuffer' + ) gl.getSupportedExtensions = function () { return _supportedExtensions.slice() } diff --git a/src/javascript/extensions/angle-instanced-arrays.js b/src/javascript/extensions/angle-instanced-arrays.js index 08fa43e9..345fd3cc 100644 --- a/src/javascript/extensions/angle-instanced-arrays.js +++ b/src/javascript/extensions/angle-instanced-arrays.js @@ -11,15 +11,15 @@ class ANGLEInstancedArrays { } drawArraysInstancedANGLE (mode, first, count, primCount) { - this._drawArraysInstancedANGLE(mode, first, count, primCount) + this._drawArraysInstancedANGLE(mode | 0, first | 0, count >>> 0, primCount >>> 0) } drawElementsInstancedANGLE (mode, count, type, ioffset, primCount) { - this._drawElementsInstancedANGLE(mode, count, type, ioffset, primCount) + this._drawElementsInstancedANGLE(mode | 0, count | 0, type | 0, ioffset | 0, primCount >>> 0) } vertexAttribDivisorANGLE (index, divisor) { - this._vertexAttribDivisorANGLE(index, divisor) + this._vertexAttribDivisorANGLE(index >>> 0, divisor >>> 0) } } diff --git a/src/javascript/extensions/ext-blend-minmax.js b/src/javascript/extensions/ext-blend-minmax.js index 7b2f64bb..6e9be1fb 100644 --- a/src/javascript/extensions/ext-blend-minmax.js +++ b/src/javascript/extensions/ext-blend-minmax.js @@ -1,19 +1,19 @@ -class EXTBlendMinMax { - constructor () { - this.MIN_EXT = 0x8007 - this.MAX_EXT = 0x8008 - } -} - -function getEXTBlendMinMax (context) { - let result = null - const exts = context.getSupportedExtensions() - - if (exts && exts.indexOf('EXT_blend_minmax') >= 0) { - result = new EXTBlendMinMax() - } - - return result -} - -module.exports = { getEXTBlendMinMax, EXTBlendMinMax } +class EXTBlendMinMax { + constructor () { + this.MIN_EXT = 0x8007 + this.MAX_EXT = 0x8008 + } +} + +function getEXTBlendMinMax (context) { + let result = null + const exts = context.getSupportedExtensions() + + if (exts && exts.indexOf('EXT_blend_minmax') >= 0) { + result = new EXTBlendMinMax() + } + + return result +} + +module.exports = { getEXTBlendMinMax, EXTBlendMinMax } diff --git a/src/javascript/extensions/ext-texture-filter-anisotropic.js b/src/javascript/extensions/ext-texture-filter-anisotropic.js index aa30dd2f..829aabba 100644 --- a/src/javascript/extensions/ext-texture-filter-anisotropic.js +++ b/src/javascript/extensions/ext-texture-filter-anisotropic.js @@ -1,19 +1,22 @@ -class EXTTextureFilterAnisotropic { - constructor () { - this.TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE - this.MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF - } -} - -function getEXTTextureFilterAnisotropic (context) { - let result = null - const exts = context.getSupportedExtensions() - - if (exts && exts.indexOf('EXT_texture_filter_anisotropic') >= 0) { - result = new EXTTextureFilterAnisotropic() - } - - return result -} - -module.exports = { getEXTTextureFilterAnisotropic, EXTTextureFilterAnisotropic } +class EXTTextureFilterAnisotropic { + constructor () { + this.TEXTURE_MAX_ANISOTROPY_EXT = 0x84fe + this.MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84ff + } +} + +function getEXTTextureFilterAnisotropic (context) { + let result = null + const exts = context.getSupportedExtensions() + + if (exts && exts.indexOf('EXT_texture_filter_anisotropic') >= 0) { + result = new EXTTextureFilterAnisotropic() + } + + return result +} + +module.exports = { + getEXTTextureFilterAnisotropic, + EXTTextureFilterAnisotropic +} diff --git a/src/javascript/extensions/oes-standard-derivatives.js b/src/javascript/extensions/oes-standard-derivatives.js index fd0256e1..391eb366 100644 --- a/src/javascript/extensions/oes-standard-derivatives.js +++ b/src/javascript/extensions/oes-standard-derivatives.js @@ -1,6 +1,6 @@ class OESStandardDerivatives { constructor () { - this.FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B + this.FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8b8b } } diff --git a/src/javascript/extensions/oes-vertex-array-object.js b/src/javascript/extensions/oes-vertex-array-object.js index 36b5e96f..a6bbd056 100644 --- a/src/javascript/extensions/oes-vertex-array-object.js +++ b/src/javascript/extensions/oes-vertex-array-object.js @@ -23,7 +23,7 @@ class WebGLVertexArrayObjectOES extends Linkable { class OESVertexArrayObject { constructor (ctx) { - this.VERTEX_ARRAY_BINDING_OES = 0x85B5 + this.VERTEX_ARRAY_BINDING_OES = 0x85b5 this._ctx = ctx this._vaos = {} @@ -45,8 +45,9 @@ class OESVertexArrayObject { throw new TypeError('deleteVertexArrayOES(WebGLVertexArrayObjectOES)') } - if (!(array instanceof WebGLVertexArrayObjectOES && - ctx._checkOwns(array))) { + if ( + !(array instanceof WebGLVertexArrayObjectOES && ctx._checkOwns(array)) + ) { ctx.setError(gl.INVALID_OPERATION) return } @@ -64,16 +65,19 @@ class OESVertexArrayObject { } bindVertexArrayOES (array) { - const { _ctx: ctx, _activeVertexArrayObject: activeVertexArrayObject } = this + const { _ctx: ctx, _activeVertexArrayObject: activeVertexArrayObject } = + this if (!checkObject(array)) { throw new TypeError('bindVertexArrayOES(WebGLVertexArrayObjectOES)') } if (!array) { array = null - gl.bindVertexArrayOES.call(ctx, null) - } else if (array instanceof WebGLVertexArrayObjectOES && - array._pendingDelete) { + gl.bindVertexArrayOES.call(ctx, 0) + } else if ( + array instanceof WebGLVertexArrayObjectOES && + array._pendingDelete + ) { ctx.setError(gl.INVALID_OPERATION) return } else if (ctx._checkWrapper(array, WebGLVertexArrayObjectOES)) { @@ -104,7 +108,7 @@ class OESVertexArrayObject { isVertexArrayOES (object) { const { _ctx: ctx } = this - if (!ctx._isObject(object, 'isVertexArrayOES', WebGLVertexArrayObjectOES)) return false + if (!ctx._isObject(object, 'isVertexArrayOES', WebGLVertexArrayObjectOES)) { return false } return gl.isVertexArrayOES.call(ctx, object._ | 0) } } diff --git a/src/javascript/extensions/webgl-draw-buffers.js b/src/javascript/extensions/webgl-draw-buffers.js index 7f37e0f6..a92b8580 100644 --- a/src/javascript/extensions/webgl-draw-buffers.js +++ b/src/javascript/extensions/webgl-draw-buffers.js @@ -8,7 +8,9 @@ class WebGLDrawBuffers { if (exts && exts.indexOf('WEBGL_draw_buffers') >= 0) { Object.assign(this, ctx.extWEBGL_draw_buffers()) this._buffersState = [ctx.BACK] - this._maxDrawBuffers = ctx._getParameterDirect(this.MAX_DRAW_BUFFERS_WEBGL) + this._maxDrawBuffers = ctx._getParameterDirect( + this.MAX_DRAW_BUFFERS_WEBGL + ) this._ALL_ATTACHMENTS = [] this._ALL_COLOR_ATTACHMENTS = [] const allColorAttachments = [ diff --git a/src/javascript/linkable.js b/src/javascript/linkable.js index a1517110..b3b72bfe 100644 --- a/src/javascript/linkable.js +++ b/src/javascript/linkable.js @@ -33,9 +33,7 @@ class Linkable { } _checkDelete () { - if (this._refCount <= 0 && - this._pendingDelete && - this._ !== 0) { + if (this._refCount <= 0 && this._pendingDelete && this._ !== 0) { while (this._references.length > 0) { this._unlink(this._references[0]) } diff --git a/src/javascript/node-index.js b/src/javascript/node-index.js index 983b4eba..26aef231 100644 --- a/src/javascript/node-index.js +++ b/src/javascript/node-index.js @@ -1,8 +1,15 @@ const bits = require('bit-twiddle') const { WebGLContextAttributes } = require('./webgl-context-attributes') -const { WebGLRenderingContext, WebGL2RenderingContext, wrapContext } = require('./webgl-rendering-context') +const { + WebGLRenderingContext, + WebGL2RenderingContext, + wrapContext +} = require('./webgl-rendering-context') const { WebGLTextureUnit } = require('./webgl-texture-unit') -const { WebGLVertexArrayObjectState, WebGLVertexArrayGlobalState } = require('./webgl-vertex-attribute') +const { + WebGLVertexArrayObjectState, + WebGLVertexArrayGlobalState +} = require('./webgl-vertex-attribute') let CONTEXT_COUNTER = 0 @@ -29,13 +36,16 @@ function createContext (width, height, options) { flag(options, 'preserveDrawingBuffer', false), flag(options, 'preferLowPowerToHighPerformance', false), flag(options, 'failIfMajorPerformanceCaveat', false), - flag(options, 'createWebGL2Context', false)) + flag(options, 'createWebGL2Context', false) + ) // Can only use premultipliedAlpha if alpha is set contextAttributes.premultipliedAlpha = contextAttributes.premultipliedAlpha && contextAttributes.alpha - const WebGLContext = contextAttributes.createWebGL2Context ? WebGL2RenderingContext : WebGLRenderingContext + const WebGLContext = contextAttributes.createWebGL2Context + ? WebGL2RenderingContext + : WebGLRenderingContext let ctx try { ctx = new WebGLContext( @@ -49,7 +59,8 @@ function createContext (width, height, options) { contextAttributes.preserveDrawingBuffer, contextAttributes.preferLowPowerToHighPerformance, contextAttributes.failIfMajorPerformanceCaveat, - contextAttributes.createWebGL2Context) + contextAttributes.createWebGL2Context + ) } catch (e) {} if (!ctx) { return null @@ -129,7 +140,9 @@ function createContext (width, height, options) { ctx.clearDepth(1) ctx.clearColor(0, 0, 0, 0) ctx.clearStencil(0) - ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT) + ctx.clear( + ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT + ) return wrapContext(ctx) } diff --git a/src/javascript/utils.js b/src/javascript/utils.js index 91af5253..e36a9921 100644 --- a/src/javascript/utils.js +++ b/src/javascript/utils.js @@ -8,12 +8,15 @@ function bindPublics (props, wrapper, privateInstance, privateMethods) { const value = privateInstance[prop] if (typeof value === 'function') { if (privateMethods.indexOf(prop) === -1) { - wrapper[prop] = value.bind(privateInstance) + Object.defineProperty(wrapper, prop, { + value: value.bind(privateInstance), + writable: true, + configurable: true, + enumerable: true + }) } } else { - if (prop[0] === '_' || - prop[0] === '0' || - prop[0] === '1') { + if (prop[0] === '_' || prop[0] === '0' || prop[0] === '1') { continue } wrapper[prop] = value @@ -22,18 +25,20 @@ function bindPublics (props, wrapper, privateInstance, privateMethods) { } function checkObject (object) { - return typeof object === 'object' || - (object === undefined) + return typeof object === 'object' || object === undefined } function checkUniform (program, location) { - return location instanceof WebGLUniformLocation && + return ( + location instanceof WebGLUniformLocation && location._program === program && location._linkCount === program._linkCount + ) } function isTypedArray (data) { - return data instanceof Uint8Array || + return ( + data instanceof Uint8Array || data instanceof Uint8ClampedArray || data instanceof Int8Array || data instanceof Uint16Array || @@ -42,13 +47,17 @@ function isTypedArray (data) { data instanceof Int32Array || data instanceof Float32Array || data instanceof Float64Array + ) } // Don't allow: ", $, `, @, \, ', \0 function isValidString (str) { // Remove comments first - const c = str.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '') - return !(/["$`@\\'\0]/.test(c)) + const c = str.replace( + /(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, + '' + ) + return !/["$`@\\'\0]/.test(c) } function vertexCount (primitive, count) { @@ -122,13 +131,18 @@ function uniformTypeSize (type) { } function unpackTypedArray (array) { - return (new Uint8Array(array.buffer)).subarray( + return new Uint8Array(array.buffer).subarray( array.byteOffset, - array.byteLength + array.byteOffset) + array.byteLength + array.byteOffset + ) } function extractImageData (pixels) { - if (typeof pixels === 'object' && typeof pixels.width !== 'undefined' && typeof pixels.height !== 'undefined') { + if ( + typeof pixels === 'object' && + typeof pixels.width !== 'undefined' && + typeof pixels.height !== 'undefined' + ) { if (typeof pixels.data !== 'undefined') { return pixels } @@ -137,10 +151,17 @@ function extractImageData (pixels) { if (typeof pixels.getContext === 'function') { context = pixels.getContext('2d') - } else if (typeof pixels.src !== 'undefined' && typeof document === 'object' && typeof document.createElement === 'function') { + } else if ( + typeof pixels.src !== 'undefined' && + typeof document === 'object' && + typeof document.createElement === 'function' + ) { const canvas = document.createElement('canvas') - if (typeof canvas === 'object' && typeof canvas.getContext === 'function') { + if ( + typeof canvas === 'object' && + typeof canvas.getContext === 'function' + ) { canvas.width = pixels.width canvas.height = pixels.height context = canvas.getContext('2d') @@ -178,10 +199,12 @@ function convertPixels (pixels) { if (typeof pixels === 'object' && pixels !== null) { if (pixels instanceof ArrayBuffer) { return new Uint8Array(pixels) - } else if (pixels instanceof Uint8Array || + } else if ( + pixels instanceof Uint8Array || pixels instanceof Uint16Array || pixels instanceof Uint8ClampedArray || - pixels instanceof Float32Array) { + pixels instanceof Float32Array + ) { return unpackTypedArray(pixels) } else if (pixels instanceof Buffer) { return new Uint8Array(pixels) @@ -196,16 +219,19 @@ function checkFormat (format) { format === gl.LUMINANCE_ALPHA || format === gl.LUMINANCE || format === gl.RGB || - format === gl.RGBA) + format === gl.RGBA + ) } function validCubeTarget (target) { - return target === gl.TEXTURE_CUBE_MAP_POSITIVE_X || + return ( + target === gl.TEXTURE_CUBE_MAP_POSITIVE_X || target === gl.TEXTURE_CUBE_MAP_NEGATIVE_X || target === gl.TEXTURE_CUBE_MAP_POSITIVE_Y || target === gl.TEXTURE_CUBE_MAP_NEGATIVE_Y || target === gl.TEXTURE_CUBE_MAP_POSITIVE_Z || target === gl.TEXTURE_CUBE_MAP_NEGATIVE_Z + ) } module.exports = { diff --git a/src/javascript/webgl-context-attributes.js b/src/javascript/webgl-context-attributes.js index 69bfc1cb..70d02adc 100644 --- a/src/javascript/webgl-context-attributes.js +++ b/src/javascript/webgl-context-attributes.js @@ -8,7 +8,8 @@ class WebGLContextAttributes { preserveDrawingBuffer, preferLowPowerToHighPerformance, failIfMajorPerformanceCaveat, - createWebGL2Context) { + createWebGL2Context + ) { this.alpha = alpha this.depth = depth this.stencil = stencil diff --git a/src/javascript/webgl-rendering-context.js b/src/javascript/webgl-rendering-context.js index aceb321e..6c69a4c7 100644 --- a/src/javascript/webgl-rendering-context.js +++ b/src/javascript/webgl-rendering-context.js @@ -1,17 +1,35 @@ const HEADLESS_VERSION = require('../../package.json').version const { gl, NativeWebGLRenderingContext, NativeWebGL } = require('./native-gl') -const { getANGLEInstancedArrays } = require('./extensions/angle-instanced-arrays') -const { getOESElementIndexUint } = require('./extensions/oes-element-index-unit') -const { getOESStandardDerivatives } = require('./extensions/oes-standard-derivatives') +const { + getANGLEInstancedArrays +} = require('./extensions/angle-instanced-arrays') +const { + getOESElementIndexUint +} = require('./extensions/oes-element-index-unit') +const { + getOESStandardDerivatives +} = require('./extensions/oes-standard-derivatives') const { getOESTextureFloat } = require('./extensions/oes-texture-float') -const { getOESTextureFloatLinear } = require('./extensions/oes-texture-float-linear') -const { getSTACKGLDestroyContext } = require('./extensions/stackgl-destroy-context') -const { getSTACKGLResizeDrawingBuffer } = require('./extensions/stackgl-resize-drawing-buffer') +const { + getOESTextureFloatLinear +} = require('./extensions/oes-texture-float-linear') +const { + getSTACKGLDestroyContext +} = require('./extensions/stackgl-destroy-context') +const { + getSTACKGLResizeDrawingBuffer +} = require('./extensions/stackgl-resize-drawing-buffer') const { getWebGLDrawBuffers } = require('./extensions/webgl-draw-buffers') const { getEXTBlendMinMax } = require('./extensions/ext-blend-minmax') -const { getEXTTextureFilterAnisotropic } = require('./extensions/ext-texture-filter-anisotropic') -const { getEXTShaderTextureLod } = require('./extensions/ext-shader-texture-lod') -const { getOESVertexArrayObject } = require('./extensions/oes-vertex-array-object') +const { + getEXTTextureFilterAnisotropic +} = require('./extensions/ext-texture-filter-anisotropic') +const { + getEXTShaderTextureLod +} = require('./extensions/ext-shader-texture-lod') +const { + getOESVertexArrayObject +} = require('./extensions/oes-vertex-array-object') const { bindPublics, checkObject, @@ -33,11 +51,15 @@ const { WebGLDrawingBufferWrapper } = require('./webgl-drawing-buffer-wrapper') const { WebGLProgram } = require('./webgl-program') const { WebGLRenderbuffer } = require('./webgl-renderbuffer') const { WebGLShader } = require('./webgl-shader') -const { WebGLShaderPrecisionFormat } = require('./webgl-shader-precision-format') +const { + WebGLShaderPrecisionFormat +} = require('./webgl-shader-precision-format') const { WebGLTexture } = require('./webgl-texture') const { WebGLUniformLocation } = require('./webgl-uniform-location') const { WebGLVertexArrayObject } = require('./webgl-vertex-array-object') -const { getEXTColorBufferFloat } = require('./extensions/ext-color-buffer-float') +const { + getEXTColorBufferFloat +} = require('./extensions/ext-color-buffer-float') // These are defined by the WebGL spec const MAX_UNIFORM_LENGTH = 256 @@ -68,33 +90,66 @@ const availableExtensions = { ext_color_buffer_float: getEXTColorBufferFloat } -const privateMethods = [ - 'constructor', - 'resize', - 'destroy' -] +const privateMethods = ['constructor', 'resize', 'destroy'] function wrapContext (ctx) { const isWebGL2 = ctx.constructor.name === 'WebGL2RenderingContext' - const wrapper = isWebGL2 ? new WebGL2RenderingContext() : new WebGLRenderingContext() + const wrapper = isWebGL2 + ? new WebGL2RenderingContext() + : new WebGLRenderingContext() let proto = ctx while (proto && proto !== Object.prototype) { bindPublics(Object.keys(proto), wrapper, ctx, privateMethods) - bindPublics(Object.keys(proto.constructor.prototype), wrapper, ctx, privateMethods) - bindPublics(Object.getOwnPropertyNames(proto), wrapper, ctx, privateMethods) - bindPublics(Object.getOwnPropertyNames(proto.constructor.prototype), wrapper, ctx, privateMethods) + bindPublics( + Object.keys(proto.constructor.prototype), + wrapper, + ctx, + privateMethods + ) + bindPublics( + Object.getOwnPropertyNames(proto), + wrapper, + ctx, + privateMethods + ) + bindPublics( + Object.getOwnPropertyNames(proto.constructor.prototype), + wrapper, + ctx, + privateMethods + ) proto = Object.getPrototypeOf(proto) } Object.defineProperties(wrapper, { drawingBufferWidth: { - get () { return ctx.drawingBufferWidth }, - set (value) { ctx.drawingBufferWidth = value } + get () { + return ctx.drawingBufferWidth + }, + set (value) { + ctx.drawingBufferWidth = value + } }, drawingBufferHeight: { - get () { return ctx.drawingBufferHeight }, - set (value) { ctx.drawingBufferHeight = value } + get () { + return ctx.drawingBufferHeight + }, + set (value) { + ctx.drawingBufferHeight = value + } + }, + destroy: { + value: ctx.destroy.bind(ctx), + writable: true, + configurable: true, + enumerable: false + }, + resize: { + value: ctx.resize.bind(ctx), + writable: true, + configurable: true, + enumerable: false } }) @@ -107,8 +162,10 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { if (!(location instanceof WebGLUniformLocation)) { this.setError(this.INVALID_VALUE) return false - } else if (location._program._ctx !== this || - location._linkCount !== location._program._linkCount) { + } else if ( + location._program._ctx !== this || + location._linkCount !== location._program._linkCount + ) { this.setError(this.INVALID_OPERATION) return false } @@ -128,8 +185,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } _checkOwns (object) { - return typeof object === 'object' && - object._ctx === this + return typeof object === 'object' && object._ctx === this } _checkShaderSource (shader) { @@ -188,7 +244,10 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } // Record attribute attributeLocations - const numAttribs = this.getProgramParameter(program, this.ACTIVE_ATTRIBUTES) + const numAttribs = this.getProgramParameter( + program, + this.ACTIVE_ATTRIBUTES + ) const names = new Array(numAttribs) program._attributes.length = numAttribs for (let i = 0; i < numAttribs; ++i) { @@ -205,10 +264,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } for (let i = 0; i < numAttribs; ++i) { - super.bindAttribLocation( - program._ | 0, - program._attributes[i], - names[i]) + super.bindAttribLocation(program._ | 0, program._attributes[i], names[i]) } super.linkProgram(program._ | 0) @@ -222,7 +278,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { // Check attribute and uniform name lengths for (let i = 0; i < program._uniforms.length; ++i) { if (program._uniforms[i].name.length > MAX_UNIFORM_LENGTH) { - program._linkInfoLog = 'uniform ' + program._uniforms[i].name + ' is too long' + program._linkInfoLog = + 'uniform ' + program._uniforms[i].name + ' is too long' return false } } @@ -271,11 +328,15 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } _getAttachments () { - return this._extensions.webgl_draw_buffers ? this._extensions.webgl_draw_buffers._ALL_ATTACHMENTS : DEFAULT_ATTACHMENTS + return this._extensions.webgl_draw_buffers + ? this._extensions.webgl_draw_buffers._ALL_ATTACHMENTS + : DEFAULT_ATTACHMENTS } _getColorAttachments () { - return this._extensions.webgl_draw_buffers ? this._extensions.webgl_draw_buffers._ALL_COLOR_ATTACHMENTS : DEFAULT_COLOR_ATTACHMENTS + return this._extensions.webgl_draw_buffers + ? this._extensions.webgl_draw_buffers._ALL_COLOR_ATTACHMENTS + : DEFAULT_COLOR_ATTACHMENTS } _getParameterDirect (pname) { @@ -295,21 +356,21 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { _isConstantColorBlendFunc (factor) { return ( - factor === this.CONSTANT_COLOR || - factor === this.ONE_MINUS_CONSTANT_COLOR + factor === this.CONSTANT_COLOR || factor === this.ONE_MINUS_CONSTANT_COLOR ) } _isConstantAlphaBlendFunc (factor) { return ( - factor === this.CONSTANT_ALPHA || - factor === this.ONE_MINUS_CONSTANT_ALPHA + factor === this.CONSTANT_ALPHA || factor === this.ONE_MINUS_CONSTANT_ALPHA ) } _isObject (object, method, Wrapper) { - if (!(object === null || object === undefined) && - !(object instanceof Wrapper)) { + if ( + !(object === null || object === undefined) && + !(object instanceof Wrapper) + ) { throw new TypeError(method + '(' + Wrapper.name + ')') } if (this._checkValid(object, Wrapper) && this._checkOwns(object)) { @@ -335,7 +396,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { attachments[i], this.TEXTURE_2D, 0, - 0) + 0 + ) } // Update color attachment @@ -350,7 +412,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { 0, colorFormat, this.UNSIGNED_BYTE, - null) + null + ) super.texParameteri(this.TEXTURE_2D, this.TEXTURE_MIN_FILTER, this.NEAREST) super.texParameteri(this.TEXTURE_2D, this.TEXTURE_MAG_FILTER, this.NEAREST) super.framebufferTexture2D( @@ -358,7 +421,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { this.COLOR_ATTACHMENT0, this.TEXTURE_2D, drawingBuffer._color, - 0) + 0 + ) // Update depth-stencil attachments if needed let storage = 0 @@ -367,7 +431,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { storage = this.DEPTH_STENCIL attachment = this.DEPTH_STENCIL_ATTACHMENT } else if (contextAttributes.depth) { - storage = 0x81A7 + storage = 0x81a7 attachment = this.DEPTH_ATTACHMENT } else if (contextAttributes.stencil) { storage = this.STENCIL_INDEX8 @@ -375,19 +439,14 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } if (storage) { - super.bindRenderbuffer( - this.RENDERBUFFER, - drawingBuffer._depthStencil) - super.renderbufferStorage( - this.RENDERBUFFER, - storage, - width, - height) + super.bindRenderbuffer(this.RENDERBUFFER, drawingBuffer._depthStencil) + super.renderbufferStorage(this.RENDERBUFFER, storage, width, height) super.framebufferRenderbuffer( this.FRAMEBUFFER, attachment, this.RENDERBUFFER, - drawingBuffer._depthStencil) + drawingBuffer._depthStencil + ) } // Restore previous binding state @@ -417,7 +476,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } _validBlendFunc (factor) { - return factor === this.ZERO || + return ( + factor === this.ZERO || factor === this.ONE || factor === this.SRC_COLOR || factor === this.ONE_MINUS_SRC_COLOR || @@ -432,24 +492,29 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { factor === this.ONE_MINUS_CONSTANT_COLOR || factor === this.CONSTANT_ALPHA || factor === this.ONE_MINUS_CONSTANT_ALPHA + ) } _validBlendMode (mode) { - return mode === this.FUNC_ADD || + return ( + mode === this.FUNC_ADD || mode === this.FUNC_SUBTRACT || mode === this.FUNC_REVERSE_SUBTRACT || - (this._extensions.ext_blend_minmax && ( - mode === this._extensions.ext_blend_minmax.MIN_EXT || - mode === this._extensions.ext_blend_minmax.MAX_EXT)) + (this._extensions.ext_blend_minmax && + (mode === this._extensions.ext_blend_minmax.MIN_EXT || + mode === this._extensions.ext_blend_minmax.MAX_EXT)) + ) } _validCubeTarget (target) { - return target === this.TEXTURE_CUBE_MAP_POSITIVE_X || + return ( + target === this.TEXTURE_CUBE_MAP_POSITIVE_X || target === this.TEXTURE_CUBE_MAP_NEGATIVE_X || target === this.TEXTURE_CUBE_MAP_POSITIVE_Y || target === this.TEXTURE_CUBE_MAP_NEGATIVE_Y || target === this.TEXTURE_CUBE_MAP_POSITIVE_Z || target === this.TEXTURE_CUBE_MAP_NEGATIVE_Z + ) } _validFramebufferAttachment (attachment) { @@ -461,23 +526,29 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { return true } - if (this._extensions.webgl_draw_buffers) { // eslint-disable-line - const { webgl_draw_buffers } = this._extensions; // eslint-disable-line - return attachment < (webgl_draw_buffers.COLOR_ATTACHMENT0_WEBGL + webgl_draw_buffers._maxDrawBuffers) // eslint-disable-line + if (this._extensions.webgl_draw_buffers) { + // eslint-disable-line + const webglDrawBuffers = this._extensions.webgl_draw_buffers // eslint-disable-line + return ( + attachment < + webglDrawBuffers.COLOR_ATTACHMENT0_WEBGL + + webglDrawBuffers._maxDrawBuffers + ) // eslint-disable-line } return false } _validGLSLIdentifier (str) { - return !(str.indexOf('webgl_') === 0 || + return !( + str.indexOf('webgl_') === 0 || str.indexOf('_webgl_') === 0 || - str.length > 256) + str.length > 256 + ) } _validTextureTarget (target) { - return target === this.TEXTURE_2D || - target === this.TEXTURE_CUBE_MAP + return target === this.TEXTURE_2D || target === this.TEXTURE_CUBE_MAP } _verifyTextureCompleteness (target, pname, param) { @@ -490,7 +561,18 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } // oes_texture_float but not oes_texture_float_linear - if (this._extensions.oes_texture_float && !this._extensions.oes_texture_float_linear && texture && texture._type === this.FLOAT && (pname === this.TEXTURE_MAG_FILTER || pname === this.TEXTURE_MIN_FILTER) && (param === this.LINEAR || param === this.LINEAR_MIPMAP_NEAREST || param === this.NEAREST_MIPMAP_LINEAR || param === this.LINEAR_MIPMAP_LINEAR)) { + if ( + this._extensions.oes_texture_float && + !this._extensions.oes_texture_float_linear && + texture && + texture._type === this.FLOAT && + (pname === this.TEXTURE_MAG_FILTER || + pname === this.TEXTURE_MIN_FILTER) && + (param === this.LINEAR || + param === this.LINEAR_MIPMAP_NEAREST || + param === this.NEAREST_MIPMAP_LINEAR || + param === this.LINEAR_MIPMAP_LINEAR) + ) { texture._complete = false this.bindTexture(target, texture) return @@ -518,22 +600,21 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } attachShader (program, shader) { - if (!checkObject(program) || - !checkObject(shader)) { + if (!checkObject(program) || !checkObject(shader)) { throw new TypeError('attachShader(WebGLProgram, WebGLShader)') } if (!program || !shader) { this.setError(this.INVALID_VALUE) return - } else if (program instanceof WebGLProgram && + } else if ( + program instanceof WebGLProgram && shader instanceof WebGLShader && this._checkOwns(program) && - this._checkOwns(shader)) { + this._checkOwns(shader) + ) { if (!program._linked(shader)) { this._saveError() - super.attachShader( - program._ | 0, - shader._ | 0) + super.attachShader(program._ | 0, shader._ | 0) const error = this.getError() this._restoreError(error) if (error === this.NO_ERROR) { @@ -546,8 +627,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } bindAttribLocation (program, index, name) { - if (!checkObject(program) || - typeof name !== 'string') { + if (!checkObject(program) || typeof name !== 'string') { throw new TypeError('bindAttribLocation(WebGLProgram, GLint, String)') } name += '' @@ -556,10 +636,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } else if (/^_?webgl_a/.test(name)) { this.setError(this.INVALID_OPERATION) } else if (this._checkWrapper(program, WebGLProgram)) { - return super.bindAttribLocation( - program._ | 0, - index | 0, - name) + return super.bindAttribLocation(program._ | 0, index | 0, name) } } @@ -570,18 +647,14 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { let error = 0 if (!framebuffer) { this._saveError() - super.bindFramebuffer( - target, - this._drawingBuffer._framebuffer) + super.bindFramebuffer(target, this._drawingBuffer._framebuffer) error = super.getError() this._restoreError(error) } else if (framebuffer._pendingDelete) { return } else if (this._checkWrapper(framebuffer, WebGLFramebuffer)) { this._saveError() - super.bindFramebuffer( - target, - framebuffer._ | 0) + super.bindFramebuffer(target, framebuffer._ | 0) error = super.getError() this._restoreError(error) } else { @@ -603,8 +676,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { if (!checkObject(buffer)) { throw new TypeError('bindBuffer(GLenum, WebGLBuffer)') } - if (target !== this.ARRAY_BUFFER && - target !== this.ELEMENT_ARRAY_BUFFER) { + if (target !== this.ARRAY_BUFFER && target !== this.ELEMENT_ARRAY_BUFFER) { this.setError(this.INVALID_ENUM) return } @@ -646,15 +718,11 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } if (!object) { - super.bindRenderbuffer( - target | 0, - 0) + super.bindRenderbuffer(target | 0, 0) } else if (object._pendingDelete) { return } else if (this._checkWrapper(object, WebGLRenderbuffer)) { - super.bindRenderbuffer( - target | 0, - object._ | 0) + super.bindRenderbuffer(target | 0, object._ | 0) } else { return } @@ -682,8 +750,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { let textureId = 0 if (!texture) { texture = null - } else if (texture instanceof WebGLTexture && - texture._pendingDelete) { + } else if (texture instanceof WebGLTexture && texture._pendingDelete) { // Special case: error codes for deleted textures don't get set for some dumb reason return } else if (this._checkWrapper(texture, WebGLTexture)) { @@ -694,9 +761,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } this._saveError() - super.bindTexture( - target, - textureId) + super.bindTexture(target, textureId) const error = this.getError() this._restoreError(error) @@ -737,8 +802,10 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { if (!array) { array = null super.bindVertexArray(null) - } else if (array instanceof WebGLVertexArrayObject && - array._pendingDelete) { + } else if ( + array instanceof WebGLVertexArrayObject && + array._pendingDelete + ) { this.setError(gl.INVALID_OPERATION) return } else if (this._checkWrapper(array, WebGLVertexArrayObject)) { @@ -869,62 +936,66 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { blendFunc (sfactor, dfactor) { sfactor |= 0 dfactor |= 0 - if (!this._validBlendFunc(sfactor) || - !this._validBlendFunc(dfactor)) { + if (!this._validBlendFunc(sfactor) || !this._validBlendFunc(dfactor)) { this.setError(this.INVALID_ENUM) return } - if ((this._isConstantColorBlendFunc(sfactor) && this._isConstantAlphaBlendFunc(dfactor)) || - (this._isConstantColorBlendFunc(dfactor) && this._isConstantAlphaBlendFunc(sfactor))) { + if ( + (this._isConstantColorBlendFunc(sfactor) && + this._isConstantAlphaBlendFunc(dfactor)) || + (this._isConstantColorBlendFunc(dfactor) && + this._isConstantAlphaBlendFunc(sfactor)) + ) { this.setError(this.INVALID_OPERATION) return } super.blendFunc(sfactor, dfactor) } - blendFuncSeparate ( - srcRGB, - dstRGB, - srcAlpha, - dstAlpha) { + blendFuncSeparate (srcRGB, dstRGB, srcAlpha, dstAlpha) { srcRGB |= 0 dstRGB |= 0 srcAlpha |= 0 dstAlpha |= 0 - if (!(this._validBlendFunc(srcRGB) && - this._validBlendFunc(dstRGB) && - this._validBlendFunc(srcAlpha) && - this._validBlendFunc(dstAlpha))) { + if ( + !( + this._validBlendFunc(srcRGB) && + this._validBlendFunc(dstRGB) && + this._validBlendFunc(srcAlpha) && + this._validBlendFunc(dstAlpha) + ) + ) { this.setError(this.INVALID_ENUM) return } - if ((this._isConstantColorBlendFunc(srcRGB) && this._isConstantAlphaBlendFunc(dstRGB)) || - (this._isConstantColorBlendFunc(dstRGB) && this._isConstantAlphaBlendFunc(srcRGB))) { + if ( + (this._isConstantColorBlendFunc(srcRGB) && + this._isConstantAlphaBlendFunc(dstRGB)) || + (this._isConstantColorBlendFunc(dstRGB) && + this._isConstantAlphaBlendFunc(srcRGB)) + ) { this.setError(this.INVALID_OPERATION) return } - super.blendFuncSeparate( - srcRGB, - dstRGB, - srcAlpha, - dstAlpha) + super.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) } bufferData (target, data, usage) { target |= 0 usage |= 0 - if (usage !== this.STREAM_DRAW && + if ( + usage !== this.STREAM_DRAW && usage !== this.STATIC_DRAW && - usage !== this.DYNAMIC_DRAW) { + usage !== this.DYNAMIC_DRAW + ) { this.setError(this.INVALID_ENUM) return } - if (target !== this.ARRAY_BUFFER && - target !== this.ELEMENT_ARRAY_BUFFER) { + if (target !== this.ARRAY_BUFFER && target !== this.ELEMENT_ARRAY_BUFFER) { this.setError(this.INVALID_ENUM) return } @@ -947,10 +1018,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } this._saveError() - super.bufferData( - target, - u8Data, - usage) + super.bufferData(target, u8Data, usage) const error = this.getError() this._restoreError(error) if (error !== this.NO_ERROR) { @@ -969,10 +1037,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } this._saveError() - super.bufferData( - target, - size, - usage) + super.bufferData(target, size, usage) const error = this.getError() this._restoreError(error) if (error !== this.NO_ERROR) { @@ -992,8 +1057,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { target |= 0 offset |= 0 - if (target !== this.ARRAY_BUFFER && - target !== this.ELEMENT_ARRAY_BUFFER) { + if (target !== this.ARRAY_BUFFER && target !== this.ELEMENT_ARRAY_BUFFER) { this.setError(this.INVALID_ENUM) return } @@ -1037,10 +1101,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { active._elements.set(u8Data, offset) } - super.bufferSubData( - target, - offset, - u8Data) + super.bufferSubData(target, offset, u8Data) } checkFramebufferStatus (target) { @@ -1075,26 +1136,24 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { if (!checkObject(shader)) { throw new TypeError('compileShader(WebGLShader)') } - if (this._checkWrapper(shader, WebGLShader) && - this._checkShaderSource(shader)) { + if ( + this._checkWrapper(shader, WebGLShader) && + this._checkShaderSource(shader) + ) { const prevError = this.getError() super.compileShader(shader._ | 0) const error = this.getError() shader._compileStatus = !!super.getShaderParameter( shader._ | 0, - this.COMPILE_STATUS) + this.COMPILE_STATUS + ) shader._compileInfo = super.getShaderInfoLog(shader._ | 0) this.getError() this.setError(prevError || error) } } - copyTexImage2D ( - target, - level, - internalFormat, - x, y, width, height, - border) { + copyTexImage2D (target, level, internalFormat, x, y, width, height, border) { target |= 0 level |= 0 internalFormat |= 0 @@ -1113,7 +1172,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { y, width, height, - border) + border + ) const error = this.getError() this._restoreError(error) @@ -1124,11 +1184,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } } - copyTexSubImage2D ( - target, - level, - xoffset, yoffset, - x, y, width, height) { + copyTexSubImage2D (target, level, xoffset, yoffset, x, y, width, height) { target |= 0 level |= 0 xoffset |= 0 @@ -1146,7 +1202,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { x, y, width, - height) + height + ) } cullFace (mode) { @@ -1155,8 +1212,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { createShader (type) { type |= 0 - if (type !== this.FRAGMENT_SHADER && - type !== this.VERTEX_SHADER) { + if (type !== this.FRAGMENT_SHADER && type !== this.VERTEX_SHADER) { this.setError(this.INVALID_ENUM) return null } @@ -1181,8 +1237,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { if (!checkObject(object)) { throw new TypeError(name + '(' + Type.name + ')') } - if (object instanceof Type && - this._checkOwns(object)) { + if (object instanceof Type && this._checkOwns(object)) { object._pendingDelete = true object._checkDelete() return @@ -1193,13 +1248,14 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } deleteBuffer (buffer) { - if (!checkObject(buffer) || - (buffer !== null && !(buffer instanceof WebGLBuffer))) { + if ( + !checkObject(buffer) || + (buffer !== null && !(buffer instanceof WebGLBuffer)) + ) { throw new TypeError('deleteBuffer(WebGLBuffer)') } - if (!(buffer instanceof WebGLBuffer && - this._checkOwns(buffer))) { + if (!(buffer instanceof WebGLBuffer && this._checkOwns(buffer))) { this.setError(this.INVALID_OPERATION) return } @@ -1226,13 +1282,17 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { throw new TypeError('deleteFramebuffer(WebGLFramebuffer)') } - if (!(framebuffer instanceof WebGLFramebuffer && - this._checkOwns(framebuffer))) { + if ( + !(framebuffer instanceof WebGLFramebuffer && this._checkOwns(framebuffer)) + ) { this.setError(this.INVALID_OPERATION) return } - if (this._activeFramebuffers.draw === framebuffer && this._activeFramebuffers.read === framebuffer) { + if ( + this._activeFramebuffers.draw === framebuffer && + this._activeFramebuffers.read === framebuffer + ) { this.bindFramebuffer(this.FRAMEBUFFER, null) } else if (this._isWebGL2()) { if (this._activeFramebuffers.read === framebuffer) { @@ -1262,8 +1322,12 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { throw new TypeError('deleteRenderbuffer(WebGLRenderbuffer)') } - if (!(renderbuffer instanceof WebGLRenderbuffer && - this._checkOwns(renderbuffer))) { + if ( + !( + renderbuffer instanceof WebGLRenderbuffer && + this._checkOwns(renderbuffer) + ) + ) { this.setError(this.INVALID_OPERATION) return } @@ -1321,8 +1385,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { throw new TypeError('deleteVertexArray(WebGLVertexArrayObject)') } - if (!(array instanceof WebGLVertexArrayObject && - this._checkOwns(array))) { + if (!(array instanceof WebGLVertexArrayObject && this._checkOwns(array))) { this.setError(gl.INVALID_OPERATION) return } @@ -1374,12 +1437,13 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } detachShader (program, shader) { - if (!checkObject(program) || - !checkObject(shader)) { + if (!checkObject(program) || !checkObject(shader)) { throw new TypeError('detachShader(WebGLProgram, WebGLShader)') } - if (this._checkWrapper(program, WebGLProgram) && - this._checkWrapper(shader, WebGLShader)) { + if ( + this._checkWrapper(program, WebGLProgram) && + this._checkWrapper(shader, WebGLShader) + ) { if (program._linked(shader)) { super.detachShader(program._, shader._) program._unlink(shader) @@ -1392,8 +1456,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { disable (cap) { cap |= 0 super.disable(cap) - if (cap === this.TEXTURE_2D || - cap === this.TEXTURE_CUBE_MAP) { + if (cap === this.TEXTURE_2D || cap === this.TEXTURE_CUBE_MAP) { const active = this._getActiveTextureUnit() if (active._mode === cap) { active._mode = 0 @@ -1457,13 +1520,16 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { target, attachment, renderbufferTarget, - renderbuffer) { + renderbuffer + ) { target = target | 0 attachment = attachment | 0 renderbufferTarget = renderbufferTarget | 0 if (!checkObject(renderbuffer)) { - throw new TypeError('framebufferRenderbuffer(GLenum, GLenum, GLenum, WebGLRenderbuffer)') + throw new TypeError( + 'framebufferRenderbuffer(GLenum, GLenum, GLenum, WebGLRenderbuffer)' + ) } // Since we emulate the default framebuffer, we can't rely on ANGLE's validation. @@ -1476,21 +1542,23 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { return } - super.framebufferRenderbuffer(target, attachment, renderbufferTarget, renderbuffer?._ ?? null) + super.framebufferRenderbuffer( + target, + attachment, + renderbufferTarget, + renderbuffer?._ ?? 0 + ) } - framebufferTexture2D ( - target, - attachment, - textarget, - texture, - level) { + framebufferTexture2D (target, attachment, textarget, texture, level) { target |= 0 attachment |= 0 textarget |= 0 level |= 0 if (!checkObject(texture)) { - throw new TypeError('framebufferTexture2D(GLenum, GLenum, GLenum, WebGLTexture, GLint)') + throw new TypeError( + 'framebufferTexture2D(GLenum, GLenum, GLenum, WebGLTexture, GLint)' + ) } // Check object ownership @@ -1504,7 +1572,13 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { return } - super.framebufferTexture2D(target, attachment, textarget, texture?._ ?? null, level) + super.framebufferTexture2D( + target, + attachment, + textarget, + texture?._ ?? 0, + level + ) } framebufferTextureLayer (target, attachment, texture, level, layer) { @@ -1513,7 +1587,9 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { level |= 0 layer |= 0 if (!checkObject(texture)) { - throw new TypeError('framebufferTextureLayer(GLenum, GLenum, WebGLTexture, GLint, GLint)') + throw new TypeError( + 'framebufferTextureLayer(GLenum, GLenum, WebGLTexture, GLint, GLint)' + ) } // Check object ownership @@ -1527,7 +1603,13 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { return } - super.framebufferTextureLayer(target, attachment, texture?._ ?? null, level, layer) + super.framebufferTextureLayer( + target, + attachment, + texture?._ ?? 0, + level, + layer + ) } frontFace (mode) { @@ -1567,10 +1649,12 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } getAttachedShaders (program) { - if (!checkObject(program) || + if ( + !checkObject(program) || (typeof program === 'object' && program !== null && - !(program instanceof WebGLProgram))) { + !(program instanceof WebGLProgram)) + ) { throw new TypeError('getAttachedShaders(WebGLProgram)') } if (!program) { @@ -1603,6 +1687,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } getParameter (pname) { + if (typeof pname !== 'number' && isNaN(+pname)) return null + pname = pname | 0 switch (pname) { case this.COMPRESSED_TEXTURE_FORMATS: return new Uint32Array(0) @@ -1633,28 +1719,36 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { default: if (this._extensions) { - if (this._extensions.oes_vertex_array_object && pname === this._extensions.oes_vertex_array_object.VERTEX_ARRAY_BINDING_OES) { - return this._extensions.oes_vertex_array_object._activeVertexArrayObject + if ( + this._extensions.oes_vertex_array_object && + pname === + this._extensions.oes_vertex_array_object.VERTEX_ARRAY_BINDING_OES + ) { + return this._extensions.oes_vertex_array_object + ._activeVertexArrayObject } } return super.getParameter(pname) } } - getShaderPrecisionFormat ( - shaderType, - precisionType) { + getShaderPrecisionFormat (shaderType, precisionType) { shaderType |= 0 precisionType |= 0 - if (!(shaderType === this.FRAGMENT_SHADER || - shaderType === this.VERTEX_SHADER) || - !(precisionType === this.LOW_FLOAT || + if ( + !( + shaderType === this.FRAGMENT_SHADER || shaderType === this.VERTEX_SHADER + ) || + !( + precisionType === this.LOW_FLOAT || precisionType === this.MEDIUM_FLOAT || precisionType === this.HIGH_FLOAT || precisionType === this.LOW_INT || precisionType === this.MEDIUM_INT || - precisionType === this.HIGH_INT)) { + precisionType === this.HIGH_INT + ) + ) { this.setError(this.INVALID_ENUM) return } @@ -1670,8 +1764,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { getBufferParameter (target, pname) { target |= 0 pname |= 0 - if (target !== this.ARRAY_BUFFER && - target !== this.ELEMENT_ARRAY_BUFFER) { + if (target !== this.ARRAY_BUFFER && target !== this.ELEMENT_ARRAY_BUFFER) { this.setError(this.INVALID_ENUM) return null } @@ -1702,7 +1795,11 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } this._saveError() - const result = super.getFramebufferAttachmentParameter(target, attachment, pname) + const result = super.getFramebufferAttachmentParameter( + target, + attachment, + pname + ) const error = super.getError() this._restoreError(error) @@ -1710,8 +1807,15 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { return null } - if (error === this.NO_ERROR && pname === this.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) { - const type = super.getFramebufferAttachmentParameter(target, attachment, this.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) + if ( + error === this.NO_ERROR && + pname === this.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME + ) { + const type = super.getFramebufferAttachmentParameter( + target, + attachment, + this.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE + ) if (type === this.RENDERBUFFER) { return this._renderbuffers[result] } else { @@ -1833,8 +1937,10 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } const unit = this._getActiveTextureUnit() - if ((target === this.TEXTURE_2D && !unit._bind2D) || - (target === this.TEXTURE_CUBE_MAP && !unit._bindCube)) { + if ( + (target === this.TEXTURE_2D && !unit._bind2D) || + (target === this.TEXTURE_CUBE_MAP && !unit._bindCube) + ) { this.setError(this.INVALID_OPERATION) return null } @@ -1847,7 +1953,12 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { return super.getTexParameter(target, pname) } - if (this._extensions.ext_texture_filter_anisotropic && pname === this._extensions.ext_texture_filter_anisotropic.TEXTURE_MAX_ANISOTROPY_EXT) { + if ( + this._extensions.ext_texture_filter_anisotropic && + pname === + this._extensions.ext_texture_filter_anisotropic + .TEXTURE_MAX_ANISOTROPY_EXT + ) { return super.getTexParameter(target, pname) } @@ -1856,8 +1967,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } getUniform (program, location) { - if (!checkObject(program) || - !checkObject(location)) { + if (!checkObject(program) || !checkObject(location)) { throw new TypeError('getUniform(WebGLProgram, WebGLUniformLocation)') } else if (!program) { this.setError(this.INVALID_VALUE) @@ -1948,10 +2058,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { return null } - const result = new WebGLUniformLocation( - loc, - program, - info) + const result = new WebGLUniformLocation(loc, program, info) // handle array case if (/\[0\]$/.test(name)) { @@ -1966,7 +2073,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { for (let i = 0; this.getError() === this.NO_ERROR; ++i) { const xloc = super.getUniformLocation( program._ | 0, - baseName + '[' + i + ']') + baseName + '[' + i + ']' + ) if (this.getError() !== this.NO_ERROR || xloc < 0) { break } @@ -1976,7 +2084,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { result._array = arrayLocs } else if (/\[(\d+)\]$/.test(name)) { - const offset = +(/\[(\d+)\]$/.exec(name))[1] + const offset = +/\[(\d+)\]$/.exec(name)[1] if (offset < 0 || offset >= info.size) { return null } @@ -2036,19 +2144,24 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { target |= 0 mode |= 0 - if (!( - target === this.GENERATE_MIPMAP_HINT || - ( - this._extensions.oes_standard_derivatives && target === this._extensions.oes_standard_derivatives.FRAGMENT_SHADER_DERIVATIVE_HINT_OES + if ( + !( + target === this.GENERATE_MIPMAP_HINT || + (this._extensions.oes_standard_derivatives && + target === + this._extensions.oes_standard_derivatives + .FRAGMENT_SHADER_DERIVATIVE_HINT_OES) ) - )) { + ) { this.setError(this.INVALID_ENUM) return } - if (mode !== this.FASTEST && + if ( + mode !== this.FASTEST && mode !== this.NICEST && - mode !== this.DONT_CARE) { + mode !== this.DONT_CARE + ) { this.setError(this.INVALID_ENUM) return } @@ -2062,7 +2175,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } isFramebuffer (object) { - if (!this._isObject(object, 'isFramebuffer', WebGLFramebuffer)) return false + if (!this._isObject(object, 'isFramebuffer', WebGLFramebuffer)) { return false } return super.isFramebuffer(object._ | 0) } @@ -2072,7 +2185,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } isRenderbuffer (object) { - if (!this._isObject(object, 'isRenderbuffer', WebGLRenderbuffer)) return false + if (!this._isObject(object, 'isRenderbuffer', WebGLRenderbuffer)) { return false } return super.isRenderbuffer(object._ | 0) } @@ -2087,7 +2200,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } isVertexArray (object) { - if (!this._isObject(object, 'isVertexArray', WebGLVertexArrayObject)) return false + if (!this._isObject(object, 'isVertexArray', WebGLVertexArrayObject)) { return false } return super.isVertexArray(object._ | 0) } @@ -2125,20 +2238,14 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { pname |= 0 param |= 0 if (pname === this.UNPACK_ALIGNMENT) { - if (param === 1 || - param === 2 || - param === 4 || - param === 8) { + if (param === 1 || param === 2 || param === 4 || param === 8) { this._unpackAlignment = param } else { this.setError(this.INVALID_VALUE) return } } else if (pname === this.PACK_ALIGNMENT) { - if (param === 1 || - param === 2 || - param === 4 || - param === 8) { + if (param === 1 || param === 2 || param === 4 || param === 8) { this._packAlignment = param } else { this.setError(this.INVALID_VALUE) @@ -2163,21 +2270,10 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { width |= 0 height |= 0 - super.readPixels( - x, - y, - width, - height, - format, - type, - pixels) + super.readPixels(x, y, width, height, format, type, pixels) } - renderbufferStorage ( - target, - internalFormat, - width, - height) { + renderbufferStorage (target, internalFormat, width, height) { target |= 0 internalFormat |= 0 width |= 0 @@ -2195,11 +2291,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } this._saveError() - super.renderbufferStorage( - target, - internalFormat, - width, - height) + super.renderbufferStorage(target, internalFormat, width, height) const error = this.getError() this._restoreError(error) if (error !== this.NO_ERROR) { @@ -2216,8 +2308,10 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { height = height | 0 if (!(width > 0 && height > 0)) { throw new Error('Invalid surface dimensions') - } else if (width !== this.drawingBufferWidth || - height !== this.drawingBufferHeight) { + } else if ( + width !== this.drawingBufferWidth || + height !== this.drawingBufferHeight + ) { this._resizeDrawingBuffer(width, height) this.drawingBufferWidth = width this.drawingBufferHeight = height @@ -2244,7 +2338,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { if (!isValidString(source)) { this.setError(this.INVALID_VALUE) } else if (this._checkWrapper(shader, WebGLShader)) { - super.shaderSource(shader._ | 0, this._wrapShader(shader._type, source)) // eslint-disable-line + super.shaderSource(shader._ | 0, this._wrapShader(shader._type, source)); // eslint-disable-line shader._source = source } } @@ -2288,7 +2382,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { border, format, type, - pixels) { + pixels + ) { if (arguments.length === 6) { pixels = border type = height @@ -2297,7 +2392,9 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { pixels = extractImageData(pixels) if (pixels == null) { - throw new TypeError('texImage2D(GLenum, GLint, GLenum, GLint, GLenum, GLenum, ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement)') + throw new TypeError( + 'texImage2D(GLenum, GLint, GLenum, GLint, GLenum, GLenum, ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement)' + ) } width = pixels.width @@ -2315,7 +2412,9 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { type |= 0 if (typeof pixels !== 'object' && pixels !== undefined) { - throw new TypeError('texImage2D(GLenum, GLint, GLenum, GLint, GLint, GLint, GLenum, GLenum, Uint8Array)') + throw new TypeError( + 'texImage2D(GLenum, GLint, GLenum, GLint, GLint, GLint, GLenum, GLenum, Uint8Array)' + ) } // Note: there's an ANGLE bug where it doesn't check for setting texImage2D on texture zero in WebGL compat. @@ -2339,7 +2438,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { border, format, type, - data) + data + ) const error = this.getError() this._restoreError(error) if (error === this.NO_ERROR) { @@ -2358,7 +2458,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { height, format, type, - pixels) { + pixels + ) { if (arguments.length === 7) { pixels = format type = height @@ -2367,7 +2468,9 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { pixels = extractImageData(pixels) if (pixels == null) { - throw new TypeError('texSubImage2D(GLenum, GLint, GLint, GLint, GLenum, GLenum, ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement)') + throw new TypeError( + 'texSubImage2D(GLenum, GLint, GLint, GLint, GLenum, GLenum, ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement)' + ) } width = pixels.width @@ -2376,7 +2479,9 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } if (typeof pixels !== 'object') { - throw new TypeError('texSubImage2D(GLenum, GLint, GLint, GLint, GLint, GLint, GLenum, GLenum, Uint8Array)') + throw new TypeError( + 'texSubImage2D(GLenum, GLint, GLint, GLint, GLint, GLint, GLenum, GLenum, Uint8Array)' + ) } const data = convertPixels(pixels) @@ -2390,7 +2495,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { height, format, type, - data) + data + ) } texParameterf (target, pname, param) { @@ -2408,7 +2514,12 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { return super.texParameterf(target, pname, param) } - if (this._extensions.ext_texture_filter_anisotropic && pname === this._extensions.ext_texture_filter_anisotropic.TEXTURE_MAX_ANISOTROPY_EXT) { + if ( + this._extensions.ext_texture_filter_anisotropic && + pname === + this._extensions.ext_texture_filter_anisotropic + .TEXTURE_MAX_ANISOTROPY_EXT + ) { return super.texParameterf(target, pname, param) } @@ -2457,13 +2568,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } } - vertexAttribPointer ( - index, - size, - type, - normalized, - stride, - offset) { + vertexAttribPointer (index, size, type, normalized, stride, offset) { if (stride < 0 || offset < 0) { this.setError(this.INVALID_VALUE) return @@ -2476,10 +2581,13 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { stride |= 0 offset |= 0 - if (stride < 0 || + if ( + stride < 0 || offset < 0 || - index < 0 || index >= this._vertexObjectState._attribs.length || - !(size === 1 || size === 2 || size === 3 || size === 4)) { + index < 0 || + index >= this._vertexObjectState._attribs.length || + !(size === 1 || size === 2 || size === 3 || size === 4) + ) { this.setError(this.INVALID_VALUE) return } @@ -2491,9 +2599,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { // fixed, int and unsigned int aren't allowed in WebGL const byteSize = typeSize(type) - if (byteSize === 0 || - type === this.INT || - type === this.UNSIGNED_INT) { + if (byteSize === 0 || type === this.INT || type === this.UNSIGNED_INT) { this.setError(this.INVALID_ENUM) return } @@ -2504,8 +2610,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } // stride and offset must be multiples of size - if ((stride % byteSize) !== 0 || - (offset % byteSize) !== 0) { + if (stride % byteSize !== 0 || offset % byteSize !== 0) { this.setError(this.INVALID_OPERATION) return } @@ -2519,7 +2624,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { /* index */ index, /* pointerSize */ size * byteSize, /* pointerOffset */ offset, - /* pointerStride */ stride || (size * byteSize), + /* pointerStride */ stride || size * byteSize, /* pointerType */ type, /* pointerNormal */ normalized, /* inputStride */ stride, @@ -2535,7 +2640,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { this._drawingBuffer = new WebGLDrawingBufferWrapper( super.createFramebuffer(), super.createTexture(), - super.createRenderbuffer()) + super.createRenderbuffer() + ) this._resizeDrawingBuffer(width, height) } @@ -2583,14 +2689,17 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } _checkUniformValueValid (location, value, name, count, type) { - if (!checkObject(location) || - !checkObject(value)) { + if (!checkObject(location) || !checkObject(value)) { throw new TypeError(`${name}v(WebGLUniformLocation, Array)`) } else if (!location) { return false } else if (!this._checkLocationActive(location)) { return false - } else if (typeof value !== 'object' || !value || typeof value.length !== 'number') { + } else if ( + typeof value !== 'object' || + !value || + typeof value.length !== 'number' + ) { throw new TypeError(`Second argument to ${name} must be array`) } else if (uniformTypeSize(location._activeInfo.type) > count) { this.setError(this.INVALID_OPERATION) @@ -2611,11 +2720,11 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { uniform1f (location, v0) { if (!this._checkUniformValid(location, v0, 'uniform1f', 1, 'f')) return - super.uniform1f(location._ | 0, v0) + super.uniform1f(location._ | 0, +v0) } uniform1fv (location, value) { - if (!this._checkUniformValueValid(location, value, 'uniform1fv', 1, 'f')) return + if (!this._checkUniformValueValid(location, value, 'uniform1fv', 1, 'f')) { return } if (location._array) { const locs = location._array for (let i = 0; i < locs.length && i < value.length; ++i) { @@ -2629,11 +2738,11 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { uniform1i (location, v0) { if (!this._checkUniformValid(location, v0, 'uniform1i', 1, 'i')) return - super.uniform1i(location._ | 0, v0) + super.uniform1i(location._ | 0, v0 | 0) } uniform1iv (location, value) { - if (!this._checkUniformValueValid(location, value, 'uniform1iv', 1, 'i')) return + if (!this._checkUniformValueValid(location, value, 'uniform1iv', 1, 'i')) { return } if (location._array) { const locs = location._array for (let i = 0; i < locs.length && i < value.length; ++i) { @@ -2647,16 +2756,16 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { uniform2f (location, v0, v1) { if (!this._checkUniformValid(location, v0, 'uniform2f', 2, 'f')) return - super.uniform2f(location._ | 0, v0, v1) + super.uniform2f(location._ | 0, +v0, +v1) } uniform2fv (location, value) { - if (!this._checkUniformValueValid(location, value, 'uniform2fv', 2, 'f')) return + if (!this._checkUniformValueValid(location, value, 'uniform2fv', 2, 'f')) { return } if (location._array) { const locs = location._array for (let i = 0; i < locs.length && 2 * i < value.length; ++i) { const loc = locs[i] - super.uniform2f(loc, value[2 * i], value[(2 * i) + 1]) + super.uniform2f(loc, value[2 * i], value[2 * i + 1]) } return } @@ -2665,11 +2774,11 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { uniform2i (location, v0, v1) { if (!this._checkUniformValid(location, v0, 'uniform2i', 2, 'i')) return - super.uniform2i(location._ | 0, v0, v1) + super.uniform2i(location._ | 0, v0 | 0, v1 | 0) } uniform2iv (location, value) { - if (!this._checkUniformValueValid(location, value, 'uniform2iv', 2, 'i')) return + if (!this._checkUniformValueValid(location, value, 'uniform2iv', 2, 'i')) { return } if (location._array) { const locs = location._array for (let i = 0; i < locs.length && 2 * i < value.length; ++i) { @@ -2683,11 +2792,11 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { uniform3f (location, v0, v1, v2) { if (!this._checkUniformValid(location, v0, 'uniform3f', 3, 'f')) return - super.uniform3f(location._ | 0, v0, v1, v2) + super.uniform3f(location._ | 0, +v0, +v1, +v2) } uniform3fv (location, value) { - if (!this._checkUniformValueValid(location, value, 'uniform3fv', 3, 'f')) return + if (!this._checkUniformValueValid(location, value, 'uniform3fv', 3, 'f')) { return } if (location._array) { const locs = location._array for (let i = 0; i < locs.length && 3 * i < value.length; ++i) { @@ -2701,11 +2810,11 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { uniform3i (location, v0, v1, v2) { if (!this._checkUniformValid(location, v0, 'uniform3i', 3, 'i')) return - super.uniform3i(location._ | 0, v0, v1, v2) + super.uniform3i(location._ | 0, v0 | 0, v1 | 0, v2 | 0) } uniform3iv (location, value) { - if (!this._checkUniformValueValid(location, value, 'uniform3iv', 3, 'i')) return + if (!this._checkUniformValueValid(location, value, 'uniform3iv', 3, 'i')) { return } if (location._array) { const locs = location._array for (let i = 0; i < locs.length && 3 * i < value.length; ++i) { @@ -2719,16 +2828,22 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { uniform4f (location, v0, v1, v2, v3) { if (!this._checkUniformValid(location, v0, 'uniform4f', 4, 'f')) return - super.uniform4f(location._ | 0, v0, v1, v2, v3) + super.uniform4f(location._ | 0, +v0, +v1, +v2, +v3) } uniform4fv (location, value) { - if (!this._checkUniformValueValid(location, value, 'uniform4fv', 4, 'f')) return + if (!this._checkUniformValueValid(location, value, 'uniform4fv', 4, 'f')) { return } if (location._array) { const locs = location._array for (let i = 0; i < locs.length && 4 * i < value.length; ++i) { const loc = locs[i] - super.uniform4f(loc, value[4 * i], value[4 * i + 1], value[4 * i + 2], value[4 * i + 3]) + super.uniform4f( + loc, + value[4 * i], + value[4 * i + 1], + value[4 * i + 2], + value[4 * i + 3] + ) } return } @@ -2737,16 +2852,22 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { uniform4i (location, v0, v1, v2, v3) { if (!this._checkUniformValid(location, v0, 'uniform4i', 4, 'i')) return - super.uniform4i(location._ | 0, v0, v1, v2, v3) + super.uniform4i(location._ | 0, v0 | 0, v1 | 0, v2 | 0, v3 | 0) } uniform4iv (location, value) { - if (!this._checkUniformValueValid(location, value, 'uniform4iv', 4, 'i')) return + if (!this._checkUniformValueValid(location, value, 'uniform4iv', 4, 'i')) { return } if (location._array) { const locs = location._array for (let i = 0; i < locs.length && 4 * i < value.length; ++i) { const loc = locs[i] - super.uniform4i(loc, value[4 * i], value[4 * i + 1], value[4 * i + 2], value[4 * i + 3]) + super.uniform4i( + loc, + value[4 * i], + value[4 * i + 1], + value[4 * i + 2], + value[4 * i + 3] + ) } return } @@ -2754,14 +2875,15 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } _checkUniformMatrix (location, transpose, value, name, count) { - if (!checkObject(location) || - typeof value !== 'object') { + if (!checkObject(location) || typeof value !== 'object') { throw new TypeError(name + '(WebGLUniformLocation, Boolean, Array)') - } else if (!!transpose || + } else if ( + !!transpose || typeof value !== 'object' || value === null || !value.length || - value.length % count * count !== 0) { + (value.length % count) * count !== 0 + ) { this.setError(this.INVALID_VALUE) return false } @@ -2782,30 +2904,45 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { } uniformMatrix2fv (location, transpose, value) { - if (!this._checkUniformMatrix(location, transpose, value, 'uniformMatrix2fv', 2)) return + if ( + !this._checkUniformMatrix( + location, + transpose, + value, + 'uniformMatrix2fv', + 2 + ) + ) { return } const data = new Float32Array(value) - super.uniformMatrix2fv( - location._ | 0, - !!transpose, - data) + super.uniformMatrix2fv(location._ | 0, !!transpose, data) } uniformMatrix3fv (location, transpose, value) { - if (!this._checkUniformMatrix(location, transpose, value, 'uniformMatrix3fv', 3)) return + if ( + !this._checkUniformMatrix( + location, + transpose, + value, + 'uniformMatrix3fv', + 3 + ) + ) { return } const data = new Float32Array(value) - super.uniformMatrix3fv( - location._ | 0, - !!transpose, - data) + super.uniformMatrix3fv(location._ | 0, !!transpose, data) } uniformMatrix4fv (location, transpose, value) { - if (!this._checkUniformMatrix(location, transpose, value, 'uniformMatrix4fv', 4)) return + if ( + !this._checkUniformMatrix( + location, + transpose, + value, + 'uniformMatrix4fv', + 4 + ) + ) { return } const data = new Float32Array(value) - super.uniformMatrix4fv( - location._ | 0, - !!transpose, - data) + super.uniformMatrix4fv(location._ | 0, !!transpose, data) } vertexAttrib1f (index, v0) { @@ -2900,7 +3037,13 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { data[2] = value[2] data[1] = value[1] data[0] = value[0] - return super.vertexAttrib4f(index | 0, +value[0], +value[1], +value[2], +value[3]) + return super.vertexAttrib4f( + index | 0, + +value[0], + +value[1], + +value[2], + +value[3] + ) } _isWebGL2 () { diff --git a/src/javascript/webgl-vertex-attribute.js b/src/javascript/webgl-vertex-attribute.js index d99a5348..40635ee9 100644 --- a/src/javascript/webgl-vertex-attribute.js +++ b/src/javascript/webgl-vertex-attribute.js @@ -96,7 +96,8 @@ class WebGLVertexArrayObjectState { pointerType, pointerNormal, inputStride, - inputSize) { + inputSize + ) { const attrib = this._attribs[index] if (buffer !== attrib._pointerBuffer) { if (attrib._pointerBuffer) { diff --git a/src/linkable.ts b/src/linkable.ts new file mode 100644 index 00000000..52b8dd63 --- /dev/null +++ b/src/linkable.ts @@ -0,0 +1,50 @@ +export class Linkable { + _: number; + _references: Linkable[]; + _refCount: number; + _pendingDelete: boolean; + _binding: number; + + constructor(_: number) { + this._ = _; + this._references = []; + this._refCount = 0; + this._pendingDelete = false; + this._binding = 0; + } + + _link(b: Linkable): boolean { + this._references.push(b); + b._refCount += 1; + return true; + } + + _unlink(b: Linkable): boolean { + let idx = this._references.indexOf(b); + if (idx < 0) return false; + while (idx >= 0) { + this._references[idx] = this._references[this._references.length - 1]; + this._references.pop(); + b._refCount -= 1; + b._checkDelete(); + idx = this._references.indexOf(b); + } + return true; + } + + _linked(b: Linkable): boolean { + return this._references.indexOf(b) >= 0; + } + + _checkDelete(): void { + if (this._refCount <= 0 && this._pendingDelete && this._ !== 0) { + while (this._references.length > 0) { + this._unlink(this._references[0]); + } + this._performDelete(); + this._ = 0; + } + } + + _performDelete(): void {} +} diff --git a/src/native-gl.ts b/src/native-gl.ts new file mode 100644 index 00000000..3fe995cb --- /dev/null +++ b/src/native-gl.ts @@ -0,0 +1,16 @@ +// eslint-disable-next-line @typescript-eslint/no-require-imports +const NativeWebGL = require('bindings')('webgl') as { + WebGLRenderingContext: any; + cleanup: () => void; + setError: (error: number) => void; +}; +const NativeWebGLRenderingContext: any = NativeWebGL.WebGLRenderingContext; +process.on('exit', NativeWebGL.cleanup); + +const gl: any = NativeWebGLRenderingContext.prototype; + +// from binding.gyp +delete gl['1.0.0']; +delete NativeWebGLRenderingContext['1.0.0']; + +export { gl, NativeWebGL, NativeWebGLRenderingContext }; diff --git a/src/native/SharedLibrary.h b/src/native/SharedLibrary.h index f8f5e596..5e67edc7 100644 --- a/src/native/SharedLibrary.h +++ b/src/native/SharedLibrary.h @@ -29,8 +29,10 @@ class SharedLibrary { SharedLibrary() {} bool open(const std::string &libraryPath) { - const std::string libraryPathWithExt = - GetModuleDirectory() + "/" + libraryPath + GetSharedLibraryExtension(); + const std::string dir = GetModuleDirectory(); + const std::string libraryPathWithExt = dir.empty() + ? libraryPath + GetSharedLibraryExtension() + : dir + "/" + libraryPath + GetSharedLibraryExtension(); #ifdef _WIN32 handle = LoadLibraryA(libraryPathWithExt.c_str()); #else diff --git a/src/native/bindings.cc b/src/native/bindings.cc index b5491821..2ee63dec 100644 --- a/src/native/bindings.cc +++ b/src/native/bindings.cc @@ -8,253 +8,20 @@ #include "webgl.h" #include -Nan::Persistent WEBGL_TEMPLATE; - -#define JS_GL_METHOD(webgl_name, method_name) \ - Nan::SetPrototypeTemplate(webgl_template, webgl_name, \ - Nan::New(WebGLRenderingContext::method_name)) - -#define JS_CONSTANT(x, v) Nan::SetPrototypeTemplate(webgl_template, #x, Nan::New(v)) +#define JS_CONSTANT(x, v) proto.Set(#x, Napi::Number::New(env, v)) #define JS_GL_CONSTANT(name) JS_CONSTANT(name, GL_##name) -#define JS_SET_CONSTANT(name, v) \ - Nan::Set(info.This(), Nan::New(#name).ToLocalChecked(), Nan::New(v)) +#define JS_SET_CONSTANT(name, v) obj.Set(#name, Napi::Number::New(env, v)) #define JS_SET_GL_CONSTANT(name) JS_SET_CONSTANT(name, GL_##name) -NAN_MODULE_INIT(Init) { - v8::Local webgl_template = - Nan::New(WebGLRenderingContext::New); - - webgl_template->InstanceTemplate()->SetInternalFieldCount(1); - webgl_template->SetClassName(Nan::New("WebGLRenderingContext").ToLocalChecked()); - - /* WebGL methods */ - JS_GL_METHOD("_drawArraysInstancedANGLE", DrawArraysInstancedANGLE); - JS_GL_METHOD("_drawElementsInstancedANGLE", DrawElementsInstancedANGLE); - JS_GL_METHOD("_vertexAttribDivisorANGLE", VertexAttribDivisorANGLE); - - JS_GL_METHOD("getUniform", GetUniform); - JS_GL_METHOD("uniform1f", Uniform1f); - JS_GL_METHOD("uniform2f", Uniform2f); - JS_GL_METHOD("uniform3f", Uniform3f); - JS_GL_METHOD("uniform4f", Uniform4f); - JS_GL_METHOD("uniform1i", Uniform1i); - JS_GL_METHOD("uniform2i", Uniform2i); - JS_GL_METHOD("uniform3i", Uniform3i); - JS_GL_METHOD("uniform4i", Uniform4i); - JS_GL_METHOD("pixelStorei", PixelStorei); - JS_GL_METHOD("bindAttribLocation", BindAttribLocation); - JS_GL_METHOD("getError", GetError); - JS_GL_METHOD("drawArrays", DrawArrays); - JS_GL_METHOD("uniformMatrix2fv", UniformMatrix2fv); - JS_GL_METHOD("uniformMatrix3fv", UniformMatrix3fv); - JS_GL_METHOD("uniformMatrix4fv", UniformMatrix4fv); - JS_GL_METHOD("generateMipmap", GenerateMipmap); - JS_GL_METHOD("getAttribLocation", GetAttribLocation); - JS_GL_METHOD("depthFunc", DepthFunc); - JS_GL_METHOD("viewport", Viewport); - JS_GL_METHOD("createShader", CreateShader); - JS_GL_METHOD("shaderSource", ShaderSource); - JS_GL_METHOD("compileShader", CompileShader); - JS_GL_METHOD("getShaderParameter", GetShaderParameter); - JS_GL_METHOD("getShaderInfoLog", GetShaderInfoLog); - JS_GL_METHOD("createProgram", CreateProgram); - JS_GL_METHOD("attachShader", AttachShader); - JS_GL_METHOD("linkProgram", LinkProgram); - JS_GL_METHOD("getProgramParameter", GetProgramParameter); - JS_GL_METHOD("getUniformLocation", GetUniformLocation); - JS_GL_METHOD("clearColor", ClearColor); - JS_GL_METHOD("clearDepth", ClearDepth); - JS_GL_METHOD("disable", Disable); - JS_GL_METHOD("createTexture", CreateTexture); - JS_GL_METHOD("bindTexture", BindTexture); - JS_GL_METHOD("texImage2D", TexImage2D); - JS_GL_METHOD("texParameteri", TexParameteri); - JS_GL_METHOD("texParameterf", TexParameterf); - JS_GL_METHOD("clear", Clear); - JS_GL_METHOD("useProgram", UseProgram); - JS_GL_METHOD("createFramebuffer", CreateFramebuffer); - JS_GL_METHOD("bindFramebuffer", BindFramebuffer); - JS_GL_METHOD("framebufferTexture2D", FramebufferTexture2D); - JS_GL_METHOD("createBuffer", CreateBuffer); - JS_GL_METHOD("bindBuffer", BindBuffer); - JS_GL_METHOD("bufferData", BufferData); - JS_GL_METHOD("bufferSubData", BufferSubData); - JS_GL_METHOD("enable", Enable); - JS_GL_METHOD("blendEquation", BlendEquation); - JS_GL_METHOD("blendFunc", BlendFunc); - JS_GL_METHOD("enableVertexAttribArray", EnableVertexAttribArray); - JS_GL_METHOD("vertexAttribPointer", VertexAttribPointer); - JS_GL_METHOD("activeTexture", ActiveTexture); - JS_GL_METHOD("drawElements", DrawElements); - JS_GL_METHOD("flush", Flush); - JS_GL_METHOD("finish", Finish); - JS_GL_METHOD("vertexAttrib1f", VertexAttrib1f); - JS_GL_METHOD("vertexAttrib2f", VertexAttrib2f); - JS_GL_METHOD("vertexAttrib3f", VertexAttrib3f); - JS_GL_METHOD("vertexAttrib4f", VertexAttrib4f); - JS_GL_METHOD("blendColor", BlendColor); - JS_GL_METHOD("blendEquationSeparate", BlendEquationSeparate); - JS_GL_METHOD("blendFuncSeparate", BlendFuncSeparate); - JS_GL_METHOD("clearStencil", ClearStencil); - JS_GL_METHOD("colorMask", ColorMask); - JS_GL_METHOD("copyTexImage2D", CopyTexImage2D); - JS_GL_METHOD("copyTexSubImage2D", CopyTexSubImage2D); - JS_GL_METHOD("cullFace", CullFace); - JS_GL_METHOD("depthMask", DepthMask); - JS_GL_METHOD("depthRange", DepthRange); - JS_GL_METHOD("disableVertexAttribArray", DisableVertexAttribArray); - JS_GL_METHOD("hint", Hint); - JS_GL_METHOD("isEnabled", IsEnabled); - JS_GL_METHOD("lineWidth", LineWidth); - JS_GL_METHOD("polygonOffset", PolygonOffset); - JS_GL_METHOD("scissor", Scissor); - JS_GL_METHOD("stencilFunc", StencilFunc); - JS_GL_METHOD("stencilFuncSeparate", StencilFuncSeparate); - JS_GL_METHOD("stencilMask", StencilMask); - JS_GL_METHOD("stencilMaskSeparate", StencilMaskSeparate); - JS_GL_METHOD("stencilOp", StencilOp); - JS_GL_METHOD("stencilOpSeparate", StencilOpSeparate); - JS_GL_METHOD("bindRenderbuffer", BindRenderbuffer); - JS_GL_METHOD("createRenderbuffer", CreateRenderbuffer); - JS_GL_METHOD("deleteBuffer", DeleteBuffer); - JS_GL_METHOD("deleteFramebuffer", DeleteFramebuffer); - JS_GL_METHOD("deleteProgram", DeleteProgram); - JS_GL_METHOD("deleteRenderbuffer", DeleteRenderbuffer); - JS_GL_METHOD("deleteShader", DeleteShader); - JS_GL_METHOD("deleteTexture", DeleteTexture); - JS_GL_METHOD("detachShader", DetachShader); - JS_GL_METHOD("framebufferRenderbuffer", FramebufferRenderbuffer); - JS_GL_METHOD("getVertexAttribOffset", GetVertexAttribOffset); - JS_GL_METHOD("isBuffer", IsBuffer); - JS_GL_METHOD("isFramebuffer", IsFramebuffer); - JS_GL_METHOD("isProgram", IsProgram); - JS_GL_METHOD("isRenderbuffer", IsRenderbuffer); - JS_GL_METHOD("isShader", IsShader); - JS_GL_METHOD("isTexture", IsTexture); - JS_GL_METHOD("renderbufferStorage", RenderbufferStorage); - JS_GL_METHOD("getShaderSource", GetShaderSource); - JS_GL_METHOD("validateProgram", ValidateProgram); - JS_GL_METHOD("texSubImage2D", TexSubImage2D); - JS_GL_METHOD("readPixels", ReadPixels); - JS_GL_METHOD("getTexParameter", GetTexParameter); - JS_GL_METHOD("getActiveAttrib", GetActiveAttrib); - JS_GL_METHOD("getActiveUniform", GetActiveUniform); - JS_GL_METHOD("getAttachedShaders", GetAttachedShaders); - JS_GL_METHOD("getParameter", GetParameter); - JS_GL_METHOD("getBufferParameter", GetBufferParameter); - JS_GL_METHOD("getFramebufferAttachmentParameter", GetFramebufferAttachmentParameter); - JS_GL_METHOD("getProgramInfoLog", GetProgramInfoLog); - JS_GL_METHOD("getRenderbufferParameter", GetRenderbufferParameter); - JS_GL_METHOD("getVertexAttrib", GetVertexAttrib); - JS_GL_METHOD("getSupportedExtensions", GetSupportedExtensions); - JS_GL_METHOD("getExtension", GetExtension); - JS_GL_METHOD("checkFramebufferStatus", CheckFramebufferStatus); - JS_GL_METHOD("getShaderPrecisionFormat", GetShaderPrecisionFormat); - JS_GL_METHOD("frontFace", FrontFace); - JS_GL_METHOD("sampleCoverage", SampleCoverage); - JS_GL_METHOD("destroy", Destroy); - JS_GL_METHOD("drawBuffersWEBGL", DrawBuffersWEBGL); - JS_GL_METHOD("extWEBGL_draw_buffers", EXTWEBGL_draw_buffers); - JS_GL_METHOD("createVertexArrayOES", CreateVertexArrayOES); - JS_GL_METHOD("deleteVertexArrayOES", DeleteVertexArrayOES); - JS_GL_METHOD("isVertexArrayOES", IsVertexArrayOES); - JS_GL_METHOD("bindVertexArrayOES", BindVertexArrayOES); - - // WebGL 2.0 functions: - JS_GL_METHOD("copyBufferSubData", CopyBufferSubData); - JS_GL_METHOD("getBufferSubData", GetBufferSubData); - JS_GL_METHOD("blitFramebuffer", BlitFramebuffer); - JS_GL_METHOD("framebufferTextureLayer", FramebufferTextureLayer); - JS_GL_METHOD("invalidateFramebuffer", InvalidateFramebuffer); - JS_GL_METHOD("invalidateSubFramebuffer", InvalidateSubFramebuffer); - JS_GL_METHOD("readBuffer", ReadBuffer); - JS_GL_METHOD("getInternalformatParameter", GetInternalformatParameter); - JS_GL_METHOD("renderbufferStorageMultisample", RenderbufferStorageMultisample); - JS_GL_METHOD("texStorage2D", TexStorage2D); - JS_GL_METHOD("texStorage3D", TexStorage3D); - JS_GL_METHOD("texImage3D", TexImage3D); - JS_GL_METHOD("texSubImage3D", TexSubImage3D); - JS_GL_METHOD("copyTexSubImage3D", CopyTexSubImage3D); - JS_GL_METHOD("compressedTexImage3D", CompressedTexImage3D); - JS_GL_METHOD("compressedTexSubImage3D", CompressedTexSubImage3D); - JS_GL_METHOD("getFragDataLocation", GetFragDataLocation); - JS_GL_METHOD("uniform1ui", Uniform1ui); - JS_GL_METHOD("uniform2ui", Uniform2ui); - JS_GL_METHOD("uniform3ui", Uniform3ui); - JS_GL_METHOD("uniform4ui", Uniform4ui); - JS_GL_METHOD("uniform1uiv", Uniform1uiv); - JS_GL_METHOD("uniform2uiv", Uniform2uiv); - JS_GL_METHOD("uniform3uiv", Uniform3uiv); - JS_GL_METHOD("uniform4uiv", Uniform4uiv); - JS_GL_METHOD("uniformMatrix3x2fv", UniformMatrix3x2fv); - JS_GL_METHOD("uniformMatrix4x2fv", UniformMatrix4x2fv); - JS_GL_METHOD("uniformMatrix2x3fv", UniformMatrix2x3fv); - JS_GL_METHOD("uniformMatrix4x3fv", UniformMatrix4x3fv); - JS_GL_METHOD("uniformMatrix2x4fv", UniformMatrix2x4fv); - JS_GL_METHOD("uniformMatrix3x4fv", UniformMatrix3x4fv); - JS_GL_METHOD("vertexAttribI4i", VertexAttribI4i); - JS_GL_METHOD("vertexAttribI4iv", VertexAttribI4iv); - JS_GL_METHOD("vertexAttribI4ui", VertexAttribI4ui); - JS_GL_METHOD("vertexAttribI4uiv", VertexAttribI4uiv); - JS_GL_METHOD("vertexAttribIPointer", VertexAttribIPointer); - JS_GL_METHOD("vertexAttribDivisor", VertexAttribDivisor); - JS_GL_METHOD("drawArraysInstanced", DrawArraysInstanced); - JS_GL_METHOD("drawElementsInstanced", DrawElementsInstanced); - JS_GL_METHOD("drawRangeElements", DrawRangeElements); - JS_GL_METHOD("drawBuffers", DrawBuffers); - JS_GL_METHOD("clearBufferfv", ClearBufferfv); - JS_GL_METHOD("clearBufferiv", ClearBufferiv); - JS_GL_METHOD("clearBufferuiv", ClearBufferuiv); - JS_GL_METHOD("clearBufferfi", ClearBufferfi); - JS_GL_METHOD("createQuery", CreateQuery); - JS_GL_METHOD("deleteQuery", DeleteQuery); - JS_GL_METHOD("isQuery", IsQuery); - JS_GL_METHOD("beginQuery", BeginQuery); - JS_GL_METHOD("endQuery", EndQuery); - JS_GL_METHOD("getQuery", GetQuery); - JS_GL_METHOD("getQueryParameter", GetQueryParameter); - JS_GL_METHOD("createSampler", CreateSampler); - JS_GL_METHOD("deleteSampler", DeleteSampler); - JS_GL_METHOD("isSampler", IsSampler); - JS_GL_METHOD("bindSampler", BindSampler); - JS_GL_METHOD("samplerParameteri", SamplerParameteri); - JS_GL_METHOD("samplerParameterf", SamplerParameterf); - JS_GL_METHOD("getSamplerParameter", GetSamplerParameter); - JS_GL_METHOD("fenceSync", FenceSync); - JS_GL_METHOD("isSync", IsSync); - JS_GL_METHOD("deleteSync", DeleteSync); - JS_GL_METHOD("clientWaitSync", ClientWaitSync); - JS_GL_METHOD("waitSync", WaitSync); - JS_GL_METHOD("getSyncParameter", GetSyncParameter); - JS_GL_METHOD("createTransformFeedback", CreateTransformFeedback); - JS_GL_METHOD("deleteTransformFeedback", DeleteTransformFeedback); - JS_GL_METHOD("isTransformFeedback", IsTransformFeedback); - JS_GL_METHOD("bindTransformFeedback", BindTransformFeedback); - JS_GL_METHOD("beginTransformFeedback", BeginTransformFeedback); - JS_GL_METHOD("endTransformFeedback", EndTransformFeedback); - JS_GL_METHOD("transformFeedbackVaryings", TransformFeedbackVaryings); - JS_GL_METHOD("getTransformFeedbackVarying", GetTransformFeedbackVarying); - JS_GL_METHOD("pauseTransformFeedback", PauseTransformFeedback); - JS_GL_METHOD("resumeTransformFeedback", ResumeTransformFeedback); - JS_GL_METHOD("bindBufferBase", BindBufferBase); - JS_GL_METHOD("bindBufferRange", BindBufferRange); - JS_GL_METHOD("getIndexedParameter", GetIndexedParameter); - JS_GL_METHOD("getUniformIndices", GetUniformIndices); - JS_GL_METHOD("getActiveUniforms", GetActiveUniforms); - JS_GL_METHOD("getUniformBlockIndex", GetUniformBlockIndex); - JS_GL_METHOD("getActiveUniformBlockParameter", GetActiveUniformBlockParameter); - JS_GL_METHOD("getActiveUniformBlockName", GetActiveUniformBlockName); - JS_GL_METHOD("uniformBlockBinding", UniformBlockBinding); - JS_GL_METHOD("createVertexArray", CreateVertexArray); - JS_GL_METHOD("deleteVertexArray", DeleteVertexArray); - JS_GL_METHOD("isVertexArray", IsVertexArray); - JS_GL_METHOD("bindVertexArray", BindVertexArray); +Napi::Object Init(Napi::Env env, Napi::Object exports) { + Napi::Function ctor = WebGLRenderingContext::GetClass(env); + Napi::Object proto = ctor.Get("prototype").As(); // Windows defines a macro called NO_ERROR which messes this up - Nan::SetPrototypeTemplate(webgl_template, "NO_ERROR", Nan::New(GL_NO_ERROR)); + proto.Set("NO_ERROR", Napi::Number::New(env, GL_NO_ERROR)); JS_GL_CONSTANT(INVALID_ENUM); JS_GL_CONSTANT(INVALID_VALUE); JS_GL_CONSTANT(INVALID_OPERATION); @@ -556,17 +323,24 @@ NAN_MODULE_INIT(Init) { JS_CONSTANT(IMPLEMENTATION_COLOR_READ_TYPE, 0x8B9A); JS_CONSTANT(IMPLEMENTATION_COLOR_READ_FORMAT, 0x8B9B); - // Export template - WEBGL_TEMPLATE.Reset(webgl_template); - Nan::Set(target, Nan::New("WebGLRenderingContext").ToLocalChecked(), - Nan::GetFunction(webgl_template).ToLocalChecked()); + exports.Set("WebGLRenderingContext", ctor); + + // Export cleanup helper + exports.Set("cleanup", Napi::Function::New(env, &WebGLRenderingContext::DisposeAll)); + + // Export setError — called as NativeWebGL.setError.call(glInstance, code) + exports.Set("setError", Napi::Function::New(env, [](const Napi::CallbackInfo& cbInfo) -> Napi::Value { + auto* inst = Napi::ObjectWrap::Unwrap(cbInfo.This().As()); + if (inst && inst->setActive()) { + inst->setError((GLenum)(cbInfo[0].As().Int32Value())); + } + return cbInfo.Env().Undefined(); + })); - // Export helper methods for clean up and error handling - Nan::Export(target, "cleanup", WebGLRenderingContext::DisposeAll); - Nan::Export(target, "setError", WebGLRenderingContext::SetError); + return exports; } -void BindWebGL2(const Nan::FunctionCallbackInfo &info) { +void BindWebGL2(Napi::Object obj, Napi::Env env) { /* ES3 enums */ JS_SET_GL_CONSTANT(READ_BUFFER); JS_SET_GL_CONSTANT(UNPACK_ROW_LENGTH); @@ -660,6 +434,7 @@ void BindWebGL2(const Nan::FunctionCallbackInfo &info) { JS_SET_GL_CONSTANT(UNSIGNED_INT_10F_11F_11F_REV); JS_SET_GL_CONSTANT(RGB9_E5); JS_SET_GL_CONSTANT(UNSIGNED_INT_5_9_9_9_REV); + JS_SET_GL_CONSTANT(TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH); JS_SET_GL_CONSTANT(TRANSFORM_FEEDBACK_BUFFER_MODE); JS_SET_GL_CONSTANT(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS); JS_SET_GL_CONSTANT(TRANSFORM_FEEDBACK_VARYINGS); @@ -714,6 +489,8 @@ void BindWebGL2(const Nan::FunctionCallbackInfo &info) { JS_SET_GL_CONSTANT(FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE); JS_SET_GL_CONSTANT(FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE); JS_SET_GL_CONSTANT(FRAMEBUFFER_DEFAULT); + JS_SET_GL_CONSTANT(DEPTH_STENCIL_ATTACHMENT); + JS_SET_GL_CONSTANT(DEPTH_STENCIL); JS_SET_GL_CONSTANT(UNSIGNED_INT_24_8); JS_SET_GL_CONSTANT(DEPTH24_STENCIL8); JS_SET_GL_CONSTANT(UNSIGNED_NORMALIZED); @@ -768,6 +545,7 @@ void BindWebGL2(const Nan::FunctionCallbackInfo &info) { JS_SET_GL_CONSTANT(RGB8_SNORM); JS_SET_GL_CONSTANT(RGBA8_SNORM); JS_SET_GL_CONSTANT(SIGNED_NORMALIZED); + JS_SET_GL_CONSTANT(PRIMITIVE_RESTART_FIXED_INDEX); JS_SET_GL_CONSTANT(COPY_READ_BUFFER); JS_SET_GL_CONSTANT(COPY_WRITE_BUFFER); JS_SET_GL_CONSTANT(COPY_READ_BUFFER_BINDING); @@ -838,4 +616,4 @@ void BindWebGL2(const Nan::FunctionCallbackInfo &info) { JS_SET_GL_CONSTANT(RGBA8); } -NODE_MODULE(webgl, Init) +NODE_API_MODULE(webgl, Init) diff --git a/src/native/webgl.cc b/src/native/webgl.cc index 0e030239..d5e5ee62 100644 --- a/src/native/webgl.cc +++ b/src/native/webgl.cc @@ -148,16 +148,15 @@ EGLDisplay WebGLRenderingContext::DISPLAY; WebGLRenderingContext *WebGLRenderingContext::ACTIVE = NULL; WebGLRenderingContext *WebGLRenderingContext::CONTEXT_LIST_HEAD = NULL; -#define GL_METHOD(method_name) NAN_METHOD(WebGLRenderingContext::method_name) +#define GL_METHOD(method_name) \ + Napi::Value WebGLRenderingContext::method_name(const Napi::CallbackInfo& info) #define GL_BOILERPLATE \ - Nan::HandleScope(); \ - if (info.This()->InternalFieldCount() <= 0) { \ - return Nan::ThrowError("Invalid WebGL Object"); \ - } \ - WebGLRenderingContext *inst = node::ObjectWrap::Unwrap(info.This()); \ + Napi::Env env = info.Env(); \ + WebGLRenderingContext *inst = this; \ if (!(inst && inst->setActive())) { \ - return Nan::ThrowError("Invalid GL context"); \ + Napi::Error::New(env, "Invalid GL context").ThrowAsJavaScriptException(); \ + return env.Undefined(); \ } bool ContextSupportsExtensions(WebGLRenderingContext *inst, @@ -181,16 +180,47 @@ bool CaseInsensitiveCompare(const std::string &a, const std::string &b) { return aLower < bLower; }; -WebGLRenderingContext::WebGLRenderingContext(int width, int height, bool alpha, bool depth, - bool stencil, bool antialias, bool premultipliedAlpha, - bool preserveDrawingBuffer, - bool preferLowPowerToHighPerformance, - bool failIfMajorPerformanceCaveat, - bool createWebGL2Context) - : state(GLCONTEXT_STATE_INIT), unpack_flip_y(false), unpack_premultiply_alpha(false), +WebGLRenderingContext::WebGLRenderingContext(const Napi::CallbackInfo& info) + : Napi::ObjectWrap(info), + state(GLCONTEXT_STATE_INIT), unpack_flip_y(false), unpack_premultiply_alpha(false), unpack_colorspace_conversion(0x9244), unpack_alignment(4), webGLToANGLEExtensions(&CaseInsensitiveCompare), next(NULL), prev(NULL) { + Napi::Env env = info.Env(); + if (info.Length() < 11) { + // Called with no args (e.g. from wrapContext) — create an empty shell, no GL context. + return; + } + bool createWebGL2Context = info[10].As().Value(); + _initContext( + info[0].As().Int32Value(), + info[1].As().Int32Value(), + info[2].As().Value(), + info[3].As().Value(), + info[4].As().Value(), + info[5].As().Value(), + info[6].As().Value(), + info[7].As().Value(), + info[8].As().Value(), + info[9].As().Value(), + createWebGL2Context + ); + if (state != GLCONTEXT_STATE_OK) { + std::string err = "Error creating WebGLContext"; + if (!errorMessage.empty()) err += ": " + errorMessage; + Napi::Error::New(env, err).ThrowAsJavaScriptException(); + return; + } + if (createWebGL2Context) { + BindWebGL2(this->Value(), env); + } +} +void WebGLRenderingContext::_initContext(int width, int height, bool alpha, bool depth, + bool stencil, bool antialias, bool premultipliedAlpha, + bool preserveDrawingBuffer, + bool preferLowPowerToHighPerformance, + bool failIfMajorPerformanceCaveat, + bool createWebGL2Context) { if (!eglGetProcAddress) { if (!eglLibrary.open("libEGL")) { errorMessage = "Error opening ANGLE shared library."; @@ -342,7 +372,7 @@ WebGLRenderingContext::WebGLRenderingContext(int width, int height, bool alpha, supportedWebGLExtensions.insert(webGLExtension); } } -} +} // end _initContext bool WebGLRenderingContext::setActive() { if (state != GLCONTEXT_STATE_OK) { @@ -424,153 +454,350 @@ WebGLRenderingContext::~WebGLRenderingContext() { dispose(); } GL_METHOD(SetError) { GL_BOILERPLATE; - inst->setError((GLenum)(Nan::To(info[0]).ToChecked())); + inst->setError((GLenum)(info[0].As().Int32Value())); + return env.Undefined(); } -GL_METHOD(DisposeAll) { - Nan::HandleScope(); - +Napi::Value WebGLRenderingContext::DisposeAll(const Napi::CallbackInfo& info) { while (CONTEXT_LIST_HEAD) { CONTEXT_LIST_HEAD->dispose(); } - if (WebGLRenderingContext::HAS_DISPLAY) { eglTerminate(WebGLRenderingContext::DISPLAY); WebGLRenderingContext::HAS_DISPLAY = false; } -} - -GL_METHOD(New) { - Nan::HandleScope(); - - bool createWebGL2Context = Nan::To(info[10]).ToChecked(); - - WebGLRenderingContext *instance = - new WebGLRenderingContext(Nan::To(info[0]).ToChecked(), // Width - Nan::To(info[1]).ToChecked(), // Height - Nan::To(info[2]).ToChecked(), // Alpha - Nan::To(info[3]).ToChecked(), // Depth - Nan::To(info[4]).ToChecked(), // Stencil - Nan::To(info[5]).ToChecked(), // antialias - Nan::To(info[6]).ToChecked(), // premultipliedAlpha - Nan::To(info[7]).ToChecked(), // preserve drawing buffer - Nan::To(info[8]).ToChecked(), // low power - Nan::To(info[9]).ToChecked(), // fail if crap - createWebGL2Context); - - if (instance->state != GLCONTEXT_STATE_OK) { - if (!instance->errorMessage.empty()) { - std::string error = std::string("Error creating WebGLContext: ") + instance->errorMessage; - return Nan::ThrowError(error.c_str()); - } else { - return Nan::ThrowError("Error creating WebGLContext"); - } - } - - instance->Wrap(info.This()); - - if (createWebGL2Context) { - BindWebGL2(info); - } - - info.GetReturnValue().Set(info.This()); + return info.Env().Undefined(); +} + +Napi::Function WebGLRenderingContext::GetClass(Napi::Env env) { + return DefineClass(env, "WebGLRenderingContext", { + InstanceMethod("_drawArraysInstancedANGLE", &WebGLRenderingContext::DrawArraysInstancedANGLE), + InstanceMethod("_drawElementsInstancedANGLE", &WebGLRenderingContext::DrawElementsInstancedANGLE), + InstanceMethod("_vertexAttribDivisorANGLE", &WebGLRenderingContext::VertexAttribDivisorANGLE), + InstanceMethod("getUniform", &WebGLRenderingContext::GetUniform), + InstanceMethod("uniform1f", &WebGLRenderingContext::Uniform1f), + InstanceMethod("uniform2f", &WebGLRenderingContext::Uniform2f), + InstanceMethod("uniform3f", &WebGLRenderingContext::Uniform3f), + InstanceMethod("uniform4f", &WebGLRenderingContext::Uniform4f), + InstanceMethod("uniform1i", &WebGLRenderingContext::Uniform1i), + InstanceMethod("uniform2i", &WebGLRenderingContext::Uniform2i), + InstanceMethod("uniform3i", &WebGLRenderingContext::Uniform3i), + InstanceMethod("uniform4i", &WebGLRenderingContext::Uniform4i), + InstanceMethod("pixelStorei", &WebGLRenderingContext::PixelStorei), + InstanceMethod("bindAttribLocation", &WebGLRenderingContext::BindAttribLocation), + InstanceMethod("getError", &WebGLRenderingContext::GetError), + InstanceMethod("drawArrays", &WebGLRenderingContext::DrawArrays), + InstanceMethod("uniformMatrix2fv", &WebGLRenderingContext::UniformMatrix2fv), + InstanceMethod("uniformMatrix3fv", &WebGLRenderingContext::UniformMatrix3fv), + InstanceMethod("uniformMatrix4fv", &WebGLRenderingContext::UniformMatrix4fv), + InstanceMethod("generateMipmap", &WebGLRenderingContext::GenerateMipmap), + InstanceMethod("getAttribLocation", &WebGLRenderingContext::GetAttribLocation), + InstanceMethod("depthFunc", &WebGLRenderingContext::DepthFunc), + InstanceMethod("viewport", &WebGLRenderingContext::Viewport), + InstanceMethod("createShader", &WebGLRenderingContext::CreateShader), + InstanceMethod("shaderSource", &WebGLRenderingContext::ShaderSource), + InstanceMethod("compileShader", &WebGLRenderingContext::CompileShader), + InstanceMethod("getShaderParameter", &WebGLRenderingContext::GetShaderParameter), + InstanceMethod("getShaderInfoLog", &WebGLRenderingContext::GetShaderInfoLog), + InstanceMethod("createProgram", &WebGLRenderingContext::CreateProgram), + InstanceMethod("attachShader", &WebGLRenderingContext::AttachShader), + InstanceMethod("linkProgram", &WebGLRenderingContext::LinkProgram), + InstanceMethod("getProgramParameter", &WebGLRenderingContext::GetProgramParameter), + InstanceMethod("getUniformLocation", &WebGLRenderingContext::GetUniformLocation), + InstanceMethod("clearColor", &WebGLRenderingContext::ClearColor), + InstanceMethod("clearDepth", &WebGLRenderingContext::ClearDepth), + InstanceMethod("disable", &WebGLRenderingContext::Disable), + InstanceMethod("enable", &WebGLRenderingContext::Enable), + InstanceMethod("createTexture", &WebGLRenderingContext::CreateTexture), + InstanceMethod("bindTexture", &WebGLRenderingContext::BindTexture), + InstanceMethod("texImage2D", &WebGLRenderingContext::TexImage2D), + InstanceMethod("texParameteri", &WebGLRenderingContext::TexParameteri), + InstanceMethod("texParameterf", &WebGLRenderingContext::TexParameterf), + InstanceMethod("clear", &WebGLRenderingContext::Clear), + InstanceMethod("useProgram", &WebGLRenderingContext::UseProgram), + InstanceMethod("createBuffer", &WebGLRenderingContext::CreateBuffer), + InstanceMethod("bindBuffer", &WebGLRenderingContext::BindBuffer), + InstanceMethod("createFramebuffer", &WebGLRenderingContext::CreateFramebuffer), + InstanceMethod("bindFramebuffer", &WebGLRenderingContext::BindFramebuffer), + InstanceMethod("framebufferTexture2D", &WebGLRenderingContext::FramebufferTexture2D), + InstanceMethod("bufferData", &WebGLRenderingContext::BufferData), + InstanceMethod("bufferSubData", &WebGLRenderingContext::BufferSubData), + InstanceMethod("blendEquation", &WebGLRenderingContext::BlendEquation), + InstanceMethod("blendFunc", &WebGLRenderingContext::BlendFunc), + InstanceMethod("enableVertexAttribArray", &WebGLRenderingContext::EnableVertexAttribArray), + InstanceMethod("vertexAttribPointer", &WebGLRenderingContext::VertexAttribPointer), + InstanceMethod("activeTexture", &WebGLRenderingContext::ActiveTexture), + InstanceMethod("drawElements", &WebGLRenderingContext::DrawElements), + InstanceMethod("flush", &WebGLRenderingContext::Flush), + InstanceMethod("finish", &WebGLRenderingContext::Finish), + InstanceMethod("vertexAttrib1f", &WebGLRenderingContext::VertexAttrib1f), + InstanceMethod("vertexAttrib2f", &WebGLRenderingContext::VertexAttrib2f), + InstanceMethod("vertexAttrib3f", &WebGLRenderingContext::VertexAttrib3f), + InstanceMethod("vertexAttrib4f", &WebGLRenderingContext::VertexAttrib4f), + InstanceMethod("blendColor", &WebGLRenderingContext::BlendColor), + InstanceMethod("blendEquationSeparate", &WebGLRenderingContext::BlendEquationSeparate), + InstanceMethod("blendFuncSeparate", &WebGLRenderingContext::BlendFuncSeparate), + InstanceMethod("clearStencil", &WebGLRenderingContext::ClearStencil), + InstanceMethod("colorMask", &WebGLRenderingContext::ColorMask), + InstanceMethod("copyTexImage2D", &WebGLRenderingContext::CopyTexImage2D), + InstanceMethod("copyTexSubImage2D", &WebGLRenderingContext::CopyTexSubImage2D), + InstanceMethod("cullFace", &WebGLRenderingContext::CullFace), + InstanceMethod("depthMask", &WebGLRenderingContext::DepthMask), + InstanceMethod("depthRange", &WebGLRenderingContext::DepthRange), + InstanceMethod("hint", &WebGLRenderingContext::Hint), + InstanceMethod("isEnabled", &WebGLRenderingContext::IsEnabled), + InstanceMethod("lineWidth", &WebGLRenderingContext::LineWidth), + InstanceMethod("polygonOffset", &WebGLRenderingContext::PolygonOffset), + InstanceMethod("getShaderPrecisionFormat", &WebGLRenderingContext::GetShaderPrecisionFormat), + InstanceMethod("stencilFunc", &WebGLRenderingContext::StencilFunc), + InstanceMethod("stencilFuncSeparate", &WebGLRenderingContext::StencilFuncSeparate), + InstanceMethod("stencilMask", &WebGLRenderingContext::StencilMask), + InstanceMethod("stencilMaskSeparate", &WebGLRenderingContext::StencilMaskSeparate), + InstanceMethod("stencilOp", &WebGLRenderingContext::StencilOp), + InstanceMethod("stencilOpSeparate", &WebGLRenderingContext::StencilOpSeparate), + InstanceMethod("scissor", &WebGLRenderingContext::Scissor), + InstanceMethod("bindRenderbuffer", &WebGLRenderingContext::BindRenderbuffer), + InstanceMethod("createRenderbuffer", &WebGLRenderingContext::CreateRenderbuffer), + InstanceMethod("framebufferRenderbuffer", &WebGLRenderingContext::FramebufferRenderbuffer), + InstanceMethod("deleteBuffer", &WebGLRenderingContext::DeleteBuffer), + InstanceMethod("deleteFramebuffer", &WebGLRenderingContext::DeleteFramebuffer), + InstanceMethod("deleteProgram", &WebGLRenderingContext::DeleteProgram), + InstanceMethod("deleteRenderbuffer", &WebGLRenderingContext::DeleteRenderbuffer), + InstanceMethod("deleteShader", &WebGLRenderingContext::DeleteShader), + InstanceMethod("deleteTexture", &WebGLRenderingContext::DeleteTexture), + InstanceMethod("detachShader", &WebGLRenderingContext::DetachShader), + InstanceMethod("getVertexAttribOffset", &WebGLRenderingContext::GetVertexAttribOffset), + InstanceMethod("disableVertexAttribArray", &WebGLRenderingContext::DisableVertexAttribArray), + InstanceMethod("isBuffer", &WebGLRenderingContext::IsBuffer), + InstanceMethod("isFramebuffer", &WebGLRenderingContext::IsFramebuffer), + InstanceMethod("isProgram", &WebGLRenderingContext::IsProgram), + InstanceMethod("isRenderbuffer", &WebGLRenderingContext::IsRenderbuffer), + InstanceMethod("isShader", &WebGLRenderingContext::IsShader), + InstanceMethod("isTexture", &WebGLRenderingContext::IsTexture), + InstanceMethod("renderbufferStorage", &WebGLRenderingContext::RenderbufferStorage), + InstanceMethod("getShaderSource", &WebGLRenderingContext::GetShaderSource), + InstanceMethod("validateProgram", &WebGLRenderingContext::ValidateProgram), + InstanceMethod("texSubImage2D", &WebGLRenderingContext::TexSubImage2D), + InstanceMethod("readPixels", &WebGLRenderingContext::ReadPixels), + InstanceMethod("getTexParameter", &WebGLRenderingContext::GetTexParameter), + InstanceMethod("getActiveAttrib", &WebGLRenderingContext::GetActiveAttrib), + InstanceMethod("getActiveUniform", &WebGLRenderingContext::GetActiveUniform), + InstanceMethod("getAttachedShaders", &WebGLRenderingContext::GetAttachedShaders), + InstanceMethod("getParameter", &WebGLRenderingContext::GetParameter), + InstanceMethod("getBufferParameter", &WebGLRenderingContext::GetBufferParameter), + InstanceMethod("getFramebufferAttachmentParameter", &WebGLRenderingContext::GetFramebufferAttachmentParameter), + InstanceMethod("getProgramInfoLog", &WebGLRenderingContext::GetProgramInfoLog), + InstanceMethod("getRenderbufferParameter", &WebGLRenderingContext::GetRenderbufferParameter), + InstanceMethod("getVertexAttrib", &WebGLRenderingContext::GetVertexAttrib), + InstanceMethod("getSupportedExtensions", &WebGLRenderingContext::GetSupportedExtensions), + InstanceMethod("getExtension", &WebGLRenderingContext::GetExtension), + InstanceMethod("checkFramebufferStatus", &WebGLRenderingContext::CheckFramebufferStatus), + InstanceMethod("frontFace", &WebGLRenderingContext::FrontFace), + InstanceMethod("sampleCoverage", &WebGLRenderingContext::SampleCoverage), + InstanceMethod("drawBuffersWEBGL", &WebGLRenderingContext::DrawBuffersWEBGL), + InstanceMethod("extWEBGL_draw_buffers", &WebGLRenderingContext::EXTWEBGL_draw_buffers), + InstanceMethod("createVertexArrayOES", &WebGLRenderingContext::CreateVertexArrayOES), + InstanceMethod("deleteVertexArrayOES", &WebGLRenderingContext::DeleteVertexArrayOES), + InstanceMethod("isVertexArrayOES", &WebGLRenderingContext::IsVertexArrayOES), + InstanceMethod("bindVertexArrayOES", &WebGLRenderingContext::BindVertexArrayOES), + InstanceMethod("vertexAttribDivisor", &WebGLRenderingContext::VertexAttribDivisor), + InstanceMethod("getFragDataLocation", &WebGLRenderingContext::GetFragDataLocation), + InstanceMethod("destroy", &WebGLRenderingContext::Destroy), + InstanceMethod("setError", &WebGLRenderingContext::SetError), + // WebGL 2 methods + InstanceMethod("uniform1ui", &WebGLRenderingContext::Uniform1ui), + InstanceMethod("uniform2ui", &WebGLRenderingContext::Uniform2ui), + InstanceMethod("uniform3ui", &WebGLRenderingContext::Uniform3ui), + InstanceMethod("uniform4ui", &WebGLRenderingContext::Uniform4ui), + InstanceMethod("uniform1uiv", &WebGLRenderingContext::Uniform1uiv), + InstanceMethod("uniform2uiv", &WebGLRenderingContext::Uniform2uiv), + InstanceMethod("uniform3uiv", &WebGLRenderingContext::Uniform3uiv), + InstanceMethod("uniform4uiv", &WebGLRenderingContext::Uniform4uiv), + InstanceMethod("uniformMatrix2x3fv", &WebGLRenderingContext::UniformMatrix2x3fv), + InstanceMethod("uniformMatrix3x2fv", &WebGLRenderingContext::UniformMatrix3x2fv), + InstanceMethod("uniformMatrix2x4fv", &WebGLRenderingContext::UniformMatrix2x4fv), + InstanceMethod("uniformMatrix4x2fv", &WebGLRenderingContext::UniformMatrix4x2fv), + InstanceMethod("uniformMatrix3x4fv", &WebGLRenderingContext::UniformMatrix3x4fv), + InstanceMethod("uniformMatrix4x3fv", &WebGLRenderingContext::UniformMatrix4x3fv), + InstanceMethod("vertexAttribI4i", &WebGLRenderingContext::VertexAttribI4i), + InstanceMethod("vertexAttribI4ui", &WebGLRenderingContext::VertexAttribI4ui), + InstanceMethod("vertexAttribI4iv", &WebGLRenderingContext::VertexAttribI4iv), + InstanceMethod("vertexAttribI4uiv", &WebGLRenderingContext::VertexAttribI4uiv), + InstanceMethod("vertexAttribIPointer", &WebGLRenderingContext::VertexAttribIPointer), + InstanceMethod("drawArraysInstanced", &WebGLRenderingContext::DrawArraysInstanced), + InstanceMethod("drawElementsInstanced", &WebGLRenderingContext::DrawElementsInstanced), + InstanceMethod("drawRangeElements", &WebGLRenderingContext::DrawRangeElements), + InstanceMethod("drawBuffers", &WebGLRenderingContext::DrawBuffers), + InstanceMethod("clearBufferiv", &WebGLRenderingContext::ClearBufferiv), + InstanceMethod("clearBufferuiv", &WebGLRenderingContext::ClearBufferuiv), + InstanceMethod("clearBufferfv", &WebGLRenderingContext::ClearBufferfv), + InstanceMethod("clearBufferfi", &WebGLRenderingContext::ClearBufferfi), + InstanceMethod("createQuery", &WebGLRenderingContext::CreateQuery), + InstanceMethod("deleteQuery", &WebGLRenderingContext::DeleteQuery), + InstanceMethod("isQuery", &WebGLRenderingContext::IsQuery), + InstanceMethod("beginQuery", &WebGLRenderingContext::BeginQuery), + InstanceMethod("endQuery", &WebGLRenderingContext::EndQuery), + InstanceMethod("getQuery", &WebGLRenderingContext::GetQuery), + InstanceMethod("getQueryParameter", &WebGLRenderingContext::GetQueryParameter), + InstanceMethod("createSampler", &WebGLRenderingContext::CreateSampler), + InstanceMethod("deleteSampler", &WebGLRenderingContext::DeleteSampler), + InstanceMethod("isSampler", &WebGLRenderingContext::IsSampler), + InstanceMethod("bindSampler", &WebGLRenderingContext::BindSampler), + InstanceMethod("samplerParameteri", &WebGLRenderingContext::SamplerParameteri), + InstanceMethod("samplerParameterf", &WebGLRenderingContext::SamplerParameterf), + InstanceMethod("getSamplerParameter", &WebGLRenderingContext::GetSamplerParameter), + InstanceMethod("fenceSync", &WebGLRenderingContext::FenceSync), + InstanceMethod("isSync", &WebGLRenderingContext::IsSync), + InstanceMethod("deleteSync", &WebGLRenderingContext::DeleteSync), + InstanceMethod("clientWaitSync", &WebGLRenderingContext::ClientWaitSync), + InstanceMethod("waitSync", &WebGLRenderingContext::WaitSync), + InstanceMethod("getSyncParameter", &WebGLRenderingContext::GetSyncParameter), + InstanceMethod("createTransformFeedback", &WebGLRenderingContext::CreateTransformFeedback), + InstanceMethod("deleteTransformFeedback", &WebGLRenderingContext::DeleteTransformFeedback), + InstanceMethod("isTransformFeedback", &WebGLRenderingContext::IsTransformFeedback), + InstanceMethod("bindTransformFeedback", &WebGLRenderingContext::BindTransformFeedback), + InstanceMethod("beginTransformFeedback", &WebGLRenderingContext::BeginTransformFeedback), + InstanceMethod("endTransformFeedback", &WebGLRenderingContext::EndTransformFeedback), + InstanceMethod("transformFeedbackVaryings", &WebGLRenderingContext::TransformFeedbackVaryings), + InstanceMethod("getTransformFeedbackVarying", &WebGLRenderingContext::GetTransformFeedbackVarying), + InstanceMethod("pauseTransformFeedback", &WebGLRenderingContext::PauseTransformFeedback), + InstanceMethod("resumeTransformFeedback", &WebGLRenderingContext::ResumeTransformFeedback), + InstanceMethod("bindBufferBase", &WebGLRenderingContext::BindBufferBase), + InstanceMethod("bindBufferRange", &WebGLRenderingContext::BindBufferRange), + InstanceMethod("getIndexedParameter", &WebGLRenderingContext::GetIndexedParameter), + InstanceMethod("getUniformIndices", &WebGLRenderingContext::GetUniformIndices), + InstanceMethod("getActiveUniforms", &WebGLRenderingContext::GetActiveUniforms), + InstanceMethod("getUniformBlockIndex", &WebGLRenderingContext::GetUniformBlockIndex), + InstanceMethod("getActiveUniformBlockParameter", &WebGLRenderingContext::GetActiveUniformBlockParameter), + InstanceMethod("getActiveUniformBlockName", &WebGLRenderingContext::GetActiveUniformBlockName), + InstanceMethod("uniformBlockBinding", &WebGLRenderingContext::UniformBlockBinding), + InstanceMethod("createVertexArray", &WebGLRenderingContext::CreateVertexArray), + InstanceMethod("deleteVertexArray", &WebGLRenderingContext::DeleteVertexArray), + InstanceMethod("isVertexArray", &WebGLRenderingContext::IsVertexArray), + InstanceMethod("bindVertexArray", &WebGLRenderingContext::BindVertexArray), + InstanceMethod("copyBufferSubData", &WebGLRenderingContext::CopyBufferSubData), + InstanceMethod("getBufferSubData", &WebGLRenderingContext::GetBufferSubData), + InstanceMethod("blitFramebuffer", &WebGLRenderingContext::BlitFramebuffer), + InstanceMethod("framebufferTextureLayer", &WebGLRenderingContext::FramebufferTextureLayer), + InstanceMethod("invalidateFramebuffer", &WebGLRenderingContext::InvalidateFramebuffer), + InstanceMethod("invalidateSubFramebuffer", &WebGLRenderingContext::InvalidateSubFramebuffer), + InstanceMethod("readBuffer", &WebGLRenderingContext::ReadBuffer), + InstanceMethod("getInternalformatParameter", &WebGLRenderingContext::GetInternalformatParameter), + InstanceMethod("renderbufferStorageMultisample", &WebGLRenderingContext::RenderbufferStorageMultisample), + InstanceMethod("texStorage2D", &WebGLRenderingContext::TexStorage2D), + InstanceMethod("texStorage3D", &WebGLRenderingContext::TexStorage3D), + InstanceMethod("texImage3D", &WebGLRenderingContext::TexImage3D), + InstanceMethod("texSubImage3D", &WebGLRenderingContext::TexSubImage3D), + InstanceMethod("copyTexSubImage3D", &WebGLRenderingContext::CopyTexSubImage3D), + InstanceMethod("compressedTexImage3D", &WebGLRenderingContext::CompressedTexImage3D), + InstanceMethod("compressedTexSubImage3D", &WebGLRenderingContext::CompressedTexSubImage3D), + }); } GL_METHOD(Destroy) { GL_BOILERPLATE inst->dispose(); + return env.Undefined(); } GL_METHOD(Uniform1f) { GL_BOILERPLATE; - int location = Nan::To(info[0]).ToChecked(); - float x = (float)Nan::To(info[1]).ToChecked(); + int location = info[0].As().Int32Value(); + float x = (float)info[1].As().DoubleValue(); glUniform1f(location, x); + return env.Undefined(); } GL_METHOD(Uniform2f) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLfloat x = static_cast(Nan::To(info[1]).ToChecked()); - GLfloat y = static_cast(Nan::To(info[2]).ToChecked()); + GLint location = info[0].As().Int32Value(); + GLfloat x = static_cast(info[1].As().DoubleValue()); + GLfloat y = static_cast(info[2].As().DoubleValue()); glUniform2f(location, x, y); + return env.Undefined(); } GL_METHOD(Uniform3f) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLfloat x = static_cast(Nan::To(info[1]).ToChecked()); - GLfloat y = static_cast(Nan::To(info[2]).ToChecked()); - GLfloat z = static_cast(Nan::To(info[3]).ToChecked()); + GLint location = info[0].As().Int32Value(); + GLfloat x = static_cast(info[1].As().DoubleValue()); + GLfloat y = static_cast(info[2].As().DoubleValue()); + GLfloat z = static_cast(info[3].As().DoubleValue()); glUniform3f(location, x, y, z); + return env.Undefined(); } GL_METHOD(Uniform4f) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLfloat x = static_cast(Nan::To(info[1]).ToChecked()); - GLfloat y = static_cast(Nan::To(info[2]).ToChecked()); - GLfloat z = static_cast(Nan::To(info[3]).ToChecked()); - GLfloat w = static_cast(Nan::To(info[4]).ToChecked()); + GLint location = info[0].As().Int32Value(); + GLfloat x = static_cast(info[1].As().DoubleValue()); + GLfloat y = static_cast(info[2].As().DoubleValue()); + GLfloat z = static_cast(info[3].As().DoubleValue()); + GLfloat w = static_cast(info[4].As().DoubleValue()); glUniform4f(location, x, y, z, w); + return env.Undefined(); } GL_METHOD(Uniform1i) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLint x = Nan::To(info[1]).ToChecked(); + GLint location = info[0].As().Int32Value(); + GLint x = info[1].As().Int32Value(); glUniform1i(location, x); + return env.Undefined(); } GL_METHOD(Uniform2i) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLint x = Nan::To(info[1]).ToChecked(); - GLint y = Nan::To(info[2]).ToChecked(); + GLint location = info[0].As().Int32Value(); + GLint x = info[1].As().Int32Value(); + GLint y = info[2].As().Int32Value(); glUniform2i(location, x, y); + return env.Undefined(); } GL_METHOD(Uniform3i) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLint x = Nan::To(info[1]).ToChecked(); - GLint y = Nan::To(info[2]).ToChecked(); - GLint z = Nan::To(info[3]).ToChecked(); + GLint location = info[0].As().Int32Value(); + GLint x = info[1].As().Int32Value(); + GLint y = info[2].As().Int32Value(); + GLint z = info[3].As().Int32Value(); glUniform3i(location, x, y, z); + return env.Undefined(); } GL_METHOD(Uniform4i) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLint x = Nan::To(info[1]).ToChecked(); - GLint y = Nan::To(info[2]).ToChecked(); - GLint z = Nan::To(info[3]).ToChecked(); - GLint w = Nan::To(info[4]).ToChecked(); + GLint location = info[0].As().Int32Value(); + GLint x = info[1].As().Int32Value(); + GLint y = info[2].As().Int32Value(); + GLint z = info[3].As().Int32Value(); + GLint w = info[4].As().Int32Value(); glUniform4i(location, x, y, z, w); + return env.Undefined(); } GL_METHOD(PixelStorei) { GL_BOILERPLATE; - GLenum pname = Nan::To(info[0]).ToChecked(); - GLenum param = Nan::To(info[1]).ToChecked(); + GLenum pname = info[0].As().Int32Value(); + GLenum param = info[1].As().Int32Value(); // Handle WebGL specific extensions switch (pname) { @@ -599,16 +826,18 @@ GL_METHOD(PixelStorei) { glPixelStorei(pname, param); break; } + return env.Undefined(); } GL_METHOD(BindAttribLocation) { GL_BOILERPLATE; - GLint program = Nan::To(info[0]).ToChecked(); - GLint index = Nan::To(info[1]).ToChecked(); - Nan::Utf8String name(info[2]); + GLint program = info[0].As().Int32Value(); + GLint index = info[1].As().Int32Value(); + std::string name = info[2].As().Utf8Value(); - glBindAttribLocation(program, index, *name); + glBindAttribLocation(program, index, name.c_str()); + return env.Undefined(); } GLenum WebGLRenderingContext::getError() { @@ -624,166 +853,188 @@ GLenum WebGLRenderingContext::getError() { GL_METHOD(GetError) { GL_BOILERPLATE; - info.GetReturnValue().Set(Nan::New(inst->getError())); + return Napi::Number::New(env, inst->getError()); } GL_METHOD(VertexAttribDivisorANGLE) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLuint divisor = Nan::To(info[1]).ToChecked(); + GLuint index = info[0].As().Uint32Value(); + GLuint divisor = info[1].As().Uint32Value(); glVertexAttribDivisorANGLE(index, divisor); + return env.Undefined(); } GL_METHOD(DrawArraysInstancedANGLE) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); - GLint first = Nan::To(info[1]).ToChecked(); - GLuint count = Nan::To(info[2]).ToChecked(); - GLuint icount = Nan::To(info[3]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); + GLint first = info[1].As().Int32Value(); + GLuint count = info[2].As().Uint32Value(); + GLuint icount = info[3].As().Uint32Value(); glDrawArraysInstancedANGLE(mode, first, count, icount); + return env.Undefined(); } GL_METHOD(DrawElementsInstancedANGLE) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); - GLint count = Nan::To(info[1]).ToChecked(); - GLenum type = Nan::To(info[2]).ToChecked(); - GLint offset = Nan::To(info[3]).ToChecked(); - GLuint icount = Nan::To(info[4]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); + GLint count = info[1].As().Int32Value(); + GLenum type = info[2].As().Int32Value(); + GLint offset = info[3].As().Int32Value(); + GLuint icount = info[4].As().Uint32Value(); glDrawElementsInstancedANGLE(mode, count, type, reinterpret_cast(static_cast(offset)), icount); + return env.Undefined(); } GL_METHOD(DrawArrays) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); - GLint first = Nan::To(info[1]).ToChecked(); - GLint count = Nan::To(info[2]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); + GLint first = info[1].As().Int32Value(); + GLint count = info[2].As().Int32Value(); glDrawArrays(mode, first, count); + return env.Undefined(); } GL_METHOD(UniformMatrix2fv) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = (Nan::To(info[1]).ToChecked()); - Nan::TypedArrayContents data(info[2]); + GLint location = info[0].As().Int32Value(); + GLboolean transpose = (info[1].As().Value()); + auto _arr_data = info[2].As(); + GLfloat* data = reinterpret_cast( + static_cast(_arr_data.ArrayBuffer().Data()) + _arr_data.ByteOffset()); + size_t data_len = _arr_data.ElementLength(); - glUniformMatrix2fv(location, data.length() / 4, transpose, *data); + glUniformMatrix2fv(location, data_len / 4, transpose, data); + return env.Undefined(); } GL_METHOD(UniformMatrix3fv) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = (Nan::To(info[1]).ToChecked()); - Nan::TypedArrayContents data(info[2]); + GLint location = info[0].As().Int32Value(); + GLboolean transpose = (info[1].As().Value()); + auto _arr_data = info[2].As(); + GLfloat* data = reinterpret_cast( + static_cast(_arr_data.ArrayBuffer().Data()) + _arr_data.ByteOffset()); + size_t data_len = _arr_data.ElementLength(); - glUniformMatrix3fv(location, data.length() / 9, transpose, *data); + glUniformMatrix3fv(location, data_len / 9, transpose, data); + return env.Undefined(); } GL_METHOD(UniformMatrix4fv) { GL_BOILERPLATE; - GLint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = (Nan::To(info[1]).ToChecked()); - Nan::TypedArrayContents data(info[2]); + GLint location = info[0].As().Int32Value(); + GLboolean transpose = (info[1].As().Value()); + auto _arr_data = info[2].As(); + GLfloat* data = reinterpret_cast( + static_cast(_arr_data.ArrayBuffer().Data()) + _arr_data.ByteOffset()); + size_t data_len = _arr_data.ElementLength(); - glUniformMatrix4fv(location, data.length() / 16, transpose, *data); + glUniformMatrix4fv(location, data_len / 16, transpose, data); + return env.Undefined(); } GL_METHOD(GenerateMipmap) { GL_BOILERPLATE; - GLint target = Nan::To(info[0]).ToChecked(); + GLint target = info[0].As().Int32Value(); glGenerateMipmap(target); + return env.Undefined(); } GL_METHOD(GetAttribLocation) { GL_BOILERPLATE; - GLint program = Nan::To(info[0]).ToChecked(); - Nan::Utf8String name(info[1]); + GLint program = info[0].As().Int32Value(); + std::string name = info[1].As().Utf8Value(); - GLint result = glGetAttribLocation(program, *name); + GLint result = glGetAttribLocation(program, name.c_str()); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } GL_METHOD(DepthFunc) { GL_BOILERPLATE; - glDepthFunc(Nan::To(info[0]).ToChecked()); + glDepthFunc(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(Viewport) { GL_BOILERPLATE; - GLint x = Nan::To(info[0]).ToChecked(); - GLint y = Nan::To(info[1]).ToChecked(); - GLsizei width = Nan::To(info[2]).ToChecked(); - GLsizei height = Nan::To(info[3]).ToChecked(); + GLint x = info[0].As().Int32Value(); + GLint y = info[1].As().Int32Value(); + GLsizei width = info[2].As().Int32Value(); + GLsizei height = info[3].As().Int32Value(); glViewport(x, y, width, height); + return env.Undefined(); } GL_METHOD(CreateShader) { GL_BOILERPLATE; - GLuint shader = glCreateShader(Nan::To(info[0]).ToChecked()); + GLuint shader = glCreateShader(info[0].As().Int32Value()); inst->registerGLObj(GLOBJECT_TYPE_SHADER, shader); - info.GetReturnValue().Set(Nan::New(shader)); + return Napi::Number::New(env, shader); } GL_METHOD(ShaderSource) { GL_BOILERPLATE; - GLint id = Nan::To(info[0]).ToChecked(); - Nan::Utf8String code(info[1]); + GLint id = info[0].As().Int32Value(); + std::string code = info[1].As().Utf8Value(); - const char *codes[] = {*code}; + const char *codes[] = {code.c_str()}; GLint length = code.length(); glShaderSource(id, 1, codes, &length); + return env.Undefined(); } GL_METHOD(CompileShader) { GL_BOILERPLATE; - glCompileShader(Nan::To(info[0]).ToChecked()); + glCompileShader(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(FrontFace) { GL_BOILERPLATE; - glFrontFace(Nan::To(info[0]).ToChecked()); + glFrontFace(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(GetShaderParameter) { GL_BOILERPLATE; - GLint shader = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLint shader = info[0].As().Int32Value(); + GLenum pname = info[1].As().Int32Value(); GLint value; glGetShaderiv(shader, pname, &value); - info.GetReturnValue().Set(Nan::New(value)); + return Napi::Number::New(env, value); } GL_METHOD(GetShaderInfoLog) { GL_BOILERPLATE; - GLint id = Nan::To(info[0]).ToChecked(); + GLint id = info[0].As().Int32Value(); GLint infoLogLength; glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infoLogLength); @@ -791,9 +1042,10 @@ GL_METHOD(GetShaderInfoLog) { char *error = new char[infoLogLength + 1]; glGetShaderInfoLog(id, infoLogLength + 1, &infoLogLength, error); - info.GetReturnValue().Set(Nan::New(error).ToLocalChecked()); + return Napi::String::New(env, error); delete[] error; + return env.Undefined(); } GL_METHOD(CreateProgram) { @@ -802,68 +1054,73 @@ GL_METHOD(CreateProgram) { GLuint program = glCreateProgram(); inst->registerGLObj(GLOBJECT_TYPE_PROGRAM, program); - info.GetReturnValue().Set(Nan::New(program)); + return Napi::Number::New(env, program); } GL_METHOD(AttachShader) { GL_BOILERPLATE; - GLint program = Nan::To(info[0]).ToChecked(); - GLint shader = Nan::To(info[1]).ToChecked(); + GLint program = info[0].As().Int32Value(); + GLint shader = info[1].As().Int32Value(); glAttachShader(program, shader); + return env.Undefined(); } GL_METHOD(ValidateProgram) { GL_BOILERPLATE; - glValidateProgram(Nan::To(info[0]).ToChecked()); + glValidateProgram(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(LinkProgram) { GL_BOILERPLATE; - glLinkProgram(Nan::To(info[0]).ToChecked()); + glLinkProgram(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(GetProgramParameter) { GL_BOILERPLATE; - GLint program = Nan::To(info[0]).ToChecked(); - GLenum pname = (GLenum)(Nan::To(info[1]).ToChecked()); + GLint program = info[0].As().Int32Value(); + GLenum pname = (GLenum)(info[1].As().Int32Value()); GLint value = 0; glGetProgramiv(program, pname, &value); - info.GetReturnValue().Set(Nan::New(value)); + return Napi::Number::New(env, value); } GL_METHOD(GetUniformLocation) { GL_BOILERPLATE; - GLint program = Nan::To(info[0]).ToChecked(); - Nan::Utf8String name(info[1]); + GLint program = info[0].As().Int32Value(); + std::string name = info[1].As().Utf8Value(); - info.GetReturnValue().Set(Nan::New(glGetUniformLocation(program, *name))); + return Napi::Number::New(env, glGetUniformLocation(program, name.c_str())); } GL_METHOD(ClearColor) { GL_BOILERPLATE; - GLfloat red = static_cast(Nan::To(info[0]).ToChecked()); - GLfloat green = static_cast(Nan::To(info[1]).ToChecked()); - GLfloat blue = static_cast(Nan::To(info[2]).ToChecked()); - GLfloat alpha = static_cast(Nan::To(info[3]).ToChecked()); + GLfloat red = static_cast(info[0].As().DoubleValue()); + GLfloat green = static_cast(info[1].As().DoubleValue()); + GLfloat blue = static_cast(info[2].As().DoubleValue()); + GLfloat alpha = static_cast(info[3].As().DoubleValue()); glClearColor(red, green, blue, alpha); + return env.Undefined(); } GL_METHOD(ClearDepth) { GL_BOILERPLATE; - GLfloat depth = static_cast(Nan::To(info[0]).ToChecked()); + GLfloat depth = static_cast(info[0].As().DoubleValue()); glClearDepthf(depth); + return env.Undefined(); } // Two specific enums are accepted by ANGLE when they shouldn't be. This shows up @@ -874,25 +1131,27 @@ bool IsBuggedANGLECap(GLenum cap) { return cap == GL_MULTISAMPLE || cap == GL_SA GL_METHOD(Disable) { GL_BOILERPLATE; - GLenum cap = Nan::To(info[0]).ToChecked(); + GLenum cap = info[0].As().Int32Value(); if (IsBuggedANGLECap(cap)) { inst->setError(GL_INVALID_ENUM); } else { glDisable(cap); } + return env.Undefined(); } GL_METHOD(Enable) { GL_BOILERPLATE; - GLenum cap = Nan::To(info[0]).ToChecked(); + GLenum cap = info[0].As().Int32Value(); if (IsBuggedANGLECap(cap)) { inst->setError(GL_INVALID_ENUM); } else { glEnable(cap); } + return env.Undefined(); } GL_METHOD(CreateTexture) { @@ -902,16 +1161,17 @@ GL_METHOD(CreateTexture) { glGenTextures(1, &texture); inst->registerGLObj(GLOBJECT_TYPE_TEXTURE, texture); - info.GetReturnValue().Set(Nan::New(texture)); + return Napi::Number::New(env, texture); } GL_METHOD(BindTexture) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint texture = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLint texture = info[1].As().Int32Value(); glBindTexture(target, texture); + return env.Undefined(); } std::vector WebGLRenderingContext::unpackPixels(GLenum type, GLenum format, GLint width, @@ -1016,83 +1276,99 @@ void CallTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei w GL_METHOD(TexImage2D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLenum internalformat = Nan::To(info[2]).ToChecked(); - GLsizei width = Nan::To(info[3]).ToChecked(); - GLsizei height = Nan::To(info[4]).ToChecked(); - GLint border = Nan::To(info[5]).ToChecked(); - GLenum format = Nan::To(info[6]).ToChecked(); - GLint type = Nan::To(info[7]).ToChecked(); - Nan::TypedArrayContents pixels(info[8]); - - if (*pixels) { + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLenum internalformat = info[2].As().Int32Value(); + GLsizei width = info[3].As().Int32Value(); + GLsizei height = info[4].As().Int32Value(); + GLint border = info[5].As().Int32Value(); + GLenum format = info[6].As().Int32Value(); + GLint type = info[7].As().Int32Value(); + unsigned char* pixels = nullptr; + size_t pixels_len = 0; + if (!info[8].IsNull() && !info[8].IsUndefined()) { + auto _arr_pixels = info[8].As(); + pixels = reinterpret_cast( + static_cast(_arr_pixels.ArrayBuffer().Data()) + _arr_pixels.ByteOffset()); + pixels_len = _arr_pixels.ByteLength(); + } + + if (pixels) { if (inst->unpack_flip_y || inst->unpack_premultiply_alpha) { - std::vector unpacked = inst->unpackPixels(type, format, width, height, *pixels); + std::vector unpacked = inst->unpackPixels(type, format, width, height, pixels); CallTexImage2D(target, level, internalformat, width, height, border, format, type, unpacked.size(), unpacked.data()); } else { CallTexImage2D(target, level, internalformat, width, height, border, format, type, - pixels.length(), *pixels); + pixels_len, pixels); } } else { CallTexImage2D(target, level, internalformat, width, height, border, format, type, 0, nullptr); } + return env.Undefined(); } GL_METHOD(TexSubImage2D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLint xoffset = Nan::To(info[2]).ToChecked(); - GLint yoffset = Nan::To(info[3]).ToChecked(); - GLsizei width = Nan::To(info[4]).ToChecked(); - GLsizei height = Nan::To(info[5]).ToChecked(); - GLenum format = Nan::To(info[6]).ToChecked(); - GLenum type = Nan::To(info[7]).ToChecked(); - Nan::TypedArrayContents pixels(info[8]); + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLint xoffset = info[2].As().Int32Value(); + GLint yoffset = info[3].As().Int32Value(); + GLsizei width = info[4].As().Int32Value(); + GLsizei height = info[5].As().Int32Value(); + GLenum format = info[6].As().Int32Value(); + GLenum type = info[7].As().Int32Value(); + auto _arr_pixels2 = info[8].As(); + unsigned char* pixels = reinterpret_cast( + static_cast(_arr_pixels2.ArrayBuffer().Data()) + _arr_pixels2.ByteOffset()); + size_t pixels_len = _arr_pixels2.ByteLength(); if (inst->unpack_flip_y || inst->unpack_premultiply_alpha) { - std::vector unpacked = inst->unpackPixels(type, format, width, height, *pixels); + std::vector unpacked = inst->unpackPixels(type, format, width, height, pixels); glTexSubImage2DRobustANGLE(target, level, xoffset, yoffset, width, height, format, type, unpacked.size(), unpacked.data()); } else { glTexSubImage2DRobustANGLE(target, level, xoffset, yoffset, width, height, format, type, - pixels.length(), *pixels); + pixels_len, pixels); } + return env.Undefined(); } GL_METHOD(TexParameteri) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); - GLint param = Nan::To(info[2]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum pname = info[1].As().Int32Value(); + GLint param = info[2].As().Int32Value(); glTexParameteri(target, pname, param); + return env.Undefined(); } GL_METHOD(TexParameterf) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); - GLfloat param = static_cast(Nan::To(info[2]).ToChecked()); + GLenum target = info[0].As().Int32Value(); + GLenum pname = info[1].As().Int32Value(); + GLfloat param = static_cast(info[2].As().DoubleValue()); glTexParameterf(target, pname, param); + return env.Undefined(); } GL_METHOD(Clear) { GL_BOILERPLATE; - glClear(Nan::To(info[0]).ToChecked()); + glClear(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(UseProgram) { GL_BOILERPLATE; - glUseProgram(Nan::To(info[0]).ToChecked()); + glUseProgram(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(CreateBuffer) { @@ -1102,16 +1378,17 @@ GL_METHOD(CreateBuffer) { glGenBuffers(1, &buffer); inst->registerGLObj(GLOBJECT_TYPE_BUFFER, buffer); - info.GetReturnValue().Set(Nan::New(buffer)); + return Napi::Number::New(env, buffer); } GL_METHOD(BindBuffer) { GL_BOILERPLATE; - GLenum target = (GLenum)Nan::To(info[0]).ToChecked(); - GLuint buffer = (GLuint)Nan::To(info[1]).ToChecked(); + GLenum target = (GLenum)info[0].As().Int32Value(); + GLuint buffer = (GLuint)info[1].As().Uint32Value(); glBindBuffer(target, buffer); + return env.Undefined(); } GL_METHOD(CreateFramebuffer) { @@ -1121,26 +1398,27 @@ GL_METHOD(CreateFramebuffer) { glGenFramebuffers(1, &buffer); inst->registerGLObj(GLOBJECT_TYPE_FRAMEBUFFER, buffer); - info.GetReturnValue().Set(Nan::New(buffer)); + return Napi::Number::New(env, buffer); } GL_METHOD(BindFramebuffer) { GL_BOILERPLATE; - GLint target = (GLint)Nan::To(info[0]).ToChecked(); - GLint buffer = (GLint)(Nan::To(info[1]).ToChecked()); + GLint target = (GLint)info[0].As().Int32Value(); + GLint buffer = (GLint)(info[1].As().Int32Value()); glBindFramebuffer(target, buffer); + return env.Undefined(); } GL_METHOD(FramebufferTexture2D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum attachment = Nan::To(info[1]).ToChecked(); - GLint textarget = Nan::To(info[2]).ToChecked(); - GLint texture = Nan::To(info[3]).ToChecked(); - GLint level = Nan::To(info[4]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum attachment = info[1].As().Int32Value(); + GLint textarget = info[2].As().Int32Value(); + GLint texture = info[3].As().Int32Value(); + GLint level = info[4].As().Int32Value(); // Handle depth stencil case separately if (attachment == 0x821A) { @@ -1149,373 +1427,417 @@ GL_METHOD(FramebufferTexture2D) { } else { glFramebufferTexture2D(target, attachment, textarget, texture, level); } + return env.Undefined(); } GL_METHOD(BufferData) { GL_BOILERPLATE; - GLint target = Nan::To(info[0]).ToChecked(); - GLenum usage = Nan::To(info[2]).ToChecked(); + GLint target = info[0].As().Int32Value(); + GLenum usage = info[2].As().Int32Value(); - if (info[1]->IsObject()) { - Nan::TypedArrayContents array(info[1]); - glBufferData(target, array.length(), static_cast(*array), usage); - } else if (info[1]->IsNumber()) { - glBufferData(target, Nan::To(info[1]).ToChecked(), NULL, usage); + if (info[1].IsObject()) { + auto _arr_array = info[1].As(); + char* array = reinterpret_cast( + static_cast(_arr_array.ArrayBuffer().Data()) + _arr_array.ByteOffset()); + size_t array_len = _arr_array.ElementLength(); + glBufferData(target, array_len, static_cast(array), usage); + } else if (info[1].IsNumber()) { + glBufferData(target, info[1].As().Int32Value(), NULL, usage); } + return env.Undefined(); } GL_METHOD(BufferSubData) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint offset = Nan::To(info[1]).ToChecked(); - Nan::TypedArrayContents array(info[2]); + GLenum target = info[0].As().Int32Value(); + GLint offset = info[1].As().Int32Value(); + auto _arr_array = info[2].As(); + char* array = reinterpret_cast( + static_cast(_arr_array.ArrayBuffer().Data()) + _arr_array.ByteOffset()); + size_t array_len = _arr_array.ElementLength(); - glBufferSubData(target, offset, array.length(), *array); + glBufferSubData(target, offset, array_len, array); + return env.Undefined(); } GL_METHOD(BlendEquation) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); glBlendEquation(mode); + return env.Undefined(); } GL_METHOD(BlendFunc) { GL_BOILERPLATE; - GLenum sfactor = Nan::To(info[0]).ToChecked(); - GLenum dfactor = Nan::To(info[1]).ToChecked(); + GLenum sfactor = info[0].As().Int32Value(); + GLenum dfactor = info[1].As().Int32Value(); glBlendFunc(sfactor, dfactor); + return env.Undefined(); } GL_METHOD(EnableVertexAttribArray) { GL_BOILERPLATE; - glEnableVertexAttribArray(Nan::To(info[0]).ToChecked()); + glEnableVertexAttribArray(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(VertexAttribPointer) { GL_BOILERPLATE; - GLint index = Nan::To(info[0]).ToChecked(); - GLint size = Nan::To(info[1]).ToChecked(); - GLenum type = Nan::To(info[2]).ToChecked(); - GLboolean normalized = Nan::To(info[3]).ToChecked(); - GLint stride = Nan::To(info[4]).ToChecked(); - size_t offset = Nan::To(info[5]).ToChecked(); + GLint index = info[0].As().Int32Value(); + GLint size = info[1].As().Int32Value(); + GLenum type = info[2].As().Int32Value(); + GLboolean normalized = info[3].As().Value(); + GLint stride = info[4].As().Int32Value(); + size_t offset = info[5].As().Uint32Value(); glVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast(offset)); + return env.Undefined(); } GL_METHOD(ActiveTexture) { GL_BOILERPLATE; - glActiveTexture(Nan::To(info[0]).ToChecked()); + glActiveTexture(info[0].As().Int32Value()); + return env.Undefined(); } GL_METHOD(DrawElements) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); - GLint count = Nan::To(info[1]).ToChecked(); - GLenum type = Nan::To(info[2]).ToChecked(); - size_t offset = Nan::To(info[3]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); + GLint count = info[1].As().Int32Value(); + GLenum type = info[2].As().Int32Value(); + size_t offset = info[3].As().Uint32Value(); glDrawElements(mode, count, type, reinterpret_cast(offset)); + return env.Undefined(); } GL_METHOD(Flush) { GL_BOILERPLATE; glFlush(); + return env.Undefined(); } GL_METHOD(Finish) { GL_BOILERPLATE; glFinish(); + return env.Undefined(); } GL_METHOD(VertexAttrib1f) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLfloat x = static_cast(Nan::To(info[1]).ToChecked()); + GLuint index = info[0].As().Int32Value(); + GLfloat x = static_cast(info[1].As().DoubleValue()); glVertexAttrib1f(index, x); + return env.Undefined(); } GL_METHOD(VertexAttrib2f) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLfloat x = static_cast(Nan::To(info[1]).ToChecked()); - GLfloat y = static_cast(Nan::To(info[2]).ToChecked()); + GLuint index = info[0].As().Int32Value(); + GLfloat x = static_cast(info[1].As().DoubleValue()); + GLfloat y = static_cast(info[2].As().DoubleValue()); glVertexAttrib2f(index, x, y); + return env.Undefined(); } GL_METHOD(VertexAttrib3f) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLfloat x = static_cast(Nan::To(info[1]).ToChecked()); - GLfloat y = static_cast(Nan::To(info[2]).ToChecked()); - GLfloat z = static_cast(Nan::To(info[3]).ToChecked()); + GLuint index = info[0].As().Int32Value(); + GLfloat x = static_cast(info[1].As().DoubleValue()); + GLfloat y = static_cast(info[2].As().DoubleValue()); + GLfloat z = static_cast(info[3].As().DoubleValue()); glVertexAttrib3f(index, x, y, z); + return env.Undefined(); } GL_METHOD(VertexAttrib4f) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLfloat x = static_cast(Nan::To(info[1]).ToChecked()); - GLfloat y = static_cast(Nan::To(info[2]).ToChecked()); - GLfloat z = static_cast(Nan::To(info[3]).ToChecked()); - GLfloat w = static_cast(Nan::To(info[4]).ToChecked()); + GLuint index = info[0].As().Int32Value(); + GLfloat x = static_cast(info[1].As().DoubleValue()); + GLfloat y = static_cast(info[2].As().DoubleValue()); + GLfloat z = static_cast(info[3].As().DoubleValue()); + GLfloat w = static_cast(info[4].As().DoubleValue()); glVertexAttrib4f(index, x, y, z, w); + return env.Undefined(); } GL_METHOD(BlendColor) { GL_BOILERPLATE; - GLclampf r = static_cast(Nan::To(info[0]).ToChecked()); - GLclampf g = static_cast(Nan::To(info[1]).ToChecked()); - GLclampf b = static_cast(Nan::To(info[2]).ToChecked()); - GLclampf a = static_cast(Nan::To(info[3]).ToChecked()); + GLclampf r = static_cast(info[0].As().DoubleValue()); + GLclampf g = static_cast(info[1].As().DoubleValue()); + GLclampf b = static_cast(info[2].As().DoubleValue()); + GLclampf a = static_cast(info[3].As().DoubleValue()); glBlendColor(r, g, b, a); + return env.Undefined(); } GL_METHOD(BlendEquationSeparate) { GL_BOILERPLATE; - GLenum mode_rgb = Nan::To(info[0]).ToChecked(); - GLenum mode_alpha = Nan::To(info[1]).ToChecked(); + GLenum mode_rgb = info[0].As().Int32Value(); + GLenum mode_alpha = info[1].As().Int32Value(); glBlendEquationSeparate(mode_rgb, mode_alpha); + return env.Undefined(); } GL_METHOD(BlendFuncSeparate) { GL_BOILERPLATE; - GLenum src_rgb = Nan::To(info[0]).ToChecked(); - GLenum dst_rgb = Nan::To(info[1]).ToChecked(); - GLenum src_alpha = Nan::To(info[2]).ToChecked(); - GLenum dst_alpha = Nan::To(info[3]).ToChecked(); + GLenum src_rgb = info[0].As().Int32Value(); + GLenum dst_rgb = info[1].As().Int32Value(); + GLenum src_alpha = info[2].As().Int32Value(); + GLenum dst_alpha = info[3].As().Int32Value(); glBlendFuncSeparate(src_rgb, dst_rgb, src_alpha, dst_alpha); + return env.Undefined(); } GL_METHOD(ClearStencil) { GL_BOILERPLATE; - GLint s = Nan::To(info[0]).ToChecked(); + GLint s = info[0].As().Int32Value(); glClearStencil(s); + return env.Undefined(); } GL_METHOD(ColorMask) { GL_BOILERPLATE; - GLboolean r = (Nan::To(info[0]).ToChecked()); - GLboolean g = (Nan::To(info[1]).ToChecked()); - GLboolean b = (Nan::To(info[2]).ToChecked()); - GLboolean a = (Nan::To(info[3]).ToChecked()); + GLboolean r = (info[0].As().Value()); + GLboolean g = (info[1].As().Value()); + GLboolean b = (info[2].As().Value()); + GLboolean a = (info[3].As().Value()); glColorMask(r, g, b, a); + return env.Undefined(); } GL_METHOD(CopyTexImage2D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLenum internalformat = Nan::To(info[2]).ToChecked(); - GLint x = Nan::To(info[3]).ToChecked(); - GLint y = Nan::To(info[4]).ToChecked(); - GLsizei width = Nan::To(info[5]).ToChecked(); - GLsizei height = Nan::To(info[6]).ToChecked(); - GLint border = Nan::To(info[7]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLenum internalformat = info[2].As().Int32Value(); + GLint x = info[3].As().Int32Value(); + GLint y = info[4].As().Int32Value(); + GLsizei width = info[5].As().Int32Value(); + GLsizei height = info[6].As().Int32Value(); + GLint border = info[7].As().Int32Value(); glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); + return env.Undefined(); } GL_METHOD(CopyTexSubImage2D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLint xoffset = Nan::To(info[2]).ToChecked(); - GLint yoffset = Nan::To(info[3]).ToChecked(); - GLint x = Nan::To(info[4]).ToChecked(); - GLint y = Nan::To(info[5]).ToChecked(); - GLsizei width = Nan::To(info[6]).ToChecked(); - GLsizei height = Nan::To(info[7]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLint xoffset = info[2].As().Int32Value(); + GLint yoffset = info[3].As().Int32Value(); + GLint x = info[4].As().Int32Value(); + GLint y = info[5].As().Int32Value(); + GLsizei width = info[6].As().Int32Value(); + GLsizei height = info[7].As().Int32Value(); glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); + return env.Undefined(); } GL_METHOD(CullFace) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); glCullFace(mode); + return env.Undefined(); } GL_METHOD(DepthMask) { GL_BOILERPLATE; - GLboolean flag = (Nan::To(info[0]).ToChecked()); + GLboolean flag = (info[0].As().Value()); glDepthMask(flag); + return env.Undefined(); } GL_METHOD(DepthRange) { GL_BOILERPLATE; - GLclampf zNear = static_cast(Nan::To(info[0]).ToChecked()); - GLclampf zFar = static_cast(Nan::To(info[1]).ToChecked()); + GLclampf zNear = static_cast(info[0].As().DoubleValue()); + GLclampf zFar = static_cast(info[1].As().DoubleValue()); glDepthRangef(zNear, zFar); + return env.Undefined(); } GL_METHOD(DisableVertexAttribArray) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); + GLuint index = info[0].As().Int32Value(); glDisableVertexAttribArray(index); + return env.Undefined(); } GL_METHOD(Hint) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum mode = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum mode = info[1].As().Int32Value(); glHint(target, mode); + return env.Undefined(); } GL_METHOD(IsEnabled) { GL_BOILERPLATE; - GLenum cap = Nan::To(info[0]).ToChecked(); + GLenum cap = info[0].As().Int32Value(); bool ret = glIsEnabled(cap) != 0; - info.GetReturnValue().Set(Nan::New(ret)); + return Napi::Boolean::New(env, ret); } GL_METHOD(LineWidth) { GL_BOILERPLATE; - GLfloat width = (GLfloat)(Nan::To(info[0]).ToChecked()); + GLfloat width = (GLfloat)(info[0].As().DoubleValue()); glLineWidth(width); + return env.Undefined(); } GL_METHOD(PolygonOffset) { GL_BOILERPLATE; - GLfloat factor = static_cast(Nan::To(info[0]).ToChecked()); - GLfloat units = static_cast(Nan::To(info[1]).ToChecked()); + GLfloat factor = static_cast(info[0].As().DoubleValue()); + GLfloat units = static_cast(info[1].As().DoubleValue()); glPolygonOffset(factor, units); + return env.Undefined(); } GL_METHOD(SampleCoverage) { GL_BOILERPLATE; - GLclampf value = static_cast(Nan::To(info[0]).ToChecked()); - GLboolean invert = (Nan::To(info[1]).ToChecked()); + GLclampf value = static_cast(info[0].As().DoubleValue()); + GLboolean invert = (info[1].As().Value()); glSampleCoverage(value, invert); + return env.Undefined(); } GL_METHOD(Scissor) { GL_BOILERPLATE; - GLint x = Nan::To(info[0]).ToChecked(); - GLint y = Nan::To(info[1]).ToChecked(); - GLsizei width = Nan::To(info[2]).ToChecked(); - GLsizei height = Nan::To(info[3]).ToChecked(); + GLint x = info[0].As().Int32Value(); + GLint y = info[1].As().Int32Value(); + GLsizei width = info[2].As().Int32Value(); + GLsizei height = info[3].As().Int32Value(); glScissor(x, y, width, height); + return env.Undefined(); } GL_METHOD(StencilFunc) { GL_BOILERPLATE; - GLenum func = Nan::To(info[0]).ToChecked(); - GLint ref = Nan::To(info[1]).ToChecked(); - GLuint mask = Nan::To(info[2]).ToChecked(); + GLenum func = info[0].As().Int32Value(); + GLint ref = info[1].As().Int32Value(); + GLuint mask = info[2].As().Uint32Value(); glStencilFunc(func, ref, mask); + return env.Undefined(); } GL_METHOD(StencilFuncSeparate) { GL_BOILERPLATE; - GLenum face = Nan::To(info[0]).ToChecked(); - GLenum func = Nan::To(info[1]).ToChecked(); - GLint ref = Nan::To(info[2]).ToChecked(); - GLuint mask = Nan::To(info[3]).ToChecked(); + GLenum face = info[0].As().Int32Value(); + GLenum func = info[1].As().Int32Value(); + GLint ref = info[2].As().Int32Value(); + GLuint mask = info[3].As().Uint32Value(); glStencilFuncSeparate(face, func, ref, mask); + return env.Undefined(); } GL_METHOD(StencilMask) { GL_BOILERPLATE; - GLuint mask = Nan::To(info[0]).ToChecked(); + GLuint mask = info[0].As().Uint32Value(); glStencilMask(mask); + return env.Undefined(); } GL_METHOD(StencilMaskSeparate) { GL_BOILERPLATE; - GLenum face = Nan::To(info[0]).ToChecked(); - GLuint mask = Nan::To(info[1]).ToChecked(); + GLenum face = info[0].As().Int32Value(); + GLuint mask = info[1].As().Uint32Value(); glStencilMaskSeparate(face, mask); + return env.Undefined(); } GL_METHOD(StencilOp) { GL_BOILERPLATE; - GLenum fail = Nan::To(info[0]).ToChecked(); - GLenum zfail = Nan::To(info[1]).ToChecked(); - GLenum zpass = Nan::To(info[2]).ToChecked(); + GLenum fail = info[0].As().Int32Value(); + GLenum zfail = info[1].As().Int32Value(); + GLenum zpass = info[2].As().Int32Value(); glStencilOp(fail, zfail, zpass); + return env.Undefined(); } GL_METHOD(StencilOpSeparate) { GL_BOILERPLATE; - GLenum face = Nan::To(info[0]).ToChecked(); - GLenum fail = Nan::To(info[1]).ToChecked(); - GLenum zfail = Nan::To(info[2]).ToChecked(); - GLenum zpass = Nan::To(info[3]).ToChecked(); + GLenum face = info[0].As().Int32Value(); + GLenum fail = info[1].As().Int32Value(); + GLenum zfail = info[2].As().Int32Value(); + GLenum zpass = info[3].As().Int32Value(); glStencilOpSeparate(face, fail, zfail, zpass); + return env.Undefined(); } GL_METHOD(BindRenderbuffer) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLuint buffer = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLuint buffer = info[1].As().Uint32Value(); glBindRenderbuffer(target, buffer); + return env.Undefined(); } GL_METHOD(CreateRenderbuffer) { @@ -1526,151 +1848,153 @@ GL_METHOD(CreateRenderbuffer) { inst->registerGLObj(GLOBJECT_TYPE_RENDERBUFFER, renderbuffers); - info.GetReturnValue().Set(Nan::New(renderbuffers)); + return Napi::Number::New(env, renderbuffers); } GL_METHOD(DeleteBuffer) { GL_BOILERPLATE; - GLuint buffer = (GLuint)Nan::To(info[0]).ToChecked(); + GLuint buffer = (GLuint)info[0].As().Uint32Value(); inst->unregisterGLObj(GLOBJECT_TYPE_BUFFER, buffer); glDeleteBuffers(1, &buffer); + return env.Undefined(); } GL_METHOD(DeleteFramebuffer) { GL_BOILERPLATE; - GLuint buffer = Nan::To(info[0]).ToChecked(); + GLuint buffer = info[0].As().Uint32Value(); inst->unregisterGLObj(GLOBJECT_TYPE_FRAMEBUFFER, buffer); glDeleteFramebuffers(1, &buffer); + return env.Undefined(); } GL_METHOD(DeleteProgram) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); + GLuint program = info[0].As().Uint32Value(); inst->unregisterGLObj(GLOBJECT_TYPE_PROGRAM, program); glDeleteProgram(program); + return env.Undefined(); } GL_METHOD(DeleteRenderbuffer) { GL_BOILERPLATE; - GLuint renderbuffer = Nan::To(info[0]).ToChecked(); + GLuint renderbuffer = info[0].As().Uint32Value(); inst->unregisterGLObj(GLOBJECT_TYPE_RENDERBUFFER, renderbuffer); glDeleteRenderbuffers(1, &renderbuffer); + return env.Undefined(); } GL_METHOD(DeleteShader) { GL_BOILERPLATE; - GLuint shader = Nan::To(info[0]).ToChecked(); + GLuint shader = info[0].As().Uint32Value(); inst->unregisterGLObj(GLOBJECT_TYPE_SHADER, shader); glDeleteShader(shader); + return env.Undefined(); } GL_METHOD(DeleteTexture) { GL_BOILERPLATE; - GLuint texture = Nan::To(info[0]).ToChecked(); + GLuint texture = info[0].As().Uint32Value(); inst->unregisterGLObj(GLOBJECT_TYPE_TEXTURE, texture); glDeleteTextures(1, &texture); + return env.Undefined(); } GL_METHOD(DetachShader) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - GLuint shader = Nan::To(info[1]).ToChecked(); + GLuint program = info[0].As().Uint32Value(); + GLuint shader = info[1].As().Uint32Value(); glDetachShader(program, shader); + return env.Undefined(); } GL_METHOD(FramebufferRenderbuffer) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum attachment = Nan::To(info[1]).ToChecked(); - GLenum renderbuffertarget = Nan::To(info[2]).ToChecked(); - GLuint renderbuffer = Nan::To(info[3]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum attachment = info[1].As().Int32Value(); + GLenum renderbuffertarget = info[2].As().Int32Value(); + GLuint renderbuffer = info[3].As().Uint32Value(); glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); + return env.Undefined(); } GL_METHOD(GetVertexAttribOffset) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLuint index = info[0].As().Uint32Value(); + GLenum pname = info[1].As().Int32Value(); void *ret = NULL; glGetVertexAttribPointerv(index, pname, &ret); GLuint offset = static_cast(reinterpret_cast(ret)); - info.GetReturnValue().Set(Nan::New(offset)); + return Napi::Number::New(env, offset); } GL_METHOD(IsBuffer) { GL_BOILERPLATE; - info.GetReturnValue().Set( - Nan::New(glIsBuffer(Nan::To(info[0]).ToChecked()) != 0)); + return Napi::Boolean::New(env, glIsBuffer(info[0].As().Uint32Value()) != 0); } GL_METHOD(IsFramebuffer) { GL_BOILERPLATE; - info.GetReturnValue().Set( - Nan::New(glIsFramebuffer(Nan::To(info[0]).ToChecked()) != 0)); + return Napi::Boolean::New(env, glIsFramebuffer(info[0].As().Uint32Value()) != 0); } GL_METHOD(IsProgram) { GL_BOILERPLATE; - info.GetReturnValue().Set( - Nan::New(glIsProgram(Nan::To(info[0]).ToChecked()) != 0)); + return Napi::Boolean::New(env, glIsProgram(info[0].As().Uint32Value()) != 0); } GL_METHOD(IsRenderbuffer) { GL_BOILERPLATE; - info.GetReturnValue().Set( - Nan::New(glIsRenderbuffer(Nan::To(info[0]).ToChecked()) != 0)); + return Napi::Boolean::New(env, glIsRenderbuffer(info[0].As().Uint32Value()) != 0); } GL_METHOD(IsShader) { GL_BOILERPLATE; - info.GetReturnValue().Set( - Nan::New(glIsShader(Nan::To(info[0]).ToChecked()) != 0)); + return Napi::Boolean::New(env, glIsShader(info[0].As().Uint32Value()) != 0); } GL_METHOD(IsTexture) { GL_BOILERPLATE; - info.GetReturnValue().Set( - Nan::New(glIsTexture(Nan::To(info[0]).ToChecked()) != 0)); + return Napi::Boolean::New(env, glIsTexture(info[0].As().Uint32Value()) != 0); } GL_METHOD(RenderbufferStorage) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum internalformat = Nan::To(info[1]).ToChecked(); - GLsizei width = Nan::To(info[2]).ToChecked(); - GLsizei height = Nan::To(info[3]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum internalformat = info[1].As().Int32Value(); + GLsizei width = info[2].As().Int32Value(); + GLsizei height = info[3].As().Int32Value(); // In WebGL, we map GL_DEPTH_STENCIL to GL_DEPTH24_STENCIL8 if (internalformat == GL_DEPTH_STENCIL_OES) { @@ -1680,60 +2004,66 @@ GL_METHOD(RenderbufferStorage) { } glRenderbufferStorage(target, internalformat, width, height); + return env.Undefined(); } GL_METHOD(GetShaderSource) { GL_BOILERPLATE; - GLint shader = Nan::To(info[0]).ToChecked(); + GLint shader = info[0].As().Int32Value(); GLint len; glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &len); GLchar *source = new GLchar[len]; glGetShaderSource(shader, len, NULL, source); - v8::Local str = Nan::New(source).ToLocalChecked(); + Napi::String str = Napi::String::New(env, source); delete[] source; - info.GetReturnValue().Set(str); + return str; } GL_METHOD(ReadPixels) { GL_BOILERPLATE; - GLint x = Nan::To(info[0]).ToChecked(); - GLint y = Nan::To(info[1]).ToChecked(); - GLsizei width = Nan::To(info[2]).ToChecked(); - GLsizei height = Nan::To(info[3]).ToChecked(); - GLenum format = Nan::To(info[4]).ToChecked(); - GLenum type = Nan::To(info[5]).ToChecked(); - Nan::TypedArrayContents pixels(info[6]); + GLint x = info[0].As().Int32Value(); + GLint y = info[1].As().Int32Value(); + GLsizei width = info[2].As().Int32Value(); + GLsizei height = info[3].As().Int32Value(); + GLenum format = info[4].As().Int32Value(); + GLenum type = info[5].As().Int32Value(); + auto _arr_pixels = info[6].As(); + char* pixels = reinterpret_cast( + static_cast(_arr_pixels.ArrayBuffer().Data()) + _arr_pixels.ByteOffset()); + size_t pixels_len = _arr_pixels.ElementLength(); - glReadPixels(x, y, width, height, format, type, *pixels); + glReadPixels(x, y, width, height, format, type, pixels); + return env.Undefined(); } GL_METHOD(GetTexParameter) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum pname = info[1].As().Int32Value(); if (pname == GL_TEXTURE_MAX_ANISOTROPY_EXT) { GLfloat param_value = 0; glGetTexParameterfv(target, pname, ¶m_value); - info.GetReturnValue().Set(Nan::New(param_value)); + return Napi::Number::New(env, param_value); } else { GLint param_value = 0; glGetTexParameteriv(target, pname, ¶m_value); - info.GetReturnValue().Set(Nan::New(param_value)); + return Napi::Number::New(env, param_value); } + return env.Undefined(); } GL_METHOD(GetActiveAttrib) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - GLuint index = Nan::To(info[1]).ToChecked(); + GLuint program = info[0].As().Int32Value(); + GLuint index = info[1].As().Int32Value(); GLint maxLength; glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength); @@ -1745,26 +2075,24 @@ GL_METHOD(GetActiveAttrib) { glGetActiveAttrib(program, index, maxLength, &length, &size, &type, name); if (length > 0) { - v8::Local activeInfo = Nan::New(); - Nan::Set(activeInfo, Nan::New("size").ToLocalChecked(), - Nan::New(size)); - Nan::Set(activeInfo, Nan::New("type").ToLocalChecked(), - Nan::New(type)); - Nan::Set(activeInfo, Nan::New("name").ToLocalChecked(), - Nan::New(name).ToLocalChecked()); - info.GetReturnValue().Set(activeInfo); + Napi::Object activeInfo = Napi::Object::New(env); + activeInfo.Set(Napi::String::New(env, "size"), Napi::Number::New(env, size)); + activeInfo.Set(Napi::String::New(env, "type"), Napi::Number::New(env, type)); + activeInfo.Set(Napi::String::New(env, "name"), Napi::String::New(env, name)); + return activeInfo; } else { - info.GetReturnValue().SetNull(); + return env.Null(); } delete[] name; + return env.Undefined(); } GL_METHOD(GetActiveUniform) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - GLuint index = Nan::To(info[1]).ToChecked(); + GLuint program = info[0].As().Int32Value(); + GLuint index = info[1].As().Int32Value(); GLint maxLength; glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength); @@ -1776,25 +2104,23 @@ GL_METHOD(GetActiveUniform) { glGetActiveUniform(program, index, maxLength, &length, &size, &type, name); if (length > 0) { - v8::Local activeInfo = Nan::New(); - Nan::Set(activeInfo, Nan::New("size").ToLocalChecked(), - Nan::New(size)); - Nan::Set(activeInfo, Nan::New("type").ToLocalChecked(), - Nan::New(type)); - Nan::Set(activeInfo, Nan::New("name").ToLocalChecked(), - Nan::New(name).ToLocalChecked()); - info.GetReturnValue().Set(activeInfo); + Napi::Object activeInfo = Napi::Object::New(env); + activeInfo.Set(Napi::String::New(env, "size"), Napi::Number::New(env, size)); + activeInfo.Set(Napi::String::New(env, "type"), Napi::Number::New(env, type)); + activeInfo.Set(Napi::String::New(env, "name"), Napi::String::New(env, name)); + return activeInfo; } else { - info.GetReturnValue().SetNull(); + return env.Null(); } delete[] name; + return env.Undefined(); } GL_METHOD(GetAttachedShaders) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); + GLuint program = info[0].As().Int32Value(); GLint numAttachedShaders; glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders); @@ -1803,44 +2129,41 @@ GL_METHOD(GetAttachedShaders) { GLsizei count; glGetAttachedShaders(program, numAttachedShaders, &count, shaders); - v8::Local shadersArr = Nan::New(count); + Napi::Array shadersArr = Napi::Array::New(env, count); for (int i = 0; i < count; i++) { - Nan::Set(shadersArr, i, Nan::New((int)shaders[i])); + shadersArr.Set(i, Napi::Number::New(env, (int)shaders[i])); } - info.GetReturnValue().Set(shadersArr); + return shadersArr; delete[] shaders; + return env.Undefined(); } -template -void ReturnParamValueOrNull(Nan::NAN_METHOD_ARGS_TYPE info, v8::Local value, - GLsizei bytesWritten) { +static Napi::Value ReturnParamValueOrNull(Napi::Value value, GLsizei bytesWritten, + Napi::Env env) { if (bytesWritten > 0) { - info.GetReturnValue().Set(value); + return value; } else { - info.GetReturnValue().Set(Nan::Null()); + return env.Null(); } } GL_METHOD(GetParameter) { GL_BOILERPLATE; - GLenum name = Nan::To(info[0]).ToChecked(); + GLenum name = info[0].As().Int32Value(); GLsizei bytesWritten = 0; switch (name) { case 0x9240 /* UNPACK_FLIP_Y_WEBGL */: - info.GetReturnValue().Set(Nan::New(inst->unpack_flip_y)); - return; + return Napi::Boolean::New(env, inst->unpack_flip_y); case 0x9241 /* UNPACK_PREMULTIPLY_ALPHA_WEBGL*/: - info.GetReturnValue().Set(Nan::New(inst->unpack_premultiply_alpha)); - return; + return Napi::Boolean::New(env, inst->unpack_premultiply_alpha); case 0x9243 /* UNPACK_COLORSPACE_CONVERSION_WEBGL */: - info.GetReturnValue().Set(Nan::New(inst->unpack_colorspace_conversion)); - return; + return Napi::Number::New(env, inst->unpack_colorspace_conversion); case GL_BLEND: case GL_CULL_FACE: @@ -1854,9 +2177,7 @@ GL_METHOD(GetParameter) { GLboolean params = GL_FALSE; glGetBooleanvRobustANGLE(name, sizeof(GLboolean), &bytesWritten, ¶ms); - ReturnParamValueOrNull(info, Nan::New(params != 0), bytesWritten); - - return; + return ReturnParamValueOrNull(Napi::Boolean::New(env, params != 0), bytesWritten, env); } case GL_DEPTH_CLEAR_VALUE: @@ -1868,9 +2189,7 @@ GL_METHOD(GetParameter) { GLfloat params = 0; glGetFloatvRobustANGLE(name, sizeof(GLfloat), &bytesWritten, ¶ms); - ReturnParamValueOrNull(info, Nan::New(params), bytesWritten); - - return; + return ReturnParamValueOrNull(Napi::Number::New(env, params), bytesWritten, env); } case GL_RENDERER: @@ -1880,21 +2199,19 @@ GL_METHOD(GetParameter) { case GL_EXTENSIONS: { const char *params = reinterpret_cast(glGetString(name)); if (params) { - info.GetReturnValue().Set(Nan::New(params).ToLocalChecked()); + return Napi::String::New(env, params); } - return; + return env.Null(); } case GL_MAX_VIEWPORT_DIMS: { GLint params[2] = {}; glGetIntegervRobustANGLE(name, sizeof(GLint) * 2, &bytesWritten, params); - v8::Local arr = Nan::New(2); - Nan::Set(arr, 0, Nan::New(params[0])); - Nan::Set(arr, 1, Nan::New(params[1])); - ReturnParamValueOrNull(info, arr, bytesWritten); - - return; + Napi::Array arr = Napi::Array::New(env, 2); + arr.Set((uint32_t)0, Napi::Number::New(env, params[0])); + arr.Set((uint32_t)1, Napi::Number::New(env, params[1])); + return ReturnParamValueOrNull(arr, bytesWritten, env); } case GL_SCISSOR_BOX: @@ -1902,14 +2219,12 @@ GL_METHOD(GetParameter) { GLint params[4] = {}; glGetIntegervRobustANGLE(name, sizeof(GLint) * 4, &bytesWritten, params); - v8::Local arr = Nan::New(4); - Nan::Set(arr, 0, Nan::New(params[0])); - Nan::Set(arr, 1, Nan::New(params[1])); - Nan::Set(arr, 2, Nan::New(params[2])); - Nan::Set(arr, 3, Nan::New(params[3])); - ReturnParamValueOrNull(info, arr, bytesWritten); - - return; + Napi::Array arr = Napi::Array::New(env, 4); + arr.Set((uint32_t)0, Napi::Number::New(env, params[0])); + arr.Set((uint32_t)1, Napi::Number::New(env, params[1])); + arr.Set((uint32_t)2, Napi::Number::New(env, params[2])); + arr.Set((uint32_t)3, Napi::Number::New(env, params[3])); + return ReturnParamValueOrNull(arr, bytesWritten, env); } case GL_ALIASED_LINE_WIDTH_RANGE: @@ -1918,12 +2233,10 @@ GL_METHOD(GetParameter) { GLfloat params[2] = {}; glGetFloatvRobustANGLE(name, sizeof(GLfloat) * 2, &bytesWritten, params); - v8::Local arr = Nan::New(2); - Nan::Set(arr, 0, Nan::New(params[0])); - Nan::Set(arr, 1, Nan::New(params[1])); - ReturnParamValueOrNull(info, arr, bytesWritten); - - return; + Napi::Array arr = Napi::Array::New(env, 2); + arr.Set((uint32_t)0, Napi::Number::New(env, params[0])); + arr.Set((uint32_t)1, Napi::Number::New(env, params[1])); + return ReturnParamValueOrNull(arr, bytesWritten, env); } case GL_BLEND_COLOR: @@ -1931,68 +2244,64 @@ GL_METHOD(GetParameter) { GLfloat params[4] = {}; glGetFloatvRobustANGLE(name, sizeof(GLfloat) * 4, &bytesWritten, params); - v8::Local arr = Nan::New(4); - Nan::Set(arr, 0, Nan::New(params[0])); - Nan::Set(arr, 1, Nan::New(params[1])); - Nan::Set(arr, 2, Nan::New(params[2])); - Nan::Set(arr, 3, Nan::New(params[3])); - ReturnParamValueOrNull(info, arr, bytesWritten); - - return; + Napi::Array arr = Napi::Array::New(env, 4); + arr.Set((uint32_t)0, Napi::Number::New(env, params[0])); + arr.Set((uint32_t)1, Napi::Number::New(env, params[1])); + arr.Set((uint32_t)2, Napi::Number::New(env, params[2])); + arr.Set((uint32_t)3, Napi::Number::New(env, params[3])); + return ReturnParamValueOrNull(arr, bytesWritten, env); } case GL_COLOR_WRITEMASK: { GLboolean params[4] = {}; glGetBooleanvRobustANGLE(name, sizeof(GLboolean) * 4, &bytesWritten, params); - v8::Local arr = Nan::New(4); - Nan::Set(arr, 0, Nan::New(params[0] == GL_TRUE)); - Nan::Set(arr, 1, Nan::New(params[1] == GL_TRUE)); - Nan::Set(arr, 2, Nan::New(params[2] == GL_TRUE)); - Nan::Set(arr, 3, Nan::New(params[3] == GL_TRUE)); - ReturnParamValueOrNull(info, arr, bytesWritten); - - return; + Napi::Array arr = Napi::Array::New(env, 4); + arr.Set((uint32_t)0, Napi::Boolean::New(env, params[0] == GL_TRUE)); + arr.Set((uint32_t)1, Napi::Boolean::New(env, params[1] == GL_TRUE)); + arr.Set((uint32_t)2, Napi::Boolean::New(env, params[2] == GL_TRUE)); + arr.Set((uint32_t)3, Napi::Boolean::New(env, params[3] == GL_TRUE)); + return ReturnParamValueOrNull(arr, bytesWritten, env); } default: { GLint params = 0; glGetIntegervRobustANGLE(name, sizeof(GLint), &bytesWritten, ¶ms); - ReturnParamValueOrNull(info, Nan::New(params), bytesWritten); - return; + return ReturnParamValueOrNull(Napi::Number::New(env, params), bytesWritten, env); } } + return env.Undefined(); } GL_METHOD(GetBufferParameter) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum pname = info[1].As().Int32Value(); GLint params; glGetBufferParameteriv(target, pname, ¶ms); - info.GetReturnValue().Set(Nan::New(params)); + return Napi::Number::New(env, params); } GL_METHOD(GetFramebufferAttachmentParameter) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum attachment = Nan::To(info[1]).ToChecked(); - GLenum pname = Nan::To(info[2]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum attachment = info[1].As().Int32Value(); + GLenum pname = info[2].As().Int32Value(); GLint params = 0; glGetFramebufferAttachmentParameteriv(target, attachment, pname, ¶ms); - info.GetReturnValue().Set(Nan::New(params)); + return Napi::Number::New(env, params); } GL_METHOD(GetProgramInfoLog) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); + GLuint program = info[0].As().Int32Value(); GLint infoLogLength; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); @@ -2000,67 +2309,65 @@ GL_METHOD(GetProgramInfoLog) { char *error = new char[infoLogLength + 1]; glGetProgramInfoLog(program, infoLogLength + 1, &infoLogLength, error); - info.GetReturnValue().Set(Nan::New(error).ToLocalChecked()); + return Napi::String::New(env, error); delete[] error; + return env.Undefined(); } GL_METHOD(GetShaderPrecisionFormat) { GL_BOILERPLATE; - GLenum shaderType = Nan::To(info[0]).ToChecked(); - GLenum precisionType = Nan::To(info[1]).ToChecked(); + GLenum shaderType = info[0].As().Int32Value(); + GLenum precisionType = info[1].As().Int32Value(); GLint range[2]; GLint precision; glGetShaderPrecisionFormat(shaderType, precisionType, range, &precision); - v8::Local result = Nan::New(); - Nan::Set(result, Nan::New("rangeMin").ToLocalChecked(), - Nan::New(range[0])); - Nan::Set(result, Nan::New("rangeMax").ToLocalChecked(), - Nan::New(range[1])); - Nan::Set(result, Nan::New("precision").ToLocalChecked(), - Nan::New(precision)); + Napi::Object result = Napi::Object::New(env); + result.Set(Napi::String::New(env, "rangeMin"), Napi::Number::New(env, range[0])); + result.Set(Napi::String::New(env, "rangeMax"), Napi::Number::New(env, range[1])); + result.Set(Napi::String::New(env, "precision"), Napi::Number::New(env, precision)); - info.GetReturnValue().Set(result); + return result; } GL_METHOD(GetRenderbufferParameter) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum pname = info[1].As().Int32Value(); int value; glGetRenderbufferParameteriv(target, pname, &value); - info.GetReturnValue().Set(Nan::New(value)); + return Napi::Number::New(env, value); } GL_METHOD(GetUniform) { GL_BOILERPLATE; - GLint program = Nan::To(info[0]).ToChecked(); - GLint location = Nan::To(info[1]).ToChecked(); + GLint program = info[0].As().Int32Value(); + GLint location = info[1].As().Int32Value(); float data[16]; glGetUniformfv(program, location, data); - v8::Local arr = Nan::New(16); + Napi::Array arr = Napi::Array::New(env, 16); for (int i = 0; i < 16; i++) { - Nan::Set(arr, i, Nan::New(data[i])); + arr.Set(i, Napi::Number::New(env, data[i])); } - info.GetReturnValue().Set(arr); + return arr; } GL_METHOD(GetVertexAttrib) { GL_BOILERPLATE; - GLint index = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLint index = info[0].As().Int32Value(); + GLenum pname = info[1].As().Int32Value(); GLint value; @@ -2068,8 +2375,7 @@ GL_METHOD(GetVertexAttrib) { case GL_VERTEX_ATTRIB_ARRAY_ENABLED: case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: { glGetVertexAttribiv(index, pname, &value); - info.GetReturnValue().Set(Nan::New(value != 0)); - return; + return Napi::Boolean::New(env, value != 0); } case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: @@ -2082,8 +2388,7 @@ GL_METHOD(GetVertexAttrib) { case GL_VERTEX_ATTRIB_ARRAY_TYPE: case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: { glGetVertexAttribiv(index, pname, &value); - info.GetReturnValue().Set(Nan::New(value)); - return; + return Napi::Number::New(env, value); } case GL_CURRENT_VERTEX_ATTRIB: { @@ -2091,13 +2396,12 @@ GL_METHOD(GetVertexAttrib) { glGetVertexAttribfv(index, pname, vextex_attribs); - v8::Local arr = Nan::New(4); - Nan::Set(arr, 0, Nan::New(vextex_attribs[0])); - Nan::Set(arr, 1, Nan::New(vextex_attribs[1])); - Nan::Set(arr, 2, Nan::New(vextex_attribs[2])); - Nan::Set(arr, 3, Nan::New(vextex_attribs[3])); - info.GetReturnValue().Set(arr); - return; + Napi::Array arr = Napi::Array::New(env, 4); + arr.Set((uint32_t)0, Napi::Number::New(env, vextex_attribs[0])); + arr.Set((uint32_t)1, Napi::Number::New(env, vextex_attribs[1])); + arr.Set((uint32_t)2, Napi::Number::New(env, vextex_attribs[2])); + arr.Set((uint32_t)3, Napi::Number::New(env, vextex_attribs[3])); + return arr; } default: @@ -2105,7 +2409,7 @@ GL_METHOD(GetVertexAttrib) { } inst->setError(GL_INVALID_ENUM); - info.GetReturnValue().SetNull(); + return env.Null(); } GL_METHOD(GetSupportedExtensions) { @@ -2113,19 +2417,19 @@ GL_METHOD(GetSupportedExtensions) { std::string extensions = JoinStringSet(inst->supportedWebGLExtensions); - v8::Local exts = Nan::New(extensions).ToLocalChecked(); + Napi::String exts = Napi::String::New(env, extensions); - info.GetReturnValue().Set(exts); + return exts; } GL_METHOD(GetExtension) { GL_BOILERPLATE; - Nan::Utf8String name(info[0]); + std::string name = info[0].As().Utf8Value(); - auto extsIter = inst->webGLToANGLEExtensions.find(*name); + auto extsIter = inst->webGLToANGLEExtensions.find(name.c_str()); if (extsIter == inst->webGLToANGLEExtensions.end()) { - printf("Warning: no record of ANGLE exts for WebGL extension: %s\n", *name); + printf("Warning: no record of ANGLE exts for WebGL extension: %s\n", name.c_str()); } else { for (const std::string &ext : extsIter->second) { if (inst->requestableExtensions.count(ext.c_str()) == 0) { @@ -2137,118 +2441,84 @@ GL_METHOD(GetExtension) { } } } + return env.Undefined(); } GL_METHOD(CheckFramebufferStatus) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); + GLenum target = info[0].As().Int32Value(); - info.GetReturnValue().Set( - Nan::New(static_cast(glCheckFramebufferStatus(target)))); + return Napi::Number::New(env, static_cast(glCheckFramebufferStatus(target))); } GL_METHOD(DrawBuffersWEBGL) { GL_BOILERPLATE; - v8::Local buffersArray = v8::Local::Cast(info[0]); - GLuint numBuffers = buffersArray->Length(); + Napi::Array buffersArray = info[0].As(); + GLuint numBuffers = buffersArray.Length(); GLenum *buffers = new GLenum[numBuffers]; for (GLuint i = 0; i < numBuffers; i++) { - buffers[i] = Nan::Get(buffersArray, i) - .ToLocalChecked() - ->Uint32Value(Nan::GetCurrentContext()) - .ToChecked(); + buffers[i] = buffersArray.Get(i).As().Uint32Value(); } glDrawBuffersEXT(numBuffers, buffers); delete[] buffers; + return env.Undefined(); } GL_METHOD(EXTWEBGL_draw_buffers) { - v8::Local result = Nan::New(); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT0_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT0_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT1_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT1_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT2_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT2_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT3_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT3_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT4_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT4_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT5_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT5_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT6_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT6_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT7_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT7_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT8_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT8_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT9_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT9_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT10_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT10_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT11_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT11_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT12_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT12_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT13_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT13_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT14_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT14_EXT)); - Nan::Set(result, Nan::New("COLOR_ATTACHMENT15_WEBGL").ToLocalChecked(), - Nan::New(GL_COLOR_ATTACHMENT15_EXT)); - - Nan::Set(result, Nan::New("DRAW_BUFFER0_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER0_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER1_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER1_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER2_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER2_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER3_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER3_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER4_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER4_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER5_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER5_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER6_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER6_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER7_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER7_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER8_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER8_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER9_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER9_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER10_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER10_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER11_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER11_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER12_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER12_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER13_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER13_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER14_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER14_EXT)); - Nan::Set(result, Nan::New("DRAW_BUFFER15_WEBGL").ToLocalChecked(), - Nan::New(GL_DRAW_BUFFER15_EXT)); - - Nan::Set(result, Nan::New("MAX_COLOR_ATTACHMENTS_WEBGL").ToLocalChecked(), - Nan::New(GL_MAX_COLOR_ATTACHMENTS_EXT)); - Nan::Set(result, Nan::New("MAX_DRAW_BUFFERS_WEBGL").ToLocalChecked(), - Nan::New(GL_MAX_DRAW_BUFFERS_EXT)); - - info.GetReturnValue().Set(result); + Napi::Env env = info.Env(); + Napi::Object result = Napi::Object::New(env); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT0_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT0_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT1_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT1_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT2_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT2_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT3_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT3_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT4_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT4_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT5_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT5_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT6_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT6_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT7_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT7_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT8_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT8_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT9_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT9_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT10_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT10_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT11_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT11_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT12_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT12_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT13_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT13_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT14_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT14_EXT)); + result.Set(Napi::String::New(env, "COLOR_ATTACHMENT15_WEBGL"), Napi::Number::New(env, GL_COLOR_ATTACHMENT15_EXT)); + + result.Set(Napi::String::New(env, "DRAW_BUFFER0_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER0_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER1_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER1_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER2_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER2_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER3_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER3_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER4_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER4_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER5_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER5_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER6_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER6_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER7_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER7_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER8_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER8_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER9_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER9_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER10_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER10_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER11_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER11_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER12_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER12_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER13_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER13_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER14_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER14_EXT)); + result.Set(Napi::String::New(env, "DRAW_BUFFER15_WEBGL"), Napi::Number::New(env, GL_DRAW_BUFFER15_EXT)); + + result.Set(Napi::String::New(env, "MAX_COLOR_ATTACHMENTS_WEBGL"), Napi::Number::New(env, GL_MAX_COLOR_ATTACHMENTS_EXT)); + result.Set(Napi::String::New(env, "MAX_DRAW_BUFFERS_WEBGL"), Napi::Number::New(env, GL_MAX_DRAW_BUFFERS_EXT)); + + return result; } GL_METHOD(BindVertexArrayOES) { GL_BOILERPLATE; - GLuint array = Nan::To(info[0]).ToChecked(); + GLuint array = info[0].As().Uint32Value(); glBindVertexArrayOES(array); + return env.Undefined(); } GL_METHOD(CreateVertexArrayOES) { @@ -2258,627 +2528,681 @@ GL_METHOD(CreateVertexArrayOES) { glGenVertexArraysOES(1, &array); inst->registerGLObj(GLOBJECT_TYPE_VERTEX_ARRAY, array); - info.GetReturnValue().Set(Nan::New(array)); + return Napi::Number::New(env, array); } GL_METHOD(DeleteVertexArrayOES) { GL_BOILERPLATE; - GLuint array = Nan::To(info[0]).ToChecked(); + GLuint array = info[0].As().Uint32Value(); inst->unregisterGLObj(GLOBJECT_TYPE_VERTEX_ARRAY, array); glDeleteVertexArraysOES(1, &array); + return env.Undefined(); } GL_METHOD(IsVertexArrayOES) { GL_BOILERPLATE; - info.GetReturnValue().Set( - Nan::New(glIsVertexArrayOES(Nan::To(info[0]).ToChecked()) != 0)); + return Napi::Boolean::New(env, glIsVertexArrayOES(info[0].As().Uint32Value()) != 0); } GL_METHOD(CopyBufferSubData) { GL_BOILERPLATE; - GLenum readTarget = Nan::To(info[0]).ToChecked(); - GLenum writeTarget = Nan::To(info[1]).ToChecked(); - GLintptr readOffset = Nan::To(info[2]).ToChecked(); - GLintptr writeOffset = Nan::To(info[3]).ToChecked(); - GLsizeiptr size = Nan::To(info[4]).ToChecked(); + GLenum readTarget = info[0].As().Int32Value(); + GLenum writeTarget = info[1].As().Int32Value(); + GLintptr readOffset = info[2].As().Int64Value(); + GLintptr writeOffset = info[3].As().Int64Value(); + GLsizeiptr size = info[4].As().Int64Value(); glCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); + return env.Undefined(); } GL_METHOD(GetBufferSubData) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLintptr srcByteOffset = Nan::To(info[1]).ToChecked(); - auto buffer = info[2].As(); - void *bufferPtr = buffer->Buffer()->GetBackingStore()->Data(); - GLsizeiptr bufferSize = buffer->ByteLength(); + GLenum target = info[0].As().Int32Value(); + GLintptr srcByteOffset = info[1].As().Int64Value(); + auto buffer = info[2].As(); + void *bufferPtr = (static_cast(buffer.ArrayBuffer().Data()) + buffer.ByteOffset()); + GLsizeiptr bufferSize = buffer.ByteLength(); // TODO: glGetBufferSubData(target, srcByteOffset, bufferSize, bufferPtr); + return env.Undefined(); } GL_METHOD(BlitFramebuffer) { GL_BOILERPLATE; - GLint srcX0 = Nan::To(info[0]).ToChecked(); - GLint srcY0 = Nan::To(info[1]).ToChecked(); - GLint srcX1 = Nan::To(info[2]).ToChecked(); - GLint srcY1 = Nan::To(info[3]).ToChecked(); - GLint dstX0 = Nan::To(info[4]).ToChecked(); - GLint dstY0 = Nan::To(info[5]).ToChecked(); - GLint dstX1 = Nan::To(info[6]).ToChecked(); - GLint dstY1 = Nan::To(info[7]).ToChecked(); - GLbitfield mask = Nan::To(info[8]).ToChecked(); - GLenum filter = Nan::To(info[9]).ToChecked(); + GLint srcX0 = info[0].As().Int32Value(); + GLint srcY0 = info[1].As().Int32Value(); + GLint srcX1 = info[2].As().Int32Value(); + GLint srcY1 = info[3].As().Int32Value(); + GLint dstX0 = info[4].As().Int32Value(); + GLint dstY0 = info[5].As().Int32Value(); + GLint dstX1 = info[6].As().Int32Value(); + GLint dstY1 = info[7].As().Int32Value(); + GLbitfield mask = info[8].As().Uint32Value(); + GLenum filter = info[9].As().Int32Value(); glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + return env.Undefined(); } GL_METHOD(FramebufferTextureLayer) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum attachment = Nan::To(info[1]).ToChecked(); - GLuint texture = Nan::To(info[2]).ToChecked(); - GLint level = Nan::To(info[3]).ToChecked(); - GLint layer = Nan::To(info[4]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum attachment = info[1].As().Int32Value(); + GLuint texture = info[2].As().Uint32Value(); + GLint level = info[3].As().Int32Value(); + GLint layer = info[4].As().Int32Value(); glFramebufferTextureLayer(target, attachment, texture, level, layer); + return env.Undefined(); } GL_METHOD(InvalidateFramebuffer) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - auto attachments = info[1].As(); - GLsizei count = attachments->Length(); + GLenum target = info[0].As().Int32Value(); + auto attachments = info[1].As(); + GLsizei count = attachments.Length(); GLenum *attachmentList = new GLenum[count]; for (GLsizei i = 0; i < count; i++) - attachmentList[i] = Nan::To(Nan::Get(attachments, i).ToLocalChecked()).ToChecked(); + attachmentList[i] = attachments.Get(i).As().Int32Value(); glInvalidateFramebuffer(target, count, attachmentList); delete[] attachmentList; + return env.Undefined(); } GL_METHOD(InvalidateSubFramebuffer) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - auto attachments = info[1].As(); - GLsizei count = attachments->Length(); + GLenum target = info[0].As().Int32Value(); + auto attachments = info[1].As(); + GLsizei count = attachments.Length(); GLenum *attachmentList = new GLenum[count]; for (GLsizei i = 0; i < count; i++) - attachmentList[i] = Nan::To(Nan::Get(attachments, i).ToLocalChecked()).ToChecked(); - GLint x = Nan::To(info[2]).ToChecked(); - GLint y = Nan::To(info[3]).ToChecked(); - GLsizei width = Nan::To(info[4]).ToChecked(); - GLsizei height = Nan::To(info[5]).ToChecked(); + attachmentList[i] = attachments.Get(i).As().Int32Value(); + GLint x = info[2].As().Int32Value(); + GLint y = info[3].As().Int32Value(); + GLsizei width = info[4].As().Int32Value(); + GLsizei height = info[5].As().Int32Value(); glInvalidateSubFramebuffer(target, count, attachmentList, x, y, width, height); delete[] attachmentList; + return env.Undefined(); } GL_METHOD(ReadBuffer) { GL_BOILERPLATE; - GLenum src = OverrideDrawBufferEnum(Nan::To(info[0]).ToChecked()); + GLenum src = OverrideDrawBufferEnum(info[0].As().Int32Value()); glReadBuffer(src); + return env.Undefined(); } GL_METHOD(GetInternalformatParameter) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum internalformat = Nan::To(info[1]).ToChecked(); - GLenum pname = Nan::To(info[2]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum internalformat = info[1].As().Int32Value(); + GLenum pname = info[2].As().Int32Value(); GLint result; glGetInternalformativ(target, internalformat, pname, 1, &result); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } GL_METHOD(RenderbufferStorageMultisample) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLsizei samples = Nan::To(info[1]).ToChecked(); - GLenum internalformat = Nan::To(info[2]).ToChecked(); - GLsizei width = Nan::To(info[3]).ToChecked(); - GLsizei height = Nan::To(info[4]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLsizei samples = info[1].As().Int32Value(); + GLenum internalformat = info[2].As().Int32Value(); + GLsizei width = info[3].As().Int32Value(); + GLsizei height = info[4].As().Int32Value(); glRenderbufferStorageMultisample(target, samples, internalformat, width, height); + return env.Undefined(); } GL_METHOD(TexStorage2D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLsizei levels = Nan::To(info[1]).ToChecked(); - GLenum internalformat = Nan::To(info[2]).ToChecked(); - GLsizei width = Nan::To(info[3]).ToChecked(); - GLsizei height = Nan::To(info[4]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLsizei levels = info[1].As().Int32Value(); + GLenum internalformat = info[2].As().Int32Value(); + GLsizei width = info[3].As().Int32Value(); + GLsizei height = info[4].As().Int32Value(); glTexStorage2D(target, levels, internalformat, width, height); + return env.Undefined(); } GL_METHOD(TexStorage3D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLsizei levels = Nan::To(info[1]).ToChecked(); - GLenum internalformat = Nan::To(info[2]).ToChecked(); - GLsizei width = Nan::To(info[3]).ToChecked(); - GLsizei height = Nan::To(info[4]).ToChecked(); - GLsizei depth = Nan::To(info[5]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLsizei levels = info[1].As().Int32Value(); + GLenum internalformat = info[2].As().Int32Value(); + GLsizei width = info[3].As().Int32Value(); + GLsizei height = info[4].As().Int32Value(); + GLsizei depth = info[5].As().Int32Value(); glTexStorage3D(target, levels, internalformat, width, height, depth); + return env.Undefined(); } GL_METHOD(TexImage3D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLint internalformat = Nan::To(info[2]).ToChecked(); - GLsizei width = Nan::To(info[3]).ToChecked(); - GLsizei height = Nan::To(info[4]).ToChecked(); - GLsizei depth = Nan::To(info[5]).ToChecked(); - GLint border = Nan::To(info[6]).ToChecked(); - GLenum format = Nan::To(info[7]).ToChecked(); - GLenum type = Nan::To(info[8]).ToChecked(); - if (info[9]->IsUndefined()) { + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLint internalformat = info[2].As().Int32Value(); + GLsizei width = info[3].As().Int32Value(); + GLsizei height = info[4].As().Int32Value(); + GLsizei depth = info[5].As().Int32Value(); + GLint border = info[6].As().Int32Value(); + GLenum format = info[7].As().Int32Value(); + GLenum type = info[8].As().Int32Value(); + if (info[9].IsUndefined()) { glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, nullptr); - } else if (info[9]->IsArrayBufferView()) { - auto buffer = info[9].As(); - void *bufferPtr = buffer->Buffer()->GetBackingStore()->Data(); + } else if (info[9].IsTypedArray()) { + auto buffer = info[9].As(); + void *bufferPtr = (static_cast(buffer.ArrayBuffer().Data()) + buffer.ByteOffset()); glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, bufferPtr); } else { - Nan::ThrowTypeError("Invalid data type for TexImage3D"); + Napi::TypeError::New(env, "Invalid data type for TexImage3D").ThrowAsJavaScriptException(); + return env.Undefined(); } + return env.Undefined(); } GL_METHOD(TexSubImage3D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLint xoffset = Nan::To(info[2]).ToChecked(); - GLint yoffset = Nan::To(info[3]).ToChecked(); - GLint zoffset = Nan::To(info[4]).ToChecked(); - GLsizei width = Nan::To(info[5]).ToChecked(); - GLsizei height = Nan::To(info[6]).ToChecked(); - GLsizei depth = Nan::To(info[7]).ToChecked(); - GLenum format = Nan::To(info[8]).ToChecked(); - GLenum type = Nan::To(info[9]).ToChecked(); - if (info[10]->IsUndefined()) { + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLint xoffset = info[2].As().Int32Value(); + GLint yoffset = info[3].As().Int32Value(); + GLint zoffset = info[4].As().Int32Value(); + GLsizei width = info[5].As().Int32Value(); + GLsizei height = info[6].As().Int32Value(); + GLsizei depth = info[7].As().Int32Value(); + GLenum format = info[8].As().Int32Value(); + GLenum type = info[9].As().Int32Value(); + if (info[10].IsUndefined()) { glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, nullptr); - } else if (info[10]->IsArrayBufferView()) { - auto buffer = info[10].As(); - void *bufferPtr = buffer->Buffer()->GetBackingStore()->Data(); + } else if (info[10].IsTypedArray()) { + auto buffer = info[10].As(); + void *bufferPtr = (static_cast(buffer.ArrayBuffer().Data()) + buffer.ByteOffset()); glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufferPtr); } else { - Nan::ThrowTypeError("Invalid data type for TexSubImage3D"); + Napi::TypeError::New(env, "Invalid data type for TexSubImage3D").ThrowAsJavaScriptException(); + return env.Undefined(); } + return env.Undefined(); } GL_METHOD(CopyTexSubImage3D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLint xoffset = Nan::To(info[2]).ToChecked(); - GLint yoffset = Nan::To(info[3]).ToChecked(); - GLint zoffset = Nan::To(info[4]).ToChecked(); - GLint x = Nan::To(info[5]).ToChecked(); - GLint y = Nan::To(info[6]).ToChecked(); - GLsizei width = Nan::To(info[7]).ToChecked(); - GLsizei height = Nan::To(info[8]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLint xoffset = info[2].As().Int32Value(); + GLint yoffset = info[3].As().Int32Value(); + GLint zoffset = info[4].As().Int32Value(); + GLint x = info[5].As().Int32Value(); + GLint y = info[6].As().Int32Value(); + GLsizei width = info[7].As().Int32Value(); + GLsizei height = info[8].As().Int32Value(); glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); + return env.Undefined(); } GL_METHOD(CompressedTexImage3D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLenum internalformat = Nan::To(info[2]).ToChecked(); - GLsizei width = Nan::To(info[3]).ToChecked(); - GLsizei height = Nan::To(info[4]).ToChecked(); - GLsizei depth = Nan::To(info[5]).ToChecked(); - GLint border = Nan::To(info[6]).ToChecked(); - GLsizei imageSize = Nan::To(info[7]).ToChecked(); - if (info[8]->IsUndefined()) { + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLenum internalformat = info[2].As().Int32Value(); + GLsizei width = info[3].As().Int32Value(); + GLsizei height = info[4].As().Int32Value(); + GLsizei depth = info[5].As().Int32Value(); + GLint border = info[6].As().Int32Value(); + GLsizei imageSize = info[7].As().Int32Value(); + if (info[8].IsUndefined()) { glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, nullptr); - } else if (info[8]->IsArrayBufferView()) { - auto buffer = info[8].As(); - void *bufferPtr = buffer->Buffer()->GetBackingStore()->Data(); + } else if (info[8].IsTypedArray()) { + auto buffer = info[8].As(); + void *bufferPtr = (static_cast(buffer.ArrayBuffer().Data()) + buffer.ByteOffset()); glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, bufferPtr); } else { - Nan::ThrowTypeError("Invalid data type for CompressedTexImage3D"); + Napi::TypeError::New(env, "Invalid data type for CompressedTexImage3D").ThrowAsJavaScriptException(); + return env.Undefined(); } + return env.Undefined(); } GL_METHOD(CompressedTexSubImage3D) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLint level = Nan::To(info[1]).ToChecked(); - GLint xoffset = Nan::To(info[2]).ToChecked(); - GLint yoffset = Nan::To(info[3]).ToChecked(); - GLint zoffset = Nan::To(info[4]).ToChecked(); - GLsizei width = Nan::To(info[5]).ToChecked(); - GLsizei height = Nan::To(info[6]).ToChecked(); - GLsizei depth = Nan::To(info[7]).ToChecked(); - GLenum format = Nan::To(info[8]).ToChecked(); - GLsizei imageSize = Nan::To(info[9]).ToChecked(); - if (info[10]->IsUndefined()) { + GLenum target = info[0].As().Int32Value(); + GLint level = info[1].As().Int32Value(); + GLint xoffset = info[2].As().Int32Value(); + GLint yoffset = info[3].As().Int32Value(); + GLint zoffset = info[4].As().Int32Value(); + GLsizei width = info[5].As().Int32Value(); + GLsizei height = info[6].As().Int32Value(); + GLsizei depth = info[7].As().Int32Value(); + GLenum format = info[8].As().Int32Value(); + GLsizei imageSize = info[9].As().Int32Value(); + if (info[10].IsUndefined()) { glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, nullptr); - } else if (info[10]->IsArrayBufferView()) { - auto buffer = info[10].As(); - void *bufferPtr = buffer->Buffer()->GetBackingStore()->Data(); + } else if (info[10].IsTypedArray()) { + auto buffer = info[10].As(); + void *bufferPtr = (static_cast(buffer.ArrayBuffer().Data()) + buffer.ByteOffset()); glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bufferPtr); } else { - Nan::ThrowTypeError("Invalid data type for CompressedTexSubImage3D"); + Napi::TypeError::New(env, "Invalid data type for CompressedTexSubImage3D").ThrowAsJavaScriptException(); + return env.Undefined(); } + return env.Undefined(); } GL_METHOD(GetFragDataLocation) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - Nan::Utf8String name(info[1]); - GLint location = glGetFragDataLocation(program, *name); - info.GetReturnValue().Set(Nan::New(location)); + GLuint program = info[0].As().Uint32Value(); + std::string name = info[1].As().Utf8Value(); + GLint location = glGetFragDataLocation(program, name.c_str()); + return Napi::Number::New(env, location); } GL_METHOD(Uniform1ui) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLuint v0 = Nan::To(info[1]).ToChecked(); + GLuint location = info[0].As().Uint32Value(); + GLuint v0 = info[1].As().Uint32Value(); glUniform1ui(location, v0); + return env.Undefined(); } GL_METHOD(Uniform2ui) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLuint v0 = Nan::To(info[1]).ToChecked(); - GLuint v1 = Nan::To(info[2]).ToChecked(); + GLuint location = info[0].As().Uint32Value(); + GLuint v0 = info[1].As().Uint32Value(); + GLuint v1 = info[2].As().Uint32Value(); glUniform2ui(location, v0, v1); + return env.Undefined(); } GL_METHOD(Uniform3ui) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLuint v0 = Nan::To(info[1]).ToChecked(); - GLuint v1 = Nan::To(info[2]).ToChecked(); - GLuint v2 = Nan::To(info[3]).ToChecked(); + GLuint location = info[0].As().Uint32Value(); + GLuint v0 = info[1].As().Uint32Value(); + GLuint v1 = info[2].As().Uint32Value(); + GLuint v2 = info[3].As().Uint32Value(); glUniform3ui(location, v0, v1, v2); + return env.Undefined(); } GL_METHOD(Uniform4ui) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLuint v0 = Nan::To(info[1]).ToChecked(); - GLuint v1 = Nan::To(info[2]).ToChecked(); - GLuint v2 = Nan::To(info[3]).ToChecked(); - GLuint v3 = Nan::To(info[4]).ToChecked(); + GLuint location = info[0].As().Uint32Value(); + GLuint v0 = info[1].As().Uint32Value(); + GLuint v1 = info[2].As().Uint32Value(); + GLuint v2 = info[3].As().Uint32Value(); + GLuint v3 = info[4].As().Uint32Value(); glUniform4ui(location, v0, v1, v2, v3); + return env.Undefined(); } GL_METHOD(Uniform1uiv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - auto data = info[1].As(); - GLuint *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / sizeof(GLuint); + GLuint location = info[0].As().Uint32Value(); + auto data = info[1].As(); + GLuint *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / sizeof(GLuint); glUniform1uiv(location, count, bufferPtr); + return env.Undefined(); } GL_METHOD(Uniform2uiv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - auto data = info[1].As(); - GLuint *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (2 * sizeof(GLuint)); + GLuint location = info[0].As().Uint32Value(); + auto data = info[1].As(); + GLuint *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (2 * sizeof(GLuint)); glUniform2uiv(location, count, bufferPtr); + return env.Undefined(); } GL_METHOD(Uniform3uiv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - auto data = info[1].As(); - GLuint *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (3 * sizeof(GLuint)); + GLuint location = info[0].As().Uint32Value(); + auto data = info[1].As(); + GLuint *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (3 * sizeof(GLuint)); glUniform3uiv(location, count, bufferPtr); + return env.Undefined(); } GL_METHOD(Uniform4uiv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - auto data = info[1].As(); - GLuint *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (4 * sizeof(GLuint)); + GLuint location = info[0].As().Uint32Value(); + auto data = info[1].As(); + GLuint *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (4 * sizeof(GLuint)); glUniform4uiv(location, count, bufferPtr); + return env.Undefined(); } GL_METHOD(UniformMatrix3x2fv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = Nan::To(info[1]).ToChecked(); - auto data = info[2].As(); - GLfloat *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (6 * sizeof(GLfloat)); + GLuint location = info[0].As().Uint32Value(); + GLboolean transpose = info[1].As().Value(); + auto data = info[2].As(); + GLfloat *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (6 * sizeof(GLfloat)); glUniformMatrix3x2fv(location, count, transpose, bufferPtr); + return env.Undefined(); } GL_METHOD(UniformMatrix4x2fv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = Nan::To(info[1]).ToChecked(); - auto data = info[2].As(); - GLfloat *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (8 * sizeof(GLfloat)); + GLuint location = info[0].As().Uint32Value(); + GLboolean transpose = info[1].As().Value(); + auto data = info[2].As(); + GLfloat *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (8 * sizeof(GLfloat)); glUniformMatrix4x2fv(location, count, transpose, bufferPtr); + return env.Undefined(); } GL_METHOD(UniformMatrix2x3fv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = Nan::To(info[1]).ToChecked(); - auto data = info[2].As(); - GLfloat *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (6 * sizeof(GLfloat)); + GLuint location = info[0].As().Uint32Value(); + GLboolean transpose = info[1].As().Value(); + auto data = info[2].As(); + GLfloat *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (6 * sizeof(GLfloat)); glUniformMatrix2x3fv(location, count, transpose, bufferPtr); + return env.Undefined(); } GL_METHOD(UniformMatrix4x3fv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = Nan::To(info[1]).ToChecked(); - auto data = info[2].As(); - GLfloat *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (12 * sizeof(GLfloat)); + GLuint location = info[0].As().Uint32Value(); + GLboolean transpose = info[1].As().Value(); + auto data = info[2].As(); + GLfloat *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (12 * sizeof(GLfloat)); glUniformMatrix4x3fv(location, count, transpose, bufferPtr); + return env.Undefined(); } GL_METHOD(UniformMatrix2x4fv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = Nan::To(info[1]).ToChecked(); - auto data = info[2].As(); - GLfloat *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (8 * sizeof(GLfloat)); + GLuint location = info[0].As().Uint32Value(); + GLboolean transpose = info[1].As().Value(); + auto data = info[2].As(); + GLfloat *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (8 * sizeof(GLfloat)); glUniformMatrix2x4fv(location, count, transpose, bufferPtr); + return env.Undefined(); } GL_METHOD(UniformMatrix3x4fv) { GL_BOILERPLATE; - GLuint location = Nan::To(info[0]).ToChecked(); - GLboolean transpose = Nan::To(info[1]).ToChecked(); - auto data = info[2].As(); - GLfloat *bufferPtr = static_cast(data->Buffer()->GetBackingStore()->Data()); - GLsizei count = data->ByteLength() / (12 * sizeof(GLfloat)); + GLuint location = info[0].As().Uint32Value(); + GLboolean transpose = info[1].As().Value(); + auto data = info[2].As(); + GLfloat *bufferPtr = reinterpret_cast((static_cast(data.ArrayBuffer().Data()) + data.ByteOffset())); + GLsizei count = data.ByteLength() / (12 * sizeof(GLfloat)); glUniformMatrix3x4fv(location, count, transpose, bufferPtr); + return env.Undefined(); } GL_METHOD(VertexAttribI4i) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLint x = Nan::To(info[1]).ToChecked(); - GLint y = Nan::To(info[2]).ToChecked(); - GLint z = Nan::To(info[3]).ToChecked(); - GLint w = Nan::To(info[4]).ToChecked(); + GLuint index = info[0].As().Uint32Value(); + GLint x = info[1].As().Int32Value(); + GLint y = info[2].As().Int32Value(); + GLint z = info[3].As().Int32Value(); + GLint w = info[4].As().Int32Value(); glVertexAttribI4i(index, x, y, z, w); + return env.Undefined(); } GL_METHOD(VertexAttribI4iv) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - auto values = info[1].As(); - GLint *bufferPtr = static_cast(values->Buffer()->GetBackingStore()->Data()); + GLuint index = info[0].As().Uint32Value(); + auto values = info[1].As(); + GLint *bufferPtr = reinterpret_cast((static_cast(values.ArrayBuffer().Data()) + values.ByteOffset())); glVertexAttribI4iv(index, bufferPtr); + return env.Undefined(); } GL_METHOD(VertexAttribI4ui) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLuint x = Nan::To(info[1]).ToChecked(); - GLuint y = Nan::To(info[2]).ToChecked(); - GLuint z = Nan::To(info[3]).ToChecked(); - GLuint w = Nan::To(info[4]).ToChecked(); + GLuint index = info[0].As().Uint32Value(); + GLuint x = info[1].As().Uint32Value(); + GLuint y = info[2].As().Uint32Value(); + GLuint z = info[3].As().Uint32Value(); + GLuint w = info[4].As().Uint32Value(); glVertexAttribI4ui(index, x, y, z, w); + return env.Undefined(); } GL_METHOD(VertexAttribI4uiv) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - auto values = info[1].As(); - GLuint *bufferPtr = static_cast(values->Buffer()->GetBackingStore()->Data()); + GLuint index = info[0].As().Uint32Value(); + auto values = info[1].As(); + GLuint *bufferPtr = reinterpret_cast((static_cast(values.ArrayBuffer().Data()) + values.ByteOffset())); glVertexAttribI4uiv(index, bufferPtr); + return env.Undefined(); } GL_METHOD(VertexAttribIPointer) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLint size = Nan::To(info[1]).ToChecked(); - GLenum type = Nan::To(info[2]).ToChecked(); - GLsizei stride = Nan::To(info[3]).ToChecked(); - GLintptr offset = Nan::To(info[4]).ToChecked(); + GLuint index = info[0].As().Uint32Value(); + GLint size = info[1].As().Int32Value(); + GLenum type = info[2].As().Int32Value(); + GLsizei stride = info[3].As().Int32Value(); + GLintptr offset = info[4].As().Int64Value(); glVertexAttribIPointer(index, size, type, stride, reinterpret_cast(offset)); + return env.Undefined(); } GL_METHOD(VertexAttribDivisor) { GL_BOILERPLATE; - GLuint index = Nan::To(info[0]).ToChecked(); - GLuint divisor = Nan::To(info[1]).ToChecked(); + GLuint index = info[0].As().Uint32Value(); + GLuint divisor = info[1].As().Uint32Value(); glVertexAttribDivisor(index, divisor); + return env.Undefined(); } GL_METHOD(DrawArraysInstanced) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); - GLint first = Nan::To(info[1]).ToChecked(); - GLsizei count = Nan::To(info[2]).ToChecked(); - GLsizei instanceCount = Nan::To(info[3]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); + GLint first = info[1].As().Int32Value(); + GLsizei count = info[2].As().Int32Value(); + GLsizei instanceCount = info[3].As().Int32Value(); glDrawArraysInstanced(mode, first, count, instanceCount); + return env.Undefined(); } GL_METHOD(DrawElementsInstanced) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); - GLsizei count = Nan::To(info[1]).ToChecked(); - GLenum type = Nan::To(info[2]).ToChecked(); - GLintptr offset = Nan::To(info[3]).ToChecked(); - GLsizei instanceCount = Nan::To(info[4]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); + GLsizei count = info[1].As().Int32Value(); + GLenum type = info[2].As().Int32Value(); + GLintptr offset = info[3].As().Int64Value(); + GLsizei instanceCount = info[4].As().Int32Value(); glDrawElementsInstanced(mode, count, type, reinterpret_cast(offset), instanceCount); + return env.Undefined(); } GL_METHOD(DrawRangeElements) { GL_BOILERPLATE; - GLenum mode = Nan::To(info[0]).ToChecked(); - GLuint start = Nan::To(info[1]).ToChecked(); - GLuint end = Nan::To(info[2]).ToChecked(); - GLsizei count = Nan::To(info[3]).ToChecked(); - GLenum type = Nan::To(info[4]).ToChecked(); - GLintptr offset = Nan::To(info[5]).ToChecked(); + GLenum mode = info[0].As().Int32Value(); + GLuint start = info[1].As().Uint32Value(); + GLuint end = info[2].As().Uint32Value(); + GLsizei count = info[3].As().Int32Value(); + GLenum type = info[4].As().Int32Value(); + GLintptr offset = info[5].As().Int64Value(); glDrawRangeElements(mode, start, end, count, type, reinterpret_cast(offset)); + return env.Undefined(); } GL_METHOD(DrawBuffers) { GL_BOILERPLATE; - auto buffers = info[0].As(); - GLsizei count = buffers->Length(); + auto buffers = info[0].As(); + GLsizei count = buffers.Length(); GLenum *bufferList = new GLenum[count]; for (GLsizei i = 0; i < count; i++) { - GLenum buffer = Nan::To(Nan::Get(buffers, i).ToLocalChecked()).ToChecked(); + GLenum buffer = buffers.Get(i).As().Int32Value(); bufferList[i] = OverrideDrawBufferEnum(buffer); } glDrawBuffers(count, bufferList); delete[] bufferList; + return env.Undefined(); } GL_METHOD(ClearBufferfv) { GL_BOILERPLATE; - GLenum buffer = Nan::To(info[0]).ToChecked(); - GLint drawbuffer = Nan::To(info[1]).ToChecked(); - auto values = info[2].As(); - GLfloat *bufferPtr = static_cast(values->Buffer()->GetBackingStore()->Data()); + GLenum buffer = info[0].As().Int32Value(); + GLint drawbuffer = info[1].As().Int32Value(); + auto values = info[2].As(); + GLfloat *bufferPtr = reinterpret_cast((static_cast(values.ArrayBuffer().Data()) + values.ByteOffset())); glClearBufferfv(buffer, drawbuffer, bufferPtr); + return env.Undefined(); } GL_METHOD(ClearBufferiv) { GL_BOILERPLATE; - GLenum buffer = Nan::To(info[0]).ToChecked(); - GLint drawbuffer = Nan::To(info[1]).ToChecked(); - auto values = info[2].As(); - GLint *bufferPtr = static_cast(values->Buffer()->GetBackingStore()->Data()); + GLenum buffer = info[0].As().Int32Value(); + GLint drawbuffer = info[1].As().Int32Value(); + auto values = info[2].As(); + GLint *bufferPtr = reinterpret_cast((static_cast(values.ArrayBuffer().Data()) + values.ByteOffset())); glClearBufferiv(buffer, drawbuffer, bufferPtr); + return env.Undefined(); } GL_METHOD(ClearBufferuiv) { GL_BOILERPLATE; - GLenum buffer = Nan::To(info[0]).ToChecked(); - GLint drawbuffer = Nan::To(info[1]).ToChecked(); - auto values = info[2].As(); - GLuint *bufferPtr = static_cast(values->Buffer()->GetBackingStore()->Data()); + GLenum buffer = info[0].As().Int32Value(); + GLint drawbuffer = info[1].As().Int32Value(); + auto values = info[2].As(); + GLuint *bufferPtr = reinterpret_cast((static_cast(values.ArrayBuffer().Data()) + values.ByteOffset())); glClearBufferuiv(buffer, drawbuffer, bufferPtr); + return env.Undefined(); } GL_METHOD(ClearBufferfi) { GL_BOILERPLATE; - GLenum buffer = Nan::To(info[0]).ToChecked(); - GLint drawbuffer = Nan::To(info[1]).ToChecked(); - GLfloat depth = Nan::To(info[2]).ToChecked(); - GLint stencil = Nan::To(info[3]).ToChecked(); + GLenum buffer = info[0].As().Int32Value(); + GLint drawbuffer = info[1].As().Int32Value(); + GLfloat depth = info[2].As().DoubleValue(); + GLint stencil = info[3].As().Int32Value(); glClearBufferfi(buffer, drawbuffer, depth, stencil); + return env.Undefined(); } GL_METHOD(CreateQuery) { GL_BOILERPLATE; GLuint query; glGenQueries(1, &query); - info.GetReturnValue().Set(Nan::New(query)); + return Napi::Number::New(env, query); } GL_METHOD(DeleteQuery) { GL_BOILERPLATE; - GLuint query = Nan::To(info[0]).ToChecked(); + GLuint query = info[0].As().Uint32Value(); glDeleteQueries(1, &query); + return env.Undefined(); } GL_METHOD(IsQuery) { GL_BOILERPLATE; - GLuint query = Nan::To(info[0]).ToChecked(); + GLuint query = info[0].As().Uint32Value(); GLboolean result = glIsQuery(query); - info.GetReturnValue().Set(Nan::New(result != GL_FALSE)); + return Napi::Boolean::New(env, result != GL_FALSE); } GL_METHOD(BeginQuery) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLuint query = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLuint query = info[1].As().Uint32Value(); glBeginQuery(target, query); + return env.Undefined(); } GL_METHOD(EndQuery) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); + GLenum target = info[0].As().Int32Value(); glEndQuery(target); + return env.Undefined(); } GL_METHOD(GetQuery) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLenum pname = info[1].As().Int32Value(); GLuint result; glGetQueryiv(target, pname, reinterpret_cast(&result)); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } GL_METHOD(GetQueryParameter) { GL_BOILERPLATE; - GLuint query = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLuint query = info[0].As().Uint32Value(); + GLenum pname = info[1].As().Int32Value(); GLuint result; glGetQueryObjectuiv(query, pname, &result); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } GL_METHOD(CreateSampler) { GL_BOILERPLATE; GLuint sampler; glGenSamplers(1, &sampler); - info.GetReturnValue().Set(Nan::New(sampler)); + return Napi::Number::New(env, sampler); } GL_METHOD(DeleteSampler) { GL_BOILERPLATE; - GLuint sampler = Nan::To(info[0]).ToChecked(); + GLuint sampler = info[0].As().Uint32Value(); glDeleteSamplers(1, &sampler); + return env.Undefined(); } GL_METHOD(IsSampler) { GL_BOILERPLATE; - GLuint sampler = Nan::To(info[0]).ToChecked(); + GLuint sampler = info[0].As().Uint32Value(); GLboolean result = glIsSampler(sampler); - info.GetReturnValue().Set(Nan::New(result != GL_FALSE)); + return Napi::Boolean::New(env, result != GL_FALSE); } GL_METHOD(BindSampler) { GL_BOILERPLATE; - GLuint unit = Nan::To(info[0]).ToChecked(); - GLuint sampler = Nan::To(info[1]).ToChecked(); + GLuint unit = info[0].As().Uint32Value(); + GLuint sampler = info[1].As().Uint32Value(); glBindSampler(unit, sampler); + return env.Undefined(); } GL_METHOD(SamplerParameteri) { GL_BOILERPLATE; - GLuint sampler = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); - GLint param = Nan::To(info[2]).ToChecked(); + GLuint sampler = info[0].As().Uint32Value(); + GLenum pname = info[1].As().Int32Value(); + GLint param = info[2].As().Int32Value(); glSamplerParameteri(sampler, pname, param); + return env.Undefined(); } GL_METHOD(SamplerParameterf) { GL_BOILERPLATE; - GLuint sampler = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); - GLfloat param = Nan::To(info[2]).ToChecked(); + GLuint sampler = info[0].As().Uint32Value(); + GLenum pname = info[1].As().Int32Value(); + GLfloat param = info[2].As().DoubleValue(); glSamplerParameterf(sampler, pname, param); + return env.Undefined(); } GL_METHOD(GetSamplerParameter) { GL_BOILERPLATE; - GLuint sampler = Nan::To(info[0]).ToChecked(); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLuint sampler = info[0].As().Uint32Value(); + GLenum pname = info[1].As().Int32Value(); GLint result; glGetSamplerParameteriv(sampler, pname, &result); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } // ANGLE internally stores GLsync values as integer handles, so this is safe on ANGLE. @@ -2890,257 +3214,275 @@ uint32_t SyncToInt(GLsync sync) { return static_cast(reinterpret_cast< GL_METHOD(FenceSync) { GL_BOILERPLATE; - GLenum condition = Nan::To(info[0]).ToChecked(); - GLbitfield flags = Nan::To(info[1]).ToChecked(); + GLenum condition = info[0].As().Int32Value(); + GLbitfield flags = info[1].As().Uint32Value(); GLsync sync = glFenceSync(condition, flags); - info.GetReturnValue().Set(Nan::New(SyncToInt(sync))); + return Napi::Number::New(env, SyncToInt(sync)); } GL_METHOD(IsSync) { GL_BOILERPLATE; - GLsync sync = IntToSync(Nan::To(info[0]).ToChecked()); + GLsync sync = IntToSync(info[0].As().Uint32Value()); GLboolean result = glIsSync(sync); - info.GetReturnValue().Set(Nan::New(result != GL_FALSE)); + return Napi::Boolean::New(env, result != GL_FALSE); } GL_METHOD(DeleteSync) { GL_BOILERPLATE; - GLsync sync = IntToSync(Nan::To(info[0]).ToChecked()); + GLsync sync = IntToSync(info[0].As().Uint32Value()); glDeleteSync(sync); + return env.Undefined(); } GL_METHOD(ClientWaitSync) { GL_BOILERPLATE; - GLsync sync = IntToSync(Nan::To(info[0]).ToChecked()); - GLbitfield flags = Nan::To(info[1]).ToChecked(); - GLuint64 timeout = Nan::To(info[2]).ToChecked(); + GLsync sync = IntToSync(info[0].As().Uint32Value()); + GLbitfield flags = info[1].As().Uint32Value(); + GLuint64 timeout = info[2].As().Int64Value(); GLenum result = glClientWaitSync(sync, flags, timeout); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } GL_METHOD(WaitSync) { GL_BOILERPLATE; - GLsync sync = IntToSync(Nan::To(info[0]).ToChecked()); - GLbitfield flags = Nan::To(info[1]).ToChecked(); - GLint64 timeout = Nan::To(info[2]).ToChecked(); + GLsync sync = IntToSync(info[0].As().Uint32Value()); + GLbitfield flags = info[1].As().Uint32Value(); + GLint64 timeout = info[2].As().Int64Value(); glWaitSync(sync, flags, timeout); + return env.Undefined(); } GL_METHOD(GetSyncParameter) { GL_BOILERPLATE; - GLsync sync = IntToSync(Nan::To(info[0]).ToChecked()); - GLenum pname = Nan::To(info[1]).ToChecked(); + GLsync sync = IntToSync(info[0].As().Uint32Value()); + GLenum pname = info[1].As().Int32Value(); GLint result; glGetSynciv(sync, pname, 1, nullptr, &result); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } GL_METHOD(CreateTransformFeedback) { GL_BOILERPLATE; GLuint tf; glGenTransformFeedbacks(1, &tf); - info.GetReturnValue().Set(Nan::New(tf)); + return Napi::Number::New(env, tf); } GL_METHOD(DeleteTransformFeedback) { GL_BOILERPLATE; - GLuint tf = Nan::To(info[0]).ToChecked(); + GLuint tf = info[0].As().Uint32Value(); glDeleteTransformFeedbacks(1, &tf); + return env.Undefined(); } GL_METHOD(IsTransformFeedback) { GL_BOILERPLATE; - GLuint tf = Nan::To(info[0]).ToChecked(); + GLuint tf = info[0].As().Uint32Value(); GLboolean result = glIsTransformFeedback(tf); - info.GetReturnValue().Set(Nan::New(result != GL_FALSE)); + return Napi::Boolean::New(env, result != GL_FALSE); } GL_METHOD(BindTransformFeedback) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLuint tf = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLuint tf = info[1].As().Uint32Value(); glBindTransformFeedback(target, tf); + return env.Undefined(); } GL_METHOD(BeginTransformFeedback) { GL_BOILERPLATE; - GLenum primitiveMode = Nan::To(info[0]).ToChecked(); + GLenum primitiveMode = info[0].As().Int32Value(); glBeginTransformFeedback(primitiveMode); + return env.Undefined(); } GL_METHOD(EndTransformFeedback) { GL_BOILERPLATE; glEndTransformFeedback(); + return env.Undefined(); } GL_METHOD(TransformFeedbackVaryings) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - auto varyings = info[1].As(); - GLenum bufferMode = Nan::To(info[2]).ToChecked(); - GLsizei count = varyings->Length(); + GLuint program = info[0].As().Uint32Value(); + Napi::Array varyings = info[1].As(); + GLenum bufferMode = info[2].As().Int32Value(); + GLsizei count = (GLsizei)varyings.Length(); + std::vector varyingStrs(count); const char **varyingStrings = new const char *[count]; for (GLsizei i = 0; i < count; i++) { - Nan::Utf8String str(Nan::Get(varyings, i).ToLocalChecked()); - varyingStrings[i] = *str; + varyingStrs[i] = varyings.Get(i).As().Utf8Value(); + varyingStrings[i] = varyingStrs[i].c_str(); } glTransformFeedbackVaryings(program, count, varyingStrings, bufferMode); delete[] varyingStrings; + return env.Undefined(); } GL_METHOD(GetTransformFeedbackVarying) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - GLuint index = Nan::To(info[1]).ToChecked(); + GLuint program = info[0].As().Uint32Value(); + GLuint index = info[1].As().Uint32Value(); char name[256]; GLsizei length; GLsizei size; GLenum type; glGetTransformFeedbackVarying(program, index, 256, &length, &size, &type, name); - v8::Local result = Nan::New(); - Nan::Set(result, Nan::New("name").ToLocalChecked(), Nan::New(name).ToLocalChecked()); - Nan::Set(result, Nan::New("size").ToLocalChecked(), Nan::New(size)); - Nan::Set(result, Nan::New("type").ToLocalChecked(), Nan::New(type)); - info.GetReturnValue().Set(result); + Napi::Object result = Napi::Object::New(env); + result.Set(Napi::String::New(env, "name"), Napi::String::New(env, name)); + result.Set(Napi::String::New(env, "size"), Napi::Number::New(env, size)); + result.Set(Napi::String::New(env, "type"), Napi::Number::New(env, type)); + return result; } GL_METHOD(PauseTransformFeedback) { GL_BOILERPLATE; glPauseTransformFeedback(); + return env.Undefined(); } GL_METHOD(ResumeTransformFeedback) { GL_BOILERPLATE; glResumeTransformFeedback(); + return env.Undefined(); } GL_METHOD(BindBufferBase) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLuint index = Nan::To(info[1]).ToChecked(); - GLuint buffer = Nan::To(info[2]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLuint index = info[1].As().Uint32Value(); + GLuint buffer = info[2].As().Uint32Value(); glBindBufferBase(target, index, buffer); + return env.Undefined(); } GL_METHOD(BindBufferRange) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLuint index = Nan::To(info[1]).ToChecked(); - GLuint buffer = Nan::To(info[2]).ToChecked(); - GLintptr offset = Nan::To(info[3]).ToChecked(); - GLsizeiptr size = Nan::To(info[4]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLuint index = info[1].As().Uint32Value(); + GLuint buffer = info[2].As().Uint32Value(); + GLintptr offset = info[3].As().Int64Value(); + GLsizeiptr size = info[4].As().Int64Value(); glBindBufferRange(target, index, buffer, offset, size); + return env.Undefined(); } GL_METHOD(GetIndexedParameter) { GL_BOILERPLATE; - GLenum target = Nan::To(info[0]).ToChecked(); - GLuint index = Nan::To(info[1]).ToChecked(); + GLenum target = info[0].As().Int32Value(); + GLuint index = info[1].As().Uint32Value(); GLint result; glGetIntegeri_v(target, index, &result); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } GL_METHOD(GetUniformIndices) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - auto uniformNames = info[1].As(); - GLsizei count = uniformNames->Length(); + GLuint program = info[0].As().Uint32Value(); + Napi::Array uniformNames = info[1].As(); + GLsizei count = (GLsizei)uniformNames.Length(); + std::vector nameStrs(count); const char **names = new const char *[count]; for (GLsizei i = 0; i < count; i++) { - Nan::Utf8String name(Nan::Get(uniformNames, i).ToLocalChecked()); - names[i] = *name; + nameStrs[i] = uniformNames.Get(i).As().Utf8Value(); + names[i] = nameStrs[i].c_str(); } GLuint *indices = new GLuint[count]; glGetUniformIndices(program, count, names, indices); - v8::Local result = Nan::New(count); + Napi::Array result = Napi::Array::New(env, count); for (GLsizei i = 0; i < count; i++) { - Nan::Set(result, i, Nan::New(indices[i])); + result.Set(i, Napi::Number::New(env, indices[i])); } - info.GetReturnValue().Set(result); + return result; delete[] names; delete[] indices; + return env.Undefined(); } GL_METHOD(GetActiveUniforms) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - auto uniformIndices = info[1].As(); - GLsizei count = uniformIndices->Length(); + GLuint program = info[0].As().Uint32Value(); + auto uniformIndices = info[1].As(); + GLsizei count = uniformIndices.Length(); GLuint *indices = new GLuint[count]; for (GLsizei i = 0; i < count; i++) { - indices[i] = Nan::To(Nan::Get(uniformIndices, i).ToLocalChecked()).ToChecked(); + indices[i] = uniformIndices.Get(i).As().Uint32Value(); } - GLenum pname = Nan::To(info[2]).ToChecked(); + GLenum pname = info[2].As().Int32Value(); GLint *params = new GLint[count]; glGetActiveUniformsiv(program, count, indices, pname, params); - v8::Local result = Nan::New(count); + Napi::Array result = Napi::Array::New(env, count); for (GLsizei i = 0; i < count; i++) { - Nan::Set(result, i, Nan::New(params[i])); + result.Set(i, Napi::Number::New(env, params[i])); } - info.GetReturnValue().Set(result); + return result; delete[] indices; delete[] params; + return env.Undefined(); } GL_METHOD(GetUniformBlockIndex) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - Nan::Utf8String blockName(info[1]); - GLuint index = glGetUniformBlockIndex(program, *blockName); - info.GetReturnValue().Set(Nan::New(index)); + GLuint program = info[0].As().Uint32Value(); + std::string blockName = info[1].As().Utf8Value(); + GLuint index = glGetUniformBlockIndex(program, blockName.c_str()); + return Napi::Number::New(env, index); } GL_METHOD(GetActiveUniformBlockParameter) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - GLuint uniformBlockIndex = Nan::To(info[1]).ToChecked(); - GLenum pname = Nan::To(info[2]).ToChecked(); + GLuint program = info[0].As().Uint32Value(); + GLuint uniformBlockIndex = info[1].As().Uint32Value(); + GLenum pname = info[2].As().Int32Value(); GLint result; glGetActiveUniformBlockiv(program, uniformBlockIndex, pname, &result); - info.GetReturnValue().Set(Nan::New(result)); + return Napi::Number::New(env, result); } GL_METHOD(GetActiveUniformBlockName) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - GLuint uniformBlockIndex = Nan::To(info[1]).ToChecked(); + GLuint program = info[0].As().Uint32Value(); + GLuint uniformBlockIndex = info[1].As().Uint32Value(); char name[256]; GLsizei length; glGetActiveUniformBlockName(program, uniformBlockIndex, 256, &length, name); - info.GetReturnValue().Set(Nan::New(name).ToLocalChecked()); + return Napi::String::New(env, name); } GL_METHOD(UniformBlockBinding) { GL_BOILERPLATE; - GLuint program = Nan::To(info[0]).ToChecked(); - GLuint uniformBlockIndex = Nan::To(info[1]).ToChecked(); - GLuint uniformBlockBinding = Nan::To(info[2]).ToChecked(); + GLuint program = info[0].As().Uint32Value(); + GLuint uniformBlockIndex = info[1].As().Uint32Value(); + GLuint uniformBlockBinding = info[2].As().Uint32Value(); glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); + return env.Undefined(); } GL_METHOD(CreateVertexArray) { GL_BOILERPLATE; GLuint vao; glGenVertexArrays(1, &vao); - info.GetReturnValue().Set(Nan::New(vao)); + return Napi::Number::New(env, vao); } GL_METHOD(DeleteVertexArray) { GL_BOILERPLATE; - GLuint vao = Nan::To(info[0]).ToChecked(); + GLuint vao = info[0].As().Uint32Value(); glDeleteVertexArrays(1, &vao); + return env.Undefined(); } GL_METHOD(IsVertexArray) { GL_BOILERPLATE; - GLuint vao = Nan::To(info[0]).ToChecked(); + GLuint vao = info[0].As().Uint32Value(); GLboolean result = glIsVertexArray(vao); - info.GetReturnValue().Set(Nan::New(result != GL_FALSE)); + return Napi::Boolean::New(env, result != GL_FALSE); } GL_METHOD(BindVertexArray) { GL_BOILERPLATE; - GLuint vao = Nan::To(info[0]).ToChecked(); + GLuint vao = info[0].As().Uint32Value(); glBindVertexArray(vao); + return env.Undefined(); } diff --git a/src/native/webgl.h b/src/native/webgl.h index 3ee2c8bd..382e186f 100644 --- a/src/native/webgl.h +++ b/src/native/webgl.h @@ -7,9 +7,7 @@ #include #include -#include "nan.h" -#include -#include +#include #define EGL_EGL_PROTOTYPES 0 #define GL_GLES_PROTOTYPES 0 @@ -41,7 +39,7 @@ using GLObjectReference = std::pair; using WebGLToANGLEExtensionsMap = std::map, decltype(&CaseInsensitiveCompare)>; -struct WebGLRenderingContext : public node::ObjectWrap { +struct WebGLRenderingContext : public Napi::ObjectWrap { // The underlying OpenGL context static bool HAS_DISPLAY; @@ -94,11 +92,16 @@ struct WebGLRenderingContext : public node::ObjectWrap { next = prev = NULL; } - // Constructor - WebGLRenderingContext(int width, int height, bool alpha, bool depth, bool stencil, bool antialias, - bool premultipliedAlpha, bool preserveDrawingBuffer, - bool preferLowPowerToHighPerformance, bool failIfMajorPerformanceCaveat, - bool createWebGL2Context); + // Napi constructor + WebGLRenderingContext(const Napi::CallbackInfo& info); + static Napi::Function GetClass(Napi::Env env); + + // Internal GL init helper (moved from old constructor) + void _initContext(int width, int height, bool alpha, bool depth, bool stencil, bool antialias, + bool premultipliedAlpha, bool preserveDrawingBuffer, + bool preferLowPowerToHighPerformance, bool failIfMajorPerformanceCaveat, + bool createWebGL2Context); + virtual ~WebGLRenderingContext(); // Context validation @@ -113,8 +116,8 @@ struct WebGLRenderingContext : public node::ObjectWrap { std::set errorSet; void setError(GLenum error); GLenum getError(); - static NAN_METHOD(SetError); - static NAN_METHOD(GetError); + Napi::Value SetError(const Napi::CallbackInfo& info); + Napi::Value GetError(const Napi::CallbackInfo& info); // Preferred depth format GLenum preferredDepth; @@ -122,247 +125,246 @@ struct WebGLRenderingContext : public node::ObjectWrap { // Destructors void dispose(); - static NAN_METHOD(DisposeAll); - - static NAN_METHOD(New); - static NAN_METHOD(Destroy); - - static NAN_METHOD(VertexAttribDivisorANGLE); - static NAN_METHOD(DrawArraysInstancedANGLE); - static NAN_METHOD(DrawElementsInstancedANGLE); - - static NAN_METHOD(Uniform1f); - static NAN_METHOD(Uniform2f); - static NAN_METHOD(Uniform3f); - static NAN_METHOD(Uniform4f); - static NAN_METHOD(Uniform1i); - static NAN_METHOD(Uniform2i); - static NAN_METHOD(Uniform3i); - static NAN_METHOD(Uniform4i); - - static NAN_METHOD(PixelStorei); - static NAN_METHOD(BindAttribLocation); - static NAN_METHOD(DrawArrays); - static NAN_METHOD(UniformMatrix2fv); - static NAN_METHOD(UniformMatrix3fv); - static NAN_METHOD(UniformMatrix4fv); - static NAN_METHOD(GenerateMipmap); - static NAN_METHOD(GetAttribLocation); - static NAN_METHOD(DepthFunc); - static NAN_METHOD(Viewport); - static NAN_METHOD(CreateShader); - static NAN_METHOD(ShaderSource); - static NAN_METHOD(CompileShader); - static NAN_METHOD(GetShaderParameter); - static NAN_METHOD(GetShaderInfoLog); - static NAN_METHOD(CreateProgram); - static NAN_METHOD(AttachShader); - static NAN_METHOD(LinkProgram); - static NAN_METHOD(GetProgramParameter); - static NAN_METHOD(GetUniformLocation); - static NAN_METHOD(ClearColor); - static NAN_METHOD(ClearDepth); - static NAN_METHOD(Disable); - static NAN_METHOD(Enable); - static NAN_METHOD(CreateTexture); - static NAN_METHOD(BindTexture); - static NAN_METHOD(TexImage2D); - static NAN_METHOD(TexParameteri); - static NAN_METHOD(TexParameterf); - static NAN_METHOD(Clear); - static NAN_METHOD(UseProgram); - static NAN_METHOD(CreateBuffer); - static NAN_METHOD(BindBuffer); - static NAN_METHOD(CreateFramebuffer); - static NAN_METHOD(BindFramebuffer); - static NAN_METHOD(FramebufferTexture2D); - static NAN_METHOD(BufferData); - static NAN_METHOD(BufferSubData); - static NAN_METHOD(BlendEquation); - static NAN_METHOD(BlendFunc); - static NAN_METHOD(EnableVertexAttribArray); - static NAN_METHOD(VertexAttribPointer); - static NAN_METHOD(ActiveTexture); - static NAN_METHOD(DrawElements); - static NAN_METHOD(Flush); - static NAN_METHOD(Finish); - - static NAN_METHOD(VertexAttrib1f); - static NAN_METHOD(VertexAttrib2f); - static NAN_METHOD(VertexAttrib3f); - static NAN_METHOD(VertexAttrib4f); - - static NAN_METHOD(BlendColor); - static NAN_METHOD(BlendEquationSeparate); - static NAN_METHOD(BlendFuncSeparate); - static NAN_METHOD(ClearStencil); - static NAN_METHOD(ColorMask); - static NAN_METHOD(CopyTexImage2D); - static NAN_METHOD(CopyTexSubImage2D); - static NAN_METHOD(CullFace); - static NAN_METHOD(DepthMask); - static NAN_METHOD(DepthRange); - static NAN_METHOD(Hint); - static NAN_METHOD(IsEnabled); - static NAN_METHOD(LineWidth); - static NAN_METHOD(PolygonOffset); - - static NAN_METHOD(GetShaderPrecisionFormat); - - static NAN_METHOD(StencilFunc); - static NAN_METHOD(StencilFuncSeparate); - static NAN_METHOD(StencilMask); - static NAN_METHOD(StencilMaskSeparate); - static NAN_METHOD(StencilOp); - static NAN_METHOD(StencilOpSeparate); - - static NAN_METHOD(Scissor); - - static NAN_METHOD(BindRenderbuffer); - static NAN_METHOD(CreateRenderbuffer); - static NAN_METHOD(FramebufferRenderbuffer); - - static NAN_METHOD(DeleteBuffer); - static NAN_METHOD(DeleteFramebuffer); - static NAN_METHOD(DeleteProgram); - static NAN_METHOD(DeleteRenderbuffer); - static NAN_METHOD(DeleteShader); - static NAN_METHOD(DeleteTexture); - static NAN_METHOD(DetachShader); - - static NAN_METHOD(GetVertexAttribOffset); - static NAN_METHOD(DisableVertexAttribArray); - - static NAN_METHOD(IsBuffer); - static NAN_METHOD(IsFramebuffer); - static NAN_METHOD(IsProgram); - static NAN_METHOD(IsRenderbuffer); - static NAN_METHOD(IsShader); - static NAN_METHOD(IsTexture); - - static NAN_METHOD(RenderbufferStorage); - static NAN_METHOD(GetShaderSource); - static NAN_METHOD(ValidateProgram); - - static NAN_METHOD(TexSubImage2D); - static NAN_METHOD(ReadPixels); - static NAN_METHOD(GetTexParameter); - static NAN_METHOD(GetActiveAttrib); - static NAN_METHOD(GetActiveUniform); - static NAN_METHOD(GetAttachedShaders); - static NAN_METHOD(GetParameter); - static NAN_METHOD(GetBufferParameter); - static NAN_METHOD(GetFramebufferAttachmentParameter); - static NAN_METHOD(GetProgramInfoLog); - static NAN_METHOD(GetRenderbufferParameter); - static NAN_METHOD(GetVertexAttrib); - static NAN_METHOD(GetSupportedExtensions); - static NAN_METHOD(GetExtension); - static NAN_METHOD(CheckFramebufferStatus); - - static NAN_METHOD(FrontFace); - static NAN_METHOD(SampleCoverage); - static NAN_METHOD(GetUniform); - - static NAN_METHOD(DrawBuffersWEBGL); - static NAN_METHOD(EXTWEBGL_draw_buffers); - - static NAN_METHOD(BindVertexArrayOES); - static NAN_METHOD(CreateVertexArrayOES); - static NAN_METHOD(DeleteVertexArrayOES); - static NAN_METHOD(IsVertexArrayOES); + static Napi::Value DisposeAll(const Napi::CallbackInfo& info); + + Napi::Value Destroy(const Napi::CallbackInfo& info); + + Napi::Value VertexAttribDivisorANGLE(const Napi::CallbackInfo& info); + Napi::Value DrawArraysInstancedANGLE(const Napi::CallbackInfo& info); + Napi::Value DrawElementsInstancedANGLE(const Napi::CallbackInfo& info); + + Napi::Value Uniform1f(const Napi::CallbackInfo& info); + Napi::Value Uniform2f(const Napi::CallbackInfo& info); + Napi::Value Uniform3f(const Napi::CallbackInfo& info); + Napi::Value Uniform4f(const Napi::CallbackInfo& info); + Napi::Value Uniform1i(const Napi::CallbackInfo& info); + Napi::Value Uniform2i(const Napi::CallbackInfo& info); + Napi::Value Uniform3i(const Napi::CallbackInfo& info); + Napi::Value Uniform4i(const Napi::CallbackInfo& info); + + Napi::Value PixelStorei(const Napi::CallbackInfo& info); + Napi::Value BindAttribLocation(const Napi::CallbackInfo& info); + Napi::Value DrawArrays(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix2fv(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix3fv(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix4fv(const Napi::CallbackInfo& info); + Napi::Value GenerateMipmap(const Napi::CallbackInfo& info); + Napi::Value GetAttribLocation(const Napi::CallbackInfo& info); + Napi::Value DepthFunc(const Napi::CallbackInfo& info); + Napi::Value Viewport(const Napi::CallbackInfo& info); + Napi::Value CreateShader(const Napi::CallbackInfo& info); + Napi::Value ShaderSource(const Napi::CallbackInfo& info); + Napi::Value CompileShader(const Napi::CallbackInfo& info); + Napi::Value GetShaderParameter(const Napi::CallbackInfo& info); + Napi::Value GetShaderInfoLog(const Napi::CallbackInfo& info); + Napi::Value CreateProgram(const Napi::CallbackInfo& info); + Napi::Value AttachShader(const Napi::CallbackInfo& info); + Napi::Value LinkProgram(const Napi::CallbackInfo& info); + Napi::Value GetProgramParameter(const Napi::CallbackInfo& info); + Napi::Value GetUniformLocation(const Napi::CallbackInfo& info); + Napi::Value ClearColor(const Napi::CallbackInfo& info); + Napi::Value ClearDepth(const Napi::CallbackInfo& info); + Napi::Value Disable(const Napi::CallbackInfo& info); + Napi::Value Enable(const Napi::CallbackInfo& info); + Napi::Value CreateTexture(const Napi::CallbackInfo& info); + Napi::Value BindTexture(const Napi::CallbackInfo& info); + Napi::Value TexImage2D(const Napi::CallbackInfo& info); + Napi::Value TexParameteri(const Napi::CallbackInfo& info); + Napi::Value TexParameterf(const Napi::CallbackInfo& info); + Napi::Value Clear(const Napi::CallbackInfo& info); + Napi::Value UseProgram(const Napi::CallbackInfo& info); + Napi::Value CreateBuffer(const Napi::CallbackInfo& info); + Napi::Value BindBuffer(const Napi::CallbackInfo& info); + Napi::Value CreateFramebuffer(const Napi::CallbackInfo& info); + Napi::Value BindFramebuffer(const Napi::CallbackInfo& info); + Napi::Value FramebufferTexture2D(const Napi::CallbackInfo& info); + Napi::Value BufferData(const Napi::CallbackInfo& info); + Napi::Value BufferSubData(const Napi::CallbackInfo& info); + Napi::Value BlendEquation(const Napi::CallbackInfo& info); + Napi::Value BlendFunc(const Napi::CallbackInfo& info); + Napi::Value EnableVertexAttribArray(const Napi::CallbackInfo& info); + Napi::Value VertexAttribPointer(const Napi::CallbackInfo& info); + Napi::Value ActiveTexture(const Napi::CallbackInfo& info); + Napi::Value DrawElements(const Napi::CallbackInfo& info); + Napi::Value Flush(const Napi::CallbackInfo& info); + Napi::Value Finish(const Napi::CallbackInfo& info); + + Napi::Value VertexAttrib1f(const Napi::CallbackInfo& info); + Napi::Value VertexAttrib2f(const Napi::CallbackInfo& info); + Napi::Value VertexAttrib3f(const Napi::CallbackInfo& info); + Napi::Value VertexAttrib4f(const Napi::CallbackInfo& info); + + Napi::Value BlendColor(const Napi::CallbackInfo& info); + Napi::Value BlendEquationSeparate(const Napi::CallbackInfo& info); + Napi::Value BlendFuncSeparate(const Napi::CallbackInfo& info); + Napi::Value ClearStencil(const Napi::CallbackInfo& info); + Napi::Value ColorMask(const Napi::CallbackInfo& info); + Napi::Value CopyTexImage2D(const Napi::CallbackInfo& info); + Napi::Value CopyTexSubImage2D(const Napi::CallbackInfo& info); + Napi::Value CullFace(const Napi::CallbackInfo& info); + Napi::Value DepthMask(const Napi::CallbackInfo& info); + Napi::Value DepthRange(const Napi::CallbackInfo& info); + Napi::Value Hint(const Napi::CallbackInfo& info); + Napi::Value IsEnabled(const Napi::CallbackInfo& info); + Napi::Value LineWidth(const Napi::CallbackInfo& info); + Napi::Value PolygonOffset(const Napi::CallbackInfo& info); + + Napi::Value GetShaderPrecisionFormat(const Napi::CallbackInfo& info); + + Napi::Value StencilFunc(const Napi::CallbackInfo& info); + Napi::Value StencilFuncSeparate(const Napi::CallbackInfo& info); + Napi::Value StencilMask(const Napi::CallbackInfo& info); + Napi::Value StencilMaskSeparate(const Napi::CallbackInfo& info); + Napi::Value StencilOp(const Napi::CallbackInfo& info); + Napi::Value StencilOpSeparate(const Napi::CallbackInfo& info); + + Napi::Value Scissor(const Napi::CallbackInfo& info); + + Napi::Value BindRenderbuffer(const Napi::CallbackInfo& info); + Napi::Value CreateRenderbuffer(const Napi::CallbackInfo& info); + Napi::Value FramebufferRenderbuffer(const Napi::CallbackInfo& info); + + Napi::Value DeleteBuffer(const Napi::CallbackInfo& info); + Napi::Value DeleteFramebuffer(const Napi::CallbackInfo& info); + Napi::Value DeleteProgram(const Napi::CallbackInfo& info); + Napi::Value DeleteRenderbuffer(const Napi::CallbackInfo& info); + Napi::Value DeleteShader(const Napi::CallbackInfo& info); + Napi::Value DeleteTexture(const Napi::CallbackInfo& info); + Napi::Value DetachShader(const Napi::CallbackInfo& info); + + Napi::Value GetVertexAttribOffset(const Napi::CallbackInfo& info); + Napi::Value DisableVertexAttribArray(const Napi::CallbackInfo& info); + + Napi::Value IsBuffer(const Napi::CallbackInfo& info); + Napi::Value IsFramebuffer(const Napi::CallbackInfo& info); + Napi::Value IsProgram(const Napi::CallbackInfo& info); + Napi::Value IsRenderbuffer(const Napi::CallbackInfo& info); + Napi::Value IsShader(const Napi::CallbackInfo& info); + Napi::Value IsTexture(const Napi::CallbackInfo& info); + + Napi::Value RenderbufferStorage(const Napi::CallbackInfo& info); + Napi::Value GetShaderSource(const Napi::CallbackInfo& info); + Napi::Value ValidateProgram(const Napi::CallbackInfo& info); + + Napi::Value TexSubImage2D(const Napi::CallbackInfo& info); + Napi::Value ReadPixels(const Napi::CallbackInfo& info); + Napi::Value GetTexParameter(const Napi::CallbackInfo& info); + Napi::Value GetActiveAttrib(const Napi::CallbackInfo& info); + Napi::Value GetActiveUniform(const Napi::CallbackInfo& info); + Napi::Value GetAttachedShaders(const Napi::CallbackInfo& info); + Napi::Value GetParameter(const Napi::CallbackInfo& info); + Napi::Value GetBufferParameter(const Napi::CallbackInfo& info); + Napi::Value GetFramebufferAttachmentParameter(const Napi::CallbackInfo& info); + Napi::Value GetProgramInfoLog(const Napi::CallbackInfo& info); + Napi::Value GetRenderbufferParameter(const Napi::CallbackInfo& info); + Napi::Value GetVertexAttrib(const Napi::CallbackInfo& info); + Napi::Value GetSupportedExtensions(const Napi::CallbackInfo& info); + Napi::Value GetExtension(const Napi::CallbackInfo& info); + Napi::Value CheckFramebufferStatus(const Napi::CallbackInfo& info); + + Napi::Value FrontFace(const Napi::CallbackInfo& info); + Napi::Value SampleCoverage(const Napi::CallbackInfo& info); + Napi::Value GetUniform(const Napi::CallbackInfo& info); + + Napi::Value DrawBuffersWEBGL(const Napi::CallbackInfo& info); + Napi::Value EXTWEBGL_draw_buffers(const Napi::CallbackInfo& info); + + Napi::Value BindVertexArrayOES(const Napi::CallbackInfo& info); + Napi::Value CreateVertexArrayOES(const Napi::CallbackInfo& info); + Napi::Value DeleteVertexArrayOES(const Napi::CallbackInfo& info); + Napi::Value IsVertexArrayOES(const Napi::CallbackInfo& info); // WebGL 2 methods - static NAN_METHOD(CopyBufferSubData); - static NAN_METHOD(GetBufferSubData); - static NAN_METHOD(BlitFramebuffer); - static NAN_METHOD(FramebufferTextureLayer); - static NAN_METHOD(InvalidateFramebuffer); - static NAN_METHOD(InvalidateSubFramebuffer); - static NAN_METHOD(ReadBuffer); - static NAN_METHOD(GetInternalformatParameter); - static NAN_METHOD(RenderbufferStorageMultisample); - static NAN_METHOD(TexStorage2D); - static NAN_METHOD(TexStorage3D); - static NAN_METHOD(TexImage3D); - static NAN_METHOD(TexSubImage3D); - static NAN_METHOD(CopyTexSubImage3D); - static NAN_METHOD(CompressedTexImage3D); - static NAN_METHOD(CompressedTexSubImage3D); - static NAN_METHOD(GetFragDataLocation); - static NAN_METHOD(Uniform1ui); - static NAN_METHOD(Uniform2ui); - static NAN_METHOD(Uniform3ui); - static NAN_METHOD(Uniform4ui); - static NAN_METHOD(Uniform1uiv); - static NAN_METHOD(Uniform2uiv); - static NAN_METHOD(Uniform3uiv); - static NAN_METHOD(Uniform4uiv); - static NAN_METHOD(UniformMatrix3x2fv); - static NAN_METHOD(UniformMatrix4x2fv); - static NAN_METHOD(UniformMatrix2x3fv); - static NAN_METHOD(UniformMatrix4x3fv); - static NAN_METHOD(UniformMatrix2x4fv); - static NAN_METHOD(UniformMatrix3x4fv); - static NAN_METHOD(VertexAttribI4i); - static NAN_METHOD(VertexAttribI4iv); - static NAN_METHOD(VertexAttribI4ui); - static NAN_METHOD(VertexAttribI4uiv); - static NAN_METHOD(VertexAttribIPointer); - static NAN_METHOD(VertexAttribDivisor); - static NAN_METHOD(DrawArraysInstanced); - static NAN_METHOD(DrawElementsInstanced); - static NAN_METHOD(DrawRangeElements); - static NAN_METHOD(DrawBuffers); - static NAN_METHOD(ClearBufferfv); - static NAN_METHOD(ClearBufferiv); - static NAN_METHOD(ClearBufferuiv); - static NAN_METHOD(ClearBufferfi); - static NAN_METHOD(CreateQuery); - static NAN_METHOD(DeleteQuery); - static NAN_METHOD(IsQuery); - static NAN_METHOD(BeginQuery); - static NAN_METHOD(EndQuery); - static NAN_METHOD(GetQuery); - static NAN_METHOD(GetQueryParameter); - static NAN_METHOD(CreateSampler); - static NAN_METHOD(DeleteSampler); - static NAN_METHOD(IsSampler); - static NAN_METHOD(BindSampler); - static NAN_METHOD(SamplerParameteri); - static NAN_METHOD(SamplerParameterf); - static NAN_METHOD(GetSamplerParameter); - static NAN_METHOD(FenceSync); - static NAN_METHOD(IsSync); - static NAN_METHOD(DeleteSync); - static NAN_METHOD(ClientWaitSync); - static NAN_METHOD(WaitSync); - static NAN_METHOD(GetSyncParameter); - static NAN_METHOD(CreateTransformFeedback); - static NAN_METHOD(DeleteTransformFeedback); - static NAN_METHOD(IsTransformFeedback); - static NAN_METHOD(BindTransformFeedback); - static NAN_METHOD(BeginTransformFeedback); - static NAN_METHOD(EndTransformFeedback); - static NAN_METHOD(TransformFeedbackVaryings); - static NAN_METHOD(GetTransformFeedbackVarying); - static NAN_METHOD(PauseTransformFeedback); - static NAN_METHOD(ResumeTransformFeedback); - static NAN_METHOD(BindBufferBase); - static NAN_METHOD(BindBufferRange); - static NAN_METHOD(GetIndexedParameter); - static NAN_METHOD(GetUniformIndices); - static NAN_METHOD(GetActiveUniforms); - static NAN_METHOD(GetUniformBlockIndex); - static NAN_METHOD(GetActiveUniformBlockParameter); - static NAN_METHOD(GetActiveUniformBlockName); - static NAN_METHOD(UniformBlockBinding); - static NAN_METHOD(CreateVertexArray); - static NAN_METHOD(DeleteVertexArray); - static NAN_METHOD(IsVertexArray); - static NAN_METHOD(BindVertexArray); + Napi::Value CopyBufferSubData(const Napi::CallbackInfo& info); + Napi::Value GetBufferSubData(const Napi::CallbackInfo& info); + Napi::Value BlitFramebuffer(const Napi::CallbackInfo& info); + Napi::Value FramebufferTextureLayer(const Napi::CallbackInfo& info); + Napi::Value InvalidateFramebuffer(const Napi::CallbackInfo& info); + Napi::Value InvalidateSubFramebuffer(const Napi::CallbackInfo& info); + Napi::Value ReadBuffer(const Napi::CallbackInfo& info); + Napi::Value GetInternalformatParameter(const Napi::CallbackInfo& info); + Napi::Value RenderbufferStorageMultisample(const Napi::CallbackInfo& info); + Napi::Value TexStorage2D(const Napi::CallbackInfo& info); + Napi::Value TexStorage3D(const Napi::CallbackInfo& info); + Napi::Value TexImage3D(const Napi::CallbackInfo& info); + Napi::Value TexSubImage3D(const Napi::CallbackInfo& info); + Napi::Value CopyTexSubImage3D(const Napi::CallbackInfo& info); + Napi::Value CompressedTexImage3D(const Napi::CallbackInfo& info); + Napi::Value CompressedTexSubImage3D(const Napi::CallbackInfo& info); + Napi::Value GetFragDataLocation(const Napi::CallbackInfo& info); + Napi::Value Uniform1ui(const Napi::CallbackInfo& info); + Napi::Value Uniform2ui(const Napi::CallbackInfo& info); + Napi::Value Uniform3ui(const Napi::CallbackInfo& info); + Napi::Value Uniform4ui(const Napi::CallbackInfo& info); + Napi::Value Uniform1uiv(const Napi::CallbackInfo& info); + Napi::Value Uniform2uiv(const Napi::CallbackInfo& info); + Napi::Value Uniform3uiv(const Napi::CallbackInfo& info); + Napi::Value Uniform4uiv(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix3x2fv(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix4x2fv(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix2x3fv(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix4x3fv(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix2x4fv(const Napi::CallbackInfo& info); + Napi::Value UniformMatrix3x4fv(const Napi::CallbackInfo& info); + Napi::Value VertexAttribI4i(const Napi::CallbackInfo& info); + Napi::Value VertexAttribI4iv(const Napi::CallbackInfo& info); + Napi::Value VertexAttribI4ui(const Napi::CallbackInfo& info); + Napi::Value VertexAttribI4uiv(const Napi::CallbackInfo& info); + Napi::Value VertexAttribIPointer(const Napi::CallbackInfo& info); + Napi::Value VertexAttribDivisor(const Napi::CallbackInfo& info); + Napi::Value DrawArraysInstanced(const Napi::CallbackInfo& info); + Napi::Value DrawElementsInstanced(const Napi::CallbackInfo& info); + Napi::Value DrawRangeElements(const Napi::CallbackInfo& info); + Napi::Value DrawBuffers(const Napi::CallbackInfo& info); + Napi::Value ClearBufferfv(const Napi::CallbackInfo& info); + Napi::Value ClearBufferiv(const Napi::CallbackInfo& info); + Napi::Value ClearBufferuiv(const Napi::CallbackInfo& info); + Napi::Value ClearBufferfi(const Napi::CallbackInfo& info); + Napi::Value CreateQuery(const Napi::CallbackInfo& info); + Napi::Value DeleteQuery(const Napi::CallbackInfo& info); + Napi::Value IsQuery(const Napi::CallbackInfo& info); + Napi::Value BeginQuery(const Napi::CallbackInfo& info); + Napi::Value EndQuery(const Napi::CallbackInfo& info); + Napi::Value GetQuery(const Napi::CallbackInfo& info); + Napi::Value GetQueryParameter(const Napi::CallbackInfo& info); + Napi::Value CreateSampler(const Napi::CallbackInfo& info); + Napi::Value DeleteSampler(const Napi::CallbackInfo& info); + Napi::Value IsSampler(const Napi::CallbackInfo& info); + Napi::Value BindSampler(const Napi::CallbackInfo& info); + Napi::Value SamplerParameteri(const Napi::CallbackInfo& info); + Napi::Value SamplerParameterf(const Napi::CallbackInfo& info); + Napi::Value GetSamplerParameter(const Napi::CallbackInfo& info); + Napi::Value FenceSync(const Napi::CallbackInfo& info); + Napi::Value IsSync(const Napi::CallbackInfo& info); + Napi::Value DeleteSync(const Napi::CallbackInfo& info); + Napi::Value ClientWaitSync(const Napi::CallbackInfo& info); + Napi::Value WaitSync(const Napi::CallbackInfo& info); + Napi::Value GetSyncParameter(const Napi::CallbackInfo& info); + Napi::Value CreateTransformFeedback(const Napi::CallbackInfo& info); + Napi::Value DeleteTransformFeedback(const Napi::CallbackInfo& info); + Napi::Value IsTransformFeedback(const Napi::CallbackInfo& info); + Napi::Value BindTransformFeedback(const Napi::CallbackInfo& info); + Napi::Value BeginTransformFeedback(const Napi::CallbackInfo& info); + Napi::Value EndTransformFeedback(const Napi::CallbackInfo& info); + Napi::Value TransformFeedbackVaryings(const Napi::CallbackInfo& info); + Napi::Value GetTransformFeedbackVarying(const Napi::CallbackInfo& info); + Napi::Value PauseTransformFeedback(const Napi::CallbackInfo& info); + Napi::Value ResumeTransformFeedback(const Napi::CallbackInfo& info); + Napi::Value BindBufferBase(const Napi::CallbackInfo& info); + Napi::Value BindBufferRange(const Napi::CallbackInfo& info); + Napi::Value GetIndexedParameter(const Napi::CallbackInfo& info); + Napi::Value GetUniformIndices(const Napi::CallbackInfo& info); + Napi::Value GetActiveUniforms(const Napi::CallbackInfo& info); + Napi::Value GetUniformBlockIndex(const Napi::CallbackInfo& info); + Napi::Value GetActiveUniformBlockParameter(const Napi::CallbackInfo& info); + Napi::Value GetActiveUniformBlockName(const Napi::CallbackInfo& info); + Napi::Value UniformBlockBinding(const Napi::CallbackInfo& info); + Napi::Value CreateVertexArray(const Napi::CallbackInfo& info); + Napi::Value DeleteVertexArray(const Napi::CallbackInfo& info); + Napi::Value IsVertexArray(const Napi::CallbackInfo& info); + Napi::Value BindVertexArray(const Napi::CallbackInfo& info); }; -void BindWebGL2(const Nan::FunctionCallbackInfo &info); +void BindWebGL2(Napi::Object target, Napi::Env env); #endif diff --git a/src/node-index.ts b/src/node-index.ts new file mode 100644 index 00000000..8ab0fd9e --- /dev/null +++ b/src/node-index.ts @@ -0,0 +1,144 @@ +// eslint-disable-next-line @typescript-eslint/no-require-imports +const bits = require('bit-twiddle') as { + log2: (n: number) => number; + nextPow2: (n: number) => number; +}; +import { WebGLContextAttributes } from './webgl-context-attributes'; +import { + WebGLRenderingContext, + WebGL2RenderingContext, + wrapContext, +} from './webgl-rendering-context'; +import { WebGLTextureUnit } from './webgl-texture-unit'; +import { + WebGLVertexArrayObjectState, + WebGLVertexArrayGlobalState, +} from './webgl-vertex-attribute'; + +let CONTEXT_COUNTER = 0; + +function flag( + options: Record | null | undefined, + name: string, + dflt: boolean, +): boolean { + if (!options || !(typeof options === 'object') || !(name in options)) { + return dflt; + } + return !!options[name]; +} + +export function createContext( + width: number, + height: number, + options?: Record, +): any { + width = width | 0; + height = height | 0; + if (!(width > 0 && height > 0)) return null; + + const contextAttributes = new WebGLContextAttributes( + flag(options, 'alpha', true), + flag(options, 'depth', true), + flag(options, 'stencil', false), + false, + flag(options, 'premultipliedAlpha', true), + flag(options, 'preserveDrawingBuffer', false), + flag(options, 'preferLowPowerToHighPerformance', false), + flag(options, 'failIfMajorPerformanceCaveat', false), + flag(options, 'createWebGL2Context', false), + ); + + contextAttributes.premultipliedAlpha = + contextAttributes.premultipliedAlpha && contextAttributes.alpha; + + const WebGLContext = contextAttributes.createWebGL2Context + ? WebGL2RenderingContext + : WebGLRenderingContext; + + let ctx: any; + try { + const AnyWebGLContext = WebGLContext as any; + ctx = new AnyWebGLContext( + 1, + 1, + contextAttributes.alpha, + contextAttributes.depth, + contextAttributes.stencil, + contextAttributes.antialias, + contextAttributes.premultipliedAlpha, + contextAttributes.preserveDrawingBuffer, + contextAttributes.preferLowPowerToHighPerformance, + contextAttributes.failIfMajorPerformanceCaveat, + contextAttributes.createWebGL2Context, + ); + } catch {} + + if (!ctx) return null; + + ctx.drawingBufferWidth = width; + ctx.drawingBufferHeight = height; + ctx._ = CONTEXT_COUNTER++; + ctx._contextAttributes = contextAttributes; + ctx._extensions = {}; + ctx._programs = {}; + ctx._shaders = {}; + ctx._buffers = {}; + ctx._textures = {}; + ctx._framebuffers = {}; + ctx._renderbuffers = {}; + ctx._activeProgram = null; + ctx._activeFramebuffers = { read: null, draw: null }; + ctx._activeRenderbuffer = null; + ctx._checkStencil = false; + ctx._stencilState = true; + + if (contextAttributes.createWebGL2Context) { + ctx._vaos = {}; + ctx._activeVertexArrayObject = null; + } + + const numTextures = ctx.getParameter(ctx.MAX_COMBINED_TEXTURE_IMAGE_UNITS); + ctx._textureUnits = new Array(numTextures); + for (let i = 0; i < numTextures; ++i) { + ctx._textureUnits[i] = new WebGLTextureUnit(ctx, i); + } + ctx._activeTextureUnit = 0; + ctx.activeTexture(ctx.TEXTURE0); + + ctx._errorStack = []; + + ctx._defaultVertexObjectState = new WebGLVertexArrayObjectState(ctx); + ctx._vertexObjectState = ctx._defaultVertexObjectState; + ctx._vertexGlobalState = new WebGLVertexArrayGlobalState(ctx); + + ctx._maxTextureSize = ctx.getParameter(ctx.MAX_TEXTURE_SIZE); + ctx._maxTextureLevel = bits.log2(bits.nextPow2(ctx._maxTextureSize)); + ctx._maxCubeMapSize = ctx.getParameter(ctx.MAX_CUBE_MAP_TEXTURE_SIZE); + ctx._maxCubeMapLevel = bits.log2(bits.nextPow2(ctx._maxCubeMapSize)); + + ctx._unpackAlignment = 4; + ctx._packAlignment = 4; + + ctx._allocateDrawingBuffer(width, height); + + const attrib0Buffer = ctx.createBuffer(); + ctx._attrib0Buffer = attrib0Buffer; + + ctx.bindBuffer(ctx.ARRAY_BUFFER, null); + ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null); + ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); + ctx.bindRenderbuffer(ctx.RENDERBUFFER, null); + + ctx.viewport(0, 0, width, height); + ctx.scissor(0, 0, width, height); + + ctx.clearDepth(1); + ctx.clearColor(0, 0, 0, 0); + ctx.clearStencil(0); + ctx.clear( + ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT, + ); + + return wrapContext(ctx); +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 00000000..c88a7927 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,227 @@ +import { gl } from './native-gl'; +import { WebGLUniformLocation } from './webgl-uniform-location'; + +export function bindPublics( + props: string[], + wrapper: any, + privateInstance: any, + privateMethods: string[], +): void { + for (let i = 0; i < props.length; i++) { + const prop = props[i]; + const value = privateInstance[prop]; + if (typeof value === 'function') { + if (privateMethods.indexOf(prop) === -1) { + Object.defineProperty(wrapper, prop, { + value: value.bind(privateInstance), + writable: true, + configurable: true, + enumerable: false, + }); + } + } else { + if (prop[0] === '_' || prop[0] === '0' || prop[0] === '1') { + continue; + } + wrapper[prop] = value; + } + } +} + +export function checkObject(object: unknown): boolean { + return typeof object === 'object' || object === undefined; +} + +export function checkUniform(program: any, location: any): boolean { + return ( + location instanceof WebGLUniformLocation && + location._program === program && + location._linkCount === program._linkCount + ); +} + +export function isTypedArray(data: unknown): boolean { + return ( + data instanceof Uint8Array || + data instanceof Uint8ClampedArray || + data instanceof Int8Array || + data instanceof Uint16Array || + data instanceof Int16Array || + data instanceof Uint32Array || + data instanceof Int32Array || + data instanceof Float32Array || + data instanceof Float64Array + ); +} + +// Don't allow: ", $, `, @, \, ', \0 +export function isValidString(str: string): boolean { + const c = str.replace( + /(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, + '', + ); + return !/["$`@\\'\0]/.test(c); +} + +export function vertexCount(primitive: number, count: number): number { + switch (primitive) { + case gl.TRIANGLES: + return count - (count % 3); + case gl.LINES: + return count - (count % 2); + case gl.LINE_LOOP: + case gl.POINTS: + return count; + case gl.TRIANGLE_FAN: + case gl.LINE_STRIP: + if (count < 2) return 0; + return count; + case gl.TRIANGLE_STRIP: + if (count < 3) return 0; + return count; + default: + return -1; + } +} + +export function typeSize(type: number): number { + switch (type) { + case gl.UNSIGNED_BYTE: + case gl.BYTE: + return 1; + case gl.UNSIGNED_SHORT: + case gl.SHORT: + return 2; + case gl.UNSIGNED_INT: + case gl.INT: + case gl.FLOAT: + return 4; + } + return 0; +} + +export function uniformTypeSize(type: number): number { + switch (type) { + case gl.BOOL_VEC4: + case gl.INT_VEC4: + case gl.FLOAT_VEC4: + return 4; + case gl.BOOL_VEC3: + case gl.INT_VEC3: + case gl.FLOAT_VEC3: + return 3; + case gl.BOOL_VEC2: + case gl.INT_VEC2: + case gl.FLOAT_VEC2: + return 2; + case gl.BOOL: + case gl.INT: + case gl.FLOAT: + case gl.SAMPLER_2D: + case gl.SAMPLER_CUBE: + return 1; + default: + return 0; + } +} + +export function unpackTypedArray(array: ArrayBufferView): Uint8Array { + return new Uint8Array(array.buffer).subarray( + array.byteOffset, + (array as any).byteLength + array.byteOffset, + ); +} + +export function extractImageData(pixels: any): any { + if ( + typeof pixels === 'object' && + typeof pixels.width !== 'undefined' && + typeof pixels.height !== 'undefined' + ) { + if (typeof pixels.data !== 'undefined') { + return pixels; + } + + let context: CanvasRenderingContext2D | null = null; + + if (typeof pixels.getContext === 'function') { + context = pixels.getContext('2d'); + } else if ( + typeof pixels.src !== 'undefined' && + typeof document === 'object' && + typeof document.createElement === 'function' + ) { + const canvas = document.createElement('canvas'); + if ( + typeof canvas === 'object' && + typeof canvas.getContext === 'function' + ) { + canvas.width = pixels.width; + canvas.height = pixels.height; + context = canvas.getContext('2d'); + if (context !== null) { + context.drawImage(pixels, 0, 0); + } + } + } + + if (context !== null) { + return context!.getImageData(0, 0, pixels.width, pixels.height); + } + } + return null; +} + +export function formatSize(internalFormat: number): number { + switch (internalFormat) { + case gl.ALPHA: + case gl.LUMINANCE: + return 1; + case gl.LUMINANCE_ALPHA: + return 2; + case gl.RGB: + return 3; + case gl.RGBA: + return 4; + } + return 0; +} + +export function convertPixels(pixels: any): Uint8Array | null { + if (typeof pixels === 'object' && pixels !== null) { + if (pixels instanceof ArrayBuffer) { + return new Uint8Array(pixels); + } else if ( + pixels instanceof Uint8Array || + pixels instanceof Uint16Array || + pixels instanceof Uint8ClampedArray || + pixels instanceof Float32Array + ) { + return unpackTypedArray(pixels); + } else if (pixels instanceof Buffer) { + return new Uint8Array(pixels); + } + } + return null; +} + +export function checkFormat(format: number): boolean { + return ( + format === gl.ALPHA || + format === gl.LUMINANCE_ALPHA || + format === gl.LUMINANCE || + format === gl.RGB || + format === gl.RGBA + ); +} + +export function validCubeTarget(target: number): boolean { + return ( + target === gl.TEXTURE_CUBE_MAP_POSITIVE_X || + target === gl.TEXTURE_CUBE_MAP_NEGATIVE_X || + target === gl.TEXTURE_CUBE_MAP_POSITIVE_Y || + target === gl.TEXTURE_CUBE_MAP_NEGATIVE_Y || + target === gl.TEXTURE_CUBE_MAP_POSITIVE_Z || + target === gl.TEXTURE_CUBE_MAP_NEGATIVE_Z + ); +} diff --git a/src/webgl-active-info.ts b/src/webgl-active-info.ts new file mode 100644 index 00000000..b36f4f8d --- /dev/null +++ b/src/webgl-active-info.ts @@ -0,0 +1,11 @@ +export class WebGLActiveInfo { + size: number; + type: number; + name: string; + + constructor(_: { size: number; type: number; name: string }) { + this.size = _.size; + this.type = _.type; + this.name = _.name; + } +} diff --git a/src/webgl-buffer.ts b/src/webgl-buffer.ts new file mode 100644 index 00000000..0464b6af --- /dev/null +++ b/src/webgl-buffer.ts @@ -0,0 +1,21 @@ +import { Linkable } from './linkable'; +import { gl } from './native-gl'; + +export class WebGLBuffer extends Linkable { + _ctx: any; + _size: number; + _elements: Uint8Array; + + constructor(_: number, ctx: any) { + super(_); + this._ctx = ctx; + this._size = 0; + this._elements = new Uint8Array(0); + } + + _performDelete(): void { + const ctx = this._ctx; + delete ctx._buffers[this._ | 0]; + gl.deleteBuffer.call(ctx, this._ | 0); + } +} diff --git a/src/webgl-context-attributes.ts b/src/webgl-context-attributes.ts new file mode 100644 index 00000000..444ef22c --- /dev/null +++ b/src/webgl-context-attributes.ts @@ -0,0 +1,33 @@ +export class WebGLContextAttributes { + alpha: boolean; + depth: boolean; + stencil: boolean; + antialias: boolean; + premultipliedAlpha: boolean; + preserveDrawingBuffer: boolean; + preferLowPowerToHighPerformance: boolean; + failIfMajorPerformanceCaveat: boolean; + createWebGL2Context: boolean; + + constructor( + alpha: boolean, + depth: boolean, + stencil: boolean, + antialias: boolean, + premultipliedAlpha: boolean, + preserveDrawingBuffer: boolean, + preferLowPowerToHighPerformance: boolean, + failIfMajorPerformanceCaveat: boolean, + createWebGL2Context: boolean, + ) { + this.alpha = alpha; + this.depth = depth; + this.stencil = stencil; + this.antialias = antialias; + this.premultipliedAlpha = premultipliedAlpha; + this.preserveDrawingBuffer = preserveDrawingBuffer; + this.preferLowPowerToHighPerformance = preferLowPowerToHighPerformance; + this.failIfMajorPerformanceCaveat = failIfMajorPerformanceCaveat; + this.createWebGL2Context = createWebGL2Context; + } +} diff --git a/src/webgl-drawing-buffer-wrapper.ts b/src/webgl-drawing-buffer-wrapper.ts new file mode 100644 index 00000000..534443cb --- /dev/null +++ b/src/webgl-drawing-buffer-wrapper.ts @@ -0,0 +1,11 @@ +export class WebGLDrawingBufferWrapper { + _framebuffer: number; + _color: number; + _depthStencil: number; + + constructor(framebuffer: number, color: number, depthStencil: number) { + this._framebuffer = framebuffer; + this._color = color; + this._depthStencil = depthStencil; + } +} diff --git a/src/webgl-framebuffer.ts b/src/webgl-framebuffer.ts new file mode 100644 index 00000000..09f1d40f --- /dev/null +++ b/src/webgl-framebuffer.ts @@ -0,0 +1,24 @@ +import { Linkable } from './linkable'; +import { gl } from './native-gl'; + +export class WebGLFramebuffer extends Linkable { + _ctx: any; + _width: number; + _height: number; + _status: number | null; + + constructor(_: number, ctx: any) { + super(_); + this._ctx = ctx; + this._binding = 0; + this._width = 0; + this._height = 0; + this._status = null; + } + + _performDelete(): void { + const ctx = this._ctx; + delete ctx._framebuffers[this._ | 0]; + gl.deleteFramebuffer.call(ctx, this._ | 0); + } +} diff --git a/src/webgl-program.ts b/src/webgl-program.ts new file mode 100644 index 00000000..42c21b9a --- /dev/null +++ b/src/webgl-program.ts @@ -0,0 +1,28 @@ +import { Linkable } from './linkable'; +import { gl } from './native-gl'; +import type { WebGLActiveInfo } from './webgl-active-info'; + +export class WebGLProgram extends Linkable { + _ctx: any; + _linkCount: number; + _linkStatus: boolean; + _linkInfoLog: string; + _attributes: number[]; + _uniforms: WebGLActiveInfo[]; + + constructor(_: number, ctx: any) { + super(_); + this._ctx = ctx; + this._linkCount = 0; + this._linkStatus = false; + this._linkInfoLog = 'not linked'; + this._attributes = []; + this._uniforms = []; + } + + _performDelete(): void { + const ctx = this._ctx; + delete ctx._programs[this._ | 0]; + gl.deleteProgram.call(ctx, this._ | 0); + } +} diff --git a/src/webgl-renderbuffer.ts b/src/webgl-renderbuffer.ts new file mode 100644 index 00000000..e3ef782c --- /dev/null +++ b/src/webgl-renderbuffer.ts @@ -0,0 +1,24 @@ +import { Linkable } from './linkable'; +import { gl } from './native-gl'; + +export class WebGLRenderbuffer extends Linkable { + _ctx: any; + _width: number; + _height: number; + _format: number; + + constructor(_: number, ctx: any) { + super(_); + this._ctx = ctx; + this._binding = 0; + this._width = 0; + this._height = 0; + this._format = 0; + } + + _performDelete(): void { + const ctx = this._ctx; + delete ctx._renderbuffers[this._ | 0]; + gl.deleteRenderbuffer.call(ctx, this._ | 0); + } +} diff --git a/src/webgl-rendering-context.ts b/src/webgl-rendering-context.ts new file mode 100644 index 00000000..cdd7da29 --- /dev/null +++ b/src/webgl-rendering-context.ts @@ -0,0 +1,3148 @@ +// eslint-disable-next-line @typescript-eslint/no-require-imports +const HEADLESS_VERSION = require('../package.json').version as string; +import { gl, NativeWebGLRenderingContext, NativeWebGL } from './native-gl'; +import { getANGLEInstancedArrays } from './extensions/angle-instanced-arrays'; +import { getOESElementIndexUint } from './extensions/oes-element-index-unit'; +import { getOESStandardDerivatives } from './extensions/oes-standard-derivatives'; +import { getOESTextureFloat } from './extensions/oes-texture-float'; +import { getOESTextureFloatLinear } from './extensions/oes-texture-float-linear'; +import { getSTACKGLDestroyContext } from './extensions/stackgl-destroy-context'; +import { getSTACKGLResizeDrawingBuffer } from './extensions/stackgl-resize-drawing-buffer'; +import { getWebGLDrawBuffers } from './extensions/webgl-draw-buffers'; +import { getEXTBlendMinMax } from './extensions/ext-blend-minmax'; +import { getEXTTextureFilterAnisotropic } from './extensions/ext-texture-filter-anisotropic'; +import { getEXTShaderTextureLod } from './extensions/ext-shader-texture-lod'; +import { getOESVertexArrayObject } from './extensions/oes-vertex-array-object'; +import { + bindPublics, + checkObject, + checkUniform, + isValidString, + typeSize, + uniformTypeSize, + extractImageData, + isTypedArray, + unpackTypedArray, + convertPixels, + validCubeTarget, +} from './utils'; + +import { WebGLActiveInfo } from './webgl-active-info'; +import { WebGLFramebuffer } from './webgl-framebuffer'; +import { WebGLBuffer } from './webgl-buffer'; +import { WebGLDrawingBufferWrapper } from './webgl-drawing-buffer-wrapper'; +import { WebGLProgram } from './webgl-program'; +import { WebGLRenderbuffer } from './webgl-renderbuffer'; +import { WebGLShader } from './webgl-shader'; +import { WebGLShaderPrecisionFormat } from './webgl-shader-precision-format'; +import { WebGLTexture } from './webgl-texture'; +import { WebGLUniformLocation } from './webgl-uniform-location'; +import { WebGLVertexArrayObject } from './webgl-vertex-array-object'; +import { getEXTColorBufferFloat } from './extensions/ext-color-buffer-float'; + +// These are defined by the WebGL spec +const MAX_UNIFORM_LENGTH = 256; +const MAX_ATTRIBUTE_LENGTH = 256; + +const DEFAULT_ATTACHMENTS = [ + gl.COLOR_ATTACHMENT0, + gl.DEPTH_ATTACHMENT, + gl.STENCIL_ATTACHMENT, + gl.DEPTH_STENCIL_ATTACHMENT, +]; + +const DEFAULT_COLOR_ATTACHMENTS = [gl.COLOR_ATTACHMENT0]; + +const availableExtensions: Record any> = { + angle_instanced_arrays: getANGLEInstancedArrays, + oes_element_index_uint: getOESElementIndexUint, + oes_texture_float: getOESTextureFloat, + oes_texture_float_linear: getOESTextureFloatLinear, + oes_standard_derivatives: getOESStandardDerivatives, + oes_vertex_array_object: getOESVertexArrayObject, + stackgl_destroy_context: getSTACKGLDestroyContext, + stackgl_resize_drawingbuffer: getSTACKGLResizeDrawingBuffer, + webgl_draw_buffers: getWebGLDrawBuffers, + ext_blend_minmax: getEXTBlendMinMax, + ext_texture_filter_anisotropic: getEXTTextureFilterAnisotropic, + ext_shader_texture_lod: getEXTShaderTextureLod, + ext_color_buffer_float: getEXTColorBufferFloat, +}; + +const privateMethods = ['constructor', 'resize', 'destroy']; + +export function wrapContext(ctx: any): any { + const isWebGL2 = ctx.constructor.name === 'WebGL2RenderingContext'; + const wrapper = isWebGL2 + ? new WebGL2RenderingContext() + : new WebGLRenderingContext(); + + let proto = ctx; + while (proto && proto !== Object.prototype) { + bindPublics(Object.keys(proto), wrapper, ctx, privateMethods); + bindPublics( + Object.keys(proto.constructor.prototype), + wrapper, + ctx, + privateMethods, + ); + bindPublics( + Object.getOwnPropertyNames(proto), + wrapper, + ctx, + privateMethods, + ); + bindPublics( + Object.getOwnPropertyNames(proto.constructor.prototype), + wrapper, + ctx, + privateMethods, + ); + proto = Object.getPrototypeOf(proto); + } + + Object.defineProperties(wrapper, { + drawingBufferWidth: { + get() { + return ctx.drawingBufferWidth; + }, + set(value) { + ctx.drawingBufferWidth = value; + }, + }, + drawingBufferHeight: { + get() { + return ctx.drawingBufferHeight; + }, + set(value) { + ctx.drawingBufferHeight = value; + }, + }, + }); + + return wrapper; +} + +// We need to wrap some of the native WebGL functions to handle certain error codes and check input values +class WebGLRenderingContextHelper extends NativeWebGLRenderingContext { + _checkLocation(location: any): boolean { + if (!(location instanceof WebGLUniformLocation)) { + this.setError(this.INVALID_VALUE); + return false; + } else if ( + location._program._ctx !== this || + location._linkCount !== location._program._linkCount + ) { + this.setError(this.INVALID_OPERATION); + return false; + } + return true; + } + + _checkLocationActive(location: any): boolean { + if (!location) { + return false; + } else if (!this._checkLocation(location)) { + return false; + } else if (location._program !== this._activeProgram) { + this.setError(this.INVALID_OPERATION); + return false; + } + return true; + } + + _checkOwns(object: any): boolean { + return typeof object === 'object' && object._ctx === this; + } + + _checkShaderSource(_shader: any): boolean { + return true; + } + + _checkTextureTarget(target: number): boolean { + const unit = this._getActiveTextureUnit(); + let tex = null; + if (target === this.TEXTURE_2D) { + tex = unit._bind2D; + } else if (target === this.TEXTURE_CUBE_MAP) { + tex = unit._bindCube; + } else if (this._isWebGL2() && target === this.TEXTURE_3D) { + tex = unit._bind3D; + } else if (this._isWebGL2() && target === this.TEXTURE_2D_ARRAY) { + tex = unit._bind2DArray; + } else { + this.setError(this.INVALID_ENUM); + return false; + } + if (!tex) { + this.setError(this.INVALID_OPERATION); + return false; + } + return true; + } + + _checkWrapper(object: any, Wrapper: any): boolean { + if (!this._checkValid(object, Wrapper)) { + this.setError(this.INVALID_VALUE); + return false; + } else if (!this._checkOwns(object)) { + this.setError(this.INVALID_OPERATION); + return false; + } + return true; + } + + _checkValid(object: any, Type: any): boolean { + return object instanceof Type && object._ !== 0; + } + + _checkVertexIndex(index: number): boolean { + if (index < 0 || index >= this._vertexObjectState._attribs.length) { + this.setError(this.INVALID_VALUE); + return false; + } + return true; + } + + _fixupLink(program: any): boolean { + if (!super.getProgramParameter(program._, this.LINK_STATUS)) { + program._linkInfoLog = super.getProgramInfoLog(program._); + return false; + } + + // Record attribute attributeLocations + const numAttribs = this.getProgramParameter( + program, + this.ACTIVE_ATTRIBUTES, + ); + const names = new Array(numAttribs); + program._attributes.length = numAttribs; + for (let i = 0; i < numAttribs; ++i) { + names[i] = this.getActiveAttrib(program, i)!.name; + program._attributes[i] = this.getAttribLocation(program, names[i]) | 0; + } + + // Check attribute names + for (let i = 0; i < names.length; ++i) { + if (names[i].length > MAX_ATTRIBUTE_LENGTH) { + program._linkInfoLog = 'attribute ' + names[i] + ' is too long'; + return false; + } + } + + for (let i = 0; i < numAttribs; ++i) { + super.bindAttribLocation(program._ | 0, program._attributes[i], names[i]); + } + + super.linkProgram(program._ | 0); + + const numUniforms = this.getProgramParameter(program, this.ACTIVE_UNIFORMS); + program._uniforms.length = numUniforms; + for (let i = 0; i < numUniforms; ++i) { + program._uniforms[i] = this.getActiveUniform(program, i); + } + + // Check attribute and uniform name lengths + for (let i = 0; i < program._uniforms.length; ++i) { + if (program._uniforms[i].name.length > MAX_UNIFORM_LENGTH) { + program._linkInfoLog = + 'uniform ' + program._uniforms[i].name + ' is too long'; + return false; + } + } + + program._linkInfoLog = ''; + return true; + } + + _framebufferOk(): boolean { + return true; + } + + _getActiveBuffer(target: number): any { + if (target === this.ARRAY_BUFFER) { + return this._vertexGlobalState._arrayBufferBinding; + } else if (target === this.ELEMENT_ARRAY_BUFFER) { + return this._vertexObjectState._elementArrayBufferBinding; + } + return null; + } + + _getActiveTextureUnit(): any { + return this._textureUnits[this._activeTextureUnit]; + } + + _getActiveTexture(target: number): any { + const activeUnit = this._getActiveTextureUnit(); + if (target === this.TEXTURE_2D) { + return activeUnit._bind2D; + } else if (target === this.TEXTURE_CUBE_MAP) { + return activeUnit._bindCube; + } else if (this._isWebGL2() && target === this.TEXTURE_2D_ARRAY) { + return activeUnit._bind2DArray; + } else if (this._isWebGL2() && target === this.TEXTURE_3D) { + return activeUnit._bind3D; + } + return null; + } + + _getActiveFramebuffer(target: number): any { + if (target === this.READ_FRAMEBUFFER) { + return this._activeFramebuffers.read; + } else { + return this._activeFramebuffers.draw; + } + } + + _getAttachments(): number[] { + return this._extensions.webgl_draw_buffers + ? this._extensions.webgl_draw_buffers._ALL_ATTACHMENTS + : DEFAULT_ATTACHMENTS; + } + + _getColorAttachments(): number[] { + return this._extensions.webgl_draw_buffers + ? this._extensions.webgl_draw_buffers._ALL_COLOR_ATTACHMENTS + : DEFAULT_COLOR_ATTACHMENTS; + } + + _getParameterDirect(pname: number): any { + return super.getParameter(pname); + } + + _getTexImage(target: number): any { + const unit = this._getActiveTextureUnit(); + if (target === this.TEXTURE_2D) { + return unit._bind2D; + } else if (validCubeTarget(target)) { + return unit._bindCube; + } + this.setError(this.INVALID_ENUM); + return null; + } + + _isConstantColorBlendFunc(factor: number): boolean { + return ( + factor === this.CONSTANT_COLOR || factor === this.ONE_MINUS_CONSTANT_COLOR + ); + } + + _isConstantAlphaBlendFunc(factor: number): boolean { + return ( + factor === this.CONSTANT_ALPHA || factor === this.ONE_MINUS_CONSTANT_ALPHA + ); + } + + _isObject(object: any, method: string, Wrapper: any): boolean { + if ( + !(object === null || object === undefined) && + !(object instanceof Wrapper) + ) { + throw new TypeError(method + '(' + Wrapper.name + ')'); + } + if (this._checkValid(object, Wrapper) && this._checkOwns(object)) { + return true; + } + return false; + } + + _resizeDrawingBuffer(width: number, height: number): void { + const prevFramebuffer = this._activeFramebuffers.draw; + const prevTexture = this._getActiveTexture(this.TEXTURE_2D); + const prevRenderbuffer = this._activeRenderbuffer; + + const contextAttributes = this._contextAttributes; + + const drawingBuffer = this._drawingBuffer; + super.bindFramebuffer(this.FRAMEBUFFER, drawingBuffer._framebuffer); + const attachments = this._getAttachments(); + // Clear all attachments + for (let i = 0; i < attachments.length; ++i) { + super.framebufferTexture2D( + this.FRAMEBUFFER, + attachments[i], + this.TEXTURE_2D, + 0, + 0, + ); + } + + // Update color attachment + super.bindTexture(this.TEXTURE_2D, drawingBuffer._color); + const colorFormat = contextAttributes.alpha ? this.RGBA : this.RGB; + super.texImage2D( + this.TEXTURE_2D, + 0, + colorFormat, + width, + height, + 0, + colorFormat, + this.UNSIGNED_BYTE, + null, + ); + super.texParameteri(this.TEXTURE_2D, this.TEXTURE_MIN_FILTER, this.NEAREST); + super.texParameteri(this.TEXTURE_2D, this.TEXTURE_MAG_FILTER, this.NEAREST); + super.framebufferTexture2D( + this.FRAMEBUFFER, + this.COLOR_ATTACHMENT0, + this.TEXTURE_2D, + drawingBuffer._color, + 0, + ); + + // Update depth-stencil attachments if needed + let storage = 0; + let attachment = 0; + if (contextAttributes.depth && contextAttributes.stencil) { + storage = this.DEPTH_STENCIL; + attachment = this.DEPTH_STENCIL_ATTACHMENT; + } else if (contextAttributes.depth) { + storage = 0x81a7; + attachment = this.DEPTH_ATTACHMENT; + } else if (contextAttributes.stencil) { + storage = this.STENCIL_INDEX8; + attachment = this.STENCIL_ATTACHMENT; + } + + if (storage) { + super.bindRenderbuffer(this.RENDERBUFFER, drawingBuffer._depthStencil); + super.renderbufferStorage(this.RENDERBUFFER, storage, width, height); + super.framebufferRenderbuffer( + this.FRAMEBUFFER, + attachment, + this.RENDERBUFFER, + drawingBuffer._depthStencil, + ); + } + + // Restore previous binding state + this.bindFramebuffer(this.FRAMEBUFFER, prevFramebuffer); + this.bindTexture(this.TEXTURE_2D, prevTexture); + this.bindRenderbuffer(this.RENDERBUFFER, prevRenderbuffer); + } + + _restoreError(lastError: number): void { + const topError = this._errorStack.pop(); + if (topError === this.NO_ERROR) { + this.setError(lastError); + } else { + this.setError(topError); + } + } + + _saveError(): void { + this._errorStack.push(this.getError()); + } + + _switchActiveProgram(active: any): void { + if (active) { + active._refCount -= 1; + active._checkDelete(); + } + } + + _validBlendFunc(factor: number): boolean { + return ( + factor === this.ZERO || + factor === this.ONE || + factor === this.SRC_COLOR || + factor === this.ONE_MINUS_SRC_COLOR || + factor === this.DST_COLOR || + factor === this.ONE_MINUS_DST_COLOR || + factor === this.SRC_ALPHA || + factor === this.ONE_MINUS_SRC_ALPHA || + factor === this.DST_ALPHA || + factor === this.ONE_MINUS_DST_ALPHA || + factor === this.SRC_ALPHA_SATURATE || + factor === this.CONSTANT_COLOR || + factor === this.ONE_MINUS_CONSTANT_COLOR || + factor === this.CONSTANT_ALPHA || + factor === this.ONE_MINUS_CONSTANT_ALPHA + ); + } + + _validBlendMode(mode: number): boolean { + return ( + mode === this.FUNC_ADD || + mode === this.FUNC_SUBTRACT || + mode === this.FUNC_REVERSE_SUBTRACT || + (this._extensions.ext_blend_minmax && + (mode === this._extensions.ext_blend_minmax.MIN_EXT || + mode === this._extensions.ext_blend_minmax.MAX_EXT)) + ); + } + + _validCubeTarget(target: number): boolean { + return ( + target === this.TEXTURE_CUBE_MAP_POSITIVE_X || + target === this.TEXTURE_CUBE_MAP_NEGATIVE_X || + target === this.TEXTURE_CUBE_MAP_POSITIVE_Y || + target === this.TEXTURE_CUBE_MAP_NEGATIVE_Y || + target === this.TEXTURE_CUBE_MAP_POSITIVE_Z || + target === this.TEXTURE_CUBE_MAP_NEGATIVE_Z + ); + } + + _validFramebufferAttachment(attachment: number): boolean { + switch (attachment) { + case this.DEPTH_ATTACHMENT: + case this.STENCIL_ATTACHMENT: + case this.DEPTH_STENCIL_ATTACHMENT: + case this.COLOR_ATTACHMENT0: + return true; + } + + if (this._extensions.webgl_draw_buffers) { + // eslint-disable-line + const { webgl_draw_buffers } = this._extensions; // eslint-disable-line + return ( + attachment < + webgl_draw_buffers.COLOR_ATTACHMENT0_WEBGL + + webgl_draw_buffers._maxDrawBuffers + ); // eslint-disable-line + } + + return false; + } + + _validGLSLIdentifier(str: string): boolean { + return !( + str.indexOf('webgl_') === 0 || + str.indexOf('_webgl_') === 0 || + str.length > 256 + ); + } + + _validTextureTarget(target: number): boolean { + return target === this.TEXTURE_2D || target === this.TEXTURE_CUBE_MAP; + } + + _verifyTextureCompleteness( + target: number, + pname: number, + param: number, + ): void { + const unit = this._getActiveTextureUnit(); + let texture = null; + if (target === this.TEXTURE_2D) { + texture = unit._bind2D; + } else if (this._validCubeTarget(target)) { + texture = unit._bindCube; + } + + // oes_texture_float but not oes_texture_float_linear + if ( + this._extensions.oes_texture_float && + !this._extensions.oes_texture_float_linear && + texture && + texture._type === this.FLOAT && + (pname === this.TEXTURE_MAG_FILTER || + pname === this.TEXTURE_MIN_FILTER) && + (param === this.LINEAR || + param === this.LINEAR_MIPMAP_NEAREST || + param === this.NEAREST_MIPMAP_LINEAR || + param === this.LINEAR_MIPMAP_LINEAR) + ) { + texture._complete = false; + this.bindTexture(target, texture); + return; + } + + if (texture && texture._complete === false) { + texture._complete = true; + this.bindTexture(target, texture); + } + } + + _wrapShader(_type: number, source: string): string { + return source; + } + + activeTexture(texture: number): void { + texture |= 0; + const texNum = texture - this.TEXTURE0; + if (texNum >= 0 && texNum < this._textureUnits.length) { + this._activeTextureUnit = texNum; + return super.activeTexture(texture); + } + + this.setError(this.INVALID_ENUM); + } + + attachShader(program: any, shader: any): void { + if (!checkObject(program) || !checkObject(shader)) { + throw new TypeError('attachShader(WebGLProgram, WebGLShader)'); + } + if (!program || !shader) { + this.setError(this.INVALID_VALUE); + return; + } else if ( + program instanceof WebGLProgram && + shader instanceof WebGLShader && + this._checkOwns(program) && + this._checkOwns(shader) + ) { + if (!program._linked(shader)) { + this._saveError(); + super.attachShader(program._ | 0, shader._ | 0); + const error = this.getError(); + this._restoreError(error); + if (error === this.NO_ERROR) { + program._link(shader); + } + return; + } + } + this.setError(this.INVALID_OPERATION); + } + + bindAttribLocation(program: any, index: number, name: string): void { + if (!checkObject(program) || typeof name !== 'string') { + throw new TypeError('bindAttribLocation(WebGLProgram, GLint, String)'); + } + name += ''; + if (!isValidString(name) || name.length > MAX_ATTRIBUTE_LENGTH) { + this.setError(this.INVALID_VALUE); + } else if (/^_?webgl_a/.test(name)) { + this.setError(this.INVALID_OPERATION); + } else if (this._checkWrapper(program, WebGLProgram)) { + return super.bindAttribLocation(program._ | 0, index | 0, name); + } + } + + bindFramebuffer(target: number, framebuffer: any): void { + if (!checkObject(framebuffer)) { + throw new TypeError('bindFramebuffer(GLenum, WebGLFramebuffer)'); + } + let error = 0; + if (!framebuffer) { + this._saveError(); + super.bindFramebuffer(target, this._drawingBuffer._framebuffer); + error = super.getError(); + this._restoreError(error); + } else if (framebuffer._pendingDelete) { + return; + } else if (this._checkWrapper(framebuffer, WebGLFramebuffer)) { + this._saveError(); + super.bindFramebuffer(target, framebuffer._ | 0); + error = super.getError(); + this._restoreError(error); + } else { + return; + } + + if (target === this.FRAMEBUFFER) { + this._activeFramebuffers.draw = framebuffer; + this._activeFramebuffers.read = framebuffer; + } else if (target === this.READ_FRAMEBUFFER) { + this._activeFramebuffers.read = framebuffer; + } else if (target === this.DRAW_FRAMEBUFFER) { + this._activeFramebuffers.draw = framebuffer; + } + } + + bindBuffer(target: number, buffer: any): void { + target |= 0; + if (!checkObject(buffer)) { + throw new TypeError('bindBuffer(GLenum, WebGLBuffer)'); + } + if (target !== this.ARRAY_BUFFER && target !== this.ELEMENT_ARRAY_BUFFER) { + this.setError(this.INVALID_ENUM); + return; + } + + if (!buffer) { + buffer = null; + super.bindBuffer(target, 0); + } else if (buffer._pendingDelete) { + return; + } else if (this._checkWrapper(buffer, WebGLBuffer)) { + if (buffer._binding && buffer._binding !== target) { + this.setError(this.INVALID_OPERATION); + return; + } + buffer._binding = target | 0; + + super.bindBuffer(target, buffer._ | 0); + } else { + return; + } + + if (target === this.ARRAY_BUFFER) { + // Buffers of type ARRAY_BUFFER are bound to the global vertex state. + this._vertexGlobalState.setArrayBuffer(buffer); + } else { + // Buffers of type ELEMENT_ARRAY_BUFFER are bound to vertex array object state. + this._vertexObjectState.setElementArrayBuffer(buffer); + } + } + + bindRenderbuffer(target: number, object: any): void { + if (!checkObject(object)) { + throw new TypeError('bindRenderbuffer(GLenum, WebGLRenderbuffer)'); + } + + if (target !== this.RENDERBUFFER) { + this.setError(this.INVALID_ENUM); + return; + } + + if (!object) { + super.bindRenderbuffer(target | 0, 0); + } else if (object._pendingDelete) { + return; + } else if (this._checkWrapper(object, WebGLRenderbuffer)) { + super.bindRenderbuffer(target | 0, object._ | 0); + } else { + return; + } + const active = this._activeRenderbuffer; + if (active !== object) { + if (active) { + active._refCount -= 1; + active._checkDelete(); + } + if (object) { + object._refCount += 1; + } + } + this._activeRenderbuffer = object; + } + + bindTexture(target: number, texture: any): void { + target |= 0; + + if (!checkObject(texture)) { + throw new TypeError('bindTexture(GLenum, WebGLTexture)'); + } + + // Get texture id + let textureId = 0; + if (!texture) { + texture = null; + } else if (texture instanceof WebGLTexture && texture._pendingDelete) { + // Special case: error codes for deleted textures don't get set for some dumb reason + return; + } else if (this._checkWrapper(texture, WebGLTexture)) { + texture._binding = target; + textureId = texture._ | 0; + } else { + return; + } + + this._saveError(); + super.bindTexture(target, textureId); + const error = this.getError(); + this._restoreError(error); + + if (error !== this.NO_ERROR) { + return; + } + + const activeUnit = this._getActiveTextureUnit(); + const activeTex = this._getActiveTexture(target); + + // Update references + if (activeTex !== texture) { + if (activeTex) { + activeTex._refCount -= 1; + activeTex._checkDelete(); + } + if (texture) { + texture._refCount += 1; + } + } + + if (target === this.TEXTURE_2D) { + activeUnit._bind2D = texture; + } else if (target === this.TEXTURE_CUBE_MAP) { + activeUnit._bindCube = texture; + } else if (this._isWebGL2() && target === this.TEXTURE_2D_ARRAY) { + activeUnit._bind2DArray = texture; + } else if (this._isWebGL2() && target === this.TEXTURE_3D) { + activeUnit._bind3D = texture; + } + } + + bindVertexArray(array: any): void { + if (!checkObject(array)) { + throw new TypeError('bindVertexArray(WebGLVertexArrayObject)'); + } + + if (!array) { + array = null; + super.bindVertexArray(null); + } else if ( + array instanceof WebGLVertexArrayObject && + array._pendingDelete + ) { + this.setError(gl.INVALID_OPERATION); + return; + } else if (this._checkWrapper(array, WebGLVertexArrayObject)) { + super.bindVertexArray(array._); + } else { + return; + } + + if (this._activeVertexArrayObject !== array) { + if (this._activeVertexArrayObject) { + this._activeVertexArrayObject._refCount -= 1; + this._activeVertexArrayObject._checkDelete(); + } + if (array) { + array._refCount += 1; + } + } + + if (array === null) { + this._vertexObjectState = this._defaultVertexObjectState; + } else { + this._vertexObjectState = array._vertexState; + } + + // Update the active vertex array object. + this._activeVertexArrayObject = array; + } + + blendColor(red: number, green: number, blue: number, alpha: number): any { + return super.blendColor(+red, +green, +blue, +alpha); + } + + blendEquation(mode: number): void { + mode |= 0; + if (this._validBlendMode(mode)) { + return super.blendEquation(mode); + } + this.setError(this.INVALID_ENUM); + } + + blendEquationSeparate(modeRGB: number, modeAlpha: number): void { + modeRGB |= 0; + modeAlpha |= 0; + if (this._validBlendMode(modeRGB) && this._validBlendMode(modeAlpha)) { + return super.blendEquationSeparate(modeRGB, modeAlpha); + } + this.setError(this.INVALID_ENUM); + } + + createBuffer(): WebGLBuffer | null { + const id = super.createBuffer(); + if (id <= 0) return null; + const webGLBuffer = new WebGLBuffer(id, this); + this._buffers[id] = webGLBuffer; + return webGLBuffer; + } + + createFramebuffer(): WebGLFramebuffer | null { + const id = super.createFramebuffer(); + if (id <= 0) return null; + const webGLFramebuffer = new WebGLFramebuffer(id, this); + this._framebuffers[id] = webGLFramebuffer; + return webGLFramebuffer; + } + + createProgram(): WebGLProgram | null { + const id = super.createProgram(); + if (id <= 0) return null; + const webGLProgram = new WebGLProgram(id, this); + this._programs[id] = webGLProgram; + return webGLProgram; + } + + createRenderbuffer(): WebGLRenderbuffer | null { + const id = super.createRenderbuffer(); + if (id <= 0) return null; + const webGLRenderbuffer = new WebGLRenderbuffer(id, this); + this._renderbuffers[id] = webGLRenderbuffer; + return webGLRenderbuffer; + } + + createTexture(): WebGLTexture | null { + const id = super.createTexture(); + if (id <= 0) return null; + const webGlTexture = new WebGLTexture(id, this); + this._textures[id] = webGlTexture; + return webGlTexture; + } + + createVertexArray(): WebGLVertexArrayObject | null { + // TODO: do not expose VAO methods in WebGL 1 + const arrayId = super.createVertexArray(); + if (arrayId <= 0) return null; + const array = new WebGLVertexArrayObject(arrayId, this); + this._vaos[arrayId] = array; + return array; + } + + getContextAttributes(): any { + return this._contextAttributes; + } + + getExtension(name: string): any { + const str = name.toLowerCase(); + if (str in this._extensions) { + return this._extensions[str]; + } + + if (!(str in availableExtensions)) { + return null; + } + + super.getExtension(str); + const ext = availableExtensions[str](this); + this._extensions[str] = ext; + return ext; + } + + getSupportedExtensions(): string[] { + const ret = super.getSupportedExtensions(); + return ret.split(' '); + } + + setError(error: number): void { + NativeWebGL.setError.call(this, error | 0); + } + + blendFunc(sfactor: number, dfactor: number): void { + sfactor |= 0; + dfactor |= 0; + if (!this._validBlendFunc(sfactor) || !this._validBlendFunc(dfactor)) { + this.setError(this.INVALID_ENUM); + return; + } + if ( + (this._isConstantColorBlendFunc(sfactor) && + this._isConstantAlphaBlendFunc(dfactor)) || + (this._isConstantColorBlendFunc(dfactor) && + this._isConstantAlphaBlendFunc(sfactor)) + ) { + this.setError(this.INVALID_OPERATION); + return; + } + super.blendFunc(sfactor, dfactor); + } + + blendFuncSeparate( + srcRGB: number, + dstRGB: number, + srcAlpha: number, + dstAlpha: number, + ): void { + srcRGB |= 0; + dstRGB |= 0; + srcAlpha |= 0; + dstAlpha |= 0; + + if ( + !( + this._validBlendFunc(srcRGB) && + this._validBlendFunc(dstRGB) && + this._validBlendFunc(srcAlpha) && + this._validBlendFunc(dstAlpha) + ) + ) { + this.setError(this.INVALID_ENUM); + return; + } + + if ( + (this._isConstantColorBlendFunc(srcRGB) && + this._isConstantAlphaBlendFunc(dstRGB)) || + (this._isConstantColorBlendFunc(dstRGB) && + this._isConstantAlphaBlendFunc(srcRGB)) + ) { + this.setError(this.INVALID_OPERATION); + return; + } + + super.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); + } + + bufferData(target: number, data: any, usage: number): void { + target |= 0; + usage |= 0; + if ( + usage !== this.STREAM_DRAW && + usage !== this.STATIC_DRAW && + usage !== this.DYNAMIC_DRAW + ) { + this.setError(this.INVALID_ENUM); + return; + } + + if (target !== this.ARRAY_BUFFER && target !== this.ELEMENT_ARRAY_BUFFER) { + this.setError(this.INVALID_ENUM); + return; + } + + const active = this._getActiveBuffer(target); + if (!active) { + this.setError(this.INVALID_OPERATION); + return; + } + + if (typeof data === 'object') { + let u8Data = null; + if (isTypedArray(data) || data instanceof DataView) { + u8Data = unpackTypedArray(data); + } else if (data instanceof ArrayBuffer) { + u8Data = new Uint8Array(data); + } else { + this.setError(this.INVALID_VALUE); + return; + } + + this._saveError(); + super.bufferData(target, u8Data, usage); + const error = this.getError(); + this._restoreError(error); + if (error !== this.NO_ERROR) { + return; + } + + active._size = u8Data.length; + if (target === this.ELEMENT_ARRAY_BUFFER) { + active._elements = new Uint8Array(u8Data); + } + } else if (typeof data === 'number') { + const size = data | 0; + if (size < 0) { + this.setError(this.INVALID_VALUE); + return; + } + + this._saveError(); + super.bufferData(target, size, usage); + const error = this.getError(); + this._restoreError(error); + if (error !== this.NO_ERROR) { + return; + } + + active._size = size; + if (target === this.ELEMENT_ARRAY_BUFFER) { + active._elements = new Uint8Array(size); + } + } else { + this.setError(this.INVALID_VALUE); + } + } + + bufferSubData(target: number, offset: number, data: any): void { + target |= 0; + offset |= 0; + + if (target !== this.ARRAY_BUFFER && target !== this.ELEMENT_ARRAY_BUFFER) { + this.setError(this.INVALID_ENUM); + return; + } + + if (data === null) { + return; + } + + if (!data || typeof data !== 'object') { + this.setError(this.INVALID_VALUE); + return; + } + + const active = this._getActiveBuffer(target); + if (!active) { + this.setError(this.INVALID_OPERATION); + return; + } + + if (offset < 0 || offset >= active._size) { + this.setError(this.INVALID_VALUE); + return; + } + + let u8Data = null; + if (isTypedArray(data) || data instanceof DataView) { + u8Data = unpackTypedArray(data); + } else if (data instanceof ArrayBuffer) { + u8Data = new Uint8Array(data); + } else { + this.setError(this.INVALID_VALUE); + return; + } + + if (offset + u8Data.length > active._size) { + this.setError(this.INVALID_VALUE); + return; + } + + if (target === this.ELEMENT_ARRAY_BUFFER) { + active._elements.set(u8Data, offset); + } + + super.bufferSubData(target, offset, u8Data); + } + + checkFramebufferStatus(target: number): any { + return super.checkFramebufferStatus(target); + } + + clear(mask: number): any { + if (!this._framebufferOk()) { + return; + } + return super.clear(mask | 0); + } + + clearColor(red: number, green: number, blue: number, alpha: number): any { + return super.clearColor(+red, +green, +blue, +alpha); + } + + clearDepth(depth: number): any { + return super.clearDepth(+depth); + } + + clearStencil(s: number): any { + this._checkStencil = false; + return super.clearStencil(s | 0); + } + + colorMask(red: any, green: any, blue: any, alpha: any): any { + return super.colorMask(!!red, !!green, !!blue, !!alpha); + } + + compileShader(shader: any): void { + if (!checkObject(shader)) { + throw new TypeError('compileShader(WebGLShader)'); + } + if ( + this._checkWrapper(shader, WebGLShader) && + this._checkShaderSource(shader) + ) { + const prevError = this.getError(); + super.compileShader(shader._ | 0); + const error = this.getError(); + shader._compileStatus = !!super.getShaderParameter( + shader._ | 0, + this.COMPILE_STATUS, + ); + shader._compileInfo = super.getShaderInfoLog(shader._ | 0); + this.getError(); + this.setError(prevError || error); + } + } + + copyTexImage2D( + target: number, + level: number, + internalFormat: number, + x: number, + y: number, + width: number, + height: number, + border: number, + ): void { + target |= 0; + level |= 0; + internalFormat |= 0; + x |= 0; + y |= 0; + width |= 0; + height |= 0; + border |= 0; + + this._saveError(); + super.copyTexImage2D( + target, + level, + internalFormat, + x, + y, + width, + height, + border, + ); + const error = this.getError(); + this._restoreError(error); + + if (error === this.NO_ERROR) { + const texture = this._getTexImage(target); + texture._format = gl.RGBA; + texture._type = gl.UNSIGNED_BYTE; + } + } + + copyTexSubImage2D( + target: number, + level: number, + xoffset: number, + yoffset: number, + x: number, + y: number, + width: number, + height: number, + ): void { + target |= 0; + level |= 0; + xoffset |= 0; + yoffset |= 0; + x |= 0; + y |= 0; + width |= 0; + height |= 0; + + super.copyTexSubImage2D( + target, + level, + xoffset, + yoffset, + x, + y, + width, + height, + ); + } + + cullFace(mode: number): any { + return super.cullFace(mode | 0); + } + + createShader(type: number): WebGLShader | null { + type |= 0; + if (type !== this.FRAGMENT_SHADER && type !== this.VERTEX_SHADER) { + this.setError(this.INVALID_ENUM); + return null; + } + const id = super.createShader(type); + if (id < 0) { + return null; + } + const result = new WebGLShader(id, this, type); + this._shaders[id] = result; + return result; + } + + deleteProgram(object: any): void { + return this._deleteLinkable('deleteProgram', object, WebGLProgram); + } + + deleteShader(object: any): void { + return this._deleteLinkable('deleteShader', object, WebGLShader); + } + + _deleteLinkable(name: string, object: any, Type: any): void { + if (!checkObject(object)) { + throw new TypeError(name + '(' + Type.name + ')'); + } + if (object instanceof Type && this._checkOwns(object)) { + object._pendingDelete = true; + object._checkDelete(); + return; + } + if (object !== null) { + this.setError(this.INVALID_OPERATION); + } + } + + deleteBuffer(buffer: any): void { + if ( + !checkObject(buffer) || + (buffer !== null && !(buffer instanceof WebGLBuffer)) + ) { + throw new TypeError('deleteBuffer(WebGLBuffer)'); + } + + if (!(buffer instanceof WebGLBuffer && this._checkOwns(buffer))) { + this.setError(this.INVALID_OPERATION); + return; + } + + if (this._vertexGlobalState._arrayBufferBinding === buffer) { + this.bindBuffer(this.ARRAY_BUFFER, null); + } + if (this._vertexObjectState._elementArrayBufferBinding === buffer) { + this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, null); + } + + if (this._vertexObjectState === this._defaultVertexObjectState) { + // If no vertex array object is bound, release attrib bindings for the + // array buffer. + this._vertexObjectState.releaseArrayBuffer(buffer); + } + + buffer._pendingDelete = true; + buffer._checkDelete(); + } + + deleteFramebuffer(framebuffer: any): void { + if (!checkObject(framebuffer)) { + throw new TypeError('deleteFramebuffer(WebGLFramebuffer)'); + } + + if ( + !(framebuffer instanceof WebGLFramebuffer && this._checkOwns(framebuffer)) + ) { + this.setError(this.INVALID_OPERATION); + return; + } + + if ( + this._activeFramebuffers.draw === framebuffer && + this._activeFramebuffers.read === framebuffer + ) { + this.bindFramebuffer(this.FRAMEBUFFER, null); + } else if (this._isWebGL2()) { + if (this._activeFramebuffers.read === framebuffer) { + this.bindFramebuffer(this.READ_FRAMEBUFFER, null); + } else if (this._activeFramebuffers.draw === framebuffer) { + this.bindFramebuffer(this.DRAW_FRAMEBUFFER, null); + } + } + + framebuffer._pendingDelete = true; + framebuffer._checkDelete(); + } + + deleteRenderbuffer(renderbuffer: any): void { + if (!checkObject(renderbuffer)) { + throw new TypeError('deleteRenderbuffer(WebGLRenderbuffer)'); + } + + if ( + !( + renderbuffer instanceof WebGLRenderbuffer && + this._checkOwns(renderbuffer) + ) + ) { + this.setError(this.INVALID_OPERATION); + return; + } + + if (this._activeRenderbuffer === renderbuffer) { + this.bindRenderbuffer(this.RENDERBUFFER, null); + } + + renderbuffer._pendingDelete = true; + renderbuffer._checkDelete(); + } + + deleteTexture(texture: any): void { + if (!checkObject(texture)) { + throw new TypeError('deleteTexture(WebGLTexture)'); + } + + if (texture instanceof WebGLTexture) { + if (!this._checkOwns(texture)) { + this.setError(this.INVALID_OPERATION); + return; + } + } else { + return; + } + + // Unbind from all texture units + const curActive = this._activeTextureUnit; + + for (let i = 0; i < this._textureUnits.length; ++i) { + const unit = this._textureUnits[i]; + if (unit._bind2D === texture) { + this.activeTexture(this.TEXTURE0 + i); + this.bindTexture(this.TEXTURE_2D, null); + } else if (unit._bindCube === texture) { + this.activeTexture(this.TEXTURE0 + i); + this.bindTexture(this.TEXTURE_CUBE_MAP, null); + } else if (this._isWebGL2() && unit._bind2DArray === texture) { + this.activeTexture(this.TEXTURE_2D_ARRAY); + this.bindTexture(this.TEXTURE_2D_ARRAY, null); + } else if (this._isWebGL2() && unit._bind3D === texture) { + this.activeTexture(this.TEXTURE_3D); + this.bindTexture(this.TEXTURE_3D, null); + } + } + this.activeTexture(this.TEXTURE0 + curActive); + + // Mark texture for deletion + texture._pendingDelete = true; + texture._checkDelete(); + } + + deleteVertexArray(array: any): void { + if (!checkObject(array)) { + throw new TypeError('deleteVertexArray(WebGLVertexArrayObject)'); + } + + if (!(array instanceof WebGLVertexArrayObject && this._checkOwns(array))) { + this.setError(gl.INVALID_OPERATION); + return; + } + + if (array._pendingDelete) { + return; + } + + if (this._activeVertexArrayObject === array) { + this.bindVertexArray(null); + } + + array._pendingDelete = true; + array._checkDelete(); + } + + depthFunc(func: number): void { + func |= 0; + switch (func) { + case this.NEVER: + case this.LESS: + case this.EQUAL: + case this.LEQUAL: + case this.GREATER: + case this.NOTEQUAL: + case this.GEQUAL: + case this.ALWAYS: + return super.depthFunc(func); + default: + this.setError(this.INVALID_ENUM); + } + } + + depthMask(flag: any): any { + return super.depthMask(!!flag); + } + + depthRange(zNear: number, zFar: number): void { + zNear = +zNear; + zFar = +zFar; + if (zNear <= zFar) { + return super.depthRange(zNear, zFar); + } + this.setError(this.INVALID_OPERATION); + } + + destroy(): void { + super.destroy(); + } + + detachShader(program: any, shader: any): void { + if (!checkObject(program) || !checkObject(shader)) { + throw new TypeError('detachShader(WebGLProgram, WebGLShader)'); + } + if ( + this._checkWrapper(program, WebGLProgram) && + this._checkWrapper(shader, WebGLShader) + ) { + if (program._linked(shader)) { + super.detachShader(program._, shader._); + program._unlink(shader); + } else { + this.setError(this.INVALID_OPERATION); + } + } + } + + disable(cap: number): void { + cap |= 0; + super.disable(cap); + if (cap === this.TEXTURE_2D || cap === this.TEXTURE_CUBE_MAP) { + const active = this._getActiveTextureUnit(); + if (active._mode === cap) { + active._mode = 0; + } + } + } + + disableVertexAttribArray(index: number): void { + index |= 0; + if (index < 0 || index >= this._vertexObjectState._attribs.length) { + this.setError(this.INVALID_VALUE); + return; + } + super.disableVertexAttribArray(index); + this._vertexObjectState._attribs[index]._isPointer = false; + } + + drawArrays(mode: number, first: number, count: number): any { + mode |= 0; + first |= 0; + count |= 0; + + return super.drawArrays(mode, first, count); + } + + drawElements( + mode: number, + count: number, + type: number, + ioffset: number, + ): any { + mode |= 0; + count |= 0; + type |= 0; + ioffset |= 0; + + return super.drawElements(mode, count, type, ioffset); + } + + enable(cap: number): void { + cap |= 0; + super.enable(cap); + } + + enableVertexAttribArray(index: number): void { + index |= 0; + if (index < 0 || index >= this._vertexObjectState._attribs.length) { + this.setError(this.INVALID_VALUE); + return; + } + + super.enableVertexAttribArray(index); + + this._vertexObjectState._attribs[index]._isPointer = true; + } + + finish(): any { + return super.finish(); + } + + flush(): any { + return super.flush(); + } + + framebufferRenderbuffer( + target: number, + attachment: number, + renderbufferTarget: number, + renderbuffer: any, + ): void { + target = target | 0; + attachment = attachment | 0; + renderbufferTarget = renderbufferTarget | 0; + + if (!checkObject(renderbuffer)) { + throw new TypeError( + 'framebufferRenderbuffer(GLenum, GLenum, GLenum, WebGLRenderbuffer)', + ); + } + + // Since we emulate the default framebuffer, we can't rely on ANGLE's validation. + if (!this._getActiveFramebuffer(target)) { + this.setError(this.INVALID_OPERATION); + return; + } + + if (renderbuffer && !this._checkWrapper(renderbuffer, WebGLRenderbuffer)) { + return; + } + + super.framebufferRenderbuffer( + target, + attachment, + renderbufferTarget, + renderbuffer?._ ?? null, + ); + } + + framebufferTexture2D( + target: number, + attachment: number, + textarget: number, + texture: any, + level: number, + ): void { + target |= 0; + attachment |= 0; + textarget |= 0; + level |= 0; + if (!checkObject(texture)) { + throw new TypeError( + 'framebufferTexture2D(GLenum, GLenum, GLenum, WebGLTexture, GLint)', + ); + } + + // Check object ownership + if (texture && !this._checkWrapper(texture, WebGLTexture)) { + return; + } + + // Since we emulate the default framebuffer, we can't rely on ANGLE's validation. + if (!this._getActiveFramebuffer(target)) { + this.setError(this.INVALID_OPERATION); + return; + } + + super.framebufferTexture2D( + target, + attachment, + textarget, + texture?._ ?? null, + level, + ); + } + + framebufferTextureLayer( + target: number, + attachment: number, + texture: any, + level: number, + layer: number, + ): void { + target |= 0; + attachment |= 0; + level |= 0; + layer |= 0; + if (!checkObject(texture)) { + throw new TypeError( + 'framebufferTextureLayer(GLenum, GLenum, WebGLTexture, GLint, GLint)', + ); + } + + // Check object ownership + if (texture && !this._checkWrapper(texture, WebGLTexture)) { + return; + } + + // Since we emulate the default framebuffer, we can't rely on ANGLE's validation. + if (!this._getActiveFramebuffer(target)) { + this.setError(this.INVALID_OPERATION); + return; + } + + super.framebufferTextureLayer( + target, + attachment, + texture?._ ?? null, + level, + layer, + ); + } + + frontFace(mode: number): any { + return super.frontFace(mode | 0); + } + + generateMipmap(target: number): any { + return super.generateMipmap(target | 0) | 0; + } + + getActiveAttrib(program: any, index: number): WebGLActiveInfo | null { + if (!checkObject(program)) { + throw new TypeError('getActiveAttrib(WebGLProgram)'); + } else if (!program) { + this.setError(this.INVALID_VALUE); + } else if (this._checkWrapper(program, WebGLProgram)) { + const info = super.getActiveAttrib(program._ | 0, index | 0); + if (info) { + return new WebGLActiveInfo(info); + } + } + return null; + } + + getActiveUniform(program: any, index: number): WebGLActiveInfo | null { + if (!checkObject(program)) { + throw new TypeError('getActiveUniform(WebGLProgram, GLint)'); + } else if (!program) { + this.setError(this.INVALID_VALUE); + } else if (this._checkWrapper(program, WebGLProgram)) { + const info = super.getActiveUniform(program._ | 0, index | 0); + if (info) { + return new WebGLActiveInfo(info); + } + } + return null; + } + + getAttachedShaders(program: any): any[] | null { + if ( + !checkObject(program) || + (typeof program === 'object' && + program !== null && + !(program instanceof WebGLProgram)) + ) { + throw new TypeError('getAttachedShaders(WebGLProgram)'); + } + if (!program) { + this.setError(this.INVALID_VALUE); + } else if (this._checkWrapper(program, WebGLProgram)) { + const shaderArray = super.getAttachedShaders(program._ | 0); + if (!shaderArray) { + return null; + } + const unboxedShaders = new Array(shaderArray.length); + for (let i = 0; i < shaderArray.length; ++i) { + unboxedShaders[i] = this._shaders[shaderArray[i]]; + } + return unboxedShaders; + } + return null; + } + + getAttribLocation(program: any, name: string): number { + if (!checkObject(program)) { + throw new TypeError('getAttribLocation(WebGLProgram, String)'); + } + name += ''; + if (!isValidString(name) || name.length > MAX_ATTRIBUTE_LENGTH) { + this.setError(this.INVALID_VALUE); + } else if (this._checkWrapper(program, WebGLProgram)) { + return super.getAttribLocation(program._ | 0, name + ''); + } + return -1; + } + + getParameter(pname: number): any { + switch (pname) { + case this.COMPRESSED_TEXTURE_FORMATS: + return new Uint32Array(0); + case this.ARRAY_BUFFER_BINDING: + return this._vertexGlobalState._arrayBufferBinding; + case this.ELEMENT_ARRAY_BUFFER_BINDING: + return this._vertexObjectState._elementArrayBufferBinding; + case this.CURRENT_PROGRAM: + return this._activeProgram; + case this.FRAMEBUFFER_BINDING: + return this._activeFramebuffers.draw; + case this.READ_FRAMEBUFFER_BINDING: + return this._activeFramebuffers.read; + case this.RENDERBUFFER_BINDING: + return this._activeRenderbuffer; + case this.TEXTURE_BINDING_2D: + return this._getActiveTextureUnit()._bind2D; + case this.TEXTURE_BINDING_CUBE_MAP: + return this._getActiveTextureUnit()._bindCube; + case this.VERSION: + return 'WebGL 1.0 stack-gl ' + HEADLESS_VERSION; + case this.VENDOR: + return 'stack-gl'; + case this.RENDERER: + return 'ANGLE'; + case this.SHADING_LANGUAGE_VERSION: + return 'WebGL GLSL ES 1.0 stack-gl'; + + default: + if (this._extensions) { + if ( + this._extensions.oes_vertex_array_object && + pname === + this._extensions.oes_vertex_array_object.VERTEX_ARRAY_BINDING_OES + ) { + return this._extensions.oes_vertex_array_object + ._activeVertexArrayObject; + } + } + return super.getParameter(pname); + } + } + + getShaderPrecisionFormat( + shaderType: number, + precisionType: number, + ): WebGLShaderPrecisionFormat | null | undefined { + shaderType |= 0; + precisionType |= 0; + + if ( + !( + shaderType === this.FRAGMENT_SHADER || shaderType === this.VERTEX_SHADER + ) || + !( + precisionType === this.LOW_FLOAT || + precisionType === this.MEDIUM_FLOAT || + precisionType === this.HIGH_FLOAT || + precisionType === this.LOW_INT || + precisionType === this.MEDIUM_INT || + precisionType === this.HIGH_INT + ) + ) { + this.setError(this.INVALID_ENUM); + return; + } + + const format = super.getShaderPrecisionFormat(shaderType, precisionType); + if (!format) { + return null; + } + + return new WebGLShaderPrecisionFormat(format); + } + + getBufferParameter(target: number, pname: number): any { + target |= 0; + pname |= 0; + if (target !== this.ARRAY_BUFFER && target !== this.ELEMENT_ARRAY_BUFFER) { + this.setError(this.INVALID_ENUM); + return null; + } + + switch (pname) { + case this.BUFFER_SIZE: + case this.BUFFER_USAGE: + return super.getBufferParameter(target | 0, pname | 0); + default: + this.setError(this.INVALID_ENUM); + return null; + } + } + + getError(): number { + return super.getError(); + } + + getFramebufferAttachmentParameter( + target: number, + attachment: number, + pname: number, + ): any { + target |= 0; + attachment |= 0; + pname |= 0; + + // Since we emulate the default framebuffer, we can't rely on ANGLE's validation. + if (!this._getActiveFramebuffer(target)) { + this.setError(this.INVALID_OPERATION); + return null; + } + + this._saveError(); + const result = super.getFramebufferAttachmentParameter( + target, + attachment, + pname, + ); + const error = super.getError(); + this._restoreError(error); + + if (error) { + return null; + } + + if ( + error === this.NO_ERROR && + pname === this.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME + ) { + const type = super.getFramebufferAttachmentParameter( + target, + attachment, + this.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, + ); + if (type === this.RENDERBUFFER) { + return this._renderbuffers[result]; + } else { + return this._textures[result]; + } + } + + return result; + } + + getProgramParameter(program: any, pname: number): any { + pname |= 0; + if (!checkObject(program)) { + throw new TypeError('getProgramParameter(WebGLProgram, GLenum)'); + } else if (this._checkWrapper(program, WebGLProgram)) { + switch (pname) { + case this.DELETE_STATUS: + return program._pendingDelete; + + case this.LINK_STATUS: + return program._linkStatus; + + case this.VALIDATE_STATUS: + return !!super.getProgramParameter(program._, pname); + + case this.ATTACHED_SHADERS: + case this.ACTIVE_ATTRIBUTES: + case this.ACTIVE_UNIFORMS: + return super.getProgramParameter(program._, pname); + } + this.setError(this.INVALID_ENUM); + } + return null; + } + + getProgramInfoLog(program: any): string | null { + if (!checkObject(program)) { + throw new TypeError('getProgramInfoLog(WebGLProgram)'); + } else if (this._checkWrapper(program, WebGLProgram)) { + return program._linkInfoLog; + } + return null; + } + + getRenderbufferParameter(target: number, pname: number): any { + target |= 0; + pname |= 0; + if (target !== this.RENDERBUFFER) { + this.setError(this.INVALID_ENUM); + return null; + } + const renderbuffer = this._activeRenderbuffer; + if (!renderbuffer) { + this.setError(this.INVALID_OPERATION); + return null; + } + switch (pname) { + case this.RENDERBUFFER_INTERNAL_FORMAT: + return renderbuffer._format; + case this.RENDERBUFFER_WIDTH: + return renderbuffer._width; + case this.RENDERBUFFER_HEIGHT: + return renderbuffer._height; + case this.RENDERBUFFER_SIZE: + case this.RENDERBUFFER_RED_SIZE: + case this.RENDERBUFFER_GREEN_SIZE: + case this.RENDERBUFFER_BLUE_SIZE: + case this.RENDERBUFFER_ALPHA_SIZE: + case this.RENDERBUFFER_DEPTH_SIZE: + case this.RENDERBUFFER_STENCIL_SIZE: + return super.getRenderbufferParameter(target, pname); + } + this.setError(this.INVALID_ENUM); + return null; + } + + getShaderParameter(shader: any, pname: number): any { + pname |= 0; + if (!checkObject(shader)) { + throw new TypeError('getShaderParameter(WebGLShader, GLenum)'); + } else if (this._checkWrapper(shader, WebGLShader)) { + switch (pname) { + case this.DELETE_STATUS: + return shader._pendingDelete; + case this.COMPILE_STATUS: + return shader._compileStatus; + case this.SHADER_TYPE: + return shader._type; + } + this.setError(this.INVALID_ENUM); + } + return null; + } + + getShaderInfoLog(shader: any): string | null { + if (!checkObject(shader)) { + throw new TypeError('getShaderInfoLog(WebGLShader)'); + } else if (this._checkWrapper(shader, WebGLShader)) { + return shader._compileInfo; + } + return null; + } + + getShaderSource(shader: any): string | null { + if (!checkObject(shader)) { + throw new TypeError('Input to getShaderSource must be an object'); + } else if (this._checkWrapper(shader, WebGLShader)) { + return shader._source; + } + return null; + } + + getTexParameter(target: number, pname: number): any { + target |= 0; + pname |= 0; + + if (!this._checkTextureTarget(target)) { + return null; + } + + const unit = this._getActiveTextureUnit(); + if ( + (target === this.TEXTURE_2D && !unit._bind2D) || + (target === this.TEXTURE_CUBE_MAP && !unit._bindCube) + ) { + this.setError(this.INVALID_OPERATION); + return null; + } + + switch (pname) { + case this.TEXTURE_MAG_FILTER: + case this.TEXTURE_MIN_FILTER: + case this.TEXTURE_WRAP_S: + case this.TEXTURE_WRAP_T: + return super.getTexParameter(target, pname); + } + + if ( + this._extensions.ext_texture_filter_anisotropic && + pname === + this._extensions.ext_texture_filter_anisotropic + .TEXTURE_MAX_ANISOTROPY_EXT + ) { + return super.getTexParameter(target, pname); + } + + this.setError(this.INVALID_ENUM); + return null; + } + + getUniform(program: any, location: any): any { + if (!checkObject(program) || !checkObject(location)) { + throw new TypeError('getUniform(WebGLProgram, WebGLUniformLocation)'); + } else if (!program) { + this.setError(this.INVALID_VALUE); + return null; + } else if (!location) { + return null; + } else if (this._checkWrapper(program, WebGLProgram)) { + if (!checkUniform(program, location)) { + this.setError(this.INVALID_OPERATION); + return null; + } + const data = super.getUniform(program._ | 0, location._ | 0); + if (!data) { + return null; + } + switch (location._activeInfo.type) { + case this.FLOAT: + return data[0]; + case this.FLOAT_VEC2: + return new Float32Array(data.slice(0, 2)); + case this.FLOAT_VEC3: + return new Float32Array(data.slice(0, 3)); + case this.FLOAT_VEC4: + return new Float32Array(data.slice(0, 4)); + case this.INT: + return data[0] | 0; + case this.INT_VEC2: + return new Int32Array(data.slice(0, 2)); + case this.INT_VEC3: + return new Int32Array(data.slice(0, 3)); + case this.INT_VEC4: + return new Int32Array(data.slice(0, 4)); + case this.BOOL: + return !!data[0]; + case this.BOOL_VEC2: + return [!!data[0], !!data[1]]; + case this.BOOL_VEC3: + return [!!data[0], !!data[1], !!data[2]]; + case this.BOOL_VEC4: + return [!!data[0], !!data[1], !!data[2], !!data[3]]; + case this.FLOAT_MAT2: + return new Float32Array(data.slice(0, 4)); + case this.FLOAT_MAT3: + return new Float32Array(data.slice(0, 9)); + case this.FLOAT_MAT4: + return new Float32Array(data.slice(0, 16)); + case this.SAMPLER_2D: + case this.SAMPLER_CUBE: + return data[0] | 0; + default: + return null; + } + } + return null; + } + + getUniformLocation( + program: any, + name: string, + ): WebGLUniformLocation | null | undefined { + if (!checkObject(program)) { + throw new TypeError('getUniformLocation(WebGLProgram, String)'); + } + + name += ''; + if (!isValidString(name)) { + this.setError(this.INVALID_VALUE); + return; + } + + if (this._checkWrapper(program, WebGLProgram)) { + const loc = super.getUniformLocation(program._ | 0, name); + if (loc >= 0) { + let searchName = name; + if (/\[\d+\]$/.test(name)) { + searchName = name.replace(/\[\d+\]$/, '[0]'); + } + + let info = null; + for (let i = 0; i < program._uniforms.length; ++i) { + const infoItem = program._uniforms[i]; + if (infoItem.name === searchName) { + info = { + size: infoItem.size, + type: infoItem.type, + name: infoItem.name, + }; + } + } + if (!info) { + return null; + } + + const result = new WebGLUniformLocation(loc, program, info); + + // handle array case + if (/\[0\]$/.test(name)) { + const baseName = name.replace(/\[0\]$/, ''); + const arrayLocs: number[] = []; + + this._saveError(); + for (let i = 0; this.getError() === this.NO_ERROR; ++i) { + const xloc = super.getUniformLocation( + program._ | 0, + baseName + '[' + i + ']', + ); + if (this.getError() !== this.NO_ERROR || xloc < 0) { + break; + } + arrayLocs.push(xloc); + } + this._restoreError(this.NO_ERROR); + + result._array = arrayLocs; + } else if (/\[(\d+)\]$/.test(name)) { + const offset = +/\[(\d+)\]$/.exec(name)![1]; + if (offset < 0 || offset >= info.size) { + return null; + } + } + return result; + } + } + return null; + } + + getVertexAttrib(index: number, pname: number): any { + index |= 0; + pname |= 0; + if (index < 0 || index >= this._vertexObjectState._attribs.length) { + this.setError(this.INVALID_VALUE); + return null; + } + const attrib = this._vertexObjectState._attribs[index]; + const vertexAttribValue = this._vertexGlobalState._attribs[index]._data; + + switch (pname) { + case this.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + return attrib._pointerBuffer; + case this.VERTEX_ATTRIB_ARRAY_ENABLED: + return attrib._isPointer; + case this.VERTEX_ATTRIB_ARRAY_SIZE: + return attrib._inputSize; + case this.VERTEX_ATTRIB_ARRAY_STRIDE: + return attrib._inputStride; + case this.VERTEX_ATTRIB_ARRAY_TYPE: + return attrib._pointerType; + case this.VERTEX_ATTRIB_ARRAY_NORMALIZED: + return attrib._pointerNormal; + case this.CURRENT_VERTEX_ATTRIB: + return new Float32Array(vertexAttribValue); + default: + return super.getVertexAttrib(index, pname); + } + } + + getVertexAttribOffset(index: number, pname: number): any { + index |= 0; + pname |= 0; + if (index < 0 || index >= this._vertexObjectState._attribs.length) { + this.setError(this.INVALID_VALUE); + return null; + } + if (pname === this.VERTEX_ATTRIB_ARRAY_POINTER) { + return this._vertexObjectState._attribs[index]._pointerOffset; + } else { + this.setError(this.INVALID_ENUM); + return null; + } + } + + hint(target: number, mode: number): any { + target |= 0; + mode |= 0; + + if ( + !( + target === this.GENERATE_MIPMAP_HINT || + (this._extensions.oes_standard_derivatives && + target === + this._extensions.oes_standard_derivatives + .FRAGMENT_SHADER_DERIVATIVE_HINT_OES) + ) + ) { + this.setError(this.INVALID_ENUM); + return; + } + + if ( + mode !== this.FASTEST && + mode !== this.NICEST && + mode !== this.DONT_CARE + ) { + this.setError(this.INVALID_ENUM); + return; + } + + return super.hint(target, mode); + } + + isBuffer(object: any): boolean { + if (!this._isObject(object, 'isBuffer', WebGLBuffer)) return false; + return super.isBuffer(object._ | 0); + } + + isFramebuffer(object: any): boolean { + if (!this._isObject(object, 'isFramebuffer', WebGLFramebuffer)) + return false; + return super.isFramebuffer(object._ | 0); + } + + isProgram(object: any): boolean { + if (!this._isObject(object, 'isProgram', WebGLProgram)) return false; + return super.isProgram(object._ | 0); + } + + isRenderbuffer(object: any): boolean { + if (!this._isObject(object, 'isRenderbuffer', WebGLRenderbuffer)) + return false; + return super.isRenderbuffer(object._ | 0); + } + + isShader(object: any): boolean { + if (!this._isObject(object, 'isShader', WebGLShader)) return false; + return super.isShader(object._ | 0); + } + + isTexture(object: any): boolean { + if (!this._isObject(object, 'isTexture', WebGLTexture)) return false; + return super.isTexture(object._ | 0); + } + + isVertexArray(object: any): boolean { + if (!this._isObject(object, 'isVertexArray', WebGLVertexArrayObject)) + return false; + return super.isVertexArray(object._ | 0); + } + + isEnabled(cap: number): boolean { + return super.isEnabled(cap | 0); + } + + lineWidth(width: number): void { + if (isNaN(width)) { + this.setError(this.INVALID_VALUE); + return; + } + return super.lineWidth(+width); + } + + linkProgram(program: any): void { + if (!checkObject(program)) { + throw new TypeError('linkProgram(WebGLProgram)'); + } + if (this._checkWrapper(program, WebGLProgram)) { + program._linkCount += 1; + program._attributes = []; + const prevError = this.getError(); + super.linkProgram(program._ | 0); + const error = this.getError(); + if (error === this.NO_ERROR) { + program._linkStatus = this._fixupLink(program); + } + this.getError(); + this.setError(prevError || error); + } + } + + pixelStorei(pname: number, param: number): any { + pname |= 0; + param |= 0; + if (pname === this.UNPACK_ALIGNMENT) { + if (param === 1 || param === 2 || param === 4 || param === 8) { + this._unpackAlignment = param; + } else { + this.setError(this.INVALID_VALUE); + return; + } + } else if (pname === this.PACK_ALIGNMENT) { + if (param === 1 || param === 2 || param === 4 || param === 8) { + this._packAlignment = param; + } else { + this.setError(this.INVALID_VALUE); + return; + } + } else if (pname === this.UNPACK_COLORSPACE_CONVERSION_WEBGL) { + if (!(param === this.NONE || param === this.BROWSER_DEFAULT_WEBGL)) { + this.setError(this.INVALID_VALUE); + return; + } + } + return super.pixelStorei(pname, param); + } + + polygonOffset(factor: number, units: number): any { + return super.polygonOffset(+factor, +units); + } + + readPixels( + x: number, + y: number, + width: number, + height: number, + format: number, + type: number, + pixels: any, + ): void { + x |= 0; + y |= 0; + width |= 0; + height |= 0; + + super.readPixels(x, y, width, height, format, type, pixels); + } + + renderbufferStorage( + target: number, + internalFormat: number, + width: number, + height: number, + ): void { + target |= 0; + internalFormat |= 0; + width |= 0; + height |= 0; + + if (target !== this.RENDERBUFFER) { + this.setError(this.INVALID_ENUM); + return; + } + + const renderbuffer = this._activeRenderbuffer; + if (!renderbuffer) { + this.setError(this.INVALID_OPERATION); + return; + } + + this._saveError(); + super.renderbufferStorage(target, internalFormat, width, height); + const error = this.getError(); + this._restoreError(error); + if (error !== this.NO_ERROR) { + return; + } + + renderbuffer._width = width; + renderbuffer._height = height; + renderbuffer._format = internalFormat; + } + + resize(width: number, height: number): void { + width = width | 0; + height = height | 0; + if (!(width > 0 && height > 0)) { + throw new Error('Invalid surface dimensions'); + } else if ( + width !== this.drawingBufferWidth || + height !== this.drawingBufferHeight + ) { + this._resizeDrawingBuffer(width, height); + this.drawingBufferWidth = width; + this.drawingBufferHeight = height; + } + } + + sampleCoverage(value: number, invert: any): any { + return super.sampleCoverage(+value, !!invert); + } + + scissor(x: number, y: number, width: number, height: number): any { + return super.scissor(x | 0, y | 0, width | 0, height | 0); + } + + shaderSource(shader: any, source: any): void { + if (!checkObject(shader)) { + throw new TypeError('shaderSource(WebGLShader, String)'); + } + if (!shader || (!source && typeof source !== 'string')) { + this.setError(this.INVALID_VALUE); + return; + } + source += ''; + if (!isValidString(source)) { + this.setError(this.INVALID_VALUE); + } else if (this._checkWrapper(shader, WebGLShader)) { + super.shaderSource(shader._ | 0, this._wrapShader(shader._type, source)); // eslint-disable-line + shader._source = source; + } + } + + stencilFunc(func: number, ref: number, mask: number): any { + this._checkStencil = true; + return super.stencilFunc(func | 0, ref | 0, mask | 0); + } + + stencilFuncSeparate( + face: number, + func: number, + ref: number, + mask: number, + ): any { + this._checkStencil = true; + return super.stencilFuncSeparate(face | 0, func | 0, ref | 0, mask | 0); + } + + stencilMask(mask: number): any { + this._checkStencil = true; + return super.stencilMask(mask | 0); + } + + stencilMaskSeparate(face: number, mask: number): any { + this._checkStencil = true; + return super.stencilMaskSeparate(face | 0, mask | 0); + } + + stencilOp(fail: number, zfail: number, zpass: number): any { + this._checkStencil = true; + return super.stencilOp(fail | 0, zfail | 0, zpass | 0); + } + + stencilOpSeparate( + face: number, + fail: number, + zfail: number, + zpass: number, + ): any { + this._checkStencil = true; + return super.stencilOpSeparate(face | 0, fail | 0, zfail | 0, zpass | 0); + } + + texImage2D( + target: any, + level: any, + internalFormat: any, + width: any, + height: any, + border: any, + format?: any, + type?: any, + pixels?: any, + ): void { + if (arguments.length === 6) { + pixels = border; + type = height; + format = width; + + pixels = extractImageData(pixels); + + if (pixels == null) { + throw new TypeError( + 'texImage2D(GLenum, GLint, GLenum, GLint, GLenum, GLenum, ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement)', + ); + } + + width = pixels.width; + height = pixels.height; + pixels = pixels.data; + } + + target |= 0; + level |= 0; + internalFormat |= 0; + width |= 0; + height |= 0; + border |= 0; + format |= 0; + type |= 0; + + if (typeof pixels !== 'object' && pixels !== undefined) { + throw new TypeError( + 'texImage2D(GLenum, GLint, GLenum, GLint, GLint, GLint, GLenum, GLenum, Uint8Array)', + ); + } + + // Note: there's an ANGLE bug where it doesn't check for setting texImage2D on texture zero in WebGL compat. + if (this._getActiveTexture(target) === null) { + if (target === this.TEXTURE_2D || target === this.TEXTURE_CUBE_MAP) { + this.setError(this.INVALID_OPERATION); + return; + } + } + + const data = convertPixels(pixels); + + // Need to check for out of memory error + this._saveError(); + super.texImage2D( + target, + level, + internalFormat, + width, + height, + border, + format, + type, + data, + ); + const error = this.getError(); + this._restoreError(error); + if (error === this.NO_ERROR) { + const texture = this._getTexImage(target); + texture._format = format; + texture._type = type; + } + } + + texSubImage2D( + target: any, + level: any, + xoffset: any, + yoffset: any, + width: any, + height: any, + format: any, + type?: any, + pixels?: any, + ): void { + if (arguments.length === 7) { + pixels = format; + type = height; + format = width; + + pixels = extractImageData(pixels); + + if (pixels == null) { + throw new TypeError( + 'texSubImage2D(GLenum, GLint, GLint, GLint, GLenum, GLenum, ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement)', + ); + } + + width = pixels.width; + height = pixels.height; + pixels = pixels.data; + } + + if (typeof pixels !== 'object') { + throw new TypeError( + 'texSubImage2D(GLenum, GLint, GLint, GLint, GLint, GLint, GLenum, GLenum, Uint8Array)', + ); + } + + const data = convertPixels(pixels); + + super.texSubImage2D( + target, + level, + xoffset, + yoffset, + width, + height, + format, + type, + data, + ); + } + + texParameterf(target: number, pname: number, param: number): void { + target |= 0; + pname |= 0; + param = +param; + + if (this._checkTextureTarget(target)) { + this._verifyTextureCompleteness(target, pname, param); + switch (pname) { + case this.TEXTURE_MIN_FILTER: + case this.TEXTURE_MAG_FILTER: + case this.TEXTURE_WRAP_S: + case this.TEXTURE_WRAP_T: + return super.texParameterf(target, pname, param); + } + + if ( + this._extensions.ext_texture_filter_anisotropic && + pname === + this._extensions.ext_texture_filter_anisotropic + .TEXTURE_MAX_ANISOTROPY_EXT + ) { + return super.texParameterf(target, pname, param); + } + + this.setError(this.INVALID_ENUM); + } + } + + texParameteri(target: number, pname: number, param: number): any { + target |= 0; + pname |= 0; + param |= 0; + + // Note: there's an ANGLE bug where it doesn't check for setting texParameter on texture zero in WebGL compat. + if (!this._checkTextureTarget(target)) { + return; + } + return super.texParameteri(target, pname, param); + } + + useProgram(program: any): any { + if (!checkObject(program)) { + throw new TypeError('useProgram(WebGLProgram)'); + } else if (!program) { + this._switchActiveProgram(this._activeProgram); + this._activeProgram = null; + return super.useProgram(0); + } else if (this._checkWrapper(program, WebGLProgram)) { + if (this._activeProgram !== program) { + this._switchActiveProgram(this._activeProgram); + this._activeProgram = program; + program._refCount += 1; + } + return super.useProgram(program._ | 0); + } + } + + validateProgram(program: any): void { + if (this._checkWrapper(program, WebGLProgram)) { + super.validateProgram(program._ | 0); + const error = this.getError(); + if (error === this.NO_ERROR) { + program._linkInfoLog = super.getProgramInfoLog(program._ | 0); + } + this.getError(); + this.setError(error); + } + } + + vertexAttribPointer( + index: number, + size: number, + type: number, + normalized: any, + stride: number, + offset: number, + ): void { + if (stride < 0 || offset < 0) { + this.setError(this.INVALID_VALUE); + return; + } + + index |= 0; + size |= 0; + type |= 0; + normalized = !!normalized; + stride |= 0; + offset |= 0; + + if ( + stride < 0 || + offset < 0 || + index < 0 || + index >= this._vertexObjectState._attribs.length || + !(size === 1 || size === 2 || size === 3 || size === 4) + ) { + this.setError(this.INVALID_VALUE); + return; + } + + if (this._vertexGlobalState._arrayBufferBinding === null) { + this.setError(this.INVALID_OPERATION); + return; + } + + // fixed, int and unsigned int aren't allowed in WebGL + const byteSize = typeSize(type); + if (byteSize === 0 || type === this.INT || type === this.UNSIGNED_INT) { + this.setError(this.INVALID_ENUM); + return; + } + + if (stride > 255 || stride < 0) { + this.setError(this.INVALID_VALUE); + return; + } + + // stride and offset must be multiples of size + if (stride % byteSize !== 0 || offset % byteSize !== 0) { + this.setError(this.INVALID_OPERATION); + return; + } + + // Call vertex attrib pointer + super.vertexAttribPointer(index, size, type, normalized, stride, offset); + + // Update the vertex state object and references. + this._vertexObjectState.setVertexAttribPointer( + /* buffer */ this._vertexGlobalState._arrayBufferBinding, + /* index */ index, + /* pointerSize */ size * byteSize, + /* pointerOffset */ offset, + /* pointerStride */ stride || size * byteSize, + /* pointerType */ type, + /* pointerNormal */ normalized, + /* inputStride */ stride, + /* inputSize */ size, + ); + } + + viewport(x: number, y: number, width: number, height: number): any { + return super.viewport(x | 0, y | 0, width | 0, height | 0); + } + + _allocateDrawingBuffer(width: number, height: number): void { + this._drawingBuffer = new WebGLDrawingBufferWrapper( + super.createFramebuffer(), + super.createTexture(), + super.createRenderbuffer(), + ); + + this._resizeDrawingBuffer(width, height); + } + + isContextLost(): boolean { + return false; + } + + compressedTexImage2D(): void { + // TODO not yet implemented + } + + compressedTexSubImage2D(): void { + // TODO not yet implemented + } + + _checkUniformValid( + location: any, + v0: any, + name: string, + count: number, + type: string, + ): any { + if (!checkObject(location)) { + throw new TypeError(`${name}(WebGLUniformLocation, ...)`); + } else if (!location) { + return false; + } else if (this._checkLocationActive(location)) { + const utype = location._activeInfo.type; + if (utype === this.SAMPLER_2D || utype === this.SAMPLER_CUBE) { + if (count !== 1) { + this.setError(this.INVALID_VALUE); + return; + } + if (type !== 'i') { + this.setError(this.INVALID_OPERATION); + return; + } + if (v0 < 0 || v0 >= this._textureUnits.length) { + this.setError(this.INVALID_VALUE); + return false; + } + } + if (uniformTypeSize(utype) > count) { + this.setError(this.INVALID_OPERATION); + return false; + } + return true; + } + return false; + } + + _checkUniformValueValid( + location: any, + value: any, + name: string, + count: number, + _type: string, + ): boolean { + if (!checkObject(location) || !checkObject(value)) { + throw new TypeError(`${name}v(WebGLUniformLocation, Array)`); + } else if (!location) { + return false; + } else if (!this._checkLocationActive(location)) { + return false; + } else if ( + typeof value !== 'object' || + !value || + typeof value.length !== 'number' + ) { + throw new TypeError(`Second argument to ${name} must be array`); + } else if (uniformTypeSize(location._activeInfo.type) > count) { + this.setError(this.INVALID_OPERATION); + return false; + } else if (value.length >= count && value.length % count === 0) { + if (location._array) { + return true; + } else if (value.length === count) { + return true; + } else { + this.setError(this.INVALID_OPERATION); + return false; + } + } + this.setError(this.INVALID_VALUE); + return false; + } + + uniform1f(location: any, v0: number): void { + if (!this._checkUniformValid(location, v0, 'uniform1f', 1, 'f')) return; + super.uniform1f(location._ | 0, v0); + } + + uniform1fv(location: any, value: any): void { + if (!this._checkUniformValueValid(location, value, 'uniform1fv', 1, 'f')) + return; + if (location._array) { + const locs = location._array; + for (let i = 0; i < locs.length && i < value.length; ++i) { + const loc = locs[i]; + super.uniform1f(loc, value[i]); + } + return; + } + super.uniform1f(location._ | 0, value[0]); + } + + uniform1i(location: any, v0: number): void { + if (!this._checkUniformValid(location, v0, 'uniform1i', 1, 'i')) return; + super.uniform1i(location._ | 0, v0 | 0); + } + + uniform1iv(location: any, value: any): void { + if (!this._checkUniformValueValid(location, value, 'uniform1iv', 1, 'i')) + return; + if (location._array) { + const locs = location._array; + for (let i = 0; i < locs.length && i < value.length; ++i) { + const loc = locs[i]; + super.uniform1i(loc, value[i]); + } + return; + } + this.uniform1i(location, value[0]); + } + + uniform2f(location: any, v0: number, v1: number): void { + if (!this._checkUniformValid(location, v0, 'uniform2f', 2, 'f')) return; + super.uniform2f(location._ | 0, v0, v1); + } + + uniform2fv(location: any, value: any): void { + if (!this._checkUniformValueValid(location, value, 'uniform2fv', 2, 'f')) + return; + if (location._array) { + const locs = location._array; + for (let i = 0; i < locs.length && 2 * i < value.length; ++i) { + const loc = locs[i]; + super.uniform2f(loc, value[2 * i], value[2 * i + 1]); + } + return; + } + super.uniform2f(location._ | 0, value[0], value[1]); + } + + uniform2i(location: any, v0: number, v1: number): void { + if (!this._checkUniformValid(location, v0, 'uniform2i', 2, 'i')) return; + super.uniform2i(location._ | 0, v0, v1); + } + + uniform2iv(location: any, value: any): void { + if (!this._checkUniformValueValid(location, value, 'uniform2iv', 2, 'i')) + return; + if (location._array) { + const locs = location._array; + for (let i = 0; i < locs.length && 2 * i < value.length; ++i) { + const loc = locs[i]; + super.uniform2i(loc, value[2 * i], value[2 * i + 1]); + } + return; + } + this.uniform2i(location, value[0], value[1]); + } + + uniform3f(location: any, v0: number, v1: number, v2: number): void { + if (!this._checkUniformValid(location, v0, 'uniform3f', 3, 'f')) return; + super.uniform3f(location._ | 0, v0, v1, v2); + } + + uniform3fv(location: any, value: any): void { + if (!this._checkUniformValueValid(location, value, 'uniform3fv', 3, 'f')) + return; + if (location._array) { + const locs = location._array; + for (let i = 0; i < locs.length && 3 * i < value.length; ++i) { + const loc = locs[i]; + super.uniform3f(loc, value[3 * i], value[3 * i + 1], value[3 * i + 2]); + } + return; + } + super.uniform3f(location._ | 0, value[0], value[1], value[2]); + } + + uniform3i(location: any, v0: number, v1: number, v2: number): void { + if (!this._checkUniformValid(location, v0, 'uniform3i', 3, 'i')) return; + super.uniform3i(location._ | 0, v0, v1, v2); + } + + uniform3iv(location: any, value: any): void { + if (!this._checkUniformValueValid(location, value, 'uniform3iv', 3, 'i')) + return; + if (location._array) { + const locs = location._array; + for (let i = 0; i < locs.length && 3 * i < value.length; ++i) { + const loc = locs[i]; + super.uniform3i(loc, value[3 * i], value[3 * i + 1], value[3 * i + 2]); + } + return; + } + this.uniform3i(location, value[0], value[1], value[2]); + } + + uniform4f( + location: any, + v0: number, + v1: number, + v2: number, + v3: number, + ): void { + if (!this._checkUniformValid(location, v0, 'uniform4f', 4, 'f')) return; + super.uniform4f(location._ | 0, v0, v1, v2, v3); + } + + uniform4fv(location: any, value: any): void { + if (!this._checkUniformValueValid(location, value, 'uniform4fv', 4, 'f')) + return; + if (location._array) { + const locs = location._array; + for (let i = 0; i < locs.length && 4 * i < value.length; ++i) { + const loc = locs[i]; + super.uniform4f( + loc, + value[4 * i], + value[4 * i + 1], + value[4 * i + 2], + value[4 * i + 3], + ); + } + return; + } + super.uniform4f(location._ | 0, value[0], value[1], value[2], value[3]); + } + + uniform4i( + location: any, + v0: number, + v1: number, + v2: number, + v3: number, + ): void { + if (!this._checkUniformValid(location, v0, 'uniform4i', 4, 'i')) return; + super.uniform4i(location._ | 0, v0, v1, v2, v3); + } + + uniform4iv(location: any, value: any): void { + if (!this._checkUniformValueValid(location, value, 'uniform4iv', 4, 'i')) + return; + if (location._array) { + const locs = location._array; + for (let i = 0; i < locs.length && 4 * i < value.length; ++i) { + const loc = locs[i]; + super.uniform4i( + loc, + value[4 * i], + value[4 * i + 1], + value[4 * i + 2], + value[4 * i + 3], + ); + } + return; + } + this.uniform4i(location, value[0], value[1], value[2], value[3]); + } + + _checkUniformMatrix( + location: any, + transpose: any, + value: any, + name: string, + count: number, + ): boolean { + if (!checkObject(location) || typeof value !== 'object') { + throw new TypeError(name + '(WebGLUniformLocation, Boolean, Array)'); + } else if ( + !!transpose || + typeof value !== 'object' || + value === null || + !value.length || + (value.length % count) * count !== 0 + ) { + this.setError(this.INVALID_VALUE); + return false; + } + if (!location) { + return false; + } + if (!this._checkLocationActive(location)) { + return false; + } + + if (value.length === count * count) { + return true; + } else if (location._array) { + return true; + } + this.setError(this.INVALID_VALUE); + return false; + } + + uniformMatrix2fv(location: any, transpose: any, value: any): void { + if ( + !this._checkUniformMatrix( + location, + transpose, + value, + 'uniformMatrix2fv', + 2, + ) + ) + return; + const data = new Float32Array(value); + super.uniformMatrix2fv(location._ | 0, !!transpose, data); + } + + uniformMatrix3fv(location: any, transpose: any, value: any): void { + if ( + !this._checkUniformMatrix( + location, + transpose, + value, + 'uniformMatrix3fv', + 3, + ) + ) + return; + const data = new Float32Array(value); + super.uniformMatrix3fv(location._ | 0, !!transpose, data); + } + + uniformMatrix4fv(location: any, transpose: any, value: any): void { + if ( + !this._checkUniformMatrix( + location, + transpose, + value, + 'uniformMatrix4fv', + 4, + ) + ) + return; + const data = new Float32Array(value); + super.uniformMatrix4fv(location._ | 0, !!transpose, data); + } + + vertexAttrib1f(index: number, v0: number): any { + index |= 0; + if (!this._checkVertexIndex(index)) return; + const data = this._vertexGlobalState._attribs[index]._data; + data[3] = 1; + data[1] = data[2] = 0; + data[0] = v0; + return super.vertexAttrib1f(index | 0, +v0); + } + + vertexAttrib2f(index: number, v0: number, v1: number): any { + index |= 0; + if (!this._checkVertexIndex(index)) return; + const data = this._vertexGlobalState._attribs[index]._data; + data[3] = 1; + data[2] = 0; + data[1] = v1; + data[0] = v0; + return super.vertexAttrib2f(index | 0, +v0, +v1); + } + + vertexAttrib3f(index: number, v0: number, v1: number, v2: number): any { + index |= 0; + if (!this._checkVertexIndex(index)) return; + const data = this._vertexGlobalState._attribs[index]._data; + data[3] = 1; + data[2] = v2; + data[1] = v1; + data[0] = v0; + return super.vertexAttrib3f(index | 0, +v0, +v1, +v2); + } + + vertexAttrib4f( + index: number, + v0: number, + v1: number, + v2: number, + v3: number, + ): any { + index |= 0; + if (!this._checkVertexIndex(index)) return; + const data = this._vertexGlobalState._attribs[index]._data; + data[3] = v3; + data[2] = v2; + data[1] = v1; + data[0] = v0; + return super.vertexAttrib4f(index | 0, +v0, +v1, +v2, +v3); + } + + vertexAttrib1fv(index: number, value: any): any { + if (typeof value !== 'object' || value === null || value.length < 1) { + this.setError(this.INVALID_OPERATION); + return; + } + const data = this._vertexGlobalState._attribs[index]._data; + data[3] = 1; + data[2] = 0; + data[1] = 0; + data[0] = value[0]; + return super.vertexAttrib1f(index | 0, +value[0]); + } + + vertexAttrib2fv(index: number, value: any): any { + if (typeof value !== 'object' || value === null || value.length < 2) { + this.setError(this.INVALID_OPERATION); + return; + } + const data = this._vertexGlobalState._attribs[index]._data; + data[3] = 1; + data[2] = 0; + data[1] = value[1]; + data[0] = value[0]; + return super.vertexAttrib2f(index | 0, +value[0], +value[1]); + } + + vertexAttrib3fv(index: number, value: any): any { + if (typeof value !== 'object' || value === null || value.length < 3) { + this.setError(this.INVALID_OPERATION); + return; + } + const data = this._vertexGlobalState._attribs[index]._data; + data[3] = 1; + data[2] = value[2]; + data[1] = value[1]; + data[0] = value[0]; + return super.vertexAttrib3f(index | 0, +value[0], +value[1], +value[2]); + } + + vertexAttrib4fv(index: number, value: any): any { + if (typeof value !== 'object' || value === null || value.length < 4) { + this.setError(this.INVALID_OPERATION); + return; + } + const data = this._vertexGlobalState._attribs[index]._data; + data[3] = value[3]; + data[2] = value[2]; + data[1] = value[1]; + data[0] = value[0]; + return super.vertexAttrib4f( + index | 0, + +value[0], + +value[1], + +value[2], + +value[3], + ); + } + + _isWebGL2(): boolean { + return this.TEXTURE_2D_ARRAY !== undefined; + } +} + +// Make the gl consts available as static properties +for (const [key, value] of Object.entries(gl)) { + if (typeof value !== 'number') { + continue; + } + Object.assign(WebGLRenderingContextHelper, { [key]: value }); +} + +export class WebGLRenderingContext extends WebGLRenderingContextHelper {} + +export class WebGL2RenderingContext extends WebGLRenderingContextHelper {} diff --git a/src/webgl-shader-precision-format.ts b/src/webgl-shader-precision-format.ts new file mode 100644 index 00000000..a1c6a66d --- /dev/null +++ b/src/webgl-shader-precision-format.ts @@ -0,0 +1,11 @@ +export class WebGLShaderPrecisionFormat { + rangeMin: number; + rangeMax: number; + precision: number; + + constructor(_: { rangeMin: number; rangeMax: number; precision: number }) { + this.rangeMin = _.rangeMin; + this.rangeMax = _.rangeMax; + this.precision = _.precision; + } +} diff --git a/src/webgl-shader.ts b/src/webgl-shader.ts new file mode 100644 index 00000000..bc162e3a --- /dev/null +++ b/src/webgl-shader.ts @@ -0,0 +1,25 @@ +import { Linkable } from './linkable'; +import { gl } from './native-gl'; + +export class WebGLShader extends Linkable { + _type: number; + _ctx: any; + _source: string; + _compileStatus: boolean; + _compileInfo: string; + + constructor(_: number, ctx: any, type: number) { + super(_); + this._type = type; + this._ctx = ctx; + this._source = ''; + this._compileStatus = false; + this._compileInfo = ''; + } + + _performDelete(): void { + const ctx = this._ctx; + delete ctx._shaders[this._ | 0]; + gl.deleteShader.call(ctx, this._ | 0); + } +} diff --git a/src/webgl-texture-unit.ts b/src/webgl-texture-unit.ts new file mode 100644 index 00000000..b07ab1fe --- /dev/null +++ b/src/webgl-texture-unit.ts @@ -0,0 +1,23 @@ +import type { WebGLTexture } from './webgl-texture'; + +export class WebGLTextureUnit { + _ctx: any; + _idx: number; + _mode: number; + _bind2D: WebGLTexture | null; + _bindCube: WebGLTexture | null; + _bind2DArray?: WebGLTexture | null; + _bind3D?: WebGLTexture | null; + + constructor(ctx: any, idx: number) { + this._ctx = ctx; + this._idx = idx; + this._mode = 0; + this._bind2D = null; + this._bindCube = null; + if (ctx._isWebGL2()) { + this._bind2DArray = null; + this._bind3D = null; + } + } +} diff --git a/src/webgl-texture.ts b/src/webgl-texture.ts new file mode 100644 index 00000000..30b3705b --- /dev/null +++ b/src/webgl-texture.ts @@ -0,0 +1,24 @@ +import { Linkable } from './linkable'; +import { gl } from './native-gl'; + +export class WebGLTexture extends Linkable { + _ctx: any; + _format: number; + _type: number; + _complete: boolean; + + constructor(_: number, ctx: any) { + super(_); + this._ctx = ctx; + this._binding = 0; + this._format = 0; + this._type = 0; + this._complete = true; + } + + _performDelete(): void { + const ctx = this._ctx; + delete ctx._textures[this._ | 0]; + gl.deleteTexture.call(ctx, this._ | 0); + } +} diff --git a/src/webgl-uniform-location.ts b/src/webgl-uniform-location.ts new file mode 100644 index 00000000..f7f0b8d6 --- /dev/null +++ b/src/webgl-uniform-location.ts @@ -0,0 +1,18 @@ +import type { WebGLProgram } from './webgl-program'; +import type { WebGLActiveInfo } from './webgl-active-info'; + +export class WebGLUniformLocation { + _: number; + _program: WebGLProgram; + _linkCount: number; + _activeInfo: WebGLActiveInfo; + _array: null | number[]; + + constructor(_: number, program: WebGLProgram, info: WebGLActiveInfo) { + this._ = _; + this._program = program; + this._linkCount = program._linkCount; + this._activeInfo = info; + this._array = null; + } +} diff --git a/src/webgl-vertex-array-object.ts b/src/webgl-vertex-array-object.ts new file mode 100644 index 00000000..bfa75bab --- /dev/null +++ b/src/webgl-vertex-array-object.ts @@ -0,0 +1,21 @@ +import { Linkable } from './linkable'; +import { gl } from './native-gl'; +import { WebGLVertexArrayObjectState } from './webgl-vertex-attribute'; + +export class WebGLVertexArrayObject extends Linkable { + _ctx: any; + _vertexState: WebGLVertexArrayObjectState; + + constructor(_: number, ctx: any) { + super(_); + this._ctx = ctx; + this._vertexState = new WebGLVertexArrayObjectState(ctx); + } + + _performDelete(): void { + this._vertexState.cleanUp(); + delete (this as any)._vertexState; + delete this._ctx._vaos[this._]; + gl.deleteVertexArray.call(this._ctx, this._ | 0); + } +} diff --git a/src/webgl-vertex-attribute.ts b/src/webgl-vertex-attribute.ts new file mode 100644 index 00000000..cb6b33a0 --- /dev/null +++ b/src/webgl-vertex-attribute.ts @@ -0,0 +1,175 @@ +import { gl } from './native-gl'; +import { WebGLBuffer } from './webgl-buffer'; + +export class WebGLVertexArrayObjectAttribute { + _ctx: any; + _idx: number; + _isPointer: boolean; + _pointerBuffer: WebGLBuffer | null; + _pointerOffset: number; + _pointerSize: number; + _pointerStride: number; + _pointerType: number; + _pointerNormal: boolean; + _inputSize: number; + _inputStride: number; + + constructor(ctx: any, idx: number) { + this._ctx = ctx; + this._idx = idx; + this._isPointer = false; + this._pointerBuffer = null; + this._pointerOffset = 0; + this._pointerSize = 0; + this._pointerStride = 0; + this._pointerType = gl.FLOAT; + this._pointerNormal = false; + this._inputSize = 4; + this._inputStride = 0; + } + + _clear(): void { + this._isPointer = false; + this._pointerBuffer = null; + this._pointerOffset = 0; + this._pointerSize = 0; + this._pointerStride = 0; + this._pointerType = gl.FLOAT; + this._pointerNormal = false; + this._inputSize = 4; + this._inputStride = 0; + } +} + +export class WebGLVertexArrayGlobalAttribute { + _idx: number; + _data: Float32Array; + + constructor(idx: number) { + this._idx = idx; + this._data = new Float32Array([0, 0, 0, 1]); + } +} + +export class WebGLVertexArrayObjectState { + _attribs: WebGLVertexArrayObjectAttribute[]; + _elementArrayBufferBinding: WebGLBuffer | null; + + constructor(ctx: any) { + const numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS); + this._attribs = new Array(numAttribs); + for (let i = 0; i < numAttribs; ++i) { + this._attribs[i] = new WebGLVertexArrayObjectAttribute(ctx, i); + } + this._elementArrayBufferBinding = null; + } + + setElementArrayBuffer(buffer: WebGLBuffer | null): void { + if (buffer !== null && !(buffer instanceof WebGLBuffer)) { + throw new TypeError('setElementArrayBuffer(WebGLBuffer?)'); + } + const current = this._elementArrayBufferBinding; + if (current !== buffer) { + if (current) { + current._refCount -= 1; + current._checkDelete(); + } + if (buffer) { + buffer._refCount += 1; + } + this._elementArrayBufferBinding = buffer; + } + } + + cleanUp(): void { + const elementArrayBuffer = this._elementArrayBufferBinding; + if (elementArrayBuffer) { + elementArrayBuffer._refCount -= 1; + elementArrayBuffer._checkDelete(); + this._elementArrayBufferBinding = null; + } + + for (let i = 0; i < this._attribs.length; ++i) { + const attrib = this._attribs[i]; + if (attrib._pointerBuffer) { + attrib._pointerBuffer._refCount -= 1; + attrib._pointerBuffer._checkDelete(); + } + attrib._clear(); + } + } + + releaseArrayBuffer(buffer: WebGLBuffer | null): void { + if (!buffer) return; + for (let i = 0; i < this._attribs.length; ++i) { + const attrib = this._attribs[i]; + if (attrib._pointerBuffer === buffer) { + attrib._pointerBuffer!._refCount -= 1; + attrib._pointerBuffer!._checkDelete(); + attrib._clear(); + } + } + } + + setVertexAttribPointer( + buffer: WebGLBuffer | null, + index: number, + pointerSize: number, + pointerOffset: number, + pointerStride: number, + pointerType: number, + pointerNormal: boolean, + inputStride: number, + inputSize: number, + ): void { + const attrib = this._attribs[index]; + if (buffer !== attrib._pointerBuffer) { + if (attrib._pointerBuffer) { + attrib._pointerBuffer._refCount -= 1; + attrib._pointerBuffer._checkDelete(); + } + if (buffer) { + buffer._refCount += 1; + } + attrib._pointerBuffer = buffer; + } + attrib._pointerSize = pointerSize; + attrib._pointerOffset = pointerOffset; + attrib._pointerStride = pointerStride; + attrib._pointerType = pointerType; + attrib._pointerNormal = pointerNormal; + attrib._inputStride = inputStride; + attrib._inputSize = inputSize; + } +} + +export class WebGLVertexArrayGlobalState { + _attribs: WebGLVertexArrayGlobalAttribute[]; + _arrayBufferBinding: WebGLBuffer | null; + + constructor(ctx: any) { + const numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS); + this._attribs = new Array(numAttribs); + for (let i = 0; i < numAttribs; ++i) { + this._attribs[i] = new WebGLVertexArrayGlobalAttribute(i); + } + this._arrayBufferBinding = null; + } + + setArrayBuffer(buffer: WebGLBuffer | null): void { + if (buffer !== null && !(buffer instanceof WebGLBuffer)) { + throw new TypeError('setArrayBuffer(WebGLBuffer?)'); + } + const current = this._arrayBufferBinding; + if (current !== buffer) { + if (current) { + current._refCount -= 1; + current._checkDelete(); + } + if (buffer) { + buffer._refCount += 1; + } + this._arrayBufferBinding = buffer; + } + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..9694e3bb --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "node", + "rootDir": "./src", + "outDir": "./dist", + "strict": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] +}