1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018 |
- /**
- * Uniforms of a program.
- * Those form a tree structure with a special top-level container for the root,
- * which you get by calling 'new WebGLUniforms( gl, program )'.
- *
- *
- * Properties of inner nodes including the top-level container:
- *
- * .seq - array of nested uniforms
- * .map - nested uniforms by name
- *
- *
- * Methods of all nodes except the top-level container:
- *
- * .setValue( gl, value, [textures] )
- *
- * uploads a uniform value(s)
- * the 'textures' parameter is needed for sampler uniforms
- *
- *
- * Static methods of the top-level container (textures factorizations):
- *
- * .upload( gl, seq, values, textures )
- *
- * sets uniforms in 'seq' to 'values[id].value'
- *
- * .seqWithValue( seq, values ) : filteredSeq
- *
- * filters 'seq' entries with corresponding entry in values
- *
- *
- * Methods of the top-level container (textures factorizations):
- *
- * .setValue( gl, name, value, textures )
- *
- * sets uniform with name 'name' to 'value'
- *
- * .setOptional( gl, obj, prop )
- *
- * like .set for an optional property of the object
- *
- */
- import { CubeTexture } from '../../textures/CubeTexture.js';
- import { Texture } from '../../textures/Texture.js';
- import { DataArrayTexture } from '../../textures/DataArrayTexture.js';
- import { Data3DTexture } from '../../textures/Data3DTexture.js';
- const emptyTexture = /*@__PURE__*/ new Texture();
- const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture();
- const empty3dTexture = /*@__PURE__*/ new Data3DTexture();
- const emptyCubeTexture = /*@__PURE__*/ new CubeTexture();
- // --- Utilities ---
- // Array Caches (provide typed arrays for temporary by size)
- const arrayCacheF32 = [];
- const arrayCacheI32 = [];
- // Float32Array caches used for uploading Matrix uniforms
- const mat4array = new Float32Array( 16 );
- const mat3array = new Float32Array( 9 );
- const mat2array = new Float32Array( 4 );
- // Flattening for arrays of vectors and matrices
- function flatten( array, nBlocks, blockSize ) {
- const firstElem = array[ 0 ];
- if ( firstElem <= 0 || firstElem > 0 ) return array;
- // unoptimized: ! isNaN( firstElem )
- // see http://jacksondunstan.com/articles/983
- const n = nBlocks * blockSize;
- let r = arrayCacheF32[ n ];
- if ( r === undefined ) {
- r = new Float32Array( n );
- arrayCacheF32[ n ] = r;
- }
- if ( nBlocks !== 0 ) {
- firstElem.toArray( r, 0 );
- for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
- offset += blockSize;
- array[ i ].toArray( r, offset );
- }
- }
- return r;
- }
- function arraysEqual( a, b ) {
- if ( a.length !== b.length ) return false;
- for ( let i = 0, l = a.length; i < l; i ++ ) {
- if ( a[ i ] !== b[ i ] ) return false;
- }
- return true;
- }
- function copyArray( a, b ) {
- for ( let i = 0, l = b.length; i < l; i ++ ) {
- a[ i ] = b[ i ];
- }
- }
- // Texture unit allocation
- function allocTexUnits( textures, n ) {
- let r = arrayCacheI32[ n ];
- if ( r === undefined ) {
- r = new Int32Array( n );
- arrayCacheI32[ n ] = r;
- }
- for ( let i = 0; i !== n; ++ i ) {
- r[ i ] = textures.allocateTextureUnit();
- }
- return r;
- }
- // --- Setters ---
- // Note: Defining these methods externally, because they come in a bunch
- // and this way their names minify.
- // Single scalar
- function setValueV1f( gl, v ) {
- const cache = this.cache;
- if ( cache[ 0 ] === v ) return;
- gl.uniform1f( this.addr, v );
- cache[ 0 ] = v;
- }
- // Single float vector (from flat array or THREE.VectorN)
- function setValueV2f( gl, v ) {
- const cache = this.cache;
- if ( v.x !== undefined ) {
- if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
- gl.uniform2f( this.addr, v.x, v.y );
- cache[ 0 ] = v.x;
- cache[ 1 ] = v.y;
- }
- } else {
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform2fv( this.addr, v );
- copyArray( cache, v );
- }
- }
- function setValueV3f( gl, v ) {
- const cache = this.cache;
- if ( v.x !== undefined ) {
- if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
- gl.uniform3f( this.addr, v.x, v.y, v.z );
- cache[ 0 ] = v.x;
- cache[ 1 ] = v.y;
- cache[ 2 ] = v.z;
- }
- } else if ( v.r !== undefined ) {
- if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
- gl.uniform3f( this.addr, v.r, v.g, v.b );
- cache[ 0 ] = v.r;
- cache[ 1 ] = v.g;
- cache[ 2 ] = v.b;
- }
- } else {
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform3fv( this.addr, v );
- copyArray( cache, v );
- }
- }
- function setValueV4f( gl, v ) {
- const cache = this.cache;
- if ( v.x !== undefined ) {
- if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
- gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
- cache[ 0 ] = v.x;
- cache[ 1 ] = v.y;
- cache[ 2 ] = v.z;
- cache[ 3 ] = v.w;
- }
- } else {
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform4fv( this.addr, v );
- copyArray( cache, v );
- }
- }
- // Single matrix (from flat array or THREE.MatrixN)
- function setValueM2( gl, v ) {
- const cache = this.cache;
- const elements = v.elements;
- if ( elements === undefined ) {
- if ( arraysEqual( cache, v ) ) return;
- gl.uniformMatrix2fv( this.addr, false, v );
- copyArray( cache, v );
- } else {
- if ( arraysEqual( cache, elements ) ) return;
- mat2array.set( elements );
- gl.uniformMatrix2fv( this.addr, false, mat2array );
- copyArray( cache, elements );
- }
- }
- function setValueM3( gl, v ) {
- const cache = this.cache;
- const elements = v.elements;
- if ( elements === undefined ) {
- if ( arraysEqual( cache, v ) ) return;
- gl.uniformMatrix3fv( this.addr, false, v );
- copyArray( cache, v );
- } else {
- if ( arraysEqual( cache, elements ) ) return;
- mat3array.set( elements );
- gl.uniformMatrix3fv( this.addr, false, mat3array );
- copyArray( cache, elements );
- }
- }
- function setValueM4( gl, v ) {
- const cache = this.cache;
- const elements = v.elements;
- if ( elements === undefined ) {
- if ( arraysEqual( cache, v ) ) return;
- gl.uniformMatrix4fv( this.addr, false, v );
- copyArray( cache, v );
- } else {
- if ( arraysEqual( cache, elements ) ) return;
- mat4array.set( elements );
- gl.uniformMatrix4fv( this.addr, false, mat4array );
- copyArray( cache, elements );
- }
- }
- // Single integer / boolean
- function setValueV1i( gl, v ) {
- const cache = this.cache;
- if ( cache[ 0 ] === v ) return;
- gl.uniform1i( this.addr, v );
- cache[ 0 ] = v;
- }
- // Single integer / boolean vector (from flat array)
- function setValueV2i( gl, v ) {
- const cache = this.cache;
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform2iv( this.addr, v );
- copyArray( cache, v );
- }
- function setValueV3i( gl, v ) {
- const cache = this.cache;
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform3iv( this.addr, v );
- copyArray( cache, v );
- }
- function setValueV4i( gl, v ) {
- const cache = this.cache;
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform4iv( this.addr, v );
- copyArray( cache, v );
- }
- // Single unsigned integer
- function setValueV1ui( gl, v ) {
- const cache = this.cache;
- if ( cache[ 0 ] === v ) return;
- gl.uniform1ui( this.addr, v );
- cache[ 0 ] = v;
- }
- // Single unsigned integer vector (from flat array)
- function setValueV2ui( gl, v ) {
- const cache = this.cache;
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform2uiv( this.addr, v );
- copyArray( cache, v );
- }
- function setValueV3ui( gl, v ) {
- const cache = this.cache;
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform3uiv( this.addr, v );
- copyArray( cache, v );
- }
- function setValueV4ui( gl, v ) {
- const cache = this.cache;
- if ( arraysEqual( cache, v ) ) return;
- gl.uniform4uiv( this.addr, v );
- copyArray( cache, v );
- }
- // Single texture (2D / Cube)
- function setValueT1( gl, v, textures ) {
- const cache = this.cache;
- const unit = textures.allocateTextureUnit();
- if ( cache[ 0 ] !== unit ) {
- gl.uniform1i( this.addr, unit );
- cache[ 0 ] = unit;
- }
- textures.setTexture2D( v || emptyTexture, unit );
- }
- function setValueT3D1( gl, v, textures ) {
- const cache = this.cache;
- const unit = textures.allocateTextureUnit();
- if ( cache[ 0 ] !== unit ) {
- gl.uniform1i( this.addr, unit );
- cache[ 0 ] = unit;
- }
- textures.setTexture3D( v || empty3dTexture, unit );
- }
- function setValueT6( gl, v, textures ) {
- const cache = this.cache;
- const unit = textures.allocateTextureUnit();
- if ( cache[ 0 ] !== unit ) {
- gl.uniform1i( this.addr, unit );
- cache[ 0 ] = unit;
- }
- textures.setTextureCube( v || emptyCubeTexture, unit );
- }
- function setValueT2DArray1( gl, v, textures ) {
- const cache = this.cache;
- const unit = textures.allocateTextureUnit();
- if ( cache[ 0 ] !== unit ) {
- gl.uniform1i( this.addr, unit );
- cache[ 0 ] = unit;
- }
- textures.setTexture2DArray( v || emptyArrayTexture, unit );
- }
- // Helper to pick the right setter for the singular case
- function getSingularSetter( type ) {
- switch ( type ) {
- case 0x1406: return setValueV1f; // FLOAT
- case 0x8b50: return setValueV2f; // _VEC2
- case 0x8b51: return setValueV3f; // _VEC3
- case 0x8b52: return setValueV4f; // _VEC4
- case 0x8b5a: return setValueM2; // _MAT2
- case 0x8b5b: return setValueM3; // _MAT3
- case 0x8b5c: return setValueM4; // _MAT4
- case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
- case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
- case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
- case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
- case 0x1405: return setValueV1ui; // UINT
- case 0x8dc6: return setValueV2ui; // _VEC2
- case 0x8dc7: return setValueV3ui; // _VEC3
- case 0x8dc8: return setValueV4ui; // _VEC4
- case 0x8b5e: // SAMPLER_2D
- case 0x8d66: // SAMPLER_EXTERNAL_OES
- case 0x8dca: // INT_SAMPLER_2D
- case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
- case 0x8b62: // SAMPLER_2D_SHADOW
- return setValueT1;
- case 0x8b5f: // SAMPLER_3D
- case 0x8dcb: // INT_SAMPLER_3D
- case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
- return setValueT3D1;
- case 0x8b60: // SAMPLER_CUBE
- case 0x8dcc: // INT_SAMPLER_CUBE
- case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
- case 0x8dc5: // SAMPLER_CUBE_SHADOW
- return setValueT6;
- case 0x8dc1: // SAMPLER_2D_ARRAY
- case 0x8dcf: // INT_SAMPLER_2D_ARRAY
- case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
- case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
- return setValueT2DArray1;
- }
- }
- // Array of scalars
- function setValueV1fArray( gl, v ) {
- gl.uniform1fv( this.addr, v );
- }
- // Array of vectors (from flat array or array of THREE.VectorN)
- function setValueV2fArray( gl, v ) {
- const data = flatten( v, this.size, 2 );
- gl.uniform2fv( this.addr, data );
- }
- function setValueV3fArray( gl, v ) {
- const data = flatten( v, this.size, 3 );
- gl.uniform3fv( this.addr, data );
- }
- function setValueV4fArray( gl, v ) {
- const data = flatten( v, this.size, 4 );
- gl.uniform4fv( this.addr, data );
- }
- // Array of matrices (from flat array or array of THREE.MatrixN)
- function setValueM2Array( gl, v ) {
- const data = flatten( v, this.size, 4 );
- gl.uniformMatrix2fv( this.addr, false, data );
- }
- function setValueM3Array( gl, v ) {
- const data = flatten( v, this.size, 9 );
- gl.uniformMatrix3fv( this.addr, false, data );
- }
- function setValueM4Array( gl, v ) {
- const data = flatten( v, this.size, 16 );
- gl.uniformMatrix4fv( this.addr, false, data );
- }
- // Array of integer / boolean
- function setValueV1iArray( gl, v ) {
- gl.uniform1iv( this.addr, v );
- }
- // Array of integer / boolean vectors (from flat array)
- function setValueV2iArray( gl, v ) {
- gl.uniform2iv( this.addr, v );
- }
- function setValueV3iArray( gl, v ) {
- gl.uniform3iv( this.addr, v );
- }
- function setValueV4iArray( gl, v ) {
- gl.uniform4iv( this.addr, v );
- }
- // Array of unsigned integer
- function setValueV1uiArray( gl, v ) {
- gl.uniform1uiv( this.addr, v );
- }
- // Array of unsigned integer vectors (from flat array)
- function setValueV2uiArray( gl, v ) {
- gl.uniform2uiv( this.addr, v );
- }
- function setValueV3uiArray( gl, v ) {
- gl.uniform3uiv( this.addr, v );
- }
- function setValueV4uiArray( gl, v ) {
- gl.uniform4uiv( this.addr, v );
- }
- // Array of textures (2D / 3D / Cube / 2DArray)
- function setValueT1Array( gl, v, textures ) {
- const n = v.length;
- const units = allocTexUnits( textures, n );
- gl.uniform1iv( this.addr, units );
- for ( let i = 0; i !== n; ++ i ) {
- textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
- }
- }
- function setValueT3DArray( gl, v, textures ) {
- const n = v.length;
- const units = allocTexUnits( textures, n );
- gl.uniform1iv( this.addr, units );
- for ( let i = 0; i !== n; ++ i ) {
- textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] );
- }
- }
- function setValueT6Array( gl, v, textures ) {
- const n = v.length;
- const units = allocTexUnits( textures, n );
- gl.uniform1iv( this.addr, units );
- for ( let i = 0; i !== n; ++ i ) {
- textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
- }
- }
- function setValueT2DArrayArray( gl, v, textures ) {
- const n = v.length;
- const units = allocTexUnits( textures, n );
- gl.uniform1iv( this.addr, units );
- for ( let i = 0; i !== n; ++ i ) {
- textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] );
- }
- }
- // Helper to pick the right setter for a pure (bottom-level) array
- function getPureArraySetter( type ) {
- switch ( type ) {
- case 0x1406: return setValueV1fArray; // FLOAT
- case 0x8b50: return setValueV2fArray; // _VEC2
- case 0x8b51: return setValueV3fArray; // _VEC3
- case 0x8b52: return setValueV4fArray; // _VEC4
- case 0x8b5a: return setValueM2Array; // _MAT2
- case 0x8b5b: return setValueM3Array; // _MAT3
- case 0x8b5c: return setValueM4Array; // _MAT4
- case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
- case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
- case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
- case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
- case 0x1405: return setValueV1uiArray; // UINT
- case 0x8dc6: return setValueV2uiArray; // _VEC2
- case 0x8dc7: return setValueV3uiArray; // _VEC3
- case 0x8dc8: return setValueV4uiArray; // _VEC4
- case 0x8b5e: // SAMPLER_2D
- case 0x8d66: // SAMPLER_EXTERNAL_OES
- case 0x8dca: // INT_SAMPLER_2D
- case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
- case 0x8b62: // SAMPLER_2D_SHADOW
- return setValueT1Array;
- case 0x8b5f: // SAMPLER_3D
- case 0x8dcb: // INT_SAMPLER_3D
- case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
- return setValueT3DArray;
- case 0x8b60: // SAMPLER_CUBE
- case 0x8dcc: // INT_SAMPLER_CUBE
- case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
- case 0x8dc5: // SAMPLER_CUBE_SHADOW
- return setValueT6Array;
- case 0x8dc1: // SAMPLER_2D_ARRAY
- case 0x8dcf: // INT_SAMPLER_2D_ARRAY
- case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
- case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
- return setValueT2DArrayArray;
- }
- }
- // --- Uniform Classes ---
- class SingleUniform {
- constructor( id, activeInfo, addr ) {
- this.id = id;
- this.addr = addr;
- this.cache = [];
- this.setValue = getSingularSetter( activeInfo.type );
- // this.path = activeInfo.name; // DEBUG
- }
- }
- class PureArrayUniform {
- constructor( id, activeInfo, addr ) {
- this.id = id;
- this.addr = addr;
- this.cache = [];
- this.size = activeInfo.size;
- this.setValue = getPureArraySetter( activeInfo.type );
- // this.path = activeInfo.name; // DEBUG
- }
- }
- class StructuredUniform {
- constructor( id ) {
- this.id = id;
- this.seq = [];
- this.map = {};
- }
- setValue( gl, value, textures ) {
- const seq = this.seq;
- for ( let i = 0, n = seq.length; i !== n; ++ i ) {
- const u = seq[ i ];
- u.setValue( gl, value[ u.id ], textures );
- }
- }
- }
- // --- Top-level ---
- // Parser - builds up the property tree from the path strings
- const RePathPart = /(\w+)(\])?(\[|\.)?/g;
- // extracts
- // - the identifier (member name or array index)
- // - followed by an optional right bracket (found when array index)
- // - followed by an optional left bracket or dot (type of subscript)
- //
- // Note: These portions can be read in a non-overlapping fashion and
- // allow straightforward parsing of the hierarchy that WebGL encodes
- // in the uniform names.
- function addUniform( container, uniformObject ) {
- container.seq.push( uniformObject );
- container.map[ uniformObject.id ] = uniformObject;
- }
- function parseUniform( activeInfo, addr, container ) {
- const path = activeInfo.name,
- pathLength = path.length;
- // reset RegExp object, because of the early exit of a previous run
- RePathPart.lastIndex = 0;
- while ( true ) {
- const match = RePathPart.exec( path ),
- matchEnd = RePathPart.lastIndex;
- let id = match[ 1 ];
- const idIsIndex = match[ 2 ] === ']',
- subscript = match[ 3 ];
- if ( idIsIndex ) id = id | 0; // convert to integer
- if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
- // bare name or "pure" bottom-level array "[0]" suffix
- addUniform( container, subscript === undefined ?
- new SingleUniform( id, activeInfo, addr ) :
- new PureArrayUniform( id, activeInfo, addr ) );
- break;
- } else {
- // step into inner node / create it in case it doesn't exist
- const map = container.map;
- let next = map[ id ];
- if ( next === undefined ) {
- next = new StructuredUniform( id );
- addUniform( container, next );
- }
- container = next;
- }
- }
- }
- // Root Container
- class WebGLUniforms {
- constructor( gl, program ) {
- this.seq = [];
- this.map = {};
- const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
- for ( let i = 0; i < n; ++ i ) {
- const info = gl.getActiveUniform( program, i ),
- addr = gl.getUniformLocation( program, info.name );
- parseUniform( info, addr, this );
- }
- }
- setValue( gl, name, value, textures ) {
- const u = this.map[ name ];
- if ( u !== undefined ) u.setValue( gl, value, textures );
- }
- setOptional( gl, object, name ) {
- const v = object[ name ];
- if ( v !== undefined ) this.setValue( gl, name, v );
- }
- static upload( gl, seq, values, textures ) {
- for ( let i = 0, n = seq.length; i !== n; ++ i ) {
- const u = seq[ i ],
- v = values[ u.id ];
- if ( v.needsUpdate !== false ) {
- // note: always updating when .needsUpdate is undefined
- u.setValue( gl, v.value, textures );
- }
- }
- }
- static seqWithValue( seq, values ) {
- const r = [];
- for ( let i = 0, n = seq.length; i !== n; ++ i ) {
- const u = seq[ i ];
- if ( u.id in values ) r.push( u );
- }
- return r;
- }
- }
- export { WebGLUniforms };
|