kopia lustrzana https://github.com/OpenDroneMap/WebODM
1344 wiersze
46 KiB
JavaScript
1344 wiersze
46 KiB
JavaScript
'use strict';
|
|
var Map = require( 'osg/Map' );
|
|
var mat4 = require( 'osg/glMatrix' ).mat4;
|
|
var Notify = require( 'osg/notify' );
|
|
var Object = require( 'osg/Object' );
|
|
var Program = require( 'osg/Program' );
|
|
var StateAttribute = require( 'osg/StateAttribute' );
|
|
var Stack = require( 'osg/Stack' );
|
|
var Uniform = require( 'osg/Uniform' );
|
|
var MACROUTILS = require( 'osg/Utils' );
|
|
var WebGLCaps = require( 'osg/WebGLCaps' );
|
|
|
|
|
|
var checkUniformCache = [
|
|
undefined,
|
|
function uniformCheck1( uniformArray, cacheArray ) {
|
|
if ( uniformArray[ 0 ] === cacheArray[ 0 ] ) return true;
|
|
cacheArray[ 0 ] = uniformArray[ 0 ];
|
|
return false;
|
|
},
|
|
|
|
function uniformCheck2( uniformArray, cacheArray ) {
|
|
if ( uniformArray[ 0 ] === cacheArray[ 0 ] && uniformArray[ 1 ] === cacheArray[ 1 ] ) return true;
|
|
cacheArray[ 0 ] = uniformArray[ 0 ];
|
|
cacheArray[ 1 ] = uniformArray[ 1 ];
|
|
return false;
|
|
},
|
|
|
|
function uniformCheck3( uniformArray, cacheArray ) {
|
|
if ( uniformArray[ 0 ] === cacheArray[ 0 ] && uniformArray[ 1 ] === cacheArray[ 1 ] && uniformArray[ 2 ] === cacheArray[ 2 ] ) return true;
|
|
cacheArray[ 0 ] = uniformArray[ 0 ];
|
|
cacheArray[ 1 ] = uniformArray[ 1 ];
|
|
cacheArray[ 2 ] = uniformArray[ 2 ];
|
|
return false;
|
|
},
|
|
|
|
function uniformCheck4( uniformArray, cacheArray ) {
|
|
if ( uniformArray[ 0 ] === cacheArray[ 0 ] && uniformArray[ 1 ] === cacheArray[ 1 ] && uniformArray[ 2 ] === cacheArray[ 2 ] && uniformArray[ 3 ] === cacheArray[ 3 ] ) return true;
|
|
cacheArray[ 0 ] = uniformArray[ 0 ];
|
|
cacheArray[ 1 ] = uniformArray[ 1 ];
|
|
cacheArray[ 2 ] = uniformArray[ 2 ];
|
|
cacheArray[ 3 ] = uniformArray[ 3 ];
|
|
return false;
|
|
}
|
|
];
|
|
|
|
|
|
var State = function ( shaderGeneratorProxy ) {
|
|
Object.call( this );
|
|
|
|
this._graphicContext = undefined;
|
|
this._shaderGeneratorProxy = shaderGeneratorProxy;
|
|
|
|
if ( shaderGeneratorProxy === undefined )
|
|
console.break();
|
|
|
|
this._currentVAO = null;
|
|
this._currentIndexVBO = null;
|
|
|
|
this.vertexAttribList = [];
|
|
this.stateSets = new Stack();
|
|
this._shaderGeneratorNames = new Stack();
|
|
this.uniforms = new Map();
|
|
|
|
this.textureAttributeMapList = [];
|
|
|
|
this.attributeMap = new Map();
|
|
|
|
this.modelMatrix = Uniform.createMatrix4( mat4.create(), 'uModelMatrix' );
|
|
this.viewMatrix = Uniform.createMatrix4( mat4.create(), 'uViewMatrix' );
|
|
this.modelViewMatrix = Uniform.createMatrix4( mat4.create(), 'uModelViewMatrix' );
|
|
this.projectionMatrix = Uniform.createMatrix4( mat4.create(), 'uProjectionMatrix' );
|
|
this.modelViewNormalMatrix = Uniform.createMatrix4( mat4.create(), 'uModelViewNormalMatrix' );
|
|
|
|
// track uniform for color array enabled
|
|
var arrayColorEnable = new Stack();
|
|
arrayColorEnable.globalDefault = Uniform.createFloat1( 0.0, 'uArrayColorEnabled' );
|
|
|
|
this.uniforms.setMap( {
|
|
ArrayColorEnabled: arrayColorEnable
|
|
} );
|
|
|
|
|
|
this._previousColorAttribPair = {};
|
|
this.vertexAttribMap = {};
|
|
this.vertexAttribMap._disable = [];
|
|
this.vertexAttribMap._keys = [];
|
|
|
|
this._frameStamp = undefined;
|
|
|
|
// we dont use Map because in this use case with a few entries
|
|
// {} is faster
|
|
this._programCommonUniformsCache = {};
|
|
|
|
// keep pointer on the last applied modelview matrix
|
|
this._modelViewMatrix = undefined;
|
|
// keep pointer on the last applied projection matrix
|
|
this._projectionMatrix = undefined;
|
|
|
|
|
|
// keep track of last applied program
|
|
this._program = undefined;
|
|
// inject a default program to initialize the stack Program
|
|
this.applyAttribute( new Program() );
|
|
|
|
this._numPushStateSet = 0;
|
|
this._numApply = 0;
|
|
|
|
this._programUniformCache = [];
|
|
this._cacheUniformId = 0;
|
|
};
|
|
|
|
State.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Object.prototype, {
|
|
|
|
getCacheUniformsApplyRenderLeaf: function () {
|
|
return this._programCommonUniformsCache;
|
|
},
|
|
|
|
setGraphicContext: function ( graphicContext ) {
|
|
this._graphicContext = graphicContext;
|
|
this._extVAO = WebGLCaps.instance( graphicContext ).getWebGLExtension( 'OES_vertex_array_object' );
|
|
},
|
|
|
|
getGraphicContext: function () {
|
|
return this._graphicContext;
|
|
},
|
|
|
|
getShaderGeneratorProxy: function () {
|
|
return this._shaderGeneratorProxy;
|
|
},
|
|
|
|
pushCheckOverride: function ( stack, object, maskValue ) {
|
|
// object can be a Uniform, an Attribute, or a shader generator name
|
|
if ( stack.values().length === 0 ) {
|
|
stack.push( this.getObjectPair( object, maskValue ) );
|
|
} else if ( ( stack.back().value & StateAttribute.OVERRIDE ) && !( maskValue & StateAttribute.PROTECTED ) ) {
|
|
stack.push( stack.back() );
|
|
} else {
|
|
stack.push( this.getObjectPair( object, maskValue ) );
|
|
}
|
|
},
|
|
|
|
pushStateSet: function ( stateset ) {
|
|
this._numPushStateSet++;
|
|
this.stateSets.push( stateset );
|
|
|
|
if ( stateset.attributeMap ) {
|
|
this.pushAttributeMap( this.attributeMap, stateset.attributeMap );
|
|
}
|
|
|
|
if ( stateset.textureAttributeMapList ) {
|
|
var list = stateset.textureAttributeMapList;
|
|
for ( var textureUnit = 0, l = list.length; textureUnit < l; textureUnit++ ) {
|
|
if ( !list[ textureUnit ] ) {
|
|
continue;
|
|
}
|
|
|
|
var textureUnitAttributeMap = this.getOrCreateTextureAttributeMap( textureUnit );
|
|
this.pushAttributeMap( textureUnitAttributeMap, list[ textureUnit ] );
|
|
}
|
|
}
|
|
|
|
if ( stateset.uniforms ) {
|
|
this.pushUniformsList( this.uniforms, stateset.uniforms );
|
|
}
|
|
var generatorPair = stateset.getShaderGeneratorPair();
|
|
if ( generatorPair )
|
|
this.pushCheckOverride( this._shaderGeneratorNames, generatorPair.getShaderGeneratorName(), generatorPair.getValue() );
|
|
},
|
|
|
|
getStateSetStackSize: function () {
|
|
return this.stateSets.values().length;
|
|
},
|
|
|
|
insertStateSet: ( function () {
|
|
var tmpStack = [];
|
|
|
|
return function ( pos, stateSet ) {
|
|
|
|
tmpStack.length = 0;
|
|
var length = this.getStateSetStackSize();
|
|
while ( length > pos ) {
|
|
tmpStack.push( this.stateSets.back() );
|
|
this.popStateSet();
|
|
length--;
|
|
}
|
|
|
|
this.pushStateSet( stateSet );
|
|
|
|
for ( var i = tmpStack.length - 1; i >= 0; i-- ) {
|
|
this.pushStateSet( tmpStack[ i ] );
|
|
}
|
|
|
|
};
|
|
} )(),
|
|
|
|
removeStateSet: ( function () {
|
|
var tmpStack = [];
|
|
|
|
return function ( pos ) {
|
|
|
|
var length = this.getStateSetStackSize();
|
|
if ( pos >= length ) {
|
|
Notify.warn( 'Warning State:removeStateSet ' + pos + ' out of range' );
|
|
return;
|
|
}
|
|
|
|
tmpStack.length = 0;
|
|
|
|
// record the StateSet above the one we intend to remove
|
|
while ( length - 1 > pos ) {
|
|
tmpStack.push( this.stateSets.back() );
|
|
this.popStateSet();
|
|
length--;
|
|
}
|
|
|
|
// remove the intended StateSet as well
|
|
this.popStateSet();
|
|
|
|
// push back the original ones that were above the remove StateSet
|
|
for ( var i = tmpStack.length - 1; i >= 0; i-- ) {
|
|
this.pushStateSet( tmpStack[ i ] );
|
|
}
|
|
|
|
};
|
|
} )(),
|
|
|
|
|
|
// needed because we use a cache during the frame to avoid
|
|
// applying uniform or operation. At each frame we need to
|
|
// invalidate those informations
|
|
resetCacheFrame: function () {
|
|
this._modelViewMatrix = this._projectionMatrix = undefined;
|
|
},
|
|
|
|
resetStats: function () {
|
|
this._numApply = 0;
|
|
this._numPushStateSet = 0;
|
|
},
|
|
|
|
// apply program if needed
|
|
applyProgram: function ( program ) {
|
|
if ( this._program === program ) return;
|
|
this._program = program;
|
|
this.getGraphicContext().useProgram( program );
|
|
},
|
|
|
|
applyModelViewMatrix: ( function () {
|
|
|
|
var normal = mat4.create();
|
|
|
|
return function StateApplyModelViewMatrix( matrix ) {
|
|
|
|
if ( this._modelViewMatrix === matrix ) return false;
|
|
|
|
var program = this.getLastProgramApplied();
|
|
var uniformCache = program.getUniformsCache();
|
|
var mu = this.modelViewMatrix;
|
|
var mul = uniformCache.uModelViewMatrix;
|
|
var gc = this.getGraphicContext();
|
|
if ( mul ) {
|
|
|
|
mu.setMatrix4( matrix );
|
|
mu.apply( gc, mul );
|
|
}
|
|
|
|
var sendNormal;
|
|
if ( this._modelViewMatrix ) {
|
|
|
|
// check if we need to push normal
|
|
// test rotation component, if not diff
|
|
// we dont need to send normal
|
|
var m2 = this._modelViewMatrix;
|
|
for ( var i = 0; i < 11; i++ ) {
|
|
if ( matrix[ i ] !== m2[ i ] ) {
|
|
sendNormal = true;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
sendNormal = true;
|
|
}
|
|
|
|
if ( sendNormal ) {
|
|
mu = this.modelViewNormalMatrix;
|
|
mul = uniformCache.uModelViewNormalMatrix;
|
|
if ( mul ) {
|
|
|
|
normal[ 0 ] = matrix[ 0 ];
|
|
normal[ 1 ] = matrix[ 1 ];
|
|
normal[ 2 ] = matrix[ 2 ];
|
|
normal[ 4 ] = matrix[ 4 ];
|
|
normal[ 5 ] = matrix[ 5 ];
|
|
normal[ 6 ] = matrix[ 6 ];
|
|
normal[ 8 ] = matrix[ 8 ];
|
|
normal[ 9 ] = matrix[ 9 ];
|
|
normal[ 10 ] = matrix[ 10 ];
|
|
|
|
mat4.invert( normal, normal );
|
|
mat4.transpose( normal, normal );
|
|
|
|
mu.setMatrix4( normal );
|
|
mu.apply( gc, mul );
|
|
}
|
|
}
|
|
|
|
this._modelViewMatrix = matrix;
|
|
return true;
|
|
};
|
|
} )(),
|
|
|
|
|
|
applyModelViewMatrixEperiment: ( function () {
|
|
|
|
var normal = mat4.create();
|
|
|
|
var checkMatrix = function ( m0, m1 ) {
|
|
if ( m0[ 0 ] !== m1[ 0 ] ) return true;
|
|
if ( m0[ 1 ] !== m1[ 1 ] ) return true;
|
|
if ( m0[ 2 ] !== m1[ 2 ] ) return true;
|
|
if ( m0[ 4 ] !== m1[ 4 ] ) return true;
|
|
if ( m0[ 5 ] !== m1[ 5 ] ) return true;
|
|
if ( m0[ 6 ] !== m1[ 6 ] ) return true;
|
|
if ( m0[ 8 ] !== m1[ 8 ] ) return true;
|
|
if ( m0[ 9 ] !== m1[ 9 ] ) return true;
|
|
if ( m0[ 10 ] !== m1[ 10 ] ) return true;
|
|
return false;
|
|
};
|
|
|
|
var epsilon = 1e-6;
|
|
var scaleEpsilonMax = 1.0 + epsilon;
|
|
var scaleEpsilonMin = 1.0 - epsilon;
|
|
|
|
return function StateApplyModelViewMatrix( matrix ) {
|
|
if ( this._modelViewMatrix === matrix ) return false;
|
|
|
|
var program = this.getLastProgramApplied();
|
|
|
|
var mu = this.modelViewMatrix;
|
|
var mul = program.getUniformsCache().uModelViewMatrix;
|
|
if ( mul ) {
|
|
|
|
mu.setMatrix4( matrix );
|
|
mu.apply( this.getGraphicContext(), mul );
|
|
}
|
|
|
|
var sendNormal = true;
|
|
if ( this._modelViewMatrix ) {
|
|
sendNormal = checkMatrix( matrix, this._modelViewMatrix );
|
|
// check if we need to push normal
|
|
// test rotation component, if not diff
|
|
// we dont need to send normal
|
|
// for ( var i = 0; i < 11; i++ ) {
|
|
// if ( matrix[ i ] !== this._modelViewMatrix[ i ] ) {
|
|
// sendNormal = true;
|
|
// break;
|
|
// }
|
|
// }
|
|
}
|
|
|
|
if ( sendNormal ) {
|
|
mu = this.modelViewNormalMatrix;
|
|
mul = program.getUniformsCache().uModelViewNormalMatrix;
|
|
if ( mul ) {
|
|
|
|
// mat4.copy( normal , matrix );
|
|
normal[ 0 ] = matrix[ 0 ];
|
|
normal[ 1 ] = matrix[ 1 ];
|
|
normal[ 2 ] = matrix[ 2 ];
|
|
normal[ 4 ] = matrix[ 4 ];
|
|
normal[ 5 ] = matrix[ 5 ];
|
|
normal[ 6 ] = matrix[ 6 ];
|
|
normal[ 8 ] = matrix[ 8 ];
|
|
normal[ 9 ] = matrix[ 9 ];
|
|
normal[ 10 ] = matrix[ 10 ];
|
|
|
|
// check for scaling
|
|
var xlen = normal[ 0 ] * normal[ 0 ] + normal[ 4 ] * normal[ 4 ] + normal[ 8 ] * normal[ 8 ];
|
|
var ylen = normal[ 1 ] * normal[ 1 ] + normal[ 5 ] * normal[ 5 ] + normal[ 9 ] * normal[ 9 ];
|
|
var zlen = normal[ 2 ] * normal[ 2 ] + normal[ 6 ] * normal[ 6 ] + normal[ 10 ] * normal[ 10 ];
|
|
|
|
// http://www.gamedev.net/topic/637192-detect-non-uniform-scaling-in-matrix/
|
|
if ( xlen > scaleEpsilonMax || xlen < scaleEpsilonMin ||
|
|
ylen > scaleEpsilonMax || ylen < scaleEpsilonMin ||
|
|
zlen > scaleEpsilonMax || zlen < scaleEpsilonMin ) {
|
|
|
|
mat4.invert( normal, normal );
|
|
mat4.transpose( normal, normal );
|
|
}
|
|
|
|
mu.setMatrix4( normal );
|
|
mu.apply( this.getGraphicContext(), mul );
|
|
}
|
|
}
|
|
|
|
this._modelViewMatrix = matrix;
|
|
return true;
|
|
};
|
|
} )(),
|
|
|
|
applyProjectionMatrix: function ( matrix ) {
|
|
|
|
if ( this._projectionMatrix === matrix ) return;
|
|
|
|
this._projectionMatrix = matrix;
|
|
var program = this.getLastProgramApplied();
|
|
var mu = this.projectionMatrix;
|
|
|
|
var mul = program.getUniformsCache()[ mu.getName() ];
|
|
if ( mul ) {
|
|
|
|
mu.setMatrix4( matrix );
|
|
mu.apply( this.getGraphicContext(), mul );
|
|
|
|
}
|
|
},
|
|
|
|
applyStateSet: function ( stateset ) {
|
|
this.pushStateSet( stateset );
|
|
this.apply();
|
|
this.popStateSet();
|
|
},
|
|
|
|
popAllStateSets: function () {
|
|
while ( this.stateSets.values().length ) {
|
|
this.popStateSet();
|
|
}
|
|
},
|
|
|
|
popStateSet: function () {
|
|
|
|
if ( this.stateSets.empty() ) return;
|
|
|
|
var stateset = this.stateSets.pop();
|
|
|
|
if ( stateset.attributeMap ) {
|
|
this.popAttributeMap( this.attributeMap, stateset.attributeMap );
|
|
}
|
|
|
|
if ( stateset.textureAttributeMapList ) {
|
|
var list = stateset.textureAttributeMapList;
|
|
for ( var textureUnit = 0, l = list.length; textureUnit < l; textureUnit++ ) {
|
|
if ( !list[ textureUnit ] ) {
|
|
continue;
|
|
}
|
|
this.popAttributeMap( this.textureAttributeMapList[ textureUnit ], list[ textureUnit ] );
|
|
}
|
|
}
|
|
|
|
if ( stateset.uniforms ) {
|
|
this.popUniformsList( this.uniforms, stateset.uniforms );
|
|
}
|
|
|
|
if ( stateset.getShaderGeneratorPair() ) {
|
|
this._shaderGeneratorNames.pop();
|
|
}
|
|
},
|
|
|
|
_createAttributeStack: function ( attributeMap, key, globalDefault ) {
|
|
|
|
var attributeStack = new Stack();
|
|
|
|
attributeMap[ key ] = attributeStack;
|
|
attributeMap[ key ].globalDefault = globalDefault;
|
|
attributeMap.dirty();
|
|
|
|
return attributeStack;
|
|
|
|
},
|
|
|
|
haveAppliedAttribute: function ( attribute ) {
|
|
|
|
var key = attribute.getTypeMember();
|
|
var attributeStack = this.attributeMap[ key ];
|
|
if ( !attributeStack ) {
|
|
attributeStack = this._createAttributeStack( this.attributeMap, key, attribute.cloneType() );
|
|
}
|
|
attributeStack.lastApplied = attribute;
|
|
attributeStack.asChanged = true;
|
|
|
|
},
|
|
|
|
applyAttribute: function ( attribute ) {
|
|
|
|
var key = attribute.getTypeMember();
|
|
|
|
var attributeMap = this.attributeMap;
|
|
var attributeStack = attributeMap[ key ];
|
|
if ( !attributeStack ) {
|
|
attributeStack = this._createAttributeStack( this.attributeMap, key, attribute.cloneType() );
|
|
}
|
|
|
|
if ( attributeStack.lastApplied !== attribute ) {
|
|
|
|
if ( attribute.apply ) {
|
|
attribute.apply( this );
|
|
}
|
|
attributeStack.lastApplied = attribute;
|
|
attributeStack.asChanged = true;
|
|
}
|
|
},
|
|
|
|
applyTextureAttribute: function ( unit, attribute ) {
|
|
|
|
|
|
var gl = this.getGraphicContext();
|
|
gl.activeTexture( gl.TEXTURE0 + unit );
|
|
var key = attribute.getTypeMember();
|
|
|
|
if ( !this.textureAttributeMapList[ unit ] ) {
|
|
this.textureAttributeMapList[ unit ] = new Map();
|
|
}
|
|
|
|
var textureUnitAttributeMap = this.getOrCreateTextureAttributeMap( unit );
|
|
var attributeStack = textureUnitAttributeMap[ key ];
|
|
if ( !attributeStack ) {
|
|
attributeStack = this._createAttributeStack( textureUnitAttributeMap, key, attribute.cloneType() );
|
|
}
|
|
|
|
|
|
if ( attributeStack.lastApplied !== attribute ) {
|
|
|
|
if ( attribute.apply ) {
|
|
|
|
// there is a texture we bind it.
|
|
attribute.apply( this, unit );
|
|
|
|
// TODO: optimization:
|
|
// if attribute.isTextureNull()
|
|
// only bind if last Framebuffer Texture Binded
|
|
// are the same as those we try to write from
|
|
// need rewrite of the fbo attachments system to keep history
|
|
// and state to keep last fbo textures binded.
|
|
// (applyTextureAttributeStack concerned too)
|
|
}
|
|
attributeStack.lastApplied = attribute;
|
|
attributeStack.asChanged = true;
|
|
}
|
|
},
|
|
|
|
getLastProgramApplied: function () {
|
|
return this.attributeMap.Program.lastApplied;
|
|
},
|
|
|
|
applyDefault: function () {
|
|
// reset GL State To Default
|
|
// we skip the textures/uniforms/shaders call since they are not necessary
|
|
|
|
// noticed that we accumulate lot of stack, maybe because of the stateGraph
|
|
// CP: ^^ really ? check it / report an issue
|
|
this.popAllStateSets();
|
|
|
|
this.applyAttributeMap( this.attributeMap );
|
|
this.applyTextureAttributeMapList( this.textureAttributeMapList );
|
|
},
|
|
|
|
apply: function () {
|
|
|
|
var lastProgram = this.getLastProgramApplied();
|
|
|
|
this.applyAttributeMap( this.attributeMap );
|
|
this.applyTextureAttributeMapList( this.textureAttributeMapList );
|
|
|
|
var generatedProgram = this._generateAndApplyProgram();
|
|
|
|
if ( generatedProgram ) {
|
|
// will cache uniform and apply them with the program
|
|
|
|
this._applyGeneratedProgramUniforms( this.attributeMap.Program.lastApplied );
|
|
|
|
} else {
|
|
|
|
// custom program so we will iterate on uniform from the program and apply them
|
|
// but in order to be able to use Attribute in the state graph we will check if
|
|
// our program want them. It must be defined by the user
|
|
this._applyCustomProgramUniforms( this.attributeMap.Program.lastApplied );
|
|
|
|
}
|
|
|
|
// reset reference of last applied matrix
|
|
if ( lastProgram !== this.getLastProgramApplied() ) {
|
|
this._modelViewMatrix = undefined;
|
|
this._projectionMatrix = undefined;
|
|
}
|
|
},
|
|
|
|
|
|
applyAttributeMap: function ( attributeMap ) {
|
|
|
|
var attributeStack;
|
|
var attributeMapKeys = attributeMap.getKeys();
|
|
|
|
for ( var i = 0, l = attributeMapKeys.length; i < l; i++ ) {
|
|
var key = attributeMapKeys[ i ];
|
|
|
|
attributeStack = attributeMap[ key ];
|
|
if ( !attributeStack || !attributeStack.asChanged ) {
|
|
continue;
|
|
}
|
|
|
|
var attribute;
|
|
if ( attributeStack.values().length === 0 ) {
|
|
attribute = attributeStack.globalDefault;
|
|
} else {
|
|
attribute = attributeStack.back().object;
|
|
}
|
|
|
|
/*develblock:start*/
|
|
Notify.assert( key === attribute.getTypeMember(), 'State:applyAttributeMap attribute key ' + key + ' !== ' + attribute.getTypeMember() );
|
|
/*develblock:end*/
|
|
|
|
|
|
if ( attributeStack.lastApplied !== attribute ) {
|
|
|
|
if ( attribute.apply )
|
|
attribute.apply( this );
|
|
|
|
attributeStack.lastApplied = attribute;
|
|
|
|
}
|
|
attributeStack.asChanged = false;
|
|
|
|
}
|
|
},
|
|
|
|
getObjectPair: function ( object, value ) {
|
|
return {
|
|
object: object,
|
|
value: value
|
|
};
|
|
},
|
|
|
|
pushUniformsList: function ( uniformMap, stateSetUniformMap ) {
|
|
/*jshint bitwise: false */
|
|
var name;
|
|
var uniform;
|
|
|
|
var stateSetUniformMapKeys = stateSetUniformMap.getKeys();
|
|
|
|
for ( var i = 0, l = stateSetUniformMapKeys.length; i < l; i++ ) {
|
|
var key = stateSetUniformMapKeys[ i ];
|
|
var uniformPair = stateSetUniformMap[ key ];
|
|
uniform = uniformPair.getUniform();
|
|
name = uniform.getName();
|
|
if ( !uniformMap[ name ] ) {
|
|
this._createAttributeStack( uniformMap, name, uniform );
|
|
}
|
|
|
|
this.pushCheckOverride( uniformMap[ name ], uniform, uniformPair.getValue() );
|
|
}
|
|
/*jshint bitwise: true */
|
|
},
|
|
|
|
popUniformsList: function ( uniformMap, stateSetUniformMap ) {
|
|
|
|
var stateSetUniformMapKeys = stateSetUniformMap.getKeys();
|
|
|
|
for ( var i = 0, l = stateSetUniformMapKeys.length; i < l; i++ ) {
|
|
var key = stateSetUniformMapKeys[ i ];
|
|
uniformMap[ key ].pop();
|
|
}
|
|
},
|
|
|
|
|
|
// this funtion must called only if stack has changed
|
|
// check applyTextureAttributeMapList
|
|
_applyTextureAttributeStack: function ( gl, textureUnit, attributeStack ) {
|
|
|
|
var attribute;
|
|
if ( attributeStack.values().length === 0 ) {
|
|
attribute = attributeStack.globalDefault;
|
|
} else {
|
|
attribute = attributeStack.back().object;
|
|
}
|
|
|
|
// if the the stack has changed but the last applied attribute is the same
|
|
// then we dont need to apply it again
|
|
if ( attributeStack.lastApplied !== attribute ) {
|
|
|
|
gl.activeTexture( gl.TEXTURE0 + textureUnit );
|
|
attribute.apply( this, textureUnit );
|
|
|
|
attributeStack.lastApplied = attribute;
|
|
}
|
|
|
|
attributeStack.asChanged = false;
|
|
},
|
|
|
|
applyTextureAttributeMapList: function ( textureAttributesMapList ) {
|
|
var gl = this._graphicContext;
|
|
var textureAttributeMap;
|
|
|
|
for ( var textureUnit = 0, l = textureAttributesMapList.length; textureUnit < l; textureUnit++ ) {
|
|
textureAttributeMap = textureAttributesMapList[ textureUnit ];
|
|
if ( !textureAttributeMap ) {
|
|
continue;
|
|
}
|
|
|
|
|
|
var textureAttributeMapKeys = textureAttributeMap.getKeys();
|
|
|
|
for ( var i = 0, lt = textureAttributeMapKeys.length; i < lt; i++ ) {
|
|
var key = textureAttributeMapKeys[ i ];
|
|
|
|
var attributeStack = textureAttributeMap[ key ];
|
|
|
|
// skip if not stack or not changed in stack
|
|
if ( !attributeStack || !attributeStack.asChanged ) continue;
|
|
|
|
this._applyTextureAttributeStack( gl, textureUnit, attributeStack );
|
|
// var attribute;
|
|
// if ( attributeStack.values().length === 0 ) {
|
|
// attribute = attributeStack.globalDefault;
|
|
// } else {
|
|
// attribute = attributeStack.back().object;
|
|
// }
|
|
// if ( attributeStack.asChanged ) {
|
|
|
|
// gl.activeTexture( gl.TEXTURE0 + textureUnit );
|
|
// attribute.apply( this, textureUnit );
|
|
// attributeStack.lastApplied = attribute;
|
|
// attributeStack.asChanged = false;
|
|
|
|
// }
|
|
}
|
|
}
|
|
},
|
|
|
|
setGlobalDefaultValue: function ( attribute ) {
|
|
Notify.log( 'setGlobalDefaultValue is deprecated, use instead setGlobalDefaultAttribute' );
|
|
this.setGlobalDefaultAttribute( attribute );
|
|
},
|
|
|
|
setGlobalDefaultAttribute: function ( attribute ) {
|
|
var typeMember = attribute.getTypeMember();
|
|
var attributeMap = this.attributeMap;
|
|
|
|
if ( attributeMap[ typeMember ] === undefined ) {
|
|
this._createAttributeStack( attributeMap, typeMember, attribute );
|
|
} else {
|
|
attributeMap[ typeMember ].globalDefault = attribute;
|
|
}
|
|
},
|
|
|
|
getGlobalDefaultAttribute: function ( typeMember ) {
|
|
var attributeMap = this.attributeMap;
|
|
if ( attributeMap[ typeMember ] === undefined ) return undefined;
|
|
|
|
return attributeMap[ typeMember ].globalDefault;
|
|
},
|
|
|
|
setGlobalDefaultTextureAttribute: function ( unit, attribute ) {
|
|
var attributeMap = this.getOrCreateTextureAttributeMap( unit );
|
|
|
|
var typeMember = attribute.getTypeMember();
|
|
|
|
if ( attributeMap[ typeMember ] === undefined ) {
|
|
this._createAttributeStack( attributeMap, typeMember, attribute );
|
|
} else {
|
|
attributeMap[ typeMember ].globalDefault = attribute;
|
|
}
|
|
|
|
},
|
|
|
|
getGlobalDefaultTextureAttribute: function ( unit, typeMember ) {
|
|
var attributeMap = this.getOrCreateTextureAttributeMap( unit );
|
|
var as = attributeMap[ typeMember ];
|
|
return as.globalDefault;
|
|
},
|
|
|
|
getOrCreateTextureAttributeMap: function ( unit ) {
|
|
if ( !this.textureAttributeMapList[ unit ] ) this.textureAttributeMapList[ unit ] = new Map();
|
|
return this.textureAttributeMapList[ unit ];
|
|
},
|
|
|
|
pushAttributeMap: function ( attributeMap, stateSetAttributeMap ) {
|
|
/*jshint bitwise: false */
|
|
var attributeStack;
|
|
var stateSetAttributeMapKeys = stateSetAttributeMap.getKeys();
|
|
|
|
for ( var i = 0, l = stateSetAttributeMapKeys.length; i < l; i++ ) {
|
|
|
|
var type = stateSetAttributeMapKeys[ i ];
|
|
var attributePair = stateSetAttributeMap[ type ];
|
|
var attribute = attributePair.getAttribute();
|
|
|
|
if ( attributeMap[ type ] === undefined ) {
|
|
this._createAttributeStack( attributeMap, type, attribute.cloneType() );
|
|
}
|
|
|
|
attributeStack = attributeMap[ type ];
|
|
this.pushCheckOverride( attributeStack, attribute, attributePair.getValue() );
|
|
attributeStack.asChanged = true;
|
|
}
|
|
/*jshint bitwise: true */
|
|
},
|
|
|
|
popAttributeMap: function ( attributeMap, stateSetAttributeMap ) {
|
|
|
|
var attributeStack;
|
|
var stateSetAttributeMapKeys = stateSetAttributeMap.getKeys();
|
|
|
|
for ( var i = 0, l = stateSetAttributeMapKeys.length; i < l; i++ ) {
|
|
|
|
var type = stateSetAttributeMapKeys[ i ];
|
|
attributeStack = attributeMap[ type ];
|
|
attributeStack.pop();
|
|
attributeStack.asChanged = true;
|
|
|
|
}
|
|
},
|
|
|
|
setIndexArray: function ( array ) {
|
|
|
|
var gl = this._graphicContext;
|
|
|
|
if ( this._currentIndexVBO !== array ) {
|
|
array.bind( gl );
|
|
this._currentIndexVBO = array;
|
|
}
|
|
|
|
if ( array.isDirty() ) {
|
|
array.compile( gl );
|
|
}
|
|
|
|
},
|
|
|
|
lazyDisablingOfVertexAttributes: function () {
|
|
var keys = this.vertexAttribMap._keys;
|
|
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
|
var attr = keys[ i ];
|
|
if ( this.vertexAttribMap[ attr ] ) {
|
|
this.vertexAttribMap._disable[ attr ] = true;
|
|
}
|
|
}
|
|
},
|
|
|
|
enableVertexColor: function () {
|
|
|
|
var program = this.attributeMap.Program.lastApplied;
|
|
|
|
if ( !program.getUniformsCache().uArrayColorEnabled ||
|
|
!program.getAttributesCache().Color ) return; // no color uniform or attribute used, exit
|
|
|
|
// update uniform
|
|
var uniform = this.uniforms.ArrayColorEnabled.globalDefault;
|
|
|
|
var previousColorEnabled = this._previousColorAttribPair[ program.getInstanceID() ];
|
|
|
|
if ( !previousColorEnabled ) {
|
|
uniform.setFloat( 1.0 );
|
|
uniform.apply( this.getGraphicContext(), program.getUniformsCache().uArrayColorEnabled );
|
|
this._previousColorAttribPair[ program.getInstanceID() ] = true;
|
|
}
|
|
|
|
},
|
|
|
|
|
|
disableVertexColor: function () {
|
|
|
|
var program = this.attributeMap.Program.lastApplied;
|
|
|
|
if ( !program.getUniformsCache().uArrayColorEnabled ||
|
|
!program.getAttributesCache().Color ) return; // no color uniform or attribute used, exit
|
|
|
|
// update uniform
|
|
var uniform = this.uniforms.ArrayColorEnabled.globalDefault;
|
|
|
|
var previousColorEnabled = this._previousColorAttribPair[ program.getInstanceID() ];
|
|
|
|
if ( previousColorEnabled ) {
|
|
uniform.setFloat( 0.0 );
|
|
uniform.apply( this.getGraphicContext(), program.getUniformsCache().uArrayColorEnabled );
|
|
this._previousColorAttribPair[ program.getInstanceID() ] = false;
|
|
}
|
|
|
|
},
|
|
|
|
|
|
applyDisablingOfVertexAttributes: function () {
|
|
|
|
var keys = this.vertexAttribMap._keys;
|
|
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
|
if ( this.vertexAttribMap._disable[ keys[ i ] ] === true ) {
|
|
var attr = keys[ i ];
|
|
this._graphicContext.disableVertexAttribArray( attr );
|
|
this.vertexAttribMap._disable[ attr ] = false;
|
|
this.vertexAttribMap[ attr ] = false;
|
|
}
|
|
}
|
|
},
|
|
|
|
clearVertexAttribCache: function () {
|
|
|
|
var vertexAttribMap = this.vertexAttribMap;
|
|
var keys = vertexAttribMap._keys;
|
|
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
|
var attr = keys[ i ];
|
|
vertexAttribMap[ attr ] = undefined;
|
|
vertexAttribMap._disable[ attr ] = false;
|
|
}
|
|
|
|
this.vertexAttribMap._disable.length = 0;
|
|
this.vertexAttribMap._keys.length = 0;
|
|
|
|
},
|
|
|
|
/**
|
|
* set a vertex array object.
|
|
* return true if binded the vao and false
|
|
* if was already binded
|
|
*/
|
|
setVertexArrayObject: function ( vao ) {
|
|
|
|
if ( this._currentVAO !== vao ) {
|
|
|
|
this._extVAO.bindVertexArrayOES( vao );
|
|
this._currentVAO = vao;
|
|
|
|
// disable cache to force a re enable of array
|
|
if ( !vao ) this.clearVertexAttribCache();
|
|
|
|
// disable currentIndexVBO to force to bind indexArray from Geometry
|
|
// if there is a change of vao
|
|
this._currentIndexVBO = undefined;
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
setVertexAttribArray: function ( attrib, array, normalize ) {
|
|
|
|
var vertexAttribMap = this.vertexAttribMap;
|
|
vertexAttribMap._disable[ attrib ] = false;
|
|
var gl = this._graphicContext;
|
|
var binded = false;
|
|
|
|
if ( array.isDirty() ) {
|
|
array.bind( gl );
|
|
array.compile( gl );
|
|
binded = true;
|
|
}
|
|
|
|
var currentArray = vertexAttribMap[ attrib ];
|
|
if ( currentArray !== array ) {
|
|
|
|
if ( !binded ) {
|
|
array.bind( gl );
|
|
}
|
|
|
|
if ( !currentArray ) {
|
|
gl.enableVertexAttribArray( attrib );
|
|
|
|
// can be === false (so undefined check is important)
|
|
if ( currentArray === undefined )
|
|
vertexAttribMap._keys.push( attrib );
|
|
|
|
}
|
|
|
|
vertexAttribMap[ attrib ] = array;
|
|
gl.vertexAttribPointer( attrib, array.getItemSize(), array.getType(), normalize, 0, 0 );
|
|
}
|
|
},
|
|
|
|
|
|
_getActiveUniformsFromProgramAttributes: function ( program, activeUniformsList ) {
|
|
|
|
var attributeMapStack = this.attributeMap;
|
|
|
|
var attributeKeys = program.getTrackAttributes().attributeKeys;
|
|
|
|
if ( attributeKeys.length > 0 ) {
|
|
|
|
for ( var i = 0, l = attributeKeys.length; i < l; i++ ) {
|
|
|
|
var key = attributeKeys[ i ];
|
|
var attributeStack = attributeMapStack[ key ];
|
|
if ( attributeStack === undefined ) {
|
|
continue;
|
|
}
|
|
|
|
// we just need the uniform list and not the attribute itself
|
|
var attribute = attributeStack.globalDefault;
|
|
if ( attribute.getOrCreateUniforms === undefined ) {
|
|
continue;
|
|
}
|
|
|
|
var uniformMap = attribute.getOrCreateUniforms();
|
|
var uniformKeys = uniformMap.getKeys();
|
|
|
|
for ( var a = 0, b = uniformKeys.length; a < b; a++ ) {
|
|
activeUniformsList.push( uniformMap[ uniformKeys[ a ] ] );
|
|
}
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
_getActiveUniformsFromProgramTextureAttributes: function ( program, activeUniformsList ) {
|
|
|
|
var textureAttributeKeysList = program.getTrackAttributes().textureAttributeKeys;
|
|
if ( textureAttributeKeysList === undefined ) return;
|
|
|
|
for ( var unit = 0, nbUnit = textureAttributeKeysList.length; unit < nbUnit; unit++ ) {
|
|
|
|
var textureAttributeKeys = textureAttributeKeysList[ unit ];
|
|
if ( textureAttributeKeys === undefined ) continue;
|
|
|
|
var unitTextureAttributeList = this.textureAttributeMapList[ unit ];
|
|
if ( unitTextureAttributeList === undefined ) continue;
|
|
|
|
for ( var i = 0, l = textureAttributeKeys.length; i < l; i++ ) {
|
|
var key = textureAttributeKeys[ i ];
|
|
|
|
var attributeStack = unitTextureAttributeList[ key ];
|
|
if ( attributeStack === undefined ) {
|
|
continue;
|
|
}
|
|
// we just need the uniform list and not the attribute itself
|
|
var attribute = attributeStack.globalDefault;
|
|
if ( attribute.getOrCreateUniforms === undefined ) {
|
|
continue;
|
|
}
|
|
var uniformMap = attribute.getOrCreateUniforms();
|
|
var uniformMapKeys = uniformMap.getKeys();
|
|
|
|
for ( var a = 0, b = uniformMapKeys.length; a < b; a++ ) {
|
|
activeUniformsList.push( uniformMap[ uniformMapKeys[ a ] ] );
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
_cacheUniformsForCustomProgram: function ( program, activeUniformsList ) {
|
|
|
|
this._getActiveUniformsFromProgramAttributes( program, activeUniformsList );
|
|
|
|
this._getActiveUniformsFromProgramTextureAttributes( program, activeUniformsList );
|
|
|
|
var gl = this._graphicContext;
|
|
|
|
// now we have a list on uniforms we want to track but we will filter them to use only what is needed by our program
|
|
// not that if you create a uniforms whith the same name of a tracked attribute, and it will override it
|
|
var uniformsFinal = new Map();
|
|
|
|
for ( var i = 0, l = activeUniformsList.length; i < l; i++ ) {
|
|
var u = activeUniformsList[ i ];
|
|
var uniformName = u.getName();
|
|
var loc = gl.getUniformLocation( program._program, uniformName );
|
|
if ( loc !== undefined && loc !== null ) {
|
|
uniformsFinal[ uniformName ] = u;
|
|
}
|
|
}
|
|
uniformsFinal.dirty();
|
|
program.trackUniforms = uniformsFinal;
|
|
|
|
},
|
|
|
|
_applyCustomProgramUniforms: ( function () {
|
|
|
|
var activeUniformsList = [];
|
|
|
|
return function ( program ) {
|
|
|
|
// custom program so we will iterate on uniform from the program and apply them
|
|
// but in order to be able to use Attribute in the state graph we will check if
|
|
// our program want them. It must be defined by the user
|
|
|
|
// first time we see attributes key, so we will keep a list of uniforms from attributes
|
|
activeUniformsList.length = 0;
|
|
|
|
// fill the program with cached active uniforms map from attributes and texture attributes
|
|
if ( program.getTrackAttributes() !== undefined && program.trackUniforms === undefined ) {
|
|
this._cacheUniformsForCustomProgram( program, activeUniformsList );
|
|
}
|
|
|
|
var programUniformMap = program.getUniformsCache();
|
|
var programUniformKeys = programUniformMap.getKeys();
|
|
var uniformMapStackContent = this.uniforms;
|
|
|
|
var programTrackUniformMap;
|
|
if ( program.trackUniforms )
|
|
programTrackUniformMap = program.trackUniforms;
|
|
|
|
var uniform;
|
|
for ( var i = 0, l = programUniformKeys.length; i < l; i++ ) {
|
|
var uniformKey = programUniformKeys[ i ];
|
|
var location = programUniformMap[ uniformKey ];
|
|
var uniformStack = uniformMapStackContent[ uniformKey ];
|
|
|
|
if ( uniformStack === undefined ) {
|
|
|
|
if ( programTrackUniformMap !== undefined ) {
|
|
uniform = programTrackUniformMap[ uniformKey ];
|
|
if ( uniform !== undefined ) {
|
|
uniform.apply( this._graphicContext, location );
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( uniformStack.values().length === 0 ) {
|
|
uniform = uniformStack.globalDefault;
|
|
} else {
|
|
uniform = uniformStack.back().object;
|
|
}
|
|
uniform.apply( this._graphicContext, location );
|
|
|
|
}
|
|
}
|
|
};
|
|
} )(),
|
|
|
|
|
|
// apply a generated program if necessary
|
|
// It build a Shader from the shader generator
|
|
// it apply for the following condition
|
|
// the user has not put a Pogram in the stack or if he has he added one with OFF
|
|
_generateAndApplyProgram: function () {
|
|
|
|
var attributeMap = this.attributeMap;
|
|
if ( attributeMap.Program !== undefined && attributeMap.Program.values().length !== 0 && attributeMap.Program.back().value !== StateAttribute.OFF )
|
|
return undefined;
|
|
|
|
// no custom program look into the stack of ShaderGenerator name
|
|
// what we should use to generate a program
|
|
|
|
var last = this._shaderGeneratorNames.back();
|
|
var shaderGenerator = this._shaderGeneratorProxy.getShaderGenerator( last ? last.object : undefined );
|
|
|
|
var program = shaderGenerator.getOrCreateProgram( this );
|
|
this.applyAttribute( program );
|
|
return program;
|
|
},
|
|
|
|
_computeForeignUniforms: function ( programUniformMap, activeUniformMap ) {
|
|
|
|
var uniformMapKeys = programUniformMap.getKeys();
|
|
var uniformMap = programUniformMap;
|
|
|
|
var foreignUniforms = [];
|
|
for ( var i = 0, l = uniformMapKeys.length; i < l; i++ ) {
|
|
|
|
var name = uniformMapKeys[ i ];
|
|
var location = uniformMap[ name ];
|
|
|
|
if ( location !== undefined && activeUniformMap[ name ] === undefined ) {
|
|
|
|
// filter 'standard' uniform matrix that will be applied for all shader
|
|
if ( name !== this.modelViewMatrix.getName() &&
|
|
name !== this.modelMatrix.getName() &&
|
|
name !== this.viewMatrix.getName() &&
|
|
name !== this.projectionMatrix.getName() &&
|
|
name !== this.modelViewNormalMatrix.getName() &&
|
|
name !== 'uArrayColorEnabled' ) {
|
|
foreignUniforms.push( name );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return foreignUniforms;
|
|
},
|
|
|
|
_removeUniformsNotRequiredByProgram: function ( activeUniformMap, programUniformMap ) {
|
|
|
|
var activeUniformMapKeys = activeUniformMap.getKeys();
|
|
|
|
for ( var i = 0, l = activeUniformMapKeys.length; i < l; i++ ) {
|
|
var name = activeUniformMapKeys[ i ];
|
|
var location = programUniformMap[ name ];
|
|
if ( location === undefined || location === null ) {
|
|
delete activeUniformMap[ name ];
|
|
activeUniformMap.dirty();
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
_cacheUniformsForGeneratedProgram: function ( program ) {
|
|
|
|
var foreignUniforms = this._computeForeignUniforms( program.getUniformsCache(), program.getActiveUniforms() );
|
|
program.setForeignUniforms( foreignUniforms );
|
|
|
|
|
|
// remove uniforms listed by attributes (getActiveUniforms) but not required by the program
|
|
this._removeUniformsNotRequiredByProgram( program.getActiveUniforms(), program.getUniformsCache() );
|
|
|
|
},
|
|
|
|
_copyUniformEntry: function ( uniform ) {
|
|
|
|
var internalArray = uniform.getInternalArray();
|
|
var cacheData;
|
|
if ( internalArray.length < 16 )
|
|
cacheData = new internalArray.constructor( internalArray.length );
|
|
|
|
return cacheData;
|
|
},
|
|
|
|
_initUniformCache: function ( program ) {
|
|
|
|
var activeUniformMap = program.getActiveUniforms();
|
|
var activeUniformKeys = activeUniformMap.getKeys();
|
|
|
|
var foreignUniformKeys = program.getForeignUniforms();
|
|
var uniformMapStack = this.uniforms;
|
|
|
|
var cacheForeignUniforms = [];
|
|
var cacheActiveUniforms = [];
|
|
|
|
var i, l, cache, name, cacheData, uniform;
|
|
|
|
program._cacheUniformId = this._cacheUniformId++;
|
|
this._programUniformCache[ program._cacheUniformId ] = {};
|
|
|
|
if ( foreignUniformKeys.length ) {
|
|
cache = cacheForeignUniforms;
|
|
for ( i = 0, l = foreignUniformKeys.length; i < l; i++ ) {
|
|
name = foreignUniformKeys[ i ];
|
|
var uniStack = uniformMapStack[ name ];
|
|
if ( uniStack ) {
|
|
uniform = uniStack.globalDefault;
|
|
cacheData = this._copyUniformEntry( uniform );
|
|
cache.push( cacheData );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if ( activeUniformKeys.length ) {
|
|
cache = cacheActiveUniforms;
|
|
for ( i = 0, l = activeUniformKeys.length; i < l; i++ ) {
|
|
name = activeUniformKeys[ i ];
|
|
uniform = activeUniformMap[ name ];
|
|
cacheData = this._copyUniformEntry( uniform );
|
|
cache.push( cacheData );
|
|
}
|
|
}
|
|
|
|
this._programUniformCache[ program._cacheUniformId ].foreign = cacheForeignUniforms;
|
|
this._programUniformCache[ program._cacheUniformId ].active = cacheActiveUniforms;
|
|
|
|
},
|
|
|
|
_checkCacheAndApplyUniform: function ( uniform, cacheArray, i, programUniformMap, name ) {
|
|
var isCached;
|
|
var internalArray = uniform.getInternalArray();
|
|
var uniformArrayLength = internalArray.length;
|
|
if ( uniformArrayLength <= 4 ) {
|
|
var uniformCache = cacheArray[ i ];
|
|
isCached = checkUniformCache[ uniformArrayLength ]( internalArray, uniformCache );
|
|
} else {
|
|
isCached = false;
|
|
}
|
|
|
|
if ( !isCached ) {
|
|
var location = programUniformMap[ name ];
|
|
uniform.apply( this._graphicContext, location );
|
|
}
|
|
},
|
|
|
|
// note that about TextureAttribute that need uniform on unit we would need to improve
|
|
// the current uniformList ...
|
|
|
|
// when we apply the shader for the first time, we want to compute the active uniforms for this shader and the list of uniforms not extracted from attributes called foreignUniforms
|
|
_applyGeneratedProgramUniforms: function ( program ) {
|
|
|
|
var foreignUniformKeys = program.getForeignUniforms();
|
|
if ( !foreignUniformKeys ) {
|
|
this._cacheUniformsForGeneratedProgram( program );
|
|
foreignUniformKeys = program.getForeignUniforms();
|
|
|
|
this._initUniformCache( program );
|
|
}
|
|
|
|
var programUniformMap = program.getUniformsCache();
|
|
var activeUniformMap = program.getActiveUniforms();
|
|
|
|
var cacheUniformsActive = this._programUniformCache[ program._cacheUniformId ].active;
|
|
var cacheUniformsForeign = this._programUniformCache[ program._cacheUniformId ].foreign;
|
|
|
|
// apply active uniforms
|
|
// caching uniforms from attribtues make it impossible to overwrite uniform with a custom uniform instance not used in the attributes
|
|
var i, l, name, uniform;
|
|
var activeUniformKeys = activeUniformMap.getKeys();
|
|
|
|
this.nbApplyUniform += activeUniformKeys.length;
|
|
for ( i = 0, l = activeUniformKeys.length; i < l; i++ ) {
|
|
|
|
name = activeUniformKeys[ i ];
|
|
uniform = activeUniformMap[ name ];
|
|
|
|
this._checkCacheAndApplyUniform( uniform, cacheUniformsActive, i, programUniformMap, name );
|
|
}
|
|
|
|
var uniformMapStack = this.uniforms;
|
|
|
|
// apply now foreign uniforms, it's uniforms needed by the program but not contains in attributes used to generate this program
|
|
for ( i = 0, l = foreignUniformKeys.length; i < l; i++ ) {
|
|
name = foreignUniformKeys[ i ];
|
|
var uniformStack = uniformMapStack[ name ];
|
|
if ( uniformStack !== undefined ) {
|
|
if ( uniformStack.values().length === 0 ) {
|
|
uniform = uniformStack.globalDefault;
|
|
Notify.warn( 'Uniform Default Not attached to a StateSet in Scene Hierarchy: ' + uniformStack.globalDefault.getName() );
|
|
} else {
|
|
uniform = uniformStack.back().object;
|
|
}
|
|
}
|
|
|
|
this._checkCacheAndApplyUniform( uniform, cacheUniformsForeign, i, programUniformMap, name );
|
|
|
|
}
|
|
},
|
|
|
|
// Use to detect changes in RenderLeaf between call to avoid to applyStateSet
|
|
_setStateSetsDrawID: function ( id ) {
|
|
var values = this.stateSets.values();
|
|
for ( var i = 0, nbStateSets = values.length; i < nbStateSets; i++ ) {
|
|
values[ i ].setDrawID( id );
|
|
}
|
|
},
|
|
|
|
_stateSetStackChanged: function ( id, nbLast ) {
|
|
var values = this.stateSets.values();
|
|
var nbStateSets = values.length;
|
|
if ( nbLast !== nbStateSets )
|
|
return true;
|
|
|
|
for ( var i = 0; i < nbStateSets; i++ ) {
|
|
if ( id !== values[ i ].getDrawID() )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
} ), 'osg', 'State' );
|
|
|
|
module.exports = State;
|