kopia lustrzana https://github.com/OpenDroneMap/WebODM
Started replacing OSGJS with three.js
rodzic
9fc005d8aa
commit
f9f4f9f869
|
@ -1,10 +1,15 @@
|
|||
import React from 'react';
|
||||
import './css/ModelView.scss';
|
||||
import {osgDB, osgGA, osgViewer, osg, CADManipulator} from './vendor/osgjs/OSG';
|
||||
import $ from 'jquery';
|
||||
|
||||
const THREE = require('three'); // import does not work :/
|
||||
require('./vendor/OBJLoader');
|
||||
THREE.OrbitControls = require('three-orbit-controls')(THREE);
|
||||
THREE.MTLLoader = require('three-mtl-loader');
|
||||
|
||||
class ModelView extends React.Component {
|
||||
static defaultProps = {
|
||||
test: 0
|
||||
test: 1
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
|
@ -19,29 +24,64 @@ class ModelView extends React.Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.viewer = new osgViewer.Viewer(this.canvas);
|
||||
this.viewer.init();
|
||||
|
||||
const node = new osg.MatrixTransform();
|
||||
var container;
|
||||
var camera, controls, scene, renderer;
|
||||
var lighting, ambient, keyLight, fillLight, backLight;
|
||||
var windowHalfX = window.innerWidth / 2;
|
||||
var windowHalfY = window.innerHeight / 2;
|
||||
|
||||
this.viewer.setSceneData( node );
|
||||
this.viewer.setupManipulator(new osgGA.CADManipulator());
|
||||
this.viewer.getManipulator().computeHomePosition();
|
||||
this.viewer.run();
|
||||
const init = () => {
|
||||
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
|
||||
camera.position.z = 3;
|
||||
|
||||
let request = osgDB.readNodeURL( '/static/app/test/test.osgjs' );
|
||||
request.then( function ( model ) {
|
||||
node.addChild(model);
|
||||
this.viewer.getManipulator().computeHomePosition();
|
||||
}.bind( this ) );
|
||||
scene = new THREE.Scene();
|
||||
ambient = new THREE.AmbientLight(0xFFFFFF, 1.0);
|
||||
scene.add(ambient);
|
||||
|
||||
var mtlLoader = new THREE.MTLLoader();
|
||||
mtlLoader.setTexturePath('/static/app/test/');
|
||||
mtlLoader.setPath('/static/app/test/');
|
||||
mtlLoader.load('odm_textured_model.mtl', function (materials) {
|
||||
materials.preload();
|
||||
|
||||
|
||||
const objLoader = new THREE.OBJLoader();
|
||||
objLoader.setMaterials(materials);
|
||||
objLoader.load('/static/app/test/odm_textured_model.obj', function (object) {
|
||||
scene.add(object);
|
||||
console.log(object);
|
||||
});
|
||||
});
|
||||
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize($(this.canvas).width(), $(this.canvas).height());
|
||||
|
||||
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.2;
|
||||
controls.enableZoom = true;
|
||||
|
||||
this.canvas.appendChild(renderer.domElement);
|
||||
};
|
||||
|
||||
function render() {
|
||||
requestAnimationFrame(render);
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
init();
|
||||
render();
|
||||
}
|
||||
|
||||
// React render
|
||||
render(){
|
||||
return (<div className="model-view">
|
||||
<canvas
|
||||
<div
|
||||
ref={(domNode) => { this.canvas = domNode; }}
|
||||
style={{height: "100%", width: "100%"}}
|
||||
onContextMenu={(e) => {e.preventDefault();}}></canvas>
|
||||
onContextMenu={(e) => {e.preventDefault();}}></div>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
|
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
File diff suppressed because one or more lines are too long
Plik diff jest za duży
Load Diff
|
@ -1,13 +0,0 @@
|
|||
// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
|
||||
require('../../js/transition.js')
|
||||
require('../../js/alert.js')
|
||||
require('../../js/button.js')
|
||||
require('../../js/carousel.js')
|
||||
require('../../js/collapse.js')
|
||||
require('../../js/dropdown.js')
|
||||
require('../../js/modal.js')
|
||||
require('../../js/tooltip.js')
|
||||
require('../../js/popover.js')
|
||||
require('../../js/scrollspy.js')
|
||||
require('../../js/tab.js')
|
||||
require('../../js/affix.js')
|
|
@ -1,40 +0,0 @@
|
|||
'use strict';
|
||||
var osgNameSpace = require( 'osgNameSpace' );
|
||||
var osg = require( 'osg/osg' );
|
||||
var osgAnimation = require( 'osgAnimation/osgAnimation' );
|
||||
var osgDB = require( 'osgDB/osgDB' );
|
||||
var osgGA = require( 'osgGA/osgGA' );
|
||||
var osgUtil = require( 'osgUtil/osgUtil' );
|
||||
var osgViewer = require( 'osgViewer/osgViewer' );
|
||||
var osgShader = require( 'osgShader/osgShader' );
|
||||
var osgShadow = require( 'osgShadow/osgShadow' );
|
||||
var osgText = require( 'osgText/osgText' );
|
||||
var osgWrappers = require( 'osgWrappers/osgWrappers' );
|
||||
var osgPlugins = require( 'osgPlugins/osgPlugins' );
|
||||
|
||||
|
||||
var openSceneGraph = osgNameSpace;
|
||||
|
||||
openSceneGraph.osg = osg;
|
||||
openSceneGraph.osgAnimation = osgAnimation;
|
||||
openSceneGraph.osgDB = osgDB;
|
||||
openSceneGraph.osgGA = osgGA;
|
||||
openSceneGraph.osgUtil = osgUtil;
|
||||
openSceneGraph.osgViewer = osgViewer;
|
||||
openSceneGraph.osgShader = osgShader;
|
||||
openSceneGraph.osgShadow = osgShadow;
|
||||
openSceneGraph.osgText = osgText;
|
||||
openSceneGraph.osgWrappers = osgWrappers;
|
||||
openSceneGraph.osgPlugins = osgPlugins;
|
||||
|
||||
var namespaces = [ 'osg', 'osgAnimation', 'osgDB', 'osgGA', 'osgUtil', 'osgViewer', 'osgShader', 'osgShadow', 'osgText', 'osgWrappers', 'osgPlugins' ];
|
||||
|
||||
|
||||
// for backward compatibility
|
||||
openSceneGraph.globalify = function () {
|
||||
namespaces.forEach( function ( namespace ) {
|
||||
window[ namespace ] = openSceneGraph[ namespace ];
|
||||
} );
|
||||
};
|
||||
|
||||
module.exports = openSceneGraph;
|
|
@ -1,5 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
ArrayType: Float64Array
|
||||
};
|
|
@ -1,332 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Transform = require( 'osg/Transform' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var vec4 = require( 'osg/glMatrix' ).vec4;
|
||||
var quat = require( 'osg/glMatrix' ).quat;
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
var Node = require( 'osg/Node' );
|
||||
|
||||
/** AutoTransform is a derived form of Transform that automatically
|
||||
* scales or rotates to keep its children aligned with screen coordinates.
|
||||
* W.r.t. AutorotateModes only rotate to screen is supported right now.
|
||||
* More AutorotateModes modes should be addressed in the future.
|
||||
* @class AutoTransform
|
||||
*/
|
||||
|
||||
var AutoTransform = function () {
|
||||
Transform.call( this );
|
||||
this._matrix = mat4.create();
|
||||
this._position = vec3.create();
|
||||
this._matrixDirty = true;
|
||||
this._scale = vec3.fromValues( 1.0, 1.0, 1.0 );
|
||||
this._minimumScale = 0;
|
||||
this._maximumScale = Number.MAX_VALUE;
|
||||
this._rotation = quat.create();
|
||||
this._pivotPoint = vec3.create();
|
||||
this._autoScaleToScreen = false;
|
||||
this._autoRotateToScreen = false;
|
||||
this._cachedMatrix = mat4.create();
|
||||
this._firstTimeToInitEyePoint = true;
|
||||
this._autoScaleTransitionWidthRatio = 0.25;
|
||||
this._billboardAttribute = undefined;
|
||||
this._previousWidth = 0.0;
|
||||
this._previousHeight = 0.0;
|
||||
this._previousProjection = mat4.create();
|
||||
this._previousModelView = mat4.create();
|
||||
this._previousPosition = vec3.create();
|
||||
};
|
||||
|
||||
/** @lends Autotransform.prototype */
|
||||
AutoTransform.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Transform.prototype, {
|
||||
|
||||
getMatrix: function () {
|
||||
return this._matrix;
|
||||
},
|
||||
|
||||
setMatrix: function ( m ) {
|
||||
this._matrix = m;
|
||||
this.dirtyBound();
|
||||
},
|
||||
|
||||
setPosition: function ( pos ) {
|
||||
this._position = pos;
|
||||
this._matrixDirty = true;
|
||||
this.dirtyBound();
|
||||
},
|
||||
getPosition: function () {
|
||||
return this._position;
|
||||
},
|
||||
|
||||
setRotation: function ( q ) {
|
||||
this._rotation = q;
|
||||
this._matrixDirty = true;
|
||||
this.dirtyBound();
|
||||
},
|
||||
|
||||
getRotation: function () {
|
||||
return this._rotation;
|
||||
},
|
||||
|
||||
setScale: function ( scale ) {
|
||||
this.setScaleFromvec3( vec3.fromValues( scale, scale, scale ) );
|
||||
},
|
||||
|
||||
setScaleFromvec3: function ( scaleVec ) {
|
||||
this._scale = scaleVec;
|
||||
this._matrixDirty = true;
|
||||
this.dirtyBound();
|
||||
},
|
||||
|
||||
getScale: function () {
|
||||
return this._scale;
|
||||
},
|
||||
|
||||
setMinimumScale: function ( minimumScale ) {
|
||||
this._minimumScale = minimumScale;
|
||||
},
|
||||
|
||||
getMinimumScale: function () {
|
||||
return this._minimumScale;
|
||||
},
|
||||
|
||||
setMaximumScale: function ( maximumScale ) {
|
||||
this._maximumScale = maximumScale;
|
||||
},
|
||||
|
||||
getMaximumScale: function () {
|
||||
return this._maximumScale;
|
||||
},
|
||||
|
||||
setAutoScaleToScreen: function ( autoScaleToScreen ) {
|
||||
this._autoScaleToScreen = autoScaleToScreen;
|
||||
this._matrixDirty = true;
|
||||
},
|
||||
|
||||
getAutoScaleToScreen: function () {
|
||||
return this._autoScaleToScreen;
|
||||
},
|
||||
|
||||
setAutoRotateToScreen: function ( value ) {
|
||||
this._autoRotateToScreen = value;
|
||||
},
|
||||
|
||||
getAutoRotateToScreen: function () {
|
||||
return this._autoRotateToScreen;
|
||||
},
|
||||
|
||||
setAutoScaleTransitionWidthRatio: function ( autoScaleTransitionWidthRatio ) {
|
||||
this._autoScaleTransitionWidthRatio = autoScaleTransitionWidthRatio;
|
||||
},
|
||||
|
||||
getAutoScaleTransitionWidthRatio: function () {
|
||||
return this._autoScaleTransitionWidthRatio;
|
||||
},
|
||||
|
||||
// local to "local world" (not Global World)
|
||||
computeLocalToWorldMatrix: function ( matrix /*, nodeVisitor */ ) {
|
||||
if ( this._matrixDirty ) this.computeMatrix();
|
||||
if ( this.referenceFrame === TransformEnums.RELATIVE_RF ) {
|
||||
mat4.mul( matrix, matrix, this._matrix );
|
||||
} else {
|
||||
mat4.copy( matrix, this._matrix );
|
||||
}
|
||||
},
|
||||
|
||||
computeMatrix: ( function () {
|
||||
var neg = vec3.create();
|
||||
var tmpMat = mat4.create();
|
||||
return function () {
|
||||
if ( !this._matrixDirty ) return;
|
||||
mat4.fromQuat( this._matrix, this._rotation );
|
||||
|
||||
mat4.fromTranslation( tmpMat, this._position );
|
||||
mat4.mul( this._matrix, tmpMat, this._matrix );
|
||||
mat4.scale( this._matrix, this._matrix, this._scale );
|
||||
mat4.translate( this._matrix, this._matrix, vec3.neg( neg, this._pivotPoint ) );
|
||||
this._matrixDirty = false;
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
computeWorldToLocalMatrix: ( function () {
|
||||
var neg = vec3.create();
|
||||
var rotInverse = quat.create();
|
||||
var scaleInverse = vec3.create();
|
||||
var tmpMat = mat4.create();
|
||||
|
||||
return function ( matrix /*, nodeVisitor */ ) {
|
||||
if ( this.scale[ 0 ] === 0.0 && this.scale[ 1 ] === 0.0 && this.scale[ 2 ] === 0.0 ) {
|
||||
return false;
|
||||
}
|
||||
scaleInverse[ 0 ] = 1.0 / this._scale[ 0 ];
|
||||
scaleInverse[ 1 ] = 1.0 / this._scale[ 1 ];
|
||||
scaleInverse[ 2 ] = 1.0 / this._scale[ 2 ];
|
||||
if ( this.referenceFrame === TransformEnums.RELATIVE_RF ) {
|
||||
|
||||
mat4.fromTranslation( tmpMat, vec3.neg( neg, this._position ) );
|
||||
mat4.mul( matrix, tmpMat, matrix );
|
||||
|
||||
if ( !quat.zeroRotation( this._rotation ) ) {
|
||||
mat4.fromQuat( tmpMat, quat.invert( rotInverse, this._rotation ) );
|
||||
mat4.mul( matrix, tmpMat, matrix );
|
||||
}
|
||||
mat4.fromScaling( tmpMat, scaleInverse );
|
||||
mat4.mul( matrix, tmpMat, matrix );
|
||||
|
||||
mat4.fromTranslation( tmpMat, this._pivotPoint );
|
||||
mat4.mul( matrix, tmpMat, matrix );
|
||||
|
||||
} else { // absolute
|
||||
mat4.fromQuat( this._matrix, quat.invert( rotInverse, this._rotation ) );
|
||||
mat4.translate( matrix, matrix, vec3.neg( neg, this._position ) );
|
||||
|
||||
mat4.fromScaling( tmpMat, scaleInverse );
|
||||
mat4.mul( matrix, tmpMat, matrix );
|
||||
|
||||
mat4.fromTranslation( tmpMat, this._pivotPoint );
|
||||
mat4.mul( matrix, tmpMat, matrix );
|
||||
|
||||
}
|
||||
return true;
|
||||
};
|
||||
} )(),
|
||||
|
||||
computeBound: ( function () {
|
||||
var matrix = mat4.create();
|
||||
return function ( bSphere ) {
|
||||
if ( this._autoScaleToScreen && this._firstTimeToInitEyePoint )
|
||||
return bSphere;
|
||||
Node.prototype.computeBound.call( this, bSphere );
|
||||
if ( !bSphere.valid() ) {
|
||||
return bSphere;
|
||||
}
|
||||
mat4.identity( matrix );
|
||||
// local to local world (not Global World)
|
||||
this.computeLocalToWorldMatrix( matrix );
|
||||
//Matrix.transformBoundingSphere( matrix, bSphere, bSphere );
|
||||
bSphere.transformMat4( bSphere, matrix );
|
||||
return bSphere;
|
||||
};
|
||||
} )(),
|
||||
|
||||
accept: ( function () {
|
||||
|
||||
return function ( visitor ) {
|
||||
if ( visitor.getVisitorType() === NodeVisitor.CULL_VISITOR ) {
|
||||
|
||||
var width = visitor.getViewport().width();
|
||||
var height = visitor.getViewport().height();
|
||||
var projMat = visitor.getCurrentProjectionMatrix();
|
||||
var modelViewMat = visitor.getCurrentModelViewMatrix();
|
||||
var position = this._position;
|
||||
var doUpdate = this._firstTimeToInitEyePoint;
|
||||
if ( !this._firstTimeToInitEyePoint ) {
|
||||
if ( width !== this._previousWidth || height !== this._previousHeight ) {
|
||||
doUpdate = true;
|
||||
} else if ( !mat4.exactEquals( projMat, this._previousProjection ) ) {
|
||||
doUpdate = true;
|
||||
} else if ( !mat4.exactEquals( modelViewMat, this._previousModelView ) ) {
|
||||
doUpdate = true;
|
||||
} else if ( !vec3.exactEquals( position, this._previousPosition ) ) {
|
||||
doUpdate = true;
|
||||
}
|
||||
}
|
||||
this._firstTimeToInitEyePoint = false;
|
||||
if ( doUpdate ) {
|
||||
if ( this._autoScaleToScreen ) {
|
||||
var viewport = visitor.getViewport();
|
||||
var psvector = this.computePixelSizeVector( viewport, projMat, modelViewMat );
|
||||
var v = vec4.fromValues( this._position[ 0 ], this._position[ 1 ], this._position[ 2 ], 1.0 );
|
||||
var pixelSize = vec4.dot( v, psvector );
|
||||
pixelSize = 0.48 / pixelSize;
|
||||
var size = 1.0 / pixelSize;
|
||||
if ( this._autoScaleTransitionWidthRatio > 0.0 ) {
|
||||
var c, b, a;
|
||||
if ( this._minimumScale > 0.0 ) {
|
||||
var j = this._minimumScale;
|
||||
var i = ( this._maximumScale < Number.MAX_VALUE ) ?
|
||||
this._minimumScale + ( this._maximumScale - this._minimumScale ) * this._autoScaleTransitionWidthRatio :
|
||||
this._minimumScale * ( 1.0 + this._autoScaleTransitionWidthRatio );
|
||||
c = 1.0 / ( 4.0 * ( i - j ) );
|
||||
b = 1.0 - 2.0 * c * i;
|
||||
a = j + b * b / ( 4.0 * c );
|
||||
var k = -b / ( 2.0 * c );
|
||||
if ( size < k ) size = this._minimumScale;
|
||||
else if ( size < i ) size = a + b * size + c * ( size * size );
|
||||
}
|
||||
if ( this._maximumScale < Number.MAX_VALUE ) {
|
||||
var n = this._maximumScale;
|
||||
var m = ( this._minimumScale > 0.0 ) ?
|
||||
this._maximumScale + ( this._minimumScale - this._maximumScale ) * this._autoScaleTransitionWidthRatio :
|
||||
this._maximumScale * ( 1.0 - this._autoScaleTransitionWidthRatio );
|
||||
c = 1.0 / ( 4.0 * ( m - n ) );
|
||||
b = 1.0 - 2.0 * c * m;
|
||||
a = n + b * b / ( 4.0 * c );
|
||||
var p = -b / ( 2.0 * c );
|
||||
|
||||
if ( size > p ) size = this._maximumScale;
|
||||
else if ( size > m ) size = a + b * size + c * ( size * size );
|
||||
}
|
||||
}
|
||||
this.setScale( size );
|
||||
}
|
||||
if ( this._autoRotateToScreen ) {
|
||||
var rotation = quat.create();
|
||||
mat4.getRotation( rotation, modelViewMat );
|
||||
this.setRotation( quat.invert( rotation, rotation ) );
|
||||
}
|
||||
this._previousWidth = width;
|
||||
this._previousHeight = height;
|
||||
vec3.copy( this._previousPosition, position );
|
||||
mat4.copy( this._previousProjection, projMat );
|
||||
mat4.copy( this._previousModelView, modelViewMat );
|
||||
}
|
||||
}
|
||||
|
||||
Node.prototype.accept.call( this, visitor );
|
||||
};
|
||||
} )(),
|
||||
|
||||
computePixelSizeVector: ( function () {
|
||||
var scale00 = vec3.create();
|
||||
var scale10 = vec3.create();
|
||||
return function ( W, P, M ) {
|
||||
// Where W = viewport, P = ProjectionMatrix, M = ModelViewMatrix
|
||||
// Comment from OSG:
|
||||
// pre adjust P00,P20,P23,P33 by multiplying them by the viewport window matrix.
|
||||
// here we do it in short hand with the knowledge of how the window matrix is formed
|
||||
// note P23,P33 are multiplied by an implicit 1 which would come from the window matrix.
|
||||
|
||||
// scaling for horizontal pixels
|
||||
var P00 = P[ 0 ] * W.width() * 0.5;
|
||||
var P20_00 = P[ 8 ] * W.width() * 0.5 + P[ 11 ] * W.width() * 0.5;
|
||||
vec3.set( scale00, M[ 0 ] * P00 + M[ 2 ] * P20_00,
|
||||
M[ 4 ] * P00 + M[ 6 ] * P20_00,
|
||||
M[ 8 ] * P00 + M[ 10 ] * P20_00 );
|
||||
|
||||
// scaling for vertical pixels
|
||||
var P10 = P[ 5 ] * W.height() * 0.5;
|
||||
var P20_10 = P[ 9 ] * W.height() * 0.5 + P[ 11 ] * W.height() * 0.5;
|
||||
vec3.set( scale10, M[ 1 ] * P10 + M[ 2 ] * P20_10,
|
||||
M[ 5 ] * P10 + M[ 6 ] * P20_10,
|
||||
M[ 9 ] * P10 + M[ 10 ] * P20_10 );
|
||||
|
||||
var P23 = P[ 11 ];
|
||||
var P33 = P[ 15 ];
|
||||
var pixelSizeVector = vec4.fromValues( M[ 2 ] * P23, M[ 6 ] * P23, M[ 10 ] * P23, M[ 14 ] * P23 + M[ 15 ] * P33 );
|
||||
|
||||
var scaleRatio = 0.7071067811 / Math.sqrt( vec3.sqrLen( scale00 ) + vec3.sqrLen( scale10 ) );
|
||||
vec4.scale( pixelSizeVector, pixelSizeVector, scaleRatio );
|
||||
return pixelSizeVector;
|
||||
};
|
||||
} )()
|
||||
|
||||
|
||||
} ), 'osg', 'AutoTransform' );
|
||||
MACROUTILS.setTypeID( AutoTransform );
|
||||
|
||||
module.exports = AutoTransform;
|
|
@ -1,31 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
|
||||
|
||||
var BillboardAttribute = function () {
|
||||
StateAttribute.call( this );
|
||||
this._attributeEnable = false;
|
||||
};
|
||||
|
||||
BillboardAttribute.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'Billboard',
|
||||
|
||||
cloneType: function () {
|
||||
return new BillboardAttribute();
|
||||
},
|
||||
|
||||
setEnabled: function ( state ) {
|
||||
this._attributeEnable = state;
|
||||
},
|
||||
|
||||
isEnabled: function () {
|
||||
return this._attributeEnable;
|
||||
},
|
||||
|
||||
apply: function () {}
|
||||
|
||||
} ), 'osg', 'Billboard' );
|
||||
|
||||
module.exports = BillboardAttribute;
|
|
@ -1,49 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var vec4 = require( 'osg/glMatrix' ).vec4;
|
||||
|
||||
/**
|
||||
* Manage BlendColor attribute
|
||||
* @class
|
||||
* @memberOf osg
|
||||
* @extends StateAttribute
|
||||
*/
|
||||
var BlendColor = function ( color ) {
|
||||
StateAttribute.call( this );
|
||||
this._constantColor = vec4.create();
|
||||
vec4.set( this._constantColor, 1.0, 1.0, 1.0, 1.0 );
|
||||
if ( color !== undefined ) {
|
||||
this.setConstantColor( color );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @lends BlendColor.prototype
|
||||
*/
|
||||
BlendColor.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
attributeType: 'BlendColor',
|
||||
cloneType: function () {
|
||||
return new BlendColor();
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {} color
|
||||
*/
|
||||
setConstantColor: function ( color ) {
|
||||
vec4.copy( this._constantColor, color );
|
||||
},
|
||||
getConstantColor: function () {
|
||||
return this._constantColor;
|
||||
},
|
||||
apply: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
gl.blendColor( this._constantColor[ 0 ],
|
||||
this._constantColor[ 1 ],
|
||||
this._constantColor[ 2 ],
|
||||
this._constantColor[ 3 ] );
|
||||
}
|
||||
} ), 'osg', 'BlendColor' );
|
||||
|
||||
module.exports = BlendColor;
|
|
@ -1,155 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
|
||||
/**
|
||||
* Manage Blending mode
|
||||
* @class BlendFunc
|
||||
*/
|
||||
var BlendFunc = function ( sourceRGB, destinationRGB, sourceAlpha, destinationAlpha ) {
|
||||
StateAttribute.call( this );
|
||||
this._sourceFactor = BlendFunc.DISABLE;
|
||||
this._destinationFactor = BlendFunc.DISABLE;
|
||||
this._sourceFactorAlpha = this._sourceFactor;
|
||||
this._destinationFactorAlpha = this._destinationFactor;
|
||||
this._separate = false;
|
||||
if ( sourceRGB !== undefined ) {
|
||||
this.setSource( sourceRGB );
|
||||
}
|
||||
if ( destinationRGB !== undefined ) {
|
||||
this.setDestination( destinationRGB );
|
||||
}
|
||||
|
||||
if ( sourceAlpha !== undefined ) {
|
||||
this.setSourceAlpha( sourceAlpha );
|
||||
}
|
||||
if ( destinationAlpha !== undefined ) {
|
||||
this.setDestinationAlpha( destinationAlpha );
|
||||
}
|
||||
};
|
||||
|
||||
BlendFunc.DISABLE = -1;
|
||||
BlendFunc.ZERO = 0;
|
||||
BlendFunc.ONE = 1;
|
||||
BlendFunc.SRC_COLOR = 0x0300;
|
||||
BlendFunc.ONE_MINUS_SRC_COLOR = 0x0301;
|
||||
BlendFunc.SRC_ALPHA = 0x0302;
|
||||
BlendFunc.ONE_MINUS_SRC_ALPHA = 0x0303;
|
||||
BlendFunc.DST_ALPHA = 0x0304;
|
||||
BlendFunc.ONE_MINUS_DST_ALPHA = 0x0305;
|
||||
BlendFunc.DST_COLOR = 0x0306;
|
||||
BlendFunc.ONE_MINUS_DST_COLOR = 0x0307;
|
||||
BlendFunc.SRC_ALPHA_SATURATE = 0x0308;
|
||||
|
||||
/* Separate Blend Functions */
|
||||
BlendFunc.BLEND_DST_RGB = 0x80C8;
|
||||
BlendFunc.BLEND_SRC_RGB = 0x80C9;
|
||||
BlendFunc.BLEND_DST_ALPHA = 0x80CA;
|
||||
BlendFunc.BLEND_SRC_ALPHA = 0x80CB;
|
||||
BlendFunc.CONSTANT_COLOR = 0x8001;
|
||||
BlendFunc.ONE_MINUS_CONSTANT_COLOR = 0x8002;
|
||||
BlendFunc.CONSTANT_ALPHA = 0x8003;
|
||||
BlendFunc.ONE_MINUS_CONSTANT_ALPHA = 0x8004;
|
||||
BlendFunc.BLEND_COLOR = 0x8005;
|
||||
|
||||
|
||||
/** @lends BlendFunc.prototype */
|
||||
BlendFunc.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
/**
|
||||
StateAttribute type of BlendFunc
|
||||
@type String
|
||||
*/
|
||||
attributeType: 'BlendFunc',
|
||||
/**
|
||||
Create an instance of this StateAttribute
|
||||
*/
|
||||
cloneType: function () /**BlendFunc*/ {
|
||||
return new BlendFunc();
|
||||
},
|
||||
setSource: function ( f ) {
|
||||
this.setSourceRGB( f );
|
||||
this.setSourceAlpha( f );
|
||||
},
|
||||
getSource: function () {
|
||||
return this._sourceFactor;
|
||||
},
|
||||
setDestination: function ( f ) {
|
||||
this.setDestinationRGB( f );
|
||||
this.setDestinationAlpha( f );
|
||||
},
|
||||
getDestination: function () {
|
||||
return this._destinationFactor;
|
||||
},
|
||||
getSeparate: function () {
|
||||
return this._separate;
|
||||
},
|
||||
checkSeparate: function () {
|
||||
return ( this._sourceFactor !== this._sourceFactorAlpha ||
|
||||
this._destinationFactor !== this._destinationFactorAlpha );
|
||||
},
|
||||
setSourceRGB: function ( f ) {
|
||||
if ( typeof f === 'string' ) {
|
||||
this._sourceFactor = BlendFunc[ f ];
|
||||
} else {
|
||||
this._sourceFactor = f;
|
||||
}
|
||||
this._separate = this.checkSeparate();
|
||||
},
|
||||
getSourceRGB: function () {
|
||||
return this._sourceFactor;
|
||||
},
|
||||
setSourceAlpha: function ( f ) {
|
||||
if ( typeof f === 'string' ) {
|
||||
this._sourceFactorAlpha = BlendFunc[ f ];
|
||||
} else {
|
||||
this._sourceFactorAlpha = f;
|
||||
}
|
||||
this._separate = this.checkSeparate();
|
||||
},
|
||||
getSourceAlpha: function () {
|
||||
return this._sourceFactorAlpha;
|
||||
},
|
||||
setDestinationRGB: function ( f ) {
|
||||
if ( typeof f === 'string' ) {
|
||||
this._destinationFactor = BlendFunc[ f ];
|
||||
} else {
|
||||
this._destinationFactor = f;
|
||||
}
|
||||
this._separate = this.checkSeparate();
|
||||
},
|
||||
getDestinationRGB: function () {
|
||||
return this._destinationFactor;
|
||||
},
|
||||
setDestinationAlpha: function ( f ) {
|
||||
if ( typeof f === 'string' ) {
|
||||
this._destinationFactorAlpha = BlendFunc[ f ];
|
||||
} else {
|
||||
this._destinationFactorAlpha = f;
|
||||
}
|
||||
this._separate = this.checkSeparate();
|
||||
},
|
||||
getDestinationAlpha: function () {
|
||||
return this._destinationFactorAlpha;
|
||||
},
|
||||
|
||||
/**
|
||||
Apply the mode, must be called in the draw traversal
|
||||
@param state
|
||||
*/
|
||||
apply: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
if ( this._sourceFactor === BlendFunc.DISABLE || this._destinationFactor === BlendFunc.DISABLE ) {
|
||||
gl.disable( gl.BLEND );
|
||||
} else {
|
||||
gl.enable( gl.BLEND );
|
||||
if ( this._separate ) {
|
||||
gl.blendFuncSeparate( this._sourceFactor, this._destinationFactor,
|
||||
this._sourceFactorAlpha, this._destinationFactorAlpha );
|
||||
} else {
|
||||
gl.blendFunc( this._sourceFactor, this._destinationFactor );
|
||||
}
|
||||
}
|
||||
}
|
||||
} ), 'osg', 'BlendFunc' );
|
||||
|
||||
module.exports = BlendFunc;
|
|
@ -1,228 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
|
||||
|
||||
var BoundingBox = function () {
|
||||
this._min = vec3.create();
|
||||
this._max = vec3.create();
|
||||
this.init();
|
||||
};
|
||||
BoundingBox.prototype = MACROUTILS.objectLibraryClass( {
|
||||
|
||||
init: function () {
|
||||
vec3.copy( this._min, vec3.INFINITY );
|
||||
vec3.copy( this._max, vec3.NEGATIVE_INFINITY );
|
||||
},
|
||||
|
||||
copy: function ( bbox ) {
|
||||
var min = this._min;
|
||||
var bmin = bbox._min;
|
||||
min[ 0 ] = bmin[ 0 ];
|
||||
min[ 1 ] = bmin[ 1 ];
|
||||
min[ 2 ] = bmin[ 2 ];
|
||||
|
||||
var max = this._max;
|
||||
var bmax = bbox._max;
|
||||
max[ 0 ] = bmax[ 0 ];
|
||||
max[ 1 ] = bmax[ 1 ];
|
||||
max[ 2 ] = bmax[ 2 ];
|
||||
},
|
||||
|
||||
valid: function () {
|
||||
return ( this._max[ 0 ] >= this._min[ 0 ] && this._max[ 1 ] >= this._min[ 1 ] && this._max[ 2 ] >= this._min[ 2 ] );
|
||||
},
|
||||
|
||||
expandByBoundingSphere: function ( bs ) {
|
||||
if ( !bs.valid() ) {
|
||||
return;
|
||||
}
|
||||
var max = this._max;
|
||||
var min = this._min;
|
||||
var radius = bs._radius;
|
||||
var x = bs._center[ 0 ];
|
||||
var y = bs._center[ 1 ];
|
||||
var z = bs._center[ 2 ];
|
||||
min[ 0 ] = Math.min( min[ 0 ], x - radius );
|
||||
min[ 1 ] = Math.min( min[ 1 ], y - radius );
|
||||
min[ 2 ] = Math.min( min[ 2 ], z - radius );
|
||||
|
||||
max[ 0 ] = Math.max( max[ 0 ], x + radius );
|
||||
max[ 1 ] = Math.max( max[ 1 ], y + radius );
|
||||
max[ 2 ] = Math.max( max[ 2 ], z + radius );
|
||||
},
|
||||
|
||||
expandBySphere: function ( bs ) {
|
||||
Notify.log( 'BoundingBox.expandBySphere is deprecated, use instead BoundBox.expandByBoundingSphere' );
|
||||
return this.expandByBoundingSphere( bs );
|
||||
},
|
||||
|
||||
expandByvec3: function ( v ) {
|
||||
var min = this._min;
|
||||
var max = this._max;
|
||||
min[ 0 ] = Math.min( min[ 0 ], v[ 0 ] );
|
||||
min[ 1 ] = Math.min( min[ 1 ], v[ 1 ] );
|
||||
min[ 2 ] = Math.min( min[ 2 ], v[ 2 ] );
|
||||
|
||||
max[ 0 ] = Math.max( max[ 0 ], v[ 0 ] );
|
||||
max[ 1 ] = Math.max( max[ 1 ], v[ 1 ] );
|
||||
max[ 2 ] = Math.max( max[ 2 ], v[ 2 ] );
|
||||
},
|
||||
|
||||
expandByBoundingBox: function ( bb ) {
|
||||
if ( !bb.valid() )
|
||||
return;
|
||||
|
||||
var min = this._min;
|
||||
var max = this._max;
|
||||
var bbmin = bb._min;
|
||||
var bbmax = bb._max;
|
||||
|
||||
if ( bbmin[ 0 ] < min[ 0 ] ) min[ 0 ] = bbmin[ 0 ];
|
||||
if ( bbmax[ 0 ] > max[ 0 ] ) max[ 0 ] = bbmax[ 0 ];
|
||||
|
||||
if ( bbmin[ 1 ] < min[ 1 ] ) min[ 1 ] = bbmin[ 1 ];
|
||||
if ( bbmax[ 1 ] > max[ 1 ] ) max[ 1 ] = bbmax[ 1 ];
|
||||
|
||||
if ( bbmin[ 2 ] < min[ 2 ] ) min[ 2 ] = bbmin[ 2 ];
|
||||
if ( bbmax[ 2 ] > max[ 2 ] ) max[ 2 ] = bbmax[ 2 ];
|
||||
},
|
||||
|
||||
center: function ( result ) {
|
||||
var min = this._min;
|
||||
var max = this._max;
|
||||
result[ 0 ] = ( min[ 0 ] + max[ 0 ] ) * 0.5;
|
||||
result[ 1 ] = ( min[ 1 ] + max[ 1 ] ) * 0.5;
|
||||
result[ 2 ] = ( min[ 2 ] + max[ 2 ] ) * 0.5;
|
||||
return result;
|
||||
},
|
||||
|
||||
radius: function () {
|
||||
return Math.sqrt( this.radius2() );
|
||||
},
|
||||
|
||||
radius2: function () {
|
||||
var min = this._min;
|
||||
var max = this._max;
|
||||
var dx = max[ 0 ] - min[ 0 ];
|
||||
var dy = max[ 1 ] - min[ 1 ];
|
||||
var dz = max[ 2 ] - min[ 2 ];
|
||||
return 0.25 * ( dx * dx + dy * dy + dz * dz );
|
||||
},
|
||||
|
||||
getMin: function () {
|
||||
return this._min;
|
||||
},
|
||||
|
||||
getMax: function () {
|
||||
return this._max;
|
||||
},
|
||||
|
||||
setMin: function ( min ) {
|
||||
vec3.copy( this._min, min );
|
||||
return this;
|
||||
},
|
||||
|
||||
setMax: function ( max ) {
|
||||
vec3.copy( this._max, max );
|
||||
return this;
|
||||
},
|
||||
|
||||
xMax: function () {
|
||||
return this._max[ 0 ];
|
||||
},
|
||||
|
||||
yMax: function () {
|
||||
return this._max[ 1 ];
|
||||
},
|
||||
|
||||
zMax: function () {
|
||||
return this._max[ 2 ];
|
||||
},
|
||||
|
||||
xMin: function () {
|
||||
return this._min[ 0 ];
|
||||
},
|
||||
|
||||
yMin: function () {
|
||||
return this._min[ 1 ];
|
||||
},
|
||||
|
||||
zMin: function () {
|
||||
return this._min[ 2 ];
|
||||
},
|
||||
|
||||
corner: function ( pos, ret ) {
|
||||
/*jshint bitwise: false */
|
||||
if ( pos & 1 ) {
|
||||
ret[ 0 ] = this._max[ 0 ];
|
||||
} else {
|
||||
ret[ 0 ] = this._min[ 0 ];
|
||||
}
|
||||
if ( pos & 2 ) {
|
||||
ret[ 1 ] = this._max[ 1 ];
|
||||
} else {
|
||||
ret[ 1 ] = this._min[ 1 ];
|
||||
}
|
||||
if ( pos & 4 ) {
|
||||
ret[ 2 ] = this._max[ 2 ];
|
||||
} else {
|
||||
ret[ 2 ] = this._min[ 2 ];
|
||||
}
|
||||
return ret;
|
||||
/*jshint bitwise: true */
|
||||
},
|
||||
|
||||
// http://dev.theomader.com/transform-bounding-boxes/
|
||||
// https://github.com/erich666/GraphicsGems/blob/master/gems/TransBox.c
|
||||
transformMat4: ( function () {
|
||||
var tmpMin = vec3.create();
|
||||
var tmpMax = vec3.create();
|
||||
return function ( out, m ) {
|
||||
|
||||
var inMin = this.getMin();
|
||||
var inMax = this.getMax();
|
||||
|
||||
/* Take care of translation by beginning at T. */
|
||||
mat4.getTranslation( tmpMin, m );
|
||||
vec3.copy( tmpMax, tmpMin );
|
||||
|
||||
/* Now find the extreme points by considering the product of the */
|
||||
/* min and max with each component of M. */
|
||||
for ( var i = 0; i < 3; ++i ) {
|
||||
var i4 = i * 4;
|
||||
var mini = inMin[ i ];
|
||||
var maxi = inMax[ i ];
|
||||
for ( var j = 0; j < 3; ++j ) {
|
||||
var cm = m[ i4 + j ];
|
||||
var a = cm * maxi;
|
||||
var b = cm * mini;
|
||||
if ( a < b ) {
|
||||
tmpMin[ j ] += a;
|
||||
tmpMax[ j ] += b;
|
||||
} else {
|
||||
tmpMin[ j ] += b;
|
||||
tmpMax[ j ] += a;
|
||||
}
|
||||
}
|
||||
}
|
||||
var outMax = out.getMax();
|
||||
var outMin = out.getMin();
|
||||
|
||||
outMax[ 0 ] = tmpMax[ 0 ];
|
||||
outMax[ 1 ] = tmpMax[ 1 ];
|
||||
outMax[ 2 ] = tmpMax[ 2 ];
|
||||
|
||||
outMin[ 0 ] = tmpMin[ 0 ];
|
||||
outMin[ 1 ] = tmpMin[ 1 ];
|
||||
outMin[ 2 ] = tmpMin[ 2 ];
|
||||
|
||||
return out;
|
||||
};
|
||||
} )()
|
||||
|
||||
}, 'osg', 'BoundingBox' );
|
||||
|
||||
module.exports = BoundingBox;
|
|
@ -1,195 +0,0 @@
|
|||
'use strict';
|
||||
var BoundingBox = require( 'osg/BoundingBox' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
|
||||
|
||||
var BoundingSphere = function () {
|
||||
this._center = vec3.create();
|
||||
this._radius = -1.0;
|
||||
};
|
||||
|
||||
BoundingSphere.prototype = {
|
||||
init: function () {
|
||||
vec3.init( this._center );
|
||||
this._radius = -1.0;
|
||||
},
|
||||
valid: function () {
|
||||
return this._radius >= 0.0;
|
||||
},
|
||||
set: function ( center, radius ) {
|
||||
this._center = center;
|
||||
this._radius = radius;
|
||||
},
|
||||
center: function () {
|
||||
return this._center;
|
||||
},
|
||||
radius: function () {
|
||||
return this._radius;
|
||||
},
|
||||
radius2: function () {
|
||||
return this._radius * this._radius;
|
||||
},
|
||||
|
||||
expandByBoundingBox: ( function () {
|
||||
var v = vec3.create();
|
||||
var newbb = new BoundingBox();
|
||||
|
||||
return function ( bb ) {
|
||||
if ( !bb.valid() )
|
||||
return;
|
||||
|
||||
if ( this.valid() ) {
|
||||
vec3.copy( newbb._min, bb._min );
|
||||
vec3.copy( newbb._max, bb._max );
|
||||
|
||||
for ( var i = 0; i < 8; i++ ) {
|
||||
vec3.sub( v, bb.corner( i, v ), this._center ); // get the direction vector from corner
|
||||
vec3.normalize( v, v ); // normalise it.
|
||||
vec3.scaleAndAdd( v, this._center, v, -this._radius ); // move the vector in the opposite direction distance radius.
|
||||
newbb.expandByvec3( v ); // add it into the new bounding box.
|
||||
}
|
||||
|
||||
newbb.center( this._center );
|
||||
this._radius = newbb.radius();
|
||||
} else {
|
||||
bb.center( this._center );
|
||||
this._radius = bb.radius();
|
||||
}
|
||||
};
|
||||
} )(),
|
||||
|
||||
expandByBox: function ( bb ) {
|
||||
Notify.log( 'BoundingSphere.expandByBox is deprecated, use instead BoundingSphere.expandByBoundingBox' );
|
||||
return this.expandByBoundingBox( bb );
|
||||
},
|
||||
|
||||
expandByvec3: ( function () {
|
||||
var dv = vec3.create();
|
||||
return function ( v ) {
|
||||
if ( this.valid() ) {
|
||||
vec3.sub( dv, v, this.center( dv ) );
|
||||
var r = vec3.length( dv );
|
||||
if ( r > this.radius() ) {
|
||||
var dr = ( r - this.radius() ) * 0.5;
|
||||
this._center[ 0 ] += dv[ 0 ] * ( dr / r );
|
||||
this._center[ 1 ] += dv[ 1 ] * ( dr / r );
|
||||
this._center[ 2 ] += dv[ 2 ] * ( dr / r );
|
||||
this._radius += dr;
|
||||
}
|
||||
} else {
|
||||
this._center[ 0 ] = v[ 0 ];
|
||||
this._center[ 1 ] = v[ 1 ];
|
||||
this._center[ 2 ] = v[ 2 ];
|
||||
this._radius = 0.0;
|
||||
}
|
||||
};
|
||||
} )(),
|
||||
|
||||
expandRadiusBySphere: function ( sh ) {
|
||||
if ( sh.valid() ) {
|
||||
if ( this.valid() ) {
|
||||
var r = vec3.distance( this._center, sh._center ) + sh._radius;
|
||||
if ( r > this._radius ) {
|
||||
this._radius = r;
|
||||
}
|
||||
// else do nothing as vertex is within sphere.
|
||||
} else {
|
||||
vec3.copy( this._center, sh._center );
|
||||
this._radius = sh._radius;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
expandBy: function ( bs ) {
|
||||
Notify.log( 'BoundingSphere.expandBy is deprecated, use instead BoundingSphere.expandByBoundingSphere' );
|
||||
this.expandByBoundingSphere( bs );
|
||||
},
|
||||
|
||||
expandByBoundingSphere: function ( sh ) {
|
||||
// ignore operation if incomming BoundingSphere is invalid.
|
||||
if ( !sh.valid() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This sphere is not set so use the inbound sphere
|
||||
if ( !this.valid() ) {
|
||||
this._center[ 0 ] = sh._center[ 0 ];
|
||||
this._center[ 1 ] = sh._center[ 1 ];
|
||||
this._center[ 2 ] = sh._center[ 2 ];
|
||||
this._radius = sh.radius();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate d == The distance between the sphere centers
|
||||
var d = vec3.distance( sh.center(), this.center() );
|
||||
|
||||
// New sphere is already inside this one
|
||||
if ( d + sh.radius() <= this.radius() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// New sphere completely contains this one
|
||||
if ( d + this.radius() <= sh.radius() ) {
|
||||
this._center[ 0 ] = sh._center[ 0 ];
|
||||
this._center[ 1 ] = sh._center[ 1 ];
|
||||
this._center[ 2 ] = sh._center[ 2 ];
|
||||
this._radius = sh._radius;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Build a new sphere that completely contains the other two:
|
||||
//
|
||||
// The center point lies halfway along the line between the furthest
|
||||
// points on the edges of the two spheres.
|
||||
//
|
||||
// Computing those two points is ugly - so we'll use similar triangles
|
||||
var newRadius = ( this.radius() + d + sh.radius() ) * 0.5;
|
||||
var ratio = ( newRadius - this.radius() ) / d;
|
||||
|
||||
this._center[ 0 ] += ( sh._center[ 0 ] - this._center[ 0 ] ) * ratio;
|
||||
this._center[ 1 ] += ( sh._center[ 1 ] - this._center[ 1 ] ) * ratio;
|
||||
this._center[ 2 ] += ( sh._center[ 2 ] - this._center[ 2 ] ) * ratio;
|
||||
|
||||
this._radius = newRadius;
|
||||
},
|
||||
contains: function ( v ) {
|
||||
if ( !this.valid() )
|
||||
return false;
|
||||
return vec3.sqrDist( this.center(), v ) <= this.radius2();
|
||||
},
|
||||
intersects: function ( bs ) {
|
||||
if ( !this.valid() || !bs.valid() )
|
||||
return false;
|
||||
var r = this.radius() + bs.radius();
|
||||
return vec3.sqrDist( bs.center(), this.center() ) <= r * r;
|
||||
},
|
||||
|
||||
transformMat4: ( function () {
|
||||
var scaleVec = vec3.create();
|
||||
return function ( out, matrix ) {
|
||||
if ( !this.valid() ) return out;
|
||||
|
||||
if ( out._center !== this._center ) {
|
||||
vec3.copy( out._center, this._center );
|
||||
out._radius = this._radius;
|
||||
}
|
||||
var sphCenter = out._center;
|
||||
var sphRadius = out._radius;
|
||||
|
||||
mat4.getSqrScale( scaleVec, matrix );
|
||||
var scale = Math.sqrt( Math.max( Math.max( scaleVec[ 0 ], scaleVec[ 1 ] ), scaleVec[ 2 ] ) );
|
||||
sphRadius = sphRadius * scale;
|
||||
out._radius = sphRadius;
|
||||
vec3.transformMat4( sphCenter, sphCenter, matrix );
|
||||
|
||||
return out;
|
||||
};
|
||||
} )()
|
||||
|
||||
};
|
||||
|
||||
module.exports = BoundingSphere;
|
|
@ -1,179 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var Object = require( 'osg/Object' );
|
||||
var GLObject = require( 'osg/GLObject' );
|
||||
var Timer = require( 'osg/Timer' );
|
||||
|
||||
|
||||
var getAttributeType = function ( array ) {
|
||||
var type;
|
||||
|
||||
if ( array instanceof MACROUTILS.Float32Array ) type = 0x1406;
|
||||
if ( array instanceof MACROUTILS.Uint32Array ) type = 0x1405;
|
||||
if ( array instanceof MACROUTILS.Uint16Array ) type = 0x1403;
|
||||
if ( array instanceof MACROUTILS.Uint8Array ) type = 0x1401;
|
||||
|
||||
return type;
|
||||
};
|
||||
|
||||
/**
|
||||
* BufferArray manage vertex / normal / ... array used by webgl.
|
||||
* osgjs automatically converts array buffers to Float32Array and
|
||||
* element array buffers to Uint16Array if not said explicitly with
|
||||
* preserveArrayType variable in constructor.
|
||||
* @class BufferArray
|
||||
*/
|
||||
|
||||
var BufferArray = function ( target, elements, itemSize, preserveArrayType ) {
|
||||
|
||||
GLObject.call( this );
|
||||
// maybe could inherit from Object
|
||||
this._instanceID = Object.getInstanceID();
|
||||
|
||||
this.dirty();
|
||||
|
||||
this._itemSize = itemSize;
|
||||
this._target = typeof target === 'string' ? BufferArray[ target ] : target;
|
||||
|
||||
// initialized by setElements
|
||||
this._type = undefined;
|
||||
this._normalize = false;
|
||||
|
||||
if ( elements !== undefined ) {
|
||||
var typedArray = elements;
|
||||
if ( !preserveArrayType ) {
|
||||
if ( this._target === BufferArray.ELEMENT_ARRAY_BUFFER ) {
|
||||
typedArray = elements instanceof MACROUTILS.Uint16Array ? elements : new MACROUTILS.Uint16Array( elements );
|
||||
} else {
|
||||
typedArray = elements instanceof MACROUTILS.Float32Array ? elements : new MACROUTILS.Float32Array( elements );
|
||||
}
|
||||
}
|
||||
this.setElements( typedArray );
|
||||
}
|
||||
};
|
||||
|
||||
BufferArray.ELEMENT_ARRAY_BUFFER = 0x8893;
|
||||
BufferArray.ARRAY_BUFFER = 0x8892;
|
||||
|
||||
// static cache of glBuffers flagged for deletion, which will actually
|
||||
// be deleted in the correct GL context.
|
||||
BufferArray._sDeletedGLBufferArrayCache = new window.Map();
|
||||
|
||||
// static method to delete Program
|
||||
BufferArray.deleteGLBufferArray = function ( gl, buffer ) {
|
||||
if ( !BufferArray._sDeletedGLBufferArrayCache.has( gl ) )
|
||||
BufferArray._sDeletedGLBufferArrayCache.set( gl, [] );
|
||||
BufferArray._sDeletedGLBufferArrayCache.get( gl ).push( buffer );
|
||||
};
|
||||
|
||||
// static method to flush all the cached glPrograms which need to be deleted in the GL context specified
|
||||
BufferArray.flushDeletedGLBufferArrays = function ( gl, availableTime ) {
|
||||
// if no time available don't try to flush objects.
|
||||
if ( availableTime <= 0.0 ) return availableTime;
|
||||
if ( !BufferArray._sDeletedGLBufferArrayCache.has( gl ) ) return availableTime;
|
||||
var elapsedTime = 0.0;
|
||||
var beginTime = Timer.instance().tick();
|
||||
var deleteList = BufferArray._sDeletedGLBufferArrayCache.get( gl );
|
||||
var numBuffers = deleteList.length;
|
||||
for ( var i = numBuffers - 1; i >= 0 && elapsedTime < availableTime; i-- ) {
|
||||
gl.deleteBuffer( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
elapsedTime = Timer.instance().deltaS( beginTime, Timer.instance().tick() );
|
||||
}
|
||||
return availableTime - elapsedTime;
|
||||
};
|
||||
|
||||
BufferArray.flushAllDeletedGLBufferArrays = function ( gl ) {
|
||||
if ( !BufferArray._sDeletedGLBufferArrayCache.has( gl ) ) return;
|
||||
var deleteList = BufferArray._sDeletedGLBufferArrayCache.get( gl );
|
||||
var numBuffers = deleteList.length;
|
||||
for ( var i = numBuffers - 1; i >= 0; i-- ) {
|
||||
gl.deleteBuffer( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
}
|
||||
};
|
||||
|
||||
/** @lends BufferArray.prototype */
|
||||
BufferArray.prototype = MACROUTILS.objectInherit( GLObject.prototype, {
|
||||
getInstanceID: function () {
|
||||
return this._instanceID;
|
||||
},
|
||||
setItemSize: function ( size ) {
|
||||
this._itemSize = size;
|
||||
},
|
||||
isValid: function () {
|
||||
if ( this._buffer !== undefined ||
|
||||
this._elements !== undefined ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
releaseGLObjects: function () {
|
||||
if ( this._buffer !== undefined && this._buffer !== null && this._gl !== undefined ) {
|
||||
BufferArray.deleteGLBufferArray( this._gl, this._buffer );
|
||||
}
|
||||
this._buffer = undefined;
|
||||
},
|
||||
|
||||
setNormalize: function ( normalize ) {
|
||||
this._normalize = normalize;
|
||||
},
|
||||
|
||||
getNormalize: function () {
|
||||
return this._normalize;
|
||||
},
|
||||
|
||||
bind: function ( gl ) {
|
||||
if ( !this._gl ) this.setGraphicContext( gl );
|
||||
var target = this._target;
|
||||
var buffer = this._buffer;
|
||||
|
||||
if ( buffer ) {
|
||||
gl.bindBuffer( target, buffer );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !buffer && this._elements.length > 0 ) {
|
||||
this._buffer = gl.createBuffer();
|
||||
this._numItems = this._elements.length / this._itemSize;
|
||||
gl.bindBuffer( target, this._buffer );
|
||||
}
|
||||
},
|
||||
getItemSize: function () {
|
||||
return this._itemSize;
|
||||
},
|
||||
dirty: function () {
|
||||
this._dirty = true;
|
||||
},
|
||||
isDirty: function () {
|
||||
return this._dirty;
|
||||
},
|
||||
compile: function ( gl ) {
|
||||
if ( this._dirty ) {
|
||||
MACROUTILS.timeStamp( 'osgjs.metrics:bufferData' );
|
||||
gl.bufferData( this._target, this._elements, gl.STATIC_DRAW );
|
||||
this._dirty = false;
|
||||
}
|
||||
},
|
||||
getElements: function () {
|
||||
return this._elements;
|
||||
},
|
||||
setElements: function ( elements ) {
|
||||
this._elements = elements;
|
||||
this._type = getAttributeType( elements );
|
||||
this._dirty = true;
|
||||
},
|
||||
getType: function () {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
BufferArray.create = function ( type, elements, itemSize ) {
|
||||
Notify.log( 'BufferArray.create is deprecated, use new BufferArray with same arguments instead' );
|
||||
return new BufferArray( type, elements, itemSize );
|
||||
};
|
||||
|
||||
module.exports = BufferArray;
|
|
@ -1,40 +0,0 @@
|
|||
'use strict';
|
||||
var BufferArray = require( 'osg/BufferArray' );
|
||||
|
||||
|
||||
var BufferArrayProxy = function ( bufferArray ) {
|
||||
|
||||
this._initialBufferArray = undefined;
|
||||
this._bufferArray = undefined;
|
||||
if ( bufferArray ) {
|
||||
this.setBufferArray( bufferArray );
|
||||
this.setInitialBufferArray( bufferArray );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var prototype = {
|
||||
setInitialBufferArray: function ( bufferArray ) {
|
||||
this._initialBufferArray = bufferArray;
|
||||
},
|
||||
getInitialBufferArray: function () {
|
||||
return this._initialBufferArray;
|
||||
},
|
||||
setBufferArray: function ( bufferArray ) {
|
||||
this._bufferArray = bufferArray.getBufferArray ? bufferArray.getBufferArray() : bufferArray;
|
||||
},
|
||||
getBufferArray: function () {
|
||||
return this._bufferArray;
|
||||
}
|
||||
};
|
||||
|
||||
// adds original method of BufferArray prototype for the proxy for convenient usage
|
||||
var keys = window.Object.keys( BufferArray.prototype );
|
||||
keys.forEach( function ( methodName ) {
|
||||
prototype[ methodName ] = function () {
|
||||
return BufferArray.prototype[ methodName ].apply( this._bufferArray, arguments );
|
||||
};
|
||||
} );
|
||||
|
||||
BufferArrayProxy.prototype = prototype;
|
||||
module.exports = BufferArrayProxy;
|
|
@ -1,252 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Transform = require( 'osg/Transform' );
|
||||
var CullSettings = require( 'osg/CullSettings' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var Texture = require( 'osg/Texture' );
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
var vec4 = require( 'osg/glMatrix' ).vec4;
|
||||
|
||||
|
||||
/**
|
||||
* Camera - is a subclass of Transform which represents encapsulates the settings of a Camera.
|
||||
* @class Camera
|
||||
* @inherits Transform CullSettings
|
||||
*/
|
||||
var Camera = function () {
|
||||
Transform.call( this );
|
||||
CullSettings.call( this );
|
||||
|
||||
this.viewport = undefined;
|
||||
this._graphicContext = undefined;
|
||||
this.setClearColor( vec4.fromValues( 0, 0, 0, 1.0 ) );
|
||||
this.setClearDepth( 1.0 );
|
||||
|
||||
/*jshint bitwise: false */
|
||||
this.setClearMask( Camera.COLOR_BUFFER_BIT | Camera.DEPTH_BUFFER_BIT );
|
||||
/*jshint bitwise: true */
|
||||
|
||||
this.setViewMatrix( mat4.create() );
|
||||
this.setProjectionMatrix( mat4.create() );
|
||||
this.renderOrder = Camera.NESTED_RENDER;
|
||||
this.renderOrderNum = 0;
|
||||
|
||||
this._view = undefined;
|
||||
this._renderer = undefined;
|
||||
this._attachments = {};
|
||||
};
|
||||
|
||||
Camera.PRE_RENDER = 0;
|
||||
Camera.NESTED_RENDER = 1;
|
||||
Camera.POST_RENDER = 2;
|
||||
|
||||
Camera.COLOR_BUFFER_BIT = 0x00004000;
|
||||
Camera.DEPTH_BUFFER_BIT = 0x00000100;
|
||||
Camera.STENCIL_BUFFER_BIT = 0x00000400;
|
||||
|
||||
/** @lends Camera.prototype */
|
||||
Camera.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit(
|
||||
CullSettings.prototype,
|
||||
MACROUTILS.objectInherit( Transform.prototype, {
|
||||
// at which view this camera is attached
|
||||
getView: function () {
|
||||
return this._view;
|
||||
},
|
||||
|
||||
setView: function ( view ) {
|
||||
this._view = view;
|
||||
},
|
||||
|
||||
getRenderer: function () {
|
||||
return this._renderer;
|
||||
},
|
||||
|
||||
setRenderer: function ( renderer ) {
|
||||
this._renderer = renderer;
|
||||
},
|
||||
|
||||
// Set the final draw callback for custom operations
|
||||
// to be done after the drawing of
|
||||
// the camera's subgraph and pre render stages.
|
||||
setFinalDrawCallback: function ( cb ) {
|
||||
|
||||
this._finalDrawCallback = cb;
|
||||
|
||||
},
|
||||
|
||||
getFinalDrawCallback: function () {
|
||||
|
||||
return this._finalDrawCallback;
|
||||
|
||||
},
|
||||
|
||||
// Set the initial draw callback for custom operations
|
||||
// to be done before the drawing of
|
||||
// the camera's subgraph and pre render stages.
|
||||
setInitialDrawCallback: function ( cb ) {
|
||||
|
||||
this._initialDrawCallback = cb;
|
||||
|
||||
},
|
||||
|
||||
getInitialDrawCallback: function () {
|
||||
|
||||
return this._initialDrawCallback;
|
||||
|
||||
},
|
||||
|
||||
|
||||
getAttachments: function () {
|
||||
return this._attachments;
|
||||
},
|
||||
|
||||
setGraphicContext: function ( gc ) {
|
||||
this._graphicContext = gc;
|
||||
},
|
||||
getGraphicContext: function () {
|
||||
return this._graphicContext;
|
||||
},
|
||||
setClearDepth: function ( depth ) {
|
||||
this.clearDepth = depth;
|
||||
},
|
||||
getClearDepth: function () {
|
||||
return this.clearDepth;
|
||||
},
|
||||
|
||||
setClearMask: function ( mask ) {
|
||||
this.clearMask = mask;
|
||||
},
|
||||
getClearMask: function () {
|
||||
return this.clearMask;
|
||||
},
|
||||
|
||||
setClearColor: function ( color ) {
|
||||
this.clearColor = color;
|
||||
},
|
||||
getClearColor: function () {
|
||||
return this.clearColor;
|
||||
},
|
||||
|
||||
setViewport: function ( vp ) {
|
||||
this.viewport = vp;
|
||||
this.getOrCreateStateSet().setAttributeAndModes( vp );
|
||||
},
|
||||
getViewport: function () {
|
||||
return this.viewport;
|
||||
},
|
||||
|
||||
|
||||
setViewMatrix: function ( matrix ) {
|
||||
this.modelviewMatrix = matrix;
|
||||
},
|
||||
setViewMatrixAsLookAt: function ( eye, center, up ) {
|
||||
mat4.lookAt( this.getViewMatrix(), eye, center, up );
|
||||
},
|
||||
setProjectionMatrix: function ( matrix ) {
|
||||
this.projectionMatrix = matrix;
|
||||
},
|
||||
|
||||
/** Set to an orthographic projection. See OpenGL glOrtho for documentation further details.*/
|
||||
setProjectionMatrixAsOrtho: function ( left, right,
|
||||
bottom, top,
|
||||
zNear, zFar ) {
|
||||
mat4.ortho( this.getProjectionMatrix(), left, right, bottom, top, zNear, zFar );
|
||||
},
|
||||
isRenderToTextureCamera: function () {
|
||||
return window.Object.keys( this._attachments ).length > 0;
|
||||
},
|
||||
|
||||
getViewMatrix: function () {
|
||||
return this.modelviewMatrix;
|
||||
},
|
||||
getProjectionMatrix: function () {
|
||||
return this.projectionMatrix;
|
||||
},
|
||||
getRenderOrder: function () {
|
||||
return this.renderOrder;
|
||||
},
|
||||
setRenderOrder: function ( order, orderNum ) {
|
||||
this.renderOrder = order;
|
||||
this.renderOrderNum = orderNum;
|
||||
},
|
||||
|
||||
detachAll: function () {
|
||||
this._attachments = {};
|
||||
|
||||
if ( this.frameBufferObject ) {
|
||||
this.frameBufferObject.dirty();
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: fix in case of shared fbo
|
||||
// TODO: fix adding a resize case
|
||||
resetAttachments: function () {
|
||||
|
||||
|
||||
if ( this.frameBufferObject ) {
|
||||
|
||||
this.frameBufferObject.reset();
|
||||
// remove framebuffer
|
||||
this.frameBufferObject = 0;
|
||||
}
|
||||
|
||||
// removes camera attachement
|
||||
this._attachments = {};
|
||||
|
||||
},
|
||||
|
||||
attachTexture: function ( bufferComponent, texture, textureTarget ) {
|
||||
if ( this.frameBufferObject ) {
|
||||
this.frameBufferObject.dirty();
|
||||
}
|
||||
|
||||
// because before the argument was level and the spec says
|
||||
// it must always be 0 ! is valid for 0 or undefined
|
||||
if ( !textureTarget ) {
|
||||
textureTarget = Texture.TEXTURE_2D;
|
||||
}
|
||||
|
||||
this._attachments[ bufferComponent ] = {
|
||||
'attachment': bufferComponent,
|
||||
'texture': texture,
|
||||
'textureTarget': textureTarget
|
||||
};
|
||||
},
|
||||
|
||||
attachRenderBuffer: function ( bufferComponent, internalFormat ) {
|
||||
if ( this.frameBufferObject ) {
|
||||
this.frameBufferObject.dirty();
|
||||
}
|
||||
this._attachments[ bufferComponent ] = {
|
||||
'format': internalFormat,
|
||||
'attachment': bufferComponent
|
||||
};
|
||||
},
|
||||
|
||||
computeLocalToWorldMatrix: function ( matrix /*,nodeVisitor*/ ) {
|
||||
if ( this.referenceFrame === TransformEnums.RELATIVE_RF ) {
|
||||
mat4.mul( matrix, matrix, this.modelviewMatrix );
|
||||
} else { // absolute
|
||||
mat4.copy( matrix, this.modelviewMatrix );
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
computeWorldToLocalMatrix: ( function () {
|
||||
var minverse = mat4.create();
|
||||
return function ( matrix /*, nodeVisitor */ ) {
|
||||
mat4.invert( minverse, this.modelviewMatrix );
|
||||
if ( this.referenceFrame === TransformEnums.RELATIVE_RF ) {
|
||||
mat4.mul( matrix, minverse, matrix );
|
||||
} else {
|
||||
mat4.copy( matrix, minverse );
|
||||
}
|
||||
return true;
|
||||
};
|
||||
} )()
|
||||
|
||||
} ) ), 'osg', 'Camera' );
|
||||
|
||||
MACROUTILS.setTypeID( Camera );
|
||||
|
||||
module.exports = Camera;
|
|
@ -1,44 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
|
||||
|
||||
var ColorMask = function ( red, green, blue, alpha ) {
|
||||
|
||||
StateAttribute.call( this );
|
||||
|
||||
this._colorMask = [ true, true, true, true ];
|
||||
this.setMask( red, green, blue, alpha );
|
||||
};
|
||||
|
||||
ColorMask.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'ColorMask',
|
||||
|
||||
cloneType: function () {
|
||||
return new ColorMask();
|
||||
},
|
||||
|
||||
setMask: function ( red, green, blue, alpha ) {
|
||||
|
||||
if ( red !== undefined &&
|
||||
green !== undefined &&
|
||||
blue !== undefined &&
|
||||
alpha !== undefined ) {
|
||||
|
||||
this._colorMask[ 0 ] = red;
|
||||
this._colorMask[ 1 ] = green;
|
||||
this._colorMask[ 2 ] = blue;
|
||||
this._colorMask[ 3 ] = alpha;
|
||||
}
|
||||
},
|
||||
|
||||
apply: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
var colorMask = this._colorMask;
|
||||
gl.colorMask( colorMask[ 0 ], colorMask[ 1 ], colorMask[ 2 ], colorMask[ 3 ] );
|
||||
}
|
||||
|
||||
} ), 'osg', 'ColorMask' );
|
||||
|
||||
module.exports = ColorMask;
|
|
@ -1,109 +0,0 @@
|
|||
'use strict';
|
||||
var BoundingBox = require( 'osg/BoundingBox' );
|
||||
var Geometry = require( 'osg/Geometry' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var MatrixMemoryPool = require( 'osg/MatrixMemoryPool' );
|
||||
var Transform = require( 'osg/Transform' );
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
|
||||
|
||||
var ComputeBoundsVisitor = function ( traversalMode ) {
|
||||
NodeVisitor.call( this, traversalMode );
|
||||
|
||||
// keep a matrix in memory to avoid to create matrix
|
||||
this._reservedMatrixStack = new MatrixMemoryPool();
|
||||
|
||||
// Matrix stack along path traversal
|
||||
this._matrixStack = [];
|
||||
this._bb = new BoundingBox();
|
||||
};
|
||||
|
||||
ComputeBoundsVisitor.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( NodeVisitor.prototype, {
|
||||
|
||||
reset: function () {
|
||||
this._reservedMatrixStack.reset();
|
||||
this._matrixStack.length = 0;
|
||||
this._bb.init();
|
||||
},
|
||||
|
||||
getBoundingBox: function () {
|
||||
return this._bb;
|
||||
},
|
||||
|
||||
// not implemented
|
||||
//void getPolytope(osg::Polytope& polytope, float margin=0.1) const;
|
||||
//void getBase(osg::Polytope& polytope, float margin=0.1) const;
|
||||
|
||||
//applyDrawable: function ( drawable ) {},
|
||||
|
||||
applyTransform: function ( transform ) {
|
||||
|
||||
var matrix = this._reservedMatrixStack.get();
|
||||
var stackLength = this._matrixStack.length;
|
||||
|
||||
if ( stackLength )
|
||||
mat4.copy( matrix, this._matrixStack[ stackLength - 1 ] );
|
||||
else
|
||||
mat4.identity( matrix );
|
||||
|
||||
transform.computeLocalToWorldMatrix( matrix, this );
|
||||
|
||||
this.pushMatrix( matrix );
|
||||
|
||||
this.traverse( transform );
|
||||
|
||||
this.popMatrix();
|
||||
},
|
||||
|
||||
apply: function ( node ) {
|
||||
|
||||
if ( node instanceof Transform ) {
|
||||
this.applyTransform( node );
|
||||
return;
|
||||
|
||||
} else if ( node instanceof Geometry ) {
|
||||
this.applyBoundingBox( node.getBoundingBox() );
|
||||
return;
|
||||
}
|
||||
|
||||
this.traverse( node );
|
||||
|
||||
},
|
||||
|
||||
pushMatrix: function ( matrix ) {
|
||||
this._matrixStack.push( matrix );
|
||||
},
|
||||
|
||||
popMatrix: function () {
|
||||
this._matrixStack.pop();
|
||||
},
|
||||
|
||||
|
||||
applyBoundingBox: ( function () {
|
||||
var bbOut = new BoundingBox();
|
||||
|
||||
return function ( bbox ) {
|
||||
|
||||
var stackLength = this._matrixStack.length;
|
||||
|
||||
if ( !stackLength )
|
||||
this._bb.expandByBoundingBox( bbox );
|
||||
else if ( bbox.valid() ) {
|
||||
var matrix = this._matrixStack[ stackLength - 1 ];
|
||||
//Matrix.transformBoundingBox( matrix, bbox, bbOut );
|
||||
bbox.transformMat4( bbOut, matrix );
|
||||
this._bb.expandByBoundingBox( bbOut );
|
||||
}
|
||||
|
||||
};
|
||||
} )(),
|
||||
|
||||
getMatrixStack: function () {
|
||||
return this._matrixStack;
|
||||
}
|
||||
|
||||
|
||||
} ), 'osg', 'ComputeBoundsVisitor' );
|
||||
|
||||
module.exports = ComputeBoundsVisitor;
|
|
@ -1,51 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
|
||||
|
||||
/**
|
||||
* Manage CullFace attribute
|
||||
* @class CullFace
|
||||
*/
|
||||
var CullFace = function ( mode ) {
|
||||
StateAttribute.call( this );
|
||||
this.setMode( mode !== undefined ? mode : CullFace.BACK );
|
||||
};
|
||||
|
||||
CullFace.DISABLE = 0x0;
|
||||
CullFace.FRONT = 0x0404;
|
||||
CullFace.BACK = 0x0405;
|
||||
CullFace.FRONT_AND_BACK = 0x0408;
|
||||
|
||||
/** @lends CullFace.prototype */
|
||||
CullFace.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'CullFace',
|
||||
|
||||
cloneType: function () {
|
||||
return new CullFace();
|
||||
},
|
||||
|
||||
setMode: function ( mode ) {
|
||||
var value = mode;
|
||||
if ( typeof value === 'string' ) value = CullFace[ value ];
|
||||
this._mode = value;
|
||||
},
|
||||
|
||||
getMode: function () {
|
||||
return this._mode;
|
||||
},
|
||||
|
||||
apply: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
if ( this._mode === CullFace.DISABLE ) {
|
||||
gl.disable( gl.CULL_FACE );
|
||||
} else {
|
||||
gl.enable( gl.CULL_FACE );
|
||||
gl.cullFace( this._mode );
|
||||
}
|
||||
|
||||
}
|
||||
} ), 'osg', 'CullFace' );
|
||||
|
||||
module.exports = CullFace;
|
|
@ -1,95 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
var CullSettings = function () {
|
||||
|
||||
// Not doing a this.reset()
|
||||
// because of multiple inheritance
|
||||
// it will call the wrong reset
|
||||
// cullstack reset for isntance()
|
||||
CullSettings.prototype.reset.call( this );
|
||||
|
||||
};
|
||||
|
||||
CullSettings.prototype = {
|
||||
reset: function () {
|
||||
|
||||
this._computeNearFar = true;
|
||||
this._nearFarRatio = 0.005;
|
||||
|
||||
// Magic numbers 3 & 4
|
||||
this.bbCornerFar = 3;
|
||||
this.bbCornerNear = 4;
|
||||
// see code below for for the
|
||||
// Code simplification origin
|
||||
// var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
// var lookVector = vec3.fromValues( 0.0, 0.0, -1.0 );
|
||||
// /*jshint bitwise: false */
|
||||
// this.bbCornerFar = ( lookVector[ 0 ] >= 0 ? 1 : 0 ) | ( lookVector[ 1 ] >= 0 ? 2 : 0 ) | ( lookVector[ 2 ] >= 0 ? 4 : 0 );
|
||||
// this.bbCornerNear = ( ~this.bbCornerFar ) & 7;
|
||||
// /*jshint bitwise: true */
|
||||
// is equivalent to
|
||||
|
||||
this._enableFrustumCulling = false;
|
||||
|
||||
// who sets the parameter
|
||||
// if it's cullvisitor
|
||||
// it's an OVERRIDER for enableFrustumCulling
|
||||
// allowing for global EnableFrustimCulling
|
||||
this._settingsSourceOverrider = this;
|
||||
//LOD bias for the CullVisitor to use
|
||||
this._LODScale = 1.0;
|
||||
// Custom clampProjectionMatrix
|
||||
this._clampProjectionMatrixCallback = undefined;
|
||||
},
|
||||
|
||||
setCullSettings: function ( settings ) {
|
||||
this._computeNearFar = settings._computeNearFar;
|
||||
this._nearFarRatio = settings._nearFarRatio;
|
||||
this._enableFrustumCulling = settings._enableFrustumCulling;
|
||||
this._settingsSourceOverrider = settings._settingsSourceOverrider;
|
||||
this._clampProjectionMatrixCallback = settings._clampProjectionMatrixCallback;
|
||||
},
|
||||
|
||||
setNearFarRatio: function ( ratio ) {
|
||||
this._nearFarRatio = ratio;
|
||||
},
|
||||
getNearFarRatio: function () {
|
||||
return this._nearFarRatio;
|
||||
},
|
||||
setComputeNearFar: function ( value ) {
|
||||
this._computeNearFar = value;
|
||||
},
|
||||
getComputeNearFar: function () {
|
||||
return this._computeNearFar;
|
||||
},
|
||||
|
||||
setEnableFrustumCulling: function ( value ) {
|
||||
this._enableFrustumCulling = value;
|
||||
},
|
||||
getEnableFrustumCulling: function () {
|
||||
return this._enableFrustumCulling;
|
||||
},
|
||||
|
||||
getSettingSourceOverrider: function () {
|
||||
return this._settingsSourceOverrider;
|
||||
},
|
||||
|
||||
setClampProjectionMatrixCallback: function ( callback ) {
|
||||
this._clampProjectionMatrixCallback = callback;
|
||||
},
|
||||
|
||||
getClampProjectionMatrixCallback: function () {
|
||||
return this._clampProjectionMatrixCallback;
|
||||
},
|
||||
|
||||
setLODScale: function ( scale ) {
|
||||
this._LODScale = scale;
|
||||
},
|
||||
getLODScale: function () {
|
||||
return this._LODScale;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = CullSettings;
|
|
@ -1,394 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var BoundingSphere = require( 'osg/BoundingSphere' );
|
||||
var Camera = require( 'osg/Camera' );
|
||||
var ComputeMatrixFromNodePath = require( 'osg/computeMatrixFromNodePath' );
|
||||
var CullSettings = require( 'osg/CullSettings' );
|
||||
var CullingSet = require( 'osg/CullingSet' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var Plane = require( 'osg/Plane' );
|
||||
var MatrixMemoryPool = require( 'osg/MatrixMemoryPool' );
|
||||
var Transform = require( 'osg/Transform' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
|
||||
var CullStack = function () {
|
||||
|
||||
this._modelViewMatrixStack = [];
|
||||
this._projectionMatrixStack = [];
|
||||
this._viewportStack = [];
|
||||
this._cullingSetStack = [];
|
||||
this._frustumVolume = -1.0;
|
||||
this._bbCornerFar = 0;
|
||||
this._bbCornerNear = 0;
|
||||
|
||||
// keep a matrix in memory to avoid to create matrix
|
||||
this._reservedMatrixStack = new MatrixMemoryPool();
|
||||
|
||||
this._reserveCullingSetStack = [
|
||||
new CullingSet()
|
||||
];
|
||||
this._reserveCullingSetStack.current = 0;
|
||||
|
||||
|
||||
// data for caching camera matrix inverse for computation of world/view
|
||||
// contains index of the camera node in the nodepath
|
||||
this._cameraIndexStack = [];
|
||||
// contains index of the camera modelview matrix in the modelViewMatrixStack
|
||||
this._cameraModelViewIndexStack = [];
|
||||
|
||||
// contains the id has a key to computed Inverse Matrix
|
||||
this._cameraMatrixInverse = [];
|
||||
this._cameraMatrixInverseRoot = undefined;
|
||||
|
||||
};
|
||||
|
||||
CullStack.prototype = MACROUTILS.objectInherit( CullSettings.prototype, {
|
||||
|
||||
_getReservedCullingSet: function () {
|
||||
var m = this._reserveCullingSetStack[ this._reserveCullingSetStack.current++ ];
|
||||
if ( this._reserveCullingSetStack.current === this._reserveCullingSetStack.length ) {
|
||||
this._reserveCullingSetStack.push( new CullingSet() );
|
||||
}
|
||||
return m;
|
||||
},
|
||||
reset: function () {
|
||||
this._modelViewMatrixStack.length = 0;
|
||||
this._projectionMatrixStack.length = 0;
|
||||
this._cullingSetStack.length = 0;
|
||||
|
||||
this._reservedMatrixStack.reset();
|
||||
this._reserveCullingSetStack.current = 0;
|
||||
|
||||
this._cameraModelViewIndexStack.length = 0;
|
||||
this._cameraIndexStack.length = 0;
|
||||
this._cameraMatrixInverse.length = 0;
|
||||
this._cameraMatrixInverseRoot = undefined;
|
||||
},
|
||||
|
||||
getProjectionMatrixStack: function () {
|
||||
return this._projectionMatrixStack;
|
||||
},
|
||||
getCurrentProjectionMatrix: function () {
|
||||
return this._projectionMatrixStack[ this._projectionMatrixStack.length - 1 ];
|
||||
},
|
||||
|
||||
getCurrentModelViewMatrix: function () {
|
||||
return this._modelViewMatrixStack[ this._modelViewMatrixStack.length - 1 ];
|
||||
},
|
||||
|
||||
getCurrentModelviewMatrix: function () {
|
||||
Notify.warn( 'deprecated switch to getCurrentModelViewMatrix' );
|
||||
return this.getCurrentModelViewMatrix();
|
||||
},
|
||||
|
||||
getCameraInverseMatrix: function () {
|
||||
|
||||
// Return or compute and cache the MatrixInverse of the last
|
||||
// active camera in absolute reference
|
||||
|
||||
// if no index the camera inverse is the root with an fake id
|
||||
if ( !this._cameraIndexStack.length )
|
||||
return this._cameraMatrixInverseRoot;
|
||||
|
||||
var idx = this._cameraIndexStack[ this._cameraIndexStack.length - 1 ];
|
||||
|
||||
// get the camera node
|
||||
var camera = this.getNodePath()[ idx ];
|
||||
var id = camera.getInstanceID();
|
||||
|
||||
if ( this._cameraMatrixInverse[ id ] === undefined ) {
|
||||
var indexInModelViewMatrixStack = this._cameraModelViewIndexStack[ this._cameraModelViewIndexStack.length - 1 ];
|
||||
var mat = this._modelViewMatrixStack[ indexInModelViewMatrixStack ];
|
||||
var matInverse = this._reservedMatrixStack.get();
|
||||
mat4.invert( matInverse, mat );
|
||||
this._cameraMatrixInverse[ id ] = matInverse;
|
||||
}
|
||||
return this._cameraMatrixInverse[ id ];
|
||||
},
|
||||
|
||||
getCurrentModelMatrix: function () {
|
||||
// Improvment could be to cache more things
|
||||
// and / or use this method only if the shader use it
|
||||
var invMatrix = this.getCameraInverseMatrix();
|
||||
var m = this._reservedMatrixStack.get();
|
||||
var world = mat4.mul( m, invMatrix, this.getCurrentModelViewMatrix() );
|
||||
return world;
|
||||
},
|
||||
|
||||
getCurrentViewMatrix: function () {
|
||||
// Improvment could be to cache more things
|
||||
// and / or use this method only if the shader use it
|
||||
if ( !this._cameraIndexStack.length )
|
||||
return this._modelViewMatrixStack[ 0 ];
|
||||
|
||||
// also we could keep the index of the current to avoid lenght-1 at each access
|
||||
// it's implemented in osg like that:
|
||||
// https://github.com/openscenegraph/osg/blob/master/include/osg/fast_back_stack
|
||||
var idx = this._cameraModelViewIndexStack[ this._cameraModelViewIndexStack.length - 1 ];
|
||||
return this._modelViewMatrixStack[ idx ];
|
||||
},
|
||||
|
||||
getViewport: function () {
|
||||
if ( this._viewportStack.length === 0 ) {
|
||||
return undefined;
|
||||
}
|
||||
return this._viewportStack[ this._viewportStack.length - 1 ];
|
||||
},
|
||||
getLookVectorLocal: function ( outLookVector ) {
|
||||
var lookVectorLocal = this.getCurrentModelViewMatrix();
|
||||
return vec3.set( outLookVector, -lookVectorLocal[ 2 ], -lookVectorLocal[ 6 ], -lookVectorLocal[ 10 ] );
|
||||
},
|
||||
pushViewport: function ( vp ) {
|
||||
this._viewportStack.push( vp );
|
||||
},
|
||||
popViewport: function () {
|
||||
this._viewportStack.pop();
|
||||
},
|
||||
|
||||
getFrustumPlanes: ( function () {
|
||||
|
||||
var mvp = mat4.create();
|
||||
|
||||
return function ( out, projection, view, withNearFar ) {
|
||||
mat4.mul( mvp, projection, view );
|
||||
|
||||
var computeNearFar = !!withNearFar;
|
||||
|
||||
// Right clipping plane.
|
||||
var right = out[ 0 ];
|
||||
right[ 0 ] = mvp[ 3 ] - mvp[ 0 ];
|
||||
right[ 1 ] = mvp[ 7 ] - mvp[ 4 ];
|
||||
right[ 2 ] = mvp[ 11 ] - mvp[ 8 ];
|
||||
right[ 3 ] = mvp[ 15 ] - mvp[ 12 ];
|
||||
|
||||
// Left clipping plane.
|
||||
var left = out[ 1 ];
|
||||
left[ 0 ] = mvp[ 3 ] + mvp[ 0 ];
|
||||
left[ 1 ] = mvp[ 7 ] + mvp[ 4 ];
|
||||
left[ 2 ] = mvp[ 11 ] + mvp[ 8 ];
|
||||
left[ 3 ] = mvp[ 15 ] + mvp[ 12 ];
|
||||
|
||||
// Bottom clipping plane.
|
||||
var bottom = out[ 2 ];
|
||||
bottom[ 0 ] = mvp[ 3 ] + mvp[ 1 ];
|
||||
bottom[ 1 ] = mvp[ 7 ] + mvp[ 5 ];
|
||||
bottom[ 2 ] = mvp[ 11 ] + mvp[ 9 ];
|
||||
bottom[ 3 ] = mvp[ 15 ] + mvp[ 13 ];
|
||||
|
||||
// Top clipping plane.
|
||||
var top = out[ 3 ];
|
||||
top[ 0 ] = mvp[ 3 ] - mvp[ 1 ];
|
||||
top[ 1 ] = mvp[ 7 ] - mvp[ 5 ];
|
||||
top[ 2 ] = mvp[ 11 ] - mvp[ 9 ];
|
||||
top[ 3 ] = mvp[ 15 ] - mvp[ 13 ];
|
||||
|
||||
if ( computeNearFar ) {
|
||||
// Far clipping plane.
|
||||
var far = out[ 4 ];
|
||||
far[ 0 ] = mvp[ 3 ] - mvp[ 2 ];
|
||||
far[ 1 ] = mvp[ 7 ] - mvp[ 6 ];
|
||||
far[ 2 ] = mvp[ 11 ] - mvp[ 10 ];
|
||||
far[ 3 ] = mvp[ 15 ] - mvp[ 14 ];
|
||||
|
||||
// Near clipping plane.
|
||||
var near = out[ 5 ];
|
||||
near[ 0 ] = mvp[ 3 ] + mvp[ 2 ];
|
||||
near[ 1 ] = mvp[ 7 ] + mvp[ 6 ];
|
||||
near[ 2 ] = mvp[ 11 ] + mvp[ 10 ];
|
||||
near[ 3 ] = mvp[ 15 ] + mvp[ 14 ];
|
||||
}
|
||||
|
||||
//Normalize the planes
|
||||
var j = withNearFar ? 6 : 4;
|
||||
for ( var i = 0; i < j; i++ ) {
|
||||
Plane.normalizeEquation( out[ i ] );
|
||||
}
|
||||
|
||||
};
|
||||
} )(),
|
||||
|
||||
pushCullingSet: function () {
|
||||
var cs = this._getReservedCullingSet();
|
||||
if ( this._enableFrustumCulling ) {
|
||||
mat4.getFrustumPlanes( cs.getFrustum().getPlanes(), this.getCurrentProjectionMatrix(), this.getCurrentModelViewMatrix(), false );
|
||||
// TODO: no far no near.
|
||||
// should check if we have them
|
||||
// should add at least a near 0 clip if not
|
||||
cs.getFrustum().setupMask( 4 );
|
||||
}
|
||||
|
||||
this._cullingSetStack.push( cs );
|
||||
},
|
||||
popCullingSet: function () {
|
||||
return this._cullingSetStack.pop();
|
||||
},
|
||||
getCurrentCullingSet: function () {
|
||||
return this._cullingSetStack[ this._cullingSetStack.length - 1 ];
|
||||
},
|
||||
|
||||
|
||||
pushCurrentMask: function () {
|
||||
var cs = this.getCurrentCullingSet();
|
||||
if ( cs ) cs.pushCurrentMask();
|
||||
},
|
||||
popCurrentMask: function () {
|
||||
var cs = this.getCurrentCullingSet();
|
||||
if ( cs ) cs.popCurrentMask();
|
||||
},
|
||||
|
||||
isVerticesCulled: function ( vertices ) {
|
||||
if ( !this._enableFrustumCulling )
|
||||
return false;
|
||||
return this.getCurrentCullingSet().isVerticesCulled( vertices );
|
||||
},
|
||||
|
||||
isBoundingBoxCulled: function ( bb ) {
|
||||
if ( !this._enableFrustumCulling )
|
||||
return false;
|
||||
return bb.valid() && this.getCurrentCullingSet().isBoundingBoxCulled( bb );
|
||||
},
|
||||
|
||||
isBoundingSphereCulled: function ( bs ) {
|
||||
if ( !this._enableFrustumCulling )
|
||||
return false;
|
||||
return bs.valid() && this.getCurrentCullingSet().isBoundingSphereCulled( bs );
|
||||
},
|
||||
|
||||
isCulled: ( function () {
|
||||
var bsWorld = new BoundingSphere();
|
||||
return function ( node, nodePath ) {
|
||||
if ( !this._enableFrustumCulling )
|
||||
return false;
|
||||
if ( node.isCullingActive() ) {
|
||||
if ( this.getCurrentCullingSet().getCurrentResultMask() === 0 )
|
||||
return false; // father bounding sphere totally inside
|
||||
|
||||
var matrix = this._reservedMatrixStack.get();
|
||||
mat4.identity( matrix );
|
||||
|
||||
// TODO: Perf just get World Matrix at each node transform
|
||||
// store it in a World Transform Node Path (only world matrix change)
|
||||
// so that it's computed once and reused for each further node getCurrentModel
|
||||
// otherwise, it's 1 mult for each node, each matrix node, and each geometry
|
||||
//matrix = this.getCurrentModelMatrix();
|
||||
// tricky: change push be before isculled, and pop in case of culling
|
||||
// strange bug for now on frustum culling sample with that
|
||||
|
||||
if ( node instanceof Transform ) {
|
||||
|
||||
// tricky: MatrixTransform getBound is already transformed to
|
||||
// its local space whereas nodepath also have its matrix ...
|
||||
// so to get world space, you HAVE to remove that matrix from nodePATH
|
||||
// TODO: GC Perf of array slice creating new array
|
||||
matrix = ComputeMatrixFromNodePath.computeLocalToWorld( nodePath.slice( 0, nodePath.length - 1 ), true, matrix );
|
||||
|
||||
} else {
|
||||
|
||||
matrix = ComputeMatrixFromNodePath.computeLocalToWorld( nodePath, true, matrix );
|
||||
|
||||
}
|
||||
|
||||
// Matrix.transformBoundingSphere( matrix, node.getBound(), bsWorld );
|
||||
node.getBound().transformMat4( bsWorld, matrix );
|
||||
|
||||
return this.getCurrentCullingSet().isBoundingSphereCulled( bsWorld );
|
||||
} else {
|
||||
this.getCurrentCullingSet().resetCullingMask();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} )(),
|
||||
|
||||
|
||||
|
||||
pushModelViewMatrix: ( function () {
|
||||
var lookVector = vec3.create();
|
||||
return function ( matrix ) {
|
||||
|
||||
// When pushing a matrix, it can be a transform or camera. To compute
|
||||
// differents matrix type in shader ( ViewMatrix/ModelMatrix/ModelViewMatrix )
|
||||
// we track camera node when using pushModelViewMatrix
|
||||
// To detect a camera, we check on the nodepath the type of the node and if the
|
||||
// camera is relatif or absolute.
|
||||
// When we detect an absolute camera we keep it's index to get it when needed to
|
||||
// compute the World/View matrix
|
||||
// Th ere is an exception for the root camera, the root camera is not pushed on the
|
||||
// CullVisitor but only its matrixes, so to handle this we compute the inverse camera
|
||||
// when the nodepath has a lenght of 0
|
||||
// To avoid to compute too much inverse matrix, we keep a cache of them during the
|
||||
// traverse and store the result under the instanceID key, except for the root
|
||||
var np = this.getNodePath();
|
||||
var length = np.length;
|
||||
if ( !length ) { // root
|
||||
var matInverse = this._reservedMatrixStack.get();
|
||||
mat4.invert( matInverse, matrix );
|
||||
this._cameraMatrixInverseRoot = matInverse;
|
||||
} else {
|
||||
var index = length - 1;
|
||||
if ( np[ index ].getTypeID() === Camera.getTypeID() && np[ index ].getReferenceFrame() === TransformEnums.ABSOLUTE_RF ) {
|
||||
this._cameraIndexStack.push( index );
|
||||
this._cameraModelViewIndexStack.push( this._modelViewMatrixStack.length );
|
||||
}
|
||||
}
|
||||
|
||||
this._modelViewMatrixStack.push( matrix );
|
||||
this.getLookVectorLocal( lookVector );
|
||||
|
||||
/*jshint bitwise: false */
|
||||
this._bbCornerFar = ( lookVector[ 0 ] >= 0 ? 1 : 0 ) | ( lookVector[ 1 ] >= 0 ? 2 : 0 ) | ( lookVector[ 2 ] >= 0 ? 4 : 0 );
|
||||
this._bbCornerNear = ( ~this._bbCornerFar ) & 7;
|
||||
/*jshint bitwise: true */
|
||||
|
||||
};
|
||||
} )(),
|
||||
popModelViewMatrix: ( function () {
|
||||
var lookVector = vec3.create();
|
||||
|
||||
return function () {
|
||||
|
||||
// if same index it's a camera and we have to pop it
|
||||
var np = this.getNodePath();
|
||||
var index = np.length - 1;
|
||||
if ( this._cameraIndexStack.length && index === this._cameraIndexStack[ this._cameraIndexStack.length - 1 ] ) {
|
||||
this._cameraIndexStack.pop();
|
||||
this._cameraModelViewIndexStack.pop();
|
||||
}
|
||||
|
||||
this._modelViewMatrixStack.pop();
|
||||
|
||||
if ( this._modelViewMatrixStack.length !== 0 ) {
|
||||
this.getLookVectorLocal( lookVector );
|
||||
} else {
|
||||
vec3.set( lookVector, 0.0, 0.0, -1.0 );
|
||||
}
|
||||
|
||||
/*jshint bitwise: false */
|
||||
this._bbCornerFar = ( lookVector[ 0 ] >= 0.0 ? 1.0 : 0.0 ) | ( lookVector[ 1 ] >= 0 ? 2.0 : 0.0 ) | ( lookVector[ 2 ] >= 0 ? 4.0 : 0.0 );
|
||||
this._bbCornerNear = ( ~this._bbCornerFar ) & 7;
|
||||
/*jshint bitwise: true */
|
||||
};
|
||||
} )(),
|
||||
|
||||
pushProjectionMatrix: function ( matrix ) {
|
||||
this._projectionMatrixStack.push( matrix );
|
||||
|
||||
// need to recompute frustum volume.
|
||||
this._frustumVolume = -1.0;
|
||||
|
||||
this.pushCullingSet();
|
||||
},
|
||||
popProjectionMatrix: function () {
|
||||
this._projectionMatrixStack.pop();
|
||||
|
||||
// need to recompute frustum volume.
|
||||
this._frustumVolume = -1.0;
|
||||
|
||||
this.popCullingSet();
|
||||
}
|
||||
|
||||
|
||||
} );
|
||||
|
||||
module.exports = CullStack;
|
|
@ -1,761 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var osgMath = require( 'osg/math' );
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
var CullSettings = require( 'osg/CullSettings' );
|
||||
var CullStack = require( 'osg/CullStack' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var MatrixTransform = require( 'osg/MatrixTransform' );
|
||||
var AutoTransform = require( 'osg/AutoTransform' );
|
||||
var Projection = require( 'osg/Projection' );
|
||||
var LightSource = require( 'osg/LightSource' );
|
||||
var osgPool = require( 'osgUtil/osgPool' );
|
||||
var Geometry = require( 'osg/Geometry' );
|
||||
var RenderLeaf = require( 'osg/RenderLeaf' );
|
||||
var RenderBin = require( 'osg/RenderBin' );
|
||||
var RenderStage = require( 'osg/RenderStage' );
|
||||
var Node = require( 'osg/Node' );
|
||||
var Lod = require( 'osg/Lod' );
|
||||
var PagedLOD = require( 'osg/PagedLOD' );
|
||||
var Camera = require( 'osg/Camera' );
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var Skeleton = require( 'osgAnimation/Skeleton' );
|
||||
var RigGeometry = require( 'osgAnimation/RigGeometry' );
|
||||
var Bone = require( 'osgAnimation/Bone' );
|
||||
var MorphGeometry = require( 'osgAnimation/MorphGeometry' );
|
||||
|
||||
/**
|
||||
* CullVisitor traverse the tree and collect Matrix/State for the rendering traverse
|
||||
* @class CullVisitor
|
||||
*/
|
||||
var CullVisitor = function () {
|
||||
NodeVisitor.call( this, NodeVisitor.TRAVERSE_ACTIVE_CHILDREN );
|
||||
CullSettings.call( this );
|
||||
CullStack.call( this );
|
||||
|
||||
this._rootStateGraph = undefined;
|
||||
this._currentStateGraph = undefined;
|
||||
this._currentRenderBin = undefined;
|
||||
this._currentRenderStage = undefined;
|
||||
this._rootRenderStage = undefined;
|
||||
this._computedNear = Number.POSITIVE_INFINITY;
|
||||
this._computedFar = Number.NEGATIVE_INFINITY;
|
||||
|
||||
var lookVector = vec3.fromValues( 0.0, 0.0, -1.0 );
|
||||
this._camera = undefined;
|
||||
/*jshint bitwise: false */
|
||||
this._bbCornerFar = ( lookVector[ 0 ] >= 0 ? 1 : 0 ) | ( lookVector[ 1 ] >= 0 ? 2 : 0 ) | ( lookVector[ 2 ] >= 0 ? 4 : 0 );
|
||||
this._bbCornerNear = ( ~this._bbCornerFar ) & 7;
|
||||
/*jshint bitwise: true */
|
||||
|
||||
this._reserveLeafStack = [ new RenderLeaf() ];
|
||||
this._reserveLeafStackCurrent = 0;
|
||||
|
||||
this._reserveRenderStageStacks = {};
|
||||
|
||||
this._reserveCullSettingsStack = [ new CullSettings() ];
|
||||
this._reserveCullSettingsStackCurrent = 0;
|
||||
|
||||
this._renderBinStack = [];
|
||||
this.visitorType = NodeVisitor.CULL_VISITOR;
|
||||
|
||||
this._identityMatrix = mat4.create();
|
||||
|
||||
this._renderer = undefined;
|
||||
this._renderStageType = RenderStage;
|
||||
|
||||
this._numCamera = 0;
|
||||
this._numMatrixTransform = 0;
|
||||
this._numProjection = 0;
|
||||
this._numNode = 0;
|
||||
this._numLightSource = 0;
|
||||
this._numGeometry = 0;
|
||||
|
||||
};
|
||||
|
||||
/** @lends CullVisitor.prototype */
|
||||
CullVisitor.prototype = MACROUTILS.objectInherit( CullStack.prototype, MACROUTILS.objectInherit( NodeVisitor.prototype, {
|
||||
distance: function ( coord, matrix ) {
|
||||
return -( coord[ 0 ] * matrix[ 2 ] + coord[ 1 ] * matrix[ 6 ] + coord[ 2 ] * matrix[ 10 ] + matrix[ 14 ] );
|
||||
},
|
||||
|
||||
getComputedNear: function () {
|
||||
return this._computedNear;
|
||||
},
|
||||
|
||||
getComputedFar: function () {
|
||||
return this._computedFar;
|
||||
},
|
||||
|
||||
resetStats: function () {
|
||||
this._numCamera = 0;
|
||||
this._numMatrixTransform = 0;
|
||||
this._numProjection = 0;
|
||||
this._numNode = 0;
|
||||
this._numLightSource = 0;
|
||||
this._numGeometry = 0;
|
||||
},
|
||||
|
||||
handleCullCallbacksAndTraverse: function ( node ) {
|
||||
var ccb = node.getCullCallback();
|
||||
if ( ccb && !ccb.cull( node, this ) )
|
||||
return;
|
||||
this.traverse( node );
|
||||
},
|
||||
|
||||
getCurrentCamera: function () {
|
||||
return this._currentRenderBin.getStage().getCamera();
|
||||
},
|
||||
|
||||
updateCalculatedNearFar: ( function () {
|
||||
var nearVec = vec3.create();
|
||||
var farVec = vec3.create();
|
||||
|
||||
return function ( matrix, drawable ) {
|
||||
|
||||
var bb = drawable.getBoundingBox();
|
||||
var dNear, dFar;
|
||||
|
||||
// efficient computation of near and far, only taking into account the nearest and furthest
|
||||
// corners of the bounding box.
|
||||
dNear = this.distance( bb.corner( this._bbCornerNear, nearVec ), matrix );
|
||||
dFar = this.distance( bb.corner( this._bbCornerFar, farVec ), matrix );
|
||||
|
||||
if ( dNear > dFar ) {
|
||||
var tmp = dNear;
|
||||
dNear = dFar;
|
||||
dFar = tmp;
|
||||
}
|
||||
|
||||
if ( dFar < 0.0 ) {
|
||||
// whole object behind the eye point so discard
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( dNear < this._computedNear ) {
|
||||
this._computedNear = dNear;
|
||||
}
|
||||
|
||||
if ( dFar > this._computedFar ) {
|
||||
this._computedFar = dFar;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
};
|
||||
} )(),
|
||||
|
||||
|
||||
setStateGraph: function ( sg ) {
|
||||
this._rootStateGraph = sg;
|
||||
this._currentStateGraph = sg;
|
||||
},
|
||||
setRenderStage: function ( rg ) {
|
||||
this._rootRenderStage = rg;
|
||||
this._currentRenderBin = rg;
|
||||
},
|
||||
setRenderer: function ( renderer ) {
|
||||
this._renderer = renderer;
|
||||
},
|
||||
getRenderer: function () {
|
||||
return this._renderer;
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
CullStack.prototype.reset.call( this );
|
||||
// Reset the stack before reseting the current leaf index.
|
||||
// Reseting elements and refilling them later is faster than create new elements
|
||||
// That's the reason to have a leafStack, see http://jsperf.com/refill/2
|
||||
this.resetRenderLeafStack();
|
||||
this._reserveLeafStackCurrent = 0;
|
||||
|
||||
this.resetCullSettingsStack();
|
||||
this._reserveCullSettingsStackCurrent = 0;
|
||||
|
||||
// renderstage / renderbin pools
|
||||
var resetStages = window.Object.keys( this._reserveRenderStageStacks );
|
||||
for ( var i = 0, l = resetStages.length; i < l; i++ ) {
|
||||
var key = resetStages[ i ];
|
||||
this._reserveRenderStageStacks[ key ].reset();
|
||||
}
|
||||
RenderBin.resetStack();
|
||||
|
||||
this._computedNear = Number.POSITIVE_INFINITY;
|
||||
this._computedFar = Number.NEGATIVE_INFINITY;
|
||||
},
|
||||
|
||||
getCurrentRenderBin: function () {
|
||||
return this._currentRenderBin;
|
||||
},
|
||||
|
||||
setCurrentRenderBin: function ( rb ) {
|
||||
this._currentRenderBin = rb;
|
||||
},
|
||||
|
||||
// mimic the osg implementation
|
||||
// in osg you can push 0, in this case an identity matrix will be loaded
|
||||
addPositionedAttribute: function ( matrix, attribute ) {
|
||||
|
||||
var m = matrix ? matrix : this._identityMatrix;
|
||||
this._currentRenderBin.getStage().positionedAttribute.push( [ m, attribute ] );
|
||||
|
||||
},
|
||||
|
||||
pushStateSet: function ( stateset ) {
|
||||
this._currentStateGraph = this._currentStateGraph.findOrInsert( stateset );
|
||||
if ( stateset.getBinName() !== undefined ) {
|
||||
var renderBinStack = this._renderBinStack;
|
||||
var currentRenderBin = this._currentRenderBin;
|
||||
renderBinStack.push( currentRenderBin );
|
||||
this._currentRenderBin = currentRenderBin.getStage().findOrInsert( stateset.getBinNumber(), stateset.getBinName() );
|
||||
}
|
||||
},
|
||||
|
||||
/** Pop the top state set and hence associated state group.
|
||||
* Move the current state group to the parent of the popped
|
||||
* state group.
|
||||
*/
|
||||
popStateSet: function () {
|
||||
var currentStateGraph = this._currentStateGraph;
|
||||
var stateset = currentStateGraph.getStateSet();
|
||||
this._currentStateGraph = currentStateGraph.parent;
|
||||
if ( stateset.getBinName() !== undefined ) {
|
||||
var renderBinStack = this._renderBinStack;
|
||||
if ( renderBinStack.length === 0 ) {
|
||||
this._currentRenderBin = this._currentRenderBin.getStage();
|
||||
} else {
|
||||
this._currentRenderBin = renderBinStack.pop();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
popProjectionMatrix: function () {
|
||||
if ( this._computeNearFar === true && this._computedFar >= this._computedNear ) {
|
||||
var m = this.getCurrentProjectionMatrix();
|
||||
if ( this._clampProjectionMatrixCallback !== undefined ) {
|
||||
this._clampProjectionMatrixCallback( m, this._computedNear, this._computedFar, this._nearFarRatio );
|
||||
} else {
|
||||
this.clampProjectionMatrix( m, this._computedNear, this._computedFar, this._nearFarRatio );
|
||||
}
|
||||
}
|
||||
CullStack.prototype.popProjectionMatrix.call( this );
|
||||
},
|
||||
|
||||
|
||||
clampProjectionMatrix: function ( projection, znear, zfar, nearFarRatio, resultNearFar ) {
|
||||
var epsilon = 1e-6;
|
||||
if ( zfar < znear - epsilon ) {
|
||||
Notify.log( 'clampProjectionMatrix not applied, invalid depth range, znear = ' + znear + ' zfar = ' + zfar, false, true );
|
||||
return false;
|
||||
}
|
||||
|
||||
var desiredZnear, desiredZfar;
|
||||
if ( zfar < znear + epsilon ) {
|
||||
// znear and zfar are too close together and could cause divide by zero problems
|
||||
// late on in the clamping code, so move the znear and zfar apart.
|
||||
var average = ( znear + zfar ) * 0.5;
|
||||
znear = average - epsilon;
|
||||
zfar = average + epsilon;
|
||||
// OSG_INFO << '_clampProjectionMatrix widening znear and zfar to '<<znear<<' '<<zfar<<std::endl;
|
||||
}
|
||||
|
||||
if ( Math.abs( projection[ 3 ] ) < epsilon &&
|
||||
Math.abs( projection[ 7 ] ) < epsilon &&
|
||||
Math.abs( projection[ 11 ] ) < epsilon ) {
|
||||
// OSG_INFO << 'Orthographic matrix before clamping'<<projection<<std::endl;
|
||||
|
||||
var deltaSpan = ( zfar - znear ) * 0.02;
|
||||
if ( deltaSpan < 1.0 ) {
|
||||
deltaSpan = 1.0;
|
||||
}
|
||||
desiredZnear = znear - deltaSpan;
|
||||
desiredZfar = zfar + deltaSpan;
|
||||
|
||||
// assign the clamped values back to the computed values.
|
||||
znear = desiredZnear;
|
||||
zfar = desiredZfar;
|
||||
|
||||
projection[ 10 ] = -2.0 / ( desiredZfar - desiredZnear );
|
||||
projection[ 14 ] = -( desiredZfar + desiredZnear ) / ( desiredZfar - desiredZnear );
|
||||
// OSG_INFO << 'Orthographic matrix after clamping '<<projection<<std::endl;
|
||||
} else {
|
||||
|
||||
// OSG_INFO << 'Persepective matrix before clamping'<<projection<<std::endl;
|
||||
//std::cout << '_computed_znear'<<_computed_znear<<std::endl;
|
||||
//std::cout << '_computed_zfar'<<_computed_zfar<<std::endl;
|
||||
|
||||
var zfarPushRatio = 1.02;
|
||||
var znearPullRatio = 0.98;
|
||||
|
||||
//znearPullRatio = 0.99;
|
||||
|
||||
desiredZnear = znear * znearPullRatio;
|
||||
desiredZfar = zfar * zfarPushRatio;
|
||||
|
||||
// near plane clamping.
|
||||
var minNearPlane = zfar * nearFarRatio;
|
||||
if ( desiredZnear < minNearPlane ) {
|
||||
desiredZnear = minNearPlane;
|
||||
}
|
||||
|
||||
// assign the clamped values back to the computed values.
|
||||
znear = desiredZnear;
|
||||
zfar = desiredZfar;
|
||||
|
||||
var m22 = projection[ 10 ];
|
||||
var m32 = projection[ 14 ];
|
||||
var m23 = projection[ 11 ];
|
||||
var m33 = projection[ 15 ];
|
||||
var transNearPlane = ( -desiredZnear * m22 + m32 ) / ( -desiredZnear * m23 + m33 );
|
||||
var transFarPlane = ( -desiredZfar * m22 + m32 ) / ( -desiredZfar * m23 + m33 );
|
||||
|
||||
var ratio = Math.abs( 2.0 / ( transNearPlane - transFarPlane ) );
|
||||
var center = -( transNearPlane + transFarPlane ) / 2.0;
|
||||
|
||||
var centerRatio = center * ratio;
|
||||
projection[ 2 ] = projection[ 2 ] * ratio + projection[ 3 ] * centerRatio;
|
||||
projection[ 6 ] = projection[ 6 ] * ratio + projection[ 7 ] * centerRatio;
|
||||
projection[ 10 ] = m22 * ratio + m23 * centerRatio;
|
||||
projection[ 14 ] = m32 * ratio + m33 * centerRatio;
|
||||
// same as
|
||||
// var matrix = [ 1.0, 0.0, 0.0, 0.0,
|
||||
// 0.0, 1.0, 0.0, 0.0,
|
||||
// 0.0, 0.0, ratio, 0.0,
|
||||
// 0.0, 0.0, center * ratio, 1.0
|
||||
// ];
|
||||
// mat4.mul( projection , matrix, projection );
|
||||
|
||||
// OSG_INFO << 'Persepective matrix after clamping'<<projection<<std::endl;
|
||||
}
|
||||
if ( resultNearFar !== undefined ) {
|
||||
resultNearFar[ 0 ] = znear;
|
||||
resultNearFar[ 1 ] = zfar;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
popCameraModelViewProjectionMatrix: function () {
|
||||
this.popModelViewMatrix();
|
||||
this.popProjectionMatrix();
|
||||
},
|
||||
|
||||
pushCameraModelViewProjectionMatrix: function ( camera, modelview, projection ) {
|
||||
this.pushModelViewMatrix( modelview );
|
||||
this.pushProjectionMatrix( projection );
|
||||
},
|
||||
|
||||
apply: function ( node ) {
|
||||
this[ node.typeID ]( node );
|
||||
},
|
||||
|
||||
createOrReuseRenderStage: function ( classInstance ) {
|
||||
|
||||
var type = !classInstance ? 'RenderStage' : classInstance.className();
|
||||
var classCtor = !classInstance ? RenderStage : classInstance.constructor;
|
||||
|
||||
var stack;
|
||||
if ( this._reserveRenderStageStacks[ type ] ) {
|
||||
stack = this._reserveRenderStageStacks[ type ];
|
||||
} else {
|
||||
stack = new osgPool.OsgObjectMemoryStack( classCtor );
|
||||
this._reserveRenderStageStacks[ type ] = stack;
|
||||
}
|
||||
return stack.get().init();
|
||||
|
||||
},
|
||||
|
||||
createOrReuseRenderLeaf: function () {
|
||||
var l = this._reserveLeafStack[ this._reserveLeafStackCurrent++ ];
|
||||
if ( this._reserveLeafStackCurrent === this._reserveLeafStack.length ) {
|
||||
this._reserveLeafStack.push( new RenderLeaf() );
|
||||
}
|
||||
return l;
|
||||
},
|
||||
|
||||
resetRenderLeafStack: function () {
|
||||
for ( var i = 0, j = this._reserveLeafStackCurrent; i <= j; i++ ) {
|
||||
this._reserveLeafStack[ i ].reset();
|
||||
}
|
||||
},
|
||||
|
||||
createOrReuseCullSettings: function () {
|
||||
var l = this._reserveCullSettingsStack[ this._reserveCullSettingsStackCurrent++ ];
|
||||
|
||||
if ( this._reserveCullSettingsStackCurrent === this._reserveCullSettingsStack.length ) {
|
||||
|
||||
this._reserveCullSettingsStack.push( new CullSettings() );
|
||||
|
||||
}
|
||||
return l;
|
||||
},
|
||||
|
||||
resetCullSettingsStack: function () {
|
||||
for ( var i = 0, j = this._reserveCullSettingsStackCurrent; i <= j; i++ ) {
|
||||
this._reserveCullSettingsStack[ i ].reset();
|
||||
}
|
||||
},
|
||||
|
||||
// function call after the push state in the geometry apply function
|
||||
// the idea is to avoid heavy copy-paste for the rigGeometry apply
|
||||
// since the only difference is that we want to push an additional state
|
||||
// Maybe it will be useful when we'll add morph target geometry or something...
|
||||
postPushGeometry: function ( cull, node ) {
|
||||
|
||||
var sourceGeometry;
|
||||
var geometryStateSetAnimation;
|
||||
|
||||
if ( node instanceof RigGeometry ) {
|
||||
|
||||
geometryStateSetAnimation = node.getStateSetAnimation();
|
||||
if ( geometryStateSetAnimation ) cull.pushStateSet( geometryStateSetAnimation );
|
||||
|
||||
sourceGeometry = node.getSourceGeometry();
|
||||
|
||||
if ( sourceGeometry instanceof MorphGeometry ) {
|
||||
|
||||
geometryStateSetAnimation = sourceGeometry.getStateSetAnimation();
|
||||
if ( geometryStateSetAnimation ) cull.pushStateSet( geometryStateSetAnimation );
|
||||
|
||||
}
|
||||
|
||||
} else if ( node instanceof MorphGeometry ) {
|
||||
|
||||
geometryStateSetAnimation = node.getStateSetAnimation();
|
||||
if ( geometryStateSetAnimation ) cull.pushStateSet( geometryStateSetAnimation );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// same comment as above (postPushGeometry)
|
||||
prePopGeometry: function ( cull, node ) {
|
||||
|
||||
if ( node instanceof RigGeometry ) {
|
||||
|
||||
var sourceGeometry = node.getSourceGeometry();
|
||||
|
||||
if ( sourceGeometry instanceof MorphGeometry ) {
|
||||
|
||||
if ( sourceGeometry.getStateSetAnimation() ) cull.popStateSet();
|
||||
|
||||
}
|
||||
|
||||
if ( node.getStateSetAnimation() ) cull.popStateSet();
|
||||
|
||||
} else if ( node instanceof MorphGeometry && node.getStateSetAnimation() ) {
|
||||
|
||||
cull.popStateSet();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
pushLeaf: function ( node, depth ) {
|
||||
var leafs = this._currentStateGraph.leafs;
|
||||
if ( leafs.length === 0 ) {
|
||||
this._currentRenderBin.addStateGraph( this._currentStateGraph );
|
||||
}
|
||||
|
||||
var leaf = this.createOrReuseRenderLeaf();
|
||||
|
||||
leaf.init( this._currentStateGraph,
|
||||
node,
|
||||
this.getCurrentProjectionMatrix(),
|
||||
this.getCurrentViewMatrix(),
|
||||
this.getCurrentModelViewMatrix(),
|
||||
this.getCurrentModelMatrix(),
|
||||
depth );
|
||||
|
||||
leafs.push( leaf );
|
||||
|
||||
}
|
||||
|
||||
} ) );
|
||||
|
||||
|
||||
// Camera cull visitor call
|
||||
// ANY CHANGE, any change : double check in rendere Camera code
|
||||
// for the first camera
|
||||
CullVisitor.prototype[ Camera.typeID ] = function ( camera ) {
|
||||
this._numCamera++;
|
||||
|
||||
var stateset = camera.getStateSet();
|
||||
if ( stateset ) this.pushStateSet( stateset );
|
||||
|
||||
var modelview = this._reservedMatrixStack.get();
|
||||
var projection = this._reservedMatrixStack.get();
|
||||
|
||||
if ( camera.getReferenceFrame() === TransformEnums.RELATIVE_RF ) {
|
||||
|
||||
var lastProjectionMatrix = this.getCurrentProjectionMatrix();
|
||||
mat4.mul( projection, lastProjectionMatrix, camera.getProjectionMatrix() );
|
||||
|
||||
var lastViewMatrix = this.getCurrentModelViewMatrix();
|
||||
mat4.mul( modelview, lastViewMatrix, camera.getViewMatrix() );
|
||||
|
||||
} else {
|
||||
|
||||
// absolute
|
||||
mat4.copy( modelview, camera.getViewMatrix() );
|
||||
mat4.copy( projection, camera.getProjectionMatrix() );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// save current state of the camera
|
||||
var previousZnear = this._computedNear;
|
||||
var previousZfar = this._computedFar;
|
||||
|
||||
// save cullSettings
|
||||
// TODO Perf: why it's not a stack
|
||||
// and is pollutin GC ?
|
||||
var previousCullsettings = this.createOrReuseCullSettings();
|
||||
previousCullsettings.setCullSettings( this );
|
||||
|
||||
this._computedNear = Number.POSITIVE_INFINITY;
|
||||
this._computedFar = Number.NEGATIVE_INFINITY;
|
||||
//
|
||||
|
||||
this.setCullSettings( camera );
|
||||
// global override
|
||||
// upon who setted the parameter
|
||||
// if it's cullvisitor
|
||||
// it's an OVERRIDER for enableFrustumCulling
|
||||
// allowing for global EnableFrustimCulling
|
||||
if ( previousCullsettings.getSettingSourceOverrider() === this && previousCullsettings.getEnableFrustumCulling() ) {
|
||||
this.setEnableFrustumCulling( true );
|
||||
}
|
||||
|
||||
|
||||
this.pushCameraModelViewProjectionMatrix( camera, modelview, projection );
|
||||
|
||||
if ( camera.getViewport() ) {
|
||||
this.pushViewport( camera.getViewport() );
|
||||
}
|
||||
|
||||
|
||||
// nested camera
|
||||
if ( camera.getRenderOrder() === Camera.NESTED_RENDER ) {
|
||||
|
||||
this.handleCullCallbacksAndTraverse( camera );
|
||||
|
||||
} else {
|
||||
// not tested
|
||||
|
||||
var renderBin = this.getCurrentRenderBin();
|
||||
var previousStage = renderBin.getStage();
|
||||
|
||||
// use render to texture stage
|
||||
var rtts = this.createOrReuseRenderStage( this._rootRenderStage );
|
||||
|
||||
rtts.setCamera( camera );
|
||||
rtts.setClearDepth( camera.getClearDepth() );
|
||||
rtts.setClearColor( camera.getClearColor() );
|
||||
rtts.setClearMask( camera.getClearMask() );
|
||||
|
||||
var vp;
|
||||
if ( camera.getViewport() === undefined ) {
|
||||
vp = previousStage.getViewport();
|
||||
} else {
|
||||
vp = camera.getViewport();
|
||||
}
|
||||
rtts.setViewport( vp );
|
||||
|
||||
// skip positional state for now
|
||||
// ...
|
||||
|
||||
this.setCurrentRenderBin( rtts );
|
||||
|
||||
this.handleCullCallbacksAndTraverse( camera );
|
||||
|
||||
this.setCurrentRenderBin( renderBin );
|
||||
|
||||
if ( camera.getRenderOrder() === Camera.PRE_RENDER ) {
|
||||
this.getCurrentRenderBin().getStage().addPreRenderStage( rtts, camera.renderOrderNum );
|
||||
} else {
|
||||
this.getCurrentRenderBin().getStage().addPostRenderStage( rtts, camera.renderOrderNum );
|
||||
}
|
||||
}
|
||||
|
||||
this.popCameraModelViewProjectionMatrix( camera );
|
||||
|
||||
if ( camera.getViewport() ) {
|
||||
this.popViewport();
|
||||
}
|
||||
|
||||
// restore previous state of the camera
|
||||
this.setCullSettings( previousCullsettings );
|
||||
this._computedNear = previousZnear;
|
||||
this._computedFar = previousZfar;
|
||||
|
||||
if ( stateset ) this.popStateSet();
|
||||
|
||||
};
|
||||
|
||||
|
||||
CullVisitor.prototype[ MatrixTransform.typeID ] = function ( node ) {
|
||||
this._numMatrixTransform++;
|
||||
|
||||
// Camera and lights must enlarge node parent bounding boxes for this not to cull
|
||||
if ( this.isCulled( node, this.nodePath ) ) {
|
||||
return;
|
||||
}
|
||||
// push the culling mode.
|
||||
this.pushCurrentMask();
|
||||
|
||||
var matrix = this._reservedMatrixStack.get();
|
||||
var lastMatrixStack = this.getCurrentModelViewMatrix();
|
||||
mat4.copy( matrix, lastMatrixStack );
|
||||
node.computeLocalToWorldMatrix( matrix );
|
||||
this.pushModelViewMatrix( matrix );
|
||||
|
||||
|
||||
var stateset = node.getStateSet();
|
||||
|
||||
if ( stateset ) this.pushStateSet( stateset );
|
||||
|
||||
this.handleCullCallbacksAndTraverse( node );
|
||||
|
||||
if ( stateset ) this.popStateSet();
|
||||
|
||||
|
||||
this.popModelViewMatrix();
|
||||
|
||||
// pop the culling mode.
|
||||
this.popCurrentMask();
|
||||
};
|
||||
|
||||
CullVisitor.prototype[ Projection.typeID ] = function ( node ) {
|
||||
this._numProjection++;
|
||||
|
||||
var lastMatrixStack = this.getCurrentProjectionMatrix();
|
||||
var matrix = this._reservedMatrixStack.get();
|
||||
mat4.mul( matrix, lastMatrixStack, node.getProjectionMatrix() );
|
||||
this.pushProjectionMatrix( matrix );
|
||||
|
||||
var stateset = node.getStateSet();
|
||||
if ( stateset ) this.pushStateSet( stateset );
|
||||
|
||||
this.handleCullCallbacksAndTraverse( node );
|
||||
|
||||
if ( stateset ) this.popStateSet();
|
||||
|
||||
this.popProjectionMatrix();
|
||||
};
|
||||
|
||||
// here it's treated as a group node for culling
|
||||
// as there's isn't any in osgjs
|
||||
// so frustumCulling is done here
|
||||
CullVisitor.prototype[ Node.typeID ] = function ( node ) {
|
||||
this._numNode++;
|
||||
|
||||
// Camera and lights must enlarge node parent bounding boxes for this not to cull
|
||||
if ( this.isCulled( node, this.nodePath ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// push the culling mode.
|
||||
this.pushCurrentMask();
|
||||
|
||||
var stateset = node.getStateSet();
|
||||
if ( stateset ) this.pushStateSet( stateset );
|
||||
|
||||
this.handleCullCallbacksAndTraverse( node );
|
||||
|
||||
if ( stateset ) this.popStateSet();
|
||||
|
||||
// pop the culling mode.
|
||||
this.popCurrentMask();
|
||||
};
|
||||
|
||||
// same code like MatrixTransform
|
||||
CullVisitor.prototype[ AutoTransform.typeID ] = CullVisitor.prototype[ MatrixTransform.typeID ];
|
||||
|
||||
// same code like Node
|
||||
CullVisitor.prototype[ Lod.typeID ] = CullVisitor.prototype[ Node.typeID ];
|
||||
|
||||
// same code like Node
|
||||
CullVisitor.prototype[ PagedLOD.typeID ] = CullVisitor.prototype[ Node.typeID ];
|
||||
|
||||
|
||||
CullVisitor.prototype[ LightSource.typeID ] = function ( node ) {
|
||||
this._numLightSource++;
|
||||
|
||||
var stateset = node.getStateSet();
|
||||
if ( stateset ) this.pushStateSet( stateset );
|
||||
|
||||
var light = node.getLight();
|
||||
if ( light ) {
|
||||
if ( node.getReferenceFrame() === TransformEnums.RELATIVE_RF )
|
||||
this.addPositionedAttribute( this.getCurrentModelViewMatrix(), light );
|
||||
else
|
||||
this.addPositionedAttribute( null, light );
|
||||
}
|
||||
|
||||
|
||||
this.handleCullCallbacksAndTraverse( node );
|
||||
|
||||
if ( stateset ) this.popStateSet();
|
||||
};
|
||||
|
||||
CullVisitor.prototype[ Geometry.typeID ] = ( function () {
|
||||
|
||||
var tempVec = vec3.create();
|
||||
var loggedOnce = false;
|
||||
return function geometryApply( node ) {
|
||||
|
||||
this._numGeometry++;
|
||||
|
||||
var modelview = this.getCurrentModelViewMatrix();
|
||||
var bb = node.getBoundingBox();
|
||||
if ( this._computeNearFar && bb.valid() ) {
|
||||
if ( !this.updateCalculatedNearFar( modelview, node ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// using modelview is not a pb because geometry
|
||||
// is a leaf node, else traversing the graph would be an
|
||||
// issue because we use modelview after
|
||||
var ccb = node.getCullCallback();
|
||||
if ( ccb && !ccb.cull( node, this ) )
|
||||
return;
|
||||
|
||||
var stateset = node.getStateSet();
|
||||
if ( stateset ) this.pushStateSet( stateset );
|
||||
|
||||
this.postPushGeometry( this, node );
|
||||
|
||||
var depth = 0;
|
||||
if ( bb.valid() ) {
|
||||
depth = this.distance( bb.center( tempVec ), modelview );
|
||||
}
|
||||
if ( osgMath.isNaN( depth ) ) {
|
||||
|
||||
if ( !loggedOnce ) {
|
||||
Notify.warn( 'warning geometry has a NaN depth, ' + modelview + ' center ' + tempVec );
|
||||
loggedOnce = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this.pushLeaf( node, depth );
|
||||
|
||||
}
|
||||
|
||||
this.prePopGeometry( this, node );
|
||||
if ( stateset ) this.popStateSet();
|
||||
};
|
||||
} )();
|
||||
|
||||
CullVisitor.prototype[ Skeleton.typeID ] = CullVisitor.prototype[ MatrixTransform.typeID ];
|
||||
|
||||
CullVisitor.prototype[ RigGeometry.typeID ] = CullVisitor.prototype[ Geometry.typeID ];
|
||||
|
||||
CullVisitor.prototype[ MorphGeometry.typeID ] = CullVisitor.prototype[ Geometry.typeID ];
|
||||
|
||||
CullVisitor.prototype[ Bone.typeID ] = CullVisitor.prototype[ MatrixTransform.typeID ];
|
||||
|
||||
module.exports = CullVisitor;
|
|
@ -1,81 +0,0 @@
|
|||
'use strict';
|
||||
var Polytope = require( 'osg/Polytope' );
|
||||
|
||||
var CullingSet = function () {
|
||||
|
||||
this._mask = CullingSet.DEFAULT_CULLING;
|
||||
this._frustum = new Polytope();
|
||||
|
||||
};
|
||||
|
||||
CullingSet.prototype = {
|
||||
|
||||
reset: function () {
|
||||
this._mask = CullingSet.DEFAULT_CULLING;
|
||||
this._frustum.clear();
|
||||
},
|
||||
setCullingMask: function ( mask ) {
|
||||
this._mask = mask;
|
||||
},
|
||||
getCullingMask: function () {
|
||||
return this._mask;
|
||||
},
|
||||
setFrustum: function ( frustum ) {
|
||||
this._frustum = frustum;
|
||||
},
|
||||
getFrustum: function () {
|
||||
return this._frustum;
|
||||
},
|
||||
getCurrentResultMask: function () {
|
||||
return this._frustum.getCurrentMask();
|
||||
},
|
||||
pushCurrentMask: function () {
|
||||
this._frustum.pushCurrentMask();
|
||||
},
|
||||
popCurrentMask: function () {
|
||||
this._frustum.popCurrentMask();
|
||||
},
|
||||
resetCullingMask: function () {
|
||||
this._frustum.setResultMask( this._frustum.getCurrentMask() );
|
||||
},
|
||||
isBoundingBoxCulled: function ( bbox ) {
|
||||
if ( this._mask & CullingSet.VIEW_FRUSTUM_CULLING ) {
|
||||
// is it outside the view frustum...
|
||||
if ( !this._frustum.containsBoundingBox( bbox ) ) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
isBoundingSphereCulled: function ( bs ) {
|
||||
if ( this._mask & CullingSet.VIEW_FRUSTUM_CULLING ) {
|
||||
// is it outside the view frustum...
|
||||
if ( !this._frustum.containsBoundingSphere( bs ) ) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
isVerticesCulled: function ( vertices ) {
|
||||
if ( this._mask & CullingSet.VIEW_FRUSTUM_CULLING ) {
|
||||
// is it outside the view frustum...
|
||||
if ( !this._frustum.containsVertices( vertices ) ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
CullingSet.NO_CULLING = 0x0;
|
||||
|
||||
CullingSet.VIEW_FRUSTUM_LEFT_CULLING = 0x1;
|
||||
CullingSet.VIEW_FRUSTUM_RIGHT_CULLING = 0x2;
|
||||
CullingSet.VIEW_FRUSTUM_TOP_CULLING = 0x3;
|
||||
CullingSet.VIEW_FRUSTUM_BOTTOM_CULLING = 0x4;
|
||||
CullingSet.NEAR_PLANE_CULLING = 0x5;
|
||||
CullingSet.FAR_PLANE_CULLING = 0x6;
|
||||
|
||||
CullingSet.VIEW_FRUSTUM_SIDES_CULLING = CullingSet.VIEW_FRUSTUM_LEFT_CULLING | CullingSet.VIEW_FRUSTUM_RIGHT_CULLING | CullingSet.VIEW_FRUSTUM_BOTTOM_CULLING | CullingSet.VIEW_FRUSTUM_TOP_CULLING;
|
||||
|
||||
CullingSet.VIEW_FRUSTUM_CULLING = CullingSet.VIEW_FRUSTUM_SIDES_CULLING | CullingSet.NEAR_PLANE_CULLING | CullingSet.FAR_PLANE_CULLING;
|
||||
|
||||
CullingSet.DEFAULT_CULLING = CullingSet.VIEW_FRUSTUM_SIDES_CULLING;
|
||||
|
||||
CullingSet.ENABLE_ALL_CULLING = CullingSet.VIEW_FRUSTUM_CULLING;
|
||||
|
||||
module.exports = CullingSet;
|
|
@ -1,72 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
|
||||
var Depth = function ( func, near, far, writeMask ) {
|
||||
StateAttribute.call( this );
|
||||
|
||||
this._func = Depth.LESS;
|
||||
this._near = 0.0;
|
||||
this._far = 1.0;
|
||||
this._writeMask = true;
|
||||
|
||||
if ( func !== undefined ) {
|
||||
if ( typeof ( func ) === 'string' ) {
|
||||
this._func = Depth[ func ];
|
||||
} else {
|
||||
this._func = func;
|
||||
}
|
||||
}
|
||||
if ( near !== undefined ) {
|
||||
this._near = near;
|
||||
}
|
||||
if ( far !== undefined ) {
|
||||
this._far = far;
|
||||
}
|
||||
if ( writeMask !== undefined ) {
|
||||
this._writeMask = writeMask;
|
||||
}
|
||||
};
|
||||
|
||||
Depth.DISABLE = 0x0000;
|
||||
Depth.NEVER = 0x0200;
|
||||
Depth.LESS = 0x0201;
|
||||
Depth.EQUAL = 0x0202;
|
||||
Depth.LEQUAL = 0x0203;
|
||||
Depth.GREATER = 0x0204;
|
||||
Depth.NOTEQUAL = 0x0205;
|
||||
Depth.GEQUAL = 0x0206;
|
||||
Depth.ALWAYS = 0x0207;
|
||||
|
||||
Depth.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
attributeType: 'Depth',
|
||||
cloneType: function () {
|
||||
return new Depth();
|
||||
},
|
||||
setRange: function ( near, far ) {
|
||||
this._near = near;
|
||||
this._far = far;
|
||||
},
|
||||
setWriteMask: function ( mask ) {
|
||||
this._writeMask = mask;
|
||||
},
|
||||
getWriteMask: function () {
|
||||
return this._writeMask;
|
||||
},
|
||||
getFunc: function () {
|
||||
return this._func;
|
||||
},
|
||||
apply: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
if ( this._func === 0 ) {
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
} else {
|
||||
gl.enable( gl.DEPTH_TEST );
|
||||
gl.depthFunc( this._func );
|
||||
gl.depthMask( this._writeMask );
|
||||
gl.depthRange( this._near, this._far );
|
||||
}
|
||||
}
|
||||
} ), 'osg', 'Depth' );
|
||||
|
||||
module.exports = Depth;
|
|
@ -1,51 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* DrawArrayLengths manage rendering primitives
|
||||
* @class DrawArrayLengths
|
||||
*/
|
||||
var DrawArrayLengths = function ( mode, first, array ) {
|
||||
this._mode = mode;
|
||||
this._first = first;
|
||||
this._arrayLengths = array.slice( 0 );
|
||||
};
|
||||
|
||||
/** @lends DrawArrayLengths.prototype */
|
||||
DrawArrayLengths.prototype = {
|
||||
draw: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
var mode = this._mode;
|
||||
var first = this._first;
|
||||
var array = this._arrayLengths;
|
||||
for ( var i = 0, l = array.length; i < l; i++ ) {
|
||||
var count = array[ i ];
|
||||
gl.drawArrays( mode, first, count );
|
||||
first += count;
|
||||
}
|
||||
},
|
||||
getMode: function () {
|
||||
return this._mode;
|
||||
},
|
||||
getNumIndices: function () {
|
||||
var count = 0;
|
||||
var array = this._arrayLengths;
|
||||
for ( var i = 0, l = array.length; i < l; i++ ) {
|
||||
count += array[ i ];
|
||||
}
|
||||
return count;
|
||||
},
|
||||
getCount: function () {
|
||||
return this.getNumIndices();
|
||||
},
|
||||
getArrayLengths: function () {
|
||||
return this._arrayLengths;
|
||||
},
|
||||
getFirst: function () {
|
||||
return this._first;
|
||||
},
|
||||
setFirst: function ( first ) {
|
||||
this._first = first;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DrawArrayLengths;
|
|
@ -1,59 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var PrimitiveSet = require( 'osg/primitiveSet' );
|
||||
|
||||
|
||||
/**
|
||||
* DrawArrays manage rendering primitives
|
||||
* @class DrawArrays
|
||||
*/
|
||||
var DrawArrays = function ( mode, first, count ) {
|
||||
this.mode = mode;
|
||||
if ( mode !== undefined ) {
|
||||
if ( typeof ( mode ) === 'string' ) {
|
||||
mode = PrimitiveSet[ mode ];
|
||||
}
|
||||
this.mode = mode;
|
||||
}
|
||||
this.first = first;
|
||||
this.count = count;
|
||||
};
|
||||
|
||||
/** @lends DrawArrays.prototype */
|
||||
DrawArrays.prototype = {
|
||||
draw: function ( state ) {
|
||||
if ( this.count === 0 )
|
||||
return;
|
||||
var gl = state.getGraphicContext();
|
||||
gl.drawArrays( this.mode, this.first, this.count );
|
||||
},
|
||||
getMode: function () {
|
||||
return this.mode;
|
||||
},
|
||||
setCount: function ( count ) {
|
||||
this.count = count;
|
||||
},
|
||||
getCount: function () {
|
||||
return this.count;
|
||||
},
|
||||
setFirst: function ( first ) {
|
||||
this.first = first;
|
||||
},
|
||||
getFirst: function () {
|
||||
return this.first;
|
||||
},
|
||||
getNumIndices: function () {
|
||||
return this.count;
|
||||
},
|
||||
index: function ( i ) {
|
||||
return this.first + i;
|
||||
}
|
||||
|
||||
};
|
||||
DrawArrays.create = function ( mode, first, count ) {
|
||||
Notify.log( 'DrawArrays.create is deprecated, use new DrawArrays with same arguments' );
|
||||
var d = new DrawArrays( mode, first, count );
|
||||
return d;
|
||||
};
|
||||
|
||||
module.exports = DrawArrays;
|
|
@ -1,86 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var PrimitiveSet = require( 'osg/primitiveSet' );
|
||||
|
||||
|
||||
/**
|
||||
* DrawElements manage rendering of indexed primitives
|
||||
* @class DrawElements
|
||||
*/
|
||||
var DrawElements = function ( mode, indices ) {
|
||||
this.mode = PrimitiveSet.POINTS;
|
||||
if ( mode !== undefined ) {
|
||||
if ( typeof ( mode ) === 'string' ) {
|
||||
mode = PrimitiveSet[ mode ];
|
||||
}
|
||||
this.mode = mode;
|
||||
}
|
||||
this.count = 0;
|
||||
this.offset = 0;
|
||||
this.indices = indices;
|
||||
this.uType = DrawElements.UNSIGNED_SHORT;
|
||||
if ( indices !== undefined ) {
|
||||
this.setIndices( indices );
|
||||
}
|
||||
};
|
||||
|
||||
DrawElements.UNSIGNED_BYTE = 0x1401;
|
||||
DrawElements.UNSIGNED_SHORT = 0x1403;
|
||||
DrawElements.UNSIGNED_INT = 0x1405;
|
||||
|
||||
/** @lends DrawElements.prototype */
|
||||
DrawElements.prototype = {
|
||||
getMode: function () {
|
||||
return this.mode;
|
||||
},
|
||||
draw: function ( state ) {
|
||||
if ( this.count === 0 )
|
||||
return;
|
||||
state.setIndexArray( this.indices );
|
||||
this.drawElements( state );
|
||||
},
|
||||
drawElements: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
gl.drawElements( this.mode, this.count, this.uType, this.offset );
|
||||
},
|
||||
setIndices: function ( indices ) {
|
||||
this.indices = indices;
|
||||
var elts = indices.getElements();
|
||||
this.count = elts.length;
|
||||
|
||||
var nbBytes = elts.BYTES_PER_ELEMENT;
|
||||
if ( nbBytes === 1 ) this.uType = DrawElements.UNSIGNED_BYTE;
|
||||
else if ( nbBytes === 2 ) this.uType = DrawElements.UNSIGNED_SHORT;
|
||||
else if ( nbBytes === 4 ) this.uType = DrawElements.UNSIGNED_INT;
|
||||
},
|
||||
getIndices: function () {
|
||||
return this.indices;
|
||||
},
|
||||
setFirst: function ( val ) {
|
||||
this.offset = val;
|
||||
},
|
||||
getFirst: function () {
|
||||
return this.offset;
|
||||
},
|
||||
setCount: function ( val ) {
|
||||
this.count = val;
|
||||
},
|
||||
getCount: function () {
|
||||
return this.count;
|
||||
},
|
||||
getNumIndices: function () {
|
||||
return this.indices.getElements().length;
|
||||
},
|
||||
index: function ( i ) {
|
||||
return this.indices.getElements()[ i ];
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
DrawElements.create = function ( mode, indices ) {
|
||||
Notify.log( 'DrawElements.create is deprecated, use new DrawElements with same arguments' );
|
||||
return new DrawElements( mode, indices );
|
||||
};
|
||||
|
||||
module.exports = DrawElements;
|
|
@ -1,140 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
|
||||
|
||||
var EllipsoidModel = function () {
|
||||
this._radiusEquator = EllipsoidModel.WGS_84_RADIUS_EQUATOR;
|
||||
this._radiusPolar = EllipsoidModel.WGS_84_RADIUS_POLAR;
|
||||
this.computeCoefficients();
|
||||
};
|
||||
|
||||
EllipsoidModel.WGS_84_RADIUS_EQUATOR = 6378137.0;
|
||||
EllipsoidModel.WGS_84_RADIUS_POLAR = 6356752.3142;
|
||||
|
||||
EllipsoidModel.prototype = {
|
||||
setRadiusEquator: function ( radius ) {
|
||||
this._radiusEquator = radius;
|
||||
this.computeCoefficients();
|
||||
},
|
||||
getRadiusEquator: function () {
|
||||
return this._radiusEquator;
|
||||
},
|
||||
setRadiusPolar: function ( radius ) {
|
||||
this._radiusPolar = radius;
|
||||
this.computeCoefficients();
|
||||
},
|
||||
getRadiusPolar: function () {
|
||||
return this._radiusPolar;
|
||||
},
|
||||
convertLatLongHeightToXYZ: function ( latitude, longitude, height, result ) {
|
||||
if ( result === undefined ) {
|
||||
Notify.warn( 'deprecated, use this signature convertLatLongHeightToXYZ( latitude, longitude, height, result )' );
|
||||
result = vec3.create();
|
||||
}
|
||||
var sinLatitude = Math.sin( latitude );
|
||||
var cosLatitude = Math.cos( latitude );
|
||||
var N = this._radiusEquator / Math.sqrt( 1.0 - this._eccentricitySquared * sinLatitude * sinLatitude );
|
||||
var X = ( N + height ) * cosLatitude * Math.cos( longitude );
|
||||
var Y = ( N + height ) * cosLatitude * Math.sin( longitude );
|
||||
var Z = ( N * ( 1.0 - this._eccentricitySquared ) + height ) * sinLatitude;
|
||||
result[ 0 ] = X;
|
||||
result[ 1 ] = Y;
|
||||
result[ 2 ] = Z;
|
||||
return result;
|
||||
},
|
||||
convertXYZToLatLongHeight: function ( X, Y, Z, result ) {
|
||||
if ( result === undefined ) {
|
||||
Notify.warn( 'deprecated, use this signature convertXYZToLatLongHeight( X, Y, Z , result)' );
|
||||
result = vec3.create();
|
||||
}
|
||||
// http://www.colorado.edu/geography/gcraft/notes/datum/gif/xyzllh.gif
|
||||
var p = Math.sqrt( X * X + Y * Y );
|
||||
var theta = Math.atan2( Z * this._radiusEquator, ( p * this._radiusPolar ) );
|
||||
var eDashSquared = ( this._radiusEquator * this._radiusEquator - this._radiusPolar * this._radiusPolar ) / ( this._radiusPolar * this._radiusPolar );
|
||||
|
||||
var sinTheta = Math.sin( theta );
|
||||
var cosTheta = Math.cos( theta );
|
||||
|
||||
var latitude = Math.atan( ( Z + eDashSquared * this._radiusPolar * sinTheta * sinTheta * sinTheta ) /
|
||||
( p - this._eccentricitySquared * this._radiusEquator * cosTheta * cosTheta * cosTheta ) );
|
||||
var longitude = Math.atan2( Y, X );
|
||||
|
||||
var sinLatitude = Math.sin( latitude );
|
||||
var N = this._radiusEquator / Math.sqrt( 1.0 - this._eccentricitySquared * sinLatitude * sinLatitude );
|
||||
|
||||
var cosLat = Math.cos( latitude );
|
||||
if ( cosLat === 0 ) cosLat = 1;
|
||||
var height = p / cosLat - N;
|
||||
result[ 0 ] = latitude;
|
||||
result[ 1 ] = longitude;
|
||||
result[ 2 ] = height;
|
||||
return result;
|
||||
},
|
||||
computeLocalUpVector: function ( X, Y, Z ) {
|
||||
// Note latitude is angle between normal to ellipsoid surface and XY-plane
|
||||
var latitude, longitude, altitude;
|
||||
var coord = this.convertXYZToLatLongHeight( X, Y, Z, latitude, longitude, altitude );
|
||||
latitude = coord[ 0 ];
|
||||
longitude = coord[ 1 ];
|
||||
altitude = coord[ 2 ];
|
||||
|
||||
// Compute up vector
|
||||
return [ Math.cos( longitude ) * Math.cos( latitude ),
|
||||
Math.sin( longitude ) * Math.cos( latitude ),
|
||||
Math.sin( latitude )
|
||||
];
|
||||
},
|
||||
isWGS84: function () {
|
||||
return ( this._radiusEquator === EllipsoidModel.WGS_84_RADIUS_EQUATOR && this._radiusPolar === EllipsoidModel.WGS_84_RADIUS_POLAR );
|
||||
},
|
||||
|
||||
computeCoefficients: function () {
|
||||
var flattening = ( this._radiusEquator - this._radiusPolar ) / this._radiusEquator;
|
||||
this._eccentricitySquared = 2.0 * flattening - flattening * flattening;
|
||||
},
|
||||
computeLocalToWorldTransformFromLatLongHeight: function ( latitude, longitude, height, result ) {
|
||||
if ( result === undefined ) {
|
||||
Notify.warn( 'deprecated, use this signature computeLocalToWorldTransformFromLatLongHeight(latitude, longitude, height, result)' );
|
||||
result = mat4.create();
|
||||
}
|
||||
var pos = this.convertLatLongHeightToXYZ( latitude, longitude, height, result );
|
||||
mat4.fromTranslation( result, pos );
|
||||
this.computeCoordinateFrame( latitude, longitude, result );
|
||||
return result;
|
||||
},
|
||||
computeLocalToWorldTransformFromXYZ: function ( X, Y, Z ) {
|
||||
var lla = this.convertXYZToLatLongHeight( X, Y, Z );
|
||||
var m = mat4.fromTranslation( mat4.create(), vec3.fromValues( X, Y, Z ) );
|
||||
this.computeCoordinateFrame( lla[ 0 ], lla[ 1 ], m );
|
||||
return m;
|
||||
},
|
||||
computeCoordinateFrame: ( function () {
|
||||
var up = vec3.create();
|
||||
var east = vec3.create();
|
||||
var north = vec3.create();
|
||||
return function ( latitude, longitude, localToWorld ) {
|
||||
// Compute up vector
|
||||
up[ 0 ] = Math.cos( longitude ) * Math.cos( latitude );
|
||||
up[ 1 ] = Math.sin( longitude ) * Math.cos( latitude );
|
||||
up[ 2 ] = Math.sin( latitude );
|
||||
|
||||
// Compute east vector
|
||||
east[ 0 ] = -Math.sin( longitude );
|
||||
east[ 1 ] = -Math.cos( longitude );
|
||||
|
||||
// Compute north vector = outer product up x east
|
||||
vec3.cross( north, up, east );
|
||||
|
||||
// set matrix
|
||||
mat4.set( localToWorld,
|
||||
east[ 0 ], east[ 1 ], east[ 2 ], 0,
|
||||
north[ 0 ], north[ 1 ], north[ 2 ], 0,
|
||||
up[ 0 ], up[ 1 ], up[ 2 ], 0,
|
||||
0, 0, 0, 1 );
|
||||
};
|
||||
} )()
|
||||
};
|
||||
|
||||
module.exports = EllipsoidModel;
|
|
@ -1,351 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var GLObject = require( 'osg/GLObject' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var Timer = require( 'osg/Timer' );
|
||||
var WebglCaps = require( 'osg/WebGLCaps' );
|
||||
|
||||
/**
|
||||
* FrameBufferObject manage fbo / rtt
|
||||
* @class FrameBufferObject
|
||||
*/
|
||||
var FrameBufferObject = function () {
|
||||
|
||||
GLObject.call( this );
|
||||
StateAttribute.call( this );
|
||||
this._fbo = undefined;
|
||||
this._rbo = undefined;
|
||||
this._attachments = [];
|
||||
this._dirty = true;
|
||||
|
||||
};
|
||||
|
||||
FrameBufferObject.COLOR_ATTACHMENT0 = 0x8CE0;
|
||||
FrameBufferObject.DEPTH_ATTACHMENT = 0x8D00;
|
||||
FrameBufferObject.DEPTH_COMPONENT16 = 0x81A5;
|
||||
// static cache of glFrameBuffer flagged for deletion, which will actually
|
||||
// be deleted in the correct GL context.
|
||||
FrameBufferObject._sDeletedGLFrameBufferCache = new window.Map();
|
||||
|
||||
// static method to delete FrameBuffers
|
||||
FrameBufferObject.deleteGLFrameBuffer = function ( gl, fb ) {
|
||||
|
||||
if ( !FrameBufferObject._sDeletedGLFrameBufferCache.has( gl ) )
|
||||
FrameBufferObject._sDeletedGLFrameBufferCache.set( gl, [] );
|
||||
|
||||
FrameBufferObject._sDeletedGLFrameBufferCache.get( gl ).push( fb );
|
||||
};
|
||||
|
||||
// static method to flush all the cached glFrameBuffers which need to be deleted in the GL context specified
|
||||
FrameBufferObject.flushDeletedGLFrameBuffers = function ( gl, availableTime ) {
|
||||
|
||||
// if no time available don't try to flush objects.
|
||||
if ( availableTime <= 0.0 ) return availableTime;
|
||||
|
||||
if ( !FrameBufferObject._sDeletedGLFrameBufferCache.has( gl ) ) return availableTime;
|
||||
|
||||
var elapsedTime = 0.0;
|
||||
var beginTime = Timer.instance().tick();
|
||||
var deleteList = FrameBufferObject._sDeletedGLFrameBufferCache.get( gl );
|
||||
var numBuffers = deleteList.length;
|
||||
|
||||
for ( var i = numBuffers - 1; i >= 0 && elapsedTime < availableTime; i-- ) {
|
||||
gl.deleteFramebuffer( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
elapsedTime = Timer.instance().deltaS( beginTime, Timer.instance().tick() );
|
||||
}
|
||||
|
||||
return availableTime - elapsedTime;
|
||||
};
|
||||
|
||||
FrameBufferObject.flushAllDeletedGLFrameBuffers = function ( gl ) {
|
||||
|
||||
if ( !FrameBufferObject._sDeletedGLFrameBufferCache.has( gl ) ) return;
|
||||
|
||||
var deleteList = FrameBufferObject._sDeletedGLFrameBufferCache.get( gl );
|
||||
var numBuffers = deleteList.length;
|
||||
|
||||
for ( var i = numBuffers - 1; i >= 0; i-- ) {
|
||||
gl.deleteFramebuffer( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// static cache of glRenderBuffer flagged for deletion, which will actually
|
||||
// be deleted in the correct GL context.
|
||||
FrameBufferObject._sDeletedGLRenderBufferCache = new window.Map();
|
||||
|
||||
// static method to delete RenderBuffers
|
||||
FrameBufferObject.deleteGLRenderBuffer = function ( gl, fb ) {
|
||||
|
||||
if ( !FrameBufferObject._sDeletedGLRenderBufferCache.has( gl ) )
|
||||
FrameBufferObject._sDeletedGLRenderBufferCache.set( gl, [] );
|
||||
|
||||
FrameBufferObject._sDeletedGLRenderBufferCache.get( gl ).push( fb );
|
||||
};
|
||||
|
||||
|
||||
// static method to flush all the cached glRenderBuffers which need to be deleted in the GL context specified
|
||||
FrameBufferObject.flushDeletedGLRenderBuffers = function ( gl, availableTime ) {
|
||||
|
||||
// if no time available don't try to flush objects.
|
||||
if ( availableTime <= 0.0 ) return availableTime;
|
||||
|
||||
if ( !FrameBufferObject._sDeletedGLRenderBufferCache.has( gl ) ) return availableTime;
|
||||
|
||||
var elapsedTime = 0.0;
|
||||
var beginTime = Timer.instance().tick();
|
||||
var deleteList = FrameBufferObject._sDeletedGLRenderBufferCache.get( gl );
|
||||
var numBuffers = deleteList.length;
|
||||
|
||||
for ( var i = numBuffers - 1; i >= 0 && elapsedTime < availableTime; i-- ) {
|
||||
gl.deleteRenderbuffer( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
elapsedTime = Timer.instance().deltaS( beginTime, Timer.instance().tick() );
|
||||
}
|
||||
|
||||
return availableTime - elapsedTime;
|
||||
};
|
||||
|
||||
FrameBufferObject.flushAllDeletedGLRenderBuffers = function ( gl ) {
|
||||
|
||||
if ( !FrameBufferObject._sDeletedGLRenderBufferCache.has( gl ) ) return;
|
||||
|
||||
var deleteList = FrameBufferObject._sDeletedGLRenderBufferCache.get( gl );
|
||||
var numBuffers = deleteList.length;
|
||||
|
||||
for ( var i = numBuffers - 1; i >= 0; i-- ) {
|
||||
gl.deleteRenderbuffer( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
}
|
||||
};
|
||||
|
||||
/** @lends FrameBufferObject.prototype */
|
||||
FrameBufferObject.prototype = MACROUTILS.objectInherit( GLObject.prototype, MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'FrameBufferObject',
|
||||
|
||||
cloneType: function () {
|
||||
return new FrameBufferObject();
|
||||
},
|
||||
|
||||
dirty: function () {
|
||||
this._dirty = true;
|
||||
},
|
||||
|
||||
isDirty: function () {
|
||||
return this._dirty;
|
||||
},
|
||||
|
||||
setAttachment: function ( attachment ) {
|
||||
this._attachments.push( attachment );
|
||||
},
|
||||
|
||||
releaseGLObjects: function () {
|
||||
|
||||
if ( this._fbo !== undefined && this._gl !== undefined ) {
|
||||
FrameBufferObject.deleteGLFrameBuffer( this._gl, this._fbo );
|
||||
}
|
||||
this._fbo = undefined;
|
||||
|
||||
if ( this._rbo !== undefined && this._gl !== undefined ) {
|
||||
FrameBufferObject.deleteGLRenderBuffer( this._gl, this._rbo );
|
||||
}
|
||||
this._rbo = undefined;
|
||||
|
||||
},
|
||||
|
||||
_reportFrameBufferError: function ( code ) {
|
||||
switch ( code ) {
|
||||
case 0x8CD6:
|
||||
Notify.debug( 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT' );
|
||||
break;
|
||||
case 0x8CD7:
|
||||
Notify.debug( 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT' );
|
||||
break;
|
||||
case 0x8CD9:
|
||||
Notify.debug( 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS' );
|
||||
break;
|
||||
case 0x8CDD:
|
||||
Notify.debug( 'FRAMEBUFFER_UNSUPPORTED' );
|
||||
break;
|
||||
default:
|
||||
Notify.debug( 'FRAMEBUFFER unknown error ' + code.toString( 16 ) );
|
||||
}
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
this.releaseGLObjects();
|
||||
this._attachments = [];
|
||||
},
|
||||
|
||||
getFrameBufferObject: function () {
|
||||
return this._fbo;
|
||||
},
|
||||
|
||||
createFrameBufferObject: function ( state ) {
|
||||
this.setGraphicContext( state.getGraphicContext() );
|
||||
this._fbo = this._gl.createFramebuffer();
|
||||
},
|
||||
|
||||
createRenderBuffer: function ( format, width, height ) {
|
||||
var gl = this._gl;
|
||||
var renderBuffer = gl.createRenderbuffer();
|
||||
gl.bindRenderbuffer( gl.RENDERBUFFER, renderBuffer );
|
||||
gl.renderbufferStorage( gl.RENDERBUFFER, format, width, height );
|
||||
|
||||
return renderBuffer;
|
||||
},
|
||||
|
||||
framebufferRenderBuffer: function ( attachment, renderBuffer ) {
|
||||
|
||||
var gl = this._gl;
|
||||
gl.bindRenderbuffer( gl.RENDERBUFFER, renderBuffer );
|
||||
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderBuffer );
|
||||
|
||||
/* develblock:start */
|
||||
// only visible with webgl-insector enabled
|
||||
if ( gl.rawgl !== undefined ) {
|
||||
Notify.log( 'FBO: renderBuffer: ' + this._fbo.trackedObject.defaultName );
|
||||
}
|
||||
/* develblock:end */
|
||||
},
|
||||
|
||||
framebufferTexture2D: function ( state, attachment, textureTarget, texture ) {
|
||||
|
||||
var gl = this._gl;
|
||||
|
||||
// apply on unit 1 to init it
|
||||
// make sure we do bind it whatever state stack
|
||||
// texture is cached
|
||||
state.applyTextureAttribute( 1, texture );
|
||||
|
||||
if ( texture.isDirty() || !texture.getTextureObject() ) {
|
||||
// image wasn't ready, texture not allocated due to lack of gpu MEM
|
||||
return false;
|
||||
}
|
||||
|
||||
gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, textureTarget, texture.getTextureObject().id(), 0 );
|
||||
|
||||
/* develblock:start */
|
||||
// only visible with webgl-insector enabled
|
||||
// allow trace debug (fb<->texture link)
|
||||
if ( gl.rawgl !== undefined ) {
|
||||
Notify.log( 'FBO: texture: ' + texture.getName() + ' : ' + texture.getTextureObject().id().trackedObject.defaultName + ' fbo: ' + this._fbo.trackedObject.defaultName );
|
||||
}
|
||||
/* develblock:end */
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
bindFrameBufferObject: function () {
|
||||
var gl = this._gl;
|
||||
gl.bindFramebuffer( gl.FRAMEBUFFER, this._fbo );
|
||||
},
|
||||
|
||||
checkStatus: function () {
|
||||
|
||||
var gl = this._gl;
|
||||
var status = gl.checkFramebufferStatus( gl.FRAMEBUFFER );
|
||||
if ( status !== 0x8CD5 ) {
|
||||
this._reportFrameBufferError( status );
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_checkAllowedSize: function ( w, h ) {
|
||||
|
||||
var maxSize = WebglCaps.instance().getWebGLParameter( 'MAX_RENDERBUFFER_SIZE' );
|
||||
|
||||
if ( w === 0 || h === 0 || h > maxSize || w > maxSize ) {
|
||||
Notify.error( 'width (' + w + ') or height (' + w + ') makes frame buffer not bindable. Max RenderBuffer is "' + maxSize + '"' );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
},
|
||||
|
||||
apply: function ( state ) {
|
||||
|
||||
if ( !this._gl ) this.setGraphicContext( state.getGraphicContext() );
|
||||
var gl = this._gl;
|
||||
|
||||
var attachments = this._attachments;
|
||||
|
||||
// if the fbo is created manually, we want to just bind it
|
||||
if ( attachments.length > 0 || this._fbo ) {
|
||||
|
||||
if ( this.isDirty() ) {
|
||||
|
||||
if ( !this._fbo )
|
||||
this.createFrameBufferObject( state );
|
||||
|
||||
this.bindFrameBufferObject();
|
||||
|
||||
var hasRenderBuffer = false;
|
||||
|
||||
for ( var i = 0, l = attachments.length; i < l; ++i ) {
|
||||
|
||||
var attachment = attachments[ i ];
|
||||
|
||||
// render buffer
|
||||
if ( !attachment.texture ) {
|
||||
|
||||
if ( !this._checkAllowedSize( attachment.width, attachment.height ) ) {
|
||||
this.releaseGLObjects();
|
||||
return;
|
||||
}
|
||||
|
||||
this._rbo = this.createRenderBuffer( attachment.format, attachment.width, attachment.height );
|
||||
this.framebufferRenderBuffer( attachment.attachment, this._rbo );
|
||||
hasRenderBuffer = true;
|
||||
|
||||
} else {
|
||||
|
||||
// use texture
|
||||
var texture = attachment.texture;
|
||||
|
||||
if ( !this._checkAllowedSize( texture.getWidth(), texture.getHeight() ) ) {
|
||||
this.releaseGLObjects();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !this.framebufferTexture2D( state, attachment.attachment, attachment.textureTarget, texture ) ) {
|
||||
this.releaseGLObjects();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.checkStatus();
|
||||
|
||||
// set it to null only if used renderbuffer
|
||||
if ( hasRenderBuffer )
|
||||
gl.bindRenderbuffer( gl.RENDERBUFFER, null );
|
||||
|
||||
this._dirty = false;
|
||||
|
||||
} else {
|
||||
|
||||
gl.bindFramebuffer( gl.FRAMEBUFFER, this._fbo );
|
||||
|
||||
if ( Notify.reportWebGLError === true )
|
||||
this.checkStatus();
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
|
||||
}
|
||||
}
|
||||
} ) );
|
||||
|
||||
|
||||
module.exports = FrameBufferObject;
|
|
@ -1,37 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var FrameStamp = function () {
|
||||
this._frame = 0;
|
||||
this._startSimulation = 0.0;
|
||||
this._currentSimulation = 0.0;
|
||||
this._deltaTime = 0.0; // last time elapsed since the next traversal
|
||||
};
|
||||
|
||||
FrameStamp.prototype = {
|
||||
setReferenceTime: function ( s ) {
|
||||
this._startSimulation = s;
|
||||
},
|
||||
getReferenceTime: function () {
|
||||
return this._startSimulation;
|
||||
},
|
||||
setSimulationTime: function ( s ) {
|
||||
this._currentSimulation = s;
|
||||
},
|
||||
getSimulationTime: function () {
|
||||
return this._currentSimulation;
|
||||
},
|
||||
setDeltaTime: function ( d ) {
|
||||
this._deltaTime = d;
|
||||
},
|
||||
getDeltaTime: function () {
|
||||
return this._deltaTime;
|
||||
},
|
||||
setFrameNumber: function ( n ) {
|
||||
this._frame = n;
|
||||
},
|
||||
getFrameNumber: function () {
|
||||
return this._frame;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = FrameStamp;
|
|
@ -1,19 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
// Base class for GLResources: Textures, Buffers, Programs, Shaders, FrameBuffers and RenderBuffers
|
||||
// It holds a reference to the graphic context that is needed for resource deletion
|
||||
|
||||
var GLObject = function () {
|
||||
this._gl = undefined;
|
||||
};
|
||||
|
||||
GLObject.prototype = {
|
||||
setGraphicContext: function ( gl ) {
|
||||
this._gl = gl;
|
||||
},
|
||||
getGraphicContext: function () {
|
||||
return this._gl;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = GLObject;
|
|
@ -1,474 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Node = require( 'osg/Node' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var WebGLCaps = require( 'osg/WebGLCaps' );
|
||||
var DrawElements = require( 'osg/DrawElements' );
|
||||
var BufferArrayProxy = require( 'osg/BufferArrayProxy' );
|
||||
|
||||
/**
|
||||
* Geometry manage array and primitives to draw a geometry.
|
||||
* @class Geometry
|
||||
*/
|
||||
|
||||
var Geometry = function () {
|
||||
|
||||
Node.call( this );
|
||||
|
||||
// Use proxy to detect change in vertex attributes
|
||||
// you should use setVertexAttribute but if you dont
|
||||
if ( window.Proxy ) {
|
||||
|
||||
var self = this;
|
||||
|
||||
this._attributes = {};
|
||||
this._primitives = [];
|
||||
this.attributes = new Proxy( this._attributes, {
|
||||
set: function ( obj, prop, value ) {
|
||||
var old = obj[ prop ];
|
||||
if ( old !== value ) {
|
||||
obj[ prop ] = value;
|
||||
self.dirty();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} );
|
||||
|
||||
var push = function () {
|
||||
this.push.apply( this, arguments );
|
||||
self.dirty();
|
||||
|
||||
}.bind( this._primitives );
|
||||
|
||||
var pop = function () {
|
||||
this.pop();
|
||||
self.dirty();
|
||||
|
||||
}.bind( this._primitives );
|
||||
|
||||
this.primitives = new Proxy( this._primitives, {
|
||||
get: function ( obj, key ) {
|
||||
if ( key === 'push' ) return push;
|
||||
if ( key === 'pop' ) return pop;
|
||||
return obj[ key ];
|
||||
}
|
||||
} );
|
||||
|
||||
} else {
|
||||
|
||||
this.attributes = {};
|
||||
this.primitives = [];
|
||||
this._primitives = this.primitives;
|
||||
this._attributes = this.attributes;
|
||||
|
||||
}
|
||||
|
||||
// function is generated for each Shader Program ID
|
||||
// which generates a a special "draw"
|
||||
// TODO: could be upon hash of combination of attributes
|
||||
// (as multiple shader Programs can use same combination of attributes)
|
||||
this._cacheDrawCall = {};
|
||||
|
||||
// VAO cached data, per combination of vertex buffer
|
||||
// program id also the cache key
|
||||
this._extVAO = undefined;
|
||||
this._vao = {};
|
||||
this._cacheVertexAttributeBufferList = {};
|
||||
|
||||
// null means the kdTree builder will skip the kdTree creation
|
||||
this._shape = undefined;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* enableVAO flag
|
||||
* We rely on Proxy to detect changes in vertextes attributes list or in primitives
|
||||
* list. If you dont have Proxy and you still want to use the VAO code path, replace
|
||||
* OSG.osg.Geometry.enableVAO = true at the begining of your application, but be sure to
|
||||
* not change vertexes attributes without calling dirty after.
|
||||
*/
|
||||
Geometry.enableVAO = Boolean( window.Proxy );
|
||||
if ( Geometry.enableVAO ) Notify.info( 'enable VAO' );
|
||||
|
||||
|
||||
/** @lends Geometry.prototype */
|
||||
Geometry.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Node.prototype, {
|
||||
|
||||
releaseGLObjects: function () {
|
||||
|
||||
if ( this.stateset !== undefined ) this.stateset.releaseGLObjects();
|
||||
|
||||
var keys = window.Object.keys( this._attributes );
|
||||
var value;
|
||||
var i, l;
|
||||
|
||||
for ( i = 0, l = keys.length; i < l; i++ ) {
|
||||
value = this._attributes[ keys[ i ] ];
|
||||
value.releaseGLObjects();
|
||||
}
|
||||
|
||||
for ( var j = 0, h = this._primitives.length; j < h; j++ ) {
|
||||
var prim = this._primitives[ j ];
|
||||
if ( prim.getIndices !== undefined ) {
|
||||
if ( prim.getIndices() !== undefined && prim.getIndices() !== null ) {
|
||||
prim.indices.releaseGLObjects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.releaseVAO();
|
||||
|
||||
},
|
||||
|
||||
releaseVAO: function () {
|
||||
|
||||
if ( !this._extVAO ) return;
|
||||
|
||||
var keys = window.Object.keys( this._vao );
|
||||
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
||||
var prgID = keys[ i ];
|
||||
if ( this._vao[ prgID ] ) {
|
||||
var vao = this._vao[ prgID ];
|
||||
this._extVAO.deleteVertexArrayOES( vao );
|
||||
this._vao[ prgID ] = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
dirty: function () {
|
||||
this._cacheDrawCall = {};
|
||||
this.releaseVAO();
|
||||
},
|
||||
|
||||
getPrimitives: function () {
|
||||
// Notify.warn( 'deprecated use instead getPrimitiveSetList' );
|
||||
return this.getPrimitiveSetList();
|
||||
},
|
||||
|
||||
getAttributes: function () {
|
||||
// Notify.warn( 'deprecated use instead getVertexAttributeList' );
|
||||
return this.getVertexAttributeList();
|
||||
},
|
||||
|
||||
getShape: function () {
|
||||
return this._shape;
|
||||
},
|
||||
|
||||
setShape: function ( shape ) {
|
||||
this._shape = shape;
|
||||
},
|
||||
|
||||
getVertexAttributeList: function () {
|
||||
return this.attributes;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the primitiveset list
|
||||
* If you modify something inside this array
|
||||
* you must call dirty() on the Geometry
|
||||
*/
|
||||
getPrimitiveSetList: function () {
|
||||
return this.primitives;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the buffer array on the attribute name key
|
||||
* key is often something like Vertex, Normal, Color, ...
|
||||
* for classic geometry
|
||||
*
|
||||
* if you change a buffer a dirty will be automatically
|
||||
* called to rebuild the VAO if needed.
|
||||
*/
|
||||
setVertexAttribArray: function ( key, array ) {
|
||||
if ( this._attributes[ key ] !== array ) {
|
||||
this._attributes[ key ] = array;
|
||||
this.dirty();
|
||||
}
|
||||
},
|
||||
|
||||
_generateVertexSetup: function ( validAttributeKeyList, validAttributeIndexList, includeFirstIndexBuffer ) {
|
||||
|
||||
// generate setup for vertex attribute
|
||||
// will be used as setup for vao or as is without vao
|
||||
var vertexAttributeSetup = [ '//generated by Geometry::implementation',
|
||||
'state.lazyDisablingOfVertexAttributes();',
|
||||
'var attr;'
|
||||
];
|
||||
|
||||
for ( var i = 0, l = validAttributeKeyList.length; i < l; i++ ) {
|
||||
|
||||
vertexAttributeSetup.push( 'attr = this._attributes[\'' + validAttributeKeyList[ i ] + '\'];' );
|
||||
vertexAttributeSetup.push( 'if ( attr.BufferArrayProxy ) attr = attr.getBufferArray();' );
|
||||
vertexAttributeSetup.push( 'if ( !attr.isValid() ) return;' );
|
||||
vertexAttributeSetup.push( 'state.setVertexAttribArray(' + validAttributeIndexList[ i ] + ', attr, attr.getNormalize() );' );
|
||||
|
||||
}
|
||||
|
||||
vertexAttributeSetup.push( 'state.applyDisablingOfVertexAttributes();' );
|
||||
|
||||
if ( includeFirstIndexBuffer )
|
||||
vertexAttributeSetup.push( 'state.setIndexArray( this._primitives[ 0 ].getIndices() );' );
|
||||
|
||||
return vertexAttributeSetup;
|
||||
},
|
||||
|
||||
_generatePrimitive: function ( primitives, hasVertexColor, optimizeVAO ) {
|
||||
|
||||
var primitiveSetup = [
|
||||
hasVertexColor ? 'state.enableVertexColor();' : 'state.disableVertexColor();'
|
||||
];
|
||||
|
||||
if ( optimizeVAO ) {
|
||||
return primitiveSetup.concat( [
|
||||
'var primitive = this._primitives[ 0 ];',
|
||||
'var indexes = primitive.getIndices();',
|
||||
'if ( indexes.isDirty() ) {;',
|
||||
' indexes.bind( gl );',
|
||||
' indexes.compile( gl );',
|
||||
'};',
|
||||
'primitive.drawElements( state );'
|
||||
] );
|
||||
}
|
||||
|
||||
|
||||
primitiveSetup.push( 'var primitives = this._primitives;' );
|
||||
for ( var j = 0, m = primitives.length; j < m; j++ )
|
||||
primitiveSetup.push( 'primitives[' + j + '].draw(state);' );
|
||||
|
||||
return primitiveSetup;
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a function specific to the Geometry/Program
|
||||
* two version one using VAO and a regular one
|
||||
*/
|
||||
generateDrawCommand: ( function () {
|
||||
|
||||
var validAttributeList = [];
|
||||
var validAttributeKeyList = [];
|
||||
|
||||
return function ( state, program, prgID ) {
|
||||
|
||||
var attributesCacheKeys = program._attributesCache.getKeys();
|
||||
var attributesCacheMap = program._attributesCache;
|
||||
var geometryVertexAttributes = this.getVertexAttributeList();
|
||||
|
||||
validAttributeKeyList.length = 0;
|
||||
validAttributeList.length = 0;
|
||||
|
||||
// 1 - register valid vertex attributes and color flag
|
||||
|
||||
var attribute, i, l, j, m, key, attr;
|
||||
|
||||
var extVAO = this._extVAO;
|
||||
var listVABuff = extVAO ? [] : undefined;
|
||||
|
||||
var hasVertexColor = false;
|
||||
|
||||
for ( i = 0, l = attributesCacheKeys.length; i < l; i++ ) {
|
||||
|
||||
key = attributesCacheKeys[ i ];
|
||||
attribute = attributesCacheMap[ key ];
|
||||
attr = geometryVertexAttributes[ key ];
|
||||
|
||||
if ( attr === undefined ) continue;
|
||||
|
||||
var attributeBuffer = this._attributes[ key ];
|
||||
|
||||
// dont use VAO if we have BufferArrayProxy
|
||||
// typically used for morphing
|
||||
if ( attributeBuffer instanceof BufferArrayProxy ) {
|
||||
attributeBuffer = attributeBuffer.getBufferArray();
|
||||
extVAO = false;
|
||||
}
|
||||
|
||||
if ( !attributeBuffer.isValid() ) return undefined;
|
||||
|
||||
// store for later usage at draw time/update
|
||||
if ( extVAO ) listVABuff.push( attributeBuffer );
|
||||
|
||||
if ( !hasVertexColor && key === 'Color' )
|
||||
hasVertexColor = true;
|
||||
|
||||
validAttributeKeyList.push( key );
|
||||
validAttributeList.push( attribute );
|
||||
}
|
||||
|
||||
|
||||
var autogeneratedFunction;
|
||||
var functionName;
|
||||
|
||||
// generate specific function using VAO or standard
|
||||
if ( extVAO ) {
|
||||
|
||||
this._cacheVertexAttributeBufferList[ prgID ] = listVABuff;
|
||||
|
||||
// if there is only one drawElement we can put the index buffer
|
||||
// in the vao
|
||||
var optimizeIndexBufferVAO = ( this._primitives.length === 1 && this._primitives[ 0 ] instanceof DrawElements );
|
||||
|
||||
var vertexAttributeSetup = this._generateVertexSetup( validAttributeKeyList, validAttributeList, optimizeIndexBufferVAO );
|
||||
|
||||
state.clearVertexAttribCache();
|
||||
var vao = this._extVAO.createVertexArrayOES();
|
||||
state.setVertexArrayObject( vao );
|
||||
this._vao[ prgID ] = vao;
|
||||
|
||||
// evaluate the vertexAttribute setup to register into the vao
|
||||
/*jshint evil: true */
|
||||
var vertexSetupCommand = new Function( 'state', vertexAttributeSetup.join( '\n' ) );
|
||||
/*jshint evil: false */
|
||||
vertexSetupCommand.call( this, state );
|
||||
|
||||
// setup the program
|
||||
var vaoSetup = [
|
||||
'var gl = state.getGraphicContext();',
|
||||
'var vao = this._vao[ ' + prgID + ' ] ',
|
||||
'var hasChanged = state.setVertexArrayObject( vao );',
|
||||
'if ( hasChanged ) {',
|
||||
' var vaList = this._cacheVertexAttributeBufferList[ ' + prgID + ' ];',
|
||||
' var va;'
|
||||
];
|
||||
for ( j = 0, m = listVABuff.length; j < m; j++ ) {
|
||||
vaoSetup.push( ' va = vaList[ ' + j + '];' );
|
||||
vaoSetup.push( ' if ( va.isDirty() ) {;' );
|
||||
vaoSetup.push( ' va.bind( gl );' );
|
||||
vaoSetup.push( ' va.compile( gl );' );
|
||||
vaoSetup.push( ' };' );
|
||||
}
|
||||
vaoSetup.push( '}' );
|
||||
|
||||
autogeneratedFunction = vaoSetup.concat( this._generatePrimitive( this._primitives, hasVertexColor, optimizeIndexBufferVAO ) ).join( '\n' );
|
||||
functionName = 'GeometryDrawImplementationCacheVAO';
|
||||
|
||||
} else {
|
||||
|
||||
autogeneratedFunction = this._generateVertexSetup( validAttributeKeyList, validAttributeList, false ).concat( this._generatePrimitive( this._primitives, hasVertexColor, false ) ).join( '\n' );
|
||||
functionName = 'GeometryDrawImplementationCache';
|
||||
|
||||
}
|
||||
|
||||
/*jshint evil: true */
|
||||
// name the function
|
||||
// http://stackoverflow.com/questions/5905492/dynamic-function-name-in-javascript
|
||||
var drawCommand = ( new Function( 'state', 'return function ' + functionName + '( state ) { ' + autogeneratedFunction + '}' ) )();
|
||||
/*jshint evil: false */
|
||||
|
||||
this._cacheDrawCall[ prgID ] = drawCommand;
|
||||
return drawCommand;
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
drawImplementation: function ( state ) {
|
||||
|
||||
var program = state.getLastProgramApplied();
|
||||
var prgID = program.getInstanceID();
|
||||
|
||||
var cachedDraw = this._cacheDrawCall[ prgID ];
|
||||
|
||||
// most of the time we should use vao
|
||||
if ( this._extVAO && !this._vao[ prgID ] ) state.setVertexArrayObject( null );
|
||||
|
||||
if ( cachedDraw === undefined ) {
|
||||
|
||||
if ( !this._primitives.length ) return;
|
||||
|
||||
// no cache for this combination of vertex attributes
|
||||
// compute new Draw Call
|
||||
|
||||
if ( this._extVAO === undefined && Geometry.enableVAO ) { // will be null if not supported
|
||||
var extVAO = WebGLCaps.instance( state.getGraphicContext() ).getWebGLExtension( 'OES_vertex_array_object' );
|
||||
this._extVAO = extVAO;
|
||||
}
|
||||
|
||||
cachedDraw = this.generateDrawCommand( state, program, prgID );
|
||||
}
|
||||
|
||||
cachedDraw.call( this, state );
|
||||
|
||||
},
|
||||
|
||||
setBound: function ( bb ) {
|
||||
this._boundingBox = bb;
|
||||
this._boundingBoxComputed = true;
|
||||
},
|
||||
|
||||
computeBoundingBox: function ( boundingBox ) {
|
||||
|
||||
boundingBox.init();
|
||||
|
||||
var vertexArray = this.getVertexAttributeList().Vertex;
|
||||
if ( vertexArray && vertexArray.getElements() && vertexArray.getItemSize() > 2 ) {
|
||||
var vertexes = vertexArray.getElements();
|
||||
var itemSize = vertexArray.getItemSize();
|
||||
|
||||
var min = boundingBox.getMin();
|
||||
var max = boundingBox.getMax();
|
||||
|
||||
var minx = min[ 0 ];
|
||||
var miny = min[ 1 ];
|
||||
var minz = min[ 2 ];
|
||||
var maxx = max[ 0 ];
|
||||
var maxy = max[ 1 ];
|
||||
var maxz = max[ 2 ];
|
||||
|
||||
// if the box is un-initialized min=Inf and max=-Inf
|
||||
// we can't simply write if(x > min) [...] else (x < max) [...]
|
||||
// most of the time the else condition is run so it's a kinda useless
|
||||
// optimization anyway
|
||||
for ( var idx = 0, l = vertexes.length; idx < l; idx += itemSize ) {
|
||||
var v1 = vertexes[ idx ];
|
||||
var v2 = vertexes[ idx + 1 ];
|
||||
var v3 = vertexes[ idx + 2 ];
|
||||
if ( v1 < minx ) minx = v1;
|
||||
if ( v1 > maxx ) maxx = v1;
|
||||
if ( v2 < miny ) miny = v2;
|
||||
if ( v2 > maxy ) maxy = v2;
|
||||
if ( v3 < minz ) minz = v3;
|
||||
if ( v3 > maxz ) maxz = v3;
|
||||
}
|
||||
|
||||
min[ 0 ] = minx;
|
||||
min[ 1 ] = miny;
|
||||
min[ 2 ] = minz;
|
||||
max[ 0 ] = maxx;
|
||||
max[ 1 ] = maxy;
|
||||
max[ 2 ] = maxz;
|
||||
}
|
||||
|
||||
return boundingBox;
|
||||
},
|
||||
|
||||
computeBoundingSphere: function ( boundingSphere ) {
|
||||
boundingSphere.init();
|
||||
var bb = this.getBoundingBox();
|
||||
boundingSphere.expandByBoundingBox( bb );
|
||||
return boundingSphere;
|
||||
}
|
||||
|
||||
|
||||
} ), 'osg', 'Geometry' );
|
||||
|
||||
Geometry.appendVertexAttributeToList = function ( from, to, postfix ) {
|
||||
|
||||
var keys = window.Object.keys( from );
|
||||
var key, keyPostFix;
|
||||
|
||||
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
||||
|
||||
key = keys[ i ];
|
||||
keyPostFix = key;
|
||||
if ( postfix !== undefined )
|
||||
keyPostFix += '_' + postfix;
|
||||
|
||||
to[ keyPostFix ] = from[ key ];
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
MACROUTILS.setTypeID( Geometry );
|
||||
|
||||
module.exports = Geometry;
|
|
@ -1,241 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Object = require( 'osg/Object' );
|
||||
|
||||
var ImageBitmap = window.ImageBitmap || function () {};
|
||||
|
||||
var ImageObject = function ( image ) {
|
||||
Object.call( this );
|
||||
|
||||
this._imageObject = undefined;
|
||||
this._url = undefined;
|
||||
this._width = undefined;
|
||||
this._height = undefined;
|
||||
this._dirty = true;
|
||||
this._mipmap = [];
|
||||
|
||||
if ( image ) {
|
||||
this.setImage( image );
|
||||
}
|
||||
|
||||
this._isGreyscale = undefined;
|
||||
};
|
||||
|
||||
ImageObject.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Object.prototype, {
|
||||
|
||||
dirty: function () {
|
||||
this._isGreyscale = undefined;
|
||||
this._dirty = true;
|
||||
},
|
||||
|
||||
isDirty: function () {
|
||||
return this._dirty;
|
||||
},
|
||||
|
||||
setDirty: function ( bool ) {
|
||||
this._dirty = bool;
|
||||
},
|
||||
|
||||
getImage: function () {
|
||||
return ( this._imageObject instanceof ImageObject ) ? this._imageObject.getImage() : this._imageObject;
|
||||
},
|
||||
|
||||
getURL: function () {
|
||||
return this._url;
|
||||
},
|
||||
|
||||
setURL: function ( url ) {
|
||||
this._url = url;
|
||||
},
|
||||
|
||||
useOrCreateImage: function ( img ) {
|
||||
return ( img instanceof( ImageObject ) === false ) ? new ImageObject( img ) : img;
|
||||
},
|
||||
|
||||
setImage: function ( img ) {
|
||||
if ( !this._url && img && ( img.src || img.currentSrc ) ) {
|
||||
// TODO what is currentSrc ?
|
||||
this._url = img.src || img.currentSrc;
|
||||
}
|
||||
|
||||
this._mipmap.length = 0;
|
||||
|
||||
// img can be an image or an array of image if specify the
|
||||
// all mipmap levels
|
||||
if ( Array.isArray( img ) ) {
|
||||
for ( var i = 0, nbImg = img.length; i < nbImg; i++ ) {
|
||||
this._mipmap.push( this.useOrCreateImage( img[ i ] ) );
|
||||
}
|
||||
this.setWidth( this._mipmap[ 0 ].getWidth() );
|
||||
this.setHeight( this._mipmap[ 0 ].getHeight() );
|
||||
} else {
|
||||
this._mipmap.push( img );
|
||||
}
|
||||
|
||||
this._imageObject = this._mipmap[ 0 ];
|
||||
this.dirty();
|
||||
},
|
||||
|
||||
isCanvas: function () {
|
||||
return this.getImage() instanceof window.HTMLCanvasElement;
|
||||
},
|
||||
|
||||
isBitmap: function () {
|
||||
return this.getImage() instanceof ImageBitmap;
|
||||
},
|
||||
|
||||
isVideo: function () {
|
||||
return this.getImage() instanceof window.HTMLVideoElement;
|
||||
},
|
||||
|
||||
isImage: function () {
|
||||
return this.getImage() instanceof window.Image;
|
||||
},
|
||||
|
||||
isTypedArray: function () {
|
||||
var img = this.getImage();
|
||||
return img instanceof Uint8Array || img instanceof Float32Array || img instanceof Uint16Array;
|
||||
},
|
||||
|
||||
setWidth: function ( w ) {
|
||||
this._width = w;
|
||||
},
|
||||
|
||||
setHeight: function ( h ) {
|
||||
this._height = h;
|
||||
},
|
||||
|
||||
getWidth: function () {
|
||||
var img = this.getImage();
|
||||
if ( this.isImage() ) {
|
||||
return img.naturalWidth;
|
||||
} else if ( this.isVideo() ) {
|
||||
return img.videoWidth;
|
||||
} else if ( this.isCanvas() || this.isBitmap() ) {
|
||||
return img.width;
|
||||
}
|
||||
return this._width;
|
||||
},
|
||||
|
||||
getHeight: function () {
|
||||
var img = this.getImage();
|
||||
if ( this.isImage() ) {
|
||||
return img.naturalHeight;
|
||||
} else if ( this.isVideo() ) {
|
||||
return img.videoHeight;
|
||||
} else if ( this.isCanvas() || this.isBitmap() ) {
|
||||
return img.height;
|
||||
}
|
||||
return this._height;
|
||||
},
|
||||
|
||||
isGreyscale: function ( nbSamples ) {
|
||||
if ( this._isGreyscale !== undefined )
|
||||
return this._isGreyscale;
|
||||
|
||||
if ( this._imageObject !== undefined && this.isReady() && this._isGreyscale === undefined ) {
|
||||
|
||||
var canvas = this._imageObject;
|
||||
if ( !this.isCanvas() ) {
|
||||
canvas = document.createElement( 'canvas' );
|
||||
}
|
||||
var ctx = canvas.getContext( '2d' );
|
||||
canvas.width = this._imageObject.width;
|
||||
canvas.height = this._imageObject.height;
|
||||
ctx.drawImage( this._imageObject, 0, 0 );
|
||||
|
||||
var sampleX, sampleY;
|
||||
// cap sample if needed
|
||||
if ( !nbSamples ) {
|
||||
sampleX = canvas.width;
|
||||
sampleY = canvas.height;
|
||||
}
|
||||
if ( nbSamples > 0 ) {
|
||||
nbSamples = Math.min( Math.min( canvas.width, canvas.height ), nbSamples );
|
||||
sampleX = sampleY = nbSamples;
|
||||
}
|
||||
|
||||
var isGreyscale = true;
|
||||
var xFactor = canvas.width / ( sampleX );
|
||||
var yFactor = canvas.height / ( sampleY );
|
||||
for ( var i = 0; i < sampleX; i++ ) {
|
||||
for ( var j = 0; j < sampleY; j++ ) {
|
||||
var x = Math.floor( xFactor * ( i + 0.5 ) ),
|
||||
y = Math.floor( yFactor * ( j + 0.5 ) );
|
||||
var data = ctx.getImageData( x, y, 1, 1 ).data;
|
||||
if ( !( data[ 0 ] === data[ 1 ] && data[ 0 ] === data[ 2 ] ) ) {
|
||||
isGreyscale = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._isGreyscale = isGreyscale;
|
||||
}
|
||||
|
||||
return this._isGreyscale;
|
||||
},
|
||||
|
||||
isReady: function () {
|
||||
|
||||
// image is a osgImage
|
||||
if ( this._imageObject && this._imageObject instanceof ImageObject ) {
|
||||
return this._imageObject.isReady();
|
||||
}
|
||||
|
||||
|
||||
// image are ready for static data
|
||||
if ( this.isCanvas() || this.isTypedArray() || this.isBitmap() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( this.isImage() ) {
|
||||
var image = this.getImage();
|
||||
if ( image.complete ) {
|
||||
if ( image.naturalWidth !== undefined && image.naturalWidth === 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( this.isVideo() ) {
|
||||
if ( this.getWidth() !== 0 ) return true;
|
||||
}
|
||||
|
||||
// here means we have something but we don't know what
|
||||
// Check if the object is not a image
|
||||
// by "feature" detect it
|
||||
var imageTry = this.getImage();
|
||||
if ( imageTry.complete ) {
|
||||
if ( imageTry.naturalWidth !== undefined && imageTry.naturalWidth === 0 ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// It's not something we recognise
|
||||
/*develblock:start*/
|
||||
Notify.warn( 'Warning can\'t detect image object ' );
|
||||
/*develblock:end*/
|
||||
return false;
|
||||
},
|
||||
|
||||
getMipmap: function () {
|
||||
return this._mipmap;
|
||||
},
|
||||
|
||||
hasMipmap: function () {
|
||||
return this._mipmap.length > 1;
|
||||
},
|
||||
|
||||
release: function () {
|
||||
this._mipmap.length = 0;
|
||||
this._imageObject = undefined;
|
||||
}
|
||||
} ), 'osg', 'Image' );
|
||||
|
||||
MACROUTILS.setTypeID( ImageObject );
|
||||
|
||||
module.exports = ImageObject;
|
|
@ -1,68 +0,0 @@
|
|||
'use strict';
|
||||
var P = require( 'bluebird' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Image = require( 'osg/Image' );
|
||||
|
||||
|
||||
var ImageStream = function ( video ) {
|
||||
Image.call( this, video );
|
||||
this._canPlayDefered = undefined;
|
||||
};
|
||||
|
||||
ImageStream.PAUSE = 0;
|
||||
ImageStream.PLAYING = 1;
|
||||
|
||||
ImageStream.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Image.prototype, {
|
||||
|
||||
isDirty: function () {
|
||||
return this._status === ImageStream.PLAYING; // video is dirty if playing
|
||||
},
|
||||
|
||||
setImage: function ( video ) {
|
||||
Image.prototype.setImage.call( this, video );
|
||||
|
||||
this._status = ImageStream.STOP;
|
||||
|
||||
// event at the end of the stream
|
||||
video.addEventListener( 'ended', function () {
|
||||
if ( !this._imageObject.loop )
|
||||
this.stop();
|
||||
}.bind( this ), true );
|
||||
|
||||
this.dirty();
|
||||
},
|
||||
|
||||
setLooping: function ( bool ) {
|
||||
this._imageObject.loop = bool;
|
||||
},
|
||||
|
||||
play: function () {
|
||||
this._imageObject.play();
|
||||
this._status = ImageStream.PLAYING;
|
||||
},
|
||||
|
||||
stop: function () {
|
||||
this._imageObject.pause();
|
||||
this._status = ImageStream.PAUSE;
|
||||
},
|
||||
|
||||
whenReady: function () {
|
||||
|
||||
if ( !this._imageObject ) {
|
||||
return P.reject();
|
||||
}
|
||||
|
||||
if ( !this._canPlayDefered ) {
|
||||
this._canPlayDefered = P.defer();
|
||||
this._imageObject.addEventListener( 'canplaythrough', this._canPlayDefered.resolve.bind( this._canPlayDefered, this ), true );
|
||||
}
|
||||
|
||||
return this._canPlayDefered.promise;
|
||||
}
|
||||
|
||||
|
||||
} ), 'osg', 'ImageStream' );
|
||||
|
||||
MACROUTILS.setTypeID( ImageStream );
|
||||
|
||||
module.exports = ImageStream;
|
|
@ -1,432 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var BoundingBox = require( 'osg/BoundingBox' );
|
||||
var TriangleIndexFunctor = require( 'osg/TriangleIndexFunctor' );
|
||||
var PrimitiveSet = require( 'osg/primitiveSet' );
|
||||
var KdTreeRayIntersector = require( 'osg/KdTreeRayIntersector' );
|
||||
var KdTreeSphereIntersector = require( 'osg/KdTreeSphereIntersector' );
|
||||
|
||||
|
||||
// **** GENERAL INFO ON KDTREE ****
|
||||
// A KdTree is a Spatial Partitionning Tree (http://en.wikipedia.org/wiki/Space_partitioning)
|
||||
// The type of tree is sort of defined by the splitting axis method:
|
||||
// - Per Axis split (octree/ kdtree)
|
||||
// - Arbritrary direction split (bsp)
|
||||
|
||||
// The algorithm used for splitting, the name for finding best split is 'Surface Area Heuristic (SAH)'
|
||||
// Octree divide the space in 8 subspace (one box -> 8 sub boxes)
|
||||
// whereas kdtree does it by splitting population number in two equal group
|
||||
|
||||
// Kd Tree http://en.wikipedia.org/wiki/K-d_tree
|
||||
// a given set of points is sorted along one Axis (e.g. X).
|
||||
// The sorted list is split at the median.
|
||||
// The result are two sets, one for each half-space (left and right).
|
||||
|
||||
// Then, for the current node, the splitting-plane position (or the median-point) and depth is saved.
|
||||
// Finally, if the point-set has more than n point and the tree depth is below m
|
||||
// (with n,m chosen by the user, as build options), two child-nodes (L/R one for each point-set)
|
||||
// are created which themselfs repeat the pocedure.
|
||||
|
||||
// The split-axis gets alternated at each depth, the split order is computed by checking the main
|
||||
// bounding box the length of its axis
|
||||
// **** GENERAL INFO ON KDTREE ****
|
||||
|
||||
// The KdTree implemented here is flattened, ie, a node and its children all lie in the same array
|
||||
// The most important thing is the understanding of the variables first and second for each node
|
||||
// Their semantic depend if the node is a leaf or not
|
||||
// if it's a leaf :
|
||||
// first and second defines a range in the triangles array (triangles in the cell)
|
||||
// if it's not a leaf :
|
||||
// - first and second respectively represents the left and right sub children
|
||||
// We know that a node is a leaf if first is negative, in that case the range will be defined by
|
||||
// [ -first - 1, -first-1 + second ]
|
||||
var KdNode = function ( first, second ) {
|
||||
this._bb = new BoundingBox();
|
||||
this._first = first;
|
||||
this._second = second;
|
||||
// These variables represent the local clipped ray (for intersection test)
|
||||
// They are mostly temporary because they are recomputed for each intersection test
|
||||
this._nodeRayStart = vec3.create();
|
||||
this._nodeRayEnd = vec3.create();
|
||||
};
|
||||
|
||||
var BuildKdTree = function ( kdTree ) {
|
||||
this._kdTree = kdTree;
|
||||
this._bb = new BoundingBox();
|
||||
this._primitiveIndices = null; // Uint32Array
|
||||
this._centers = null; // Float32Array
|
||||
this._axisOrder = vec3.create();
|
||||
this._stackLength = 0;
|
||||
};
|
||||
|
||||
BuildKdTree.prototype = {
|
||||
build: function ( options, geom ) {
|
||||
var targetTris = options._targetNumTrianglesPerLeaf;
|
||||
var vertexAttrib = geom.getVertexAttributeList().Vertex;
|
||||
if ( !vertexAttrib )
|
||||
return false;
|
||||
var vertices = vertexAttrib.getElements();
|
||||
if ( !vertices )
|
||||
return false;
|
||||
var nbVertices = vertices.length / 3;
|
||||
if ( nbVertices < targetTris )
|
||||
return false;
|
||||
|
||||
this._bb.copy( geom.getBoundingBox() );
|
||||
this._kdTree.setVertices( vertices );
|
||||
|
||||
this.computeDivisions( options );
|
||||
options._numVerticesProcessed += nbVertices;
|
||||
|
||||
this.computeTriangles( geom );
|
||||
|
||||
var node = new KdNode( -1, this._primitiveIndices.length );
|
||||
node._bb.copy( this._bb );
|
||||
var nodeNum = this._kdTree.addNode( node );
|
||||
|
||||
var bb = new BoundingBox();
|
||||
bb.copy( this._bb );
|
||||
nodeNum = this.divide( options, bb, nodeNum, 0 );
|
||||
|
||||
// Here we re-order the triangle list so that we can have a flat tree
|
||||
// _primitiveIndices is the ordered array of the triangle indices
|
||||
var triangles = this._kdTree.getTriangles();
|
||||
var primitives = this._primitiveIndices;
|
||||
var nbPrimitives = primitives.length;
|
||||
var triangleOrdered = new MACROUTILS.Uint32Array( triangles.length );
|
||||
for ( var i = 0, j = 0; i < nbPrimitives; ++i, j += 3 ) {
|
||||
var id = primitives[ i ] * 3;
|
||||
triangleOrdered[ j ] = triangles[ id ];
|
||||
triangleOrdered[ j + 1 ] = triangles[ id + 1 ];
|
||||
triangleOrdered[ j + 2 ] = triangles[ id + 2 ];
|
||||
}
|
||||
this._kdTree.setTriangles( triangleOrdered );
|
||||
return this._kdTree.getNodes().length > 0;
|
||||
},
|
||||
// The function first gather all the triangles of the geometry
|
||||
// It then computes the centroid for each triangle and initialize
|
||||
// of triangles indices that will refer to the main triangles array
|
||||
computeTriangles: function ( geom ) {
|
||||
var kdTree = this._kdTree;
|
||||
|
||||
var totalLenArray = 0;
|
||||
var geomPrimitives = geom.primitives;
|
||||
var nbPrimitives = geomPrimitives.length;
|
||||
var i = 0;
|
||||
for ( i = 0; i < nbPrimitives; i++ ) {
|
||||
var prim = geomPrimitives[ i ];
|
||||
var mode = prim.getMode();
|
||||
// ignore points and line stuffs
|
||||
if ( mode === PrimitiveSet.TRIANGLES )
|
||||
totalLenArray += prim.getCount();
|
||||
else if ( mode === PrimitiveSet.TRIANGLE_STRIP || mode === PrimitiveSet.TRIANGLE_FAN )
|
||||
totalLenArray += ( prim.getCount() - 2 ) * 3;
|
||||
}
|
||||
var indices = new MACROUTILS.Uint32Array( totalLenArray );
|
||||
var next = 0;
|
||||
var cb = function ( i1, i2, i3 ) {
|
||||
if ( i1 === i2 || i1 === i3 || i2 === i3 )
|
||||
return;
|
||||
indices[ next ] = i1;
|
||||
indices[ next + 1 ] = i2;
|
||||
indices[ next + 2 ] = i3;
|
||||
next += 3;
|
||||
};
|
||||
|
||||
|
||||
var tif = new TriangleIndexFunctor();
|
||||
tif.init( geom, cb );
|
||||
tif.apply();
|
||||
|
||||
indices = indices.subarray( 0, next );
|
||||
|
||||
var nbTriangles = indices.length;
|
||||
kdTree.setTriangles( indices );
|
||||
|
||||
var vertices = kdTree.getVertices();
|
||||
|
||||
this._centers = new MACROUTILS.Float32Array( nbTriangles );
|
||||
var centers = this._centers;
|
||||
this._primitiveIndices = new MACROUTILS.Uint32Array( nbTriangles / 3 );
|
||||
var primitives = this._primitiveIndices;
|
||||
|
||||
var j = 0;
|
||||
for ( i = 0, j = 0; i < nbTriangles; i += 3, ++j ) {
|
||||
var iv0 = indices[ i ];
|
||||
var iv1 = indices[ i + 1 ];
|
||||
var iv2 = indices[ i + 2 ];
|
||||
|
||||
// discard degenerate points
|
||||
if ( iv0 === iv1 || iv1 === iv2 || iv0 === iv2 )
|
||||
return;
|
||||
|
||||
iv0 *= 3;
|
||||
iv1 *= 3;
|
||||
iv2 *= 3;
|
||||
|
||||
var v0x = vertices[ iv0 ];
|
||||
var v0y = vertices[ iv0 + 1 ];
|
||||
var v0z = vertices[ iv0 + 2 ];
|
||||
|
||||
var v1x = vertices[ iv1 ];
|
||||
var v1y = vertices[ iv1 + 1 ];
|
||||
var v1z = vertices[ iv1 + 2 ];
|
||||
|
||||
var v2x = vertices[ iv2 ];
|
||||
var v2y = vertices[ iv2 + 1 ];
|
||||
var v2z = vertices[ iv2 + 2 ];
|
||||
|
||||
var minx = Math.min( v0x, Math.min( v1x, v2x ) );
|
||||
var miny = Math.min( v0y, Math.min( v1y, v2y ) );
|
||||
var minz = Math.min( v0z, Math.min( v1z, v2z ) );
|
||||
|
||||
var maxx = Math.max( v0x, Math.max( v1x, v2x ) );
|
||||
var maxy = Math.max( v0y, Math.max( v1y, v2y ) );
|
||||
var maxz = Math.max( v0z, Math.max( v1z, v2z ) );
|
||||
centers[ i ] = ( minx + maxx ) * 0.5;
|
||||
centers[ i + 1 ] = ( miny + maxy ) * 0.5;
|
||||
centers[ i + 2 ] = ( minz + maxz ) * 0.5;
|
||||
primitives[ j ] = j;
|
||||
}
|
||||
},
|
||||
computeDivisions: function ( options ) {
|
||||
this._stackLength = options._maxNumLevels;
|
||||
var max = this._bb._max;
|
||||
var min = this._bb._min;
|
||||
var dx = max[ 0 ] - min[ 0 ];
|
||||
var dy = max[ 1 ] - min[ 1 ];
|
||||
var dz = max[ 2 ] - min[ 2 ];
|
||||
var axisOrder = this._axisOrder;
|
||||
|
||||
// We set the cutting order (longest edge aabb first)
|
||||
axisOrder[ 0 ] = ( dx >= dy && dx >= dz ) ? 0 : ( dy >= dz ) ? 1 : 2;
|
||||
axisOrder[ 2 ] = ( dx < dy && dx < dz ) ? 0 : ( dy < dz ) ? 1 : 2;
|
||||
var sum = axisOrder[ 0 ] + axisOrder[ 2 ];
|
||||
axisOrder[ 1 ] = sum === 3 ? 0 : sum === 2 ? 1 : 2;
|
||||
},
|
||||
// The core function of the kdtree building
|
||||
// It checks if the node need to be subdivide or not
|
||||
// If it decides it's a leaf, it computes the final bounding box of the node
|
||||
// and it ends here
|
||||
// If it's a node, then it puts the splitting axis position on the median population
|
||||
// On the same time it reorder the triangle index array
|
||||
divide: function ( options, bb, nodeIndex, level ) {
|
||||
var kdTree = this._kdTree;
|
||||
var primitives = this._primitiveIndices;
|
||||
var nodes = kdTree.getNodes();
|
||||
var node = nodes[ nodeIndex ];
|
||||
|
||||
var first = node._first;
|
||||
var second = node._second;
|
||||
|
||||
var needToDivide = level < this._stackLength && first < 0 && second > options._targetNumTrianglesPerLeaf;
|
||||
var istart = -first - 1;
|
||||
var iend = istart + second - 1;
|
||||
|
||||
if ( !needToDivide ) {
|
||||
if ( first < 0 ) {
|
||||
// leaf is done, now compute bound on it.
|
||||
this.computeNodeBox( node, istart, iend );
|
||||
}
|
||||
return nodeIndex;
|
||||
}
|
||||
|
||||
if ( first >= 0 )
|
||||
return nodeIndex;
|
||||
// leaf node as first < 0, so look at dividing it.
|
||||
|
||||
var axis = this._axisOrder[ level % 3 ];
|
||||
var originalMin = bb._min[ axis ];
|
||||
var originalMax = bb._max[ axis ];
|
||||
|
||||
var mid = ( originalMin + originalMax ) * 0.5;
|
||||
|
||||
var originalLeftChildIndex = 0;
|
||||
var originalRightChildIndex = 0;
|
||||
var insitueDivision = false;
|
||||
|
||||
var left = istart;
|
||||
var right = iend;
|
||||
|
||||
var centers = this._centers;
|
||||
while ( left < right ) {
|
||||
while ( left < right && ( centers[ primitives[ left ] * 3 + axis ] <= mid ) ) {
|
||||
++left;
|
||||
}
|
||||
|
||||
while ( left < right && ( centers[ primitives[ right ] * 3 + axis ] > mid ) ) {
|
||||
--right;
|
||||
}
|
||||
|
||||
if ( left < right ) {
|
||||
var tmp = primitives[ left ];
|
||||
primitives[ left ] = primitives[ right ];
|
||||
primitives[ right ] = tmp;
|
||||
++left;
|
||||
--right;
|
||||
}
|
||||
}
|
||||
|
||||
if ( left === right ) {
|
||||
if ( centers[ primitives[ left ] * 3 + axis ] <= mid ) ++left;
|
||||
else --right;
|
||||
}
|
||||
|
||||
if ( ( right - istart ) <= -1 ) {
|
||||
originalLeftChildIndex = 0;
|
||||
originalRightChildIndex = nodeIndex;
|
||||
insitueDivision = true;
|
||||
} else if ( ( iend - left ) <= -1 ) {
|
||||
originalLeftChildIndex = nodeIndex;
|
||||
originalRightChildIndex = 0;
|
||||
insitueDivision = true;
|
||||
} else {
|
||||
originalLeftChildIndex = kdTree.addNode( new KdNode( -istart - 1, ( right - istart ) + 1 ) );
|
||||
originalRightChildIndex = kdTree.addNode( new KdNode( -left - 1, ( iend - left ) + 1 ) );
|
||||
}
|
||||
|
||||
|
||||
var restore = bb._max[ axis ];
|
||||
bb._max[ axis ] = mid;
|
||||
|
||||
var leftChildIndex = originalLeftChildIndex !== 0 ? this.divide( options, bb, originalLeftChildIndex, level + 1 ) : 0;
|
||||
|
||||
bb._max[ axis ] = restore;
|
||||
|
||||
restore = bb._min[ axis ];
|
||||
bb._min[ axis ] = mid;
|
||||
|
||||
var rightChildIndex = originalRightChildIndex !== 0 ? this.divide( options, bb, originalRightChildIndex, level + 1 ) : 0;
|
||||
|
||||
bb._min[ axis ] = restore;
|
||||
|
||||
if ( !insitueDivision ) {
|
||||
node._first = leftChildIndex;
|
||||
node._second = rightChildIndex;
|
||||
|
||||
insitueDivision = true;
|
||||
|
||||
var bnode = node._bb;
|
||||
bnode.init();
|
||||
if ( leftChildIndex !== 0 ) bnode.expandByBoundingBox( nodes[ leftChildIndex ]._bb );
|
||||
if ( rightChildIndex !== 0 ) bnode.expandByBoundingBox( nodes[ rightChildIndex ]._bb );
|
||||
}
|
||||
return nodeIndex;
|
||||
},
|
||||
// It computes the bounding box of the node so that the box contains all the triangles
|
||||
// of the cell
|
||||
computeNodeBox: function ( node, istart, iend ) {
|
||||
var minx = Infinity,
|
||||
miny = Infinity,
|
||||
minz = Infinity,
|
||||
maxx = -Infinity,
|
||||
maxy = -Infinity,
|
||||
maxz = -Infinity;
|
||||
var triangles = this._kdTree.getTriangles();
|
||||
var vertices = this._kdTree.getVertices();
|
||||
var primitives = this._primitiveIndices;
|
||||
for ( var i = istart; i <= iend; ++i ) {
|
||||
var id = primitives[ i ] * 3;
|
||||
var iv0 = triangles[ id ] * 3;
|
||||
var iv1 = triangles[ id + 1 ] * 3;
|
||||
var iv2 = triangles[ id + 2 ] * 3;
|
||||
|
||||
var v0x = vertices[ iv0 ];
|
||||
var v0y = vertices[ iv0 + 1 ];
|
||||
var v0z = vertices[ iv0 + 2 ];
|
||||
|
||||
var v1x = vertices[ iv1 ];
|
||||
var v1y = vertices[ iv1 + 1 ];
|
||||
var v1z = vertices[ iv1 + 2 ];
|
||||
|
||||
var v2x = vertices[ iv2 ];
|
||||
var v2y = vertices[ iv2 + 1 ];
|
||||
var v2z = vertices[ iv2 + 2 ];
|
||||
|
||||
minx = Math.min( minx, Math.min( v0x, Math.min( v1x, v2x ) ) );
|
||||
miny = Math.min( miny, Math.min( v0y, Math.min( v1y, v2y ) ) );
|
||||
minz = Math.min( minz, Math.min( v0z, Math.min( v1z, v2z ) ) );
|
||||
|
||||
maxx = Math.max( maxx, Math.max( v0x, Math.max( v1x, v2x ) ) );
|
||||
maxy = Math.max( maxy, Math.max( v0y, Math.max( v1y, v2y ) ) );
|
||||
maxz = Math.max( maxz, Math.max( v0z, Math.max( v1z, v2z ) ) );
|
||||
}
|
||||
var epsilon = 1E-6;
|
||||
var bnode = node._bb;
|
||||
var bmin = bnode._min;
|
||||
var bmax = bnode._max;
|
||||
bmin[ 0 ] = minx - epsilon;
|
||||
bmin[ 1 ] = miny - epsilon;
|
||||
bmin[ 2 ] = minz - epsilon;
|
||||
bmax[ 0 ] = maxx + epsilon;
|
||||
bmax[ 1 ] = maxy + epsilon;
|
||||
bmax[ 2 ] = maxz + epsilon;
|
||||
}
|
||||
};
|
||||
|
||||
var KdTree = function () {
|
||||
this._vertices = null;
|
||||
this._kdNodes = [];
|
||||
this._triangles = null; // Float32Array
|
||||
};
|
||||
|
||||
KdTree.prototype = MACROUTILS.objectLibraryClass( {
|
||||
getVertices: function () {
|
||||
return this._vertices;
|
||||
},
|
||||
setVertices: function ( vertices ) {
|
||||
this._vertices = vertices;
|
||||
},
|
||||
getNodes: function () {
|
||||
return this._kdNodes;
|
||||
},
|
||||
getTriangles: function () {
|
||||
return this._triangles;
|
||||
},
|
||||
setTriangles: function ( triangles ) {
|
||||
this._triangles = triangles;
|
||||
},
|
||||
addNode: function ( node ) {
|
||||
this._kdNodes.push( node );
|
||||
return this._kdNodes.length - 1;
|
||||
},
|
||||
build: function ( options, geom ) {
|
||||
var buildTree = new BuildKdTree( this );
|
||||
return buildTree.build( options, geom );
|
||||
},
|
||||
intersectRay: function ( start, end, intersections, nodePath ) {
|
||||
if ( this._kdNodes.length === 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var numIntersectionsBefore = intersections.length;
|
||||
|
||||
if ( !this._rayIntersector ) {
|
||||
this._rayIntersector = new KdTreeRayIntersector();
|
||||
this._rayIntersector.setKdtree( this._vertices, this._kdNodes, this._triangles );
|
||||
}
|
||||
this._rayIntersector.init( intersections, start, end, nodePath );
|
||||
this._rayIntersector.intersect( this.getNodes()[ 0 ], start, end );
|
||||
|
||||
return numIntersectionsBefore !== intersections.length;
|
||||
},
|
||||
intersectSphere: function ( center, radius, intersections, nodePath ) {
|
||||
if ( this._kdNodes.length === 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var numIntersectionsBefore = intersections.length;
|
||||
|
||||
if ( !this._sphereIntersector ) {
|
||||
this._sphereIntersector = new KdTreeSphereIntersector();
|
||||
this._sphereIntersector.setKdtree( this._vertices, this._kdNodes, this._triangles );
|
||||
}
|
||||
this._sphereIntersector.init( intersections, center, radius, nodePath );
|
||||
this._sphereIntersector.intersect( this.getNodes()[ 0 ] );
|
||||
|
||||
return numIntersectionsBefore !== intersections.length;
|
||||
}
|
||||
}, 'osg', 'KdTree' );
|
||||
|
||||
module.exports = KdTree;
|
|
@ -1,32 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
var KdTree = require( 'osg/KdTree' );
|
||||
|
||||
|
||||
var KdTreeBuilder = function ( options ) {
|
||||
NodeVisitor.call( this );
|
||||
this._buildOptions = options !== undefined ? options : {
|
||||
_numVerticesProcessed: 0,
|
||||
_targetNumTrianglesPerLeaf: 50,
|
||||
_maxNumLevels: 20
|
||||
};
|
||||
};
|
||||
|
||||
KdTreeBuilder.prototype = MACROUTILS.objectInherit( NodeVisitor.prototype, {
|
||||
apply: function ( node ) {
|
||||
if ( node.getShape ) {
|
||||
var shape = node.getShape();
|
||||
// we test if the kdTree is already built and if we can build it (null means we skip it)
|
||||
if ( shape === undefined ) {
|
||||
var kdTree = new KdTree();
|
||||
if ( kdTree.build( this._buildOptions, node ) ) {
|
||||
node.setShape( kdTree );
|
||||
}
|
||||
}
|
||||
}
|
||||
this.traverse( node );
|
||||
}
|
||||
} );
|
||||
|
||||
module.exports = KdTreeBuilder;
|
|
@ -1,231 +0,0 @@
|
|||
'use strict';
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var TriangleIntersector = require( 'osgUtil/TriangleIntersector' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
|
||||
var KdTreeRayIntersector = function () {
|
||||
|
||||
if ( arguments && arguments.length ) {
|
||||
Notify.warn( 'using ctor as initialiser is deprecated, use init(intersections, start, end, nodePath) and/or setKdtree: function ( vertices, nodes, triangles )' );
|
||||
}
|
||||
|
||||
this._intersector = new TriangleIntersector();
|
||||
this._dInvX = vec3.create();
|
||||
this._dInvY = vec3.create();
|
||||
this._dInvZ = vec3.create();
|
||||
|
||||
};
|
||||
|
||||
KdTreeRayIntersector.prototype = {
|
||||
setKdtree: function ( vertices, nodes, triangles ) {
|
||||
this._vertices = vertices;
|
||||
this._kdNodes = nodes;
|
||||
this._triangles = triangles;
|
||||
},
|
||||
init: ( function () {
|
||||
|
||||
var dir = vec3.create();
|
||||
|
||||
return function ( intersections, start, end, nodePath ) {
|
||||
var d = vec3.sub( dir, end, start );
|
||||
var len = vec3.length( d );
|
||||
var invLen = 0.0;
|
||||
if ( len !== 0.0 )
|
||||
invLen = 1.0 / len;
|
||||
vec3.scale( d, d, invLen );
|
||||
if ( d[ 0 ] !== 0.0 ) vec3.scale( this._dInvX, d, 1.0 / d[ 0 ] );
|
||||
if ( d[ 1 ] !== 0.0 ) vec3.scale( this._dInvY, d, 1.0 / d[ 1 ] );
|
||||
if ( d[ 2 ] !== 0.0 ) vec3.scale( this._dInvZ, d, 1.0 / d[ 2 ] );
|
||||
|
||||
this._intersector._intersections = intersections;
|
||||
this._intersector.setNodePath( nodePath );
|
||||
this._intersector.set( start, end );
|
||||
};
|
||||
} )(),
|
||||
// Classic ray intersection test
|
||||
// If it's a leaf it does ray-triangles intersection with the triangles in the cell
|
||||
// If it's not a leaf, it descend in the tree in a recursive way as long as the ray
|
||||
// intersects the boundinbox of the nodes
|
||||
intersect: ( function () {
|
||||
|
||||
var v0 = vec3.create();
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
|
||||
return function ( node, ls, le ) {
|
||||
var first = node._first;
|
||||
var second = node._second;
|
||||
var triangles = this._triangles;
|
||||
var vertices = this._vertices;
|
||||
|
||||
if ( first < 0 ) {
|
||||
// treat as a leaf
|
||||
var istart = -first - 1;
|
||||
var iend = istart + second;
|
||||
var intersector = this._intersector;
|
||||
intersector.index = istart;
|
||||
|
||||
for ( var i = istart; i < iend; ++i ) {
|
||||
var id = i * 3;
|
||||
var iv0 = triangles[ id ];
|
||||
var iv1 = triangles[ id + 1 ];
|
||||
var iv2 = triangles[ id + 2 ];
|
||||
|
||||
var j = iv0 * 3;
|
||||
v0[ 0 ] = vertices[ j ];
|
||||
v0[ 1 ] = vertices[ j + 1 ];
|
||||
v0[ 2 ] = vertices[ j + 2 ];
|
||||
|
||||
j = iv1 * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
|
||||
j = iv2 * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
|
||||
intersector.intersect( v0, v1, v2, iv0, iv1, iv2 );
|
||||
}
|
||||
} else {
|
||||
var s = node._nodeRayStart;
|
||||
var e = node._nodeRayEnd;
|
||||
var kNodes = this._kdNodes;
|
||||
|
||||
var kNode;
|
||||
vec3.copy( s, ls );
|
||||
vec3.copy( e, le );
|
||||
if ( first > 0 ) {
|
||||
kNode = kNodes[ first ];
|
||||
if ( this.intersectAndClip( s, e, kNode._bb ) ) {
|
||||
this.intersect( kNode, s, e );
|
||||
}
|
||||
}
|
||||
if ( second > 0 ) {
|
||||
vec3.copy( s, ls );
|
||||
vec3.copy( e, le );
|
||||
kNode = kNodes[ second ];
|
||||
if ( this.intersectAndClip( s, e, kNode._bb ) ) {
|
||||
this.intersect( kNode, s, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} )(),
|
||||
// This method do 2 things
|
||||
// It test if the ray intersects the node
|
||||
// If so... it clip the ray so that the start and end point of the ray are
|
||||
// snapped to the bounding box of the nodes
|
||||
intersectAndClip: ( function () {
|
||||
|
||||
return function ( s, e, bb ) {
|
||||
var min = bb._min;
|
||||
var xmin = min[ 0 ];
|
||||
var ymin = min[ 1 ];
|
||||
var zmin = min[ 2 ];
|
||||
|
||||
var max = bb._max;
|
||||
var xmax = max[ 0 ];
|
||||
var ymax = max[ 1 ];
|
||||
var zmax = max[ 2 ];
|
||||
|
||||
var invX = this._dInvX;
|
||||
var invY = this._dInvY;
|
||||
var invZ = this._dInvZ;
|
||||
|
||||
if ( s[ 0 ] <= e[ 0 ] ) {
|
||||
// trivial reject of segment wholely outside.
|
||||
if ( e[ 0 ] < xmin ) return false;
|
||||
if ( s[ 0 ] > xmax ) return false;
|
||||
|
||||
if ( s[ 0 ] < xmin ) {
|
||||
// clip s to xMin.
|
||||
vec3.scaleAndAdd( s, s, invX, xmin - s[ 0 ] );
|
||||
}
|
||||
|
||||
if ( e[ 0 ] > xmax ) {
|
||||
// clip e to xMax.
|
||||
vec3.scaleAndAdd( e, s, invX, xmax - s[ 0 ] );
|
||||
}
|
||||
} else {
|
||||
if ( s[ 0 ] < xmin ) return false;
|
||||
if ( e[ 0 ] > xmax ) return false;
|
||||
|
||||
if ( e[ 0 ] < xmin ) {
|
||||
// clip s to xMin.
|
||||
vec3.scaleAndAdd( e, s, invX, xmin - s[ 0 ] );
|
||||
}
|
||||
|
||||
if ( s[ 0 ] > xmax ) {
|
||||
// clip e to xMax.
|
||||
vec3.scaleAndAdd( s, s, invX, xmax - s[ 0 ] );
|
||||
}
|
||||
}
|
||||
|
||||
// compate s and e against the yMin to yMax range of bb.
|
||||
if ( s[ 1 ] <= e[ 1 ] ) {
|
||||
|
||||
// trivial reject of segment wholely outside.
|
||||
if ( e[ 1 ] < ymin ) return false;
|
||||
if ( s[ 1 ] > ymax ) return false;
|
||||
|
||||
if ( s[ 1 ] < ymin ) {
|
||||
// clip s to yMin.
|
||||
vec3.scaleAndAdd( s, s, invY, ymin - s[ 1 ] );
|
||||
}
|
||||
|
||||
if ( e[ 1 ] > ymax ) {
|
||||
// clip e to yMax.
|
||||
vec3.scaleAndAdd( e, s, invY, ymax - s[ 1 ] );
|
||||
}
|
||||
} else {
|
||||
if ( s[ 1 ] < ymin ) return false;
|
||||
if ( e[ 1 ] > ymax ) return false;
|
||||
|
||||
if ( e[ 1 ] < ymin ) {
|
||||
// clip s to yMin.
|
||||
vec3.scaleAndAdd( e, s, invY, ymin - s[ 1 ] );
|
||||
}
|
||||
|
||||
if ( s[ 1 ] > ymax ) {
|
||||
// clip e to yMax.
|
||||
vec3.scaleAndAdd( s, s, invY, ymax - s[ 1 ] );
|
||||
}
|
||||
}
|
||||
|
||||
// compate s and e against the zMin to zMax range of bb.
|
||||
if ( s[ 2 ] <= e[ 2 ] ) {
|
||||
// trivial reject of segment wholely outside.
|
||||
if ( e[ 2 ] < zmin ) return false;
|
||||
if ( s[ 2 ] > zmax ) return false;
|
||||
|
||||
if ( s[ 2 ] < zmin ) {
|
||||
// clip s to zMin.
|
||||
vec3.scaleAndAdd( s, s, invZ, zmin - s[ 2 ] );
|
||||
}
|
||||
|
||||
if ( e[ 2 ] > zmax ) {
|
||||
// clip e to zMax.
|
||||
vec3.scaleAndAdd( e, s, invZ, zmax - s[ 2 ] );
|
||||
}
|
||||
} else {
|
||||
if ( s[ 2 ] < zmin ) return false;
|
||||
if ( e[ 2 ] > zmax ) return false;
|
||||
|
||||
if ( e[ 2 ] < zmin ) {
|
||||
// clip s to zMin.
|
||||
vec3.scaleAndAdd( e, s, invZ, zmin - s[ 2 ] );
|
||||
}
|
||||
|
||||
if ( s[ 2 ] > zmax ) {
|
||||
// clip e to zMax.
|
||||
vec3.scaleAndAdd( s, s, invZ, zmax - s[ 2 ] );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
} )()
|
||||
};
|
||||
|
||||
module.exports = KdTreeRayIntersector;
|
|
@ -1,91 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var KdTreeRayIntersector = require( 'osg/KdTreeRayIntersector' );
|
||||
var TriangleSphereIntersector = require( 'osgUtil/TriangleSphereIntersector' );
|
||||
|
||||
|
||||
var KdTreeSphereIntersector = function () {
|
||||
|
||||
this._intersector = new TriangleSphereIntersector();
|
||||
|
||||
};
|
||||
|
||||
KdTreeSphereIntersector.prototype = MACROUTILS.objectInherit( KdTreeRayIntersector.prototype, {
|
||||
|
||||
init: function ( intersections, center, radius, nodePath ) {
|
||||
|
||||
this._intersector._intersections = intersections;
|
||||
this._intersector.setNodePath( nodePath );
|
||||
this._intersector.set( center, radius );
|
||||
this._center = center;
|
||||
this._radius = radius;
|
||||
|
||||
},
|
||||
|
||||
intersect: ( function () {
|
||||
|
||||
var v0 = vec3.create();
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
|
||||
return function ( node ) {
|
||||
var first = node._first;
|
||||
var second = node._second;
|
||||
var triangles = this._triangles;
|
||||
var vertices = this._vertices;
|
||||
|
||||
if ( first < 0 ) {
|
||||
// treat as a leaf
|
||||
var istart = -first - 1;
|
||||
var iend = istart + second;
|
||||
var intersector = this._intersector;
|
||||
intersector.index = istart;
|
||||
|
||||
for ( var i = istart; i < iend; ++i ) {
|
||||
var id = i * 3;
|
||||
var iv0 = triangles[ id ];
|
||||
var iv1 = triangles[ id + 1 ];
|
||||
var iv2 = triangles[ id + 2 ];
|
||||
|
||||
var j = iv0 * 3;
|
||||
v0[ 0 ] = vertices[ j ];
|
||||
v0[ 1 ] = vertices[ j + 1 ];
|
||||
v0[ 2 ] = vertices[ j + 2 ];
|
||||
|
||||
j = iv1 * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
|
||||
j = iv2 * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
|
||||
intersector.intersect( v0, v1, v2, iv0, iv1, iv2 );
|
||||
}
|
||||
} else {
|
||||
if ( first > 0 ) {
|
||||
if ( this.intersectSphere( this._kdNodes[ first ]._bb ) ) {
|
||||
this.intersect( this._kdNodes[ first ] );
|
||||
}
|
||||
}
|
||||
if ( second > 0 ) {
|
||||
if ( this.intersectSphere( this._kdNodes[ second ]._bb ) ) {
|
||||
this.intersect( this._kdNodes[ second ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} )(),
|
||||
intersectSphere: ( function () {
|
||||
var tmp = vec3.create();
|
||||
return function ( bb ) {
|
||||
var r = this._radius + bb.radius();
|
||||
return vec3.sqrDist( bb.center( tmp ), this._center ) <= r * r;
|
||||
};
|
||||
} )()
|
||||
} );
|
||||
|
||||
module.exports = KdTreeSphereIntersector;
|
|
@ -1,335 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var Uniform = require( 'osg/Uniform' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var vec4 = require( 'osg/glMatrix' ).vec4;
|
||||
var Map = require( 'osg/Map' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
|
||||
|
||||
// use the same kind of opengl lights
|
||||
// see http://www.glprogramming.com/red/chapter05.html
|
||||
|
||||
|
||||
var Light = function ( lightNum, disable ) {
|
||||
StateAttribute.call( this );
|
||||
|
||||
var lightNumber = lightNum !== undefined ? lightNum : 0;
|
||||
|
||||
this._ambient = vec4.fromValues( 0.2, 0.2, 0.2, 1.0 );
|
||||
this._diffuse = vec4.fromValues( 0.8, 0.8, 0.8, 1.0 );
|
||||
this._specular = vec4.fromValues( 0.2, 0.2, 0.2, 1.0 );
|
||||
|
||||
// Default is directional as postion[3] is 0
|
||||
this._position = vec4.fromValues( 0.0, 0.0, 1.0, 0.0 );
|
||||
this._direction = vec3.fromValues( 0.0, 0.0, -1.0 );
|
||||
|
||||
// TODO : refactor lights management w=1.0 (isHemi), w=-1.0
|
||||
// (isNotHemi) _ground contains the color but w says if it's
|
||||
// an hemi or not
|
||||
this._ground = vec4.fromValues( 0.2, 0.2, 0.2, -1.0 );
|
||||
|
||||
this._spotCutoff = 180.0;
|
||||
this._spotBlend = 0.01;
|
||||
|
||||
// the array contains constant, linear, quadratic factor
|
||||
this._attenuation = vec4.fromValues( 1.0, 0.0, 0.0, 0.0 );
|
||||
|
||||
this._lightUnit = lightNumber;
|
||||
|
||||
this._invMatrix = mat4.create();
|
||||
|
||||
this._enable = !disable;
|
||||
|
||||
};
|
||||
|
||||
Light.DIRECTION = 'DIRECTION';
|
||||
Light.SPOT = 'SPOT';
|
||||
Light.POINT = 'POINT';
|
||||
Light.HEMI = 'HEMI';
|
||||
|
||||
Light.uniforms = {};
|
||||
Light.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'Light',
|
||||
|
||||
cloneType: function () {
|
||||
return new Light( this._lightUnit, true );
|
||||
},
|
||||
|
||||
getTypeMember: function () {
|
||||
return this.attributeType + this._lightUnit;
|
||||
},
|
||||
|
||||
getUniformName: function ( name ) {
|
||||
var prefix = this.getType() + this._lightUnit.toString();
|
||||
return 'u' + prefix + '_' + name;
|
||||
},
|
||||
|
||||
getHash: function () {
|
||||
return this.getTypeMember() + this.getLightType() + this.isEnabled().toString();
|
||||
},
|
||||
|
||||
getOrCreateUniforms: function () {
|
||||
|
||||
var obj = Light;
|
||||
var typeMember = this.getTypeMember();
|
||||
|
||||
if ( obj.uniforms[ typeMember ] ) return obj.uniforms[ typeMember ];
|
||||
|
||||
var uniforms = {
|
||||
ambient: Uniform.createFloat4( this.getUniformName( 'ambient' ) ),
|
||||
diffuse: Uniform.createFloat4( this.getUniformName( 'diffuse' ) ),
|
||||
specular: Uniform.createFloat4( this.getUniformName( 'specular' ) ),
|
||||
attenuation: Uniform.createFloat4( this.getUniformName( 'attenuation' ) ),
|
||||
position: Uniform.createFloat4( this.getUniformName( 'position' ) ),
|
||||
direction: Uniform.createFloat3( this.getUniformName( 'direction' ) ),
|
||||
spotCutOff: Uniform.createFloat1( this.getUniformName( 'spotCutOff' ) ),
|
||||
spotBlend: Uniform.createFloat1( this.getUniformName( 'spotBlend' ) ),
|
||||
ground: Uniform.createFloat4( this.getUniformName( 'ground' ) ),
|
||||
matrix: Uniform.createMatrix4( this.getUniformName( 'matrix' ) ),
|
||||
invMatrix: Uniform.createMatrix4( this.getUniformName( 'invMatrix' ) )
|
||||
};
|
||||
|
||||
obj.uniforms[ typeMember ] = new Map( uniforms );
|
||||
|
||||
return obj.uniforms[ typeMember ];
|
||||
},
|
||||
|
||||
// enable / disable is not implemented in uniform
|
||||
// we should add it
|
||||
isEnabled: function () {
|
||||
return this._enable;
|
||||
},
|
||||
|
||||
setEnabled: function ( bool ) {
|
||||
this._enable = bool;
|
||||
},
|
||||
|
||||
// Deprecated methods, should be removed in the future
|
||||
isEnable: function () {
|
||||
Notify.log( 'Light.isEnable() is deprecated, use isEnabled instead' );
|
||||
return this.isEnabled();
|
||||
},
|
||||
|
||||
setEnable: function ( bool ) {
|
||||
Notify.log( 'Light.setEnable() is deprecated, use setEnabled instead' );
|
||||
this.setEnabled( bool );
|
||||
},
|
||||
|
||||
// colors
|
||||
setAmbient: function ( a ) {
|
||||
vec4.copy( this._ambient, a );
|
||||
},
|
||||
|
||||
getAmbient: function () {
|
||||
return this._ambient;
|
||||
},
|
||||
|
||||
setDiffuse: function ( a ) {
|
||||
vec4.copy( this._diffuse, a );
|
||||
},
|
||||
|
||||
getDiffuse: function () {
|
||||
return this._diffuse;
|
||||
},
|
||||
|
||||
setSpecular: function ( a ) {
|
||||
vec4.copy( this._specular, a );
|
||||
},
|
||||
|
||||
getSpecular: function () {
|
||||
return this._specular;
|
||||
},
|
||||
|
||||
|
||||
// position, also used for directional light
|
||||
// position[3] === 0 means directional
|
||||
// see creating lightsources http://www.glprogramming.com/red/chapter05.html
|
||||
setPosition: function ( a ) {
|
||||
vec4.copy( this._position, a );
|
||||
},
|
||||
|
||||
getPosition: function () {
|
||||
return this._position;
|
||||
},
|
||||
|
||||
// unused for directional
|
||||
setDirection: function ( a ) {
|
||||
vec3.copy( this._direction, a );
|
||||
},
|
||||
|
||||
getDirection: function () {
|
||||
return this._direction;
|
||||
},
|
||||
|
||||
|
||||
setSpotCutoff: function ( a ) {
|
||||
this._spotCutoff = a;
|
||||
},
|
||||
|
||||
getSpotCutoff: function () {
|
||||
return this._spotCutoff;
|
||||
},
|
||||
|
||||
setSpotBlend: function ( a ) {
|
||||
this._spotBlend = a;
|
||||
},
|
||||
|
||||
getSpotBlend: function () {
|
||||
return this._spotBlend;
|
||||
},
|
||||
|
||||
// set/get the color of the ground
|
||||
setGround: function ( a ) {
|
||||
vec3.copy( this._ground, a );
|
||||
},
|
||||
|
||||
getGround: function () {
|
||||
return this._ground;
|
||||
},
|
||||
|
||||
// attenuation coeff
|
||||
setConstantAttenuation: function ( value ) {
|
||||
this._attenuation[ 0 ] = value;
|
||||
},
|
||||
|
||||
getConstantAttenuation: function () {
|
||||
return this._attenuation[ 0 ];
|
||||
},
|
||||
|
||||
setLinearAttenuation: function ( value ) {
|
||||
this._attenuation[ 1 ] = value;
|
||||
},
|
||||
|
||||
getLinearAttenuation: function () {
|
||||
return this._attenuation[ 1 ];
|
||||
},
|
||||
|
||||
setQuadraticAttenuation: function ( value ) {
|
||||
this._attenuation[ 2 ] = value;
|
||||
},
|
||||
|
||||
getQuadraticAttenuation: function () {
|
||||
return this._attenuation[ 2 ];
|
||||
},
|
||||
|
||||
setLightType: function ( type ) {
|
||||
if ( type === Light.DIRECTION )
|
||||
return this.setLightAsDirection();
|
||||
else if ( type === Light.SPOT )
|
||||
return this.setLightAsSpot();
|
||||
else if ( type === Light.HEMI )
|
||||
return this.setLightAsHemi();
|
||||
return this.setLightAsPoint();
|
||||
},
|
||||
|
||||
getLightType: function () {
|
||||
if ( this.isDirectionLight() )
|
||||
return Light.DIRECTION;
|
||||
else if ( this.isSpotLight() )
|
||||
return Light.SPOT;
|
||||
else if ( this.isHemiLight() )
|
||||
return Light.HEMI;
|
||||
return Light.POINT;
|
||||
},
|
||||
|
||||
setLightAsSpot: function () {
|
||||
vec4.set( this._position, 0.0, 0.0, 0.0, 1.0 );
|
||||
vec3.set( this._direction, 0.0, 0.0, -1.0 );
|
||||
this._ground[ 3 ] = -1.0;
|
||||
this._spotCutoff = 90;
|
||||
},
|
||||
|
||||
setLightAsPoint: function () {
|
||||
vec4.set( this._position, 0.0, 0.0, 0.0, 1.0 );
|
||||
vec3.set( this._direction, 0.0, 0.0, -1.0 );
|
||||
this._ground[ 3 ] = -1.0;
|
||||
},
|
||||
|
||||
setLightAsDirection: function () {
|
||||
vec4.set( this._position, 0.0, 0.0, 1.0, 0.0 );
|
||||
this._spotCutoff = 180;
|
||||
this._ground[ 3 ] = -1.0;
|
||||
},
|
||||
|
||||
setLightAsHemi: function () {
|
||||
vec4.set( this._position, 0.0, 0.0, 1.0, 0.0 );
|
||||
this._spotCutoff = 180;
|
||||
this._ground[ 3 ] = 1.0;
|
||||
},
|
||||
|
||||
setLightNumber: function ( unit ) {
|
||||
this._lightUnit = unit;
|
||||
},
|
||||
|
||||
getLightNumber: function () {
|
||||
return this._lightUnit;
|
||||
},
|
||||
|
||||
// internal helper
|
||||
isSpotLight: function () {
|
||||
return this._spotCutoff < 180.0;
|
||||
},
|
||||
|
||||
isDirectionLight: function () {
|
||||
return this._position[ 3 ] === 0.0 && this._ground[ 3 ] === -1.0;
|
||||
},
|
||||
|
||||
isHemiLight: function () {
|
||||
return this._ground[ 3 ] === 1.0;
|
||||
},
|
||||
|
||||
// matrix is current model view, which can mean:
|
||||
// world (node refAbsolute)
|
||||
// world+camera (camera is refAbsolute)
|
||||
// world+camera+camera+... (camera relative...)
|
||||
applyPositionedUniform: function ( matrix ) {
|
||||
|
||||
var uniformMap = this.getOrCreateUniforms();
|
||||
|
||||
var matrixArray = uniformMap.matrix.getInternalArray();
|
||||
var invMatrixArray = uniformMap.invMatrix.getInternalArray();
|
||||
|
||||
mat4.copy( matrixArray, matrix );
|
||||
mat4.copy( invMatrixArray, matrix );
|
||||
|
||||
invMatrixArray[ 12 ] = 0.0;
|
||||
invMatrixArray[ 13 ] = 0.0;
|
||||
invMatrixArray[ 14 ] = 0.0;
|
||||
|
||||
mat4.invert( invMatrixArray, invMatrixArray );
|
||||
mat4.transpose( invMatrixArray, invMatrixArray );
|
||||
},
|
||||
|
||||
apply: function () {
|
||||
|
||||
if ( !this._enable ) return;
|
||||
|
||||
var uniformMap = this.getOrCreateUniforms();
|
||||
|
||||
uniformMap.position.setFloat4( this._position );
|
||||
|
||||
if ( this.isSpotLight() ) {
|
||||
var spotsize = Math.cos( this._spotCutoff * Math.PI / 180.0 );
|
||||
uniformMap.spotCutOff.setFloat( spotsize );
|
||||
uniformMap.spotBlend.setFloat( ( 1.0 - spotsize ) * this._spotBlend );
|
||||
uniformMap.direction.setFloat3( this._direction );
|
||||
}
|
||||
|
||||
if ( this.isHemiLight() )
|
||||
uniformMap.ground.setFloat4( this._ground );
|
||||
|
||||
uniformMap.attenuation.setFloat4( this._attenuation );
|
||||
uniformMap.diffuse.setFloat4( this._diffuse );
|
||||
uniformMap.specular.setFloat4( this._specular );
|
||||
uniformMap.ambient.setFloat4( this._ambient );
|
||||
}
|
||||
|
||||
} ), 'osg', 'Light' );
|
||||
|
||||
MACROUTILS.setTypeID( Light );
|
||||
|
||||
module.exports = Light;
|
|
@ -1,53 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Node = require( 'osg/Node' );
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
|
||||
/**
|
||||
* LightSource is a positioned node to use with StateAttribute Light
|
||||
* @class LightSource
|
||||
*/
|
||||
var LightSource = function () {
|
||||
Node.call( this );
|
||||
this._light = undefined;
|
||||
this._referenceFrame = TransformEnums.RELATIVE_RF;
|
||||
};
|
||||
|
||||
/** @lends LightSource.prototype */
|
||||
LightSource.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Node.prototype, {
|
||||
getLight: function () {
|
||||
return this._light;
|
||||
},
|
||||
setLight: function ( light ) {
|
||||
this._light = light;
|
||||
},
|
||||
setReferenceFrame: function ( value ) {
|
||||
this._referenceFrame = value;
|
||||
},
|
||||
getReferenceFrame: function () {
|
||||
return this._referenceFrame;
|
||||
},
|
||||
computeBoundingSphere: ( function () {
|
||||
var tmp = vec3.create();
|
||||
|
||||
return function ( bsphere ) {
|
||||
Node.prototype.computeBoundingSphere.call( this, bsphere );
|
||||
|
||||
if ( this._light !== undefined && this._referenceFrame === TransformEnums.RELATIVE_RF ) {
|
||||
var position = this._light.getPosition();
|
||||
|
||||
if ( position[ 3 ] !== 0.0 ) {
|
||||
bsphere.expandByvec3( vec3.scale( tmp, position, 1.0 / position[ 3 ] ) );
|
||||
}
|
||||
}
|
||||
|
||||
return bsphere;
|
||||
};
|
||||
} )()
|
||||
|
||||
} ), 'osg', 'LightSource' );
|
||||
|
||||
MACROUTILS.setTypeID( LightSource );
|
||||
|
||||
module.exports = LightSource;
|
|
@ -1,22 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
|
||||
var LineWidth = function ( lineWidth ) {
|
||||
StateAttribute.call( this );
|
||||
this.lineWidth = 1.0;
|
||||
if ( lineWidth !== undefined ) {
|
||||
this.lineWidth = lineWidth;
|
||||
}
|
||||
};
|
||||
LineWidth.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
attributeType: 'LineWidth',
|
||||
cloneType: function () {
|
||||
return new LineWidth();
|
||||
},
|
||||
apply: function ( state ) {
|
||||
state.getGraphicContext().lineWidth( this.lineWidth );
|
||||
}
|
||||
} ), 'osg', 'LineWidth' );
|
||||
|
||||
module.exports = LineWidth;
|
|
@ -1,177 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Node = require( 'osg/Node' );
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var vec2 = require( 'osg/glMatrix' ).vec2;
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var BoundingSphere = require( 'osg/BoundingSphere' );
|
||||
|
||||
/**
|
||||
* Lod that can contains child node
|
||||
* @class Lod
|
||||
*/
|
||||
var Lod = function () {
|
||||
Node.call( this );
|
||||
this._radius = -1;
|
||||
this._range = [];
|
||||
this._rangeMode = Lod.DISTANCE_FROM_EYE_POINT;
|
||||
this._userDefinedCenter = [];
|
||||
this._centerMode = Lod.USE_BOUNDING_SPHERE_CENTER;
|
||||
};
|
||||
|
||||
Lod.DISTANCE_FROM_EYE_POINT = 0;
|
||||
Lod.PIXEL_SIZE_ON_SCREEN = 1;
|
||||
|
||||
Lod.USE_BOUNDING_SPHERE_CENTER = 0;
|
||||
Lod.USER_DEFINED_CENTER = 1;
|
||||
Lod.UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED = 2;
|
||||
|
||||
/** @lends Lod.prototype */
|
||||
Lod.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Node.prototype, {
|
||||
// Functions here
|
||||
getRadius: function () {
|
||||
return this._radius;
|
||||
},
|
||||
|
||||
/** Set the object-space reference radius of the volume enclosed by the LOD.
|
||||
* Used to determine the bounding sphere of the LOD in the absence of any children.*/
|
||||
setRadius: function ( radius ) {
|
||||
this._radius = radius;
|
||||
},
|
||||
|
||||
setCenter: function ( center ) {
|
||||
if ( this._centerMode !== Lod.UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED )
|
||||
this._centerMode = Lod.USER_DEFINED_CENTER;
|
||||
this._userDefinedCenter = center;
|
||||
},
|
||||
|
||||
getCenter: function () {
|
||||
if ( ( this._centerMode === Lod.USER_DEFINED_CENTER ) || ( this._centerMode === Lod.UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED ) )
|
||||
return this._userDefinedCenter;
|
||||
else return this.getBound().center();
|
||||
},
|
||||
|
||||
setCenterMode: function ( centerMode ) {
|
||||
this._centerMode = centerMode;
|
||||
},
|
||||
|
||||
computeBoundingSphere: function ( bsphere ) {
|
||||
if ( this._centerMode === Lod.USER_DEFINED_CENTER && this._radius >= 0.0 ) {
|
||||
bsphere.set( this._userDefinedCenter, this._radius );
|
||||
return bsphere;
|
||||
} else if ( this._centerMode === Lod.UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED && this._radius >= 0.0 ) {
|
||||
bsphere.set( this._userDefinedCenter, this._radius );
|
||||
var bs = new BoundingSphere();
|
||||
bsphere.expandByBoundingSphere( Node.prototype.computeBoundingSphere.call( this, bs ) );
|
||||
return bsphere;
|
||||
} else {
|
||||
Node.prototype.computeBoundingSphere.call( this, bsphere );
|
||||
return bsphere;
|
||||
}
|
||||
},
|
||||
|
||||
projectBoundingSphere: ( function () {
|
||||
// from http://www.iquilezles.org/www/articles/sphereproj/sphereproj.htm
|
||||
// Sample code at http://www.shadertoy.com/view/XdBGzd?
|
||||
var o = vec3.create();
|
||||
return function ( sph, camMatrix, fle ) {
|
||||
vec3.transformMat4( o, sph.center(), camMatrix );
|
||||
var r2 = sph.radius2();
|
||||
var z2 = o[ 2 ] * o[ 2 ];
|
||||
var l2 = vec3.sqrLen( o );
|
||||
var area = -Math.PI * fle * fle * r2 * Math.sqrt( Math.abs( ( l2 - r2 ) / ( r2 - z2 ) ) ) / ( r2 - z2 );
|
||||
return area;
|
||||
};
|
||||
} )(),
|
||||
|
||||
setRangeMode: function ( mode ) {
|
||||
//TODO: check if mode is correct
|
||||
this._rangeMode = mode;
|
||||
},
|
||||
|
||||
addChildNode: function ( node ) {
|
||||
|
||||
Node.prototype.addChild.call( this, node );
|
||||
if ( this.children.length > this._range.length ) {
|
||||
var r = [];
|
||||
var max = 0.0;
|
||||
if ( this._range.lenght > 0 )
|
||||
max = this._range[ this._range.length - 1 ][ 1 ];
|
||||
r.push( vec2.fromValues( max, max ) );
|
||||
this._range.push( r );
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
addChild: function ( node, min, max ) {
|
||||
Node.prototype.addChild.call( this, node );
|
||||
|
||||
if ( this.children.length > this._range.length ) {
|
||||
var r = [];
|
||||
r.push( vec2.fromValues( min, min ) );
|
||||
this._range.push( r );
|
||||
}
|
||||
this._range[ this.children.length - 1 ][ 0 ] = min;
|
||||
this._range[ this.children.length - 1 ][ 1 ] = max;
|
||||
return true;
|
||||
},
|
||||
|
||||
traverse: ( function () {
|
||||
|
||||
// avoid to generate variable on the heap to limit garbage collection
|
||||
// instead create variable and use the same each time
|
||||
var zeroVector = vec3.create();
|
||||
var eye = vec3.create();
|
||||
var viewModel = mat4.create();
|
||||
|
||||
return function ( visitor ) {
|
||||
var traversalMode = visitor.traversalMode;
|
||||
|
||||
switch ( traversalMode ) {
|
||||
|
||||
case NodeVisitor.TRAVERSE_ALL_CHILDREN:
|
||||
|
||||
for ( var index = 0; index < this.children.length; index++ ) {
|
||||
this.children[ index ].accept( visitor );
|
||||
}
|
||||
break;
|
||||
|
||||
case ( NodeVisitor.TRAVERSE_ACTIVE_CHILDREN ):
|
||||
var requiredRange = 0;
|
||||
var matrix = visitor.getCurrentModelViewMatrix();
|
||||
mat4.invert( viewModel, matrix );
|
||||
// Calculate distance from viewpoint
|
||||
if ( this._rangeMode === Lod.DISTANCE_FROM_EYE_POINT ) {
|
||||
vec3.transformMat4( eye, zeroVector, viewModel );
|
||||
var d = vec3.distance( this.getBound().center(), eye );
|
||||
requiredRange = d * visitor.getLODScale();
|
||||
} else {
|
||||
// Let's calculate pixels on screen
|
||||
var projmatrix = visitor.getCurrentProjectionMatrix();
|
||||
// focal lenght is the value stored in projmatrix[0]
|
||||
requiredRange = this.projectBoundingSphere( this.getBound(), matrix, projmatrix[ 0 ] );
|
||||
// Multiply by a factor to get the real area value
|
||||
requiredRange = ( ( requiredRange * visitor.getViewport().width() * visitor.getViewport().width() ) * 0.25 ) / visitor.getLODScale();
|
||||
}
|
||||
|
||||
var numChildren = this.children.length;
|
||||
if ( this._range.length < numChildren ) numChildren = this._range.length;
|
||||
|
||||
for ( var j = 0; j < numChildren; ++j ) {
|
||||
if ( this._range[ j ][ 0 ] <= requiredRange && requiredRange < this._range[ j ][ 1 ] ) {
|
||||
this.children[ j ].accept( visitor );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
} )()
|
||||
|
||||
} ), 'osg', 'Lod' );
|
||||
|
||||
MACROUTILS.setTypeID( Lod );
|
||||
module.exports = Lod;
|
|
@ -1,67 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var Map = function ( obj ) {
|
||||
|
||||
window.Object.defineProperty( this, '_dirty', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: true
|
||||
} );
|
||||
|
||||
window.Object.defineProperty( this, '_keys', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: undefined
|
||||
} );
|
||||
|
||||
if ( obj ) this.setMap( obj );
|
||||
};
|
||||
|
||||
Map.prototype = {
|
||||
|
||||
getKeys: function () {
|
||||
if ( this._dirty ) {
|
||||
this._keys = window.Object.keys( this );
|
||||
this._dirty = false;
|
||||
}
|
||||
return this._keys;
|
||||
},
|
||||
|
||||
dirty: function () {
|
||||
this._dirty = true;
|
||||
},
|
||||
|
||||
remove: function ( key ) {
|
||||
//this[ key ] = undefined;
|
||||
delete this[ key ];
|
||||
this.dirty();
|
||||
this.getKeys();
|
||||
},
|
||||
|
||||
setMap: function ( map ) {
|
||||
|
||||
var i, l;
|
||||
// remove all
|
||||
var keys = window.Object.keys( this );
|
||||
if ( keys.length > 0 ) {
|
||||
for ( i = 0, l = keys.length; i < l; i++ )
|
||||
delete this[ keys[ i ] ];
|
||||
}
|
||||
|
||||
// add new
|
||||
keys = window.Object.keys( map );
|
||||
if ( keys.length > 0 ) {
|
||||
for ( i = 0, l = keys.length; i < l; i++ ) {
|
||||
var key = keys[ i ];
|
||||
this[ key ] = map[ key ];
|
||||
}
|
||||
}
|
||||
|
||||
this.dirty();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = Map;
|
|
@ -1,108 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var vec4 = require( 'osg/glMatrix' ).vec4;
|
||||
var Uniform = require( 'osg/Uniform' );
|
||||
var Map = require( 'osg/Map' );
|
||||
|
||||
// Define a material attribute
|
||||
var Material = function () {
|
||||
StateAttribute.call( this );
|
||||
this._ambient = vec4.fromValues( 0.2, 0.2, 0.2, 1.0 );
|
||||
this._diffuse = vec4.fromValues( 0.8, 0.8, 0.8, 1.0 );
|
||||
this._specular = vec4.fromValues( 0.0, 0.0, 0.0, 1.0 );
|
||||
this._emission = vec4.fromValues( 0.0, 0.0, 0.0, 1.0 );
|
||||
this._shininess = 12.5;
|
||||
};
|
||||
|
||||
Material.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'Material',
|
||||
|
||||
cloneType: function () {
|
||||
return new Material();
|
||||
},
|
||||
|
||||
getParameterName: function ( name ) {
|
||||
return 'u' + this.getType() + '_' + name;
|
||||
},
|
||||
|
||||
getOrCreateUniforms: function () {
|
||||
var obj = Material;
|
||||
if ( obj.uniforms ) return obj.uniforms;
|
||||
|
||||
var uniformList = {
|
||||
ambient: Uniform.createFloat4( 'uMaterialAmbient' ),
|
||||
diffuse: Uniform.createFloat4( 'uMaterialDiffuse' ),
|
||||
specular: Uniform.createFloat4( 'uMaterialSpecular' ),
|
||||
emission: Uniform.createFloat4( 'uMaterialEmission' ),
|
||||
shininess: Uniform.createFloat1( 'uMaterialShininess' )
|
||||
};
|
||||
|
||||
obj.uniforms = new Map( uniformList );
|
||||
return obj.uniforms;
|
||||
},
|
||||
|
||||
setEmission: function ( a ) {
|
||||
vec4.copy( this._emission, a );
|
||||
},
|
||||
|
||||
getEmission: function () {
|
||||
return this._emission;
|
||||
},
|
||||
|
||||
setAmbient: function ( a ) {
|
||||
vec4.copy( this._ambient, a );
|
||||
},
|
||||
|
||||
getAmbient: function () {
|
||||
return this._ambient;
|
||||
},
|
||||
|
||||
setSpecular: function ( a ) {
|
||||
vec4.copy( this._specular, a );
|
||||
},
|
||||
|
||||
getSpecular: function () {
|
||||
return this._specular;
|
||||
},
|
||||
|
||||
setDiffuse: function ( a ) {
|
||||
vec4.copy( this._diffuse, a );
|
||||
},
|
||||
|
||||
getDiffuse: function () {
|
||||
return this._diffuse;
|
||||
},
|
||||
|
||||
setShininess: function ( a ) {
|
||||
this._shininess = a;
|
||||
},
|
||||
|
||||
getShininess: function () {
|
||||
return this._shininess;
|
||||
},
|
||||
|
||||
setTransparency: function ( a ) {
|
||||
this._diffuse[ 3 ] = 1.0 - a;
|
||||
},
|
||||
|
||||
getTransparency: function () {
|
||||
return this._diffuse[ 3 ];
|
||||
},
|
||||
|
||||
apply: function () {
|
||||
var uniforms = this.getOrCreateUniforms();
|
||||
|
||||
uniforms.ambient.setFloat4( this._ambient );
|
||||
uniforms.diffuse.setFloat4( this._diffuse );
|
||||
uniforms.specular.setFloat4( this._specular );
|
||||
uniforms.emission.setFloat4( this._emission );
|
||||
uniforms.shininess.setFloat( this._shininess );
|
||||
|
||||
}
|
||||
|
||||
|
||||
} ), 'osg', 'Material' );
|
||||
|
||||
module.exports = Material;
|
|
@ -1 +0,0 @@
|
|||
module.exports = require( 'osg/deprecated-MatrixVector/Matrix' );
|
|
@ -1,45 +0,0 @@
|
|||
'use strict';
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
|
||||
|
||||
/**
|
||||
* Prevents Memory fragmentation, GC heavy usage
|
||||
* using pre-allocated memory segment
|
||||
* allowing reuse of memory
|
||||
* @class MatrixMemoryPool
|
||||
*/
|
||||
var MatrixMemoryPool = function () {
|
||||
|
||||
this._stack = [ mat4.create() ];
|
||||
this._current = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** @lends MatrixMemoryPool.prototype */
|
||||
MatrixMemoryPool.prototype = {
|
||||
|
||||
// start reuse the stack
|
||||
reset: function () {
|
||||
|
||||
this._current = 0;
|
||||
|
||||
},
|
||||
|
||||
get: function () {
|
||||
|
||||
var m = this._stack[ this._current++ ];
|
||||
|
||||
if ( this._current === this._stack.length ) {
|
||||
|
||||
this._stack.push( mat4.create() );
|
||||
|
||||
}
|
||||
|
||||
return m;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = MatrixMemoryPool;
|
|
@ -1,56 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var Transform = require( 'osg/Transform' );
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
|
||||
|
||||
/**
|
||||
* MatrixTransform is a Transform Node that can be customized with user matrix
|
||||
* @class MatrixTransform
|
||||
*/
|
||||
var MatrixTransform = function () {
|
||||
Transform.call( this );
|
||||
this.matrix = mat4.create();
|
||||
};
|
||||
|
||||
/** @lends MatrixTransform.prototype */
|
||||
MatrixTransform.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Transform.prototype, {
|
||||
|
||||
getMatrix: function () {
|
||||
return this.matrix;
|
||||
},
|
||||
|
||||
setMatrix: function ( m ) {
|
||||
this.matrix = m;
|
||||
this.dirtyBound();
|
||||
},
|
||||
|
||||
// local to "local world" (not Global World)
|
||||
computeLocalToWorldMatrix: function ( matrix /*, nodeVisitor */ ) {
|
||||
|
||||
if ( this.referenceFrame === TransformEnums.RELATIVE_RF ) {
|
||||
mat4.mul( matrix, matrix, this.matrix );
|
||||
} else {
|
||||
mat4.copy( matrix, this.matrix );
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
computeWorldToLocalMatrix: ( function () {
|
||||
var minverse = mat4.create();
|
||||
return function ( matrix /*, nodeVisitor */ ) {
|
||||
|
||||
mat4.invert( minverse, this.matrix );
|
||||
if ( this.referenceFrame === TransformEnums.RELATIVE_RF ) {
|
||||
mat4.mul( matrix, minverse, matrix );
|
||||
} else { // absolute
|
||||
mat4.copy( matrix, minverse );
|
||||
}
|
||||
return true;
|
||||
};
|
||||
} )()
|
||||
} ), 'osg', 'MatrixTransform' );
|
||||
MACROUTILS.setTypeID( MatrixTransform );
|
||||
|
||||
module.exports = MatrixTransform;
|
|
@ -1,544 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Object = require( 'osg/Object' );
|
||||
var BoundingBox = require( 'osg/BoundingBox' );
|
||||
var BoundingSphere = require( 'osg/BoundingSphere' );
|
||||
var StateSet = require( 'osg/StateSet' );
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var MatrixMemoryPool = require( 'osg/MatrixMemoryPool' );
|
||||
var ComputeMatrixFromNodePath = require( 'osg/computeMatrixFromNodePath' );
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
|
||||
|
||||
/**
|
||||
* Node that can contains child node
|
||||
* @class Node
|
||||
*/
|
||||
var Node = function () {
|
||||
Object.call( this );
|
||||
|
||||
this.children = [];
|
||||
this._parents = [];
|
||||
/*jshint bitwise: false */
|
||||
this.nodeMask = ~0;
|
||||
/*jshint bitwise: true */
|
||||
|
||||
this._boundingSphere = new BoundingSphere();
|
||||
this._boundingSphereComputed = false;
|
||||
|
||||
this._boundingBox = new BoundingBox();
|
||||
this._boundingBoxComputed = false;
|
||||
|
||||
this._updateCallbacks = [];
|
||||
this._cullCallback = undefined;
|
||||
this._cullingActive = true;
|
||||
this._numChildrenWithCullingDisabled = 0;
|
||||
this._numChildrenRequiringUpdateTraversal = 0;
|
||||
|
||||
// it's a tmp object for internal use, do not use
|
||||
this._tmpBox = new BoundingBox();
|
||||
};
|
||||
|
||||
Node._reservedMatrixStack = new MatrixMemoryPool();
|
||||
var nodeGetMat = function () {
|
||||
var mat = Node._reservedMatrixStack.get.bind( Node._reservedMatrixStack );
|
||||
return mat4.identity( mat );
|
||||
};
|
||||
|
||||
/** @lends Node.prototype */
|
||||
Node.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Object.prototype, {
|
||||
|
||||
/**
|
||||
Return StateSet and create it if it does not exist yet
|
||||
@type StateSet
|
||||
*/
|
||||
getOrCreateStateSet: function () {
|
||||
if ( !this.stateset ) this.setStateSet( new StateSet() );
|
||||
return this.stateset;
|
||||
},
|
||||
|
||||
getStateSet: function () {
|
||||
return this.stateset;
|
||||
},
|
||||
|
||||
accept: function ( nv ) {
|
||||
if ( nv.validNodeMask( this ) ) {
|
||||
nv.pushOntoNodePath( this );
|
||||
nv.apply( this );
|
||||
nv.popFromNodePath();
|
||||
}
|
||||
},
|
||||
|
||||
dirtyBound: function () {
|
||||
if ( this._boundingSphereComputed === true || this._boundingBoxComputed === true ) {
|
||||
this._boundingSphereComputed = false;
|
||||
this._boundingBoxComputed = false;
|
||||
var parents = this._parents;
|
||||
for ( var i = 0, l = parents.length; i < l; i++ ) {
|
||||
parents[ i ].dirtyBound();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setNodeMask: function ( mask ) {
|
||||
this.nodeMask = mask;
|
||||
},
|
||||
|
||||
getNodeMask: function () {
|
||||
return this.nodeMask;
|
||||
},
|
||||
|
||||
setStateSet: function ( stateSet ) {
|
||||
|
||||
if ( this.stateset === stateSet ) return;
|
||||
|
||||
var deltaUpdate = 0;
|
||||
|
||||
if ( this.stateset ) {
|
||||
if ( this.stateset.requiresUpdateTraversal() ) deltaUpdate--;
|
||||
this.stateset.removeParent( this );
|
||||
}
|
||||
|
||||
if ( stateSet ) {
|
||||
stateSet.addParent( this );
|
||||
if ( stateSet.requiresUpdateTraversal() ) ++deltaUpdate;
|
||||
}
|
||||
|
||||
if ( deltaUpdate !== 0 )
|
||||
this.setNumChildrenRequiringUpdateTraversal( this.getNumChildrenRequiringUpdateTraversal() + deltaUpdate );
|
||||
|
||||
this.stateset = stateSet;
|
||||
},
|
||||
|
||||
_updateNumChildrenRequeringUpdateTraversal: function ( delta ) {
|
||||
|
||||
if ( this._numChildrenRequiringUpdateTraversal === 0 && this._parents.length ) {
|
||||
// the number of callbacks has changed, need to pass this
|
||||
// on to parents so they know whether app traversal is
|
||||
// required on this subgraph.
|
||||
for ( var i = 0, l = this._parents.length; i < l; i++ ) {
|
||||
var parent = this._parents[ i ];
|
||||
var num = parent.getNumChildrenRequiringUpdateTraversal();
|
||||
parent.setNumChildrenRequiringUpdateTraversal( num + delta );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setNumChildrenRequiringUpdateTraversal: function ( num ) {
|
||||
|
||||
// if no changes just return.
|
||||
if ( this._numChildrenRequiringUpdateTraversal === num ) return;
|
||||
|
||||
// note, if _updateCallback is set then the
|
||||
// parents won't be affected by any changes to
|
||||
// _numChildrenRequiringUpdateTraversal so no need to inform them.
|
||||
if ( !this._updateCallbacks.length && this._parents.length ) {
|
||||
|
||||
// need to pass on changes to parents.
|
||||
var delta = 0;
|
||||
if ( this._numChildrenRequiringUpdateTraversal > 0 ) --delta;
|
||||
if ( num > 0 ) ++delta;
|
||||
|
||||
if ( delta !== 0 ) {
|
||||
// the number of callbacks has changed, need to pass this
|
||||
// on to parents so they know whether app traversal is
|
||||
// required on this subgraph.
|
||||
var parents = this._parents;
|
||||
for ( var i = 0, l = parents.length; i < l; i++ ) {
|
||||
var parent = parents[ i ];
|
||||
var parentNum = parent.getNumChildrenRequiringUpdateTraversal();
|
||||
parent.setNumChildrenRequiringUpdateTraversal( parentNum + delta );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally update this objects value.
|
||||
this._numChildrenRequiringUpdateTraversal = num;
|
||||
|
||||
},
|
||||
|
||||
getNumChildrenRequiringUpdateTraversal: function () {
|
||||
return this._numChildrenRequiringUpdateTraversal;
|
||||
},
|
||||
|
||||
/**
|
||||
<p>
|
||||
Set update node callback, called during update traversal.
|
||||
The Object must have the following method
|
||||
update(node, nodeVisitor) {}
|
||||
note, callback is responsible for scenegraph traversal so
|
||||
they must call traverse(node,nv) to ensure that the
|
||||
scene graph subtree (and associated callbacks) are traversed.
|
||||
</p>
|
||||
<p>
|
||||
Here a dummy UpdateCallback example
|
||||
</p>
|
||||
@example
|
||||
var DummyUpdateCallback = function() {};
|
||||
DummyUpdateCallback.prototype = {
|
||||
update: function(node, nodeVisitor) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@param Oject callback
|
||||
*/
|
||||
setUpdateCallback: function ( cb ) {
|
||||
Notify.warn( 'deprecated use instead addUpdateCallback/removeUpdateCallback' );
|
||||
if ( cb === this._updateCallbacks[ 0 ] || !cb ) return;
|
||||
|
||||
var hasExistingCallback = Boolean( this._updateCallbacks.length );
|
||||
if ( !this._updateCallbacks.length )
|
||||
this.addUpdateCallback( cb );
|
||||
else
|
||||
this._updateCallbacks[ 0 ] = cb;
|
||||
|
||||
if ( !hasExistingCallback )
|
||||
this._updateNumChildrenRequeringUpdateTraversal( 1 );
|
||||
},
|
||||
|
||||
/** Get update node callback, called during update traversal.
|
||||
@type Oject
|
||||
*/
|
||||
getUpdateCallback: function () {
|
||||
return this._updateCallbacks[ 0 ];
|
||||
},
|
||||
|
||||
addUpdateCallback: function ( cb ) {
|
||||
var hasExistingCallback = Boolean( this._updateCallbacks.length );
|
||||
this._updateCallbacks.push( cb );
|
||||
|
||||
// send the signal on first add
|
||||
if ( !hasExistingCallback )
|
||||
this._updateNumChildrenRequeringUpdateTraversal( 1 );
|
||||
},
|
||||
|
||||
removeUpdateCallback: function ( cb ) {
|
||||
var arrayIdx = this._updateCallbacks.indexOf( cb );
|
||||
if ( arrayIdx === -1 ) return;
|
||||
this._updateCallbacks.splice( arrayIdx, 1 );
|
||||
|
||||
// send the signal when no more callback
|
||||
if ( !this._updateCallbacks.length )
|
||||
this._updateNumChildrenRequeringUpdateTraversal( -1 );
|
||||
|
||||
},
|
||||
getUpdateCallbackList: function () {
|
||||
return this._updateCallbacks;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
<p>
|
||||
Set cull node callback, called during cull traversal.
|
||||
The Object must have the following method
|
||||
cull(node, nodeVisitor) {}
|
||||
note, callback is responsible for scenegraph traversal so
|
||||
they must return true to traverse.
|
||||
</p>
|
||||
<p>
|
||||
Here a dummy CullCallback example
|
||||
</p>
|
||||
@example
|
||||
var DummyCullCallback = function() {};
|
||||
DummyCullCallback.prototype = {
|
||||
cull: function(node, nodeVisitor) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@param Oject callback
|
||||
*/
|
||||
setCullCallback: function ( cb ) {
|
||||
this._cullCallback = cb;
|
||||
},
|
||||
getCullCallback: function () {
|
||||
return this._cullCallback;
|
||||
},
|
||||
|
||||
hasChild: function ( child ) {
|
||||
for ( var i = 0, l = this.children.length; i < l; i++ ) {
|
||||
if ( this.children[ i ] === child ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
addChild: function ( child ) {
|
||||
|
||||
if ( this.children.indexOf( child ) !== -1 ) return undefined;
|
||||
|
||||
this.children.push( child );
|
||||
child.addParent( this );
|
||||
this.dirtyBound();
|
||||
|
||||
// could now require app traversal thanks to the new subgraph,
|
||||
// so need to check and update if required.
|
||||
if ( child.getNumChildrenRequiringUpdateTraversal() > 0 ||
|
||||
child.getUpdateCallbackList().length ) {
|
||||
this.setNumChildrenRequiringUpdateTraversal(
|
||||
this.getNumChildrenRequiringUpdateTraversal() + 1
|
||||
);
|
||||
}
|
||||
|
||||
return child;
|
||||
},
|
||||
|
||||
getChildren: function () {
|
||||
return this.children;
|
||||
},
|
||||
getNumChildren: function () {
|
||||
return this.children.length;
|
||||
},
|
||||
getChild: function ( num ) {
|
||||
return this.children[ num ];
|
||||
},
|
||||
getParents: function () {
|
||||
return this._parents;
|
||||
},
|
||||
|
||||
addParent: function ( parent ) {
|
||||
this._parents.push( parent );
|
||||
},
|
||||
|
||||
removeParent: function ( parent ) {
|
||||
var idx = this._parents.indexOf( parent );
|
||||
if ( idx === -1 ) return;
|
||||
this._parents.splice( idx, 1 );
|
||||
},
|
||||
|
||||
removeChildren: function () {
|
||||
var children = this.children;
|
||||
var nbChildren = children.length;
|
||||
if ( !nbChildren ) return;
|
||||
|
||||
var updateCallbackRemoved = 0;
|
||||
|
||||
for ( var i = 0; i < nbChildren; i++ ) {
|
||||
var child = children[ i ];
|
||||
child.removeParent( this );
|
||||
if ( child.getNumChildrenRequiringUpdateTraversal() > 0 || child.getUpdateCallbackList().length ) ++updateCallbackRemoved;
|
||||
}
|
||||
|
||||
children.length = 0;
|
||||
if ( updateCallbackRemoved )
|
||||
this.setNumChildrenRequiringUpdateTraversal( this.getNumChildrenRequiringUpdateTraversal() - updateCallbackRemoved );
|
||||
|
||||
this.dirtyBound();
|
||||
},
|
||||
|
||||
// preserve order
|
||||
removeChild: function ( child ) {
|
||||
|
||||
var children = this.children;
|
||||
var id = children.indexOf( child );
|
||||
if ( id === -1 ) return;
|
||||
|
||||
child.removeParent( this );
|
||||
children.splice( id, 1 );
|
||||
|
||||
if ( child.getNumChildrenRequiringUpdateTraversal() > 0 || child.getUpdateCallbackList().length )
|
||||
this.setNumChildrenRequiringUpdateTraversal( this.getNumChildrenRequiringUpdateTraversal() - 1 );
|
||||
|
||||
},
|
||||
|
||||
traverse: function ( visitor ) {
|
||||
var children = this.children;
|
||||
for ( var i = 0, l = children.length; i < l; i++ ) {
|
||||
var child = children[ i ];
|
||||
child.accept( visitor );
|
||||
}
|
||||
},
|
||||
|
||||
ascend: function ( visitor ) {
|
||||
var parents = this._parents;
|
||||
for ( var i = 0, l = parents.length; i < l; i++ ) {
|
||||
var parent = parents[ i ];
|
||||
parent.accept( visitor );
|
||||
}
|
||||
},
|
||||
|
||||
getBoundingBox: function () {
|
||||
if ( !this._boundingBoxComputed ) {
|
||||
this.computeBoundingBox( this._boundingBox );
|
||||
this._boundingBoxComputed = true;
|
||||
}
|
||||
return this._boundingBox;
|
||||
},
|
||||
|
||||
computeBoundingBox: function ( bbox ) {
|
||||
|
||||
// circular dependency... not sure if the global visitor instance should be instancied here
|
||||
var ComputeBoundsVisitor = require( 'osg/ComputeBoundsVisitor' );
|
||||
var cbv = ComputeBoundsVisitor.instance = ComputeBoundsVisitor.instance || new ComputeBoundsVisitor();
|
||||
cbv.setNodeMaskOverride( ~0x0 ); // traverse everything to be consistent with computeBoundingSphere
|
||||
cbv.reset();
|
||||
|
||||
cbv.apply( this );
|
||||
bbox.copy( cbv.getBoundingBox() );
|
||||
return bbox;
|
||||
},
|
||||
|
||||
getBoundingSphere: function () {
|
||||
return this.getBound();
|
||||
},
|
||||
|
||||
getBound: function () {
|
||||
if ( !this._boundingSphereComputed ) {
|
||||
this.computeBoundingSphere( this._boundingSphere );
|
||||
this._boundingSphereComputed = true;
|
||||
}
|
||||
return this._boundingSphere;
|
||||
},
|
||||
|
||||
computeBoundingSphere: function ( bSphere ) {
|
||||
|
||||
var children = this.children;
|
||||
var l = children.length;
|
||||
|
||||
bSphere.init();
|
||||
if ( l === 0 ) return bSphere;
|
||||
|
||||
var cc, i;
|
||||
var bb = this._tmpBox;
|
||||
bb.init();
|
||||
for ( i = 0; i < l; i++ ) {
|
||||
cc = children[ i ];
|
||||
if ( cc.referenceFrame !== TransformEnums.ABSOLUTE_RF ) {
|
||||
bb.expandByBoundingSphere( cc.getBound() );
|
||||
}
|
||||
}
|
||||
if ( !bb.valid() ) return bSphere;
|
||||
|
||||
bSphere.set( bb.center( bSphere.center() ), 0.0 );
|
||||
for ( i = 0; i < l; i++ ) {
|
||||
cc = children[ i ];
|
||||
if ( cc.referenceFrame !== TransformEnums.ABSOLUTE_RF ) {
|
||||
bSphere.expandRadiusBySphere( cc.getBound() );
|
||||
}
|
||||
}
|
||||
return bSphere;
|
||||
},
|
||||
|
||||
// matrixCreate allow user handling of garbage collection of matrices
|
||||
getWorldMatrices: ( function () {
|
||||
var CollectParentPaths = function () {
|
||||
this.nodePaths = [];
|
||||
this.halt = undefined;
|
||||
NodeVisitor.call( this, NodeVisitor.TRAVERSE_PARENTS );
|
||||
};
|
||||
CollectParentPaths.prototype = MACROUTILS.objectInherit( NodeVisitor.prototype, {
|
||||
reset: function () {
|
||||
this.nodePath.length = 0;
|
||||
this.nodePaths.length = 0;
|
||||
},
|
||||
apply: function ( node ) {
|
||||
if ( node._parents.length === 0 || node === this.halt || node.referenceFrame === TransformEnums.ABSOLUTE_RF ) {
|
||||
// copy
|
||||
this.nodePaths.push( this.nodePath.slice( 0 ) );
|
||||
} else {
|
||||
this.traverse( node );
|
||||
}
|
||||
}
|
||||
} );
|
||||
var collected = new CollectParentPaths();
|
||||
collected.setNodeMaskOverride( ~0x0 ); // traverse everything
|
||||
|
||||
return function computeLocalToWorldList( halt, matrixCreate ) {
|
||||
collected.reset();
|
||||
collected.halt = halt;
|
||||
|
||||
this.accept( collected );
|
||||
var matrixList = [];
|
||||
|
||||
var matrixGenerator = matrixCreate || mat4.create;
|
||||
for ( var i = 0, l = collected.nodePaths.length; i < l; i++ ) {
|
||||
var np = collected.nodePaths[ i ];
|
||||
var m = matrixGenerator();
|
||||
if ( np.length !== 0 ) {
|
||||
ComputeMatrixFromNodePath.computeLocalToWorld( np, true, m );
|
||||
}
|
||||
matrixList.push( m );
|
||||
}
|
||||
|
||||
return matrixList;
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
// same as getWorldMatrices GC: Perf WIN
|
||||
getWorldMatrix: function ( halt, matrix ) {
|
||||
|
||||
// pass allocator on master
|
||||
var matrixList = this.getWorldMatrices( halt, nodeGetMat );
|
||||
|
||||
if ( matrixList.length === 0 ) {
|
||||
|
||||
mat4.identity( matrix );
|
||||
|
||||
} else {
|
||||
|
||||
mat4.copy( matrix, matrixList[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
Node._reservedMatrixStack.reset();
|
||||
return matrix;
|
||||
|
||||
},
|
||||
|
||||
setCullingActive: function ( value ) {
|
||||
if ( this._cullingActive === value ) return;
|
||||
if ( this._numChildrenWithCullingDisabled === 0 && this._parents.length > 0 ) {
|
||||
var delta = 0;
|
||||
if ( !this._cullingActive ) --delta;
|
||||
if ( !value ) ++delta;
|
||||
if ( delta !== 0 ) {
|
||||
for ( var i = 0, k = this._parents.length; i < k; i++ ) {
|
||||
this._parents[ i ].setNumChildrenWithCullingDisabled( this._parents[ i ].getNumChildrenWithCullingDisabled() + delta );
|
||||
}
|
||||
}
|
||||
}
|
||||
this._cullingActive = value;
|
||||
},
|
||||
|
||||
getCullingActive: function () {
|
||||
return this._cullingActive;
|
||||
},
|
||||
|
||||
isCullingActive: function () {
|
||||
return this._numChildrenWithCullingDisabled === 0 && this._cullingActive && this.getBound().valid();
|
||||
},
|
||||
|
||||
setNumChildrenWithCullingDisabled: function ( num ) {
|
||||
if ( this._numChildrenWithCullingDisabled === num ) return;
|
||||
if ( this._cullingActive && this._parents.length > 0 ) {
|
||||
var delta = 0;
|
||||
if ( this._numChildrenWithCullingDisabled > 0 ) --delta;
|
||||
if ( num > 0 ) ++delta;
|
||||
if ( delta !== 0 ) {
|
||||
for ( var i = 0, k = this._parents.length; i < k; i++ ) {
|
||||
this._parents[ i ].setNumChildrenWithCullingDisabled( this._parents[ i ].getNumChildrenWithCullingDisabled() + delta );
|
||||
}
|
||||
}
|
||||
}
|
||||
this._numChildrenWithCullingDisabled = num;
|
||||
},
|
||||
|
||||
getNumChildrenWithCullingDisabled: function () {
|
||||
return this._numChildrenWithCullingDisabled;
|
||||
},
|
||||
|
||||
releaseGLObjects: function () {
|
||||
if ( this.stateset !== undefined ) this.stateset.releaseGLObjects();
|
||||
}
|
||||
|
||||
|
||||
} ), 'osg', 'Node' );
|
||||
MACROUTILS.setTypeID( Node );
|
||||
|
||||
|
||||
module.exports = Node;
|
|
@ -1,144 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var NodeVisitor = function ( traversalMode ) {
|
||||
/*jshint bitwise: false */
|
||||
this.traversalMask = ~0x0;
|
||||
/*jshint bitwise: true */
|
||||
this.nodeMaskOverride = 0;
|
||||
this.traversalMode = traversalMode;
|
||||
if ( traversalMode === undefined ) {
|
||||
this.traversalMode = NodeVisitor.TRAVERSE_ALL_CHILDREN;
|
||||
}
|
||||
this.nodePath = [];
|
||||
this.visitorType = NodeVisitor.NODE_VISITOR;
|
||||
this._databaseRequestHandler = undefined;
|
||||
this._frameStamp = undefined;
|
||||
|
||||
this.traverse = NodeVisitor._traversalFunctions[ this.traversalMode ];
|
||||
this.pushOntoNodePath = NodeVisitor._pushOntoNodePath[ this.traversalMode ];
|
||||
this.popFromNodePath = NodeVisitor._popFromNodePath[ this.traversalMode ];
|
||||
};
|
||||
|
||||
//NodeVisitor.TRAVERSE_NONE = 0;
|
||||
NodeVisitor.TRAVERSE_PARENTS = 1;
|
||||
NodeVisitor.TRAVERSE_ALL_CHILDREN = 2;
|
||||
NodeVisitor.TRAVERSE_ACTIVE_CHILDREN = 3;
|
||||
|
||||
NodeVisitor.NODE_VISITOR = 0;
|
||||
NodeVisitor.UPDATE_VISITOR = 1;
|
||||
NodeVisitor.CULL_VISITOR = 2;
|
||||
|
||||
// =================== Traversal functions ===============
|
||||
var traverseParents = function traverseParents( node ) {
|
||||
node.ascend( this );
|
||||
};
|
||||
|
||||
var traverseChildren = function traverseAllChildren( node ) {
|
||||
node.traverse( this );
|
||||
};
|
||||
|
||||
// must be sync with TRAVERSE_ENUMS
|
||||
NodeVisitor._traversalFunctions = [
|
||||
undefined,
|
||||
traverseParents,
|
||||
traverseChildren,
|
||||
traverseChildren
|
||||
];
|
||||
|
||||
// =================== PushOntoNodePath functions ===============
|
||||
var pushOntoNodePathParents = function ( node ) {
|
||||
this.nodePath.unshift( node );
|
||||
};
|
||||
|
||||
var pushOntoNodePathChildren = function ( node ) {
|
||||
this.nodePath.push( node );
|
||||
};
|
||||
|
||||
NodeVisitor._pushOntoNodePath = [
|
||||
undefined,
|
||||
pushOntoNodePathParents,
|
||||
pushOntoNodePathChildren,
|
||||
pushOntoNodePathChildren
|
||||
];
|
||||
|
||||
// =================== PopOntoNodePath functions ===============
|
||||
var popFromNodePathParents = function () {
|
||||
return this.nodePath.shift();
|
||||
};
|
||||
|
||||
var popFromNodePathChildren = function () {
|
||||
this.nodePath.pop();
|
||||
};
|
||||
|
||||
NodeVisitor._popFromNodePath = [
|
||||
undefined,
|
||||
popFromNodePathParents,
|
||||
popFromNodePathChildren,
|
||||
popFromNodePathChildren
|
||||
];
|
||||
|
||||
|
||||
NodeVisitor.prototype = {
|
||||
|
||||
reset: function () {
|
||||
// to be used when you want to re-use a nv
|
||||
this.nodePath.length = 0;
|
||||
},
|
||||
|
||||
setFrameStamp: function ( frameStamp ) {
|
||||
this._frameStamp = frameStamp;
|
||||
},
|
||||
|
||||
getFrameStamp: function () {
|
||||
return this._frameStamp;
|
||||
},
|
||||
|
||||
|
||||
setNodeMaskOverride: function ( m ) {
|
||||
this.nodeMaskOverride = m;
|
||||
},
|
||||
getNodeMaskOverride: function () {
|
||||
return this.nodeMaskOverride;
|
||||
},
|
||||
|
||||
setTraversalMask: function ( m ) {
|
||||
this.traversalMask = m;
|
||||
},
|
||||
getTraversalMask: function () {
|
||||
return this.traversalMask;
|
||||
},
|
||||
|
||||
getNodePath: function () {
|
||||
return this.nodePath;
|
||||
},
|
||||
|
||||
pushOntoNodePath: function ( node ) {
|
||||
NodeVisitor._pushOntoNodePath[ this.traversalMode ].call( this, node );
|
||||
},
|
||||
popFromNodePath: function () {
|
||||
NodeVisitor._popFromNodePath[ this.traversalMode ].call( this );
|
||||
},
|
||||
validNodeMask: function ( node ) {
|
||||
var nm = node.getNodeMask();
|
||||
/*jshint bitwise: false */
|
||||
return ( ( this.traversalMask & ( this.nodeMaskOverride | nm ) ) !== 0 );
|
||||
/*jshint bitwise: true */
|
||||
},
|
||||
apply: function ( node ) {
|
||||
this.traverse( node );
|
||||
},
|
||||
traverse: function ( node ) {
|
||||
NodeVisitor._traversalFunctions[ this.traversalMode ].call( this, node );
|
||||
},
|
||||
getVisitorType: function () {
|
||||
return this.visitorType;
|
||||
},
|
||||
setDatabaseRequestHandler: function ( dbpager ) {
|
||||
this._databaseRequestHandler = dbpager;
|
||||
},
|
||||
getDatabaseRequestHandler: function () {
|
||||
return this._databaseRequestHandler;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = NodeVisitor;
|
|
@ -1,53 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
|
||||
/**
|
||||
* Object class
|
||||
* @class Object
|
||||
*/
|
||||
var Object = function () {
|
||||
this._name = undefined;
|
||||
this._userdata = undefined;
|
||||
this._instanceID = Object.getInstanceID();
|
||||
};
|
||||
|
||||
/** @lends Object.prototype */
|
||||
Object.prototype = MACROUTILS.objectLibraryClass( {
|
||||
|
||||
// this method works only if constructor is set correctly
|
||||
// see issue https://github.com/cedricpinson/osgjs/issues/494
|
||||
cloneType: function () {
|
||||
var Constructor = this.constructor;
|
||||
return new Constructor();
|
||||
},
|
||||
|
||||
getInstanceID: function () {
|
||||
return this._instanceID;
|
||||
},
|
||||
|
||||
setName: function ( name ) {
|
||||
this._name = name;
|
||||
},
|
||||
|
||||
getName: function () {
|
||||
return this._name;
|
||||
},
|
||||
|
||||
setUserData: function ( data ) {
|
||||
this._userdata = data;
|
||||
},
|
||||
|
||||
getUserData: function () {
|
||||
return this._userdata;
|
||||
}
|
||||
}, 'osg', 'Object' );
|
||||
|
||||
|
||||
// get an instanceID for each object
|
||||
var instanceID = 0;
|
||||
Object.getInstanceID = function () {
|
||||
instanceID += 1;
|
||||
return instanceID;
|
||||
};
|
||||
|
||||
module.exports = Object;
|
|
@ -1,54 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
|
||||
var OptionsDefault = {
|
||||
'antialias': true, // activate MSAA
|
||||
//'overrideDevicePixelRatio': 1, // if specified override the device pixel ratio
|
||||
'fullscreen': true,
|
||||
'enableFrustumCulling': false,
|
||||
'stats': false, // display canvas with stats for the viewer
|
||||
'scrollwheel': true,
|
||||
'webgl2': false
|
||||
};
|
||||
|
||||
var Options = function () {
|
||||
|
||||
window.Object.keys( OptionsDefault ).forEach( function ( key ) {
|
||||
this[ key ] = OptionsDefault[ key ];
|
||||
}.bind( this ) );
|
||||
|
||||
};
|
||||
|
||||
|
||||
Options.prototype = {
|
||||
|
||||
extend: function ( options ) {
|
||||
MACROUTILS.objectMix( this, options );
|
||||
return this;
|
||||
},
|
||||
|
||||
get: function ( key ) {
|
||||
return this[ key ];
|
||||
},
|
||||
|
||||
getBoolean: function ( key ) {
|
||||
var val = this.getString( key );
|
||||
if ( val ) return ( val !== 'false' && val !== '0' );
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getNumber: function ( key ) {
|
||||
var val = this[ key ];
|
||||
if ( val ) return Number( val );
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getString: function ( key ) {
|
||||
var val = this[ key ];
|
||||
if ( val !== undefined ) return this[ key ].toString();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = Options;
|
|
@ -1,244 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Lod = require( 'osg/Lod' );
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
|
||||
|
||||
/**
|
||||
* PagedLOD that can contains paged child nodes
|
||||
* @class PagedLod
|
||||
*/
|
||||
var PagedLOD = function () {
|
||||
Lod.call( this );
|
||||
this._perRangeDataList = [];
|
||||
this._loading = false;
|
||||
this._expiryTime = 0.0;
|
||||
this._expiryFrame = 0;
|
||||
this._centerMode = Lod.USER_DEFINED_CENTER;
|
||||
this._frameNumberOfLastTraversal = 0;
|
||||
this._databasePath = '';
|
||||
this._numChildrenThatCannotBeExpired = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* PerRangeData utility structure to store per range values
|
||||
* @class PerRangeData
|
||||
*/
|
||||
var PerRangeData = function () {
|
||||
this.filename = '';
|
||||
this.function = undefined;
|
||||
this.loaded = false;
|
||||
this.timeStamp = 0.0;
|
||||
this.frameNumber = 0;
|
||||
this.frameNumberOfLastTraversal = 0;
|
||||
this.dbrequest = undefined;
|
||||
};
|
||||
|
||||
/** @lends PagedLOD.prototype */
|
||||
PagedLOD.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Lod.prototype, {
|
||||
// Functions here
|
||||
setRange: function ( childNo, min, max ) {
|
||||
if ( childNo >= this._range.length ) {
|
||||
var r = [];
|
||||
r.push( [ min, min ] );
|
||||
this._range.push( r );
|
||||
}
|
||||
this._range[ childNo ][ 0 ] = min;
|
||||
this._range[ childNo ][ 1 ] = max;
|
||||
},
|
||||
|
||||
setExpiryTime: function ( expiryTime ) {
|
||||
this._expiryTime = expiryTime;
|
||||
},
|
||||
|
||||
setDatabasePath: function ( path ) {
|
||||
this._databasePath = path;
|
||||
},
|
||||
|
||||
getDatabasePath: function () {
|
||||
return this._databasePath;
|
||||
},
|
||||
|
||||
setFileName: function ( childNo, filename ) {
|
||||
// May we should expand the vector first?
|
||||
if ( childNo >= this._perRangeDataList.length ) {
|
||||
var rd = new PerRangeData();
|
||||
rd.filename = filename;
|
||||
this._perRangeDataList.push( rd );
|
||||
} else {
|
||||
this._perRangeDataList[ childNo ].filename = filename;
|
||||
}
|
||||
},
|
||||
setFunction: function ( childNo, func ) {
|
||||
if ( childNo >= this._perRangeDataList.length ) {
|
||||
var rd = new PerRangeData();
|
||||
rd.function = func;
|
||||
this._perRangeDataList.push( rd );
|
||||
} else {
|
||||
this._perRangeDataList[ childNo ].function = func;
|
||||
}
|
||||
},
|
||||
|
||||
addChild: function ( node, min, max ) {
|
||||
Lod.prototype.addChild.call( this, node, min, max );
|
||||
this._perRangeDataList.push( new PerRangeData() );
|
||||
},
|
||||
|
||||
addChildNode: function ( node ) {
|
||||
Lod.prototype.addChildNode.call( this, node );
|
||||
},
|
||||
|
||||
setFrameNumberOfLastTraversal: function ( frameNumber ) {
|
||||
this._frameNumberOfLastTraversal = frameNumber;
|
||||
},
|
||||
|
||||
getFrameNumberOfLastTraversal: function () {
|
||||
return this._frameNumberOfLastTraversal;
|
||||
},
|
||||
setTimeStamp: function ( childNo, timeStamp ) {
|
||||
this._perRangeDataList[ childNo ].timeStamp = timeStamp;
|
||||
},
|
||||
setFrameNumber: function ( childNo, frameNumber ) {
|
||||
this._perRangeDataList[ childNo ].frameNumber = frameNumber;
|
||||
},
|
||||
setNumChildrenThatCannotBeExpired: function ( num ) {
|
||||
this._numChildrenThatCannotBeExpired = num;
|
||||
},
|
||||
getNumChildrenThatCannotBeExpired: function () {
|
||||
return this._numChildrenThatCannotBeExpired;
|
||||
},
|
||||
getDatabaseRequest: function ( childNo ) {
|
||||
return this._perRangeDataList[ childNo ].dbrequest;
|
||||
},
|
||||
removeExpiredChildren: function ( expiryTime, expiryFrame, removedChildren ) {
|
||||
if ( this.children.length <= this._numChildrenThatCannotBeExpired ) return;
|
||||
var i = this.children.length - 1;
|
||||
var timed, framed;
|
||||
timed = this._perRangeDataList[ i ].timeStamp + this._expiryTime;
|
||||
framed = this._perRangeDataList[ i ].frameNumber + this._expiryFrame;
|
||||
if ( timed < expiryTime && framed < expiryFrame && ( this._perRangeDataList[ i ].filename.length > 0 ||
|
||||
this._perRangeDataList[ i ].function !== undefined ) ) {
|
||||
removedChildren.push( this.children[ i ] );
|
||||
this.removeChild( this.children[ i ] );
|
||||
this._perRangeDataList[ i ].loaded = false;
|
||||
if ( this._perRangeDataList[ i ].dbrequest !== undefined ) {
|
||||
this._perRangeDataList[ i ].dbrequest._groupExpired = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
traverse: ( function () {
|
||||
|
||||
// avoid to generate variable on the heap to limit garbage collection
|
||||
// instead create variable and use the same each time
|
||||
var zeroVector = vec3.create();
|
||||
var eye = vec3.create();
|
||||
var viewModel = mat4.create();
|
||||
|
||||
return function ( visitor ) {
|
||||
|
||||
var traversalMode = visitor.traversalMode;
|
||||
var updateTimeStamp = false;
|
||||
|
||||
if ( visitor.getVisitorType() === NodeVisitor.CULL_VISITOR ) {
|
||||
this._frameNumberOfLastTraversal = visitor.getFrameStamp().getFrameNumber();
|
||||
updateTimeStamp = true;
|
||||
}
|
||||
|
||||
switch ( traversalMode ) {
|
||||
|
||||
case NodeVisitor.TRAVERSE_ALL_CHILDREN:
|
||||
|
||||
for ( var index = 0; index < this.children.length; index++ ) {
|
||||
this.children[ index ].accept( visitor );
|
||||
}
|
||||
break;
|
||||
|
||||
case ( NodeVisitor.TRAVERSE_ACTIVE_CHILDREN ):
|
||||
var requiredRange = 0;
|
||||
|
||||
// Calculate distance from viewpoint
|
||||
var matrix = visitor.getCurrentModelViewMatrix();
|
||||
mat4.invert( viewModel, matrix );
|
||||
if ( this._rangeMode === Lod.DISTANCE_FROM_EYE_POINT ) {
|
||||
vec3.transformMat4( eye, zeroVector, viewModel );
|
||||
var d = vec3.distance( this.getBound().center(), eye );
|
||||
requiredRange = d * visitor.getLODScale();
|
||||
} else {
|
||||
// Calculate pixels on screen
|
||||
var projmatrix = visitor.getCurrentProjectionMatrix();
|
||||
// focal lenght is the value stored in projmatrix[0]
|
||||
requiredRange = this.projectBoundingSphere( this.getBound(), matrix, projmatrix[ 0 ] );
|
||||
// Get the real area value and apply LODScale
|
||||
requiredRange = ( ( requiredRange * visitor.getViewport().width() * visitor.getViewport().width() ) * 0.25 ) / visitor.getLODScale();
|
||||
if ( requiredRange < 0 ) requiredRange = this._range[ this._range.length - 1 ][ 0 ];
|
||||
}
|
||||
|
||||
var needToLoadChild = false;
|
||||
var lastChildTraversed = -1;
|
||||
for ( var j = 0; j < this._range.length; ++j ) {
|
||||
if ( this._range[ j ][ 0 ] <= requiredRange && requiredRange < this._range[ j ][ 1 ] ) {
|
||||
if ( j < this.children.length ) {
|
||||
|
||||
if ( updateTimeStamp ) {
|
||||
this._perRangeDataList[ j ].timeStamp = visitor.getFrameStamp().getSimulationTime();
|
||||
this._perRangeDataList[ j ].frameNumber = visitor.getFrameStamp().getFrameNumber();
|
||||
}
|
||||
|
||||
this.children[ j ].accept( visitor );
|
||||
lastChildTraversed = j;
|
||||
} else {
|
||||
needToLoadChild = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( needToLoadChild ) {
|
||||
var numChildren = this.children.length;
|
||||
if ( numChildren > 0 && ( ( numChildren - 1 ) !== lastChildTraversed ) ) {
|
||||
|
||||
if ( updateTimeStamp ) {
|
||||
this._perRangeDataList[ numChildren - 1 ].timeStamp = visitor.getFrameStamp().getSimulationTime();
|
||||
this._perRangeDataList[ numChildren - 1 ].frameNumber = visitor.getFrameStamp().getFrameNumber();
|
||||
}
|
||||
|
||||
this.children[ numChildren - 1 ].accept( visitor );
|
||||
}
|
||||
// now request the loading of the next unloaded child.
|
||||
if ( numChildren < this._perRangeDataList.length ) {
|
||||
// compute priority from where abouts in the required range the distance falls.
|
||||
var priority = ( this._range[ numChildren ][ 0 ] - requiredRange ) / ( this._range[ numChildren ][ 1 ] - this._range[ numChildren ][ 0 ] );
|
||||
if ( this._rangeMode === Lod.PIXEL_SIZE_ON_SCREEN ) {
|
||||
priority = -priority;
|
||||
}
|
||||
// Here we do the request
|
||||
var group = visitor.nodePath[ visitor.nodePath.length - 1 ];
|
||||
if ( this._perRangeDataList[ numChildren ].loaded === false ) {
|
||||
this._perRangeDataList[ numChildren ].loaded = true;
|
||||
var dbhandler = visitor.getDatabaseRequestHandler();
|
||||
this._perRangeDataList[ numChildren ].dbrequest = dbhandler.requestNodeFile( this._perRangeDataList[ numChildren ].function, this._databasePath + this._perRangeDataList[ numChildren ].filename, group, visitor.getFrameStamp().getSimulationTime(), priority );
|
||||
} else {
|
||||
// Update timestamp of the request.
|
||||
if ( this._perRangeDataList[ numChildren ].dbrequest !== undefined ) {
|
||||
this._perRangeDataList[ numChildren ].dbrequest._timeStamp = visitor.getFrameStamp().getSimulationTime();
|
||||
this._perRangeDataList[ numChildren ].dbrequest._priority = priority;
|
||||
} else {
|
||||
// The DB request is undefined, so the DBPager was not accepting requests, we need to ask for the child again.
|
||||
this._perRangeDataList[ numChildren ].loaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
} )()
|
||||
|
||||
|
||||
} ), 'osg', 'PagedLOD' );
|
||||
|
||||
MACROUTILS.setTypeID( PagedLOD );
|
||||
module.exports = PagedLOD;
|
|
@ -1,143 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var vec4 = require( 'osg/glMatrix' ).vec4;
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
|
||||
|
||||
/** @class Plane Operations */
|
||||
var Plane = MACROUTILS.objectInherit( vec4, {
|
||||
// Many case (frustum, convexity)
|
||||
// needs to know where from a plane it stands,
|
||||
// not just boolean intersection
|
||||
INSIDE: 1,
|
||||
INTERSECT: 2,
|
||||
OUTSIDE: 3,
|
||||
/* Transform the plane */
|
||||
transformProvidingInverse: function () {
|
||||
var iplane = Plane.create();
|
||||
return function ( p, m ) {
|
||||
//Matrix.transformVec4PostMult( matrix, plane, iplane );
|
||||
var x = p[ 0 ];
|
||||
var y = p[ 1 ];
|
||||
var z = p[ 2 ];
|
||||
var w = p[ 3 ];
|
||||
|
||||
iplane[ 0 ] = m[ 0 ] * x + m[ 1 ] * y + m[ 2 ] * z + m[ 3 ] * w;
|
||||
iplane[ 1 ] = m[ 4 ] * x + m[ 5 ] * y + m[ 6 ] * z + m[ 7 ] * w;
|
||||
iplane[ 2 ] = m[ 8 ] * x + m[ 9 ] * y + m[ 10 ] * z + m[ 11 ] * w;
|
||||
iplane[ 3 ] = m[ 12 ] * x + m[ 13 ] * y + m[ 14 ] * z + m[ 15 ] * w;
|
||||
|
||||
Plane.normalizeEquation( iplane );
|
||||
Plane.copy( iplane, p );
|
||||
return p;
|
||||
};
|
||||
},
|
||||
|
||||
normalizeEquation: function ( plane ) {
|
||||
// multiply the coefficients of the plane equation with a constant factor so that the equation a^2+b^2+c^2 = 1 holds.
|
||||
var inv = 1.0 / Math.sqrt( plane[ 0 ] * plane[ 0 ] + plane[ 1 ] * plane[ 1 ] + plane[ 2 ] * plane[ 2 ] );
|
||||
plane[ 0 ] *= inv;
|
||||
plane[ 1 ] *= inv;
|
||||
plane[ 2 ] *= inv;
|
||||
plane[ 3 ] *= inv;
|
||||
},
|
||||
/*only the normal Component*/
|
||||
getNormal: function ( plane, result ) {
|
||||
result[ 0 ] = plane[ 0 ];
|
||||
result[ 1 ] = plane[ 1 ];
|
||||
result[ 2 ] = plane[ 2 ];
|
||||
return result;
|
||||
},
|
||||
setNormal: function ( plane, normal ) {
|
||||
plane[ 0 ] = normal[ 0 ];
|
||||
plane[ 1 ] = normal[ 1 ];
|
||||
plane[ 2 ] = normal[ 2 ];
|
||||
},
|
||||
/* only the distance getter*/
|
||||
getDistance: function ( plane ) {
|
||||
return plane[ 3 ];
|
||||
},
|
||||
setDistance: function ( plane, distance ) {
|
||||
plane[ 3 ] = distance;
|
||||
},
|
||||
|
||||
/* using the plane equation, compute distance to plane of a point*/
|
||||
distanceToPlane: function ( plane, position ) {
|
||||
return plane[ 0 ] * position[ 0 ] + plane[ 1 ] * position[ 1 ] + plane[ 2 ] * position[ 2 ] + plane[ 3 ];
|
||||
},
|
||||
|
||||
|
||||
intersectsOrContainsBoundingSphere: function ( plane, bSphere ) {
|
||||
if ( !bSphere.valid() ) return Plane.OUTSIDE;
|
||||
var position = bSphere.center();
|
||||
var radius = bSphere.radius();
|
||||
var d = this.distanceToPlane( plane, position );
|
||||
if ( d < -radius ) {
|
||||
return Plane.OUTSIDE;
|
||||
} else if ( d <= radius ) {
|
||||
return Plane.INTERSECT;
|
||||
}
|
||||
return Plane.INSIDE;
|
||||
},
|
||||
|
||||
instersectsBoundingSphere: function ( plane, bSphere ) {
|
||||
return this.intersectsOrContainsBoundingSphere( plane, bSphere ) === Plane.INTERSECT;
|
||||
},
|
||||
|
||||
// absPlane optional paramter is an optimisation for the
|
||||
// DOD case: on plane, many bounding boxes
|
||||
intersectsOrContainsBoundingBox: function () {
|
||||
var center = vec3.create();
|
||||
var extent = vec3.create();
|
||||
var absTemp = vec3.create();
|
||||
return function ( plane, bbox, absPlane ) {
|
||||
vec3.add( center, bbox.getMax(), bbox.getMin() );
|
||||
vec3.scale( center, center, 0.5 );
|
||||
|
||||
vec3.sub( center, bbox.getMax(), bbox.getMin() );
|
||||
vec3.scale( extent, extent, 0.5 );
|
||||
|
||||
var d = vec3.dot( center, plane );
|
||||
if ( !absPlane ) {
|
||||
absPlane = absTemp;
|
||||
absPlane[ 0 ] = Math.abs( plane[ 0 ] );
|
||||
absPlane[ 1 ] = Math.abs( plane[ 1 ] );
|
||||
absPlane[ 2 ] = Math.abs( plane[ 2 ] );
|
||||
}
|
||||
var r = vec3.dot( extent, absPlane );
|
||||
if ( d + r > 0 ) return Plane.INTERSECT; // partially inside
|
||||
if ( d - r >= 0 ) return Plane.INSIDE; // fully inside
|
||||
return Plane.OUTSIDE;
|
||||
};
|
||||
},
|
||||
|
||||
intersectsBoundingBox: function ( plane, bbox, absPlane ) {
|
||||
return this.intersectsOrContainsBoundingBox( plane, bbox, absPlane ) === Plane.INTERSECT;
|
||||
},
|
||||
|
||||
intersectOrContainsVertices: function ( plane, vertices ) {
|
||||
var side = -1;
|
||||
// all points must be on one side only
|
||||
for ( var i = 0; i < vertices.length; i++ ) {
|
||||
var d = this.distanceToPlane( plane, vertices[ i ] );
|
||||
if ( d < 0.0 ) {
|
||||
if ( side === 1 ) return Plane.INTERSECT;
|
||||
side = 2;
|
||||
} else if ( d > 0.0 ) {
|
||||
if ( side === 2 ) return Plane.INTERSECT;
|
||||
side = 1;
|
||||
} else { //if ( d === 0.0 )
|
||||
return Plane.INTERSECT;
|
||||
}
|
||||
}
|
||||
return ( side > 0 ) ? Plane.INSIDE : Plane.OUTSIDE;
|
||||
|
||||
},
|
||||
intersectVertices: function ( plane, vertices ) {
|
||||
return this.intersectOrContainsVertices( plane, vertices ) === Plane.INTERSECT;
|
||||
}
|
||||
|
||||
|
||||
} );
|
||||
|
||||
module.exports = Plane;
|
|
@ -1,349 +0,0 @@
|
|||
'use strict';
|
||||
var Object = require( 'osg/Object' );
|
||||
var Plane = require( 'osg/Plane' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var vec4 = require( 'osg/glMatrix' ).vec4;
|
||||
/*jshint bitwise: false */
|
||||
/**
|
||||
* Polytope class for representing convex clipping volumes made up of a set of planes.
|
||||
* When adding planes, their normals should point inwards (into the volume)
|
||||
* @class Polytope
|
||||
*/
|
||||
var Polytope = function () {
|
||||
|
||||
this._clippingMask = 0x0;
|
||||
|
||||
this._planeList = [ Plane.create(), Plane.create(), Plane.create(), Plane.create(), Plane.create(), Plane.create() ];
|
||||
this._vertexList = [];
|
||||
|
||||
// stack of clipping masks
|
||||
this._maskStack = [];
|
||||
|
||||
// init with a clear mask
|
||||
this._resultMask = 0;
|
||||
this._maskStack.push( this._resultMask );
|
||||
};
|
||||
|
||||
Polytope.prototype = MACROUTILS.objectInherit( Object.prototype, {
|
||||
|
||||
|
||||
getPlanes: function () {
|
||||
return this._planeList;
|
||||
},
|
||||
|
||||
setPlanes: function ( pl ) {
|
||||
this._planeList = pl;
|
||||
this.setupMask();
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
|
||||
this._clippingMask = 0x0;
|
||||
if ( this._planeList ) {
|
||||
for ( var i = 0, l = this._planeList.length; i < l; ++i ) {
|
||||
Plane.init( this._planeList[ i ] );
|
||||
}
|
||||
}
|
||||
this._vertexList = [];
|
||||
this.setupMask();
|
||||
|
||||
},
|
||||
|
||||
/** Create a Polytope which is a cube, centered at 0,0,0, with sides of 2 units.*/
|
||||
setToUnitFrustum: function ( withNear, withFar ) {
|
||||
if ( withNear === undefined ) withNear = true;
|
||||
|
||||
if ( withFar === undefined ) withFar = true;
|
||||
|
||||
this._planeList.length = 0;
|
||||
this._planeList.push( vec4.set( Plane.create(), 1.0, 0.0, 0.0, 1.0 ) ); // left plane.
|
||||
this._planeList.push( vec4.set( Plane.create(), -1.0, 0.0, 0.0, 1.0 ) ); // right plane.
|
||||
this._planeList.push( vec4.set( Plane.create(), 0.0, 1.0, 0.0, 1.0 ) ); // bottom plane.
|
||||
this._planeList.push( vec4.set( Plane.create(), 0.0, -1.0, 0.0, 1.0 ) ); // top plane.
|
||||
if ( withNear ) this._planeList.push( vec4.set( Plane.create(), 0.0, 0.0, 1.0, 1.0 ) ); // near plane
|
||||
if ( withFar ) this._planeList.push( vec4.set( Plane.create(), 0.0, 0.0, -1.0, 1.0 ) ); // far plane
|
||||
this.setupMask();
|
||||
},
|
||||
|
||||
|
||||
/** Create a Polytope which is a equivalent to BoundingBox.*/
|
||||
setToBoundingBox: function ( bb ) {
|
||||
this._planeList.length = 0;
|
||||
this._planeList.push( vec4.set( Plane.create(), 1.0, 0.0, 0.0, -bb.getMin()[ 0 ] ) ); // left plane.
|
||||
this._planeList.push( vec4.set( Plane.create(), -1.0, 0.0, 0.0, bb.getMax()[ 0 ] ) ); // right plane.
|
||||
this._planeList.push( vec4.set( Plane.create(), 0.0, 1.0, 0.0, -bb.getMin()[ 1 ] ) ); // bottom plane.
|
||||
this._planeList.push( vec4.set( Plane.create(), 0.0, -1.0, 0.0, bb.getMax()[ 1 ] ) ); // top plane.
|
||||
this._planeList.push( vec4.set( Plane.create(), 0.0, 0.0, 1.0, -bb.getMin()[ 2 ] ) ); // near plane
|
||||
this._planeList.push( vec4.set( Plane.create(), 0.0, 0.0, -1.0, bb.getMax()[ 2 ] ) ); // far plane
|
||||
this.setupMask();
|
||||
},
|
||||
|
||||
setAndTransformProvidingInverse: function ( pt, matrix ) {
|
||||
this._referenceVertexList = pt._referenceVertexList;
|
||||
var resultMask = pt._maskStack[ this._maskStack.length - 1 ];
|
||||
if ( resultMask === 0 ) {
|
||||
this._maskStack[ this._maskStack.length - 1 ] = 0;
|
||||
this._resultMask = 0;
|
||||
this._planeList.length = 0;
|
||||
return;
|
||||
}
|
||||
var selectorMask = 0x1;
|
||||
|
||||
var numActivePlanes = 0;
|
||||
// count number of active planes.
|
||||
var i;
|
||||
for ( i = 0; i !== pt._planeList.length; ++i ) {
|
||||
if ( resultMask & selectorMask ) ++numActivePlanes;
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
|
||||
this._planeList.length = numActivePlanes;
|
||||
this._resultMask = 0;
|
||||
selectorMask = 0x1;
|
||||
var index = 0;
|
||||
for ( i = 0; i !== pt._planeList.length; ++i ) {
|
||||
if ( resultMask & selectorMask ) {
|
||||
this._planeList[ index ] = pt._planeList[ i ];
|
||||
Plane.transformProvidingInverse( this._planeList[ index++ ], matrix );
|
||||
this._resultMask = ( this._resultMask << 1 ) | 1;
|
||||
}
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
|
||||
this._maskStack[ this._maskStack.length - 1 ] = this._resultMask;
|
||||
},
|
||||
|
||||
voidset: function ( pl ) {
|
||||
this._planeList = pl;
|
||||
this.setupMask();
|
||||
},
|
||||
|
||||
|
||||
add: function ( pl ) {
|
||||
this._planeList.push( pl );
|
||||
this.setupMask();
|
||||
},
|
||||
|
||||
empty: function () {
|
||||
return this._planeList.length === 0;
|
||||
},
|
||||
|
||||
getPlaneList: function () {
|
||||
return this._planeList;
|
||||
},
|
||||
|
||||
setReferenceVertexList: function ( vertices ) {
|
||||
this._referenceVertexList = vertices;
|
||||
},
|
||||
|
||||
getReferenceVertexList: function () {
|
||||
return this._referenceVertexList;
|
||||
},
|
||||
|
||||
setupMask: function ( plength ) {
|
||||
this._resultMask = 0;
|
||||
var pMasklength = ( plength !== undefined ) ? plength : this._planeList.length;
|
||||
for ( var i = 0; i < pMasklength; ++i ) {
|
||||
this._resultMask = ( this._resultMask << 1 ) | 1;
|
||||
}
|
||||
this._maskStack = [];
|
||||
this._maskStack.push( this._resultMask );
|
||||
},
|
||||
|
||||
getCurrentMask: function () {
|
||||
return this._maskStack[ this._maskStack.length - 1 ];
|
||||
},
|
||||
|
||||
setResultMask: function ( mask ) {
|
||||
this._resultMask = mask;
|
||||
},
|
||||
|
||||
getResultMask: function () {
|
||||
return this._resultMask;
|
||||
},
|
||||
|
||||
getMaskStack: function () {
|
||||
return this._maskStack;
|
||||
},
|
||||
|
||||
|
||||
// push but keep current mask
|
||||
pushCurrentMask: function () {
|
||||
this._maskStack.push( this._resultMask );
|
||||
},
|
||||
// pop and restore previous mask
|
||||
popCurrentMask: function () {
|
||||
return this._maskStack.pop();
|
||||
},
|
||||
|
||||
|
||||
/** Check whether a vertex is contained within clipping set.*/
|
||||
containsVertex: function ( v ) {
|
||||
if ( !this._maskStack[ this._maskStack.length - 1 ] ) return true;
|
||||
|
||||
var selectorMask = 0x1;
|
||||
for ( var i = 0; i < this._planeList.length; ++i ) {
|
||||
if ( ( this._maskStack[ this._maskStack.length - 1 ] & selectorMask ) && ( Plane.distanceToPlane( this._planeList[ i ], v ) < 0.0 ) ) {
|
||||
return false;
|
||||
}
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/** Check whether any part of vertex list is contained within clipping set.*/
|
||||
containsVertices: function ( vertices ) {
|
||||
if ( !this._maskStack[ this._maskStack.length - 1 ] ) return true;
|
||||
|
||||
this._resultMask = this._maskStack[ this._maskStack.length - 1 ];
|
||||
|
||||
for ( var k = 0; k < vertices.length; ++k ) {
|
||||
var v = vertices[ k ];
|
||||
var outside = false;
|
||||
var selectorMask = 0x1;
|
||||
for ( var i = 0; !outside && i < this._planeList.length; ++i ) {
|
||||
if ( ( this._maskStack[ this._maskStack.length - 1 ] & selectorMask ) && ( Plane.distanceToPlane( this._planeList[ i ], v ) < 0.0 ) ) {
|
||||
outside = true;
|
||||
}
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
|
||||
if ( !outside ) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/** Check whether any part of a bounding sphere is contained within clipping set.
|
||||
Using a mask to determine which planes should be used for the check, and
|
||||
modifying the mask to turn off planes which wouldn't contribute to clipping
|
||||
of any internal objects. This feature is used in osgUtil::CullVisitor
|
||||
to prevent redundant plane checking.*/
|
||||
containsBoundingSphere: function ( bs ) {
|
||||
if ( !this._maskStack[ this._maskStack.length - 1 ] || !bs.valid() ) return true;
|
||||
|
||||
this._resultMask = this._maskStack[ this._maskStack.length - 1 ];
|
||||
var selectorMask = 0x1;
|
||||
|
||||
for ( var i = 0; i < this._planeList.length; ++i ) {
|
||||
if ( this._resultMask & selectorMask ) {
|
||||
var res = Plane.intersectsOrContainsBoundingSphere( this._planeList[ i ], bs );
|
||||
if ( Plane.OUTSIDE === res ) {
|
||||
// totally outside a clipping set.
|
||||
return false;
|
||||
} else if ( Plane.INSIDE === res ) {
|
||||
// subsequent checks against this plane not required.
|
||||
this._resultMask ^= selectorMask;
|
||||
}
|
||||
// else if ( Plane.INTERSECT === res ) { // last possible case
|
||||
// can say nothing.
|
||||
// subsequent checks against this plane needed.
|
||||
//}
|
||||
}
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/** Check whether any part of a bounding box is contained within clipping set.
|
||||
Using a mask to determine which planes should be used for the check, and
|
||||
modifying the mask to turn off planes which wouldn't contribute to clipping
|
||||
of any internal objects. This feature is used in osgUtil::CullVisitor
|
||||
to prevent redundant plane checking.*/
|
||||
containsBoundingBox: function ( bb ) {
|
||||
if ( !this._maskStack[ this._maskStack.length - 1 ] ) return true;
|
||||
|
||||
this._resultMask = this._maskStack[ this._maskStack.length - 1 ];
|
||||
var selectorMask = 0x1;
|
||||
|
||||
for ( var i = 0; i < this._planeList.length; ++i ) {
|
||||
if ( this._resultMask & selectorMask ) {
|
||||
var res = Plane.intersectsOrContainsBoundingBox( this._planeList[ i ], bb );
|
||||
if ( Plane.OUTSIDE === res ) return false; // outside clipping set.
|
||||
else if ( Plane.INSIDE === res ) this._resultMask ^= selectorMask; // subsequent checks against this plane not required.
|
||||
// else if ( Plane.INTERSECT === res ) the last case need
|
||||
// no test here but further tests
|
||||
}
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
// correct frustum culling should double check now for
|
||||
// http://www.iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm
|
||||
// which is inside one "plane", but outside the convex plane intersection
|
||||
return true;
|
||||
},
|
||||
|
||||
/** Check whether all of vertex list is contained with clipping set.*/
|
||||
containsAllOfVertices: function ( vertices ) {
|
||||
if ( !this._maskStack[ this._maskStack.length - 1 ] ) return false;
|
||||
|
||||
this._resultMask = this._maskStack[ this._maskStack.length - 1 ];
|
||||
var selectorMask = 0x1;
|
||||
|
||||
for ( var i = 0; i < this._planeList.length; ++i ) {
|
||||
if ( this._resultMask & selectorMask ) {
|
||||
var res = Plane.intersectsOrContainsVertices( this._planeList[ i ], vertices );
|
||||
if ( res < 1 ) return false; // intersects, or is below plane.
|
||||
this._resultMask ^= selectorMask; // subsequent checks against this plane not required.
|
||||
}
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/** Check whether the entire bounding sphere is contained within clipping set.*/
|
||||
containsAllOfBoundingSphere: function ( bs ) {
|
||||
if ( !this._maskStack[ this._maskStack.length - 1 ] ) return false;
|
||||
|
||||
this._resultMask = this._maskStack[ this._maskStack.length - 1 ];
|
||||
var selectorMask = 0x1;
|
||||
|
||||
for ( var i = 0; i < this._planeList.length; ++i ) {
|
||||
if ( this._resultMask & selectorMask ) {
|
||||
var res = Plane.intersectsOrContainsBoundingSphere( this._planeList[ i ], bs );
|
||||
if ( res < 1 ) return false; // intersects, or is below plane.
|
||||
this._resultMask ^= selectorMask; // subsequent checks against this plane not required.
|
||||
}
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/** Check whether the entire bounding box is contained within clipping set.*/
|
||||
containsAllOfBoundingBox: function ( bbox ) {
|
||||
if ( !this._maskStack[ this._maskStack.length - 1 ] ) return false;
|
||||
|
||||
this._resultMask = this._maskStack[ this._maskStack.length - 1 ];
|
||||
var selectorMask = 0x1;
|
||||
|
||||
for ( var i = 0; i < this._planeList.length; ++i ) {
|
||||
if ( this._resultMask & selectorMask ) {
|
||||
var res = Plane.intersectsOrContainsBoundingBox( this._planeList[ i ], bbox );
|
||||
if ( res < 1 ) return false; // intersects, or is below plane.
|
||||
this._resultMask ^= selectorMask; // subsequent checks against this plane not required.
|
||||
}
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/** Transform the clipping set by provide a pre inverted matrix.
|
||||
* see transform for details. */
|
||||
transformProvidingInverse: function ( matrix ) {
|
||||
if ( !this._maskStack[ this._maskStack.length - 1 ] ) return;
|
||||
|
||||
this._resultMask = this._maskStack[ this._maskStack.length - 1 ];
|
||||
var selectorMask = 0x1;
|
||||
for ( var i = 0; i < this._planeList.length; ++i ) {
|
||||
if ( this._resultMask & selectorMask ) {
|
||||
Plane.transformProvidingInverse( this._planeList[ i ], matrix );
|
||||
selectorMask <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} );
|
||||
|
||||
/*jshint bitwise: true */
|
||||
|
||||
module.exports = Polytope;
|
|
@ -1,387 +0,0 @@
|
|||
'use strict';
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var PrimitiveSet = require( 'osg/primitiveSet' );
|
||||
var DrawElements = require( 'osg/DrawElements' );
|
||||
var DrawArrays = require( 'osg/DrawArrays' );
|
||||
|
||||
/**
|
||||
* PrimitiveFunctor emulates the TemplatePrimitiveFunctor class in OSG and can
|
||||
* be used to get access to the vertices that compose the things drawn by osgjs.
|
||||
* Feed it with a callback that will be called for geometry.
|
||||
* The callback must be a closure and have the next structure:
|
||||
*
|
||||
* var myCallback = function( ) {
|
||||
* return {
|
||||
* operatorPoint : function ( v ) { }, // Do your point operations here
|
||||
* operatorLine : function ( v1, v2 ){ }, // Do you line operations here
|
||||
* operatorTriangle : function ( v1, v2, v3 ) { } // Do your triangle operations here
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* Important Note: You should take into account that you are accesing the actual vertices of the primitive
|
||||
* you might want to do a copy of these values in your callback to avoid to modify the primitive geometry
|
||||
* @class PrimitiveFunctor
|
||||
*/
|
||||
|
||||
var PrimitiveFunctor = function ( geom, cb, vertices ) {
|
||||
this._geom = geom;
|
||||
this._cb = cb;
|
||||
this._vertices = vertices;
|
||||
};
|
||||
|
||||
var functorDrawElements = PrimitiveFunctor.functorDrawElements = [];
|
||||
var functorDrawArrays = PrimitiveFunctor.functorDrawArrays = [];
|
||||
|
||||
functorDrawElements[ PrimitiveSet.POINTS ] = ( function () {
|
||||
var v = vec3.create();
|
||||
return function ( offset, count, indexes, cb, vertices ) {
|
||||
|
||||
var end = offset + count;
|
||||
for ( var i = offset; i < end; ++i ) {
|
||||
var j = indexes[ i ] * 3;
|
||||
v[ 0 ] = vertices[ j ];
|
||||
v[ 1 ] = vertices[ j + 1 ];
|
||||
v[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorPoint( v );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawElements[ PrimitiveSet.LINES ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
return function ( offset, count, indexes, cb, vertices ) {
|
||||
|
||||
var end = offset + count;
|
||||
for ( var i = offset; i < end - 1; i += 2 ) {
|
||||
var j = indexes[ i ] * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = indexes[ i + 1 ] * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorLine( v1, v2 );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawElements[ PrimitiveSet.LINE_STRIP ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
return function ( offset, count, indexes, cb, vertices ) {
|
||||
|
||||
var end = offset + count;
|
||||
for ( var i = offset; i < end - 1; ++i ) {
|
||||
var j = indexes[ i ] * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = indexes[ i + 1 ] * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorLine( v1, v2 );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawElements[ PrimitiveSet.LINE_LOOP ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
return function ( offset, count, indexes, cb, vertices ) {
|
||||
|
||||
var last = offset + count - 1;
|
||||
for ( var i = offset; i < last; ++i ) {
|
||||
var j = indexes[ i ] * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = indexes[ i + 1 ] * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorLine( v1, v2 );
|
||||
}
|
||||
last = indexes[ last ] * 3;
|
||||
v1[ 0 ] = vertices[ last ];
|
||||
v1[ 1 ] = vertices[ last + 1 ];
|
||||
v1[ 2 ] = vertices[ last + 2 ];
|
||||
var first = indexes[ 0 ] * 3;
|
||||
v2[ 0 ] = vertices[ first ];
|
||||
v2[ 1 ] = vertices[ first + 1 ];
|
||||
v2[ 2 ] = vertices[ first + 2 ];
|
||||
cb.operatorLine( v1, v2 );
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawElements[ PrimitiveSet.TRIANGLES ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
var v3 = vec3.create();
|
||||
return function ( offset, count, indexes, cb, vertices ) {
|
||||
|
||||
var end = offset + count;
|
||||
for ( var i = offset; i < end; i += 3 ) {
|
||||
var j = indexes[ i ] * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = indexes[ i + 1 ] * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
j = indexes[ i + 2 ] * 3;
|
||||
v3[ 0 ] = vertices[ j ];
|
||||
v3[ 1 ] = vertices[ j + 1 ];
|
||||
v3[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorTriangle( v1, v2, v3 );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawElements[ PrimitiveSet.TRIANGLE_STRIP ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
var v3 = vec3.create();
|
||||
return function ( offset, count, indexes, cb, vertices ) {
|
||||
|
||||
for ( var i = 2, pos = offset; i < count; ++i, ++pos ) {
|
||||
var j = indexes[ pos ] * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = indexes[ pos + 1 ] * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
j = indexes[ pos + 2 ] * 3;
|
||||
v3[ 0 ] = vertices[ j ];
|
||||
v3[ 1 ] = vertices[ j + 1 ];
|
||||
v3[ 2 ] = vertices[ j + 2 ];
|
||||
if ( i % 2 ) {
|
||||
cb.operatorTriangle( v1, v3, v2 );
|
||||
} else {
|
||||
cb.operatorTriangle( v1, v2, v3 );
|
||||
}
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawElements[ PrimitiveSet.TRIANGLE_FAN ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
var v3 = vec3.create();
|
||||
return function ( offset, count, indexes, cb, vertices ) {
|
||||
|
||||
var first = indexes[ offset ];
|
||||
for ( var i = 2, pos = offset + 1; i < count; ++i, ++pos ) {
|
||||
v1[ 0 ] = vertices[ first ];
|
||||
v1[ 1 ] = vertices[ first + 1 ];
|
||||
v1[ 2 ] = vertices[ first + 2 ];
|
||||
var j = indexes[ pos ] * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
j = indexes[ pos + 1 ] * 3;
|
||||
v3[ 0 ] = vertices[ j ];
|
||||
v3[ 1 ] = vertices[ j + 1 ];
|
||||
v3[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorTriangle( v1, v2, v3 );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.POINTS ] = ( function () {
|
||||
var v = vec3.create();
|
||||
return function ( first, count, cb, vertices ) {
|
||||
|
||||
for ( var i = first; i < first + count; ++i ) {
|
||||
var j = i * 3;
|
||||
v[ 0 ] = vertices[ j ];
|
||||
v[ 1 ] = vertices[ j + 1 ];
|
||||
v[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorPoint( v );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.LINES ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
return function ( first, count, cb, vertices ) {
|
||||
|
||||
for ( var i = first; i < first + count - 1; i += 2 ) {
|
||||
var j = i * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = ( i + 1 ) * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorLine( v1, v2 );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.LINE_STRIP ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
return function ( first, count, cb, vertices ) {
|
||||
|
||||
for ( var i = first; i < first + count - 1; ++i ) {
|
||||
var j = i * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = ( i + 1 ) * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorLine( v1, v2 );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.LINE_LOOP ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
return function ( first, count, cb, vertices ) {
|
||||
|
||||
var last = first + count - 1;
|
||||
for ( var i = first; i < last; ++i ) {
|
||||
var j = i * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = ( i + 1 ) * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorLine( v1, v2 );
|
||||
}
|
||||
last = last * 3;
|
||||
v1[ 0 ] = vertices[ last ];
|
||||
v1[ 1 ] = vertices[ last + 1 ];
|
||||
v1[ 2 ] = vertices[ last + 2 ];
|
||||
first = first * 3;
|
||||
v2[ 0 ] = vertices[ first ];
|
||||
v2[ 1 ] = vertices[ first + 1 ];
|
||||
v2[ 2 ] = vertices[ first + 2 ];
|
||||
cb.operatorLine( v1, v2 );
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.TRIANGLES ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
var v3 = vec3.create();
|
||||
return function ( first, count, cb, vertices ) {
|
||||
|
||||
for ( var i = first; i < first + count; i += 3 ) {
|
||||
var j = i * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = ( i + 1 ) * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
j = ( i + 2 ) * 3;
|
||||
v3[ 0 ] = vertices[ j ];
|
||||
v3[ 1 ] = vertices[ j + 1 ];
|
||||
v3[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorTriangle( v1, v2, v3 );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.TRIANGLE_STRIP ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
var v3 = vec3.create();
|
||||
return function ( first, count, cb, vertices ) {
|
||||
|
||||
for ( var i = 2, pos = first; i < count; ++i, ++pos ) {
|
||||
var j = pos * 3;
|
||||
v1[ 0 ] = vertices[ j ];
|
||||
v1[ 1 ] = vertices[ j + 1 ];
|
||||
v1[ 2 ] = vertices[ j + 2 ];
|
||||
j = ( pos + 1 ) * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
j = ( pos + 2 ) * 3;
|
||||
v3[ 0 ] = vertices[ j ];
|
||||
v3[ 1 ] = vertices[ j + 1 ];
|
||||
v3[ 2 ] = vertices[ j + 2 ];
|
||||
if ( i % 2 ) {
|
||||
cb.operatorTriangle( v1, v3, v2 );
|
||||
} else {
|
||||
cb.operatorTriangle( v1, v2, v3 );
|
||||
}
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.TRIANGLE_FAN ] = ( function () {
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.create();
|
||||
var v3 = vec3.create();
|
||||
return function ( first, count, cb, vertices ) {
|
||||
|
||||
for ( var i = 2, pos = first + 1; i < count; ++i, ++pos ) {
|
||||
v1[ 0 ] = vertices[ first ];
|
||||
v1[ 1 ] = vertices[ first + 1 ];
|
||||
v1[ 2 ] = vertices[ first + 2 ];
|
||||
var j = pos * 3;
|
||||
v2[ 0 ] = vertices[ j ];
|
||||
v2[ 1 ] = vertices[ j + 1 ];
|
||||
v2[ 2 ] = vertices[ j + 2 ];
|
||||
j = ( pos + 1 ) * 3;
|
||||
v3[ 0 ] = vertices[ j ];
|
||||
v3[ 1 ] = vertices[ j + 1 ];
|
||||
v3[ 2 ] = vertices[ j + 2 ];
|
||||
cb.operatorTriangle( v1, v2, v3 );
|
||||
}
|
||||
};
|
||||
} )();
|
||||
|
||||
PrimitiveFunctor.prototype = {
|
||||
apply: function () {
|
||||
var geom = this._geom;
|
||||
var primitives = geom.primitives;
|
||||
if ( !primitives )
|
||||
return;
|
||||
|
||||
var cb = this._cb();
|
||||
var cbFunctor;
|
||||
var vertices = this._vertices;
|
||||
|
||||
var nbPrimitives = primitives.length;
|
||||
for ( var i = 0; i < nbPrimitives; i++ ) {
|
||||
|
||||
var primitive = primitives[ i ];
|
||||
if ( primitive instanceof DrawElements ) {
|
||||
|
||||
cbFunctor = functorDrawElements[ primitive.getMode() ];
|
||||
if ( cbFunctor ) {
|
||||
var indexes = primitive.indices.getElements();
|
||||
cbFunctor( primitive.getFirst() / indexes.BYTES_PER_ELEMENT, primitive.getCount(), indexes, cb, vertices );
|
||||
}
|
||||
|
||||
} else if ( primitive instanceof DrawArrays ) {
|
||||
|
||||
cbFunctor = functorDrawArrays[ primitive.getMode() ];
|
||||
if ( cbFunctor ) {
|
||||
cbFunctor( primitive.getFirst(), primitive.getCount(), cb, vertices );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = PrimitiveFunctor;
|
|
@ -1,323 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var GLObject = require( 'osg/GLObject' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var CustomMap = require( 'osg/Map' );
|
||||
var Timer = require( 'osg/Timer' );
|
||||
|
||||
/**
|
||||
* Program encapsulate an vertex and fragment shader
|
||||
* @class Program
|
||||
*/
|
||||
var Program = function ( vShader, fShader ) {
|
||||
GLObject.call( this );
|
||||
StateAttribute.call( this );
|
||||
this._program = null;
|
||||
|
||||
// used to know if it's a default program
|
||||
// a default program does nothing but avoid to do some
|
||||
// useless logic
|
||||
// if we vertex or fragment shader are set it's not a default
|
||||
// program anymore
|
||||
this._nullProgram = true;
|
||||
|
||||
this._vertex = undefined;
|
||||
this._fragment = undefined;
|
||||
|
||||
this._uniformsCache = undefined;
|
||||
this._attributesCache = undefined;
|
||||
this._activeUniforms = undefined;
|
||||
this._foreignUniforms = undefined;
|
||||
this._trackAttributes = undefined;
|
||||
|
||||
if ( vShader )
|
||||
this.setVertexShader( vShader );
|
||||
|
||||
if ( fShader )
|
||||
this.setFragmentShader( fShader );
|
||||
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
|
||||
var getAttributeList = function ( vertexShader ) {
|
||||
var attributeMap = {};
|
||||
|
||||
var r = vertexShader.match( /attribute\s+\w+\s+\w+/g );
|
||||
if ( r !== null ) {
|
||||
for ( var i = 0, l = r.length; i < l; i++ ) {
|
||||
var attr = r[ i ].match( /attribute\s+\w+\s+(\w+)/ )[ 1 ];
|
||||
attributeMap[ attr ] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return attributeMap;
|
||||
};
|
||||
|
||||
|
||||
// static cache of glPrograms flagged for deletion, which will actually
|
||||
// be deleted in the correct GL context.
|
||||
Program._sDeletedGLProgramCache = new window.Map();
|
||||
|
||||
// static method to delete Program
|
||||
Program.deleteGLProgram = function ( gl, program ) {
|
||||
|
||||
if ( !Program._sDeletedGLProgramCache.has( gl ) )
|
||||
Program._sDeletedGLProgramCache.set( gl, [] );
|
||||
|
||||
Program._sDeletedGLProgramCache.get( gl ).push( program );
|
||||
};
|
||||
|
||||
// static method to flush all the cached glPrograms which need to be deleted in the GL context specified
|
||||
Program.flushDeletedGLPrograms = function ( gl, availableTime ) {
|
||||
|
||||
// if no time available don't try to flush objects.
|
||||
if ( availableTime <= 0.0 ) return availableTime;
|
||||
|
||||
if ( !Program._sDeletedGLProgramCache.has( gl ) ) return availableTime;
|
||||
|
||||
var elapsedTime = 0.0;
|
||||
var beginTime = Timer.instance().tick();
|
||||
var deleteList = Program._sDeletedGLProgramCache.get( gl );
|
||||
var numPrograms = deleteList.length;
|
||||
|
||||
for ( var i = numPrograms - 1; i >= 0 && elapsedTime < availableTime; i-- ) {
|
||||
gl.deleteProgram( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
elapsedTime = Timer.instance().deltaS( beginTime, Timer.instance().tick() );
|
||||
}
|
||||
|
||||
return availableTime - elapsedTime;
|
||||
};
|
||||
|
||||
Program.flushAllDeletedGLPrograms = function ( gl ) {
|
||||
|
||||
if ( !Program._sDeletedGLProgramCache.has( gl ) ) return;
|
||||
|
||||
var deleteList = Program._sDeletedGLProgramCache.get( gl );
|
||||
var numPrograms = deleteList.length;
|
||||
|
||||
for ( var i = numPrograms - 1; i >= 0; i-- ) {
|
||||
gl.deleteProgram( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
}
|
||||
};
|
||||
|
||||
/** @lends Program.prototype */
|
||||
Program.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( GLObject.prototype, MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'Program',
|
||||
|
||||
cloneType: function () {
|
||||
return new Program();
|
||||
},
|
||||
|
||||
setVertexShader: function ( vs ) {
|
||||
this._vertex = vs;
|
||||
this._nullProgram = false;
|
||||
},
|
||||
|
||||
setFragmentShader: function ( fs ) {
|
||||
this._fragment = fs;
|
||||
this._nullProgram = false;
|
||||
},
|
||||
|
||||
getVertexShader: function () {
|
||||
return this._vertex;
|
||||
},
|
||||
getFragmentShader: function () {
|
||||
return this._fragment;
|
||||
},
|
||||
|
||||
getProgram: function () {
|
||||
return this._program;
|
||||
},
|
||||
|
||||
setActiveUniforms: function ( activeUniforms ) {
|
||||
this._activeUniforms = activeUniforms;
|
||||
},
|
||||
|
||||
getActiveUniforms: function () {
|
||||
return this._activeUniforms;
|
||||
},
|
||||
|
||||
setForeignUniforms: function ( foreignUniforms ) {
|
||||
this._foreignUniforms = foreignUniforms;
|
||||
},
|
||||
|
||||
getForeignUniforms: function () {
|
||||
return this._foreignUniforms;
|
||||
},
|
||||
|
||||
setUniformsCache: function ( uniformsCache ) {
|
||||
this._uniformsCache = uniformsCache;
|
||||
},
|
||||
|
||||
getUniformsCache: function () {
|
||||
return this._uniformsCache;
|
||||
},
|
||||
|
||||
setAttributesCache: function ( attributesCache ) {
|
||||
this._attributesCache = attributesCache;
|
||||
},
|
||||
|
||||
getAttributesCache: function () {
|
||||
return this._attributesCache;
|
||||
},
|
||||
|
||||
setTrackAttributes: function ( trackAttributes ) {
|
||||
this._trackAttributes = trackAttributes;
|
||||
},
|
||||
|
||||
getTrackAttributes: function () {
|
||||
return this._trackAttributes;
|
||||
},
|
||||
|
||||
releaseGLObjects: function () {
|
||||
// Call to releaseGLOBjects on shaders
|
||||
if ( this._vertex !== undefined ) this._vertex.releaseGLObjects();
|
||||
if ( this._fragment !== undefined ) this._fragment.releaseGLObjects();
|
||||
if ( this._program === null ) return;
|
||||
if ( this._gl !== undefined ) {
|
||||
Program.deleteGLProgram( this._gl, this._program );
|
||||
}
|
||||
this._program = undefined;
|
||||
},
|
||||
|
||||
apply: function ( state ) {
|
||||
|
||||
if ( this._nullProgram ) return;
|
||||
|
||||
if ( !this._gl ) {
|
||||
this.setGraphicContext( state.getGraphicContext() );
|
||||
}
|
||||
var gl = this._gl;
|
||||
if ( !this._program || this._dirty ) {
|
||||
|
||||
var compileClean;
|
||||
|
||||
if ( !this._vertex.shader ) {
|
||||
compileClean = this._vertex.compile( gl );
|
||||
}
|
||||
|
||||
if ( !this._fragment.shader ) {
|
||||
compileClean = this._fragment.compile( gl );
|
||||
}
|
||||
|
||||
var attributeMap = getAttributeList( this._vertex.getText() );
|
||||
|
||||
if ( compileClean ) {
|
||||
|
||||
this._program = gl.createProgram();
|
||||
|
||||
if ( attributeMap.Vertex ) {
|
||||
// force Vertex to be on 0
|
||||
gl.bindAttribLocation( this._program, 0, 'Vertex' );
|
||||
}
|
||||
|
||||
gl.attachShader( this._program, this._vertex.shader );
|
||||
gl.attachShader( this._program, this._fragment.shader );
|
||||
MACROUTILS.timeStamp( 'osgjs.metrics:linkShader' );
|
||||
gl.linkProgram( this._program );
|
||||
|
||||
if ( !gl.getProgramParameter( this._program, gl.LINK_STATUS ) && !gl.isContextLost() ) {
|
||||
var errLink = gl.getProgramInfoLog( this._program );
|
||||
|
||||
Notify.errorFold( errLink, 'can\'t link program\nvertex shader:\n' + this._vertex.text + '\n fragment shader:\n' + this._fragment.text );
|
||||
|
||||
// rawgl trick is for webgl inspector
|
||||
var debugShader = ( gl.rawgl !== undefined ? gl.rawgl : gl );
|
||||
if ( debugShader !== undefined && debugShader.getExtension !== undefined ) debugShader = debugShader.getExtension( 'WEBGL_debug_shaders' );
|
||||
if ( debugShader && errLink === 'Failed to create D3D shaders.\n' ) {
|
||||
|
||||
Notify.error( debugShader.getTranslatedShaderSource( this._vertex.shader ) );
|
||||
Notify.error( debugShader.getTranslatedShaderSource( this._fragment.shader ) );
|
||||
}
|
||||
|
||||
compileClean = false;
|
||||
}
|
||||
// TODO: better usage of validate.
|
||||
// as it's intended at shader program usage
|
||||
// validating against current gl state
|
||||
// Not for compilation stage
|
||||
// gl.validateProgram( this._program );
|
||||
|
||||
}
|
||||
|
||||
if ( !compileClean ) {
|
||||
// Any error, Any
|
||||
// Pink must die.
|
||||
if ( !Program.prototype._failSafeCache ) {
|
||||
|
||||
var program = gl.createProgram();
|
||||
this._vertex.failSafe( gl );
|
||||
this._fragment.failSafe( gl );
|
||||
|
||||
gl.attachShader( program, this._vertex.shader );
|
||||
gl.attachShader( program, this._fragment.shader );
|
||||
gl.linkProgram( program );
|
||||
gl.validateProgram( program );
|
||||
|
||||
// cache to compile and allocate only once
|
||||
// not polluting the inspector
|
||||
Program.prototype._failSafeCache = program;
|
||||
}
|
||||
Notify.warn( 'FailSafe shader Activated ' );
|
||||
this._program = this._failSafeCache;
|
||||
}
|
||||
|
||||
this._uniformsCache = new CustomMap();
|
||||
this._attributesCache = new CustomMap();
|
||||
|
||||
this.cacheUniformList( gl, this._vertex.text );
|
||||
this.cacheUniformList( gl, this._fragment.text );
|
||||
|
||||
this.cacheAttributeList( gl, window.Object.keys( attributeMap ) );
|
||||
|
||||
this._dirty = false;
|
||||
}
|
||||
|
||||
state.applyProgram( this._program );
|
||||
},
|
||||
|
||||
cacheUniformList: function ( gl, str ) {
|
||||
|
||||
var r = str.match( /uniform\s+\w+\s+\w+((\s)?\[(.*?)\])?/g );
|
||||
var map = this._uniformsCache;
|
||||
if ( r !== null ) {
|
||||
for ( var i = 0, l = r.length; i < l; i++ ) {
|
||||
var uniform = r[ i ].match( /uniform\s+\w+\s+(\w+)/ )[ 1 ];
|
||||
var uniformName = r[ i ].match( /uniform\s+\w+\s+(\w+)(\s?\[.*?\])?/ )[ 1 ];
|
||||
var location = gl.getUniformLocation( this._program, uniform );
|
||||
if ( location !== undefined && location !== null ) {
|
||||
if ( map[ uniformName ] === undefined ) {
|
||||
map[ uniformName ] = location;
|
||||
this._uniformsCache.dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
cacheAttributeList: function ( gl, attributeList ) {
|
||||
|
||||
var map = this._attributesCache;
|
||||
for ( var i = 0, l = attributeList.length; i < l; i++ ) {
|
||||
|
||||
var attr = attributeList[ i ];
|
||||
var location = gl.getAttribLocation( this._program, attr );
|
||||
|
||||
if ( location !== -1 && location !== undefined ) {
|
||||
if ( map[ attr ] === undefined ) {
|
||||
map[ attr ] = location;
|
||||
this._attributesCache.dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} ) ), 'osg', 'Program' );
|
||||
|
||||
module.exports = Program;
|
|
@ -1,21 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Node = require( 'osg/Node' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
|
||||
var Projection = function () {
|
||||
Node.call( this );
|
||||
this.projection = mat4.create();
|
||||
};
|
||||
Projection.prototype = MACROUTILS.objectInherit( Node.prototype, {
|
||||
getProjectionMatrix: function () {
|
||||
return this.projection;
|
||||
},
|
||||
setProjectionMatrix: function ( m ) {
|
||||
this.projection = m;
|
||||
}
|
||||
} );
|
||||
|
||||
MACROUTILS.setTypeID( Projection );
|
||||
|
||||
module.exports = Projection;
|
|
@ -1 +0,0 @@
|
|||
module.exports = require( 'osg/deprecated-MatrixVector/Quat' );
|
|
@ -1,321 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var Object = require( 'osg/Object' );
|
||||
var osgMath = require( 'osg/math' );
|
||||
|
||||
|
||||
/**
|
||||
* RenderBin base class. Renderbin contains geometries to be rendered as a group,
|
||||
* renderbins are rendered once each. They can improve efficiency or
|
||||
* use different rendering algorithms.
|
||||
* A renderBin can contain further renderBins producing a tree hierarchy of renderBins.
|
||||
*
|
||||
* https://github.com/openscenegraph/osg/blob/master/include/osgUtil/RenderBin#L27-L32
|
||||
*/
|
||||
var RenderBin = function ( sortMode ) {
|
||||
Object.call( this );
|
||||
|
||||
this._leafs = [];
|
||||
this.positionedAttribute = [];
|
||||
this.stateGraphList = [];
|
||||
|
||||
RenderBin.prototype.init.call( this, sortMode );
|
||||
};
|
||||
|
||||
RenderBin.SORT_BY_STATE = 0;
|
||||
RenderBin.SORT_BACK_TO_FRONT = 1;
|
||||
RenderBin.SORT_FRONT_TO_BACK = 2;
|
||||
|
||||
|
||||
// change it at runtime for default RenderBin if needed
|
||||
RenderBin.defaultSortMode = RenderBin.SORT_BY_STATE;
|
||||
|
||||
RenderBin.BinPrototypes = {
|
||||
RenderBin: function () {
|
||||
return RenderBin.getOrCreate().init();
|
||||
},
|
||||
DepthSortedBin: function () {
|
||||
return RenderBin.getOrCreate().init( RenderBin.SORT_BACK_TO_FRONT );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var sortBackToFrontFunction = function ( a, b ) {
|
||||
return b._depth - a._depth;
|
||||
};
|
||||
|
||||
|
||||
var sortFrontToBackFunction = function ( a, b ) {
|
||||
return a._depth - b._depth;
|
||||
};
|
||||
|
||||
var sortBinNumberFunction = function ( a, b ) {
|
||||
return a._binNum - b._binNum;
|
||||
};
|
||||
|
||||
|
||||
RenderBin.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Object.prototype, {
|
||||
|
||||
init: function ( sortMode ) {
|
||||
|
||||
this._leafs.length = 0;
|
||||
this.positionedAttribute.length = 0;
|
||||
this._renderStage = undefined;
|
||||
this._bins = {};
|
||||
this.stateGraphList.length = 0;
|
||||
this._parent = undefined;
|
||||
this._binNum = 0;
|
||||
|
||||
this._sorted = false;
|
||||
this._sortMode = sortMode !== undefined ? sortMode : RenderBin.defaultSortMode;
|
||||
|
||||
this._drawCallback = undefined;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_createRenderBin: function ( binName ) {
|
||||
|
||||
// default render bin constructor
|
||||
var renderBinConstructor = RenderBin.BinPrototypes.RenderBin;
|
||||
|
||||
if ( binName && RenderBin.BinPrototypes[ binName ] )
|
||||
renderBinConstructor = RenderBin.BinPrototypes[ binName ];
|
||||
|
||||
return renderBinConstructor();
|
||||
},
|
||||
|
||||
getStateGraphList: function () {
|
||||
return this.stateGraphList;
|
||||
},
|
||||
|
||||
copyLeavesFromStateGraphListToRenderLeafList: function () {
|
||||
|
||||
this._leafs.splice( 0, this._leafs.length );
|
||||
var detectedNaN = false;
|
||||
|
||||
for ( var i = 0, l = this.stateGraphList.length; i < l; i++ ) {
|
||||
var leafs = this.stateGraphList[ i ].leafs;
|
||||
for ( var j = 0, k = leafs.length; j < k; j++ ) {
|
||||
var leaf = leafs[ j ];
|
||||
if ( osgMath.isNaN( leaf._depth ) ) {
|
||||
detectedNaN = true;
|
||||
} else {
|
||||
this._leafs.push( leaf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( detectedNaN ) {
|
||||
Notify.debug( 'warning: RenderBin::copyLeavesFromStateGraphListToRenderLeafList() detected NaN depth values, database may be corrupted.' );
|
||||
}
|
||||
// empty the render graph list to prevent it being drawn along side the render leaf list (see drawImplementation.)
|
||||
this.stateGraphList.splice( 0, this.stateGraphList.length );
|
||||
},
|
||||
|
||||
getSortMode: function () {
|
||||
return this._sortMode;
|
||||
},
|
||||
|
||||
sortBackToFront: function () {
|
||||
this.copyLeavesFromStateGraphListToRenderLeafList();
|
||||
this._leafs.sort( sortBackToFrontFunction );
|
||||
},
|
||||
|
||||
sortFrontToBack: function () {
|
||||
this.copyLeavesFromStateGraphListToRenderLeafList();
|
||||
this._leafs.sort( sortFrontToBackFunction );
|
||||
},
|
||||
|
||||
sortImplementation: function () {
|
||||
var SortMode = RenderBin;
|
||||
switch ( this._sortMode ) {
|
||||
case SortMode.SORT_BACK_TO_FRONT:
|
||||
this.sortBackToFront();
|
||||
break;
|
||||
case SortMode.SORT_FRONT_TO_BACK:
|
||||
this.sortFrontToBack();
|
||||
break;
|
||||
case SortMode.SORT_BY_STATE:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
sort: function () {
|
||||
if ( this._sorted ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bins = this._bins;
|
||||
var keys = window.Object.keys( bins );
|
||||
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
||||
bins[ keys[ i ] ].sort();
|
||||
}
|
||||
this.sortImplementation();
|
||||
|
||||
this._sorted = true;
|
||||
},
|
||||
|
||||
setParent: function ( parent ) {
|
||||
this._parent = parent;
|
||||
},
|
||||
|
||||
getParent: function () {
|
||||
return this._parent;
|
||||
},
|
||||
|
||||
getBinNumber: function () {
|
||||
return this._binNum;
|
||||
},
|
||||
|
||||
findOrInsert: function ( binNum, binName ) {
|
||||
var bin = this._bins[ binNum ];
|
||||
|
||||
if ( !bin ) {
|
||||
bin = this._createRenderBin( binName );
|
||||
bin._parent = this;
|
||||
bin._binNum = binNum;
|
||||
bin._renderStage = this._renderStage;
|
||||
this._bins[ binNum ] = bin;
|
||||
}
|
||||
|
||||
return bin;
|
||||
},
|
||||
|
||||
getStage: function () {
|
||||
return this._renderStage;
|
||||
},
|
||||
|
||||
addStateGraph: function ( sg ) {
|
||||
this.stateGraphList.push( sg );
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
this.stateGraphList.length = 0;
|
||||
this._bins = {};
|
||||
this.positionedAttribute.length = 0;
|
||||
this._leafs.length = 0;
|
||||
this._sorted = false;
|
||||
},
|
||||
|
||||
draw: function ( state, previousRenderLeaf ) {
|
||||
|
||||
var previousLeaf = previousRenderLeaf;
|
||||
// use callback drawImplementation if exist
|
||||
if ( this._drawCallback && this._drawCallback.drawImplementation ) {
|
||||
previousLeaf = this._drawCallback.drawImplementation( this, state, previousLeaf );
|
||||
} else {
|
||||
previousLeaf = this.drawImplementation( state, previousLeaf );
|
||||
}
|
||||
|
||||
return previousLeaf;
|
||||
},
|
||||
|
||||
applyPositionedAttribute: function ( state, positionedAttributes ) {
|
||||
// the idea is to set uniform 'globally' in uniform map.
|
||||
for ( var index = 0, l = positionedAttributes.length; index < l; index++ ) {
|
||||
var element = positionedAttributes[ index ];
|
||||
// add or set uniforms in state
|
||||
var stateAttribute = element[ 1 ];
|
||||
var matrix = element[ 0 ];
|
||||
state.setGlobalDefaultAttribute( stateAttribute );
|
||||
stateAttribute.apply( state );
|
||||
stateAttribute.applyPositionedUniform( matrix, state );
|
||||
state.haveAppliedAttribute( stateAttribute );
|
||||
}
|
||||
},
|
||||
|
||||
drawImplementation: function ( state, previousRenderLeaf ) {
|
||||
|
||||
var previousLeaf = previousRenderLeaf;
|
||||
var binsKeys = window.Object.keys( this._bins );
|
||||
var bins = this._bins;
|
||||
|
||||
var binsArray = [];
|
||||
|
||||
for ( var i = 0, l = binsKeys.length; i < l; i++ ) {
|
||||
var k = binsKeys[ i ];
|
||||
binsArray.push( bins[ k ] );
|
||||
}
|
||||
|
||||
binsArray.sort( sortBinNumberFunction );
|
||||
|
||||
var current = 0;
|
||||
var end = binsArray.length;
|
||||
|
||||
var bin;
|
||||
// draw pre bins
|
||||
for ( ; current < end; current++ ) {
|
||||
bin = binsArray[ current ];
|
||||
if ( bin.getBinNumber() > 0 ) {
|
||||
break;
|
||||
}
|
||||
previousLeaf = bin.draw( state, previousLeaf );
|
||||
}
|
||||
|
||||
// draw leafs
|
||||
previousLeaf = this.drawLeafs( state, previousLeaf );
|
||||
|
||||
// draw post bins
|
||||
for ( ; current < end; current++ ) {
|
||||
bin = binsArray[ current ];
|
||||
previousLeaf = bin.draw( state, previousLeaf );
|
||||
}
|
||||
return previousLeaf;
|
||||
},
|
||||
|
||||
|
||||
drawLeafs: function ( state, previousRenderLeaf ) {
|
||||
|
||||
var stateList = this.stateGraphList;
|
||||
var leafs = this._leafs;
|
||||
var previousLeaf = previousRenderLeaf;
|
||||
var leaf;
|
||||
|
||||
|
||||
// draw fine grained ordering.
|
||||
for ( var d = 0, dl = leafs.length; d < dl; d++ ) {
|
||||
leaf = leafs[ d ];
|
||||
leaf.render( state, previousLeaf );
|
||||
previousLeaf = leaf;
|
||||
}
|
||||
|
||||
|
||||
// draw coarse grained ordering.
|
||||
for ( var i = 0, l = stateList.length; i < l; i++ ) {
|
||||
|
||||
var sg = stateList[ i ];
|
||||
|
||||
for ( var j = 0, ll = sg.leafs.length; j < ll; j++ ) {
|
||||
|
||||
leaf = sg.leafs[ j ];
|
||||
leaf.render( state, previousLeaf );
|
||||
previousLeaf = leaf;
|
||||
|
||||
}
|
||||
}
|
||||
return previousLeaf;
|
||||
}
|
||||
} ), 'osg', 'RenderBin' );
|
||||
|
||||
|
||||
RenderBin.getOrCreate = function () {
|
||||
|
||||
var l = RenderBin._reservedStack[ RenderBin._reservedStackCurrent++ ];
|
||||
if ( RenderBin._reservedStackCurrent === RenderBin._reservedStack.length ) {
|
||||
RenderBin._reservedStack.push( new RenderBin() );
|
||||
}
|
||||
return l;
|
||||
|
||||
};
|
||||
|
||||
RenderBin.resetStack = function () {
|
||||
RenderBin._reservedStackCurrent = 0;
|
||||
};
|
||||
|
||||
RenderBin._reservedStack = [ new RenderBin() ];
|
||||
RenderBin._reservedStackCurrent = 0;
|
||||
|
||||
module.exports = RenderBin;
|
|
@ -1,213 +0,0 @@
|
|||
'use strict';
|
||||
var StateGraph = require( 'osg/StateGraph' );
|
||||
|
||||
var CacheUniformApply = function ( state, program ) {
|
||||
this.modelUniform = program._uniformsCache[ state.modelMatrix.getName() ];
|
||||
this.viewUniform = program._uniformsCache[ state.viewMatrix.getName() ];
|
||||
|
||||
this.apply = undefined;
|
||||
this.generateUniformsApplyMethods();
|
||||
};
|
||||
|
||||
CacheUniformApply.prototype = {
|
||||
|
||||
|
||||
generateUniformsApplyMethods: function () {
|
||||
|
||||
var functionStr = [ '//generated by RenderLeaf\n' ];
|
||||
functionStr.push( 'var gl = state.getGraphicContext();' );
|
||||
functionStr.push( 'var matrixModelViewChanged = state.applyModelViewMatrix( modelview );' );
|
||||
functionStr.push( 'state.applyProjectionMatrix( projection );' );
|
||||
|
||||
if ( this.modelUniform !== undefined ) {
|
||||
functionStr.push( 'if ( matrixModelViewChanged ) {' );
|
||||
functionStr.push( ' var modelMatrix = state.modelMatrix;' );
|
||||
functionStr.push( ' modelMatrix.setMatrix4( model );' );
|
||||
functionStr.push( ' modelMatrix.apply( gl, this.modelUniform);' );
|
||||
functionStr.push( '};' );
|
||||
}
|
||||
|
||||
if ( this.viewUniform !== undefined ) {
|
||||
functionStr.push( 'if ( matrixModelViewChanged ) {' );
|
||||
functionStr.push( ' var viewMatrix = state.viewMatrix;' );
|
||||
functionStr.push( ' viewMatrix.setMatrix4( view );' );
|
||||
functionStr.push( ' viewMatrix.apply( gl, this.viewUniform);' );
|
||||
functionStr.push( '};' );
|
||||
}
|
||||
|
||||
// I am the evil, so please bother someone else
|
||||
/*jshint evil: true */
|
||||
// name the function
|
||||
// http://stackoverflow.com/questions/5905492/dynamic-function-name-in-javascript
|
||||
var func = ( new Function( 'state', 'modelview', 'model', 'view', 'projection', 'return function RenderLeafApplyMatrixUniformCache( state, modelview, model, view, projection ) { ' + functionStr.join( '\n' ) + '}' ) )();
|
||||
/*jshint evil: false */
|
||||
|
||||
this.apply = func;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var RenderLeaf = function () {
|
||||
|
||||
this._parent = undefined;
|
||||
this._geometry = undefined;
|
||||
this._depth = 0.0;
|
||||
|
||||
this._projection = undefined;
|
||||
this._view = undefined;
|
||||
this._model = undefined;
|
||||
this._modelView = undefined;
|
||||
};
|
||||
|
||||
RenderLeaf.prototype = {
|
||||
|
||||
reset: function () {
|
||||
this._parent = undefined;
|
||||
this._geometry = undefined;
|
||||
this._depth = 0.0;
|
||||
|
||||
this._projection = undefined;
|
||||
this._view = undefined;
|
||||
this._model = undefined;
|
||||
this._modelView = undefined;
|
||||
},
|
||||
|
||||
init: function ( parent, geom, projection, view, modelView, model, depth ) {
|
||||
|
||||
this._parent = parent;
|
||||
this._geometry = geom;
|
||||
this._depth = depth;
|
||||
|
||||
this._projection = projection;
|
||||
this._view = view;
|
||||
this._model = model;
|
||||
this._modelView = modelView;
|
||||
|
||||
},
|
||||
|
||||
drawGeometry: ( function () {
|
||||
|
||||
return function ( state ) {
|
||||
|
||||
|
||||
var program = state.getLastProgramApplied();
|
||||
var programInstanceID = program.getInstanceID();
|
||||
var cache = state.getCacheUniformsApplyRenderLeaf();
|
||||
var obj = cache[ programInstanceID ];
|
||||
|
||||
if ( !obj ) {
|
||||
obj = new CacheUniformApply( state, program );
|
||||
cache[ programInstanceID ] = obj;
|
||||
}
|
||||
|
||||
obj.apply( state, this._modelView, this._model, this._view, this._projection, this._normal );
|
||||
|
||||
this._geometry.drawImplementation( state );
|
||||
|
||||
};
|
||||
} )(),
|
||||
|
||||
render: ( function () {
|
||||
var idLastDraw = 0;
|
||||
var lastStateSetStackSize = -1;
|
||||
|
||||
return function ( state, previousLeaf ) {
|
||||
|
||||
var prevRenderGraph;
|
||||
var prevRenderGraphParent;
|
||||
var curRenderGraph = this._parent;
|
||||
var curRenderGraphParent = curRenderGraph.parent;
|
||||
var curRenderGraphStateSet = curRenderGraph.stateset;
|
||||
|
||||
// When rendering a RenderLeaf we try to limit the state change
|
||||
// to do that Graph of State is created during the culling pass.
|
||||
// this graph contains nodes of StateGraph type see the class StateGraph
|
||||
//
|
||||
// So to limit switching of StateSet we check where are the common parent
|
||||
// between previous RenderLeaf and this current.
|
||||
//
|
||||
// There are 3 cases when there is a prev / current render leaf
|
||||
//
|
||||
//
|
||||
// pRG: previousRenderGraph
|
||||
// cRG: currentRenderGraph
|
||||
// pRL: previousRenderLeaf
|
||||
// cRL: currentRenderLeaf
|
||||
// each RG contains a StateSet
|
||||
//
|
||||
// A B C
|
||||
// +-----+ +-----+ +-----+ +-----+
|
||||
// | pRG | | cRG | +--+ RG +--+ | RG |
|
||||
// +--+--+ +--+--+ | +-----+ | +--+--+
|
||||
// | | | | |
|
||||
// +--v--+ +--v--+ +--v--+ +--v--+ +--v--+
|
||||
// | pRG | | cRG | | pRG | | cRG | +--+ RG +--+
|
||||
// +--+--+ +--+--+ +--+--+ +--+--+ | +-----+ |
|
||||
// | | | | | |
|
||||
// +--v--+ +--v--+ +--v--+ +--v--+ +--v--+ +--v--+
|
||||
// | pRL | | cRL | | pRL | | cRL | | pRL | | cRL |
|
||||
// +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
|
||||
//
|
||||
//
|
||||
// Case A
|
||||
// no common parent StateGraphNode we need to
|
||||
// popStateSet until we find the common parent and then
|
||||
// pushStateSet from the common parent to the current
|
||||
// RenderLeaf
|
||||
//
|
||||
// Case B
|
||||
// common parent StateGraphNode so we apply the current stateSet
|
||||
//
|
||||
// Case C
|
||||
// the StateGraphNode is common to the previous RenderLeaf so we dont need
|
||||
// to do anything except if we used an insertStateSet
|
||||
//
|
||||
|
||||
if ( previousLeaf !== undefined ) {
|
||||
|
||||
// apply state if required.
|
||||
prevRenderGraph = previousLeaf._parent;
|
||||
prevRenderGraphParent = prevRenderGraph.parent;
|
||||
|
||||
if ( prevRenderGraphParent !== curRenderGraphParent ) {
|
||||
|
||||
// Case A
|
||||
StateGraph.moveStateGraph( state, prevRenderGraphParent, curRenderGraphParent );
|
||||
|
||||
state.applyStateSet( curRenderGraphStateSet );
|
||||
|
||||
} else if ( curRenderGraph !== prevRenderGraph ) {
|
||||
|
||||
// Case B
|
||||
state.applyStateSet( curRenderGraphStateSet );
|
||||
|
||||
} else {
|
||||
|
||||
// Case C
|
||||
|
||||
// in osg we call apply but actually we dont need
|
||||
// except if the stateSetStack changed.
|
||||
// for example if insert/remove StateSet has been used
|
||||
if ( state._stateSetStackChanged( idLastDraw, lastStateSetStackSize ) ) {
|
||||
state.applyStateSet( curRenderGraphStateSet );
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
StateGraph.moveStateGraph( state, undefined, curRenderGraphParent );
|
||||
state.applyStateSet( curRenderGraphStateSet );
|
||||
|
||||
}
|
||||
|
||||
state._setStateSetsDrawID( ++idLastDraw );
|
||||
lastStateSetStackSize = state.getStateSetStackSize();
|
||||
|
||||
this.drawGeometry( state );
|
||||
|
||||
};
|
||||
} )()
|
||||
|
||||
};
|
||||
|
||||
module.exports = RenderLeaf;
|
|
@ -1,313 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Camera = require( 'osg/Camera' );
|
||||
var FrameBufferObject = require( 'osg/FrameBufferObject' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var RenderBin = require( 'osg/RenderBin' );
|
||||
var vec4 = require( 'osg/glMatrix' ).vec4;
|
||||
|
||||
|
||||
/**
|
||||
* From OpenSceneGraph http://www.openscenegraph.org
|
||||
* RenderStage base class. Used for encapsulate a complete stage in
|
||||
* rendering - setting up of viewport, the projection and model
|
||||
* matrices and rendering the RenderBin's enclosed with this RenderStage.
|
||||
* RenderStage also has a dependency list of other RenderStages, each
|
||||
* of which must be called before the rendering of this stage. These
|
||||
* 'pre' rendering stages are used for advanced rendering techniques
|
||||
* like multistage pixel shading or impostors.
|
||||
*/
|
||||
var RenderStage = function () {
|
||||
|
||||
RenderBin.call( this );
|
||||
this.clearColor = vec4.create();
|
||||
this.preRenderList = [];
|
||||
this.postRenderList = [];
|
||||
// calling prototype to make sure
|
||||
// we call renderstage and not renderbin init
|
||||
RenderStage.prototype.init.call( this );
|
||||
|
||||
};
|
||||
|
||||
RenderStage.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( RenderBin.prototype, {
|
||||
|
||||
// temporary, Utils.createPrototypeClass will solve this
|
||||
constructor: RenderStage,
|
||||
|
||||
|
||||
init: function () {
|
||||
|
||||
RenderBin.prototype.init.call( this );
|
||||
this.positionedAttribute.length = 0;
|
||||
this.clearDepth = 1.0;
|
||||
vec4.set( this.clearColor, 0.0, 0.0, 0.0, 1.0 );
|
||||
/*jshint bitwise: false */
|
||||
this.clearMask = Camera.COLOR_BUFFER_BIT | Camera.DEPTH_BUFFER_BIT;
|
||||
/*jshint bitwise: true */
|
||||
this.camera = undefined;
|
||||
this.viewport = undefined;
|
||||
this.preRenderList.length = 0;
|
||||
this.postRenderList.length = 0;
|
||||
this._renderStage = this;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
RenderBin.prototype.reset.call( this );
|
||||
this.preRenderList.length = 0;
|
||||
this.postRenderList.length = 0;
|
||||
},
|
||||
|
||||
setClearDepth: function ( depth ) {
|
||||
this.clearDepth = depth;
|
||||
},
|
||||
|
||||
getClearDepth: function () {
|
||||
return this.clearDepth;
|
||||
},
|
||||
|
||||
setClearColor: function ( color ) {
|
||||
vec4.copy( this.clearColor, color );
|
||||
},
|
||||
|
||||
getClearColor: function () {
|
||||
return this.clearColor;
|
||||
},
|
||||
|
||||
setClearMask: function ( mask ) {
|
||||
this.clearMask = mask;
|
||||
},
|
||||
|
||||
getClearMask: function () {
|
||||
return this.clearMask;
|
||||
},
|
||||
|
||||
setViewport: function ( vp ) {
|
||||
this.viewport = vp;
|
||||
},
|
||||
|
||||
getViewport: function () {
|
||||
return this.viewport;
|
||||
},
|
||||
|
||||
setCamera: function ( camera ) {
|
||||
this.camera = camera;
|
||||
},
|
||||
|
||||
getCamera: function () {
|
||||
return this.camera;
|
||||
},
|
||||
|
||||
getPositionedAttribute: function () {
|
||||
return this.positionedAttribute;
|
||||
},
|
||||
|
||||
getPreRenderStageList: function () {
|
||||
return this.preRenderList;
|
||||
},
|
||||
|
||||
getPostRenderStageList: function () {
|
||||
return this.postRenderList;
|
||||
},
|
||||
|
||||
addPreRenderStage: function ( rs, order ) {
|
||||
for ( var i = 0, l = this.preRenderList.length; i < l; i++ ) {
|
||||
var render = this.preRenderList[ i ];
|
||||
if ( order < render.order ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( i < this.preRenderList.length ) {
|
||||
this.preRenderList = this.preRenderList.splice( i, 0, {
|
||||
'order': order,
|
||||
'renderStage': rs
|
||||
} );
|
||||
} else {
|
||||
this.preRenderList.push( {
|
||||
'order': order,
|
||||
'renderStage': rs
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
addPostRenderStage: function ( rs, order ) {
|
||||
for ( var i = 0, l = this.postRenderList.length; i < l; i++ ) {
|
||||
var render = this.postRenderList[ i ];
|
||||
if ( order < render.order ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( i < this.postRenderList.length ) {
|
||||
this.postRenderList = this.postRenderList.splice( i, 0, {
|
||||
'order': order,
|
||||
'renderStage': rs
|
||||
} );
|
||||
} else {
|
||||
this.postRenderList.push( {
|
||||
'order': order,
|
||||
'renderStage': rs
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
drawPreRenderStages: function ( state, previousRenderLeaf ) {
|
||||
var previousLeaf = previousRenderLeaf;
|
||||
for ( var i = 0, l = this.preRenderList.length; i < l; ++i ) {
|
||||
var sg = this.preRenderList[ i ].renderStage;
|
||||
previousLeaf = sg.draw( state, previousLeaf );
|
||||
}
|
||||
return previousLeaf;
|
||||
},
|
||||
|
||||
draw: function ( state, previousRenderLeaf ) {
|
||||
|
||||
if ( this.camera && this.camera.getInitialDrawCallback() ) {
|
||||
// if we have a camera with a final callback invoke it.
|
||||
this.camera.getInitialDrawCallback()( state );
|
||||
}
|
||||
|
||||
var previousLeaf = this.drawPreRenderStages( state, previousRenderLeaf );
|
||||
|
||||
previousLeaf = this.drawImplementation( state, previousLeaf );
|
||||
|
||||
previousLeaf = this.drawPostRenderStages( state, previousLeaf );
|
||||
|
||||
if ( this.camera && this.camera.getFinalDrawCallback() ) {
|
||||
// if we have a camera with a final callback invoke it.
|
||||
this.camera.getFinalDrawCallback()( state );
|
||||
}
|
||||
|
||||
return previousLeaf;
|
||||
|
||||
},
|
||||
|
||||
sort: function () {
|
||||
for ( var i = 0, l = this.preRenderList.length; i < l; ++i ) {
|
||||
this.preRenderList[ i ].renderStage.sort();
|
||||
}
|
||||
|
||||
RenderBin.prototype.sort.call( this );
|
||||
|
||||
for ( var j = 0, k = this.postRenderList.length; j < k; ++j ) {
|
||||
this.postRenderList[ j ].renderStage.sort();
|
||||
}
|
||||
},
|
||||
|
||||
drawPostRenderStages: function ( state, previousRenderLeaf ) {
|
||||
var previousLeaf = previousRenderLeaf;
|
||||
for ( var i = 0, l = this.postRenderList.length; i < l; ++i ) {
|
||||
var sg = this.postRenderList[ i ].renderStage;
|
||||
previousLeaf = sg.draw( state, previousLeaf );
|
||||
}
|
||||
return previousLeaf;
|
||||
},
|
||||
|
||||
applyCamera: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
if ( this.camera === undefined ) {
|
||||
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
|
||||
return;
|
||||
}
|
||||
var viewport = this.camera.getViewport();
|
||||
var fbo = this.camera.frameBufferObject;
|
||||
|
||||
if ( !fbo ) {
|
||||
fbo = new FrameBufferObject();
|
||||
this.camera.frameBufferObject = fbo;
|
||||
}
|
||||
|
||||
if ( fbo.isDirty() ) {
|
||||
|
||||
var attachments = this.camera.getAttachments();
|
||||
|
||||
// framebuffer texture and renderbuffer must be same dimension
|
||||
// otherwise framebuffer is incomplete
|
||||
var framebufferWidth, framebufferHeight;
|
||||
var colorAttachment = attachments[ FrameBufferObject.COLOR_ATTACHMENT0 ];
|
||||
if ( colorAttachment && colorAttachment.texture ) {
|
||||
framebufferWidth = colorAttachment.texture.getWidth();
|
||||
framebufferHeight = colorAttachment.texture.getHeight();
|
||||
}
|
||||
|
||||
// we should use a map in camera to avoid to regenerate the keys
|
||||
// each time. But because we dont have a lot of camera I guess
|
||||
// it does not change a lot
|
||||
var keys = window.Object.keys( attachments );
|
||||
|
||||
if ( keys.length ) {
|
||||
|
||||
// texture and renderbuffer must be same size.
|
||||
|
||||
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
||||
var key = keys[ i ];
|
||||
var a = attachments[ key ];
|
||||
|
||||
var attach = {};
|
||||
attach.attachment = a.attachment;
|
||||
|
||||
if ( a.texture === undefined ) { //renderbuffer
|
||||
|
||||
attach.format = a.format;
|
||||
attach.width = framebufferWidth !== undefined ? framebufferWidth : viewport.width();
|
||||
attach.height = framebufferHeight !== undefined ? framebufferHeight : viewport.height();
|
||||
|
||||
} else if ( a.texture !== undefined ) {
|
||||
|
||||
attach.texture = a.texture;
|
||||
attach.textureTarget = a.textureTarget;
|
||||
|
||||
if ( a.format ) {
|
||||
attach.format = a.format;
|
||||
}
|
||||
}
|
||||
|
||||
fbo.setAttachment( attach );
|
||||
}
|
||||
}
|
||||
}
|
||||
fbo.apply( state );
|
||||
},
|
||||
|
||||
drawImplementation: function ( state, previousRenderLeaf ) {
|
||||
var gl = state.getGraphicContext();
|
||||
|
||||
this.applyCamera( state );
|
||||
|
||||
// projection clipping
|
||||
if ( this.viewport === undefined ) {
|
||||
Notify.log( 'RenderStage does not have a valid viewport' );
|
||||
}
|
||||
state.applyAttribute( this.viewport );
|
||||
|
||||
// fragment clipping
|
||||
if ( this.camera ) {
|
||||
var scissor = this.camera.getStateSet() && this.camera.getStateSet().getAttribute( 'Scissor' );
|
||||
if ( scissor ) state.applyAttribute( scissor );
|
||||
}
|
||||
|
||||
/*jshint bitwise: false */
|
||||
if ( this.clearMask !== 0x0 ) {
|
||||
if ( this.clearMask & gl.COLOR_BUFFER_BIT ) {
|
||||
gl.clearColor( this.clearColor[ 0 ], this.clearColor[ 1 ], this.clearColor[ 2 ], this.clearColor[ 3 ] );
|
||||
}
|
||||
if ( this.clearMask & gl.DEPTH_BUFFER_BIT ) {
|
||||
gl.depthMask( true );
|
||||
gl.clearDepth( this.clearDepth );
|
||||
}
|
||||
/*jshint bitwise: true */
|
||||
gl.clear( this.clearMask );
|
||||
}
|
||||
|
||||
if ( this.positionedAttribute.length !== 0 ) {
|
||||
this.applyPositionedAttribute( state, this.positionedAttribute );
|
||||
}
|
||||
|
||||
var previousLeaf = RenderBin.prototype.drawImplementation.call( this, state, previousRenderLeaf );
|
||||
|
||||
return previousLeaf;
|
||||
}
|
||||
} ), 'osg', 'RenderStage' );
|
||||
|
||||
|
||||
module.exports = RenderStage;
|
|
@ -1,67 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
|
||||
var Scissor = function ( x, y, w, h ) {
|
||||
|
||||
StateAttribute.call( this );
|
||||
|
||||
this._x = x !== undefined ? x : -1;
|
||||
this._y = y !== undefined ? y : -1;
|
||||
this._width = w !== undefined ? w : -1;
|
||||
|
||||
this._height = h !== undefined ? h : -1;
|
||||
};
|
||||
|
||||
Scissor.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'Scissor',
|
||||
|
||||
cloneType: function () {
|
||||
return new Scissor();
|
||||
},
|
||||
|
||||
apply: function ( state ) {
|
||||
|
||||
var gl = state.getGraphicContext();
|
||||
if ( this._x !== -1 ) {
|
||||
|
||||
gl.enable( gl.SCISSOR_TEST );
|
||||
gl.scissor( this._x, this._y, this._width, this._height );
|
||||
|
||||
} else {
|
||||
|
||||
gl.disable( gl.SCISSOR_TEST );
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
setScissor: function ( x, y, width, height ) {
|
||||
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
|
||||
},
|
||||
|
||||
x: function () {
|
||||
return this._x;
|
||||
},
|
||||
|
||||
y: function () {
|
||||
return this._y;
|
||||
},
|
||||
|
||||
width: function () {
|
||||
return this._width;
|
||||
},
|
||||
|
||||
height: function () {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
|
||||
} ), 'osg', 'Scissor' );
|
||||
|
||||
module.exports = Scissor;
|
|
@ -1,196 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Timer = require( 'osg/Timer' );
|
||||
var GLObject = require( 'osg/GLObject' );
|
||||
|
||||
|
||||
/**
|
||||
* Shader manage shader for vertex and fragment, you need both to create a glsl program.
|
||||
* @class Shader
|
||||
*/
|
||||
var Shader = function ( type, text ) {
|
||||
GLObject.call( this );
|
||||
var t = type;
|
||||
if ( typeof ( type ) === 'string' ) {
|
||||
t = Shader[ type ];
|
||||
}
|
||||
this.type = t;
|
||||
this.setText( text );
|
||||
};
|
||||
|
||||
Shader.VERTEX_SHADER = 0x8B31;
|
||||
Shader.FRAGMENT_SHADER = 0x8B30;
|
||||
|
||||
// Debug Pink shader for when shader fails
|
||||
Shader.VS_DBG = 'attribute vec3 Vertex;uniform mat4 uModelViewMatrix;uniform mat4 uProjectionMatrix;void main(void) { gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(Vertex, 1.0);}';
|
||||
Shader.FS_DBG = 'precision lowp float; void main(void) { gl_FragColor = vec4(1.0, 0.6, 0.6, 1.0);}';
|
||||
|
||||
var debugName = '\n#define SHADER_NAME FailSafe\n';
|
||||
Shader.VS_DBG += debugName;
|
||||
Shader.FS_DBG += debugName;
|
||||
|
||||
|
||||
// static cache of glShaders flagged for deletion, which will actually
|
||||
// be deleted in the correct GL context.
|
||||
Shader._sDeletedGLShaderCache = new window.Map();
|
||||
|
||||
// static method to delete Program
|
||||
Shader.deleteGLShader = function ( gl, shader ) {
|
||||
if ( !Shader._sDeletedGLShaderCache.has( gl ) )
|
||||
Shader._sDeletedGLShaderCache.set( gl, [] );
|
||||
Shader._sDeletedGLShaderCache.get( gl ).push( shader );
|
||||
};
|
||||
|
||||
// static method to flush all the cached glShaders which need to be deleted in the GL context specified
|
||||
Shader.flushDeletedGLShaders = function ( gl, availableTime ) {
|
||||
// if no time available don't try to flush objects.
|
||||
if ( availableTime <= 0.0 ) return availableTime;
|
||||
if ( !Shader._sDeletedGLShaderCache.has( gl ) ) return availableTime;
|
||||
var elapsedTime = 0.0;
|
||||
var beginTime = Timer.instance().tick();
|
||||
var deleteList = Shader._sDeletedGLShaderCache.get( gl );
|
||||
var numShaders = deleteList.length;
|
||||
for ( var i = numShaders - 1; i >= 0 && elapsedTime < availableTime; i-- ) {
|
||||
gl.deleteShader( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
elapsedTime = Timer.instance().deltaS( beginTime, Timer.instance().tick() );
|
||||
}
|
||||
return availableTime -= elapsedTime;
|
||||
};
|
||||
|
||||
Shader.flushAllDeletedGLShaders = function ( gl ) {
|
||||
if ( !Shader._sDeletedGLShaderCache.has( gl ) ) return;
|
||||
var deleteList = Shader._sDeletedGLShaderCache.get( gl );
|
||||
var numShaders = deleteList.length;
|
||||
for ( var i = numShaders - 1; i >= 0; i-- ) {
|
||||
gl.deleteShader( deleteList[ i ] );
|
||||
deleteList.splice( i, 1 );
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/** @lends Shader.prototype */
|
||||
Shader.prototype = MACROUTILS.objectInherit( GLObject.prototype, {
|
||||
setText: function ( text ) {
|
||||
this.text = text;
|
||||
},
|
||||
getText: function () {
|
||||
return this.text;
|
||||
},
|
||||
// this is where it creates a fail safe shader that should work everywhere
|
||||
failSafe: function ( gl ) {
|
||||
this.shader = gl.createShader( this.type );
|
||||
gl.shaderSource( this.shader, this.type === Shader.VERTEX_SHADER ? Shader.VS_DBG : Shader.FS_DBG );
|
||||
gl.compileShader( this.shader );
|
||||
},
|
||||
// webgl shader compiler error to source contextualization
|
||||
// for better console log messages
|
||||
processErrors: function ( errors, source ) {
|
||||
// regex to extract error message and line from webgl compiler reporting
|
||||
var r = /ERROR: [\d]+:([\d]+): (.+)/gmi;
|
||||
// split sources in indexable per line array
|
||||
var lines = source.split( '\n' );
|
||||
var linesLength = lines.length;
|
||||
if ( linesLength === 0 ) return;
|
||||
|
||||
var i, m;
|
||||
|
||||
// IE reporting is not the same
|
||||
if ( r.exec( errors ) === null ) {
|
||||
r = /Shader compilation errors\n\((\d+)\, \d+\): (.+)/gmi;
|
||||
}
|
||||
|
||||
// reset index to start.
|
||||
r.lastIndex = 0;
|
||||
|
||||
while ( ( m = r.exec( errors ) ) != null ) {
|
||||
if ( m.index === r.lastIndex ) {
|
||||
r.lastIndex++; // moving between errors
|
||||
}
|
||||
// get error line
|
||||
var line = parseInt( m[ 1 ] );
|
||||
|
||||
if ( line > linesLength ) continue;
|
||||
// webgl error report.
|
||||
Notify.error( 'ERROR ' + m[ 2 ] + ' in line ' + line );
|
||||
|
||||
var minLine = Math.max( 0, line - 7 );
|
||||
var maxLine = Math.max( 0, line - 2 );
|
||||
// for context
|
||||
// log surrounding line priori to error with bof check
|
||||
for ( i = minLine; i <= maxLine; i++ ) {
|
||||
Notify.warn( lines[ i ].replace( /^[ \t]+/g, '' ) );
|
||||
}
|
||||
|
||||
// Warn adds a lovely /!\ icon in front of the culprit line
|
||||
maxLine = Math.max( 0, line - 1 );
|
||||
Notify.error( lines[ maxLine ].replace( /^[ \t]+/g, '' ) );
|
||||
|
||||
minLine = Math.min( linesLength, line );
|
||||
maxLine = Math.min( linesLength, line + 5 );
|
||||
// for context
|
||||
// surrounding line posterior to error (with eof check)
|
||||
for ( i = minLine; i < maxLine; i++ ) {
|
||||
Notify.warn( lines[ i ].replace( /^[ \t]+/g, '' ) );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
compile: function ( gl ) {
|
||||
if ( !this._gl ) this.setGraphicContext( gl );
|
||||
this.shader = gl.createShader( this.type );
|
||||
|
||||
var shaderText = this.text;
|
||||
if ( Shader.enableGLSLOptimizer && Shader.glslOptimizer ) {
|
||||
var shaderTypeString = this.type === Shader.VERTEX_SHADER ? 'vertex' : 'fragment';
|
||||
Notify.infoFold( shaderTypeString + ' shader before optimization', shaderText );
|
||||
// 1: opengl
|
||||
// 2: opengl es 2.0
|
||||
// 3: opengl es 3.0
|
||||
var optimized = Shader.glslOptimizer( shaderText, '2', this.type === Shader.VERTEX_SHADER );
|
||||
if ( optimized.indexOf( 'Error:' ) !== -1 ) {
|
||||
Notify.error( optimized );
|
||||
} else if ( optimized.length <= 1 ) {
|
||||
Notify.warnFold( 'glsl optimizer returned an empty shader, the original will be used', shaderText );
|
||||
} else {
|
||||
Notify.infoFold( shaderTypeString + ' shader after optimization', optimized );
|
||||
shaderText = optimized;
|
||||
}
|
||||
}
|
||||
|
||||
gl.shaderSource( this.shader, shaderText );
|
||||
MACROUTILS.timeStamp( 'osgjs.metrics:compileShader' );
|
||||
gl.compileShader( this.shader );
|
||||
if ( !gl.getShaderParameter( this.shader, gl.COMPILE_STATUS ) && !gl.isContextLost() ) {
|
||||
|
||||
var err = gl.getShaderInfoLog( this.shader );
|
||||
this.processErrors( err, shaderText );
|
||||
|
||||
var tmpText = '\n' + shaderText;
|
||||
var splittedText = tmpText.split( '\n' );
|
||||
var newText = '\n';
|
||||
for ( var i = 0, l = splittedText.length; i < l; ++i ) {
|
||||
newText += i + ' ' + splittedText[ i ] + '\n';
|
||||
}
|
||||
// still logging whole source but folded
|
||||
Notify.debugFold( 'can\'t compile shader', newText );
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
releaseGLObjects: function () {
|
||||
if ( this._gl !== undefined ) {
|
||||
Shader.deleteGLShader( this._gl, this.shader );
|
||||
}
|
||||
this.shader = undefined;
|
||||
}
|
||||
} );
|
||||
|
||||
Shader.create = function ( type, text ) {
|
||||
Notify.log( 'Shader.create is deprecated, use new Shader with the same arguments instead' );
|
||||
return new Shader( type, text );
|
||||
};
|
||||
|
||||
module.exports = Shader;
|
|
@ -1,32 +0,0 @@
|
|||
'use strict';
|
||||
var Stack = function () {
|
||||
this.globalDefault = undefined;
|
||||
this.lastApplied = undefined;
|
||||
this.asChanged = false;
|
||||
|
||||
this._values = [];
|
||||
this._back = undefined;
|
||||
};
|
||||
|
||||
Stack.prototype = {
|
||||
empty: function () {
|
||||
return this._values.length === 0;
|
||||
},
|
||||
values: function () {
|
||||
return this._values;
|
||||
},
|
||||
back: function () {
|
||||
return this._back;
|
||||
},
|
||||
push: function ( value ) {
|
||||
this._values.push( value );
|
||||
this._back = value;
|
||||
},
|
||||
pop: function () {
|
||||
var value = this._values.pop();
|
||||
this._back = this._values[ this._values.length - 1 ];
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Stack;
|
Plik diff jest za duży
Load Diff
|
@ -1,43 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Object = require( 'osg/Object' );
|
||||
|
||||
|
||||
var StateAttribute = function () {
|
||||
Object.call( this );
|
||||
};
|
||||
|
||||
StateAttribute.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Object.prototype, {
|
||||
|
||||
getType: function () {
|
||||
return this.attributeType;
|
||||
},
|
||||
|
||||
// basically, if you want two StateAttribute with the same attributeType in a stateSet/State
|
||||
// their typeMember should be different
|
||||
getTypeMember: function () {
|
||||
return this.attributeType;
|
||||
},
|
||||
|
||||
apply: function () {},
|
||||
|
||||
// getHash is used by the compiler to know if a change in a StateAttribute
|
||||
// must trigger a shader build
|
||||
// If you create your own attribute you will have to customize this function
|
||||
// a good rule is to that if you change uniform it should not rebuild a shader
|
||||
// but if you change a type or representation of your StateAttribute, then it should
|
||||
// if it impact the rendering.
|
||||
// check other attributes for examples
|
||||
getHash: function () {
|
||||
return this.getTypeMember();
|
||||
}
|
||||
|
||||
} ), 'osg', 'StateAttribute' );
|
||||
|
||||
StateAttribute.OFF = 0;
|
||||
StateAttribute.ON = 1;
|
||||
StateAttribute.OVERRIDE = 2;
|
||||
StateAttribute.PROTECTED = 4;
|
||||
StateAttribute.INHERIT = 8;
|
||||
|
||||
module.exports = StateAttribute;
|
|
@ -1,150 +0,0 @@
|
|||
'use strict';
|
||||
var osgPool = require( 'osgUtil/osgPool' );
|
||||
|
||||
|
||||
var StateGraph = function () {
|
||||
this.depth = 0;
|
||||
this.children = {};
|
||||
this.children.keys = [];
|
||||
this.leafs = [];
|
||||
this.stateset = undefined;
|
||||
this.parent = undefined;
|
||||
};
|
||||
|
||||
StateGraph.prototype = {
|
||||
|
||||
clean: function () {
|
||||
|
||||
this.leafs.length = 0;
|
||||
this.stateset = undefined;
|
||||
this.parent = undefined;
|
||||
this.depth = 0;
|
||||
var children = this.children;
|
||||
var child;
|
||||
var key, keys = children.keys;
|
||||
|
||||
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
||||
|
||||
key = keys[ i ];
|
||||
child = children[ key ];
|
||||
child.clean();
|
||||
osgPool.memoryPools.stateGraph.put( child );
|
||||
|
||||
}
|
||||
|
||||
this.children = {};
|
||||
keys.length = 0;
|
||||
this.children.keys = keys;
|
||||
},
|
||||
|
||||
getStateSet: function () {
|
||||
return this.stateset;
|
||||
},
|
||||
|
||||
findOrInsert: function ( stateset ) {
|
||||
|
||||
var sg;
|
||||
var stateSetID = stateset.getInstanceID();
|
||||
var children = this.children;
|
||||
|
||||
if ( !children[ stateSetID ] ) {
|
||||
|
||||
//sg = new StateGraph();
|
||||
sg = osgPool.memoryPools.stateGraph.get();
|
||||
|
||||
sg.parent = this;
|
||||
sg.depth = this.depth + 1;
|
||||
sg.stateset = stateset;
|
||||
children[ stateSetID ] = sg;
|
||||
children.keys.push( stateSetID );
|
||||
|
||||
} else {
|
||||
|
||||
sg = children[ stateSetID ];
|
||||
|
||||
}
|
||||
return sg;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
StateGraph.moveStateGraph = function ( state, sgCurrentArg, sgNewArg ) {
|
||||
|
||||
var stack = [];
|
||||
var sgNew = sgNewArg;
|
||||
var sgCurrent = sgCurrentArg;
|
||||
var i, l;
|
||||
if ( sgNew === sgCurrent || sgNew === undefined ) return;
|
||||
|
||||
if ( sgCurrent === undefined ) {
|
||||
// push stateset from sgNew to root, and apply
|
||||
// stateset from root to sgNew
|
||||
do {
|
||||
if ( sgNew.stateset !== undefined ) {
|
||||
stack.push( sgNew.stateset );
|
||||
}
|
||||
sgNew = sgNew.parent;
|
||||
} while ( sgNew );
|
||||
|
||||
for ( i = stack.length - 1, l = 0; i >= l; --i ) {
|
||||
state.pushStateSet( stack[ i ] );
|
||||
}
|
||||
return;
|
||||
|
||||
} else if ( sgCurrent.parent === sgNew.parent ) {
|
||||
// first handle the typical case which is two state groups
|
||||
// are neighbours.
|
||||
|
||||
// state has changed so need to pop old state.
|
||||
if ( sgCurrent.stateset !== undefined ) {
|
||||
state.popStateSet();
|
||||
}
|
||||
// and push new state.
|
||||
if ( sgNew.stateset !== undefined ) {
|
||||
state.pushStateSet( sgNew.stateset );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// need to pop back up to the same depth as the new state group.
|
||||
while ( sgCurrent.depth > sgNew.depth ) {
|
||||
if ( sgCurrent.stateset !== undefined ) {
|
||||
state.popStateSet();
|
||||
}
|
||||
sgCurrent = sgCurrent.parent;
|
||||
}
|
||||
|
||||
// use return path to trace back steps to sgNew.
|
||||
stack = [];
|
||||
|
||||
// need to pop back up to the same depth as the curr state group.
|
||||
while ( sgNew.depth > sgCurrent.depth ) {
|
||||
if ( sgNew.stateset !== undefined ) {
|
||||
stack.push( sgNew.stateset );
|
||||
}
|
||||
sgNew = sgNew.parent;
|
||||
}
|
||||
|
||||
// now pop back up both parent paths until they agree.
|
||||
|
||||
// DRT - 10/22/02
|
||||
// should be this to conform with above case where two StateGraph
|
||||
// nodes have the same parent
|
||||
while ( sgCurrent !== sgNew ) {
|
||||
if ( sgCurrent.stateset !== undefined ) {
|
||||
state.popStateSet();
|
||||
}
|
||||
sgCurrent = sgCurrent.parent;
|
||||
|
||||
if ( sgNew.stateset !== undefined ) {
|
||||
stack.push( sgNew.stateset );
|
||||
}
|
||||
sgNew = sgNew.parent;
|
||||
}
|
||||
|
||||
for ( i = stack.length - 1, l = 0; i >= l; --i ) {
|
||||
state.pushStateSet( stack[ i ] );
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = StateGraph;
|
|
@ -1,307 +0,0 @@
|
|||
'use strict';
|
||||
var Map = require( 'osg/Map' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var Object = require( 'osg/Object' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
|
||||
|
||||
/** Stores a set of modes and attributes which represent a set of OpenGL state.
|
||||
* Notice that a \c StateSet contains just a subset of the whole OpenGL state.
|
||||
* <p>In OSG, each \c Drawable and each \c Node has a reference to a
|
||||
* \c StateSet. These <tt>StateSet</tt>s can be shared between
|
||||
* different <tt>Drawable</tt>s and <tt>Node</tt>s (that is, several
|
||||
* <tt>Drawable</tt>s and <tt>Node</tt>s can reference the same \c StateSet).
|
||||
* Indeed, this practice is recommended whenever possible,
|
||||
* as this minimizes expensive state changes in the graphics pipeline.
|
||||
*/
|
||||
var StateSet = function () {
|
||||
Object.call( this );
|
||||
|
||||
this._parents = [];
|
||||
this.attributeMap = new Map();
|
||||
|
||||
this.textureAttributeMapList = [];
|
||||
|
||||
this._binName = undefined;
|
||||
this._binNumber = 0;
|
||||
|
||||
// put the shader generator name in an AttributePair
|
||||
// so that we can use the mask value
|
||||
this._shaderGeneratorPair = null;
|
||||
|
||||
this._updateCallbackList = [];
|
||||
|
||||
this.uniforms = new Map();
|
||||
|
||||
this._drawID = -1; // used by the RenderLeaf to decide if it should apply the stateSet
|
||||
};
|
||||
|
||||
StateSet.AttributePair = function ( attr, value ) {
|
||||
this._object = attr;
|
||||
this._value = value;
|
||||
};
|
||||
|
||||
StateSet.AttributePair.prototype = {
|
||||
getShaderGeneratorName: function () {
|
||||
return this._object;
|
||||
},
|
||||
getAttribute: function () {
|
||||
return this._object;
|
||||
},
|
||||
getUniform: function () {
|
||||
return this._object;
|
||||
},
|
||||
getValue: function () {
|
||||
return this._value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
StateSet.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Object.prototype, {
|
||||
|
||||
setDrawID: function ( id ) {
|
||||
this._drawID = id;
|
||||
},
|
||||
|
||||
getDrawID: function () {
|
||||
return this._drawID;
|
||||
},
|
||||
|
||||
getAttributePair: function ( attribute, value ) {
|
||||
return new StateSet.AttributePair( attribute, value );
|
||||
},
|
||||
|
||||
addUniform: function ( uniform, originalMode ) {
|
||||
var mode = originalMode !== undefined ? originalMode : StateAttribute.ON;
|
||||
var name = uniform.getName();
|
||||
this.uniforms[ name ] = this.getAttributePair( uniform, mode );
|
||||
this.uniforms.dirty();
|
||||
},
|
||||
|
||||
addParent: function ( node ) {
|
||||
this._parents.push( node );
|
||||
},
|
||||
|
||||
removeParent: function ( node ) {
|
||||
var idx = this._parents.indexOf( node );
|
||||
if ( idx === -1 ) return;
|
||||
this._parents.splice( idx, 1 );
|
||||
},
|
||||
|
||||
removeUniform: function ( uniform ) {
|
||||
this.uniforms.remove( uniform.getName() );
|
||||
},
|
||||
|
||||
removeUniformByName: function ( uniformName ) {
|
||||
this.uniforms.remove( uniformName );
|
||||
},
|
||||
|
||||
getUniform: function ( uniform ) {
|
||||
var uniformMap = this.uniforms;
|
||||
if ( uniformMap[ uniform ] ) return uniformMap[ uniform ].getAttribute();
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getUniformList: function () {
|
||||
return this.uniforms;
|
||||
},
|
||||
|
||||
setTextureAttributeAndModes: function ( unit, attribute, originalMode ) {
|
||||
var mode = originalMode !== undefined ? originalMode : StateAttribute.ON;
|
||||
this._setTextureAttribute( unit, this.getAttributePair( attribute, mode ) );
|
||||
},
|
||||
|
||||
setTextureAttributeAndMode: function ( unit, attribute, mode ) {
|
||||
Notify.log( 'StateSet.setTextureAttributeAndMode is deprecated, insteady use setTextureAttributeAndModes' );
|
||||
this.setTextureAttributeAndModes( unit, attribute, mode );
|
||||
},
|
||||
|
||||
getNumTextureAttributeLists: function () {
|
||||
return this.textureAttributeMapList.length;
|
||||
},
|
||||
|
||||
getTextureAttribute: function ( unit, attribute ) {
|
||||
if ( this.textureAttributeMapList[ unit ] === undefined ) return undefined;
|
||||
|
||||
var textureMap = this.textureAttributeMapList[ unit ];
|
||||
if ( textureMap[ attribute ] === undefined ) return undefined;
|
||||
|
||||
return textureMap[ attribute ].getAttribute();
|
||||
},
|
||||
|
||||
removeTextureAttribute: function ( unit, attributeName ) {
|
||||
if ( this.textureAttributeMapList[ unit ] === undefined ) return;
|
||||
|
||||
var textureAttributeMap = this.textureAttributeMapList[ unit ];
|
||||
if ( textureAttributeMap[ attributeName ] === undefined ) return;
|
||||
|
||||
|
||||
textureAttributeMap.remove( attributeName );
|
||||
this.textureAttributeMapList[ unit ].dirty();
|
||||
},
|
||||
|
||||
getAttribute: function ( attributeType ) {
|
||||
if ( this.attributeMap[ attributeType ] === undefined ) {
|
||||
return undefined;
|
||||
}
|
||||
return this.attributeMap[ attributeType ].getAttribute();
|
||||
},
|
||||
|
||||
setAttributeAndModes: function ( attribute, originalMode ) {
|
||||
var mode = originalMode !== undefined ? originalMode : StateAttribute.ON;
|
||||
this._setAttribute( this.getAttributePair( attribute, mode ) );
|
||||
},
|
||||
|
||||
setAttributeAndMode: function ( attribute, mode ) {
|
||||
Notify.log( 'StateSet.setAttributeAndMode is deprecated, insteady use setAttributeAndModes' );
|
||||
this.setAttributeAndModes( attribute, mode );
|
||||
},
|
||||
|
||||
setAttribute: function ( attribute, originalMode ) {
|
||||
var mode = originalMode !== undefined ? originalMode : StateAttribute.ON;
|
||||
this._setAttribute( this.getAttributePair( attribute, mode ) );
|
||||
},
|
||||
|
||||
// TODO: check if it's an attribute type or a attribute to remove it
|
||||
removeAttribute: function ( attributeName ) {
|
||||
|
||||
if ( this.attributeMap[ attributeName ] !== undefined ) {
|
||||
delete this.attributeMap[ attributeName ];
|
||||
this.attributeMap.dirty();
|
||||
}
|
||||
},
|
||||
|
||||
setRenderingHint: function ( hint ) {
|
||||
if ( hint === 'OPAQUE_BIN' ) {
|
||||
this.setRenderBinDetails( 0, 'RenderBin' );
|
||||
} else if ( hint === 'TRANSPARENT_BIN' ) {
|
||||
this.setRenderBinDetails( 10, 'DepthSortedBin' );
|
||||
} else {
|
||||
this.setRenderBinDetails( 0, '' );
|
||||
}
|
||||
},
|
||||
|
||||
getUpdateCallbackList: function () {
|
||||
return this._updateCallbackList;
|
||||
},
|
||||
|
||||
removeUpdateCallback: function ( cb ) {
|
||||
var idx = this._updateCallbackList.indexOf( cb );
|
||||
if ( idx === -1 ) return;
|
||||
this._updateCallbackList.splice( idx, 1 );
|
||||
|
||||
if ( this._updateCallbackList.length === 0 ) {
|
||||
var parents = this._parents;
|
||||
for ( var i = 0, l = parents.length; i < l; i++ ) {
|
||||
var parent = parents[ i ];
|
||||
parent.setNumChildrenRequiringUpdateTraversal( parent.getNumChildrenRequiringUpdateTraversal() - 1 );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
requiresUpdateTraversal: function () {
|
||||
return !!this._updateCallbackList.length;
|
||||
},
|
||||
|
||||
addUpdateCallback: function ( cb ) {
|
||||
|
||||
var dontNoticeParents = Boolean( this._updateCallbackList.length );
|
||||
this._updateCallbackList.push( cb );
|
||||
|
||||
// parent alreay know we have update callback
|
||||
if ( dontNoticeParents ) return;
|
||||
|
||||
var parents = this._parents;
|
||||
for ( var i = 0, l = parents.length; i < l; i++ ) {
|
||||
var parent = parents[ i ];
|
||||
parent.setNumChildrenRequiringUpdateTraversal( parent.getNumChildrenRequiringUpdateTraversal() + 1 );
|
||||
}
|
||||
},
|
||||
|
||||
hasUpdateCallback: function ( cb ) {
|
||||
return this._updateCallbackList.indexOf( cb ) !== -1;
|
||||
},
|
||||
|
||||
setRenderBinDetails: function ( num, binName ) {
|
||||
this._binNumber = num;
|
||||
this._binName = binName;
|
||||
},
|
||||
getAttributeMap: function () {
|
||||
return this.attributeMap;
|
||||
},
|
||||
getBinNumber: function () {
|
||||
return this._binNumber;
|
||||
},
|
||||
getBinName: function () {
|
||||
return this._binName;
|
||||
},
|
||||
setBinNumber: function ( binNum ) {
|
||||
this._binNumber = binNum;
|
||||
},
|
||||
setBinName: function ( binName ) {
|
||||
this._binName = binName;
|
||||
},
|
||||
getAttributeList: function () {
|
||||
var attributeMap = this.attributeMap;
|
||||
var attributeMapKeys = attributeMap.getKeys();
|
||||
|
||||
var l = attributeMapKeys.length;
|
||||
var list = [];
|
||||
for ( var i = 0; i < l; i++ ) {
|
||||
list.push( attributeMap[ attributeMapKeys[ i ] ] );
|
||||
}
|
||||
return list;
|
||||
},
|
||||
setShaderGeneratorName: function ( generatorName, mask ) {
|
||||
this._shaderGeneratorPair = this.getAttributePair( generatorName, mask );
|
||||
},
|
||||
getShaderGeneratorPair: function () {
|
||||
return this._shaderGeneratorPair;
|
||||
},
|
||||
getShaderGeneratorName: function () {
|
||||
return this._shaderGeneratorPair ? this._shaderGeneratorPair.getShaderGeneratorName() : undefined;
|
||||
},
|
||||
releaseGLObjects: function () {
|
||||
for ( var i = 0, j = this.textureAttributeMapList.length; i < j; i++ ) {
|
||||
this.getTextureAttribute( i, 'Texture' ).releaseGLObjects();
|
||||
}
|
||||
var list = this.getAttributeList();
|
||||
for ( i = 0, j = list.length; i < j; i++ ) {
|
||||
// Remove only if we have releaseGLObject method.
|
||||
if ( list[ i ]._object.releaseGLObjects ) {
|
||||
list[ i ]._object.releaseGLObjects();
|
||||
}
|
||||
}
|
||||
},
|
||||
_getUniformMap: function () {
|
||||
return this.uniforms;
|
||||
},
|
||||
|
||||
// for internal use, you should not call it directly
|
||||
_setTextureAttribute: function ( unit, attributePair ) {
|
||||
|
||||
if ( this.textureAttributeMapList[ unit ] === undefined ) {
|
||||
this.textureAttributeMapList[ unit ] = new Map();
|
||||
}
|
||||
|
||||
var name = attributePair.getAttribute().getTypeMember();
|
||||
var textureUnitAttributeMap = this.textureAttributeMapList[ unit ];
|
||||
|
||||
textureUnitAttributeMap[ name ] = attributePair;
|
||||
textureUnitAttributeMap.dirty();
|
||||
|
||||
},
|
||||
|
||||
// for internal use, you should not call it directly
|
||||
_setAttribute: function ( attributePair ) {
|
||||
|
||||
var name = attributePair.getAttribute().getTypeMember();
|
||||
this.attributeMap[ name ] = attributePair;
|
||||
this.attributeMap.dirty();
|
||||
|
||||
}
|
||||
|
||||
} ), 'osg', 'StateSet' );
|
||||
|
||||
module.exports = StateSet;
|
|
@ -1,761 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var Uniform = require( 'osg/Uniform' );
|
||||
var Image = require( 'osg/Image' );
|
||||
var GLObject = require( 'osg/GLObject' );
|
||||
var ReaderParser = require( 'osgDB/readerParser' );
|
||||
var CustomMap = require( 'osg/Map' );
|
||||
var TextureManager = require( 'osg/TextureManager' );
|
||||
var WebglCaps = require( 'osg/WebGLCaps' );
|
||||
|
||||
var ImageBitmap = window.ImageBitmap || function () {};
|
||||
|
||||
// helper
|
||||
var isPowerOf2 = function ( x ) {
|
||||
/*jshint bitwise: false */
|
||||
return ( ( x !== 0 ) && ( ( x & ( ~x + 1 ) ) === x ) );
|
||||
/*jshint bitwise: true */
|
||||
};
|
||||
|
||||
/**
|
||||
* Texture encapsulate webgl texture object
|
||||
* @class Texture
|
||||
* Not that dirty here is mainly for texture binding
|
||||
* any dirty will cause re-bind
|
||||
* hint: don't dirty a texture attached to a camera/framebuffer
|
||||
* it will end blank
|
||||
* @inherits StateAttribute
|
||||
*/
|
||||
var Texture = function () {
|
||||
|
||||
StateAttribute.call( this );
|
||||
GLObject.call( this );
|
||||
this.setDefaultParameters();
|
||||
this._dirty = true;
|
||||
this._dirtyMipmap = true;
|
||||
this._applyTexImage2DCallbacks = [];
|
||||
this._textureObject = undefined;
|
||||
|
||||
this._textureNull = true;
|
||||
};
|
||||
|
||||
var checkAndFixEnum = function ( mode, fallback ) {
|
||||
|
||||
var value = Texture[ mode ];
|
||||
|
||||
if ( value === undefined ) {
|
||||
Notify.warn( 'bad Texture enum argument ' + mode + '\n' + 'fallback to ' + fallback );
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
Texture.UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
|
||||
Texture.UNPACK_FLIP_Y_WEBGL = 0x9240;
|
||||
Texture.BROWSER_DEFAULT_WEBGL = 0x9244;
|
||||
Texture.NONE = 0x0;
|
||||
|
||||
Texture.DEPTH_COMPONENT = 0x1902;
|
||||
Texture.ALPHA = 0x1906;
|
||||
Texture.RGB = 0x1907;
|
||||
Texture.RGBA = 0x1908;
|
||||
Texture.LUMINANCE = 0x1909;
|
||||
Texture.LUMINANCE_ALPHA = 0x190A;
|
||||
|
||||
// DXT formats, from:
|
||||
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
|
||||
Texture.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
|
||||
Texture.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
|
||||
Texture.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
|
||||
Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
|
||||
|
||||
// ATC formats, from:
|
||||
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_atc/
|
||||
Texture.COMPRESSED_RGB_ATC_WEBGL = 0x8C92;
|
||||
Texture.COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93;
|
||||
Texture.COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
|
||||
|
||||
// PVR formats, from:
|
||||
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/
|
||||
Texture.COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
|
||||
Texture.COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
|
||||
Texture.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
|
||||
Texture.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
|
||||
|
||||
// ETC1 format, from:
|
||||
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/
|
||||
Texture.COMPRESSED_RGB_ETC1_WEBGL = 0x8D64;
|
||||
|
||||
// filter mode
|
||||
Texture.LINEAR = 0x2601;
|
||||
Texture.NEAREST = 0x2600;
|
||||
Texture.NEAREST_MIPMAP_NEAREST = 0x2700;
|
||||
Texture.LINEAR_MIPMAP_NEAREST = 0x2701;
|
||||
Texture.NEAREST_MIPMAP_LINEAR = 0x2702;
|
||||
Texture.LINEAR_MIPMAP_LINEAR = 0x2703;
|
||||
// filter anisotropy
|
||||
Texture.TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
|
||||
Texture.MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
|
||||
|
||||
// wrap mode
|
||||
Texture.CLAMP_TO_EDGE = 0x812F;
|
||||
Texture.REPEAT = 0x2901;
|
||||
Texture.MIRRORED_REPEAT = 0x8370;
|
||||
|
||||
// target
|
||||
Texture.TEXTURE_2D = 0x0DE1;
|
||||
Texture.TEXTURE_CUBE_MAP = 0x8513;
|
||||
Texture.TEXTURE_BINDING_CUBE_MAP = 0x8514;
|
||||
Texture.TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
|
||||
Texture.TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516;
|
||||
Texture.TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517;
|
||||
Texture.TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
|
||||
Texture.TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
|
||||
Texture.TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
|
||||
Texture.MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
|
||||
|
||||
Texture.UNSIGNED_BYTE = 0x1401;
|
||||
Texture.UNSIGNED_SHORT = 0x1403;
|
||||
Texture.UNSIGNED_SHORT_4_4_4_4 = 0x8033;
|
||||
Texture.UNSIGNED_SHORT_5_5_5_1 = 0x8034;
|
||||
Texture.UNSIGNED_SHORT_5_6_5 = 0x8363;
|
||||
Texture.FLOAT = 0x1406;
|
||||
Texture.HALF_FLOAT_OES = Texture.HALF_FLOAT = 0x8D61;
|
||||
|
||||
Texture._sTextureManager = new window.Map();
|
||||
|
||||
// Getter for textureManager
|
||||
Texture.getTextureManager = function ( gl ) {
|
||||
|
||||
if ( !Texture._sTextureManager.has( gl ) )
|
||||
Texture._sTextureManager.set( gl, new TextureManager() );
|
||||
|
||||
return Texture._sTextureManager.get( gl );
|
||||
};
|
||||
|
||||
Texture.getEnumFromString = function ( v ) {
|
||||
|
||||
var value = v;
|
||||
|
||||
if ( typeof ( value ) === 'string' )
|
||||
value = checkAndFixEnum( value, v );
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
Texture.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( GLObject.prototype, MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'Texture',
|
||||
|
||||
cloneType: function () {
|
||||
return new Texture();
|
||||
},
|
||||
|
||||
dirty: function () {
|
||||
this._dirty = true;
|
||||
},
|
||||
|
||||
isDirty: function () {
|
||||
return this._dirty;
|
||||
},
|
||||
|
||||
isTextureNull: function () {
|
||||
return this._textureNull;
|
||||
},
|
||||
|
||||
getOrCreateUniforms: function ( unit ) {
|
||||
|
||||
if ( Texture.uniforms === undefined ) {
|
||||
Texture.uniforms = [];
|
||||
}
|
||||
if ( Texture.uniforms[ unit ] === undefined ) {
|
||||
var name = this.getType() + unit;
|
||||
var uniformMap = new CustomMap();
|
||||
var uniform = Uniform.createInt1( unit, name );
|
||||
uniformMap.setMap( {
|
||||
texture: uniform
|
||||
} );
|
||||
|
||||
Texture.uniforms[ unit ] = uniformMap;
|
||||
}
|
||||
|
||||
// uniform for an texture attribute should directly in Texture.uniforms[unit]
|
||||
// and not in Texture.uniforms[unit][Texture0]
|
||||
|
||||
// Why it's in Texture.uniforms[unit]['texture'] :
|
||||
// a 'texture' is a texture attribute but you also have old texenv
|
||||
// that are texture attribute because they are applied on a texture unit.
|
||||
// I admit that currently we dont have this or we used to but we dont have it anymore.
|
||||
// It's the same design than osg.
|
||||
// We could imagine for example a TextureGreyScale texture attributes,
|
||||
// that would transform the input texture
|
||||
// on unit X into greyscale used in the shader.
|
||||
|
||||
return Texture.uniforms[ unit ];
|
||||
},
|
||||
|
||||
setDefaultParameters: function () {
|
||||
this._image = undefined;
|
||||
this._magFilter = Texture.LINEAR;
|
||||
this._minFilter = Texture.LINEAR;
|
||||
this._maxAnisotropy = 1.0;
|
||||
this._wrapS = Texture.CLAMP_TO_EDGE;
|
||||
this._wrapT = Texture.CLAMP_TO_EDGE;
|
||||
this._textureWidth = 0;
|
||||
this._textureHeight = 0;
|
||||
this._unrefImageDataAfterApply = false;
|
||||
this._internalFormat = undefined;
|
||||
this._dirtyMipmap = true;
|
||||
this._textureTarget = Texture.TEXTURE_2D;
|
||||
this._type = Texture.UNSIGNED_BYTE;
|
||||
this._isCompressed = false;
|
||||
|
||||
this._flipY = true;
|
||||
this._colorSpaceConversion = Texture.NONE; //Texture.BROWSER_DEFAULT_WEBGL;
|
||||
},
|
||||
|
||||
// check https://www.khronos.org/registry/webgl/specs/latest/1.0/#PIXEL_STORAGE_PARAMETERS
|
||||
setColorSpaceConversion: function ( enumValue ) {
|
||||
this._colorSpaceConversion = enumValue;
|
||||
},
|
||||
|
||||
setFlipY: function ( bool ) {
|
||||
this._flipY = bool;
|
||||
},
|
||||
|
||||
|
||||
getTextureTarget: function () {
|
||||
return this._textureTarget;
|
||||
},
|
||||
|
||||
getTextureObject: function () {
|
||||
return this._textureObject;
|
||||
},
|
||||
|
||||
setTextureSize: function ( w, h ) {
|
||||
|
||||
var maxSize = WebglCaps.instance().getWebGLParameter( 'MAX_TEXTURE_SIZE' );
|
||||
|
||||
if ( w !== this._textureWidth || h !== this._textureHeight )
|
||||
this.dirty();
|
||||
|
||||
if ( w !== undefined ) {
|
||||
if ( w > maxSize ) {
|
||||
Notify.error( 'width (' + w + ') too big for GPU. Max Texture Size is "' + maxSize + '"' );
|
||||
this._textureWidth = maxSize;
|
||||
} else {
|
||||
this._textureWidth = w;
|
||||
}
|
||||
}
|
||||
|
||||
if ( h !== undefined ) {
|
||||
if ( h > maxSize ) {
|
||||
Notify.error( 'height (' + h + ') too big for GPU. Max Texture Size is "' + maxSize + '"' );
|
||||
this._textureHeight = maxSize;
|
||||
} else {
|
||||
this._textureHeight = h;
|
||||
}
|
||||
}
|
||||
|
||||
this._textureNull = false;
|
||||
},
|
||||
|
||||
init: function ( state ) {
|
||||
|
||||
if ( !this._gl ) this.setGraphicContext( state.getGraphicContext() );
|
||||
|
||||
if ( !this._textureObject ) {
|
||||
this._textureObject = Texture.getTextureManager( this._gl ).generateTextureObject( this._gl,
|
||||
this,
|
||||
this._textureTarget,
|
||||
this._internalFormat,
|
||||
this._textureWidth,
|
||||
this._textureHeight );
|
||||
|
||||
this.dirty();
|
||||
this._dirtyTextureObject = false;
|
||||
this._textureNull = false;
|
||||
}
|
||||
},
|
||||
|
||||
addApplyTexImage2DCallback: function ( callback ) {
|
||||
|
||||
var index = this._applyTexImage2DCallbacks.indexOf( callback );
|
||||
if ( index < 0 ) {
|
||||
this._applyTexImage2DCallbacks.push( callback );
|
||||
}
|
||||
},
|
||||
|
||||
removeApplyTexImage2DCallback: function ( callback ) {
|
||||
|
||||
var index = this._applyTexImage2DCallbacks.indexOf( callback );
|
||||
if ( index >= 0 ) {
|
||||
this._applyTexImage2DCallbacks.splice( index, 1 );
|
||||
}
|
||||
},
|
||||
|
||||
getWidth: function () {
|
||||
return this._textureWidth;
|
||||
},
|
||||
|
||||
getHeight: function () {
|
||||
return this._textureHeight;
|
||||
},
|
||||
|
||||
releaseGLObjects: function () {
|
||||
|
||||
if ( this._textureObject !== undefined && this._textureObject !== null && this._gl !== undefined ) {
|
||||
Texture.getTextureManager( this._gl ).releaseTextureObject( this._textureObject );
|
||||
}
|
||||
this._textureObject = undefined;
|
||||
},
|
||||
|
||||
getWrapT: function () {
|
||||
return this._wrapT;
|
||||
},
|
||||
|
||||
getWrapS: function () {
|
||||
return this._wrapS;
|
||||
},
|
||||
|
||||
setWrapS: function ( value ) {
|
||||
|
||||
if ( typeof value === 'string' ) {
|
||||
this._wrapS = checkAndFixEnum( value, Texture.CLAMP_TO_EDGE );
|
||||
} else {
|
||||
this._wrapS = value;
|
||||
}
|
||||
|
||||
this.dirtyTextureParameters();
|
||||
|
||||
},
|
||||
|
||||
setWrapT: function ( value ) {
|
||||
|
||||
if ( typeof value === 'string' ) {
|
||||
this._wrapT = checkAndFixEnum( value, Texture.CLAMP_TO_EDGE );
|
||||
} else {
|
||||
this._wrapT = value;
|
||||
}
|
||||
|
||||
this.dirtyTextureParameters();
|
||||
},
|
||||
|
||||
// TODO CP:
|
||||
// we should split dirty texture object of parameters
|
||||
// dirty parameters only regenarate parameter
|
||||
// dirty texture object needs to release a texture and
|
||||
// re allocate one
|
||||
dirtyTextureParameters: function () {
|
||||
this.dirty(); // make everything dirty for now
|
||||
this.dirtyMipmap();
|
||||
this.dirtyTextureObject();
|
||||
},
|
||||
|
||||
dirtyTextureObject: function () {
|
||||
this._dirtyTextureObject = true;
|
||||
this.dirtyMipmap();
|
||||
this.dirty(); // make everything dirty for now
|
||||
},
|
||||
|
||||
|
||||
getMinFilter: function () {
|
||||
return this._minFilter;
|
||||
},
|
||||
|
||||
getMagFilter: function () {
|
||||
return this._magFilter;
|
||||
},
|
||||
|
||||
// https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
|
||||
setMaxAnisotropy: function ( multiplier ) {
|
||||
this._maxAnisotropy = multiplier;
|
||||
this.dirtyTextureParameters();
|
||||
},
|
||||
|
||||
getMaxAnisotropy: function () {
|
||||
return this._maxAnisotropy;
|
||||
},
|
||||
|
||||
// some value enable mipmapping
|
||||
setMinFilter: function ( value ) {
|
||||
|
||||
if ( typeof ( value ) === 'string' ) {
|
||||
this._minFilter = checkAndFixEnum( value, Texture.LINEAR );
|
||||
} else {
|
||||
this._minFilter = value;
|
||||
}
|
||||
|
||||
this.dirtyTextureParameters();
|
||||
},
|
||||
|
||||
// Either Linear or nearest.
|
||||
setMagFilter: function ( value ) {
|
||||
|
||||
if ( typeof ( value ) === 'string' ) {
|
||||
this._magFilter = checkAndFixEnum( value, Texture.LINEAR );
|
||||
} else {
|
||||
this._magFilter = value;
|
||||
}
|
||||
|
||||
this.dirtyTextureParameters();
|
||||
},
|
||||
|
||||
setImage: function ( img, imageFormat ) {
|
||||
|
||||
var image = img;
|
||||
if ( img instanceof window.Image ||
|
||||
img instanceof HTMLCanvasElement ||
|
||||
img instanceof ImageBitmap ||
|
||||
img instanceof Uint8Array ) {
|
||||
image = new Image( img );
|
||||
}
|
||||
|
||||
this._image = image;
|
||||
this.setImageFormat( imageFormat );
|
||||
if ( image ) {
|
||||
if ( image.getWidth && image.getHeight ) {
|
||||
this.setTextureSize( image.getWidth(), image.getHeight() );
|
||||
} else if ( image.width && image.height ) {
|
||||
this.setTextureSize( image.width, image.height );
|
||||
}
|
||||
}
|
||||
this._textureNull = false;
|
||||
this.dirty();
|
||||
},
|
||||
|
||||
getImage: function () {
|
||||
return this._image;
|
||||
},
|
||||
|
||||
setImageFormat: function ( format ) {
|
||||
|
||||
var imageFormat = format;
|
||||
if ( imageFormat ) {
|
||||
|
||||
if ( typeof imageFormat === 'string' )
|
||||
imageFormat = Texture[ imageFormat ];
|
||||
|
||||
this._imageFormat = imageFormat;
|
||||
} else {
|
||||
this._imageFormat = Texture.RGBA;
|
||||
}
|
||||
},
|
||||
|
||||
setType: function ( value ) {
|
||||
Notify.log( 'Texture.setType is deprecated, use instead Texture.setInternalFormatType' );
|
||||
this.setInternalFormatType( value );
|
||||
},
|
||||
|
||||
setInternalFormatType: function ( value ) {
|
||||
|
||||
if ( typeof value === 'string' ) {
|
||||
this._type = Texture[ value ];
|
||||
} else {
|
||||
this._type = value;
|
||||
}
|
||||
},
|
||||
|
||||
getInternalFormatType: function () {
|
||||
return this._type;
|
||||
},
|
||||
|
||||
setUnrefImageDataAfterApply: function ( bool ) {
|
||||
this._unrefImageDataAfterApply = bool;
|
||||
},
|
||||
|
||||
checkIsCompressed: function ( format ) {
|
||||
|
||||
var fo = format || this._internalFormat;
|
||||
switch ( fo ) {
|
||||
case Texture.COMPRESSED_RGB_S3TC_DXT1_EXT:
|
||||
case Texture.COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
||||
case Texture.COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
case Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
case Texture.COMPRESSED_RGB_ATC_WEBGL:
|
||||
case Texture.COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL:
|
||||
case Texture.COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL:
|
||||
case Texture.COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
|
||||
case Texture.COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
|
||||
case Texture.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
|
||||
case Texture.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
|
||||
case Texture.COMPRESSED_RGB_ETC1_WEBGL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
setInternalFormat: function ( formatSource ) {
|
||||
|
||||
var format = formatSource;
|
||||
if ( format ) {
|
||||
|
||||
if ( typeof format === 'string' )
|
||||
format = Texture[ format ];
|
||||
|
||||
this._isCompressed = this.checkIsCompressed( format );
|
||||
|
||||
} else {
|
||||
this._isCompressed = false;
|
||||
format = Texture.RGBA;
|
||||
}
|
||||
|
||||
this._internalFormat = format;
|
||||
},
|
||||
|
||||
getInternalFormat: function () {
|
||||
return this._internalFormat;
|
||||
},
|
||||
|
||||
isDirtyMipmap: function () {
|
||||
return this._dirtyMipmap;
|
||||
},
|
||||
|
||||
// Will cause the mipmaps to be regenerated on the next bind of the texture
|
||||
// Nothing will be done if the minFilter is not of the form XXX_MIPMAP_XXX
|
||||
// TODO : not to be used if the texture is compressed !
|
||||
dirtyMipmap: function () {
|
||||
this._dirtyMipmap = true;
|
||||
},
|
||||
|
||||
applyFilterParameter: function ( gl, target ) {
|
||||
|
||||
var powerOfTwo = isPowerOf2( this._textureWidth ) && isPowerOf2( this._textureHeight );
|
||||
if ( !powerOfTwo ) {
|
||||
// NPOT non support in webGL explained here
|
||||
// https://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Non-Power_of_Two_Texture_Support
|
||||
// so disabling mipmap...
|
||||
this._wrapT = Texture.CLAMP_TO_EDGE;
|
||||
this._wrapS = Texture.CLAMP_TO_EDGE;
|
||||
|
||||
if ( this._minFilter === Texture.LINEAR_MIPMAP_LINEAR ||
|
||||
this._minFilter === Texture.LINEAR_MIPMAP_NEAREST ) {
|
||||
this._minFilter = Texture.LINEAR;
|
||||
}
|
||||
}
|
||||
gl.texParameteri( target, gl.TEXTURE_MAG_FILTER, this._magFilter );
|
||||
gl.texParameteri( target, gl.TEXTURE_MIN_FILTER, this._minFilter );
|
||||
|
||||
|
||||
// handle extension EXT_texture_filter_anisotropic
|
||||
if ( this._maxAnisotropy > 1.0 && Texture.ANISOTROPIC_SUPPORT_EXT ) {
|
||||
var multiplier = this._maxAnisotropy < Texture.ANISOTROPIC_SUPPORT_MAX ? this._maxAnisotropy : Texture.ANISOTROPIC_SUPPORT_MAX;
|
||||
gl.texParameterf( target, Texture.TEXTURE_MAX_ANISOTROPY_EXT, multiplier );
|
||||
}
|
||||
|
||||
gl.texParameteri( target, gl.TEXTURE_WRAP_S, this._wrapS );
|
||||
gl.texParameteri( target, gl.TEXTURE_WRAP_T, this._wrapT );
|
||||
|
||||
},
|
||||
|
||||
generateMipmap: function ( gl, target ) {
|
||||
|
||||
this._dirtyMipmap = false;
|
||||
if ( !this.hasMipmapFilter() ) return;
|
||||
|
||||
// manual mipmap provided
|
||||
var img = this._image;
|
||||
if ( img && img.hasMipmap() ) {
|
||||
|
||||
var internalFormat = this._internalFormat;
|
||||
var mips = img.getMipmap();
|
||||
for ( var level = 1, nbLevel = mips.length; level < nbLevel; level++ ) {
|
||||
var imi = mips[ level ];
|
||||
if ( this._isCompressed )
|
||||
this.applyTexImage2D( gl, this._textureTarget, level, this._internalFormat, imi.getWidth(), imi.getHeight(), 0, imi.getImage() );
|
||||
else
|
||||
this.applyTexImage2D( gl, this._textureTarget, level, internalFormat, imi.getWidth(), imi.getHeight(), 0, internalFormat, this._type, imi.getImage() );
|
||||
}
|
||||
|
||||
} else {
|
||||
// automatic mipmap
|
||||
gl.generateMipmap( target );
|
||||
}
|
||||
},
|
||||
|
||||
// return true if contains a mipmap filter
|
||||
hasMipmapFilter: function () {
|
||||
|
||||
return this._minFilter === Texture.NEAREST_MIPMAP_NEAREST ||
|
||||
this._minFilter === Texture.LINEAR_MIPMAP_NEAREST ||
|
||||
this._minFilter === Texture.NEAREST_MIPMAP_LINEAR ||
|
||||
this._minFilter === Texture.LINEAR_MIPMAP_LINEAR;
|
||||
},
|
||||
|
||||
applyTexImage2D: function ( gl ) {
|
||||
|
||||
var args = Array.prototype.slice.call( arguments, 1 );
|
||||
MACROUTILS.timeStamp( 'osgjs.metrics:Texture.texImage2d' );
|
||||
|
||||
// use parameters of pixel store
|
||||
gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, this._flipY );
|
||||
gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, this._colorSpaceConversion );
|
||||
|
||||
if ( this._isCompressed ) gl.compressedTexImage2D.apply( gl, args );
|
||||
else gl.texImage2D.apply( gl, args );
|
||||
|
||||
// call a callback when upload is done if there is one
|
||||
var numCallback = this._applyTexImage2DCallbacks.length;
|
||||
if ( numCallback > 0 ) {
|
||||
for ( var i = 0, l = numCallback; i < l; i++ ) {
|
||||
this._applyTexImage2DCallbacks[ i ].call( this );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computeTextureFormat: function () {
|
||||
|
||||
if ( !this._internalFormat ) {
|
||||
this._internalFormat = this._imageFormat || Texture.RGBA;
|
||||
this._imageFormat = this._internalFormat;
|
||||
} else {
|
||||
this._imageFormat = this._internalFormat;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
applyImage: function ( gl, image ) {
|
||||
|
||||
if ( this._isCompressed ) {
|
||||
this.applyTexImage2D( gl, this._textureTarget, 0, this._internalFormat, this._textureWidth, this._textureHeight, 0, image.getImage() );
|
||||
} else if ( image.isTypedArray() ) {
|
||||
this.applyTexImage2D( gl,
|
||||
this._textureTarget,
|
||||
0,
|
||||
this._internalFormat,
|
||||
this._textureWidth,
|
||||
this._textureHeight,
|
||||
0,
|
||||
this._internalFormat,
|
||||
this._type,
|
||||
this._image.getImage() );
|
||||
} else {
|
||||
this.applyTexImage2D( gl,
|
||||
this._textureTarget,
|
||||
0,
|
||||
this._internalFormat,
|
||||
this._internalFormat,
|
||||
this._type,
|
||||
image.getImage() );
|
||||
}
|
||||
image.setDirty( false );
|
||||
|
||||
},
|
||||
|
||||
apply: function ( state ) {
|
||||
|
||||
var gl = state.getGraphicContext();
|
||||
// if need to release the texture
|
||||
if ( this._dirtyTextureObject ) {
|
||||
this.releaseGLObjects();
|
||||
this._dirtyTextureObject = false;
|
||||
}
|
||||
|
||||
if ( this._textureObject !== undefined && !this.isDirty() ) {
|
||||
this._textureObject.bind( gl );
|
||||
// If we have modified the texture via Rtt or texSubImage2D and _need_ updated mipmaps,
|
||||
// then we must regenerate the mipmaps explicitely.
|
||||
// In all other cases, don't set this flag because it can be costly
|
||||
if ( this.isDirtyMipmap() ) {
|
||||
this.generateMipmap( gl, this._textureTarget );
|
||||
}
|
||||
|
||||
// image update like video
|
||||
if ( this._image !== undefined && this._image.isDirty() ) {
|
||||
this.applyImage( gl, this._image );
|
||||
}
|
||||
|
||||
} else if ( this._textureNull ) {
|
||||
|
||||
gl.bindTexture( this._textureTarget, null );
|
||||
|
||||
} else {
|
||||
|
||||
var image = this._image;
|
||||
if ( image !== undefined ) {
|
||||
|
||||
// when data is ready we will upload it to the gpu
|
||||
if ( image.isReady() ) {
|
||||
|
||||
// must be called before init
|
||||
this.computeTextureFormat();
|
||||
|
||||
var imgWidth = image.getWidth() || this._textureWidth;
|
||||
var imgHeight = image.getHeight() || this._textureHeight;
|
||||
|
||||
this.setTextureSize( imgWidth, imgHeight );
|
||||
|
||||
if ( !this._textureObject ) {
|
||||
this.init( state );
|
||||
}
|
||||
|
||||
this._textureObject.bind( gl );
|
||||
|
||||
this.applyImage( gl, this._image );
|
||||
this.applyFilterParameter( gl, this._textureTarget );
|
||||
this.generateMipmap( gl, this._textureTarget );
|
||||
|
||||
if ( this._unrefImageDataAfterApply ) {
|
||||
this._image = undefined;
|
||||
}
|
||||
|
||||
this._dirty = false;
|
||||
|
||||
} else {
|
||||
gl.bindTexture( this._textureTarget, null );
|
||||
}
|
||||
|
||||
} else if ( this._textureHeight !== 0 && this._textureWidth !== 0 ) {
|
||||
|
||||
// must be called before init
|
||||
this.computeTextureFormat();
|
||||
|
||||
if ( !this._textureObject ) {
|
||||
this.init( state );
|
||||
}
|
||||
this._textureObject.bind( gl );
|
||||
this.applyTexImage2D( gl, this._textureTarget, 0, this._internalFormat, this._textureWidth, this._textureHeight, 0, this._internalFormat, this._type, null );
|
||||
|
||||
this.applyFilterParameter( gl, this._textureTarget );
|
||||
this.generateMipmap( gl, this._textureTarget );
|
||||
this._dirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} ) ), 'osg', 'Texture' );
|
||||
|
||||
MACROUTILS.setTypeID( Texture );
|
||||
|
||||
Texture.textureNull = new Texture();
|
||||
|
||||
Texture.createFromImage = function ( image, format ) {
|
||||
var a = new Texture();
|
||||
a.setImage( image, format );
|
||||
return a;
|
||||
};
|
||||
|
||||
Texture.createFromCanvas = function ( canvas, format ) {
|
||||
return Texture.createFromImage( canvas, format );
|
||||
};
|
||||
|
||||
Texture.create = function ( url ) {
|
||||
Notify.log( 'Texture.create is deprecated, use Texture.createFromURL instead' );
|
||||
return Texture.createFromURL( url );
|
||||
};
|
||||
|
||||
Texture.createFromURL = function ( imageSource, format ) {
|
||||
Notify.log( 'Texture.createFromURL is deprecated, use instead osgDB.readImageURL' );
|
||||
var texture = new Texture();
|
||||
ReaderParser.readImage( imageSource ).then( function ( img ) {
|
||||
texture.setImage( img, format );
|
||||
} );
|
||||
return texture;
|
||||
};
|
||||
|
||||
|
||||
module.exports = Texture;
|
|
@ -1,230 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Image = require( 'osg/Image' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var Texture = require( 'osg/Texture' );
|
||||
|
||||
|
||||
/**
|
||||
* TextureCubeMap
|
||||
* @class TextureCubeMap
|
||||
* @inherits Texture
|
||||
*/
|
||||
var TextureCubeMap = function () {
|
||||
|
||||
Texture.call( this );
|
||||
this._images = {};
|
||||
|
||||
// pre allocated all textures faces slots
|
||||
for ( var i = 0; i < 6; i++ ) {
|
||||
this._images[ Texture.TEXTURE_CUBE_MAP_POSITIVE_X + i ] = new Image();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** @lends TextureCubeMap.prototype */
|
||||
TextureCubeMap.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( Texture.prototype, {
|
||||
|
||||
setDefaultParameters: function () {
|
||||
Texture.prototype.setDefaultParameters.call( this );
|
||||
this._textureTarget = Texture.TEXTURE_CUBE_MAP;
|
||||
|
||||
this._flipY = false;
|
||||
},
|
||||
|
||||
cloneType: function () {
|
||||
return new TextureCubeMap();
|
||||
},
|
||||
|
||||
setImage: function ( imageFace, img, imageFormat ) {
|
||||
|
||||
var face = imageFace;
|
||||
|
||||
if ( typeof face === 'string' )
|
||||
face = Texture[ face ];
|
||||
|
||||
this._images[ face ].setImage( img, imageFormat );
|
||||
|
||||
this.setImageFormat( imageFormat );
|
||||
this.setTextureSize( this._images[ face ].getWidth(), this._images[ face ].getHeight() );
|
||||
|
||||
this._textureNull = false;
|
||||
this.dirty();
|
||||
},
|
||||
|
||||
getImage: function ( face ) {
|
||||
return this._images[ face ].getImage();
|
||||
},
|
||||
|
||||
initCubemapContent: function ( gl ) {
|
||||
|
||||
var internalFormat = this._internalFormat;
|
||||
|
||||
this.applyTexImage2D( gl, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalFormat, this._textureWidth, this._textureHeight, 0, internalFormat, this._type, null );
|
||||
|
||||
this.applyTexImage2D( gl, gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalFormat, this._textureWidth, this._textureHeight, 0, internalFormat, this._type, null );
|
||||
|
||||
this.applyTexImage2D( gl, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalFormat, this._textureWidth, this._textureHeight, 0, internalFormat, this._type, null );
|
||||
|
||||
this.applyTexImage2D( gl, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalFormat, this._textureWidth, this._textureHeight, 0, internalFormat, this._type, null );
|
||||
|
||||
this.applyTexImage2D( gl, gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalFormat, this._textureWidth, this._textureHeight, 0, internalFormat, this._type, null );
|
||||
|
||||
this.applyTexImage2D( gl, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalFormat, this._textureWidth, this._textureHeight, 0, internalFormat, this._type, null );
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// handle mipmap logic, if images for mipmap are provided or not
|
||||
generateMipmap: function ( gl, target ) {
|
||||
|
||||
if ( !this.hasMipmapFilter() ) return;
|
||||
|
||||
// manual mipmap provided
|
||||
if ( this._images[ Texture.TEXTURE_CUBE_MAP_POSITIVE_X ].hasMipmap() ) {
|
||||
|
||||
for ( var face = 0; face < 6; face++ ) {
|
||||
var faceImage = this._images[ Texture.TEXTURE_CUBE_MAP_POSITIVE_X + face ];
|
||||
if ( !faceImage.hasMipmap() ) {
|
||||
Notify.error( 'mipmap not set correctly for TextureCubemap' );
|
||||
}
|
||||
|
||||
var internalFormat = this._internalFormat;
|
||||
for ( var level = 1; level < faceImage.getMipmap().length; level++ ) {
|
||||
var size = faceImage.getMipmap()[ level ].getWidth();
|
||||
|
||||
this.applyTexImage2D( gl, gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, level, internalFormat, size, size, 0, internalFormat, this._type, faceImage.getMipmap()[ level ].getImage() );
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// automatic mipmap
|
||||
gl.generateMipmap( target );
|
||||
}
|
||||
|
||||
this._dirtyMipmap = false;
|
||||
},
|
||||
|
||||
applyImageTarget: function ( gl, internalFormat, target ) {
|
||||
|
||||
var faceImage = this._images[ target ];
|
||||
|
||||
if ( !faceImage.getImage() ) return 0;
|
||||
|
||||
if ( !faceImage.isReady() ) return 0;
|
||||
|
||||
if ( !faceImage.isDirty() ) return 1;
|
||||
|
||||
this.setTextureSize( faceImage.getWidth(), faceImage.getHeight() );
|
||||
|
||||
faceImage.setDirty( false );
|
||||
|
||||
if ( faceImage.isTypedArray() ) {
|
||||
this.applyTexImage2D( gl,
|
||||
target,
|
||||
0,
|
||||
internalFormat,
|
||||
this._textureWidth,
|
||||
this._textureHeight,
|
||||
0,
|
||||
internalFormat,
|
||||
this._type,
|
||||
faceImage.getImage() );
|
||||
} else {
|
||||
this.applyTexImage2D( gl,
|
||||
target,
|
||||
0,
|
||||
internalFormat,
|
||||
internalFormat,
|
||||
this._type,
|
||||
faceImage.getImage() );
|
||||
}
|
||||
|
||||
// release here only if no mipmap
|
||||
if ( this._unrefImageDataAfterApply &&
|
||||
!( this.hasMipmap() && faceImage.hasMipmap() ) ) {
|
||||
|
||||
faceImage.release();
|
||||
}
|
||||
|
||||
return 1;
|
||||
},
|
||||
|
||||
initCubemapContentImage: function ( gl ) {
|
||||
|
||||
var internalFormat = this._internalFormat;
|
||||
var valid = 0;
|
||||
valid += this.applyImageTarget( gl, internalFormat, gl.TEXTURE_CUBE_MAP_POSITIVE_X );
|
||||
valid += this.applyImageTarget( gl, internalFormat, gl.TEXTURE_CUBE_MAP_NEGATIVE_X );
|
||||
|
||||
valid += this.applyImageTarget( gl, internalFormat, gl.TEXTURE_CUBE_MAP_POSITIVE_Y );
|
||||
valid += this.applyImageTarget( gl, internalFormat, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y );
|
||||
|
||||
valid += this.applyImageTarget( gl, internalFormat, gl.TEXTURE_CUBE_MAP_POSITIVE_Z );
|
||||
valid += this.applyImageTarget( gl, internalFormat, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z );
|
||||
|
||||
if ( valid === 6 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
apply: function ( state ) {
|
||||
|
||||
var gl = state.getGraphicContext();
|
||||
// if need to release the texture
|
||||
if ( this._dirtyTextureObject )
|
||||
this.releaseGLObjects();
|
||||
|
||||
if ( this._textureObject !== undefined && !this.isDirty() ) {
|
||||
this._textureObject.bind( gl );
|
||||
|
||||
// If we have modified the texture via Rtt or texSubImage2D and _need_ updated mipmaps,
|
||||
// then we must regenerate the mipmaps explicitely.
|
||||
// In all other cases, don't set this flag because it can be costly
|
||||
if ( this.isDirtyMipmap() ) {
|
||||
this.generateMipmap( gl, this._textureTarget );
|
||||
}
|
||||
|
||||
} else if ( this._textureNull ) {
|
||||
|
||||
gl.bindTexture( this._textureTarget, null );
|
||||
|
||||
} else {
|
||||
|
||||
if ( !this._textureObject ) {
|
||||
|
||||
// must be called before init
|
||||
this.computeTextureFormat();
|
||||
|
||||
this.init( state );
|
||||
}
|
||||
this._textureObject.bind( gl );
|
||||
|
||||
var valid;
|
||||
|
||||
// no images it's must be a cubemap filled from rtt
|
||||
if ( !this._images[ Texture.TEXTURE_CUBE_MAP_POSITIVE_X ].getImage() ) {
|
||||
|
||||
valid = this.initCubemapContent( gl );
|
||||
|
||||
} else {
|
||||
|
||||
valid = this.initCubemapContentImage( gl );
|
||||
|
||||
}
|
||||
|
||||
if ( valid ) {
|
||||
this._dirty = false;
|
||||
this.applyFilterParameter( gl, this._textureTarget );
|
||||
this.generateMipmap( gl, this._textureTarget );
|
||||
}
|
||||
} // render to cubemap not yet implemented
|
||||
}
|
||||
|
||||
} ), 'osg', 'TextureCubeMap' );
|
||||
|
||||
MACROUTILS.setTypeID( TextureCubeMap );
|
||||
|
||||
module.exports = TextureCubeMap;
|
|
@ -1,272 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var Timer = require( 'osg/Timer' );
|
||||
|
||||
|
||||
var TextureProfile = function ( target, internalFormat, width, height ) {
|
||||
this._target = target;
|
||||
this._internalFormat = internalFormat;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._size = 0;
|
||||
this.computeSize();
|
||||
};
|
||||
|
||||
TextureProfile.prototype = {
|
||||
match: function ( textureProfile ) {
|
||||
return textureProfile._target === this._target &&
|
||||
textureProfile._internalFormat === this._internalFormat &&
|
||||
textureProfile._width === this._width &&
|
||||
textureProfile._height === this._height;
|
||||
},
|
||||
computeSize: function () {
|
||||
var Texture = require( 'osg/Texture' );
|
||||
|
||||
var numBitsPerTexel = 0;
|
||||
switch ( this._internalFormat ) {
|
||||
case ( 1 ):
|
||||
numBitsPerTexel = 8;
|
||||
break;
|
||||
case ( Texture.ALPHA ):
|
||||
numBitsPerTexel = 8;
|
||||
break;
|
||||
case ( Texture.LUMINANCE ):
|
||||
numBitsPerTexel = 8;
|
||||
break;
|
||||
|
||||
case ( Texture.LUMINANCE_ALPHA ):
|
||||
numBitsPerTexel = 16;
|
||||
break;
|
||||
case ( 2 ):
|
||||
numBitsPerTexel = 16;
|
||||
break;
|
||||
|
||||
case ( Texture.RGB ):
|
||||
numBitsPerTexel = 24;
|
||||
break;
|
||||
case ( 3 ):
|
||||
numBitsPerTexel = 24;
|
||||
break;
|
||||
|
||||
case ( Texture.RGBA ):
|
||||
numBitsPerTexel = 32;
|
||||
break;
|
||||
case ( 4 ):
|
||||
numBitsPerTexel = 32;
|
||||
break;
|
||||
|
||||
}
|
||||
var size = ( Math.ceil( this._width * this._height * numBitsPerTexel ) / 8.0 );
|
||||
|
||||
if ( this._target === Texture.TEXTURE_CUBE_MAP )
|
||||
size *= 6.0;
|
||||
|
||||
// add the mipmap overhead size even if not used
|
||||
size += size / 3.0;
|
||||
|
||||
this._size = size;
|
||||
},
|
||||
|
||||
getSize: function () {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
};
|
||||
TextureProfile.getHash = function () {
|
||||
var array = Array.prototype.slice.call( arguments );
|
||||
var hash = '';
|
||||
array.forEach( function ( element ) {
|
||||
hash += element;
|
||||
} );
|
||||
return hash;
|
||||
};
|
||||
|
||||
|
||||
var TextureObject = function ( texture, id, textureSet ) {
|
||||
this._texture = texture;
|
||||
this._id = id;
|
||||
this._textureSet = textureSet;
|
||||
};
|
||||
|
||||
TextureObject.prototype = {
|
||||
target: function () {
|
||||
return this._textureSet._profile._target;
|
||||
},
|
||||
id: function () {
|
||||
return this._id;
|
||||
},
|
||||
getTextureSet: function () {
|
||||
return this._textureSet;
|
||||
},
|
||||
reset: function () {
|
||||
this._textureObject = null;
|
||||
this._texture = undefined;
|
||||
},
|
||||
bind: function ( gl ) {
|
||||
gl.bindTexture( this.target(), this._id );
|
||||
}
|
||||
};
|
||||
|
||||
var TextureObjectSet = function ( profile ) {
|
||||
this._profile = profile;
|
||||
this._usedTextureObjects = [];
|
||||
this._orphanedTextureObjects = [];
|
||||
};
|
||||
|
||||
TextureObjectSet.prototype = {
|
||||
getProfile: function () {
|
||||
return this._profile;
|
||||
},
|
||||
getUsedTextureObjects: function () {
|
||||
return this._usedTextureObjects;
|
||||
},
|
||||
getOrphanedTextureObjects: function () {
|
||||
return this._orphanedTextureObjects;
|
||||
},
|
||||
|
||||
takeOrGenerate: function ( gl, texture ) {
|
||||
|
||||
var textureObject;
|
||||
if ( this._orphanedTextureObjects.length > 0 ) {
|
||||
textureObject = this.takeFromOrphans();
|
||||
textureObject._texture = texture;
|
||||
this._usedTextureObjects.push( textureObject );
|
||||
return textureObject;
|
||||
}
|
||||
|
||||
var textureID = gl.createTexture();
|
||||
textureObject = new TextureObject( texture, textureID, this );
|
||||
this._usedTextureObjects.push( textureObject );
|
||||
|
||||
return textureObject;
|
||||
},
|
||||
|
||||
// get texture object from pool
|
||||
takeFromOrphans: function () {
|
||||
|
||||
if ( this._orphanedTextureObjects.length )
|
||||
return this._orphanedTextureObjects.pop();
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
// release texture object
|
||||
orphan: function ( textureObject ) {
|
||||
var index = this._usedTextureObjects.indexOf( textureObject );
|
||||
if ( index !== -1 ) {
|
||||
this._orphanedTextureObjects.push( this._usedTextureObjects[ index ] );
|
||||
this._usedTextureObjects.splice( index, 1 );
|
||||
}
|
||||
},
|
||||
|
||||
flushDeletedTextureObjects: function ( gl, availableTime ) {
|
||||
// if no time available don't try to flush objects.
|
||||
if ( availableTime <= 0.0 ) return availableTime;
|
||||
var nbTextures = this._orphanedTextureObjects.length;
|
||||
// Should we use a maxSizeTexturePool value?
|
||||
//var size = this.getProfile().getSize();
|
||||
// We need to test if we have time to flush
|
||||
var elapsedTime = 0.0;
|
||||
var beginTime = Timer.instance().tick();
|
||||
var i;
|
||||
for ( i = 0; i < nbTextures && elapsedTime < availableTime; i++ ) {
|
||||
gl.deleteTexture( this._orphanedTextureObjects[ i ].id() );
|
||||
this._orphanedTextureObjects[ i ].reset();
|
||||
elapsedTime = Timer.instance().deltaS( beginTime, Timer.instance().tick() );
|
||||
}
|
||||
this._orphanedTextureObjects.splice( 0, i );
|
||||
return availableTime - elapsedTime;
|
||||
},
|
||||
|
||||
flushAllDeletedTextureObjects: function ( gl ) {
|
||||
var nbTextures = this._orphanedTextureObjects.length;
|
||||
var size = this.getProfile().getSize();
|
||||
for ( var i = 0, j = nbTextures; i < j; ++i ) {
|
||||
gl.deleteTexture( this._orphanedTextureObjects[ i ].id() );
|
||||
this._orphanedTextureObjects[ i ].reset();
|
||||
}
|
||||
this._orphanedTextureObjects.length = 0;
|
||||
Notify.info( 'TextureManager: released ' + nbTextures + ' with ' + ( nbTextures * size / ( 1024 * 1024 ) ) + ' MB' );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var TextureManager = function () {
|
||||
this._textureSetMap = {};
|
||||
};
|
||||
|
||||
TextureManager.prototype = {
|
||||
|
||||
generateTextureObject: function ( gl,
|
||||
texture,
|
||||
target,
|
||||
internalFormat,
|
||||
width,
|
||||
height ) {
|
||||
var hash = TextureProfile.getHash( target, internalFormat, width, height );
|
||||
|
||||
if ( this._textureSetMap[ hash ] === undefined ) {
|
||||
this._textureSetMap[ hash ] = new TextureObjectSet( new TextureProfile( target, internalFormat, width, height ) );
|
||||
}
|
||||
|
||||
var textureSet = this._textureSetMap[ hash ];
|
||||
var textureObject = textureSet.takeOrGenerate( gl, texture );
|
||||
return textureObject;
|
||||
},
|
||||
|
||||
updateStats: function ( frameNumber, rStats ) {
|
||||
var totalUsed = 0;
|
||||
var totalUnused = 0;
|
||||
window.Object.keys( this._textureSetMap ).forEach( function ( key ) {
|
||||
var profile = this._textureSetMap[ key ].getProfile();
|
||||
var size = profile.getSize();
|
||||
var nbUsed = this._textureSetMap[ key ].getUsedTextureObjects().length;
|
||||
var nbUnused = this._textureSetMap[ key ].getOrphanedTextureObjects().length;
|
||||
totalUsed += nbUsed * size;
|
||||
totalUnused += nbUnused * size;
|
||||
}, this );
|
||||
|
||||
var MB = 1024 * 1024;
|
||||
rStats( 'textureused' ).set( totalUsed / MB );
|
||||
rStats( 'texturereserved' ).set( totalUnused / MB );
|
||||
rStats( 'texturetotal' ).set( ( totalUsed + totalUnused ) / MB );
|
||||
},
|
||||
|
||||
reportStats: function () {
|
||||
var total = 0;
|
||||
window.Object.keys( this._textureSetMap ).forEach( function ( key ) {
|
||||
var profile = this._textureSetMap[ key ].getProfile();
|
||||
var size = profile.getSize() / ( 1024 * 1024 );
|
||||
var nb = this._textureSetMap[ key ].getUsedTextureObjects().length;
|
||||
size *= nb;
|
||||
total += size;
|
||||
Notify.notice( String( size ) + ' MB with ' + nb + ' texture of ' + profile._width + 'x' + profile._height + ' ' + profile._internalFormat );
|
||||
}, this );
|
||||
Notify.notice( String( total ) + ' MB in total' );
|
||||
},
|
||||
|
||||
flushAllDeletedTextureObjects: function ( gl ) {
|
||||
window.Object.keys( this._textureSetMap ).forEach( function ( key ) {
|
||||
this._textureSetMap[ key ].flushAllDeletedTextureObjects( gl );
|
||||
}, this );
|
||||
},
|
||||
|
||||
flushDeletedTextureObjects: function ( gl, availableTimeArg ) {
|
||||
var availableTime = availableTimeArg;
|
||||
var keys = window.Object.keys( this._textureSetMap );
|
||||
for ( var i = 0, j = keys.length; i < j && availableTime > 0.0; i++ ) {
|
||||
availableTime = this._textureSetMap[ keys[ i ] ].flushDeletedTextureObjects( gl, availableTime );
|
||||
}
|
||||
return availableTime;
|
||||
},
|
||||
|
||||
releaseTextureObject: function ( textureObject ) {
|
||||
if ( textureObject ) {
|
||||
var ts = textureObject.getTextureSet();
|
||||
ts.orphan( textureObject );
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = TextureManager;
|
|
@ -1,55 +0,0 @@
|
|||
// user performance if available or fallback
|
||||
|
||||
'use strict';
|
||||
var now = ( function () {
|
||||
|
||||
var w = window || global;
|
||||
|
||||
// if no window.performance
|
||||
if ( w.performance === undefined ) {
|
||||
return function () {
|
||||
return Date.now();
|
||||
};
|
||||
}
|
||||
|
||||
var fn = w.performance.now || w.performance.mozNow || w.performance.msNow || w.performance.oNow || w.performance.webkitNow ||
|
||||
function () {
|
||||
return Date.now();
|
||||
};
|
||||
return function () {
|
||||
return fn.apply( w.performance, arguments );
|
||||
};
|
||||
} )();
|
||||
|
||||
|
||||
var Timer = function () {};
|
||||
|
||||
Timer.instance = function () {
|
||||
|
||||
if ( !Timer._instance )
|
||||
Timer._instance = new Timer();
|
||||
|
||||
return Timer._instance;
|
||||
};
|
||||
|
||||
Timer.prototype = {
|
||||
|
||||
// delta in seconds
|
||||
deltaS: function ( t0, t1 ) {
|
||||
return ( t1 - t0 ) / 1000.0;
|
||||
},
|
||||
|
||||
// delta in milliseconds
|
||||
deltaM: function ( t0, t1 ) {
|
||||
return t1 - t0;
|
||||
},
|
||||
|
||||
tick: function () {
|
||||
return now();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
module.exports = Timer;
|
|
@ -1,382 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var Notify = require( 'osg/notify' );
|
||||
|
||||
/*
|
||||
use EXT_disjoint_timer_queryto time webgl calls GPU side average over multiple frames
|
||||
|
||||
If timestamp feature is not supported, we virtualize the query by splitting and adding
|
||||
dummy queries, that way it should handle both nested and interleaved queries.
|
||||
|
||||
Also, if you time the same queryID multiple time in the same frame, it will sum the different
|
||||
queries, that way you can track a particular of gl command for examples
|
||||
|
||||
*/
|
||||
|
||||
var TimerGPU = function ( gl ) {
|
||||
|
||||
this._enabled = false;
|
||||
|
||||
if ( gl ) {
|
||||
|
||||
var ext = gl.getExtension( 'EXT_disjoint_timer_query' );
|
||||
if ( !ext ) return this;
|
||||
|
||||
// https://github.com/KhronosGroup/WebGL/blob/master/sdk/tests/conformance/extensions/ext-disjoint-timer-query.html#L102
|
||||
// run the page if strange results
|
||||
// to validate you gpu/browser has correct gpu queries support
|
||||
this._hasTimeElapsed = ext.getQueryEXT( ext.TIME_ELAPSED_EXT, ext.QUERY_COUNTER_BITS_EXT ) >= 30;
|
||||
this._hasTimeStamp = ext.getQueryEXT( ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT ) >= 30;
|
||||
|
||||
if ( !this._hasTimeElapsed && !this._hasTimeStamp ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// no timestamp means not start/end absolute time
|
||||
// which means each start must be followed by a end
|
||||
// BEFORE any other start (of other queryID)
|
||||
if ( !this._hasTimeStamp ) Notify.debug( 'Warning: do not use interleaved GPU query' );
|
||||
|
||||
this._gl = gl;
|
||||
this._glTimer = ext;
|
||||
this._enabled = true;
|
||||
|
||||
}
|
||||
|
||||
this._frameAverageCount = 10;
|
||||
|
||||
this._glQueries = [];
|
||||
this._queriesByID = {};
|
||||
this._userQueries = []; // for timestamp, it's the same as _glQueries
|
||||
|
||||
// stuffs used to virtualize query (no timestamp)
|
||||
this._queryCount = 0;
|
||||
this._nbOpened = 0;
|
||||
};
|
||||
|
||||
TimerGPU.FRAME_COUNT = 0;
|
||||
|
||||
TimerGPU.instance = function ( gl ) {
|
||||
|
||||
if ( !TimerGPU._instance ) {
|
||||
TimerGPU._instance = new TimerGPU( gl );
|
||||
} else if ( gl && TimerGPU._instance.getContext() !== gl ) {
|
||||
TimerGPU._instance.setContext( gl );
|
||||
}
|
||||
return TimerGPU._instance;
|
||||
|
||||
};
|
||||
|
||||
TimerGPU.prototype = {
|
||||
|
||||
getContext: function () {
|
||||
return this._gl;
|
||||
},
|
||||
setContext: function ( gl ) {
|
||||
this._gl = gl;
|
||||
},
|
||||
setFrameAverageCount: function ( val ) {
|
||||
this._frameAverageCount = val;
|
||||
},
|
||||
|
||||
clearQueries: function () {
|
||||
var glQueries = this._glQueries;
|
||||
for ( var i = 0, nbQueries = glQueries.length; i < nbQueries; ++i ) {
|
||||
var query = glQueries[ i ];
|
||||
this._glTimer.deleteQueryEXT( query._pollingStartQuery );
|
||||
if ( query._pollingEndQuery ) this._glTimer.deleteQueryEXT( query );
|
||||
}
|
||||
|
||||
this._userQueries.length = 0;
|
||||
this._glQueries.length = 0;
|
||||
this._queriesByID = {};
|
||||
},
|
||||
|
||||
supportTimeStamp: function () {
|
||||
return this._hasTimeStamp;
|
||||
},
|
||||
|
||||
// many browser doesn't yet have
|
||||
// the marvellous gpu timers
|
||||
enable: function () {
|
||||
// enable only if we have the extension
|
||||
this._enabled = this._glTimer;
|
||||
},
|
||||
|
||||
disable: function () {
|
||||
this._enabled = false;
|
||||
},
|
||||
isEnabled: function () {
|
||||
return this._enabled;
|
||||
},
|
||||
|
||||
setCallback: function ( cb ) {
|
||||
this._callback = cb;
|
||||
},
|
||||
|
||||
createUserQuery: function ( queryID ) {
|
||||
var query;
|
||||
if ( this._hasTimeStamp ) {
|
||||
query = this.createGLQuery();
|
||||
} else {
|
||||
query = {
|
||||
_startIndex: 0,
|
||||
_endIndex: 0
|
||||
};
|
||||
}
|
||||
|
||||
query._id = queryID;
|
||||
query._frame = TimerGPU.FRAME_COUNT;
|
||||
query._isOpened = true;
|
||||
query._siblings = []; // if the query is called multiple time in the same frame
|
||||
|
||||
return query;
|
||||
},
|
||||
|
||||
createGLQuery: function () {
|
||||
var query = {};
|
||||
query._isWaiting = false; // wait typically 1 or 2 frames
|
||||
query._pollingStartQuery = undefined; // gl query object
|
||||
query._pollingEndQuery = undefined; // gl query object (timestamp only)
|
||||
query._averageTimer = 0.0; // cumulative average time
|
||||
query._resultCount = 0; // cumulative average count
|
||||
|
||||
if ( this._hasTimeStamp ) query._pollingEndQuery = this._glTimer.createQueryEXT();
|
||||
query._pollingStartQuery = this._glTimer.createQueryEXT();
|
||||
|
||||
this._glQueries.push( query );
|
||||
|
||||
return query;
|
||||
},
|
||||
|
||||
getOrCreateLastGLQuery: function () {
|
||||
var query = this._glQueries[ this._queryCount - 1 ];
|
||||
if ( query ) return query;
|
||||
|
||||
query = this._glQueries[ this._queryCount - 1 ] = this.createGLQuery();
|
||||
|
||||
return query;
|
||||
},
|
||||
|
||||
beginCurrentQuery: function () {
|
||||
if ( this._nbOpened === 0 ) return;
|
||||
|
||||
this._queryCount++;
|
||||
|
||||
var query = this.getOrCreateLastGLQuery();
|
||||
if ( !query._isWaiting ) {
|
||||
this._glTimer.beginQueryEXT( this._glTimer.TIME_ELAPSED_EXT, query._pollingStartQuery );
|
||||
}
|
||||
},
|
||||
|
||||
endCurrentQuery: function () {
|
||||
if ( this._nbOpened === 0 ) return;
|
||||
|
||||
if ( !this.getOrCreateLastGLQuery()._isWaiting ) {
|
||||
this._glTimer.endQueryEXT( this._glTimer.TIME_ELAPSED_EXT );
|
||||
}
|
||||
},
|
||||
|
||||
getAvailableQueryByID: function ( queryID ) {
|
||||
var query = this._queriesByID[ queryID ];
|
||||
if ( !query ) {
|
||||
query = this._queriesByID[ queryID ] = this.createUserQuery( queryID );
|
||||
this._userQueries.push( query );
|
||||
return query;
|
||||
}
|
||||
|
||||
if ( query._frame === TimerGPU.FRAME_COUNT ) {
|
||||
|
||||
if ( query._isOpened ) return query;
|
||||
|
||||
var siblings = query._siblings;
|
||||
for ( var i = 0, nbSiblings = siblings.length; i < nbSiblings; ++i ) {
|
||||
var qsib = siblings[ i ];
|
||||
if ( qsib._frame !== TimerGPU.FRAME_COUNT || qsib._isOpened ) {
|
||||
qsib._frame = TimerGPU.FRAME_COUNT;
|
||||
return qsib;
|
||||
}
|
||||
}
|
||||
|
||||
var newQuery = this.createUserQuery();
|
||||
siblings.push( newQuery );
|
||||
return newQuery;
|
||||
}
|
||||
|
||||
query._frame = TimerGPU.FRAME_COUNT;
|
||||
|
||||
return query;
|
||||
},
|
||||
|
||||
// start recording time if query already exist, don't recreate
|
||||
start: function ( queryID ) {
|
||||
|
||||
// If timing currently disabled or glTimer does not exist, exit early.
|
||||
if ( !this._enabled ) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var query = this.getAvailableQueryByID( queryID );
|
||||
query._isOpened = true;
|
||||
|
||||
if ( this._hasTimeStamp ) {
|
||||
|
||||
if ( !query._isWaiting ) this._glTimer.queryCounterEXT( query._pollingStartQuery, this._glTimer.TIMESTAMP_EXT );
|
||||
|
||||
} else {
|
||||
|
||||
this.endCurrentQuery();
|
||||
|
||||
this._nbOpened++;
|
||||
query._startIndex = this._queryCount;
|
||||
|
||||
this.beginCurrentQuery();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// stop query recording (if running) polls for results
|
||||
end: function ( queryID ) {
|
||||
|
||||
if ( !this._enabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var query = this.getAvailableQueryByID( queryID );
|
||||
query._isOpened = false;
|
||||
|
||||
if ( this._hasTimeStamp ) {
|
||||
|
||||
if ( !query._isWaiting ) this._glTimer.queryCounterEXT( query._pollingEndQuery, this._glTimer.TIMESTAMP_EXT );
|
||||
|
||||
} else {
|
||||
|
||||
this.endCurrentQuery();
|
||||
|
||||
query._endIndex = this._queryCount;
|
||||
this._nbOpened--;
|
||||
|
||||
this.beginCurrentQuery();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computeQueryAverageTime: function ( query ) {
|
||||
var average = 0;
|
||||
var glQueries = this._glQueries;
|
||||
|
||||
for ( var i = query._startIndex; i < query._endIndex; ++i ) {
|
||||
var glAvg = glQueries[ i ]._averageTimer;
|
||||
if ( glAvg < 0 ) return -1;
|
||||
average += glAvg;
|
||||
}
|
||||
|
||||
return average;
|
||||
},
|
||||
|
||||
computeFullAverageTime: function ( query ) {
|
||||
var average = this.computeQueryAverageTime( query );
|
||||
|
||||
if ( average < 0 ) return -1;
|
||||
|
||||
var siblings = query._siblings;
|
||||
for ( var i = 0, nbSiblings = siblings.length; i < nbSiblings; ++i ) {
|
||||
var qsib = siblings[ i ];
|
||||
if ( qsib._frame !== TimerGPU.FRAME_COUNT - 1 )
|
||||
continue;
|
||||
|
||||
var sibAvg = this.computeQueryAverageTime( qsib );
|
||||
if ( sibAvg < 0 ) return -1;
|
||||
average += sibAvg;
|
||||
}
|
||||
|
||||
return average;
|
||||
},
|
||||
|
||||
pollQueries: function () {
|
||||
|
||||
TimerGPU.FRAME_COUNT++;
|
||||
this._queryCount = 0;
|
||||
this._nbOpened = 0;
|
||||
|
||||
if ( !this._enabled || !this._callback ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var glQueries = this._glQueries;
|
||||
var nbGlQueries = glQueries.length;
|
||||
var i;
|
||||
|
||||
// all timer are corrupted, clear the queries
|
||||
var disjoint = this._gl.getParameter( this._glTimer.GPU_DISJOINT_EXT );
|
||||
if ( disjoint ) {
|
||||
for ( i = 0; i < nbGlQueries; ++i ) {
|
||||
glQueries[ i ]._isWaiting = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// update average time for each queries
|
||||
for ( i = 0; i < nbGlQueries; ++i ) {
|
||||
this.pollQuery( glQueries[ i ] );
|
||||
}
|
||||
|
||||
var userQueries = this._userQueries;
|
||||
var nbUserQueries = userQueries.length;
|
||||
|
||||
for ( i = 0; i < nbUserQueries; ++i ) {
|
||||
var query = userQueries[ i ];
|
||||
var average = this.computeFullAverageTime( query );
|
||||
if ( average > 0 ) {
|
||||
this._callback( average, query._id );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
pollQuery: function ( query ) {
|
||||
query._isWaiting = false;
|
||||
|
||||
// last to be queried
|
||||
var lastQuery = this._hasTimeStamp ? query._pollingEndQuery : query._pollingStartQuery;
|
||||
|
||||
// wait till results are ready
|
||||
var available = this._glTimer.getQueryObjectEXT( lastQuery, this._glTimer.QUERY_RESULT_AVAILABLE_EXT );
|
||||
if ( !available ) {
|
||||
query._isWaiting = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
var timeElapsed;
|
||||
|
||||
if ( this._hasTimeStamp ) {
|
||||
|
||||
var startTime = this._glTimer.getQueryObjectEXT( query._pollingStartQuery, this._glTimer.QUERY_RESULT_EXT );
|
||||
var endTime = this._glTimer.getQueryObjectEXT( lastQuery, this._glTimer.QUERY_RESULT_EXT );
|
||||
timeElapsed = endTime - startTime;
|
||||
|
||||
} else {
|
||||
|
||||
timeElapsed = this._glTimer.getQueryObjectEXT( lastQuery, this._glTimer.QUERY_RESULT_EXT );
|
||||
|
||||
}
|
||||
|
||||
query._resultCount++;
|
||||
|
||||
// restart cumulative average every frameAveragecount frames
|
||||
if ( query._resultCount > this._frameAverageCount ) {
|
||||
query._averageTimer = 0.0;
|
||||
query._resultCount = 1;
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average
|
||||
query._averageTimer = query._averageTimer + ( ( timeElapsed - query._averageTimer ) / ( query._resultCount ) );
|
||||
|
||||
return query._averageTimer;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = TimerGPU;
|
|
@ -1,43 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Node = require( 'osg/Node' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
|
||||
/**
|
||||
* Transform - base class for Transform type node ( Camera, MatrixTransform )
|
||||
* @class Transform
|
||||
* @inherits Node
|
||||
*/
|
||||
var Transform = function () {
|
||||
Node.call( this );
|
||||
this.referenceFrame = TransformEnums.RELATIVE_RF;
|
||||
};
|
||||
|
||||
/** @lends Transform.prototype */
|
||||
Transform.prototype = MACROUTILS.objectInherit( Node.prototype, {
|
||||
setReferenceFrame: function ( value ) {
|
||||
this.referenceFrame = value;
|
||||
},
|
||||
getReferenceFrame: function () {
|
||||
return this.referenceFrame;
|
||||
},
|
||||
|
||||
computeBoundingSphere: ( function () {
|
||||
var matrix = mat4.create();
|
||||
return function ( bSphere ) {
|
||||
Node.prototype.computeBoundingSphere.call( this, bSphere );
|
||||
if ( !bSphere.valid() ) {
|
||||
return bSphere;
|
||||
}
|
||||
|
||||
mat4.identity( matrix );
|
||||
// local to local world (not Global World)
|
||||
this.computeLocalToWorldMatrix( matrix );
|
||||
bSphere.transformMat4( bSphere, matrix );
|
||||
return bSphere;
|
||||
};
|
||||
} )()
|
||||
} );
|
||||
|
||||
module.exports = Transform;
|
|
@ -1,96 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var PrimitiveSet = require( 'osg/primitiveSet' );
|
||||
var DrawElements = require( 'osg/DrawElements' );
|
||||
var DrawArrays = require( 'osg/DrawArrays' );
|
||||
|
||||
// This class can be used to visit all the triangles of a geometry
|
||||
var TriangleIndexFunctor = function () {};
|
||||
|
||||
var functorDrawElements = TriangleIndexFunctor.functorDrawElements = [];
|
||||
var functorDrawArrays = TriangleIndexFunctor.functorDrawArrays = [];
|
||||
|
||||
functorDrawElements[ PrimitiveSet.TRIANGLES ] = function ( offset, count, indexes, cb ) {
|
||||
var end = offset + count;
|
||||
for ( var i = offset; i < end; i += 3 ) {
|
||||
cb( indexes[ i ], indexes[ i + 1 ], indexes[ i + 2 ] );
|
||||
}
|
||||
};
|
||||
|
||||
functorDrawElements[ PrimitiveSet.TRIANGLE_STRIP ] = function ( offset, count, indexes, cb ) {
|
||||
for ( var i = 2, j = offset; i < count; ++i, ++j ) {
|
||||
if ( i % 2 ) cb( indexes[ j ], indexes[ j + 2 ], indexes[ j + 1 ] );
|
||||
else cb( indexes[ j ], indexes[ j + 1 ], indexes[ j + 2 ] );
|
||||
}
|
||||
};
|
||||
|
||||
functorDrawElements[ PrimitiveSet.TRIANGLE_FAN ] = function ( offset, count, indexes, cb ) {
|
||||
var first = indexes[ offset ];
|
||||
for ( var i = 2, j = offset + 1; i < count; ++i, ++j ) {
|
||||
cb( first, indexes[ j ], indexes[ j + 1 ] );
|
||||
}
|
||||
};
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.TRIANGLES ] = function ( first, count, cb ) {
|
||||
for ( var i = 2, pos = first; i < count; i += 3, pos += 3 ) {
|
||||
cb( pos, pos + 1, pos + 2 );
|
||||
}
|
||||
};
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.TRIANGLE_STRIP ] = function ( first, count, cb ) {
|
||||
for ( var i = 2, pos = first; i < count; ++i, ++pos ) {
|
||||
if ( i % 2 ) cb( pos, pos + 2, pos + 1 );
|
||||
else cb( pos, pos + 1, pos + 2 );
|
||||
}
|
||||
};
|
||||
|
||||
functorDrawArrays[ PrimitiveSet.TRIANGLE_FAN ] = function ( first, count, cb ) {
|
||||
for ( var i = 2, pos = first + 1; i < count; ++i, ++pos ) {
|
||||
cb( first, pos, pos + 1 );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TriangleIndexFunctor.prototype = {
|
||||
|
||||
// You feed it with a callback that will be called for each triangle
|
||||
// (with the 3 indexes of vertices as arguments)
|
||||
init: function ( geom, cb ) {
|
||||
this._geom = geom;
|
||||
this._cb = cb;
|
||||
},
|
||||
|
||||
apply: function () {
|
||||
var geom = this._geom;
|
||||
var primitives = geom.primitives;
|
||||
if ( !primitives )
|
||||
return;
|
||||
|
||||
var cb = this._cb;
|
||||
var cbFunctor;
|
||||
|
||||
var nbPrimitives = primitives.length;
|
||||
for ( var i = 0; i < nbPrimitives; i++ ) {
|
||||
|
||||
var primitive = primitives[ i ];
|
||||
if ( primitive instanceof DrawElements ) {
|
||||
|
||||
cbFunctor = functorDrawElements[ primitive.getMode() ];
|
||||
if ( cbFunctor ) {
|
||||
var indexes = primitive.indices.getElements();
|
||||
cbFunctor( primitive.getFirst() / indexes.BYTES_PER_ELEMENT, primitive.getCount(), indexes, cb );
|
||||
}
|
||||
|
||||
} else if ( primitive instanceof DrawArrays ) {
|
||||
|
||||
cbFunctor = functorDrawArrays[ primitive.getMode() ];
|
||||
if ( cbFunctor ) {
|
||||
cbFunctor( primitive.getFirst(), primitive.getCount(), cb );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = TriangleIndexFunctor;
|
|
@ -1,277 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
|
||||
|
||||
/**
|
||||
* Uniform manage variable used in glsl shader.
|
||||
* @class Uniform
|
||||
*/
|
||||
var Uniform = function ( name ) {
|
||||
this._data = undefined;
|
||||
this._transpose = false;
|
||||
this._glCall = '';
|
||||
this._cache = undefined;
|
||||
this._name = name;
|
||||
this._type = undefined;
|
||||
this._isMatrix = false;
|
||||
};
|
||||
|
||||
Uniform.isUniform = function ( obj ) {
|
||||
if ( typeof obj === 'object' && window.Object.getPrototypeOf( obj ) === Uniform.prototype ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/** @lends Uniform.prototype */
|
||||
Uniform.prototype = {
|
||||
|
||||
getName: function () {
|
||||
return this._name;
|
||||
},
|
||||
|
||||
dirty: function () {
|
||||
Notify.log( 'deprecated dont use Uniform.dirty anymore' );
|
||||
},
|
||||
|
||||
getType: function () {
|
||||
return this._type;
|
||||
},
|
||||
|
||||
get: function () {
|
||||
Notify.log( 'deprecated use getInternalArray instead' );
|
||||
return this._data;
|
||||
},
|
||||
|
||||
set: function ( array ) {
|
||||
Notify.log( 'deprecated use setFloat/setInt instead' );
|
||||
var value = array;
|
||||
if ( !Array.isArray( value ) && value.byteLength === undefined )
|
||||
this._data[ 0 ] = value;
|
||||
else
|
||||
this._data = array;
|
||||
},
|
||||
|
||||
apply: function UniformApply( gl, location ) {
|
||||
|
||||
if ( !this._cache )
|
||||
this._cache = gl[ this._glCall ];
|
||||
|
||||
if ( this._isMatrix )
|
||||
this._cache.call( gl, location, this._transpose, this._data );
|
||||
else
|
||||
this._cache.call( gl, location, this._data );
|
||||
},
|
||||
|
||||
// no type checking, so array should be valid
|
||||
setInternalArray: function ( array ) {
|
||||
this._data = array;
|
||||
},
|
||||
|
||||
getInternalArray: function () {
|
||||
return this._data;
|
||||
},
|
||||
|
||||
setFloat: function ( f ) {
|
||||
this._data[ 0 ] = f;
|
||||
},
|
||||
|
||||
setFloat1: function ( f ) {
|
||||
this._data[ 0 ] = f[ 0 ];
|
||||
},
|
||||
|
||||
setFloat2: function ( f ) {
|
||||
this._data[ 0 ] = f[ 0 ];
|
||||
this._data[ 1 ] = f[ 1 ];
|
||||
},
|
||||
|
||||
setFloat3: function ( f ) {
|
||||
this._data[ 0 ] = f[ 0 ];
|
||||
this._data[ 1 ] = f[ 1 ];
|
||||
this._data[ 2 ] = f[ 2 ];
|
||||
},
|
||||
|
||||
setFloat4: function ( f ) {
|
||||
this._data[ 0 ] = f[ 0 ];
|
||||
this._data[ 1 ] = f[ 1 ];
|
||||
this._data[ 2 ] = f[ 2 ];
|
||||
this._data[ 3 ] = f[ 3 ];
|
||||
},
|
||||
|
||||
setFloat9: function ( f ) {
|
||||
this._data[ 0 ] = f[ 0 ];
|
||||
this._data[ 1 ] = f[ 1 ];
|
||||
this._data[ 2 ] = f[ 2 ];
|
||||
this._data[ 3 ] = f[ 3 ];
|
||||
this._data[ 4 ] = f[ 4 ];
|
||||
this._data[ 5 ] = f[ 5 ];
|
||||
this._data[ 6 ] = f[ 6 ];
|
||||
this._data[ 7 ] = f[ 7 ];
|
||||
this._data[ 8 ] = f[ 8 ];
|
||||
},
|
||||
|
||||
setFloat16: function ( f ) {
|
||||
this._data[ 0 ] = f[ 0 ];
|
||||
this._data[ 1 ] = f[ 1 ];
|
||||
this._data[ 2 ] = f[ 2 ];
|
||||
this._data[ 3 ] = f[ 3 ];
|
||||
this._data[ 4 ] = f[ 4 ];
|
||||
this._data[ 5 ] = f[ 5 ];
|
||||
this._data[ 6 ] = f[ 6 ];
|
||||
this._data[ 7 ] = f[ 7 ];
|
||||
this._data[ 8 ] = f[ 8 ];
|
||||
this._data[ 9 ] = f[ 9 ];
|
||||
this._data[ 10 ] = f[ 10 ];
|
||||
this._data[ 11 ] = f[ 11 ];
|
||||
this._data[ 12 ] = f[ 12 ];
|
||||
this._data[ 13 ] = f[ 13 ];
|
||||
this._data[ 14 ] = f[ 14 ];
|
||||
this._data[ 15 ] = f[ 15 ];
|
||||
}
|
||||
};
|
||||
Uniform.prototype.setVec2 = Uniform.prototype.setFloat2;
|
||||
Uniform.prototype.setVec3 = Uniform.prototype.setFloat3;
|
||||
Uniform.prototype.setVec4 = Uniform.prototype.setFloat4;
|
||||
Uniform.prototype.setMatrix4 = Uniform.prototype.setFloat16;
|
||||
Uniform.prototype.setMatrix3 = Uniform.prototype.setFloat9;
|
||||
Uniform.prototype.setInt = Uniform.prototype.setFloat;
|
||||
Uniform.prototype.setInt1 = Uniform.prototype.setFloat1;
|
||||
Uniform.prototype.setInt2 = Uniform.prototype.setFloat2;
|
||||
Uniform.prototype.setInt3 = Uniform.prototype.setFloat3;
|
||||
Uniform.prototype.setInt4 = Uniform.prototype.setFloat4;
|
||||
|
||||
|
||||
var createUniformX = function ( dataOrName, uniformName, defaultConstructor, glSignature, type, isMatrix ) {
|
||||
var data = uniformName === undefined ? undefined : dataOrName;
|
||||
var uniform = new Uniform( uniformName === undefined ? dataOrName : uniformName );
|
||||
|
||||
uniform._data = defaultConstructor();
|
||||
|
||||
if ( data !== undefined ) {
|
||||
if ( data.length ) {
|
||||
for ( var i = 0, nbElts = data.length; i < nbElts; ++i )
|
||||
uniform._data[ i ] = data[ i ];
|
||||
} else {
|
||||
uniform._data[ 0 ] = data;
|
||||
}
|
||||
}
|
||||
|
||||
uniform._glCall = glSignature;
|
||||
uniform._type = type;
|
||||
uniform._isMatrix = !!isMatrix;
|
||||
return uniform;
|
||||
};
|
||||
|
||||
var constructorFloat = function () {
|
||||
return new Float32Array( 1 );
|
||||
};
|
||||
|
||||
var constructorFloat2 = function () {
|
||||
return new Float32Array( 2 );
|
||||
};
|
||||
|
||||
var constructorFloat3 = function () {
|
||||
return new Float32Array( 3 );
|
||||
};
|
||||
|
||||
var constructorFloat4 = function () {
|
||||
return new Float32Array( 4 );
|
||||
};
|
||||
|
||||
var constructorInt = function () {
|
||||
return new Int32Array( 1 );
|
||||
};
|
||||
|
||||
var constructorInt2 = function () {
|
||||
return new Int32Array( 2 );
|
||||
};
|
||||
|
||||
var constructorInt3 = function () {
|
||||
return new Int32Array( 3 );
|
||||
};
|
||||
|
||||
var constructorInt4 = function () {
|
||||
return new Int32Array( 4 );
|
||||
};
|
||||
|
||||
var constructorMat2 = function () {
|
||||
var out = new Float32Array( 4 );
|
||||
out[ 0 ] = out[ 3 ] = 1.0;
|
||||
return out;
|
||||
};
|
||||
|
||||
var constructorMat3 = function () {
|
||||
var out = new Float32Array( 9 );
|
||||
out[ 0 ] = out[ 4 ] = out[ 8 ] = 1.0;
|
||||
return out;
|
||||
};
|
||||
|
||||
var constructorMat4 = function () {
|
||||
var out = new Float32Array( 16 );
|
||||
out[ 0 ] = out[ 5 ] = out[ 10 ] = out[ 15 ] = 1.0;
|
||||
return out;
|
||||
};
|
||||
|
||||
// works also for float array but data must be given
|
||||
Uniform.createFloat1 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorFloat, 'uniform1fv', 'float' );
|
||||
};
|
||||
|
||||
Uniform.createInt1 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorInt, 'uniform1iv', 'int' );
|
||||
};
|
||||
|
||||
Uniform.createFloat2 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorFloat2, 'uniform2fv', 'vec2' );
|
||||
};
|
||||
|
||||
Uniform.createInt2 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorInt2, 'uniform2iv', 'vec2i' );
|
||||
};
|
||||
|
||||
Uniform.createFloat3 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorFloat3, 'uniform3fv', 'vec3' );
|
||||
};
|
||||
|
||||
Uniform.createInt3 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorInt3, 'uniform3iv', 'vec3i' );
|
||||
};
|
||||
|
||||
Uniform.createFloat4 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorFloat4, 'uniform4fv', 'vec4' );
|
||||
};
|
||||
|
||||
Uniform.createInt4 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorInt4, 'uniform4iv', 'vec4i' );
|
||||
};
|
||||
|
||||
Uniform.createMatrix2 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorMat2, 'uniformMatrix2fv', 'mat2', true );
|
||||
};
|
||||
|
||||
Uniform.createMatrix3 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorMat3, 'uniformMatrix3fv', 'mat3', true );
|
||||
};
|
||||
|
||||
Uniform.createMatrix4 = function ( data, uniformName ) {
|
||||
return createUniformX( data, uniformName, constructorMat4, 'uniformMatrix4fv', 'mat4', true );
|
||||
};
|
||||
|
||||
// alias
|
||||
Uniform.float = Uniform.createFloatArray = Uniform.createFloat = Uniform.createFloat1;
|
||||
Uniform.int = Uniform.createIntArray = Uniform.createInt = Uniform.createInt1;
|
||||
|
||||
Uniform.vec2 = Uniform.createFloat2Array = Uniform.createFloat2;
|
||||
Uniform.vec2i = Uniform.createInt2Array = Uniform.createInt2;
|
||||
|
||||
Uniform.vec3 = Uniform.createFloat3Array = Uniform.createFloat3;
|
||||
Uniform.vec3i = Uniform.createInt3Array = Uniform.createInt3;
|
||||
|
||||
Uniform.vec4 = Uniform.createFloat4Array = Uniform.createFloat4;
|
||||
Uniform.vec4i = Uniform.createInt4Array = Uniform.createInt4;
|
||||
|
||||
Uniform.mat2 = Uniform.createMat2 = Uniform.createMatrix2;
|
||||
Uniform.mat3 = Uniform.createMat3 = Uniform.createMatrix3;
|
||||
Uniform.mat4 = Uniform.createMat4 = Uniform.createMatrix4;
|
||||
|
||||
module.exports = Uniform;
|
|
@ -1,52 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
|
||||
|
||||
var UpdateVisitor = function () {
|
||||
NodeVisitor.call( this );
|
||||
this.visitorType = NodeVisitor.UPDATE_VISITOR;
|
||||
this._numUpdateCallback = 0;
|
||||
};
|
||||
|
||||
UpdateVisitor.prototype = MACROUTILS.objectInherit( NodeVisitor.prototype, {
|
||||
|
||||
resetStats: function () {
|
||||
this._numUpdateCallback = 0;
|
||||
},
|
||||
|
||||
apply: function ( node ) {
|
||||
|
||||
// a way to avoid extra call is to implement getNumChildrenRequiringUpdateTraversal
|
||||
// and stateset.requiresUpdateTraversal()
|
||||
|
||||
|
||||
// handle callback in stateset
|
||||
var stateSet = node.getStateSet();
|
||||
if ( stateSet && stateSet.requiresUpdateTraversal() ) {
|
||||
var updateCallbackList = stateSet.getUpdateCallbackList();
|
||||
|
||||
var numStateSetUpdateCallback = updateCallbackList.length;
|
||||
if ( numStateSetUpdateCallback ) {
|
||||
this._numUpdateCallback += numStateSetUpdateCallback;
|
||||
for ( var i = 0, l = numStateSetUpdateCallback; i < l; i++ )
|
||||
updateCallbackList[ i ].update( stateSet, this );
|
||||
}
|
||||
}
|
||||
|
||||
// handle callback in nodes
|
||||
var ncs = node.getUpdateCallbackList();
|
||||
var numUpdateCallback = ncs.length;
|
||||
for ( var j = 0; j < numUpdateCallback; j++ ) {
|
||||
this._numUpdateCallback++;
|
||||
if ( !ncs[ j ].update( node, this ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( node.getNumChildrenRequiringUpdateTraversal() > 0 )
|
||||
this.traverse( node );
|
||||
}
|
||||
} );
|
||||
|
||||
module.exports = UpdateVisitor;
|
|
@ -1,210 +0,0 @@
|
|||
'use strict';
|
||||
var osgPool = require( 'osgUtil/osgPool' );
|
||||
var StateGraph = require( 'osg/StateGraph' );
|
||||
var Timer = require( 'osg/Timer' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
|
||||
// make the warning about StateGraph desappear
|
||||
window.Object.keys( StateGraph );
|
||||
|
||||
var Utils = {};
|
||||
|
||||
Utils.init = function () {
|
||||
var StateGraphClass = require( 'osg/StateGraph' );
|
||||
osgPool.memoryPools.stateGraph = new osgPool.OsgObjectMemoryPool( StateGraphClass ).grow( 50 );
|
||||
};
|
||||
|
||||
Utils.isArray = function ( obj ) {
|
||||
Notify.log( 'isArray is deprecated, use instead Array.isArray' );
|
||||
return Array.isArray( obj );
|
||||
};
|
||||
|
||||
Utils.extend = function () {
|
||||
// Save a reference to some core methods
|
||||
var toString = window.Object.prototype.toString;
|
||||
var hasOwnPropertyFunc = window.Object.prototype.hasOwnProperty;
|
||||
|
||||
var isFunction = function ( obj ) {
|
||||
return toString.call( obj ) === '[object Function]';
|
||||
};
|
||||
var isArray = Utils.isArray;
|
||||
var isPlainObject = function ( obj ) {
|
||||
// Must be an Object.
|
||||
// Because of IE, we also have to check the presence of the constructor property.
|
||||
// Make sure that DOM nodes and window objects don't pass through, as well
|
||||
if ( !obj || toString.call( obj ) !== '[object Object]' || obj.nodeType || obj.setInterval ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not own constructor property must be Object
|
||||
if ( obj.constructor && !hasOwnPropertyFunc.call( obj, 'constructor' ) && !hasOwnPropertyFunc.call( obj.constructor.prototype, 'isPrototypeOf' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Own properties are enumerated firstly, so to speed up,
|
||||
// if last one is own, then all properties are own.
|
||||
|
||||
var key;
|
||||
for ( key in obj ) {}
|
||||
|
||||
return key === undefined || hasOwnPropertyFunc.call( obj, key );
|
||||
};
|
||||
|
||||
// copy reference to target object
|
||||
var target = arguments[ 0 ] || {},
|
||||
i = 1,
|
||||
length = arguments.length,
|
||||
deep = false,
|
||||
options, name, src, copy;
|
||||
|
||||
// Handle a deep copy situation
|
||||
if ( typeof target === 'boolean' ) {
|
||||
deep = target;
|
||||
target = arguments[ 1 ] || {};
|
||||
// skip the boolean and the target
|
||||
i = 2;
|
||||
}
|
||||
|
||||
// Handle case when target is a string or something (possible in deep copy)
|
||||
if ( typeof target !== 'object' && !isFunction( target ) ) {
|
||||
target = {};
|
||||
}
|
||||
|
||||
// extend jQuery itself if only one argument is passed
|
||||
if ( length === i ) {
|
||||
target = this;
|
||||
--i;
|
||||
}
|
||||
|
||||
for ( ; i < length; i++ ) {
|
||||
// Only deal with non-null/undefined values
|
||||
if ( ( options = arguments[ i ] ) !== null ) {
|
||||
// Extend the base object
|
||||
for ( name in options ) {
|
||||
src = target[ name ];
|
||||
copy = options[ name ];
|
||||
|
||||
// Prevent never-ending loop
|
||||
if ( target === copy ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Recurse if we're merging object literal values or arrays
|
||||
if ( deep && copy && ( isPlainObject( copy ) || isArray( copy ) ) ) {
|
||||
var clone = src && ( isPlainObject( src ) || isArray( src ) ) ? src : isArray( copy ) ? [] : {};
|
||||
|
||||
// Never move original objects, clone them
|
||||
target[ name ] = Utils.extend( deep, clone, copy );
|
||||
|
||||
// Don't bring in undefined values
|
||||
} else if ( copy !== undefined ) {
|
||||
target[ name ] = copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the modified object
|
||||
return target;
|
||||
};
|
||||
|
||||
Utils.objectInherit = function ( base /*, extras*/ ) {
|
||||
function F() {}
|
||||
F.prototype = base;
|
||||
var obj = new F();
|
||||
|
||||
// let augment object with multiple arguement
|
||||
for ( var i = 1; i < arguments.length; i++ ) {
|
||||
Utils.objectMix( obj, arguments[ i ], false );
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
Utils.objectInehrit = function () {
|
||||
console.warn( 'please use objectInherit instead of objectInehrit' );
|
||||
};
|
||||
|
||||
Utils.objectMix = function ( obj, properties, test ) {
|
||||
for ( var key in properties ) {
|
||||
if ( !( test && obj[ key ] ) ) {
|
||||
obj[ key ] = properties[ key ];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
Utils.objectType = {};
|
||||
Utils.objectType.type = 0;
|
||||
Utils.objectType.generate = function ( arg ) {
|
||||
var t = Utils.objectType.type;
|
||||
Utils.objectType[ t ] = arg;
|
||||
Utils.objectType[ arg ] = t;
|
||||
Utils.objectType.type += 1;
|
||||
return t;
|
||||
};
|
||||
|
||||
Utils.objectLibraryClass = function ( object, libName, className ) {
|
||||
object.className = function () {
|
||||
return className;
|
||||
};
|
||||
object.libraryName = function () {
|
||||
return libName;
|
||||
};
|
||||
var libraryClassName = libName + '::' + className;
|
||||
object.libraryClassName = function () {
|
||||
return libraryClassName;
|
||||
};
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
Utils.setTypeID = function ( classObject ) {
|
||||
var className = classObject.prototype.libraryClassName();
|
||||
var typeID = Utils.objectType.generate( className );
|
||||
var getTypeID = function () {
|
||||
return typeID;
|
||||
};
|
||||
classObject.typeID = classObject.prototype.typeID = typeID;
|
||||
classObject.getTypeID = classObject.prototype.getTypeID = getTypeID;
|
||||
};
|
||||
|
||||
Utils.createPrototypeClass = function ( Constructor, prototype, libraryName, className ) {
|
||||
|
||||
Constructor.prototype = prototype;
|
||||
prototype.constructor = Constructor;
|
||||
|
||||
Utils.objectLibraryClass( prototype, libraryName, className );
|
||||
Utils.setTypeID( Constructor );
|
||||
};
|
||||
|
||||
Utils.Float32Array = typeof Float32Array !== 'undefined' ? Float32Array : null;
|
||||
Utils.Int32Array = typeof Int32Array !== 'undefined' ? Int32Array : null;
|
||||
Utils.Uint8Array = typeof Uint8Array !== 'undefined' ? Uint8Array : null;
|
||||
Utils.Uint16Array = typeof Uint16Array !== 'undefined' ? Uint16Array : null;
|
||||
Utils.Uint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : null;
|
||||
|
||||
var times = {};
|
||||
|
||||
// we bind the function to Notify.console once and for all to avoid costly apply function
|
||||
|
||||
Utils.time = ( Notify.console.time || function ( name ) {
|
||||
times[ name ] = Timer.instance().tick();
|
||||
} ).bind( Notify.console );
|
||||
|
||||
Utils.timeEnd = ( Notify.console.timeEnd || function ( name ) {
|
||||
|
||||
if ( times[ name ] === undefined )
|
||||
return;
|
||||
|
||||
var duration = Timer.instance().deltaM( times[ name ], Timer.instance().tick() );
|
||||
|
||||
Notify.debug( name + ': ' + duration + 'ms' );
|
||||
times[ name ] = undefined;
|
||||
|
||||
} ).bind( Notify.console );
|
||||
|
||||
Utils.timeStamp = ( Notify.console.timeStamp || Notify.console.markTimeline || function () {} ).bind( Notify.console );
|
||||
Utils.profile = ( Notify.console.profile || function () {} ).bind( Notify.console );
|
||||
Utils.profileEnd = ( Notify.console.profileEnd || function () {} ).bind( Notify.console );
|
||||
|
||||
module.exports = Utils;
|
|
@ -1 +0,0 @@
|
|||
module.exports = require( 'osg/deprecated-MatrixVector/Vec2' );
|
|
@ -1 +0,0 @@
|
|||
module.exports = require( 'osg/deprecated-MatrixVector/Vec3' );
|
|
@ -1 +0,0 @@
|
|||
module.exports = require( 'osg/deprecated-MatrixVector/Vec4' );
|
|
@ -1,69 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
|
||||
var Viewport = function ( x, y, w, h ) {
|
||||
StateAttribute.call( this );
|
||||
|
||||
this._x = x !== undefined ? x : 0;
|
||||
this._y = y !== undefined ? y : 0;
|
||||
this._width = w !== undefined ? w : 800;
|
||||
this._height = h !== undefined ? h : 600;
|
||||
};
|
||||
|
||||
Viewport.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( StateAttribute.prototype, {
|
||||
|
||||
attributeType: 'Viewport',
|
||||
|
||||
cloneType: function () {
|
||||
return new Viewport();
|
||||
},
|
||||
|
||||
apply: function ( state ) {
|
||||
var gl = state.getGraphicContext();
|
||||
gl.viewport( this._x, this._y, this._width, this._height );
|
||||
},
|
||||
|
||||
setViewport: function ( x, y, width, height ) {
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
},
|
||||
|
||||
x: function () {
|
||||
return this._x;
|
||||
},
|
||||
|
||||
y: function () {
|
||||
return this._y;
|
||||
},
|
||||
|
||||
width: function () {
|
||||
return this._width;
|
||||
},
|
||||
|
||||
height: function () {
|
||||
return this._height;
|
||||
},
|
||||
|
||||
computeWindowMatrix: ( function () {
|
||||
var translate = mat4.create();
|
||||
var scale = mat4.create();
|
||||
var unitVec = vec3.fromValues( 1.0, 1.0, 1.0 );
|
||||
return function ( destination ) {
|
||||
// res = Matrix offset * Matrix scale * Matrix translate
|
||||
mat4.fromTranslation( translate, unitVec );
|
||||
mat4.fromScaling( scale, [ 0.5 * this._width, 0.5 * this._height, 0.5 ] );
|
||||
var offset = mat4.fromTranslation( destination, vec3.fromValues( this._x, this._y, 0.0 ) );
|
||||
|
||||
return mat4.mul( offset, offset, mat4.mul( scale, scale, translate ) );
|
||||
|
||||
};
|
||||
} )()
|
||||
|
||||
} ), 'osg', 'Viewport' );
|
||||
|
||||
module.exports = Viewport;
|
|
@ -1,376 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var WebGLUtils = require( 'osgViewer/webgl-utils' );
|
||||
var Texture;
|
||||
|
||||
var WebGLCaps = function () {
|
||||
|
||||
// circular deps with texture
|
||||
if ( !Texture ) Texture = require( 'osg/Texture' );
|
||||
|
||||
this._checkRTT = {};
|
||||
this._webGLExtensions = {};
|
||||
this._webGLParameters = {};
|
||||
this._webGLShaderMaxInt = 'NONE';
|
||||
this._webGLShaderMaxFloat = 'NONE';
|
||||
|
||||
this._bugsDB = {};
|
||||
this._webGLPlatforms = {};
|
||||
|
||||
// webgl minimum requirements as per webgl specs
|
||||
// useful for nodejs env
|
||||
this._webGLParameters[ 'MAX_COMBINED_TEXTURE_IMAGE_UNITS' ] = 8;
|
||||
this._webGLParameters[ 'MAX_CUBE_MAP_TEXTURE_SIZE' ] = 16;
|
||||
this._webGLParameters[ 'MAX_FRAGMENT_UNIFORM_VECTORS' ] = 16;
|
||||
this._webGLParameters[ 'MAX_RENDERBUFFER_SIZE' ] = 1;
|
||||
this._webGLParameters[ 'MAX_TEXTURE_IMAGE_UNITS' ] = 8;
|
||||
this._webGLParameters[ 'MAX_TEXTURE_SIZE' ] = 64;
|
||||
this._webGLParameters[ 'MAX_VARYING_VECTORS' ] = 8;
|
||||
this._webGLParameters[ 'MAX_VERTEX_ATTRIBS' ] = 8;
|
||||
this._webGLParameters[ 'MAX_VERTEX_TEXTURE_IMAGE_UNITS' ] = 0;
|
||||
this._webGLParameters[ 'MAX_VERTEX_UNIFORM_VECTORS' ] = 128;
|
||||
this._webGLParameters[ 'MAX_VIEWPORT_DIMS' ] = [ 1, 1 ];
|
||||
this._webGLParameters[ 'NUM_COMPRESSED_TEXTURE_FORMATS' ] = 0;
|
||||
this._webGLParameters[ 'MAX_SHADER_PRECISION_FLOAT' ] = 'none';
|
||||
this._webGLParameters[ 'MAX_SHADER_PRECISION_INT' ] = 'none';
|
||||
|
||||
// for multiple context
|
||||
// allow checking we're on the good one
|
||||
this._gl = undefined;
|
||||
|
||||
};
|
||||
|
||||
WebGLCaps.instance = function ( glParam ) {
|
||||
|
||||
|
||||
if ( !WebGLCaps._instance ) {
|
||||
|
||||
var oldWebGLInspector;
|
||||
var gl = glParam;
|
||||
|
||||
if ( !gl ) {
|
||||
|
||||
// make sure we don't break webglinspector
|
||||
// with our webglcaps canvas
|
||||
var webglInspector = typeof window !== 'undefined' && window.gli;
|
||||
|
||||
if ( webglInspector ) {
|
||||
|
||||
oldWebGLInspector = window.gli.host.inspectContext;
|
||||
window.gli.host.inspectContext = false;
|
||||
|
||||
}
|
||||
|
||||
var c = document.createElement( 'canvas' );
|
||||
c.width = 32;
|
||||
c.height = 32;
|
||||
// not necessary, but for some reasons it crashed on chromium vr build
|
||||
var opt = {
|
||||
antialias: false
|
||||
};
|
||||
|
||||
gl = WebGLUtils.setupWebGL( c, opt, function () {} );
|
||||
|
||||
}
|
||||
|
||||
WebGLCaps._instance = new WebGLCaps();
|
||||
if ( gl ) {
|
||||
|
||||
WebGLCaps._instance.init( gl );
|
||||
|
||||
} else {
|
||||
|
||||
// gracefully handle non webgl
|
||||
// like nodejs, phantomjs
|
||||
// warns but no error so that nodejs/phantomjs
|
||||
// can still has some webglcaps object
|
||||
Notify.warn( 'no support for webgl context detected.' );
|
||||
|
||||
}
|
||||
|
||||
if ( oldWebGLInspector ) {
|
||||
|
||||
window.gli.host.inspectContext = oldWebGLInspector;
|
||||
|
||||
}
|
||||
|
||||
//delete c;
|
||||
}
|
||||
|
||||
if ( glParam && glParam !== WebGLCaps._instance.getContext() ) {
|
||||
|
||||
// webgl caps called with a different context
|
||||
// than the one we draw in, will result on hard crash
|
||||
// when using extension from another context
|
||||
WebGLCaps._instance.initContextDependant( glParam );
|
||||
|
||||
}
|
||||
|
||||
return WebGLCaps._instance;
|
||||
};
|
||||
|
||||
WebGLCaps.prototype = {
|
||||
|
||||
getContext: function () {
|
||||
return this._gl;
|
||||
},
|
||||
|
||||
initContextDependant: function ( gl ) {
|
||||
|
||||
// store context in case of multiple context
|
||||
this._gl = gl;
|
||||
|
||||
// Takes care of circular dependencies on Texture
|
||||
// Texture should be resolved at this point
|
||||
// Texture = require( 'osg/Texture' );
|
||||
|
||||
// get extensions
|
||||
this.initWebGLExtensions( gl );
|
||||
|
||||
// get float support
|
||||
this.hasLinearHalfFloatRTT( gl );
|
||||
this.hasLinearFloatRTT( gl );
|
||||
this.hasHalfFloatRTT( gl );
|
||||
this.hasFloatRTT( gl );
|
||||
|
||||
},
|
||||
|
||||
init: function ( gl ) {
|
||||
|
||||
// get capabilites
|
||||
this.initWebGLParameters( gl );
|
||||
|
||||
// order is important
|
||||
// to allow webgl extensions filtering
|
||||
this.initPlatformSupport();
|
||||
this.initBugDB();
|
||||
|
||||
this.initContextDependant( gl );
|
||||
|
||||
this._isGL2 = typeof window.WebGL2RenderingContext !== 'undefined' && gl instanceof window.WebGL2RenderingContext;
|
||||
|
||||
if ( this._isGL2 ) {
|
||||
|
||||
|
||||
// osgjs code is webgl1, so we fake webgl2 capabilities
|
||||
// and calls for retrocompatibility with webgl1
|
||||
this._checkRTT[ Texture.FLOAT + ',' + Texture.NEAREST ] = true;
|
||||
this._checkRTT[ Texture.HALF_FLOAT + ',' + Texture.NEAREST ] = true;
|
||||
this._checkRTT[ Texture.FLOAT + ',' + Texture.LINEAR ] = true;
|
||||
this._checkRTT[ Texture.HALF_FLOAT + ',' + Texture.LINEAR ] = true;
|
||||
|
||||
var nativeExtension = [
|
||||
'OES_element_index_uint',
|
||||
'EXT_sRGB',
|
||||
'EXT_blend_minmax',
|
||||
'EXT_frag_depth',
|
||||
'WEBGL_depth_texture',
|
||||
'EXT_shader_texture_lod',
|
||||
'OES_standard_derivatives',
|
||||
'OES_texture_float',
|
||||
'OES_texture_half_float',
|
||||
'OES_vertex_array_object',
|
||||
'WEBGL_draw_buffers',
|
||||
'OES_fbo_render_mipmap',
|
||||
'ANGLE_instanced_arrays'
|
||||
];
|
||||
|
||||
var ext = WebGLCaps._instance.getWebGLExtensions();
|
||||
var dummyFunc = function () {};
|
||||
for ( var i = 0, l = nativeExtension.length; i < l; i++ ) {
|
||||
ext[ nativeExtension[ i ] ] = dummyFunc;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
isWebGL2: function () {
|
||||
return this._isGL2;
|
||||
},
|
||||
// inevitable bugs per platform (browser/OS/GPU)
|
||||
initBugDB: function () {
|
||||
|
||||
},
|
||||
initPlatformSupport: function () {
|
||||
|
||||
var p = this._webGLPlatforms;
|
||||
|
||||
p.Apple = navigator.vendor.indexOf( 'Apple' ) !== -1 || navigator.vendor.indexOf( 'OS X' ) !== -1;
|
||||
|
||||
// degrades complexity on handhelds.
|
||||
p.Mobile = /Mobi/.test( navigator.userAgent ) || /ablet/.test( navigator.userAgent );
|
||||
|
||||
},
|
||||
getWebGLPlatform: function ( str ) {
|
||||
return this._webGLPlatforms[ str ];
|
||||
},
|
||||
getWebGLPlatforms: function () {
|
||||
return this._webGLPlatforms;
|
||||
},
|
||||
|
||||
getWebGLParameter: function ( str ) {
|
||||
return this._webGLParameters[ str ];
|
||||
},
|
||||
getWebGLParameters: function () {
|
||||
return this._webGLParameters;
|
||||
},
|
||||
getShaderMaxPrecisionFloat: function () {
|
||||
return this._webGLParameters.MAX_SHADER_PRECISION_FLOAT;
|
||||
},
|
||||
getShaderMaxPrecisionInt: function () {
|
||||
return this._webGLParameters.MAX_SHADER_PRECISION_INT;
|
||||
},
|
||||
checkSupportRTT: function ( gl, typeFloat, typeTexture ) {
|
||||
|
||||
var key = typeFloat + ',' + typeTexture;
|
||||
|
||||
// check once only
|
||||
if ( this._checkRTT[ key ] !== undefined )
|
||||
return this._checkRTT[ key ];
|
||||
|
||||
// no cached results, need gl context
|
||||
if ( !gl ) return false;
|
||||
|
||||
// from http://codeflow.org/entries/2013/feb/22/how-to-write-portable-webgl/#how-can-i-detect-if-i-can-render-to-floating-point-textures
|
||||
|
||||
// setup the texture
|
||||
var texture = gl.createTexture();
|
||||
gl.bindTexture( gl.TEXTURE_2D, texture );
|
||||
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, typeFloat, null );
|
||||
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, typeTexture );
|
||||
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, typeTexture );
|
||||
|
||||
// setup the framebuffer
|
||||
var framebuffer = gl.createFramebuffer();
|
||||
gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer );
|
||||
gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0 );
|
||||
|
||||
// check the framebuffer
|
||||
var status = this._checkRTT[ key ] = gl.checkFramebufferStatus( gl.FRAMEBUFFER ) === gl.FRAMEBUFFER_COMPLETE;
|
||||
|
||||
// cleanup
|
||||
gl.deleteTexture( texture );
|
||||
gl.deleteFramebuffer( framebuffer );
|
||||
gl.bindTexture( gl.TEXTURE_2D, null );
|
||||
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
|
||||
|
||||
return status;
|
||||
},
|
||||
hasLinearHalfFloatRTT: function ( gl ) {
|
||||
return this._webGLExtensions[ 'OES_texture_half_float_linear' ] && this.checkSupportRTT( gl, Texture.HALF_FLOAT, Texture.LINEAR );
|
||||
},
|
||||
hasLinearFloatRTT: function ( gl ) {
|
||||
return this._webGLExtensions[ 'OES_texture_float_linear' ] && this.checkSupportRTT( gl, Texture.FLOAT, Texture.LINEAR );
|
||||
},
|
||||
hasHalfFloatRTT: function ( gl ) {
|
||||
return this._webGLExtensions[ 'OES_texture_half_float' ] && this.checkSupportRTT( gl, Texture.HALF_FLOAT, Texture.NEAREST );
|
||||
},
|
||||
hasFloatRTT: function ( gl ) {
|
||||
return this._webGLExtensions[ 'OES_texture_float' ] && this.checkSupportRTT( gl, Texture.FLOAT, Texture.NEAREST );
|
||||
},
|
||||
queryPrecision: function ( gl, shaderType, precision ) {
|
||||
var answer = gl.getShaderPrecisionFormat( shaderType, precision );
|
||||
if ( !answer ) return false;
|
||||
return answer.precision !== 0;
|
||||
},
|
||||
initWebGLParameters: function ( gl ) {
|
||||
if ( !gl ) return;
|
||||
var limits = [
|
||||
'MAX_COMBINED_TEXTURE_IMAGE_UNITS',
|
||||
'MAX_CUBE_MAP_TEXTURE_SIZE',
|
||||
'MAX_FRAGMENT_UNIFORM_VECTORS',
|
||||
'MAX_RENDERBUFFER_SIZE',
|
||||
'MAX_TEXTURE_IMAGE_UNITS',
|
||||
'MAX_TEXTURE_SIZE',
|
||||
'MAX_VARYING_VECTORS',
|
||||
'MAX_VERTEX_ATTRIBS',
|
||||
'MAX_VERTEX_TEXTURE_IMAGE_UNITS',
|
||||
'MAX_VERTEX_UNIFORM_VECTORS',
|
||||
'MAX_VIEWPORT_DIMS',
|
||||
'SHADING_LANGUAGE_VERSION',
|
||||
'VERSION',
|
||||
'VENDOR',
|
||||
'RENDERER',
|
||||
'ALIASED_LINE_WIDTH_RANGE',
|
||||
'ALIASED_POINT_SIZE_RANGE',
|
||||
'RED_BITS',
|
||||
'GREEN_BITS',
|
||||
'BLUE_BITS',
|
||||
'ALPHA_BITS',
|
||||
'DEPTH_BITS',
|
||||
'STENCIL_BITS'
|
||||
];
|
||||
var params = this._webGLParameters;
|
||||
for ( var i = 0, len = limits.length; i < len; ++i ) {
|
||||
var par = limits[ i ];
|
||||
params[ par ] = gl.getParameter( gl[ par ] );
|
||||
}
|
||||
|
||||
//shader precisions for float
|
||||
if ( this.queryPrecision( gl, gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ) ) {
|
||||
params.MAX_SHADER_PRECISION_FLOAT = 'high';
|
||||
} else if ( this.queryPrecision( gl, gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ) ) {
|
||||
params.MAX_SHADER_PRECISION_FLOAT = 'medium';
|
||||
} else if ( this.queryPrecision( gl, gl.FRAGMENT_SHADER, gl.LOW_FLOAT ) ) {
|
||||
params.MAX_SHADER_PRECISION_FLOAT = 'low';
|
||||
}
|
||||
|
||||
//shader precisions for float
|
||||
if ( this.queryPrecision( gl, gl.FRAGMENT_SHADER, gl.HIGH_INT ) ) {
|
||||
params.MAX_SHADER_PRECISION_INT = 'high';
|
||||
} else if ( this.queryPrecision( gl, gl.FRAGMENT_SHADER, gl.MEDIUM_INT ) ) {
|
||||
params.MAX_SHADER_PRECISION_INT = 'medium';
|
||||
} else if ( this.queryPrecision( gl, gl.FRAGMENT_SHADER, gl.LOW_INT ) ) {
|
||||
params.MAX_SHADER_PRECISION_INT = 'low';
|
||||
}
|
||||
|
||||
// get GPU, Angle or not, Opengl/directx, etc.
|
||||
// ffx && chrome only
|
||||
var debugInfo = gl.getExtension( 'WEBGL_debug_renderer_info' );
|
||||
if ( debugInfo ) {
|
||||
params.UNMASKED_RENDERER_WEBGL = gl.getParameter( debugInfo.UNMASKED_VENDOR_WEBGL );
|
||||
params.UNMASKED_VENDOR_WEBGL = gl.getParameter( debugInfo.UNMASKED_RENDERER_WEBGL );
|
||||
|
||||
}
|
||||
// TODO ?
|
||||
// try to compile a small shader to test the spec is respected
|
||||
},
|
||||
getWebGLExtension: function ( str ) {
|
||||
return this._webGLExtensions[ str ];
|
||||
},
|
||||
getWebGLExtensions: function () {
|
||||
return this._webGLExtensions;
|
||||
},
|
||||
initWebGLExtensions: function ( gl, filterBugs ) {
|
||||
|
||||
// nodejs, phantomjs
|
||||
if ( !gl ) return;
|
||||
|
||||
var doFilter = filterBugs;
|
||||
if ( doFilter === undefined )
|
||||
doFilter = true;
|
||||
|
||||
var supported = gl.getSupportedExtensions();
|
||||
var ext = this._webGLExtensions;
|
||||
// we load all the extensions
|
||||
for ( var i = 0, len = supported.length; i < len; ++i ) {
|
||||
var sup = supported[ i ];
|
||||
|
||||
if ( doFilter && this._bugsDB[ sup ] ) {
|
||||
// bugs on that configuration, do not enable
|
||||
continue;
|
||||
}
|
||||
|
||||
ext[ sup ] = gl.getExtension( sup );
|
||||
}
|
||||
|
||||
var anisoExt = this.getWebGLExtension( 'EXT_texture_filter_anisotropic' );
|
||||
if ( anisoExt ) {
|
||||
Texture.ANISOTROPIC_SUPPORT_EXT = true;
|
||||
Texture.ANISOTROPIC_SUPPORT_MAX = gl.getParameter( anisoExt.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = WebGLCaps;
|
|
@ -1,52 +0,0 @@
|
|||
'use strict';
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
|
||||
|
||||
var computeLocalToWorld = function ( nodePath, ignoreCameras, userMatrix ) {
|
||||
|
||||
var ignoreCamera = ignoreCameras;
|
||||
|
||||
if ( ignoreCamera === undefined ) ignoreCamera = true;
|
||||
|
||||
var matrix = userMatrix || mat4.create();
|
||||
|
||||
var j = 0;
|
||||
|
||||
if ( ignoreCamera ) {
|
||||
|
||||
for ( j = nodePath.length - 1; j >= 0; j-- ) {
|
||||
|
||||
var camera = nodePath[ j ];
|
||||
|
||||
if ( camera.className() === 'Camera' &&
|
||||
( camera.getReferenceFrame() !== TransformEnums.RELATIVE_RF || camera.getParents().length === 0 ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// because when we break it's to an index - 1
|
||||
// it works because if nothing camera found j == -1 at the end of the loop
|
||||
// and if we found a camera we want to start at the camera index + 1
|
||||
j += 1;
|
||||
|
||||
}
|
||||
|
||||
for ( var i = j, l = nodePath.length; i < l; i++ ) {
|
||||
|
||||
var node = nodePath[ i ];
|
||||
|
||||
if ( node.computeLocalToWorldMatrix ) {
|
||||
node.computeLocalToWorldMatrix( matrix );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return matrix;
|
||||
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
computeLocalToWorld: computeLocalToWorld
|
||||
};
|
|
@ -1,701 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var osgMath = require( 'osg/math' );
|
||||
var BoundingBox = require( 'osg/BoundingBox' );
|
||||
var Plane = require( 'osg/Plane' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
|
||||
var glm = require( 'osg/glMatrix' );
|
||||
|
||||
var Mabs = Math.abs;
|
||||
var NMIN_VALUE = Number.MIN_VALUE;
|
||||
|
||||
// call by closur'd variables because Matrix object is not
|
||||
// resolved yet, a workaround would be to define Matrix such as:
|
||||
// var Matrix = {};
|
||||
// Matrix.create = function... ;
|
||||
// Matrix.func2 = function... ;
|
||||
var matrixCreate = glm.mat4.create;
|
||||
|
||||
/** @class Matrix Operations */
|
||||
var Matrix = {
|
||||
|
||||
create: glm.mat4.create,
|
||||
createAndSet: glm.mat4.fromValues,
|
||||
|
||||
isIdentity: function ( matrix ) {
|
||||
return glm.mat4.equals( Matrix.identity, matrix );
|
||||
},
|
||||
|
||||
valid: function ( matrix ) {
|
||||
for ( var i = 0; i < 16; i++ )
|
||||
if ( osgMath.isNaN( matrix[ i ] ) )
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
setRow: function ( matrix, row, v0, v1, v2, v3 ) {
|
||||
var rowIndex = row * 4;
|
||||
matrix[ rowIndex + 0 ] = v0;
|
||||
matrix[ rowIndex + 1 ] = v1;
|
||||
matrix[ rowIndex + 2 ] = v2;
|
||||
matrix[ rowIndex + 3 ] = v3;
|
||||
},
|
||||
|
||||
innerProduct: function ( a, b, r, c ) {
|
||||
var rIndex = r * 4;
|
||||
return ( ( a[ rIndex + 0 ] * b[ 0 + c ] ) + ( a[ rIndex + 1 ] * b[ 4 + c ] ) + ( a[ rIndex + 2 ] * b[ 8 + c ] ) + ( a[ rIndex + 3 ] * b[ 12 + c ] ) );
|
||||
},
|
||||
|
||||
set: function ( matrix, row, col, value ) {
|
||||
matrix[ row * 4 + col ] = value;
|
||||
return value;
|
||||
},
|
||||
|
||||
get: function ( matrix, row, col ) {
|
||||
return matrix[ row * 4 + col ];
|
||||
},
|
||||
|
||||
makeIdentity: glm.mat4.identity,
|
||||
|
||||
equal: glm.mat4.exactEquals,
|
||||
|
||||
/**
|
||||
* @param {Number} x position
|
||||
* @param {Number} y position
|
||||
* @param {Number} z position
|
||||
* @param {Array} matrix to write result
|
||||
*/
|
||||
makeTranslate: function ( x, y, z, matrix ) {
|
||||
return glm.mat4.fromTranslation( matrix, vec3.fromValues( x, y, z ) );
|
||||
},
|
||||
|
||||
setTrans: function ( matrix, x, y, z ) {
|
||||
matrix[ 12 ] = x;
|
||||
matrix[ 13 ] = y;
|
||||
matrix[ 14 ] = z;
|
||||
return matrix;
|
||||
},
|
||||
|
||||
getTrans: function ( matrix, result ) {
|
||||
return glm.mat4.getTranslation( result, matrix );
|
||||
},
|
||||
|
||||
// do a * b and result in a
|
||||
preMult: function ( a, b ) {
|
||||
return glm.mat4.multiply( a, a, b );
|
||||
},
|
||||
|
||||
// do a * b and store the result in b
|
||||
// Be aware of the change w.r.t OSG as b holds the result!
|
||||
postMult: function ( a, b ) {
|
||||
return glm.mat4.multiply( b, a, b );
|
||||
},
|
||||
|
||||
/* r = a * b */
|
||||
mult: function ( a, b, r ) {
|
||||
return glm.mat4.multiply( r, a, b );
|
||||
},
|
||||
|
||||
makeLookFromDirection: ( function () {
|
||||
var s = vec3.create();
|
||||
var u = vec3.create();
|
||||
var neg = vec3.create();
|
||||
|
||||
return function ( eye, eyeDir, up, result ) {
|
||||
var f = eyeDir;
|
||||
vec3.cross( s, f, up );
|
||||
vec3.normalize( s, s );
|
||||
|
||||
vec3.cross( u, s, f );
|
||||
vec3.normalize( u, u );
|
||||
|
||||
// s[0], u[0], -f[0], 0.0,
|
||||
// s[1], u[1], -f[1], 0.0,
|
||||
// s[2], u[2], -f[2], 0.0,
|
||||
// 0, 0, 0, 1.0
|
||||
|
||||
result[ 0 ] = s[ 0 ];
|
||||
result[ 1 ] = u[ 0 ];
|
||||
result[ 2 ] = -f[ 0 ];
|
||||
result[ 3 ] = 0.0;
|
||||
result[ 4 ] = s[ 1 ];
|
||||
result[ 5 ] = u[ 1 ];
|
||||
result[ 6 ] = -f[ 1 ];
|
||||
result[ 7 ] = 0.0;
|
||||
result[ 8 ] = s[ 2 ];
|
||||
result[ 9 ] = u[ 2 ];
|
||||
result[ 10 ] = -f[ 2 ];
|
||||
result[ 11 ] = 0.0;
|
||||
result[ 12 ] = 0;
|
||||
result[ 13 ] = 0;
|
||||
result[ 14 ] = 0;
|
||||
result[ 15 ] = 1.0;
|
||||
|
||||
Matrix.multTranslate( result, vec3.neg( neg, eye ), result );
|
||||
return result;
|
||||
};
|
||||
} )(),
|
||||
|
||||
makeLookAt: function ( eye, center, up, result ) {
|
||||
return glm.mat4.lookAt( result, eye, center, up );
|
||||
},
|
||||
|
||||
makeOrtho: function ( left, right, bottom, top, zNear, zFar, result ) {
|
||||
return glm.mat4.ortho( result, left, right, bottom, top, zNear, zFar );
|
||||
},
|
||||
|
||||
getLookAt: ( function () {
|
||||
var inv = matrixCreate();
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.fromValues( 0.0, 1.0, 0.0 );
|
||||
var v3 = vec3.fromValues( 0.0, 0.0, -1.0 );
|
||||
|
||||
return function ( matrix, eye, center, up, distance ) {
|
||||
if ( distance === undefined ) {
|
||||
distance = 1.0;
|
||||
}
|
||||
var result = Matrix.inverse( matrix, inv );
|
||||
if ( !result ) {
|
||||
glm.mat4.identity( inv );
|
||||
}
|
||||
Matrix.transformVec3( inv, v1, eye );
|
||||
Matrix.transform3x3( matrix, v2, up );
|
||||
Matrix.transform3x3( matrix, v3, center );
|
||||
vec3.normalize( center, center );
|
||||
vec3.add( center, vec3.scale( v1, center, distance ), eye );
|
||||
};
|
||||
} )(),
|
||||
|
||||
//getRotate_David_Spillings_Mk1
|
||||
getRotate: function ( mat, quatResult ) {
|
||||
return glm.mat4.getRotation( quatResult, mat );
|
||||
},
|
||||
|
||||
// Matrix M = Matrix M * Matrix Translate
|
||||
preMultTranslate: function ( mat, translate ) {
|
||||
return glm.mat4.translate( mat, mat, translate );
|
||||
},
|
||||
|
||||
postMultTranslate: function ( mat, translate ) {
|
||||
return glm.mat4.multiply( mat, glm.mat4.fromTranslation( glm.mat4.create(), translate ), mat );
|
||||
},
|
||||
|
||||
// result = Matrix M * Matrix Translate
|
||||
multTranslate: function ( mat, translate, result ) {
|
||||
return glm.mat4.translate( result, mat, translate );
|
||||
},
|
||||
|
||||
makeRotate: function ( angle, x, y, z, result ) {
|
||||
var v = vec3.fromValues( x, y, z );
|
||||
if ( x === 0.0 && y === 0.0 && z === 0.0 )
|
||||
v[ 2 ] = 1.0;
|
||||
return glm.mat4.fromRotation( result, angle, v );
|
||||
},
|
||||
|
||||
preMultRotate: ( function () {
|
||||
var r = matrixCreate();
|
||||
return function ( matrix, q ) {
|
||||
return glm.mat4.multiply( matrix, matrix, glm.mat4.fromQuat( r, q ) );
|
||||
};
|
||||
} )(),
|
||||
|
||||
postMultRotate: ( function () {
|
||||
var r = matrixCreate();
|
||||
return function ( m, q ) {
|
||||
return glm.mat4.multiply( m, glm.mat4.fromQuat( r, q ), m );
|
||||
};
|
||||
} )(),
|
||||
|
||||
transform3x3: function ( m, v, result ) {
|
||||
result[ 0 ] = m[ 0 ] * v[ 0 ] + m[ 1 ] * v[ 1 ] + m[ 2 ] * v[ 2 ];
|
||||
result[ 1 ] = m[ 4 ] * v[ 0 ] + m[ 5 ] * v[ 1 ] + m[ 6 ] * v[ 2 ];
|
||||
result[ 2 ] = m[ 8 ] * v[ 0 ] + m[ 9 ] * v[ 1 ] + m[ 10 ] * v[ 2 ];
|
||||
return result;
|
||||
},
|
||||
|
||||
transformVec3: function ( matrix, vector, result ) {
|
||||
return glm.vec3.transformMat4( result, vector, matrix );
|
||||
},
|
||||
|
||||
transformVec4: function ( matrix, vector, result ) {
|
||||
return glm.vec4.transformMat4( result, vector, matrix );
|
||||
},
|
||||
|
||||
// http://dev.theomader.com/transform-bounding-boxes/
|
||||
// https://github.com/erich666/GraphicsGems/blob/master/gems/TransBox.c
|
||||
transformBoundingBox: ( function () {
|
||||
var tempBbox = new BoundingBox();
|
||||
return function ( m, bbIn, bbOut ) {
|
||||
if ( bbOut === bbIn ) {
|
||||
bbOut = tempBbox;
|
||||
}
|
||||
var inMin = bbIn.getMin();
|
||||
var inMax = bbIn.getMax();
|
||||
|
||||
/* Take care of translation by beginning at T. */
|
||||
var outMin = glm.mat4.getTranslation( bbOut.getMin(), m );
|
||||
var outMax = vec3.copy( bbOut.getMax(), outMin );
|
||||
|
||||
/* Now find the extreme points by considering the product of the */
|
||||
/* min and max with each component of M. */
|
||||
for ( var i = 0; i < 3; ++i ) {
|
||||
var i4 = i * 4;
|
||||
var mini = inMin[ i ];
|
||||
var maxi = inMax[ i ];
|
||||
for ( var j = 0; j < 3; ++j ) {
|
||||
var cm = m[ i4 + j ];
|
||||
var a = cm * maxi;
|
||||
var b = cm * mini;
|
||||
if ( a < b ) {
|
||||
outMin[ j ] += a;
|
||||
outMax[ j ] += b;
|
||||
} else {
|
||||
outMin[ j ] += b;
|
||||
outMax[ j ] += a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( bbOut === tempBbox ) {
|
||||
bbIn.copy( tempBbox );
|
||||
}
|
||||
};
|
||||
} )(),
|
||||
|
||||
transformBoundingSphere: ( function () {
|
||||
var scaleVec = vec3.create();
|
||||
return function ( matrix, bSphere, bsOut ) {
|
||||
if ( !bSphere.valid() ) {
|
||||
return bsOut;
|
||||
}
|
||||
vec3.copy( bsOut._center, bSphere._center );
|
||||
bsOut._radius = bSphere._radius;
|
||||
var sphCenter = bsOut._center;
|
||||
var sphRadius = bsOut._radius;
|
||||
|
||||
Matrix.getScale2( matrix, scaleVec );
|
||||
var scale = Math.sqrt( Math.max( Math.max( scaleVec[ 0 ], scaleVec[ 1 ] ), scaleVec[ 2 ] ) );
|
||||
sphRadius = sphRadius * scale;
|
||||
bsOut._radius = sphRadius;
|
||||
Matrix.transformVec3( matrix, sphCenter, sphCenter );
|
||||
|
||||
return bsOut;
|
||||
};
|
||||
} )(),
|
||||
|
||||
transformVec4PostMult: function ( matrix, vector, result ) {
|
||||
|
||||
var x = vector[ 0 ];
|
||||
var y = vector[ 1 ];
|
||||
var z = vector[ 2 ];
|
||||
var w = vector[ 3 ];
|
||||
|
||||
result[ 0 ] = matrix[ 0 ] * x + matrix[ 1 ] * y + matrix[ 2 ] * z + matrix[ 3 ] * w;
|
||||
result[ 1 ] = matrix[ 4 ] * x + matrix[ 5 ] * y + matrix[ 6 ] * z + matrix[ 7 ] * w;
|
||||
result[ 2 ] = matrix[ 8 ] * x + matrix[ 9 ] * y + matrix[ 10 ] * z + matrix[ 11 ] * w;
|
||||
result[ 3 ] = matrix[ 12 ] * x + matrix[ 13 ] * y + matrix[ 14 ] * z + matrix[ 15 ] * w;
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
copy: function ( matrix, result ) {
|
||||
return glm.mat4.copy( result, matrix );
|
||||
},
|
||||
|
||||
inverse: function ( matrix, result ) {
|
||||
var r = glm.mat4.invert( result, matrix );
|
||||
if ( r === null ) return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
transpose: function ( mat, dest ) {
|
||||
return glm.mat4.transpose( dest, mat );
|
||||
},
|
||||
|
||||
getFrustumPlanes: ( function () {
|
||||
|
||||
var mvp = matrixCreate();
|
||||
|
||||
return function ( projection, view, result, withNearFar ) {
|
||||
glm.mat4.multiply( mvp, projection, view );
|
||||
|
||||
if ( withNearFar === undefined )
|
||||
withNearFar = false;
|
||||
// Right clipping plane.
|
||||
var right = result[ 0 ];
|
||||
right[ 0 ] = mvp[ 3 ] - mvp[ 0 ];
|
||||
right[ 1 ] = mvp[ 7 ] - mvp[ 4 ];
|
||||
right[ 2 ] = mvp[ 11 ] - mvp[ 8 ];
|
||||
right[ 3 ] = mvp[ 15 ] - mvp[ 12 ];
|
||||
|
||||
// Left clipping plane.
|
||||
var left = result[ 1 ];
|
||||
left[ 0 ] = mvp[ 3 ] + mvp[ 0 ];
|
||||
left[ 1 ] = mvp[ 7 ] + mvp[ 4 ];
|
||||
left[ 2 ] = mvp[ 11 ] + mvp[ 8 ];
|
||||
left[ 3 ] = mvp[ 15 ] + mvp[ 12 ];
|
||||
|
||||
// Bottom clipping plane.
|
||||
var bottom = result[ 2 ];
|
||||
bottom[ 0 ] = mvp[ 3 ] + mvp[ 1 ];
|
||||
bottom[ 1 ] = mvp[ 7 ] + mvp[ 5 ];
|
||||
bottom[ 2 ] = mvp[ 11 ] + mvp[ 9 ];
|
||||
bottom[ 3 ] = mvp[ 15 ] + mvp[ 13 ];
|
||||
|
||||
// Top clipping plane.
|
||||
var top = result[ 3 ];
|
||||
top[ 0 ] = mvp[ 3 ] - mvp[ 1 ];
|
||||
top[ 1 ] = mvp[ 7 ] - mvp[ 5 ];
|
||||
top[ 2 ] = mvp[ 11 ] - mvp[ 9 ];
|
||||
top[ 3 ] = mvp[ 15 ] - mvp[ 13 ];
|
||||
|
||||
if ( withNearFar ) {
|
||||
// Far clipping plane.
|
||||
var far = result[ 4 ];
|
||||
far[ 0 ] = mvp[ 3 ] - mvp[ 2 ];
|
||||
far[ 1 ] = mvp[ 7 ] - mvp[ 6 ];
|
||||
far[ 2 ] = mvp[ 11 ] - mvp[ 10 ];
|
||||
far[ 3 ] = mvp[ 15 ] - mvp[ 14 ];
|
||||
|
||||
// Near clipping plane.
|
||||
var near = result[ 5 ];
|
||||
near[ 0 ] = mvp[ 3 ] + mvp[ 2 ];
|
||||
near[ 1 ] = mvp[ 7 ] + mvp[ 6 ];
|
||||
near[ 2 ] = mvp[ 11 ] + mvp[ 10 ];
|
||||
near[ 3 ] = mvp[ 15 ] + mvp[ 14 ];
|
||||
}
|
||||
|
||||
//Normalize the planes
|
||||
var j = withNearFar ? 6 : 4;
|
||||
for ( var i = 0; i < j; i++ ) {
|
||||
Plane.normalizeEquation( result[ i ] );
|
||||
}
|
||||
|
||||
};
|
||||
} )(),
|
||||
|
||||
makePerspective: function ( fovy, aspect, znear, zfar, result ) {
|
||||
return glm.mat4.perspective( result, fovy * Math.PI / 180.0, aspect, znear, zfar );
|
||||
},
|
||||
|
||||
getFrustum: function ( matrix, result ) {
|
||||
var right = 0.0;
|
||||
var left = 0.0;
|
||||
var top = 0.0;
|
||||
var bottom = 0.0;
|
||||
var zNear, zFar;
|
||||
|
||||
if ( matrix[ 0 * 4 + 3 ] !== 0.0 || matrix[ 1 * 4 + 3 ] !== 0.0 || matrix[ 2 * 4 + 3 ] !== -1.0 || matrix[ 3 * 4 + 3 ] !== 0.0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// note: near and far must be used inside this method instead of zNear and zFar
|
||||
// because zNear and zFar are references and they may point to the same variable.
|
||||
var tempNear = matrix[ 3 * 4 + 2 ] / ( matrix[ 2 * 4 + 2 ] - 1.0 );
|
||||
var tempFar = matrix[ 3 * 4 + 2 ] / ( 1.0 + matrix[ 2 * 4 + 2 ] );
|
||||
|
||||
left = tempNear * ( matrix[ 2 * 4 ] - 1.0 ) / matrix[ 0 ];
|
||||
right = tempNear * ( 1.0 + matrix[ 2 * 4 ] ) / matrix[ 0 ];
|
||||
|
||||
top = tempNear * ( 1.0 + matrix[ 2 * 4 + 1 ] ) / matrix[ 1 * 4 + 1 ];
|
||||
bottom = tempNear * ( matrix[ 2 * 4 + 1 ] - 1.0 ) / matrix[ 1 * 4 + 1 ];
|
||||
|
||||
zNear = tempNear;
|
||||
zFar = tempFar;
|
||||
|
||||
result.left = left;
|
||||
result.right = right;
|
||||
result.top = top;
|
||||
result.bottom = bottom;
|
||||
result.zNear = zNear;
|
||||
result.zFar = zFar;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
getPerspective: ( function () {
|
||||
var c = {
|
||||
'right': 0,
|
||||
'left': 0,
|
||||
'top': 0,
|
||||
'bottom': 0,
|
||||
'zNear': 0,
|
||||
'zFar': 0
|
||||
};
|
||||
return function ( matrix, result ) {
|
||||
// get frustum and compute results
|
||||
var r = Matrix.getFrustum( matrix, c );
|
||||
if ( r ) {
|
||||
result.fovy = 180 / Math.PI * ( Math.atan( c.top / c.zNear ) - Math.atan( c.bottom / c.zNear ) );
|
||||
result.aspectRatio = ( c.right - c.left ) / ( c.top - c.bottom );
|
||||
}
|
||||
result.zNear = c.zNear;
|
||||
result.zFar = c.zFar;
|
||||
return result;
|
||||
};
|
||||
} )(),
|
||||
|
||||
preMultScale: function ( m, scale ) {
|
||||
return glm.mat4.scale( m, m, scale );
|
||||
},
|
||||
|
||||
postMultScale: function ( m, scale ) {
|
||||
return glm.mat4.multiply( m, glm.mat4.fromScaling( glm.mat4.create(), scale ), m );
|
||||
},
|
||||
|
||||
makeScale: function ( x, y, z, result ) {
|
||||
return glm.mat4.fromScaling( result, [ x, y, z ] );
|
||||
},
|
||||
|
||||
getScale: ( function () {
|
||||
var sx = vec3.create();
|
||||
var sy = vec3.create();
|
||||
var sz = vec3.create();
|
||||
return function ( matrix, result ) {
|
||||
sx[ 0 ] = matrix[ 0 ];
|
||||
sx[ 1 ] = matrix[ 4 ];
|
||||
sx[ 2 ] = matrix[ 8 ];
|
||||
sy[ 0 ] = matrix[ 1 ];
|
||||
sy[ 1 ] = matrix[ 5 ];
|
||||
sy[ 2 ] = matrix[ 9 ];
|
||||
sz[ 0 ] = matrix[ 2 ];
|
||||
sz[ 1 ] = matrix[ 6 ];
|
||||
sz[ 2 ] = matrix[ 10 ];
|
||||
|
||||
result[ 0 ] = vec3.length( sx );
|
||||
result[ 1 ] = vec3.length( sy );
|
||||
result[ 2 ] = vec3.length( sz );
|
||||
return result;
|
||||
};
|
||||
} )(),
|
||||
|
||||
getScale2: ( function () {
|
||||
var sx = vec3.create();
|
||||
var sy = vec3.create();
|
||||
var sz = vec3.create();
|
||||
return function ( matrix, result ) {
|
||||
sx[ 0 ] = matrix[ 0 ];
|
||||
sx[ 1 ] = matrix[ 4 ];
|
||||
sx[ 2 ] = matrix[ 8 ];
|
||||
sy[ 0 ] = matrix[ 1 ];
|
||||
sy[ 1 ] = matrix[ 5 ];
|
||||
sy[ 2 ] = matrix[ 9 ];
|
||||
sz[ 0 ] = matrix[ 2 ];
|
||||
sz[ 1 ] = matrix[ 6 ];
|
||||
sz[ 2 ] = matrix[ 10 ];
|
||||
|
||||
result[ 0 ] = vec3.sqrLen( sx );
|
||||
result[ 1 ] = vec3.sqrLen( sy );
|
||||
result[ 2 ] = vec3.sqrLen( sz );
|
||||
return result;
|
||||
};
|
||||
} )(),
|
||||
|
||||
clampProjectionMatrix: function ( projection, znear, zfar, nearFarRatio, resultNearFar ) {
|
||||
var epsilon = 1e-6;
|
||||
if ( zfar < znear - epsilon ) {
|
||||
Notify.log( 'clampProjectionMatrix not applied, invalid depth range, znear = ' + znear + ' zfar = ' + zfar, false, true );
|
||||
return false;
|
||||
}
|
||||
|
||||
var desiredZnear, desiredZfar;
|
||||
if ( zfar < znear + epsilon ) {
|
||||
// znear and zfar are too close together and could cause divide by zero problems
|
||||
// late on in the clamping code, so move the znear and zfar apart.
|
||||
var average = ( znear + zfar ) * 0.5;
|
||||
znear = average - epsilon;
|
||||
zfar = average + epsilon;
|
||||
// OSG_INFO << '_clampProjectionMatrix widening znear and zfar to '<<znear<<' '<<zfar<<std::endl;
|
||||
}
|
||||
|
||||
if ( Math.abs( projection[ 3 ] ) < epsilon &&
|
||||
Math.abs( projection[ 7 ] ) < epsilon &&
|
||||
Math.abs( projection[ 11 ] ) < epsilon ) {
|
||||
// OSG_INFO << 'Orthographic matrix before clamping'<<projection<<std::endl;
|
||||
|
||||
var deltaSpan = ( zfar - znear ) * 0.02;
|
||||
if ( deltaSpan < 1.0 ) {
|
||||
deltaSpan = 1.0;
|
||||
}
|
||||
desiredZnear = znear - deltaSpan;
|
||||
desiredZfar = zfar + deltaSpan;
|
||||
|
||||
// assign the clamped values back to the computed values.
|
||||
znear = desiredZnear;
|
||||
zfar = desiredZfar;
|
||||
|
||||
projection[ 10 ] = -2.0 / ( desiredZfar - desiredZnear );
|
||||
projection[ 14 ] = -( desiredZfar + desiredZnear ) / ( desiredZfar - desiredZnear );
|
||||
|
||||
// OSG_INFO << 'Orthographic matrix after clamping '<<projection<<std::endl;
|
||||
} else {
|
||||
|
||||
// OSG_INFO << 'Persepective matrix before clamping'<<projection<<std::endl;
|
||||
//std::cout << '_computed_znear'<<_computed_znear<<std::endl;
|
||||
//std::cout << '_computed_zfar'<<_computed_zfar<<std::endl;
|
||||
|
||||
var zfarPushRatio = 1.02;
|
||||
var znearPullRatio = 0.98;
|
||||
|
||||
//znearPullRatio = 0.99;
|
||||
|
||||
desiredZnear = znear * znearPullRatio;
|
||||
desiredZfar = zfar * zfarPushRatio;
|
||||
|
||||
// near plane clamping.
|
||||
var minNearPlane = zfar * nearFarRatio;
|
||||
if ( desiredZnear < minNearPlane ) {
|
||||
desiredZnear = minNearPlane;
|
||||
}
|
||||
|
||||
// assign the clamped values back to the computed values.
|
||||
znear = desiredZnear;
|
||||
zfar = desiredZfar;
|
||||
|
||||
var m22 = projection[ 10 ];
|
||||
var m32 = projection[ 14 ];
|
||||
var m23 = projection[ 11 ];
|
||||
var m33 = projection[ 15 ];
|
||||
var transNearPlane = ( -desiredZnear * m22 + m32 ) / ( -desiredZnear * m23 + m33 );
|
||||
var transFarPlane = ( -desiredZfar * m22 + m32 ) / ( -desiredZfar * m23 + m33 );
|
||||
|
||||
var ratio = Math.abs( 2.0 / ( transNearPlane - transFarPlane ) );
|
||||
var center = -( transNearPlane + transFarPlane ) / 2.0;
|
||||
|
||||
var centerRatio = center * ratio;
|
||||
projection[ 2 ] = projection[ 2 ] * ratio + projection[ 3 ] * centerRatio;
|
||||
projection[ 6 ] = projection[ 6 ] * ratio + projection[ 7 ] * centerRatio;
|
||||
projection[ 10 ] = m22 * ratio + m23 * centerRatio;
|
||||
projection[ 14 ] = m32 * ratio + m33 * centerRatio;
|
||||
// same as
|
||||
// var matrix = [ 1.0, 0.0, 0.0, 0.0,
|
||||
// 0.0, 1.0, 0.0, 0.0,
|
||||
// 0.0, 0.0, ratio, 0.0,
|
||||
// 0.0, 0.0, center * ratio, 1.0
|
||||
// ];
|
||||
// mat4.mul( projection , matrix, projection );
|
||||
|
||||
// OSG_INFO << 'Persepective matrix after clamping'<<projection<<std::endl;
|
||||
}
|
||||
if ( resultNearFar !== undefined ) {
|
||||
resultNearFar[ 0 ] = znear;
|
||||
resultNearFar[ 1 ] = zfar;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// compute the 4 corners vector of the frustum
|
||||
computeFrustumCornersVectors: function ( projectionMatrix, vectorsArray ) {
|
||||
//var znear = projectionMatrix[ 12 + 2 ] / ( projectionMatrix[ 8 + 2 ] - 1.0 );
|
||||
//var zfar = projectionMatrix[ 12 + 2 ] / ( projectionMatrix[ 8 + 2 ] + 1.0 );
|
||||
var x = 1.0 / projectionMatrix[ 0 ];
|
||||
var y = 1.0 / projectionMatrix[ 1 * 4 + 1 ];
|
||||
|
||||
vectorsArray[ 0 ] = vec3.fromValues( -x, y, 1.0 );
|
||||
vectorsArray[ 1 ] = vec3.fromValues( -x, -y, 1.0 );
|
||||
vectorsArray[ 2 ] = vec3.fromValues( x, -y, 1.0 );
|
||||
vectorsArray[ 3 ] = vec3.fromValues( x, y, 1.0 );
|
||||
return vectorsArray;
|
||||
},
|
||||
|
||||
// better precison
|
||||
// no far clipping artifacts.
|
||||
// no reason not to use.
|
||||
// Tightening the Precision of Perspective Rendering
|
||||
//http://www.geometry.caltech.edu/pubs/UD12.pdf
|
||||
// drop-in, just remove the one below, and rename this one
|
||||
makeFrustumInfinite: function ( left, right, bottom, top, znear, zfar, result ) {
|
||||
var X = 2.0 * znear / ( right - left );
|
||||
var Y = 2.0 * znear / ( top - bottom );
|
||||
var A = ( right + left ) / ( right - left );
|
||||
var B = ( top + bottom ) / ( top - bottom );
|
||||
var C = -1.0;
|
||||
Matrix.setRow( result, 0, X, 0.0, 0.0, 0.0 );
|
||||
Matrix.setRow( result, 1, 0.0, Y, 0.0, 0.0 );
|
||||
Matrix.setRow( result, 2, A, B, C, -1.0 );
|
||||
Matrix.setRow( result, 3, 0.0, 0.0, -2.0 * znear, 0.0 );
|
||||
return result;
|
||||
},
|
||||
|
||||
makeFrustum: function ( left, right, bottom, top, znear, zfar, result ) {
|
||||
return glm.mat4.frustum( result, left, right, bottom, top, znear, zfar );
|
||||
},
|
||||
|
||||
makeRotateFromQuat: function ( q, result ) {
|
||||
return glm.mat4.fromQuat( result, q );
|
||||
},
|
||||
|
||||
setRotateFromQuat: function ( m, q ) {
|
||||
var length2 = glm.quat.sqrLen( q );
|
||||
if ( Mabs( length2 ) <= NMIN_VALUE ) {
|
||||
m[ 0 ] = 0.0;
|
||||
m[ 1 ] = 0.0;
|
||||
m[ 2 ] = 0.0;
|
||||
|
||||
m[ 4 ] = 0.0;
|
||||
m[ 5 ] = 0.0;
|
||||
m[ 6 ] = 0.0;
|
||||
|
||||
m[ 8 ] = 0.0;
|
||||
m[ 9 ] = 0.0;
|
||||
m[ 10 ] = 0.0;
|
||||
} else {
|
||||
var rlength2;
|
||||
// normalize quat if required.
|
||||
// We can avoid the expensive sqrt in this case since all 'coefficients' below are products of two q components.
|
||||
// That is a square of a square root, so it is possible to avoid that
|
||||
if ( length2 !== 1.0 ) {
|
||||
rlength2 = 2.0 / length2;
|
||||
} else {
|
||||
rlength2 = 2.0;
|
||||
}
|
||||
|
||||
// Source: Gamasutra, Rotating Objects Using Quaternions
|
||||
//
|
||||
//http://www.gamasutra.com/features/19980703/quaternions_01.htm
|
||||
|
||||
var wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
|
||||
|
||||
// calculate coefficients
|
||||
x2 = rlength2 * q[ 0 ];
|
||||
y2 = rlength2 * q[ 1 ];
|
||||
z2 = rlength2 * q[ 2 ];
|
||||
|
||||
xx = q[ 0 ] * x2;
|
||||
xy = q[ 0 ] * y2;
|
||||
xz = q[ 0 ] * z2;
|
||||
|
||||
yy = q[ 1 ] * y2;
|
||||
yz = q[ 1 ] * z2;
|
||||
zz = q[ 2 ] * z2;
|
||||
|
||||
wx = q[ 3 ] * x2;
|
||||
wy = q[ 3 ] * y2;
|
||||
wz = q[ 3 ] * z2;
|
||||
|
||||
// Note. Gamasutra gets the matrix assignments inverted, resulting
|
||||
// in left-handed rotations, which is contrary to OpenGL and OSG's
|
||||
// methodology. The matrix assignment has been altered in the next
|
||||
// few lines of code to do the right thing.
|
||||
// Don Burns - Oct 13, 2001
|
||||
m[ 0 ] = 1.0 - ( yy + zz );
|
||||
m[ 4 ] = xy - wz;
|
||||
m[ 8 ] = xz + wy;
|
||||
|
||||
|
||||
m[ 0 + 1 ] = xy + wz;
|
||||
m[ 4 + 1 ] = 1.0 - ( xx + zz );
|
||||
m[ 8 + 1 ] = yz - wx;
|
||||
|
||||
m[ 0 + 2 ] = xz - wy;
|
||||
m[ 4 + 2 ] = yz + wx;
|
||||
m[ 8 + 2 ] = 1.0 - ( xx + yy );
|
||||
}
|
||||
return m;
|
||||
}
|
||||
};
|
||||
|
||||
Matrix.identity = Matrix.create();
|
||||
|
||||
module.exports = Matrix;
|
|
@ -1,386 +0,0 @@
|
|||
'use strict';
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var Vec4 = require( 'osg/Vec4' );
|
||||
var config = require( '../../config' );
|
||||
|
||||
var ArrayType = config.ArrayType;
|
||||
|
||||
|
||||
var Msqrt = Math.sqrt;
|
||||
var Mcos = Math.cos;
|
||||
var Msin = Math.sin;
|
||||
|
||||
var Quat = {
|
||||
|
||||
create: function () {
|
||||
var out = new ArrayType( 4 );
|
||||
out[ 0 ] = 0.0;
|
||||
out[ 1 ] = 0.0;
|
||||
out[ 2 ] = 0.0;
|
||||
out[ 3 ] = 1.0;
|
||||
return out;
|
||||
},
|
||||
|
||||
createAndSet: Vec4.createAndSet,
|
||||
|
||||
makeIdentity: function ( element ) {
|
||||
return Quat.init( element );
|
||||
},
|
||||
|
||||
init: function ( element ) {
|
||||
element[ 0 ] = 0.0;
|
||||
element[ 1 ] = 0.0;
|
||||
element[ 2 ] = 0.0;
|
||||
element[ 3 ] = 1.0;
|
||||
return element;
|
||||
},
|
||||
|
||||
// reuse Vec4 methods
|
||||
copy: Vec4.copy,
|
||||
set: Vec4.set,
|
||||
sub: Vec4.sub,
|
||||
add: Vec4.add,
|
||||
dot: Vec4.dot,
|
||||
neg: Vec4.neg,
|
||||
lerp: Vec4.lerp,
|
||||
|
||||
length2: function ( a ) {
|
||||
return a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] + a[ 3 ] * a[ 3 ];
|
||||
},
|
||||
|
||||
zeroRotation: function ( q ) {
|
||||
return q[ 0 ] === 0.0 && q[ 1 ] === 0.0 && q[ 2 ] === 0.0 && q[ 3 ] === 1.0;
|
||||
},
|
||||
|
||||
length: function ( a ) {
|
||||
return Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] + a[ 3 ] * a[ 3 ] );
|
||||
},
|
||||
|
||||
makeRotate: function ( angle, x, y, z, result ) {
|
||||
var epsilon = 0.0000001;
|
||||
var length = Msqrt( x * x + y * y + z * z );
|
||||
if ( length < epsilon ) {
|
||||
return this.init( result );
|
||||
}
|
||||
|
||||
var inversenorm = 1.0 / length;
|
||||
var coshalfangle = Mcos( 0.5 * angle );
|
||||
var sinhalfangle = Msin( 0.5 * angle );
|
||||
|
||||
result[ 0 ] = x * sinhalfangle * inversenorm;
|
||||
result[ 1 ] = y * sinhalfangle * inversenorm;
|
||||
result[ 2 ] = z * sinhalfangle * inversenorm;
|
||||
result[ 3 ] = coshalfangle;
|
||||
return result;
|
||||
},
|
||||
|
||||
// http://physicsforgames.blogspot.fr/2010/02/quaternions.html
|
||||
// called quatBlend
|
||||
//
|
||||
// NLERP is supposed to be
|
||||
// - Commutative,
|
||||
// - NOT Constant velocity
|
||||
// - Torque minimal
|
||||
//
|
||||
// a and be must be normalized
|
||||
// (otherwise they're not rotation...)
|
||||
// t must be between 0 and 1
|
||||
nlerp: function ( t, a, b, r ) {
|
||||
var dot = this.dot( a, b );
|
||||
var at = 1.0 - t;
|
||||
|
||||
// shortest path
|
||||
if ( dot < 0.0 ) {
|
||||
|
||||
// negates directly b in the 4 equation
|
||||
// this.neg( b, r );
|
||||
r[ 0 ] = a[ 0 ] * at - b[ 0 ] * t;
|
||||
r[ 1 ] = a[ 1 ] * at - b[ 1 ] * t;
|
||||
r[ 2 ] = a[ 2 ] * at - b[ 2 ] * t;
|
||||
r[ 3 ] = a[ 3 ] * at - b[ 3 ] * t;
|
||||
|
||||
} else {
|
||||
r[ 0 ] = a[ 0 ] * at + b[ 0 ] * t;
|
||||
r[ 1 ] = a[ 1 ] * at + b[ 1 ] * t;
|
||||
r[ 2 ] = a[ 2 ] * at + b[ 2 ] * t;
|
||||
r[ 3 ] = a[ 3 ] * at + b[ 3 ] * t;
|
||||
}
|
||||
|
||||
return this.normalize( r, r );
|
||||
},
|
||||
|
||||
//
|
||||
// MUST READ on SLERP, NLERP, LOG-LERP
|
||||
// http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
|
||||
// with a slerp implementation (robust)
|
||||
//
|
||||
// MUST READ Howto enhance lerp, slerp and q normalize
|
||||
// http://number-none.com/product/Hacking%20Quaternions/
|
||||
//
|
||||
// MUST READ The book:
|
||||
// Essential Mathematics for Games and Interactive Applications page
|
||||
// ( from 10.6.1 Linear Interpolation to 10.6.3 Performance Improvements )
|
||||
//
|
||||
// SLERP is:
|
||||
// - NOT commutative
|
||||
// - constant velocity
|
||||
// - torque minimal
|
||||
//
|
||||
// so not to be used when blending multiple non ordered rotations
|
||||
// (as in multiple animation)
|
||||
//
|
||||
slerp: ( function () {
|
||||
|
||||
var epsilon = 0.00001;
|
||||
// a and be must be normalized
|
||||
// (otherwise they're not rotation...)
|
||||
// t must be between 0 and 1
|
||||
return function ( t, a, b, r ) {
|
||||
|
||||
var cos = this.dot( a, b );
|
||||
var invTB = 1.0;
|
||||
|
||||
// shortest path
|
||||
if ( cos < 0.0 ) {
|
||||
invTB = -1.0;
|
||||
cos = -cos;
|
||||
}
|
||||
|
||||
var ta, tb;
|
||||
if ( cos > 1.0 - epsilon ) {
|
||||
// negligible rotation: optimize by just a lerp
|
||||
// a line rather than a rotation.
|
||||
ta = 1.0 - t;
|
||||
tb = t;
|
||||
|
||||
} else {
|
||||
|
||||
var sin = Math.sqrt( 1.0 - cos * cos );
|
||||
|
||||
// which one is better ?
|
||||
|
||||
// Atan2:
|
||||
// sin != 0 && cos !f= 0
|
||||
// Atan2 returns the angle between -π and π radians (equivalent to -180 and 180 degrees)
|
||||
var angle = Math.atan2( sin, cos );
|
||||
// Acos:
|
||||
// need clamp(-1,1) on input Cos to avoid NaN but we make it lerp anyway
|
||||
// acos returns the angle between 0 and π radians (equivalent to 0 and 180 degrees)
|
||||
//var angle = Math.acos( cos ); / / 0 <= omega <= Pi( see man acos )
|
||||
|
||||
var oneOverSin = 1.0 / sin;
|
||||
ta = Math.sin( ( 1.0 - t ) * angle ) * oneOverSin;
|
||||
tb = Math.sin( t * angle ) * oneOverSin;
|
||||
}
|
||||
|
||||
tb *= invTB;
|
||||
|
||||
r[ 0 ] = a[ 0 ] * ta + b[ 0 ] * tb;
|
||||
r[ 1 ] = a[ 1 ] * ta + b[ 1 ] * tb;
|
||||
r[ 2 ] = a[ 2 ] * ta + b[ 2 ] * tb;
|
||||
r[ 3 ] = a[ 3 ] * ta + b[ 3 ] * tb;
|
||||
return r;
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
transformVec3: function ( q, a, result ) {
|
||||
var x = a[ 0 ];
|
||||
var y = a[ 1 ];
|
||||
var z = a[ 2 ];
|
||||
var qx = q[ 0 ];
|
||||
var qy = q[ 1 ];
|
||||
var qz = q[ 2 ];
|
||||
var qw = q[ 3 ];
|
||||
// calculate quat * vec
|
||||
var ix = qw * x + qy * z - qz * y;
|
||||
var iy = qw * y + qz * x - qx * z;
|
||||
var iz = qw * z + qx * y - qy * x;
|
||||
var iw = -qx * x - qy * y - qz * z;
|
||||
|
||||
// calculate result * inverse quat
|
||||
result[ 0 ] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
|
||||
result[ 1 ] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
|
||||
result[ 2 ] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
|
||||
return result;
|
||||
},
|
||||
|
||||
normalize: function ( q, qr ) {
|
||||
var div = 1.0 / this.length( q );
|
||||
qr[ 0 ] = q[ 0 ] * div;
|
||||
qr[ 1 ] = q[ 1 ] * div;
|
||||
qr[ 2 ] = q[ 2 ] * div;
|
||||
qr[ 3 ] = q[ 3 ] * div;
|
||||
return qr;
|
||||
},
|
||||
|
||||
// conjugate
|
||||
// we suppose to have unit quaternion
|
||||
conj: function ( a, result ) {
|
||||
result[ 0 ] = -a[ 0 ];
|
||||
result[ 1 ] = -a[ 1 ];
|
||||
result[ 2 ] = -a[ 2 ];
|
||||
result[ 3 ] = a[ 3 ];
|
||||
return result;
|
||||
},
|
||||
|
||||
// only if you don't have unit quaternion
|
||||
// otherwise use conjugate
|
||||
inverse: function ( a, result ) {
|
||||
var div = 1.0 / this.length2( a );
|
||||
this.conj( a, result );
|
||||
result[ 0 ] *= div;
|
||||
result[ 1 ] *= div;
|
||||
result[ 2 ] *= div;
|
||||
result[ 3 ] *= div;
|
||||
return result;
|
||||
},
|
||||
|
||||
// we suppose to have unit quaternion
|
||||
// multiply 2 quaternions
|
||||
mult: function ( a, b, result ) {
|
||||
var ax = a[ 0 ];
|
||||
var ay = a[ 1 ];
|
||||
var az = a[ 2 ];
|
||||
var aw = a[ 3 ];
|
||||
|
||||
var bx = b[ 0 ];
|
||||
var by = b[ 1 ];
|
||||
var bz = b[ 2 ];
|
||||
var bw = b[ 3 ];
|
||||
|
||||
result[ 0 ] = ax * bw + ay * bz - az * by + aw * bx;
|
||||
result[ 1 ] = -ax * bz + ay * bw + az * bx + aw * by;
|
||||
result[ 2 ] = ax * by - ay * bx + az * bw + aw * bz;
|
||||
result[ 3 ] = -ax * bx - ay * by - az * bz + aw * bw;
|
||||
return result;
|
||||
},
|
||||
|
||||
div: function ( a, b, result ) {
|
||||
var d = 1.0 / b;
|
||||
result[ 0 ] = a[ 0 ] * d;
|
||||
result[ 1 ] = a[ 1 ] * d;
|
||||
result[ 2 ] = a[ 2 ] * d;
|
||||
result[ 3 ] = a[ 3 ] * d;
|
||||
return result;
|
||||
},
|
||||
|
||||
exp: function ( a, res ) {
|
||||
var r = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
|
||||
var et = Math.exp( a[ 3 ] );
|
||||
var s = 0;
|
||||
if ( r > 0.00001 ) {
|
||||
s = et * Math.sin( r ) / r;
|
||||
}
|
||||
|
||||
res[ 0 ] = s * a[ 0 ];
|
||||
res[ 1 ] = s * a[ 1 ];
|
||||
res[ 2 ] = s * a[ 2 ];
|
||||
res[ 3 ] = et * Math.cos( r );
|
||||
return res;
|
||||
},
|
||||
|
||||
ln: function ( a, res ) {
|
||||
var n = a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ];
|
||||
var r = Math.sqrt( n );
|
||||
var t = 0;
|
||||
if ( r > 0.00001 ) {
|
||||
t = Math.atan2( r, a[ 3 ] ) / r;
|
||||
}
|
||||
|
||||
n += a[ 3 ] * a[ 3 ];
|
||||
res[ 0 ] = t * a[ 0 ];
|
||||
res[ 1 ] = t * a[ 1 ];
|
||||
res[ 2 ] = t * a[ 2 ];
|
||||
res[ 3 ] = 0.5 * Math.log( n );
|
||||
return res;
|
||||
},
|
||||
|
||||
|
||||
//http://theory.org/software/qfa/writeup/node12.html
|
||||
//http://www.ece.uwaterloo.ca/~dwharder/C++/CQOST/src/
|
||||
//http://willperone.net/Code/quaternion.php
|
||||
|
||||
// a is computeTangent(q1-1,q1,q2)
|
||||
// b is computeTangent(q2-1,q2,q2+1)
|
||||
squad: function ( t, q1, a, b, q2, r ) {
|
||||
var r1 = this.slerp( t, q1, q2 );
|
||||
var r2 = this.slerp( t, a, b );
|
||||
return this.slerp( 2.0 * t * ( 1.0 - t ), r1, r2, r );
|
||||
},
|
||||
|
||||
// qcur is current
|
||||
// q0 is qcur-1
|
||||
// q2 is qcur+1
|
||||
// compute tangent in of q1
|
||||
computeTangent: function ( q0, qcur, q2, r ) {
|
||||
|
||||
// first step
|
||||
var invq = this.inv( qcur );
|
||||
var qa = this.create();
|
||||
var qb = this.create();
|
||||
|
||||
this.mult( q2, invq, qa );
|
||||
this.ln( qa, qa );
|
||||
|
||||
this.mult( q0, invq, qb );
|
||||
this.ln( qb, qb );
|
||||
|
||||
this.add( qa, qb, qa );
|
||||
this.div( qa, -4.0, qa );
|
||||
this.exp( qa, qb );
|
||||
return this.mult( qb, qcur, r );
|
||||
},
|
||||
|
||||
makeRotateFromTo: function ( from, to, out ) {
|
||||
// Now let's get into the real stuff
|
||||
// Use "dot product plus one" as test as it can be re-used later on
|
||||
var dotProdPlus1 = 1.0 + vec3.dot( from, to );
|
||||
|
||||
// Check for degenerate case of full u-turn. Use epsilon for detection
|
||||
if ( dotProdPlus1 < 1e-7 ) {
|
||||
|
||||
// Get an orthogonal vector of the given vector
|
||||
// in a plane with maximum vector coordinates.
|
||||
// Then use it as quaternion axis with pi angle
|
||||
// Trick is to realize one value at least is >0.6 for a normalized vector.
|
||||
var x = from[ 0 ];
|
||||
var y = from[ 1 ];
|
||||
var z = from[ 2 ];
|
||||
var norm;
|
||||
if ( Math.abs( x ) < 0.6 ) {
|
||||
norm = Math.sqrt( 1.0 - x * x );
|
||||
out[ 1 ] = z / norm;
|
||||
out[ 2 ] = -y / norm;
|
||||
out[ 0 ] = out[ 3 ] = 0.0;
|
||||
} else if ( Math.abs( y ) < 0.6 ) {
|
||||
norm = Math.sqrt( 1.0 - y * y );
|
||||
out[ 0 ] = -z / norm;
|
||||
out[ 2 ] = x / norm;
|
||||
out[ 1 ] = out[ 3 ] = 0.0;
|
||||
} else {
|
||||
norm = Math.sqrt( 1.0 - z * z );
|
||||
out[ 0 ] = y / norm;
|
||||
out[ 1 ] = -x / norm;
|
||||
out[ 2 ] = out[ 3 ] = 0.0;
|
||||
}
|
||||
} else {
|
||||
// Find the shortest angle quaternion that transforms normalized vectors
|
||||
// into one other. Formula is still valid when vectors are colinear
|
||||
|
||||
var s = Math.sqrt( 0.5 * dotProdPlus1 );
|
||||
vec3.cross( out, from, to );
|
||||
var f = 0.5 / s;
|
||||
out[ 0 ] *= f;
|
||||
out[ 1 ] *= f;
|
||||
out[ 2 ] *= f;
|
||||
out[ 3 ] = s;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Quat.identity = Quat.create();
|
||||
|
||||
module.exports = Quat;
|
|
@ -1,67 +0,0 @@
|
|||
'use strict';
|
||||
var osgMath = require( 'osg/math' );
|
||||
var glm = require( 'osg/glMatrix' );
|
||||
var vec2 = glm.vec2;
|
||||
|
||||
/** @class Vec2 Operations */
|
||||
var Vec2 = {
|
||||
|
||||
create: vec2.create,
|
||||
createAndSet: vec2.fromValues,
|
||||
|
||||
copy: function ( a, r ) {
|
||||
return vec2.copy( r, a );
|
||||
},
|
||||
|
||||
set: function ( a, b, r ) {
|
||||
return vec2.set( r, a, b );
|
||||
},
|
||||
|
||||
valid: function ( a ) {
|
||||
if ( osgMath.isNaN( a[ 0 ] ) ) return false;
|
||||
if ( osgMath.isNaN( a[ 1 ] ) ) return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
mult: function ( a, b, r ) {
|
||||
r[ 0 ] = a[ 0 ] * b;
|
||||
r[ 1 ] = a[ 1 ] * b;
|
||||
return r;
|
||||
},
|
||||
|
||||
length2: vec2.sqrLen,
|
||||
length: vec2.len,
|
||||
|
||||
distance2: function ( a, b ) {
|
||||
return vec2.sqrDist( b, a );
|
||||
},
|
||||
|
||||
distance: function ( a, b ) {
|
||||
return vec2.dist( b, a );
|
||||
},
|
||||
|
||||
normalize: function ( a, r ) {
|
||||
return vec2.normalize( r, a );
|
||||
},
|
||||
|
||||
dot: vec2.dot,
|
||||
|
||||
sub: function ( a, b, r ) {
|
||||
return vec2.sub( r, a, b );
|
||||
},
|
||||
|
||||
add: function ( a, b, r ) {
|
||||
return vec2.add( r, a, b );
|
||||
},
|
||||
|
||||
neg: function ( a, r ) {
|
||||
return vec2.negate( r, a );
|
||||
},
|
||||
|
||||
lerp: function ( t, a, b, r ) {
|
||||
return vec2.lerp( r, a, b, t );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = Vec2;
|
|
@ -1,85 +0,0 @@
|
|||
'use strict';
|
||||
var osgMath = require( 'osg/math' );
|
||||
var glm = require( 'osg/glMatrix' );
|
||||
var vec3 = glm.vec3;
|
||||
|
||||
/** @class Vec3 Operations */
|
||||
var Vec3 = {
|
||||
|
||||
create: vec3.create,
|
||||
createAndSet: vec3.fromValues,
|
||||
|
||||
init: function ( a ) {
|
||||
return vec3.set( a, 0.0, 0.0, 0.0 );
|
||||
},
|
||||
|
||||
set: function ( a, b, c, r ) {
|
||||
return vec3.set( r, a, b, c );
|
||||
},
|
||||
|
||||
copy: function ( a, r ) {
|
||||
return vec3.copy( r, a );
|
||||
},
|
||||
|
||||
cross: function ( a, b, r ) {
|
||||
return vec3.cross( r, a, b );
|
||||
},
|
||||
|
||||
valid: function ( a ) {
|
||||
if ( osgMath.isNaN( a[ 0 ] ) ) return false;
|
||||
if ( osgMath.isNaN( a[ 1 ] ) ) return false;
|
||||
if ( osgMath.isNaN( a[ 2 ] ) ) return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
mult: function ( a, b, r ) {
|
||||
r[ 0 ] = a[ 0 ] * b;
|
||||
r[ 1 ] = a[ 1 ] * b;
|
||||
r[ 2 ] = a[ 2 ] * b;
|
||||
return r;
|
||||
},
|
||||
|
||||
length2: vec3.sqrLen,
|
||||
length: vec3.len,
|
||||
|
||||
distance2: function ( a, b ) {
|
||||
return vec3.sqrDist( b, a );
|
||||
},
|
||||
|
||||
distance: function ( a, b ) {
|
||||
return vec3.dist( b, a );
|
||||
},
|
||||
|
||||
normalize: function ( a, r ) {
|
||||
return vec3.normalize( r, a );
|
||||
},
|
||||
|
||||
dot: vec3.dot,
|
||||
|
||||
sub: function ( a, b, r ) {
|
||||
return vec3.sub( r, a, b );
|
||||
},
|
||||
|
||||
add: function ( a, b, r ) {
|
||||
return vec3.add( r, a, b );
|
||||
},
|
||||
|
||||
neg: function ( a, r ) {
|
||||
return vec3.negate( r, a );
|
||||
},
|
||||
|
||||
lerp: function ( t, a, b, r ) {
|
||||
return vec3.lerp( r, a, b, t );
|
||||
},
|
||||
|
||||
equal: function ( a, b ) {
|
||||
return vec3.exactEquals( a, b );
|
||||
}
|
||||
};
|
||||
|
||||
Vec3.zero = Vec3.create();
|
||||
Vec3.one = Vec3.createAndSet( 1.0, 1.0, 1.0 );
|
||||
Vec3.infinity = Vec3.createAndSet( Infinity, Infinity, Infinity );
|
||||
Vec3.negativeInfinity = Vec3.createAndSet( -Infinity, -Infinity, -Infinity );
|
||||
|
||||
module.exports = Vec3;
|
|
@ -1,50 +0,0 @@
|
|||
'use strict';
|
||||
var glm = require( 'osg/glMatrix' );
|
||||
var vec4 = glm.vec4;
|
||||
|
||||
/** @class Vec4 Operations */
|
||||
var Vec4 = {
|
||||
|
||||
create: vec4.create,
|
||||
createAndSet: vec4.fromValues,
|
||||
|
||||
init: function ( a ) {
|
||||
return vec4.set( a, 0.0, 0.0, 0.0, 0.0 );
|
||||
},
|
||||
|
||||
set: function ( a, b, c, d, r ) {
|
||||
return vec4.set( r, a, b, c, d );
|
||||
},
|
||||
|
||||
dot: vec4.dot,
|
||||
|
||||
copy: function ( a, r ) {
|
||||
return vec4.copy( r, a );
|
||||
},
|
||||
|
||||
sub: function ( a, b, r ) {
|
||||
return vec4.sub( r, a, b );
|
||||
},
|
||||
|
||||
mult: function ( a, b, r ) {
|
||||
r[ 0 ] = a[ 0 ] * b;
|
||||
r[ 1 ] = a[ 1 ] * b;
|
||||
r[ 2 ] = a[ 2 ] * b;
|
||||
r[ 3 ] = a[ 3 ] * b;
|
||||
return r;
|
||||
},
|
||||
|
||||
add: function ( a, b, r ) {
|
||||
return vec4.add( r, a, b );
|
||||
},
|
||||
|
||||
neg: function ( a, r ) {
|
||||
return vec4.negate( r, a );
|
||||
},
|
||||
|
||||
lerp: function ( t, a, b, r ) {
|
||||
return vec4.lerp( r, a, b, t );
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Vec4;
|
|
@ -1,537 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var mth = require( 'osg/math' );
|
||||
var glm = require( 'gl-matrix' );
|
||||
var config = require( '../config.js' );
|
||||
glm.glMatrix.setMatrixArrayType( config.ArrayType );
|
||||
glm.glMatrix.EPSILON = 1e-9;
|
||||
|
||||
|
||||
var vec2 = glm.vec2;
|
||||
var vec3 = glm.vec3;
|
||||
var vec4 = glm.vec4;
|
||||
var mat4 = glm.mat4;
|
||||
var quat = glm.quat;
|
||||
|
||||
// osg vec3 additions
|
||||
|
||||
vec3.create32 = function () {
|
||||
return new Float32Array( 3 );
|
||||
};
|
||||
|
||||
vec3.create64 = function () {
|
||||
return new Float64Array( 3 );
|
||||
};
|
||||
|
||||
vec3.fromValues32 = function ( a, b, c ) {
|
||||
var out = new Float32Array( 3 );
|
||||
out[ 0 ] = a;
|
||||
out[ 1 ] = b;
|
||||
out[ 2 ] = c;
|
||||
return out;
|
||||
};
|
||||
|
||||
vec3.fromValues64 = function ( a, b, c ) {
|
||||
var out = new Float64Array( 3 );
|
||||
out[ 0 ] = a;
|
||||
out[ 1 ] = b;
|
||||
out[ 2 ] = c;
|
||||
return out;
|
||||
};
|
||||
|
||||
vec3.init = function ( out ) {
|
||||
return vec3.set( out, 0.0, 0.0, 0.0 );
|
||||
};
|
||||
|
||||
vec3.transformMat4R = function ( out, v, m ) {
|
||||
out[ 0 ] = m[ 0 ] * v[ 0 ] + m[ 1 ] * v[ 1 ] + m[ 2 ] * v[ 2 ];
|
||||
out[ 1 ] = m[ 4 ] * v[ 0 ] + m[ 5 ] * v[ 1 ] + m[ 6 ] * v[ 2 ];
|
||||
out[ 2 ] = m[ 8 ] * v[ 0 ] + m[ 9 ] * v[ 1 ] + m[ 10 ] * v[ 2 ];
|
||||
};
|
||||
|
||||
vec3.valid = function ( a ) {
|
||||
if ( mth.isNaN( a[ 0 ] ) ) return false;
|
||||
if ( mth.isNaN( a[ 1 ] ) ) return false;
|
||||
if ( mth.isNaN( a[ 2 ] ) ) return false;
|
||||
return true;
|
||||
};
|
||||
vec3.neg = vec3.negate;
|
||||
vec3.ZERO = vec3.create();
|
||||
vec3.ONE = vec3.fromValues( 1.0, 1.0, 1.0 );
|
||||
vec3.INFINITY = vec3.fromValues( Infinity, Infinity, Infinity );
|
||||
vec3.NEGATIVE_INFINITY = vec3.fromValues( -Infinity, -Infinity, -Infinity );
|
||||
|
||||
// osg vec2 additions
|
||||
|
||||
vec2.create32 = function () {
|
||||
return new Float32Array( 2 );
|
||||
};
|
||||
|
||||
vec2.create64 = function () {
|
||||
return new Float64Array( 2 );
|
||||
};
|
||||
|
||||
vec2.fromValues32 = function ( a, b ) {
|
||||
var out = new Float32Array( 2 );
|
||||
out[ 0 ] = a;
|
||||
out[ 1 ] = b;
|
||||
return out;
|
||||
};
|
||||
|
||||
vec2.fromValues64 = function ( a, b ) {
|
||||
var out = new Float64Array( 2 );
|
||||
out[ 0 ] = a;
|
||||
out[ 1 ] = b;
|
||||
return out;
|
||||
};
|
||||
|
||||
vec2.init = function ( out ) {
|
||||
return vec2.set( out, 0.0, 0.0 );
|
||||
};
|
||||
|
||||
vec2.valid = function ( a ) {
|
||||
if ( mth.isNaN( a[ 0 ] ) ) return false;
|
||||
if ( mth.isNaN( a[ 1 ] ) ) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
vec2.ZERO = vec2.create();
|
||||
vec2.ONE = vec2.fromValues( 1.0, 1.0 );
|
||||
vec2.INFINITY = vec2.fromValues( Infinity, Infinity );
|
||||
vec2.NEGATIVE_INFINITY = vec2.fromValues( -Infinity, -Infinity );
|
||||
|
||||
// osg vec4 additions
|
||||
|
||||
vec4.create32 = function () {
|
||||
return new Float32Array( 4 );
|
||||
};
|
||||
|
||||
vec4.create64 = function () {
|
||||
return new Float64Array( 4 );
|
||||
};
|
||||
|
||||
vec4.fromValues32 = function ( a, b, c, d ) {
|
||||
var out = new Float32Array( 4 );
|
||||
out[ 0 ] = a;
|
||||
out[ 1 ] = b;
|
||||
out[ 2 ] = c;
|
||||
out[ 3 ] = d;
|
||||
return out;
|
||||
};
|
||||
|
||||
vec4.fromValues64 = function ( a, b, c, d ) {
|
||||
var out = new Float64Array( 4 );
|
||||
out[ 0 ] = a;
|
||||
out[ 1 ] = b;
|
||||
out[ 2 ] = c;
|
||||
out[ 3 ] = d;
|
||||
return out;
|
||||
};
|
||||
|
||||
vec4.init = function ( out ) {
|
||||
return vec4.set( out, 0.0, 0.0, 0.0, 0.0 );
|
||||
};
|
||||
|
||||
vec4.valid = function ( a ) {
|
||||
if ( mth.isNaN( a[ 0 ] ) ) return false;
|
||||
if ( mth.isNaN( a[ 1 ] ) ) return false;
|
||||
if ( mth.isNaN( a[ 2 ] ) ) return false;
|
||||
if ( mth.isNaN( a[ 3 ] ) ) return false;
|
||||
return true;
|
||||
};
|
||||
vec4.neg = vec4.negate;
|
||||
vec4.ZERO = vec4.create();
|
||||
vec4.ONE = vec4.fromValues( 1.0, 1.0, 1.0, 1.0 );
|
||||
vec4.INFINITY = vec4.fromValues( Infinity, Infinity, Infinity, Infinity );
|
||||
vec4.NEGATIVE_INFINITY = vec4.fromValues( -Infinity, -Infinity, -Infinity, -Infinity );
|
||||
|
||||
|
||||
// quat
|
||||
|
||||
quat.IDENTITY = quat.create();
|
||||
|
||||
quat.zeroRotation = function ( q ) {
|
||||
return q[ 0 ] === 0.0 && q[ 1 ] === 0.0 && q[ 2 ] === 0.0 && q[ 3 ] === 1.0;
|
||||
};
|
||||
|
||||
quat.create32 = function () {
|
||||
var out = new Float32Array( 4 );
|
||||
out[ 3 ] = 1.0;
|
||||
return out;
|
||||
};
|
||||
|
||||
quat.create64 = function () {
|
||||
var out = new Float64Array( 4 );
|
||||
out[ 3 ] = 1.0;
|
||||
return out;
|
||||
};
|
||||
|
||||
quat.fromValues32 = vec4.fromValues32;
|
||||
quat.fromValues64 = vec4.fromValues64;
|
||||
quat.init = quat.identity;
|
||||
|
||||
// http://physicsforgames.blogspot.fr/2010/02/quaternions.html
|
||||
// called quatBlend
|
||||
//
|
||||
// NLERP is supposed to be
|
||||
// - Commutative,
|
||||
// - NOT Constant velocity
|
||||
// - Torque minimal
|
||||
//
|
||||
// a and be must be normalized
|
||||
// (otherwise they're not rotation...)
|
||||
// t must be between 0 and 1
|
||||
quat.nlerp = function ( out, a, b, t ) {
|
||||
var ax = a[ 0 ],
|
||||
ay = a[ 1 ],
|
||||
az = a[ 2 ],
|
||||
aw = a[ 3 ],
|
||||
bx = b[ 0 ],
|
||||
by = b[ 1 ],
|
||||
bz = b[ 2 ],
|
||||
bw = b[ 3 ];
|
||||
var dot = ax * bx + ay * by + az * bz + aw * bw;
|
||||
var at = 1.0 - t;
|
||||
var outx, outy, outz, outw;
|
||||
// shortest path
|
||||
if ( dot < 0.0 ) {
|
||||
|
||||
// negates directly b in the 4 equation
|
||||
// this.neg( b, r );
|
||||
outx = ax * at - bx * t;
|
||||
outy = ay * at - by * t;
|
||||
outz = az * at - bz * t;
|
||||
outw = aw * at - bw * t;
|
||||
|
||||
} else {
|
||||
outx = ax * at + bx * t;
|
||||
outy = ay * at + by * t;
|
||||
outz = az * at + bz * t;
|
||||
outw = aw * at + bw * t;
|
||||
}
|
||||
|
||||
var invLen = 1.0 / Math.sqrt( outx * outx + outy * outy + outz * outz + outw * outw );
|
||||
out[ 0 ] = outx * invLen;
|
||||
out[ 1 ] = outy * invLen;
|
||||
out[ 2 ] = outz * invLen;
|
||||
out[ 3 ] = outw * invLen;
|
||||
return out;
|
||||
};
|
||||
|
||||
// MUST READ on SLERP, NLERP, LOG-LERP
|
||||
// http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
|
||||
// with a slerp implementation (robust)
|
||||
//
|
||||
// MUST READ Howto enhance lerp, slerp and q normalize
|
||||
// http://number-none.com/product/Hacking%20Quaternions/
|
||||
//
|
||||
// MUST READ The book:
|
||||
// Essential Mathematics for Games and Interactive Applications page
|
||||
// ( from 10.6.1 Linear Interpolation to 10.6.3 Performance Improvements )
|
||||
//
|
||||
// SLERP is:
|
||||
// - NOT commutative
|
||||
// - constant velocity
|
||||
// - torque minimal
|
||||
//
|
||||
// so not to be used when blending multiple non ordered rotations
|
||||
// (as in multiple animation)
|
||||
//
|
||||
// slerp see glMatrix implementation
|
||||
|
||||
|
||||
// mat4 additions
|
||||
mat4.IDENTITY = mat4.create();
|
||||
|
||||
mat4.create32 = function () {
|
||||
var out = new Float32Array( 16 );
|
||||
out[ 0 ] = out[ 5 ] = out[ 10 ] = out[ 15 ] = 1.0;
|
||||
return out;
|
||||
};
|
||||
|
||||
mat4.create64 = function () {
|
||||
var out = new Float64Array( 16 );
|
||||
out[ 0 ] = out[ 5 ] = out[ 10 ] = out[ 15 ] = 1.0;
|
||||
return out;
|
||||
};
|
||||
|
||||
mat4.setTranslation = function ( out, a ) {
|
||||
out[ 12 ] = a[ 0 ];
|
||||
out[ 13 ] = a[ 1 ];
|
||||
out[ 14 ] = a[ 2 ];
|
||||
return out;
|
||||
};
|
||||
|
||||
mat4.getFrustum = function ( out, matrix ) {
|
||||
var right = 0.0;
|
||||
var left = 0.0;
|
||||
var top = 0.0;
|
||||
var bottom = 0.0;
|
||||
var zNear, zFar;
|
||||
|
||||
if ( matrix[ 0 * 4 + 3 ] !== 0.0 || matrix[ 1 * 4 + 3 ] !== 0.0 || matrix[ 2 * 4 + 3 ] !== -1.0 || matrix[ 3 * 4 + 3 ] !== 0.0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// note: near and far must be used inside this method instead of zNear and zFar
|
||||
// because zNear and zFar are references and they may point to the same variable.
|
||||
var tempNear = matrix[ 3 * 4 + 2 ] / ( matrix[ 2 * 4 + 2 ] - 1.0 );
|
||||
var tempFar = matrix[ 3 * 4 + 2 ] / ( 1.0 + matrix[ 2 * 4 + 2 ] );
|
||||
|
||||
left = tempNear * ( matrix[ 2 * 4 ] - 1.0 ) / matrix[ 0 ];
|
||||
right = tempNear * ( 1.0 + matrix[ 2 * 4 ] ) / matrix[ 0 ];
|
||||
|
||||
top = tempNear * ( 1.0 + matrix[ 2 * 4 + 1 ] ) / matrix[ 1 * 4 + 1 ];
|
||||
bottom = tempNear * ( matrix[ 2 * 4 + 1 ] - 1.0 ) / matrix[ 1 * 4 + 1 ];
|
||||
|
||||
zNear = tempNear;
|
||||
zFar = tempFar;
|
||||
|
||||
out.left = left;
|
||||
out.right = right;
|
||||
out.top = top;
|
||||
out.bottom = bottom;
|
||||
out.zNear = zNear;
|
||||
out.zFar = zFar;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
mat4.getPerspective = ( function () {
|
||||
var c = {
|
||||
right: 0,
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
zNear: 0,
|
||||
zFar: 0
|
||||
};
|
||||
return function ( out, matrix ) {
|
||||
// get frustum and compute results
|
||||
var r = mat4.getFrustum( c, matrix );
|
||||
if ( r ) {
|
||||
out.fovy = 180 / Math.PI * ( Math.atan( c.top / c.zNear ) - Math.atan( c.bottom / c.zNear ) );
|
||||
out.aspectRatio = ( c.right - c.left ) / ( c.top - c.bottom );
|
||||
}
|
||||
out.zNear = c.zNear;
|
||||
out.zFar = c.zFar;
|
||||
return out;
|
||||
};
|
||||
} )();
|
||||
|
||||
mat4.getLookAt = ( function () {
|
||||
var inv = mat4.create();
|
||||
var v1 = vec3.create();
|
||||
var v2 = vec3.fromValues( 0.0, 1.0, 0.0 );
|
||||
var v3 = vec3.fromValues( 0.0, 0.0, -1.0 );
|
||||
|
||||
return function ( eye, center, up, matrix, distance ) {
|
||||
|
||||
var d = distance !== undefined ? distance : 1.0;
|
||||
mat4.invert( inv, matrix );
|
||||
vec3.transformMat4( eye, v1, inv );
|
||||
vec3.transformMat4R( up, v2, matrix );
|
||||
vec3.transformMat4R( center, v3, matrix );
|
||||
vec3.normalize( center, center );
|
||||
vec3.add( center, vec3.scale( v1, center, d ), eye );
|
||||
};
|
||||
} )();
|
||||
|
||||
mat4.getFrustumPlanes = ( function () {
|
||||
|
||||
var mvp = mat4.create();
|
||||
|
||||
return function ( out, projection, view, withNearFar ) {
|
||||
mat4.mul( mvp, projection, view );
|
||||
|
||||
var computeNearFar = !!withNearFar;
|
||||
|
||||
// Right clipping plane.
|
||||
var right = out[ 0 ];
|
||||
right[ 0 ] = mvp[ 3 ] - mvp[ 0 ];
|
||||
right[ 1 ] = mvp[ 7 ] - mvp[ 4 ];
|
||||
right[ 2 ] = mvp[ 11 ] - mvp[ 8 ];
|
||||
right[ 3 ] = mvp[ 15 ] - mvp[ 12 ];
|
||||
|
||||
// Left clipping plane.
|
||||
var left = out[ 1 ];
|
||||
left[ 0 ] = mvp[ 3 ] + mvp[ 0 ];
|
||||
left[ 1 ] = mvp[ 7 ] + mvp[ 4 ];
|
||||
left[ 2 ] = mvp[ 11 ] + mvp[ 8 ];
|
||||
left[ 3 ] = mvp[ 15 ] + mvp[ 12 ];
|
||||
|
||||
// Bottom clipping plane.
|
||||
var bottom = out[ 2 ];
|
||||
bottom[ 0 ] = mvp[ 3 ] + mvp[ 1 ];
|
||||
bottom[ 1 ] = mvp[ 7 ] + mvp[ 5 ];
|
||||
bottom[ 2 ] = mvp[ 11 ] + mvp[ 9 ];
|
||||
bottom[ 3 ] = mvp[ 15 ] + mvp[ 13 ];
|
||||
|
||||
// Top clipping plane.
|
||||
var top = out[ 3 ];
|
||||
top[ 0 ] = mvp[ 3 ] - mvp[ 1 ];
|
||||
top[ 1 ] = mvp[ 7 ] - mvp[ 5 ];
|
||||
top[ 2 ] = mvp[ 11 ] - mvp[ 9 ];
|
||||
top[ 3 ] = mvp[ 15 ] - mvp[ 13 ];
|
||||
|
||||
var nbPlanes = 4;
|
||||
if ( computeNearFar ) {
|
||||
nbPlanes = 6;
|
||||
// Far clipping plane.
|
||||
var far = out[ 4 ];
|
||||
far[ 0 ] = mvp[ 3 ] - mvp[ 2 ];
|
||||
far[ 1 ] = mvp[ 7 ] - mvp[ 6 ];
|
||||
far[ 2 ] = mvp[ 11 ] - mvp[ 10 ];
|
||||
far[ 3 ] = mvp[ 15 ] - mvp[ 14 ];
|
||||
|
||||
// Near clipping plane.
|
||||
var near = out[ 5 ];
|
||||
near[ 0 ] = mvp[ 3 ] + mvp[ 2 ];
|
||||
near[ 1 ] = mvp[ 7 ] + mvp[ 6 ];
|
||||
near[ 2 ] = mvp[ 11 ] + mvp[ 10 ];
|
||||
near[ 3 ] = mvp[ 15 ] + mvp[ 14 ];
|
||||
}
|
||||
|
||||
//Normalize the planes, from osg code
|
||||
for ( var i = 0; i < nbPlanes; i++ ) {
|
||||
var p = out[ i ];
|
||||
// multiply the coefficients of the plane equation with a constant factor so that the equation a^2+b^2+c^2 = 1 holds.
|
||||
var inv = 1.0 / Math.sqrt( p[ 0 ] * p[ 0 ] + p[ 1 ] * p[ 1 ] + p[ 2 ] * p[ 2 ] );
|
||||
p[ 0 ] *= inv;
|
||||
p[ 1 ] *= inv;
|
||||
p[ 2 ] *= inv;
|
||||
p[ 3 ] *= inv;
|
||||
}
|
||||
|
||||
};
|
||||
} )();
|
||||
|
||||
// better precison
|
||||
// no far clipping artifacts.
|
||||
// no reason not to use.
|
||||
// Tightening the Precision of Perspective Rendering
|
||||
//http://www.geometry.caltech.edu/pubs/UD12.pdf
|
||||
// drop-in, just remove the one below, and rename this one
|
||||
mat4.infiniteFrustum = function ( out, left, right, bottom, top, znear ) {
|
||||
var X = 2.0 * znear / ( right - left );
|
||||
var Y = 2.0 * znear / ( top - bottom );
|
||||
var A = ( right + left ) / ( right - left );
|
||||
var B = ( top + bottom ) / ( top - bottom );
|
||||
var C = -1.0;
|
||||
out[ 0 ] = X;
|
||||
out[ 1 ] = 0.0;
|
||||
out[ 2 ] = 0.0;
|
||||
out[ 3 ] = 0.0;
|
||||
|
||||
out[ 4 ] = 0.0;
|
||||
out[ 5 ] = Y;
|
||||
out[ 6 ] = 0.0;
|
||||
out[ 7 ] = 0.0;
|
||||
|
||||
out[ 8 ] = A;
|
||||
out[ 9 ] = B;
|
||||
out[ 10 ] = C;
|
||||
out[ 11 ] = -1.0;
|
||||
|
||||
out[ 12 ] = 0.0;
|
||||
out[ 13 ] = 0.0;
|
||||
out[ 14 ] = -2.0 * znear;
|
||||
out[ 15 ] = 0.0;
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
mat4.lookAtDirection = ( function () {
|
||||
var s = vec3.create();
|
||||
var u = vec3.create();
|
||||
var neg = vec3.create();
|
||||
|
||||
return function ( out, eye, eyeDir, up ) {
|
||||
var f = eyeDir;
|
||||
vec3.cross( s, f, up );
|
||||
vec3.normalize( s, s );
|
||||
|
||||
vec3.cross( u, s, f );
|
||||
vec3.normalize( u, u );
|
||||
|
||||
// s[0], u[0], -f[0], 0.0,
|
||||
// s[1], u[1], -f[1], 0.0,
|
||||
// s[2], u[2], -f[2], 0.0,
|
||||
// 0, 0, 0, 1.0
|
||||
|
||||
out[ 0 ] = s[ 0 ];
|
||||
out[ 1 ] = u[ 0 ];
|
||||
out[ 2 ] = -f[ 0 ];
|
||||
out[ 3 ] = 0.0;
|
||||
out[ 4 ] = s[ 1 ];
|
||||
out[ 5 ] = u[ 1 ];
|
||||
out[ 6 ] = -f[ 1 ];
|
||||
out[ 7 ] = 0.0;
|
||||
out[ 8 ] = s[ 2 ];
|
||||
out[ 9 ] = u[ 2 ];
|
||||
out[ 10 ] = -f[ 2 ];
|
||||
out[ 11 ] = 0.0;
|
||||
out[ 12 ] = 0;
|
||||
out[ 13 ] = 0;
|
||||
out[ 14 ] = 0;
|
||||
out[ 15 ] = 1.0;
|
||||
|
||||
return mat4.translate( out, out, vec3.neg( neg, eye ) );
|
||||
};
|
||||
} )();
|
||||
|
||||
mat4.getScale = ( function () {
|
||||
var sx = vec3.create();
|
||||
var sy = vec3.create();
|
||||
var sz = vec3.create();
|
||||
return function ( out, matrix ) {
|
||||
sx[ 0 ] = matrix[ 0 ];
|
||||
sx[ 1 ] = matrix[ 4 ];
|
||||
sx[ 2 ] = matrix[ 8 ];
|
||||
sy[ 0 ] = matrix[ 1 ];
|
||||
sy[ 1 ] = matrix[ 5 ];
|
||||
sy[ 2 ] = matrix[ 9 ];
|
||||
sz[ 0 ] = matrix[ 2 ];
|
||||
sz[ 1 ] = matrix[ 6 ];
|
||||
sz[ 2 ] = matrix[ 10 ];
|
||||
|
||||
out[ 0 ] = vec3.length( sx );
|
||||
out[ 1 ] = vec3.length( sy );
|
||||
out[ 2 ] = vec3.length( sz );
|
||||
return out;
|
||||
};
|
||||
} )();
|
||||
|
||||
mat4.getSqrScale = ( function () {
|
||||
var sx = vec3.create();
|
||||
var sy = vec3.create();
|
||||
var sz = vec3.create();
|
||||
return function ( out, matrix ) {
|
||||
sx[ 0 ] = matrix[ 0 ];
|
||||
sx[ 1 ] = matrix[ 4 ];
|
||||
sx[ 2 ] = matrix[ 8 ];
|
||||
sy[ 0 ] = matrix[ 1 ];
|
||||
sy[ 1 ] = matrix[ 5 ];
|
||||
sy[ 2 ] = matrix[ 9 ];
|
||||
sz[ 0 ] = matrix[ 2 ];
|
||||
sz[ 1 ] = matrix[ 6 ];
|
||||
sz[ 2 ] = matrix[ 10 ];
|
||||
|
||||
out[ 0 ] = vec3.sqrLen( sx );
|
||||
out[ 1 ] = vec3.sqrLen( sy );
|
||||
out[ 2 ] = vec3.sqrLen( sz );
|
||||
return out;
|
||||
};
|
||||
} )();
|
||||
|
||||
var glmRotate = mat4.rotate;
|
||||
mat4.rotate = function ( out, a, rad, axis ) {
|
||||
return glmRotate( out, a, rad, axis ) || mat4.identity( out );
|
||||
};
|
||||
|
||||
var glmFromRotate = mat4.fromRotation;
|
||||
mat4.fromRotation = function ( out, rad, axis ) {
|
||||
return glmFromRotate( out, rad, axis ) || mat4.identity( out );
|
||||
};
|
||||
|
||||
module.exports = glm;
|
|
@ -1,25 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var clamp = function ( x, min, max ) {
|
||||
// http://jsperf.com/math-clamp
|
||||
// http://jsperf.com/clamping-methods/2
|
||||
return Math.min( max, Math.max( min, x ) );
|
||||
};
|
||||
|
||||
var smoothStep = function ( edge0, edge1, x ) {
|
||||
var t = clamp( ( x - edge0 ) / ( edge1 - edge0 ), 0.0, 1.0 );
|
||||
return t * t * ( 3.0 - 2.0 * t );
|
||||
};
|
||||
|
||||
// native isNaN is slow (e.g: https://jsperf.com/isnan-performance/2)
|
||||
// note : native isNaN will return true for undefined but
|
||||
// this function assume that x is a number
|
||||
var fastIsNaN = function ( x ) {
|
||||
return x !== x;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
clamp: clamp,
|
||||
smoothStep: smoothStep,
|
||||
isNaN: fastIsNaN
|
||||
};
|
|
@ -1,108 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var Notify = {};
|
||||
|
||||
// must be uppercase and match loggers
|
||||
Notify.DEBUG = 0;
|
||||
Notify.INFO = 1;
|
||||
Notify.NOTICE = Notify.LOG = 2;
|
||||
Notify.WARN = 3;
|
||||
Notify.ERROR = 4;
|
||||
|
||||
Notify.console = window.console;
|
||||
|
||||
/** logging with readability in mind.
|
||||
* @param { level } what severity is that log (gives text color too )
|
||||
* @param { str } actual log text
|
||||
* @param { fold } sometimes you want to hide looooong text
|
||||
*/
|
||||
function logSub( level, str ) {
|
||||
|
||||
if ( !Notify.console ) return;
|
||||
|
||||
Notify.console[ level ]( str );
|
||||
if ( Notify.traceLogCall && level !== 'error' ) console.trace();
|
||||
|
||||
}
|
||||
|
||||
function logSubFold( level, title, str ) {
|
||||
|
||||
if ( !Notify.console ) return;
|
||||
|
||||
if ( Notify.console.groupCollapsed ) Notify.console.groupCollapsed( title );
|
||||
Notify.console[ level ]( str );
|
||||
if ( Notify.traceLogCall && level !== 'error' ) console.trace();
|
||||
|
||||
if ( Notify.console.groupEnd ) Notify.console.groupEnd();
|
||||
|
||||
}
|
||||
|
||||
function unFlattenMatrix( m, rowMajor ) {
|
||||
if ( rowMajor ) {
|
||||
return [ m.slice( 0, 4 ), m.slice( 4, 8 ), m.slice( 8, 12 ), m.slice( 12, 16 ) ];
|
||||
}
|
||||
|
||||
return [
|
||||
[ m[ 0 ], m[ 4 ], m[ 8 ], m[ 12 ] ],
|
||||
[ m[ 1 ], m[ 5 ], m[ 9 ], m[ 13 ] ],
|
||||
[ m[ 2 ], m[ 6 ], m[ 10 ], m[ 14 ] ],
|
||||
[ m[ 3 ], m[ 7 ], m[ 11 ], m[ 15 ] ]
|
||||
];
|
||||
}
|
||||
|
||||
function logMatrix( m, rowMajor ) {
|
||||
if ( Notify.console.table )
|
||||
logSub( 'table', unFlattenMatrix( m, rowMajor ) );
|
||||
}
|
||||
|
||||
function logMatrixFold( title, m, rowMajor ) {
|
||||
if ( Notify.console.table )
|
||||
logSubFold( 'table', title, unFlattenMatrix( m, rowMajor ) );
|
||||
}
|
||||
|
||||
var levelEntries = [ 'log', 'info', 'warn', 'error', 'debug' ];
|
||||
var loggers = {};
|
||||
for ( var i = 0; i < levelEntries.length; ++i ) {
|
||||
var level = levelEntries[ i ];
|
||||
loggers[ level ] = logSub.bind( Notify, level );
|
||||
loggers[ level + 'Fold' ] = logSubFold.bind( Notify, level );
|
||||
loggers[ level + 'Matrix' ] = logMatrix.bind( Notify );
|
||||
loggers[ level + 'MatrixFold' ] = logMatrixFold.bind( Notify );
|
||||
}
|
||||
|
||||
var assert = function ( test, str ) {
|
||||
if ( this.console !== undefined && !test ) {
|
||||
this.console.assert( test, str );
|
||||
}
|
||||
};
|
||||
Notify.assert = assert;
|
||||
|
||||
Notify.setNotifyLevel = function ( logLevel ) {
|
||||
|
||||
var dummy = function () {};
|
||||
|
||||
for ( var i = 0; i < levelEntries.length; ++i ) {
|
||||
var level = levelEntries[ i ];
|
||||
var doDummy = logLevel > Notify[ level.toUpperCase() ];
|
||||
Notify[ level ] = doDummy ? dummy : loggers[ level ];
|
||||
Notify[ level + 'Fold' ] = doDummy ? dummy : loggers[ level + 'Fold' ];
|
||||
Notify[ level + 'Matrix' ] = doDummy ? dummy : loggers[ level + 'Matrix' ];
|
||||
Notify[ level + 'MatrixFold' ] = doDummy ? dummy : loggers[ level + 'MatrixFold' ];
|
||||
}
|
||||
|
||||
// alias
|
||||
Notify.notice = Notify.log;
|
||||
Notify.noticeFold = Notify.logFold;
|
||||
Notify.noticeMatrix = Notify.logMatrix;
|
||||
Notify.noticeMatrixFold = Notify.logMatrixFold;
|
||||
};
|
||||
|
||||
Notify.setNotifyLevel( Notify.NOTICE );
|
||||
|
||||
Notify.reportWebGLError = false;
|
||||
|
||||
Notify.setConsole = function ( replacement ) {
|
||||
Notify.console = replacement;
|
||||
};
|
||||
|
||||
module.exports = Notify;
|
|
@ -1,176 +0,0 @@
|
|||
'use strict';
|
||||
var AutoTransform = require( 'osg/AutoTransform' );
|
||||
var BillboardAttribute = require( 'osg/BillboardAttribute' );
|
||||
var BlendColor = require( 'osg/BlendColor' );
|
||||
var BlendFunc = require( 'osg/BlendFunc' );
|
||||
var BoundingBox = require( 'osg/BoundingBox' );
|
||||
var BoundingSphere = require( 'osg/BoundingSphere' );
|
||||
var BufferArray = require( 'osg/BufferArray' );
|
||||
var Camera = require( 'osg/Camera' );
|
||||
var ColorMask = require( 'osg/ColorMask' );
|
||||
var ComputeBoundsVisitor = require( 'osg/ComputeBoundsVisitor' );
|
||||
var ComputeMatrixFromNodePath = require( 'osg/computeMatrixFromNodePath' );
|
||||
var CullFace = require( 'osg/CullFace' );
|
||||
var CullingSet = require( 'osg/CullingSet' );
|
||||
var CullSettings = require( 'osg/CullSettings' );
|
||||
var CullStack = require( 'osg/CullStack' );
|
||||
var CullVisitor = require( 'osg/CullVisitor' );
|
||||
var Depth = require( 'osg/Depth' );
|
||||
var DrawArrayLengths = require( 'osg/DrawArrayLengths' );
|
||||
var DrawArrays = require( 'osg/DrawArrays' );
|
||||
var DrawElements = require( 'osg/DrawElements' );
|
||||
var EllipsoidModel = require( 'osg/EllipsoidModel' );
|
||||
var FrameBufferObject = require( 'osg/FrameBufferObject' );
|
||||
var FrameStamp = require( 'osg/FrameStamp' );
|
||||
var Geometry = require( 'osg/Geometry' );
|
||||
var GLObject = require( 'osg/GLObject' );
|
||||
var Image = require( 'osg/Image' );
|
||||
var ImageStream = require( 'osg/ImageStream' );
|
||||
var KdTree = require( 'osg/KdTree' );
|
||||
var KdTreeBuilder = require( 'osg/KdTreeBuilder' );
|
||||
var Light = require( 'osg/Light' );
|
||||
var LightSource = require( 'osg/LightSource' );
|
||||
var LineWidth = require( 'osg/LineWidth' );
|
||||
var Lod = require( 'osg/Lod' );
|
||||
var Map = require( 'osg/Map' );
|
||||
var Material = require( 'osg/Material' );
|
||||
var osgjsMath = require( 'osg/math' );
|
||||
var Matrix = require( 'osg/Matrix' );
|
||||
var MatrixMemoryPool = require( 'osg/MatrixMemoryPool' );
|
||||
var MatrixTransform = require( 'osg/MatrixTransform' );
|
||||
var Node = require( 'osg/Node' );
|
||||
var NodeVisitor = require( 'osg/NodeVisitor' );
|
||||
var Notify = require( 'osg/notify' );
|
||||
var Object = require( 'osg/Object' );
|
||||
var PagedLOD = require( 'osg/PagedLOD' );
|
||||
var Polytope = require( 'osg/Polytope' );
|
||||
var Plane = require( 'osg/Plane' );
|
||||
var PrimitiveFunctor = require( 'osg/PrimitiveFunctor' );
|
||||
var PrimitiveSet = require( 'osg/primitiveSet' );
|
||||
var Program = require( 'osg/Program' );
|
||||
var Projection = require( 'osg/Projection' );
|
||||
var Quat = require( 'osg/Quat' );
|
||||
var RenderBin = require( 'osg/RenderBin' );
|
||||
var RenderLeaf = require( 'osg/RenderLeaf' );
|
||||
var RenderStage = require( 'osg/RenderStage' );
|
||||
var Shader = require( 'osg/Shader' );
|
||||
var Shape = require( 'osg/shape' );
|
||||
var Stack = require( 'osg/Stack' );
|
||||
var State = require( 'osg/State' );
|
||||
var StateAttribute = require( 'osg/StateAttribute' );
|
||||
var StateGraph = require( 'osg/StateGraph' );
|
||||
var StateSet = require( 'osg/StateSet' );
|
||||
var Texture = require( 'osg/Texture' );
|
||||
var TextureCubeMap = require( 'osg/TextureCubeMap' );
|
||||
var Transform = require( 'osg/Transform' );
|
||||
var TriangleIndexFunctor = require( 'osg/TriangleIndexFunctor' );
|
||||
var Uniform = require( 'osg/Uniform' );
|
||||
var UpdateVisitor = require( 'osg/UpdateVisitor' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Vec2 = require( 'osg/Vec2' );
|
||||
var Vec3 = require( 'osg/Vec3' );
|
||||
var Vec4 = require( 'osg/Vec4' );
|
||||
var Viewport = require( 'osg/Viewport' );
|
||||
var osgPool = require( 'osgUtil/osgPool' );
|
||||
var Scissor = require( 'osg/Scissor' );
|
||||
var TransformEnums = require( 'osg/transformEnums' );
|
||||
var Timer = require( 'osg/Timer' );
|
||||
var TimerGPU = require( 'osg/TimerGPU' );
|
||||
var WebGLCaps = require( 'osg/WebGLCaps' );
|
||||
|
||||
|
||||
var osg = {};
|
||||
osg.AutoTransform = AutoTransform;
|
||||
osg.BillboardAttribute = BillboardAttribute;
|
||||
osg.BlendColor = BlendColor;
|
||||
osg.BlendFunc = BlendFunc;
|
||||
osg.BoundingBox = BoundingBox;
|
||||
osg.BoundingSphere = BoundingSphere;
|
||||
osg.BufferArray = BufferArray;
|
||||
osg.ColorMask = ColorMask;
|
||||
osg.Camera = Camera;
|
||||
osg.ColorMask = ColorMask;
|
||||
osg.ComputeBoundsVisitor = ComputeBoundsVisitor;
|
||||
MACROUTILS.objectMix( osg, ComputeMatrixFromNodePath );
|
||||
osg.CullFace = CullFace;
|
||||
osg.CullingSet = CullingSet;
|
||||
osg.CullSettings = CullSettings;
|
||||
osg.CullStack = CullStack;
|
||||
osg.CullVisitor = CullVisitor;
|
||||
osg.Depth = Depth;
|
||||
osg.DrawArrayLengths = DrawArrayLengths;
|
||||
osg.DrawArrays = DrawArrays;
|
||||
osg.DrawElements = DrawElements;
|
||||
osg.EllipsoidModel = EllipsoidModel;
|
||||
osg.WGS_84_RADIUS_EQUATOR = EllipsoidModel.WGS_84_RADIUS_EQUATOR;
|
||||
osg.WGS_84_RADIUS_POLAR = EllipsoidModel.WGS_84_RADIUS_POLAR;
|
||||
osg.FrameBufferObject = FrameBufferObject;
|
||||
osg.FrameStamp = FrameStamp;
|
||||
osg.Geometry = Geometry;
|
||||
osg.GLObject = GLObject;
|
||||
osg.Image = Image;
|
||||
osg.ImageStream = ImageStream;
|
||||
osg.KdTree = KdTree;
|
||||
osg.KdTreeBuilder = KdTreeBuilder;
|
||||
osg.Light = Light;
|
||||
osg.LightSource = LightSource;
|
||||
osg.LineWidth = LineWidth;
|
||||
osg.Lod = Lod;
|
||||
osg.Map = Map;
|
||||
osg.Material = Material;
|
||||
MACROUTILS.objectMix( osg, osgjsMath );
|
||||
osg.Matrix = Matrix;
|
||||
osg.MatrixTransform = MatrixTransform;
|
||||
osg.MatrixMemoryPool = MatrixMemoryPool;
|
||||
osg.Node = Node;
|
||||
osg.NodeVisitor = NodeVisitor;
|
||||
MACROUTILS.objectMix( osg, Notify );
|
||||
osg.Object = Object;
|
||||
osg.PagedLOD = PagedLOD;
|
||||
osg.Plane = Plane;
|
||||
osg.Polytope = Polytope;
|
||||
osg.PrimitiveSet = PrimitiveSet;
|
||||
osg.PrimitiveFunctor = PrimitiveFunctor;
|
||||
osg.Program = Program;
|
||||
osg.Projection = Projection;
|
||||
osg.Quat = Quat;
|
||||
osg.RenderBin = RenderBin;
|
||||
osg.RenderLeaf = RenderLeaf;
|
||||
osg.RenderStage = RenderStage;
|
||||
osg.Shader = Shader;
|
||||
MACROUTILS.objectMix( osg, Shape );
|
||||
osg.Stack = Stack;
|
||||
osg.State = State;
|
||||
osg.StateAttribute = StateAttribute;
|
||||
osg.StateGraph = StateGraph;
|
||||
osg.StateSet = StateSet;
|
||||
osg.Scissor = Scissor;
|
||||
osg.Texture = Texture;
|
||||
osg.TextureCubeMap = TextureCubeMap;
|
||||
osg.Transform = Transform;
|
||||
osg.TriangleIndexFunctor = TriangleIndexFunctor;
|
||||
osg.Uniform = Uniform;
|
||||
osg.UpdateVisitor = UpdateVisitor;
|
||||
MACROUTILS.objectMix( osg, MACROUTILS );
|
||||
osg.Vec2 = Vec2;
|
||||
osg.Vec3 = Vec3;
|
||||
osg.Vec4 = Vec4;
|
||||
osg.Viewport = Viewport;
|
||||
|
||||
var glm = require( 'osg/glMatrix' );
|
||||
osg.vec2 = glm.vec2;
|
||||
osg.vec3 = glm.vec3;
|
||||
osg.vec4 = glm.vec4;
|
||||
osg.quat = glm.quat;
|
||||
osg.mat4 = glm.mat4;
|
||||
|
||||
osg.memoryPools = osgPool.memoryPools;
|
||||
|
||||
osg.Transform.RELATIVE_RF = TransformEnums.RELATIVE_RF;
|
||||
osg.Transform.ABSOLUTE_RF = TransformEnums.ABSOLUTE_RF;
|
||||
osg.Timer = Timer;
|
||||
osg.TimerGPU = TimerGPU;
|
||||
osg.WebGLCaps = WebGLCaps;
|
||||
|
||||
|
||||
module.exports = osg;
|
|
@ -1,11 +0,0 @@
|
|||
'use strict';
|
||||
var PrimitiveSet = {};
|
||||
PrimitiveSet.POINTS = 0x0000;
|
||||
PrimitiveSet.LINES = 0x0001;
|
||||
PrimitiveSet.LINE_LOOP = 0x0002;
|
||||
PrimitiveSet.LINE_STRIP = 0x0003;
|
||||
PrimitiveSet.TRIANGLES = 0x0004;
|
||||
PrimitiveSet.TRIANGLE_STRIP = 0x0005;
|
||||
PrimitiveSet.TRIANGLE_FAN = 0x0006;
|
||||
|
||||
module.exports = PrimitiveSet;
|
|
@ -1,797 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var BufferArray = require( 'osg/BufferArray' );
|
||||
var Geometry = require( 'osg/Geometry' );
|
||||
var PrimitiveSet = require( 'osg/primitiveSet' );
|
||||
var DrawArrays = require( 'osg/DrawArrays' );
|
||||
var DrawElements = require( 'osg/DrawElements' );
|
||||
var Program = require( 'osg/Program' );
|
||||
var Shader = require( 'osg/Shader' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
|
||||
|
||||
/**
|
||||
* Create a Textured Box on the given center with given size
|
||||
* @name createTexturedBox
|
||||
*/
|
||||
var createTexturedBoxGeometry = function ( cx, cy, cz,
|
||||
sx, sy, sz ) {
|
||||
|
||||
var centerx = cx !== undefined ? cx : 0.0;
|
||||
var centery = cy !== undefined ? cy : 0.0;
|
||||
var centerz = cz !== undefined ? cz : 0.0;
|
||||
|
||||
var sizex = sx !== undefined ? sx : 1.0;
|
||||
var sizey = sy !== undefined ? sy : 1.0;
|
||||
var sizez = sz !== undefined ? sz : 1.0;
|
||||
|
||||
var g = new Geometry();
|
||||
var dx, dy, dz;
|
||||
dx = sizex / 2.0;
|
||||
dy = sizey / 2.0;
|
||||
dz = sizez / 2.0;
|
||||
|
||||
var vertexes = new MACROUTILS.Float32Array( 72 );
|
||||
var uv = new MACROUTILS.Float32Array( 48 );
|
||||
var normal = new MACROUTILS.Float32Array( 72 );
|
||||
|
||||
// -ve y plane
|
||||
vertexes[ 0 ] = centerx - dx;
|
||||
vertexes[ 1 ] = centery - dy;
|
||||
vertexes[ 2 ] = centerz + dz;
|
||||
normal[ 0 ] = 0.0;
|
||||
normal[ 1 ] = -1.0;
|
||||
normal[ 2 ] = 0.0;
|
||||
uv[ 0 ] = 0.0;
|
||||
uv[ 1 ] = 1.0;
|
||||
|
||||
vertexes[ 3 ] = centerx - dx;
|
||||
vertexes[ 4 ] = centery - dy;
|
||||
vertexes[ 5 ] = centerz - dz;
|
||||
normal[ 3 ] = 0.0;
|
||||
normal[ 4 ] = -1.0;
|
||||
normal[ 5 ] = 0.0;
|
||||
uv[ 2 ] = 0.0;
|
||||
uv[ 3 ] = 0.0;
|
||||
|
||||
vertexes[ 6 ] = centerx + dx;
|
||||
vertexes[ 7 ] = centery - dy;
|
||||
vertexes[ 8 ] = centerz - dz;
|
||||
normal[ 6 ] = 0.0;
|
||||
normal[ 7 ] = -1.0;
|
||||
normal[ 8 ] = 0.0;
|
||||
uv[ 4 ] = 1.0;
|
||||
uv[ 5 ] = 0.0;
|
||||
|
||||
vertexes[ 9 ] = centerx + dx;
|
||||
vertexes[ 10 ] = centery - dy;
|
||||
vertexes[ 11 ] = centerz + dz;
|
||||
normal[ 9 ] = 0.0;
|
||||
normal[ 10 ] = -1.0;
|
||||
normal[ 11 ] = 0.0;
|
||||
uv[ 6 ] = 1.0;
|
||||
uv[ 7 ] = 1.0;
|
||||
|
||||
|
||||
// +ve y plane
|
||||
vertexes[ 12 ] = centerx + dx;
|
||||
vertexes[ 13 ] = centery + dy;
|
||||
vertexes[ 14 ] = centerz + dz;
|
||||
normal[ 12 ] = 0.0;
|
||||
normal[ 13 ] = 1.0;
|
||||
normal[ 14 ] = 0.0;
|
||||
uv[ 8 ] = 0.0;
|
||||
uv[ 9 ] = 1.0;
|
||||
|
||||
vertexes[ 15 ] = centerx + dx;
|
||||
vertexes[ 16 ] = centery + dy;
|
||||
vertexes[ 17 ] = centerz - dz;
|
||||
normal[ 15 ] = 0.0;
|
||||
normal[ 16 ] = 1.0;
|
||||
normal[ 17 ] = 0.0;
|
||||
uv[ 10 ] = 0.0;
|
||||
uv[ 11 ] = 0.0;
|
||||
|
||||
vertexes[ 18 ] = centerx - dx;
|
||||
vertexes[ 19 ] = centery + dy;
|
||||
vertexes[ 20 ] = centerz - dz;
|
||||
normal[ 18 ] = 0.0;
|
||||
normal[ 19 ] = 1.0;
|
||||
normal[ 20 ] = 0.0;
|
||||
uv[ 12 ] = 1.0;
|
||||
uv[ 13 ] = 0.0;
|
||||
|
||||
vertexes[ 21 ] = centerx - dx;
|
||||
vertexes[ 22 ] = centery + dy;
|
||||
vertexes[ 23 ] = centerz + dz;
|
||||
normal[ 21 ] = 0.0;
|
||||
normal[ 22 ] = 1.0;
|
||||
normal[ 23 ] = 0.0;
|
||||
uv[ 14 ] = 1.0;
|
||||
uv[ 15 ] = 1.0;
|
||||
|
||||
|
||||
// +ve x plane
|
||||
vertexes[ 24 ] = centerx + dx;
|
||||
vertexes[ 25 ] = centery - dy;
|
||||
vertexes[ 26 ] = centerz + dz;
|
||||
normal[ 24 ] = 1.0;
|
||||
normal[ 25 ] = 0.0;
|
||||
normal[ 26 ] = 0.0;
|
||||
uv[ 16 ] = 0.0;
|
||||
uv[ 17 ] = 1.0;
|
||||
|
||||
vertexes[ 27 ] = centerx + dx;
|
||||
vertexes[ 28 ] = centery - dy;
|
||||
vertexes[ 29 ] = centerz - dz;
|
||||
normal[ 27 ] = 1.0;
|
||||
normal[ 28 ] = 0.0;
|
||||
normal[ 29 ] = 0.0;
|
||||
uv[ 18 ] = 0.0;
|
||||
uv[ 19 ] = 0.0;
|
||||
|
||||
vertexes[ 30 ] = centerx + dx;
|
||||
vertexes[ 31 ] = centery + dy;
|
||||
vertexes[ 32 ] = centerz - dz;
|
||||
normal[ 30 ] = 1.0;
|
||||
normal[ 31 ] = 0.0;
|
||||
normal[ 32 ] = 0.0;
|
||||
uv[ 20 ] = 1.0;
|
||||
uv[ 21 ] = 0.0;
|
||||
|
||||
vertexes[ 33 ] = centerx + dx;
|
||||
vertexes[ 34 ] = centery + dy;
|
||||
vertexes[ 35 ] = centerz + dz;
|
||||
normal[ 33 ] = 1.0;
|
||||
normal[ 34 ] = 0.0;
|
||||
normal[ 35 ] = 0.0;
|
||||
uv[ 22 ] = 1.0;
|
||||
uv[ 23 ] = 1.0;
|
||||
|
||||
// -ve x plane
|
||||
vertexes[ 36 ] = centerx - dx;
|
||||
vertexes[ 37 ] = centery + dy;
|
||||
vertexes[ 38 ] = centerz + dz;
|
||||
normal[ 36 ] = -1.0;
|
||||
normal[ 37 ] = 0.0;
|
||||
normal[ 38 ] = 0.0;
|
||||
uv[ 24 ] = 0.0;
|
||||
uv[ 25 ] = 1.0;
|
||||
|
||||
vertexes[ 39 ] = centerx - dx;
|
||||
vertexes[ 40 ] = centery + dy;
|
||||
vertexes[ 41 ] = centerz - dz;
|
||||
normal[ 39 ] = -1.0;
|
||||
normal[ 40 ] = 0.0;
|
||||
normal[ 41 ] = 0.0;
|
||||
uv[ 26 ] = 0.0;
|
||||
uv[ 27 ] = 0.0;
|
||||
|
||||
vertexes[ 42 ] = centerx - dx;
|
||||
vertexes[ 43 ] = centery - dy;
|
||||
vertexes[ 44 ] = centerz - dz;
|
||||
normal[ 42 ] = -1.0;
|
||||
normal[ 43 ] = 0.0;
|
||||
normal[ 44 ] = 0.0;
|
||||
uv[ 28 ] = 1.0;
|
||||
uv[ 29 ] = 0.0;
|
||||
|
||||
vertexes[ 45 ] = centerx - dx;
|
||||
vertexes[ 46 ] = centery - dy;
|
||||
vertexes[ 47 ] = centerz + dz;
|
||||
normal[ 45 ] = -1.0;
|
||||
normal[ 46 ] = 0.0;
|
||||
normal[ 47 ] = 0.0;
|
||||
uv[ 30 ] = 1.0;
|
||||
uv[ 31 ] = 1.0;
|
||||
|
||||
// top
|
||||
// +ve z plane
|
||||
vertexes[ 48 ] = centerx - dx;
|
||||
vertexes[ 49 ] = centery + dy;
|
||||
vertexes[ 50 ] = centerz + dz;
|
||||
normal[ 48 ] = 0.0;
|
||||
normal[ 49 ] = 0.0;
|
||||
normal[ 50 ] = 1.0;
|
||||
uv[ 32 ] = 0.0;
|
||||
uv[ 33 ] = 1.0;
|
||||
|
||||
vertexes[ 51 ] = centerx - dx;
|
||||
vertexes[ 52 ] = centery - dy;
|
||||
vertexes[ 53 ] = centerz + dz;
|
||||
normal[ 51 ] = 0.0;
|
||||
normal[ 52 ] = 0.0;
|
||||
normal[ 53 ] = 1.0;
|
||||
uv[ 34 ] = 0.0;
|
||||
uv[ 35 ] = 0.0;
|
||||
|
||||
vertexes[ 54 ] = centerx + dx;
|
||||
vertexes[ 55 ] = centery - dy;
|
||||
vertexes[ 56 ] = centerz + dz;
|
||||
normal[ 54 ] = 0.0;
|
||||
normal[ 55 ] = 0.0;
|
||||
normal[ 56 ] = 1.0;
|
||||
uv[ 36 ] = 1.0;
|
||||
uv[ 37 ] = 0.0;
|
||||
|
||||
vertexes[ 57 ] = centerx + dx;
|
||||
vertexes[ 58 ] = centery + dy;
|
||||
vertexes[ 59 ] = centerz + dz;
|
||||
normal[ 57 ] = 0.0;
|
||||
normal[ 58 ] = 0.0;
|
||||
normal[ 59 ] = 1.0;
|
||||
uv[ 38 ] = 1.0;
|
||||
uv[ 39 ] = 1.0;
|
||||
|
||||
// bottom
|
||||
// -ve z plane
|
||||
vertexes[ 60 ] = centerx + dx;
|
||||
vertexes[ 61 ] = centery + dy;
|
||||
vertexes[ 62 ] = centerz - dz;
|
||||
normal[ 60 ] = 0.0;
|
||||
normal[ 61 ] = 0.0;
|
||||
normal[ 62 ] = -1.0;
|
||||
uv[ 40 ] = 0.0;
|
||||
uv[ 41 ] = 1.0;
|
||||
|
||||
vertexes[ 63 ] = centerx + dx;
|
||||
vertexes[ 64 ] = centery - dy;
|
||||
vertexes[ 65 ] = centerz - dz;
|
||||
normal[ 63 ] = 0.0;
|
||||
normal[ 64 ] = 0.0;
|
||||
normal[ 65 ] = -1.0;
|
||||
uv[ 42 ] = 0.0;
|
||||
uv[ 43 ] = 0.0;
|
||||
|
||||
vertexes[ 66 ] = centerx - dx;
|
||||
vertexes[ 67 ] = centery - dy;
|
||||
vertexes[ 68 ] = centerz - dz;
|
||||
normal[ 66 ] = 0.0;
|
||||
normal[ 67 ] = 0.0;
|
||||
normal[ 68 ] = -1.0;
|
||||
uv[ 44 ] = 1.0;
|
||||
uv[ 45 ] = 0.0;
|
||||
|
||||
vertexes[ 69 ] = centerx - dx;
|
||||
vertexes[ 70 ] = centery + dy;
|
||||
vertexes[ 71 ] = centerz - dz;
|
||||
normal[ 69 ] = 0.0;
|
||||
normal[ 70 ] = 0.0;
|
||||
normal[ 71 ] = -1.0;
|
||||
uv[ 46 ] = 1.0;
|
||||
uv[ 47 ] = 1.0;
|
||||
|
||||
var indexes = new MACROUTILS.Uint16Array( 36 );
|
||||
indexes[ 0 ] = 0;
|
||||
indexes[ 1 ] = 1;
|
||||
indexes[ 2 ] = 2;
|
||||
indexes[ 3 ] = 0;
|
||||
indexes[ 4 ] = 2;
|
||||
indexes[ 5 ] = 3;
|
||||
|
||||
indexes[ 6 ] = 4;
|
||||
indexes[ 7 ] = 5;
|
||||
indexes[ 8 ] = 6;
|
||||
indexes[ 9 ] = 4;
|
||||
indexes[ 10 ] = 6;
|
||||
indexes[ 11 ] = 7;
|
||||
|
||||
indexes[ 12 ] = 8;
|
||||
indexes[ 13 ] = 9;
|
||||
indexes[ 14 ] = 10;
|
||||
indexes[ 15 ] = 8;
|
||||
indexes[ 16 ] = 10;
|
||||
indexes[ 17 ] = 11;
|
||||
|
||||
indexes[ 18 ] = 12;
|
||||
indexes[ 19 ] = 13;
|
||||
indexes[ 20 ] = 14;
|
||||
indexes[ 21 ] = 12;
|
||||
indexes[ 22 ] = 14;
|
||||
indexes[ 23 ] = 15;
|
||||
|
||||
indexes[ 24 ] = 16;
|
||||
indexes[ 25 ] = 17;
|
||||
indexes[ 26 ] = 18;
|
||||
indexes[ 27 ] = 16;
|
||||
indexes[ 28 ] = 18;
|
||||
indexes[ 29 ] = 19;
|
||||
|
||||
indexes[ 30 ] = 20;
|
||||
indexes[ 31 ] = 21;
|
||||
indexes[ 32 ] = 22;
|
||||
indexes[ 33 ] = 20;
|
||||
indexes[ 34 ] = 22;
|
||||
indexes[ 35 ] = 23;
|
||||
|
||||
g.getAttributes().Vertex = new BufferArray( BufferArray.ARRAY_BUFFER, vertexes, 3 );
|
||||
g.getAttributes().Normal = new BufferArray( BufferArray.ARRAY_BUFFER, normal, 3 );
|
||||
g.getAttributes().TexCoord0 = new BufferArray( BufferArray.ARRAY_BUFFER, uv, 2 );
|
||||
|
||||
var primitive = new DrawElements( PrimitiveSet.TRIANGLES, new BufferArray( BufferArray.ELEMENT_ARRAY_BUFFER, indexes, 1 ) );
|
||||
g.getPrimitives().push( primitive );
|
||||
return g;
|
||||
};
|
||||
|
||||
// better perf
|
||||
// no more pixel shader hurt for nothing
|
||||
// http://michaldrobot.com/2014/04/01/gcn-execution-patterns-in-full-screen-passes/
|
||||
// It's a Singleton, as it's rendering invariant
|
||||
// so same remove uneeded state change when same geom
|
||||
var createTexturedFullScreenFakeQuadGeometry = ( function () {
|
||||
var g = new Geometry();
|
||||
|
||||
var uvs = new MACROUTILS.Float32Array( [ -1.0, -1.0, -1.0, 4.0, 4.0, -1.0 ] );
|
||||
var vertexes = new MACROUTILS.Float32Array( [ -1.0, -1.0, -1.0, 4.0, 4.0, -1.0 ] );
|
||||
|
||||
var indexes = new MACROUTILS.Uint16Array( 3 );
|
||||
indexes[ 0 ] = 2;
|
||||
indexes[ 1 ] = 1;
|
||||
indexes[ 2 ] = 0;
|
||||
|
||||
// Further optim: no index, no uv (uv.xy = position.xy in vertex shader)
|
||||
g.getAttributes().Vertex = new BufferArray( BufferArray.ARRAY_BUFFER, vertexes, 2 );
|
||||
g.getAttributes().TexCoord0 = new BufferArray( BufferArray.ARRAY_BUFFER, uvs, 2 );
|
||||
|
||||
var primitive = new DrawElements( PrimitiveSet.TRIANGLES, new BufferArray( BufferArray.ELEMENT_ARRAY_BUFFER, indexes, 1 ) );
|
||||
g.getPrimitives().push( primitive );
|
||||
|
||||
return function () {
|
||||
return g;
|
||||
};
|
||||
} )();
|
||||
|
||||
|
||||
var createTexturedQuadGeometry = function ( cornerx, cornery, cornerz,
|
||||
wx, wy, wz,
|
||||
hx, hy, hz,
|
||||
l, b, r, t ) {
|
||||
|
||||
if ( r === undefined && t === undefined ) {
|
||||
r = l;
|
||||
t = b;
|
||||
l = 0.0;
|
||||
b = 0.0;
|
||||
}
|
||||
|
||||
var g = new Geometry();
|
||||
|
||||
var vertexes = new MACROUTILS.Float32Array( 12 );
|
||||
vertexes[ 0 ] = cornerx + hx;
|
||||
vertexes[ 1 ] = cornery + hy;
|
||||
vertexes[ 2 ] = cornerz + hz;
|
||||
|
||||
vertexes[ 3 ] = cornerx;
|
||||
vertexes[ 4 ] = cornery;
|
||||
vertexes[ 5 ] = cornerz;
|
||||
|
||||
vertexes[ 6 ] = cornerx + wx;
|
||||
vertexes[ 7 ] = cornery + wy;
|
||||
vertexes[ 8 ] = cornerz + wz;
|
||||
|
||||
vertexes[ 9 ] = cornerx + wx + hx;
|
||||
vertexes[ 10 ] = cornery + wy + hy;
|
||||
vertexes[ 11 ] = cornerz + wz + hz;
|
||||
|
||||
if ( r === undefined ) {
|
||||
r = 1.0;
|
||||
}
|
||||
if ( t === undefined ) {
|
||||
t = 1.0;
|
||||
}
|
||||
|
||||
var uvs = new MACROUTILS.Float32Array( 8 );
|
||||
uvs[ 0 ] = l;
|
||||
uvs[ 1 ] = t;
|
||||
|
||||
uvs[ 2 ] = l;
|
||||
uvs[ 3 ] = b;
|
||||
|
||||
uvs[ 4 ] = r;
|
||||
uvs[ 5 ] = b;
|
||||
|
||||
uvs[ 6 ] = r;
|
||||
uvs[ 7 ] = t;
|
||||
|
||||
var n = vec3.fromValues( wx, wy, wz );
|
||||
vec3.cross( n, n, vec3.fromValues( hx, hy, hz ) );
|
||||
vec3.normalize( n, n );
|
||||
|
||||
var normal = new MACROUTILS.Float32Array( 12 );
|
||||
normal[ 0 ] = n[ 0 ];
|
||||
normal[ 1 ] = n[ 1 ];
|
||||
normal[ 2 ] = n[ 2 ];
|
||||
|
||||
normal[ 3 ] = n[ 0 ];
|
||||
normal[ 4 ] = n[ 1 ];
|
||||
normal[ 5 ] = n[ 2 ];
|
||||
|
||||
normal[ 6 ] = n[ 0 ];
|
||||
normal[ 7 ] = n[ 1 ];
|
||||
normal[ 8 ] = n[ 2 ];
|
||||
|
||||
normal[ 9 ] = n[ 0 ];
|
||||
normal[ 10 ] = n[ 1 ];
|
||||
normal[ 11 ] = n[ 2 ];
|
||||
|
||||
|
||||
var indexes = new MACROUTILS.Uint16Array( 6 );
|
||||
indexes[ 0 ] = 0;
|
||||
indexes[ 1 ] = 1;
|
||||
indexes[ 2 ] = 2;
|
||||
indexes[ 3 ] = 0;
|
||||
indexes[ 4 ] = 2;
|
||||
indexes[ 5 ] = 3;
|
||||
|
||||
g.getAttributes().Vertex = new BufferArray( BufferArray.ARRAY_BUFFER, vertexes, 3 );
|
||||
g.getAttributes().Normal = new BufferArray( BufferArray.ARRAY_BUFFER, normal, 3 );
|
||||
g.getAttributes().TexCoord0 = new BufferArray( BufferArray.ARRAY_BUFFER, uvs, 2 );
|
||||
|
||||
var primitive = new DrawElements( PrimitiveSet.TRIANGLES, new BufferArray( BufferArray.ELEMENT_ARRAY_BUFFER, indexes, 1 ) );
|
||||
g.getPrimitives().push( primitive );
|
||||
return g;
|
||||
};
|
||||
|
||||
var createTexturedBox = function ( centerx, centery, centerz,
|
||||
sizex, sizey, sizez ) {
|
||||
Notify.log( 'createTexturedBox is deprecated use instead createTexturedBoxGeometry' );
|
||||
return createTexturedBoxGeometry( centerx, centery, centerz,
|
||||
sizex, sizey, sizez );
|
||||
};
|
||||
|
||||
var createTexturedQuad = function ( cornerx, cornery, cornerz,
|
||||
wx, wy, wz,
|
||||
hx, hy, hz,
|
||||
l, b, r, t ) {
|
||||
Notify.log( 'createTexturedQuad is deprecated use instead createTexturedQuadGeometry' );
|
||||
return createTexturedQuadGeometry( cornerx, cornery, cornerz,
|
||||
wx, wy, wz,
|
||||
hx, hy, hz,
|
||||
l, b, r, t );
|
||||
};
|
||||
|
||||
var createAxisGeometry = function ( size ) {
|
||||
if ( size === undefined ) {
|
||||
size = 5.0;
|
||||
}
|
||||
if ( createAxisGeometry.getShader === undefined ) {
|
||||
createAxisGeometry.getShader = function () {
|
||||
if ( createAxisGeometry.getShader.program === undefined ) {
|
||||
var vertexshader = [
|
||||
'#ifdef GL_ES',
|
||||
'precision highp float;',
|
||||
'#endif',
|
||||
'attribute vec3 Vertex;',
|
||||
'attribute vec4 Color;',
|
||||
'uniform mat4 uModelViewMatrix;',
|
||||
'uniform mat4 uProjectionMatrix;',
|
||||
'',
|
||||
'varying vec4 vColor;',
|
||||
'',
|
||||
'void main(void) {',
|
||||
' gl_Position = uProjectionMatrix * (uModelViewMatrix * vec4(Vertex, 1.0));',
|
||||
' vColor = Color;',
|
||||
'}'
|
||||
].join( '\n' );
|
||||
|
||||
var fragmentshader = [
|
||||
'#ifdef GL_ES',
|
||||
'precision highp float;',
|
||||
'#endif',
|
||||
'varying vec4 vColor;',
|
||||
|
||||
'void main(void) {',
|
||||
'gl_FragColor = vColor;',
|
||||
'}'
|
||||
].join( '\n' );
|
||||
|
||||
var program = new Program( new Shader( 'VERTEX_SHADER', vertexshader ),
|
||||
new Shader( 'FRAGMENT_SHADER', fragmentshader ) );
|
||||
createAxisGeometry.getShader.program = program;
|
||||
}
|
||||
return createAxisGeometry.getShader.program;
|
||||
};
|
||||
}
|
||||
|
||||
var g = new Geometry();
|
||||
|
||||
var vertexes = new MACROUTILS.Float32Array( 18 );
|
||||
vertexes[ 3 ] = size;
|
||||
vertexes[ 10 ] = size;
|
||||
vertexes[ 17 ] = size;
|
||||
|
||||
var colors = new MACROUTILS.Float32Array( 24 );
|
||||
//red color
|
||||
colors[ 0 ] = colors[ 3 ] = 1.0;
|
||||
colors[ 4 ] = colors[ 4 + 3 ] = 1.0;
|
||||
//green color
|
||||
colors[ 4 * 2 + 1 ] = colors[ 4 * 2 + 3 ] = 1.0;
|
||||
colors[ 4 * 3 + 1 ] = colors[ 4 * 3 + 3 ] = 1.0;
|
||||
//blue color
|
||||
colors[ 4 * 4 + 2 ] = colors[ 4 * 4 + 3 ] = 1.0;
|
||||
colors[ 4 * 5 + 2 ] = colors[ 4 * 5 + 3 ] = 1.0;
|
||||
|
||||
g.getAttributes().Vertex = new BufferArray( BufferArray.ARRAY_BUFFER, vertexes, 3 );
|
||||
g.getAttributes().Color = new BufferArray( BufferArray.ARRAY_BUFFER, colors, 4 );
|
||||
|
||||
var primitive = new DrawArrays( PrimitiveSet.LINES, 0, 6 );
|
||||
g.getPrimitives().push( primitive );
|
||||
g.getOrCreateStateSet().setAttributeAndModes( createAxisGeometry.getShader() );
|
||||
|
||||
return g;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a Textured Sphere on the given center with given radius
|
||||
* @name createTexturedSphere
|
||||
* @author Darrell Esau
|
||||
*/
|
||||
var createTexturedSphere = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
|
||||
radius = radius || 50.0;
|
||||
|
||||
phiStart = phiStart !== undefined ? phiStart : 0.0;
|
||||
phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
|
||||
|
||||
thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
|
||||
thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
|
||||
|
||||
var segmentsX = Math.max( 3, Math.floor( widthSegments ) || 8 );
|
||||
var segmentsY = Math.max( 2, Math.floor( heightSegments ) || 6 );
|
||||
|
||||
var useDrawArrays = ( ( segmentsX * segmentsY ) / 3 ) >= 65536;
|
||||
var nbPrim = useDrawArrays ? segmentsX * segmentsY * 6 : segmentsX * segmentsY * 4;
|
||||
var fullVerticesList = new MACROUTILS.Float32Array( nbPrim * 3 );
|
||||
var fullNormalsList = new MACROUTILS.Float32Array( nbPrim * 3 );
|
||||
var fullUVList = new MACROUTILS.Float32Array( nbPrim * 2 );
|
||||
var indexes = !useDrawArrays ? new MACROUTILS.Uint16Array( segmentsX * segmentsY * 6 ) : undefined;
|
||||
var vtxCount = 0;
|
||||
var triCount = 0;
|
||||
|
||||
var v1 = new MACROUTILS.Float32Array( 3 );
|
||||
var v2 = new MACROUTILS.Float32Array( 3 );
|
||||
var v3 = new MACROUTILS.Float32Array( 3 );
|
||||
var v4 = new MACROUTILS.Float32Array( 3 );
|
||||
var n1 = new MACROUTILS.Float32Array( 3 );
|
||||
var n2 = new MACROUTILS.Float32Array( 3 );
|
||||
var n3 = new MACROUTILS.Float32Array( 3 );
|
||||
var n4 = new MACROUTILS.Float32Array( 3 );
|
||||
var uv1 = new MACROUTILS.Float32Array( 2 );
|
||||
var uv2 = new MACROUTILS.Float32Array( 2 );
|
||||
var uv3 = new MACROUTILS.Float32Array( 2 );
|
||||
var uv4 = new MACROUTILS.Float32Array( 2 );
|
||||
var getCoordAndUvSphere = function ( u, v, coord, norm, uv ) {
|
||||
coord[ 0 ] = -radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
|
||||
coord[ 1 ] = radius * Math.cos( thetaStart + v * thetaLength );
|
||||
coord[ 2 ] = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
|
||||
vec3.normalize( norm, coord );
|
||||
uv[ 0 ] = u;
|
||||
uv[ 1 ] = 1 - v;
|
||||
};
|
||||
for ( var y = 0; y < segmentsY; y++ ) {
|
||||
for ( var x = 0; x < segmentsX; x++ ) {
|
||||
getCoordAndUvSphere( ( x + 1 ) / segmentsX, y / segmentsY, v1, n1, uv1 );
|
||||
getCoordAndUvSphere( x / segmentsX, y / segmentsY, v2, n2, uv2 );
|
||||
getCoordAndUvSphere( x / segmentsX, ( y + 1 ) / segmentsY, v3, n3, uv3 );
|
||||
getCoordAndUvSphere( ( x + 1 ) / segmentsX, ( y + 1 ) / segmentsY, v4, n4, uv4 );
|
||||
|
||||
var idv = vtxCount * 3;
|
||||
fullVerticesList[ idv ] = v1[ 0 ];
|
||||
fullVerticesList[ idv + 1 ] = v1[ 1 ];
|
||||
fullVerticesList[ idv + 2 ] = v1[ 2 ];
|
||||
fullVerticesList[ idv + 3 ] = v2[ 0 ];
|
||||
fullVerticesList[ idv + 4 ] = v2[ 1 ];
|
||||
fullVerticesList[ idv + 5 ] = v2[ 2 ];
|
||||
fullVerticesList[ idv + 6 ] = v3[ 0 ];
|
||||
fullVerticesList[ idv + 7 ] = v3[ 1 ];
|
||||
fullVerticesList[ idv + 8 ] = v3[ 2 ];
|
||||
|
||||
fullNormalsList[ idv ] = n1[ 0 ];
|
||||
fullNormalsList[ idv + 1 ] = n1[ 1 ];
|
||||
fullNormalsList[ idv + 2 ] = n1[ 2 ];
|
||||
fullNormalsList[ idv + 3 ] = n2[ 0 ];
|
||||
fullNormalsList[ idv + 4 ] = n2[ 1 ];
|
||||
fullNormalsList[ idv + 5 ] = n2[ 2 ];
|
||||
fullNormalsList[ idv + 6 ] = n3[ 0 ];
|
||||
fullNormalsList[ idv + 7 ] = n3[ 1 ];
|
||||
fullNormalsList[ idv + 8 ] = n3[ 2 ];
|
||||
|
||||
var idu = vtxCount * 2;
|
||||
fullUVList[ idu ] = uv1[ 0 ];
|
||||
fullUVList[ idu + 1 ] = uv1[ 1 ];
|
||||
fullUVList[ idu + 2 ] = uv2[ 0 ];
|
||||
fullUVList[ idu + 3 ] = uv2[ 1 ];
|
||||
fullUVList[ idu + 4 ] = uv3[ 0 ];
|
||||
fullUVList[ idu + 5 ] = uv3[ 1 ];
|
||||
|
||||
vtxCount += 3;
|
||||
if ( useDrawArrays ) {
|
||||
idv = vtxCount * 3;
|
||||
fullVerticesList[ idv ] = v1[ 0 ];
|
||||
fullVerticesList[ idv + 1 ] = v1[ 1 ];
|
||||
fullVerticesList[ idv + 2 ] = v1[ 2 ];
|
||||
fullVerticesList[ idv + 3 ] = v3[ 0 ];
|
||||
fullVerticesList[ idv + 4 ] = v3[ 1 ];
|
||||
fullVerticesList[ idv + 5 ] = v3[ 2 ];
|
||||
fullVerticesList[ idv + 6 ] = v4[ 0 ];
|
||||
fullVerticesList[ idv + 7 ] = v4[ 1 ];
|
||||
fullVerticesList[ idv + 8 ] = v4[ 2 ];
|
||||
|
||||
fullNormalsList[ idv ] = n1[ 0 ];
|
||||
fullNormalsList[ idv + 1 ] = n1[ 1 ];
|
||||
fullNormalsList[ idv + 2 ] = n1[ 2 ];
|
||||
fullNormalsList[ idv + 3 ] = n3[ 0 ];
|
||||
fullNormalsList[ idv + 4 ] = n3[ 1 ];
|
||||
fullNormalsList[ idv + 5 ] = n3[ 2 ];
|
||||
fullNormalsList[ idv + 6 ] = n4[ 0 ];
|
||||
fullNormalsList[ idv + 7 ] = n4[ 1 ];
|
||||
fullNormalsList[ idv + 8 ] = n4[ 2 ];
|
||||
|
||||
idu = vtxCount * 2;
|
||||
fullUVList[ idu ] = uv1[ 0 ];
|
||||
fullUVList[ idu + 1 ] = uv1[ 1 ];
|
||||
fullUVList[ idu + 2 ] = uv3[ 0 ];
|
||||
fullUVList[ idu + 3 ] = uv3[ 1 ];
|
||||
fullUVList[ idu + 4 ] = uv4[ 0 ];
|
||||
fullUVList[ idu + 5 ] = uv4[ 1 ];
|
||||
vtxCount += 3;
|
||||
} else {
|
||||
idv = vtxCount * 3;
|
||||
fullVerticesList[ idv ] = v4[ 0 ];
|
||||
fullVerticesList[ idv + 1 ] = v4[ 1 ];
|
||||
fullVerticesList[ idv + 2 ] = v4[ 2 ];
|
||||
|
||||
fullNormalsList[ idv ] = n4[ 0 ];
|
||||
fullNormalsList[ idv + 1 ] = n4[ 1 ];
|
||||
fullNormalsList[ idv + 2 ] = n4[ 2 ];
|
||||
|
||||
idu = vtxCount * 2;
|
||||
fullUVList[ idu ] = uv4[ 0 ];
|
||||
fullUVList[ idu + 1 ] = uv4[ 1 ];
|
||||
|
||||
var iStart = triCount * 3;
|
||||
var tristart = vtxCount - 3;
|
||||
indexes[ iStart ] = tristart;
|
||||
indexes[ iStart + 1 ] = tristart + 1;
|
||||
indexes[ iStart + 2 ] = tristart + 2;
|
||||
indexes[ iStart + 3 ] = tristart;
|
||||
indexes[ iStart + 4 ] = tristart + 2;
|
||||
indexes[ iStart + 5 ] = tristart + 3;
|
||||
triCount += 2;
|
||||
vtxCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var g = new Geometry();
|
||||
g.getAttributes().Vertex = new BufferArray( 'ARRAY_BUFFER', fullVerticesList, 3 );
|
||||
g.getAttributes().Normal = new BufferArray( 'ARRAY_BUFFER', fullNormalsList, 3 );
|
||||
g.getAttributes().TexCoord0 = new BufferArray( 'ARRAY_BUFFER', fullUVList, 2 );
|
||||
|
||||
if ( useDrawArrays )
|
||||
g.getPrimitives().push( new DrawArrays( PrimitiveSet.TRIANGLES, 0, fullVerticesList.length / 3 ) );
|
||||
else
|
||||
g.getPrimitives().push( new DrawElements( PrimitiveSet.TRIANGLES, new BufferArray( 'ELEMENT_ARRAY_BUFFER', indexes, 1 ) ) );
|
||||
return g;
|
||||
};
|
||||
|
||||
var createGridGeometry = function ( cx, cy, cz, wx, wy, wz, hx, hy, hz, res1, res2 ) {
|
||||
cx = cx !== undefined ? cx : -0.5;
|
||||
cy = cy !== undefined ? cy : -0.5;
|
||||
cz = cz !== undefined ? cz : 0.0;
|
||||
|
||||
wx = wx !== undefined ? wx : 1.0;
|
||||
wy = wy !== undefined ? wy : 0.0;
|
||||
wz = wz !== undefined ? wz : 0.0;
|
||||
|
||||
hx = hx !== undefined ? hx : 0.0;
|
||||
hy = hy !== undefined ? hy : 1.0;
|
||||
hz = hz !== undefined ? hz : 0.0;
|
||||
|
||||
res1 = res1 !== undefined ? res1 : 5;
|
||||
res2 = res2 !== undefined ? res2 : res1;
|
||||
res1 += 2;
|
||||
res2 += 2;
|
||||
|
||||
var g = new Geometry();
|
||||
var vertices = new Float32Array( ( res1 + res2 ) * 2 * 3 );
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var sx = wx / ( res1 - 1 );
|
||||
var sy = wy / ( res1 - 1 );
|
||||
var sz = wz / ( res1 - 1 );
|
||||
var ux = cx + wx + hx;
|
||||
var uy = cy + wy + hy;
|
||||
var uz = cz + wz + hz;
|
||||
for ( i = 0; i < res1; ++i ) {
|
||||
j = i * 6;
|
||||
vertices[ j ] = cx + sx * i;
|
||||
vertices[ j + 1 ] = cy + sy * i;
|
||||
vertices[ j + 2 ] = cz + sz * i;
|
||||
vertices[ j + 3 ] = ux - sx * ( res1 - i - 1 );
|
||||
vertices[ j + 4 ] = uy - sy * ( res1 - i - 1 );
|
||||
vertices[ j + 5 ] = uz - sz * ( res1 - i - 1 );
|
||||
}
|
||||
sx = hx / ( res2 - 1 );
|
||||
sy = hy / ( res2 - 1 );
|
||||
sz = hz / ( res2 - 1 );
|
||||
for ( i = 0; i < res2; ++i ) {
|
||||
j = ( res1 + i ) * 6;
|
||||
vertices[ j ] = cx + sx * i;
|
||||
vertices[ j + 1 ] = cy + sy * i;
|
||||
vertices[ j + 2 ] = cz + sz * i;
|
||||
vertices[ j + 3 ] = ux - sx * ( res2 - i - 1 );
|
||||
vertices[ j + 4 ] = uy - sy * ( res2 - i - 1 );
|
||||
vertices[ j + 5 ] = uz - sz * ( res2 - i - 1 );
|
||||
}
|
||||
g.getAttributes().Vertex = new BufferArray( BufferArray.ARRAY_BUFFER, vertices, 3 );
|
||||
var primitive = new DrawArrays( PrimitiveSet.LINES, 0, ( res1 + res2 ) * 2 );
|
||||
g.getPrimitives().push( primitive );
|
||||
return g;
|
||||
};
|
||||
|
||||
/*
|
||||
* debug lines showing bounding box abstraction
|
||||
* @param col bbox color
|
||||
*/
|
||||
var createBoundingBoxGeometry = function ( col ) {
|
||||
|
||||
var g = new Geometry();
|
||||
//unit cube centered on 0
|
||||
var vertices = new Float32Array( [ -0.5, -0.5, -0.5,
|
||||
0.5, -0.5, -0.5,
|
||||
0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5,
|
||||
0.5, -0.5, 0.5,
|
||||
0.5, 0.5, 0.5, -0.5, 0.5, 0.5
|
||||
] );
|
||||
g.getAttributes().Vertex = new BufferArray( BufferArray.ARRAY_BUFFER, vertices, 3 );
|
||||
|
||||
// use color or red
|
||||
if ( !col ) col = [ 1.0, 0.0, 0.0, 1.0 ];
|
||||
var colors = new MACROUTILS.Float32Array( 8 * 4 );
|
||||
for ( var i = 0; i < 8; i++ ) {
|
||||
for ( var k = 0; k < 4; k++ ) {
|
||||
colors[ i * 3 + k ] = col[ k ];
|
||||
}
|
||||
}
|
||||
|
||||
g.getAttributes().Color = new BufferArray( BufferArray.ARRAY_BUFFER, colors, 4 );
|
||||
|
||||
var indexes = new MACROUTILS.Uint16Array(
|
||||
[
|
||||
//up
|
||||
0, 1,
|
||||
1, 2,
|
||||
2, 3,
|
||||
3, 0,
|
||||
//down
|
||||
4, 5,
|
||||
5, 6,
|
||||
6, 7,
|
||||
7, 4,
|
||||
// side
|
||||
0, 4,
|
||||
1, 5,
|
||||
2, 6,
|
||||
3, 7
|
||||
|
||||
] );
|
||||
|
||||
g.getPrimitives().push( new DrawElements( PrimitiveSet.LINES, new BufferArray( 'ELEMENT_ARRAY_BUFFER', indexes, 1 ) ) );
|
||||
|
||||
return g;
|
||||
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createTexturedBoxGeometry: createTexturedBoxGeometry,
|
||||
createTexturedQuadGeometry: createTexturedQuadGeometry,
|
||||
createTexturedSphereGeometry: createTexturedSphere,
|
||||
createTexturedBox: createTexturedBox,
|
||||
createTexturedFullScreenFakeQuadGeometry: createTexturedFullScreenFakeQuadGeometry,
|
||||
createTexturedQuad: createTexturedQuad,
|
||||
createAxisGeometry: createAxisGeometry,
|
||||
createTexturedSphere: createTexturedSphere,
|
||||
createGridGeometry: createGridGeometry,
|
||||
createBoundingBoxGeometry: createBoundingBoxGeometry
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
'use strict';
|
||||
module.exports = {
|
||||
RELATIVE_RF: 0,
|
||||
ABSOLUTE_RF: 1
|
||||
};
|
|
@ -1,58 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var Object = require( 'osg/Object' );
|
||||
var MatrixTransform = require( 'osg/MatrixTransform' );
|
||||
|
||||
|
||||
/**
|
||||
* AnimationUpdateCallback
|
||||
* @class AnimationUpdateCallback
|
||||
*/
|
||||
var AnimationUpdateCallback = function () {
|
||||
Object.call( this );
|
||||
};
|
||||
|
||||
// check if the path is animated, it could be elsewhere though
|
||||
AnimationUpdateCallback.checkPathIsAnimated = function ( path ) {
|
||||
|
||||
for ( var i = 0, nbNodes = path.length; i < nbNodes; ++i ) {
|
||||
var node = path[ i ];
|
||||
|
||||
if ( node instanceof MatrixTransform ) {
|
||||
var ups = node.getUpdateCallbackList();
|
||||
for ( var j = 0, nbUp = ups.length; j < nbUp; ++j ) {
|
||||
if ( ups[ j ] instanceof AnimationUpdateCallback )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/** @lends AnimationUpdateCallback.prototype */
|
||||
AnimationUpdateCallback.prototype = MACROUTILS.objectInherit( Object.prototype, {
|
||||
|
||||
linkChannel: function () {},
|
||||
linkAnimation: function ( anim ) {
|
||||
var name = this.getName();
|
||||
if ( name.length === 0 ) {
|
||||
Notify.log( 'no name on an update callback, discard' );
|
||||
return 0;
|
||||
}
|
||||
var nbLinks = 0;
|
||||
var channels = anim.getChannels();
|
||||
for ( var i = 0, l = channels.length; i < l; i++ ) {
|
||||
var channel = channels[ i ];
|
||||
if ( channel.getTargetName() === name ) {
|
||||
this.linkChannel( channel );
|
||||
nbLinks++;
|
||||
}
|
||||
}
|
||||
return nbLinks;
|
||||
}
|
||||
} );
|
||||
|
||||
module.exports = AnimationUpdateCallback;
|
|
@ -1,711 +0,0 @@
|
|||
'use strict';
|
||||
var Notify = require( 'osg/notify' );
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var BaseObject = require( 'osg/Object' );
|
||||
var quat = require( 'osg/glMatrix' ).quat;
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var Channel = require( 'osgAnimation/channel' );
|
||||
var Animation = require( 'osgAnimation/animation' );
|
||||
var Interpolator = require( 'osgAnimation/interpolator' );
|
||||
var CollectAnimationUpdateCallbackVisitor = require( 'osgAnimation/CollectAnimationUpdateCallbackVisitor' );
|
||||
var Target = require( 'osgAnimation/target' );
|
||||
var UpdateMorph = require( 'osgAnimation/UpdateMorph' );
|
||||
|
||||
|
||||
var Float = {
|
||||
lerp: function ( a, b, t ) {
|
||||
return a + ( b - a ) * t;
|
||||
},
|
||||
init: function () {
|
||||
return 0.0;
|
||||
},
|
||||
copy: function ( src ) {
|
||||
return src;
|
||||
},
|
||||
create: function () {
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
var TypeToSize = [];
|
||||
TypeToSize[ Channel.ChannelType.Float ] = 1;
|
||||
TypeToSize[ Channel.ChannelType.FloatCubicBezier ] = 1;
|
||||
TypeToSize[ Channel.ChannelType.Vec3 ] = 3;
|
||||
TypeToSize[ Channel.ChannelType.Vec3CubicBezier ] = 3;
|
||||
TypeToSize[ Channel.ChannelType.Quat ] = 4;
|
||||
TypeToSize[ Channel.ChannelType.QuatSlerp ] = 4;
|
||||
TypeToSize[ Channel.ChannelType.Matrix ] = 16;
|
||||
|
||||
|
||||
var ResultType = [];
|
||||
ResultType.length = Channel.ChannelType.Count;
|
||||
ResultType[ Channel.ChannelType.Vec3 ] = vec3;
|
||||
ResultType[ Channel.ChannelType.Quat ] = quat;
|
||||
ResultType[ Channel.ChannelType.QuatSlerp ] = quat;
|
||||
ResultType[ Channel.ChannelType.Float ] = Float;
|
||||
ResultType[ Channel.ChannelType.FloatCubicBezier ] = Float;
|
||||
ResultType[ Channel.ChannelType.Vec3CubicBezier ] = vec3;
|
||||
ResultType[ Channel.ChannelType.Matrix ] = mat4;
|
||||
|
||||
/**
|
||||
* BasicAnimationManager
|
||||
* @class BasicAnimationManager
|
||||
*/
|
||||
var BasicAnimationManager = function () {
|
||||
BaseObject.call( this );
|
||||
|
||||
this._simulationTime = 0.0;
|
||||
this._pauseTime = 0.0;
|
||||
this._timeFactor = 1.0;
|
||||
this._startTime = 0.0;
|
||||
|
||||
// contains a map with instance animations
|
||||
this._instanceAnimations = {};
|
||||
|
||||
// animations to start
|
||||
this._startAnimations = {};
|
||||
|
||||
// target contains an array of all target for this manager
|
||||
// index in the array is used as ID
|
||||
// see Animation.createTarget
|
||||
// [
|
||||
// { id: 0,
|
||||
// channels: [],
|
||||
// value: 0.0,
|
||||
// defaultValue: 0.0,
|
||||
// type
|
||||
// },
|
||||
// ...
|
||||
// ];
|
||||
this._targets = [];
|
||||
this._targetsMap = {};
|
||||
|
||||
// target id with active lists
|
||||
// [
|
||||
// vec3: [ targetID0, targetID1 ]
|
||||
// Quat: [ targetID2, targetID3, ... ]
|
||||
// Float: [ ... ]
|
||||
// ]
|
||||
this._targetsByTypes = [];
|
||||
this._targetsByTypes.length = Channel.ChannelType.Count;
|
||||
for ( var i = 0, ni = this._targetsByTypes.length; i < ni; i++ ) {
|
||||
this._targetsByTypes[ i ] = [];
|
||||
}
|
||||
|
||||
// current playing animations
|
||||
this._activeAnimations = {};
|
||||
this._activeAnimationList = [];
|
||||
|
||||
// current actives channels by types
|
||||
// [ chanel0, channel1, ... ] // vec3 type
|
||||
// [ chanel2, channel3, ... ] // Quat type
|
||||
// [ chanel5, channel6, ... ] // Float type
|
||||
this._activeChannelsByTypes = [];
|
||||
this._activeChannelsByTypes.length = Channel.ChannelType.Count;
|
||||
for ( var j = 0, nj = this._activeChannelsByTypes.length; j < nj; j++ ) {
|
||||
this._activeChannelsByTypes[ j ] = [];
|
||||
}
|
||||
|
||||
// assign all target/channel in animationCallback
|
||||
// then they can read it directly
|
||||
// animation callback to update
|
||||
this._animationsUpdateCallback = {};
|
||||
this._animationsUpdateCallbackArray = [];
|
||||
|
||||
// queue of animations to register
|
||||
this._animationsToRegister = [];
|
||||
|
||||
//Pause status (true / false)
|
||||
this._pause = false;
|
||||
|
||||
this._dirty = false;
|
||||
|
||||
this._seekTime = -1;
|
||||
};
|
||||
|
||||
BasicAnimationManager.prototype = MACROUTILS.objectInherit( BaseObject.prototype, {
|
||||
|
||||
init: function ( animations ) {
|
||||
|
||||
// reset all
|
||||
this._simulationTime = 0.0;
|
||||
this._pauseTime = 0.0;
|
||||
this._timeFactor = 1.0;
|
||||
this._startTime = 0.0;
|
||||
|
||||
// contains a map with instance animations
|
||||
this._instanceAnimations = {};
|
||||
|
||||
// animations to start
|
||||
this._startAnimations = {};
|
||||
|
||||
this._resetTargets();
|
||||
|
||||
this._activeAnimations = {};
|
||||
this._activeAnimationList.length = 0;
|
||||
|
||||
for ( var i = 0, ni = this._activeChannelsByTypes.length; i < ni; i++ )
|
||||
this._activeChannelsByTypes[ i ].length = 0;
|
||||
|
||||
this._animationsUpdateCallback = {};
|
||||
this._animationsUpdateCallbackArray.length = 0;
|
||||
|
||||
this._pause = false;
|
||||
this._seekTime = -1;
|
||||
|
||||
// add animations
|
||||
this.addAnimations( animations );
|
||||
},
|
||||
|
||||
|
||||
// push all animations into the queue
|
||||
addAnimations: function ( animations ) {
|
||||
|
||||
var instanceAnimationList = this._addAnimation( animations );
|
||||
|
||||
// qeue them to assign target
|
||||
Array.prototype.push.apply( this._animationsToRegister, instanceAnimationList );
|
||||
this._dirty = true;
|
||||
this._registerAnimations();
|
||||
},
|
||||
|
||||
|
||||
update: function ( node, nv ) {
|
||||
|
||||
if ( this._dirty ) {
|
||||
this._findAnimationUpdateCallback( node );
|
||||
this._registerTargetFoundInAnimationCallback();
|
||||
this._registerAnimations();
|
||||
}
|
||||
|
||||
var t = nv.getFrameStamp().getSimulationTime();
|
||||
|
||||
if ( this._seekTime !== -1 )
|
||||
this._pauseTime = -this._seekTime + this._startTime + t;
|
||||
this._seekTime = -1;
|
||||
|
||||
if ( !this._pause ) { // Not in pause
|
||||
this._simulationTime = this._startTime + ( t - this._pauseTime );
|
||||
} else {
|
||||
this._pauseTime = ( t - this._simulationTime + this._startTime );
|
||||
}
|
||||
|
||||
this.updateManager( this._simulationTime * this._timeFactor );
|
||||
return true;
|
||||
},
|
||||
|
||||
updateManager: function ( t ) {
|
||||
|
||||
|
||||
// adds active animations / channels requested
|
||||
//
|
||||
this._processStartAnimation( t );
|
||||
|
||||
var l = Channel.ChannelType.Count;
|
||||
// update all actives channels by type
|
||||
//
|
||||
for ( var i = 0; i < l; i++ ) {
|
||||
var activeChannelType = this._activeChannelsByTypes[ i ];
|
||||
this._updateChannelsType( t, activeChannelType, Interpolator[ i ] );
|
||||
}
|
||||
|
||||
// update targets
|
||||
//
|
||||
for ( var j = 0; j < l; j++ ) {
|
||||
var targetType = this._targetsByTypes[ j ];
|
||||
this._updateTargetType( targetType, ResultType[ j ] );
|
||||
}
|
||||
|
||||
|
||||
// update all animation callback
|
||||
// expect to have UpdateMatrixTransform
|
||||
for ( var k = 0, nk = this._animationsUpdateCallbackArray.length; k < nk; k++ ) {
|
||||
var animCallback = this._animationsUpdateCallbackArray[ k ];
|
||||
animCallback.computeChannels();
|
||||
}
|
||||
|
||||
// check animation finished
|
||||
this._removeFinishedAnimation( t );
|
||||
},
|
||||
|
||||
togglePause: function () { //Pause the manager's time
|
||||
this._pause = !this._pause;
|
||||
// if we resume an animation we don't want to move forward the animation
|
||||
if ( !this._pause )
|
||||
this._seekTime = this._simulationTime;
|
||||
},
|
||||
|
||||
getSimulationTime: function () {
|
||||
return this._simulationTime;
|
||||
},
|
||||
|
||||
setSimulationTime: function ( t ) {
|
||||
this._simulationTime = t;
|
||||
},
|
||||
|
||||
setSeekTime: function ( t ) {
|
||||
this._simulationTime = t;
|
||||
this._seekTime = t;
|
||||
},
|
||||
|
||||
stopAnimation: function ( name ) {
|
||||
var activeAnimationList = this._activeAnimationList;
|
||||
for ( var i = 0, nbAnim = activeAnimationList.length; i < nbAnim; ++i ) {
|
||||
if ( activeAnimationList[ i ].name === name ) {
|
||||
this._removeActiveChannels( this._instanceAnimations[ name ] );
|
||||
this._activeAnimations[ name ] = undefined;
|
||||
activeAnimationList.splice( i, 1 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stopAllAnimation: function () {
|
||||
var activeAnimationList = this._activeAnimationList;
|
||||
for ( var i = 0, nbAnim = activeAnimationList.length; i < nbAnim; ++i ) {
|
||||
var name = activeAnimationList[ i ].name;
|
||||
this._removeActiveChannels( this._instanceAnimations[ name ] );
|
||||
this._activeAnimations[ name ] = undefined;
|
||||
}
|
||||
activeAnimationList.length = 0;
|
||||
},
|
||||
|
||||
setTimeFactor: function ( timeFactor ) {
|
||||
var tf = timeFactor / this._timeFactor;
|
||||
this._startTime += ( this._simulationTime - this._simulationTime * tf ) / tf;
|
||||
|
||||
this._timeFactor = timeFactor;
|
||||
|
||||
if ( this._pause )
|
||||
this._simulationTime += ( this._simulationTime - this._simulationTime * tf ) / tf;
|
||||
},
|
||||
|
||||
getTimeFactor: function () {
|
||||
return this._timeFactor;
|
||||
},
|
||||
|
||||
isPlaying: function ( name ) {
|
||||
if ( this._activeAnimations[ name ] ) return true;
|
||||
return false;
|
||||
},
|
||||
|
||||
// play animation using object as config
|
||||
// {
|
||||
// name: string,
|
||||
// priority: 0,
|
||||
// weight: 1.0,
|
||||
// loop: true / false
|
||||
// }
|
||||
playAnimationObject: function ( obj ) {
|
||||
|
||||
var anim = this._instanceAnimations[ obj.name ];
|
||||
if ( !anim ) {
|
||||
Notify.info( 'no animation ' + obj.name + ' found' );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.isPlaying( obj.name ) ) return;
|
||||
|
||||
anim.priority = ( obj.priority === undefined ) ? 0 : obj.priority;
|
||||
anim.weight = ( obj.weight === undefined ) ? 1.0 : obj.weight;
|
||||
anim.loop = ( obj.loop === undefined ) ? true : obj.loop;
|
||||
|
||||
this._startAnimations[ anim.name ] = anim;
|
||||
},
|
||||
|
||||
// if first argument is an object
|
||||
// playAnimationObject is called instead
|
||||
playAnimation: function ( name, loop, priority, weight ) {
|
||||
|
||||
var animationObject;
|
||||
if ( typeof name === 'object' )
|
||||
animationObject = name;
|
||||
else {
|
||||
animationObject = {
|
||||
name: name,
|
||||
priority: priority,
|
||||
weight: weight,
|
||||
loop: loop
|
||||
};
|
||||
}
|
||||
|
||||
return this.playAnimationObject( animationObject );
|
||||
},
|
||||
|
||||
getAnimations: function () {
|
||||
return this._instanceAnimations;
|
||||
},
|
||||
|
||||
|
||||
_registerAnimations: function () {
|
||||
|
||||
if ( !this._targets.length ) return;
|
||||
|
||||
for ( var i = 0, ni = this._animationsToRegister.length; i < ni; i++ ) {
|
||||
var instanceAnimation = this._animationsToRegister[ i ];
|
||||
this._registerInstanceAnimation( instanceAnimation );
|
||||
}
|
||||
|
||||
this._animationsToRegister.length = 0;
|
||||
this._dirty = false;
|
||||
},
|
||||
|
||||
// Register animation
|
||||
//
|
||||
// Register animation list all target from channel in the animations and associate
|
||||
// target found in the scenegraph. If no target are registered animation cant be
|
||||
// registered. In this case animation will be pending and resolved after a visitor
|
||||
// extract target.
|
||||
_registerInstanceAnimation: function ( instanceAnimation ) {
|
||||
|
||||
var instanceChannels = instanceAnimation.channels;
|
||||
for ( var i = 0, ni = instanceChannels.length; i < ni; i++ ) {
|
||||
var instanceChannel = instanceChannels[ i ];
|
||||
var targetName = instanceChannel.channel.target;
|
||||
var name = instanceChannel.channel.name;
|
||||
var uniqueTargetName = targetName + '.' + name;
|
||||
|
||||
// disply a warning if animation has a channel but not target found in the
|
||||
// scene graph. We could probably optimize and removes those channels, but
|
||||
// it must be a user decision in case the user plugin different scene
|
||||
// graph together and target would appear later in the scenegraph
|
||||
if ( !this._targetMap[ uniqueTargetName ] ) {
|
||||
Notify.warn( 'registerInstanceAnimation did not find targetName (' + uniqueTargetName + ') in the scene graph' );
|
||||
continue;
|
||||
}
|
||||
|
||||
instanceChannel.targetID = this._targetMap[ uniqueTargetName ].id;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
_findAnimationUpdateCallback: function ( node ) {
|
||||
var collector = new CollectAnimationUpdateCallbackVisitor();
|
||||
node.accept( collector );
|
||||
this._animationsUpdateCallback = collector.getAnimationUpdateCallbackMap();
|
||||
},
|
||||
|
||||
// assignTargetToAnimationCallback
|
||||
//
|
||||
// check all animationUpdateCallback collected and try to
|
||||
// assign the channel instance registered in the manager. If a
|
||||
// animationUpdateCallback contains channels not known by the
|
||||
// manager we skip it. It means that it should be called
|
||||
// after the animations has been registered into the animation
|
||||
// manager
|
||||
_registerTargetFoundInAnimationCallback: function () {
|
||||
|
||||
this._resetTargets();
|
||||
|
||||
var targetID = 0;
|
||||
var targetMap = this._targetMap;
|
||||
var targets = this._targets;
|
||||
|
||||
var registerTarget = function ( uniqueTargetName, target, name ) {
|
||||
if ( !targetMap[ uniqueTargetName ] ) {
|
||||
targetMap[ uniqueTargetName ] = target;
|
||||
// assign an id that will be an index into a array
|
||||
target.id = targetID++;
|
||||
targets.push( target );
|
||||
|
||||
var type = target.type; // split by type
|
||||
this._targetsByTypes[ type ].push( target );
|
||||
} else {
|
||||
// detect differents target instance with same
|
||||
// unique target name. It's a problem
|
||||
if ( target !== targetMap[ uniqueTargetName ] )
|
||||
Notify.warn( 'detected differents target instance with the same name (' + name + ')' );
|
||||
}
|
||||
}.bind( this );
|
||||
|
||||
|
||||
var target;
|
||||
var name;
|
||||
var uniqueTargetName;
|
||||
|
||||
var animationCallbackMap = this._animationsUpdateCallback;
|
||||
var keys = window.Object.keys( animationCallbackMap );
|
||||
for ( var i = 0, ni = keys.length; i < ni; i++ ) {
|
||||
var key = keys[ i ];
|
||||
var animationCallback = animationCallbackMap[ key ];
|
||||
|
||||
// handle UpdateBone and UpdateMatrixTransform but not stateSet
|
||||
if ( animationCallback.getStackedTransforms && animationCallback.getStackedTransforms().length ) {
|
||||
this._animationsUpdateCallbackArray.push( animationCallback );
|
||||
|
||||
var stackedTransforms = animationCallback.getStackedTransforms();
|
||||
for ( var j = 0, nj = stackedTransforms.length; j < nj; j++ ) {
|
||||
var stackedTransform = stackedTransforms[ j ];
|
||||
target = stackedTransform.getTarget();
|
||||
name = stackedTransform.getName();
|
||||
uniqueTargetName = animationCallback.getName() + '.' + name;
|
||||
|
||||
registerTarget( uniqueTargetName, target, name );
|
||||
}
|
||||
} else if ( animationCallback instanceof UpdateMorph ) {
|
||||
for ( var t = 0, numTarget = animationCallback.getNumTarget(); t < numTarget; t++ ) {
|
||||
name = animationCallback.getTargetName( t );
|
||||
uniqueTargetName = name + '.' + t;
|
||||
target = animationCallback.getTarget( t );
|
||||
|
||||
registerTarget( uniqueTargetName, target, name );
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_addAnimation: function ( animations ) {
|
||||
|
||||
var instanceAnimationList = [];
|
||||
for ( var i = 0, ni = animations.length; i < ni; i++ ) {
|
||||
|
||||
var animation = animations[ i ];
|
||||
var animationName = animation.name;
|
||||
|
||||
if ( this._instanceAnimations[ animationName ] )
|
||||
continue;
|
||||
|
||||
var instanceAnimation = Animation.createInstanceAnimation( animation );
|
||||
this._instanceAnimations[ animationName ] = instanceAnimation;
|
||||
instanceAnimationList.push( instanceAnimation );
|
||||
}
|
||||
|
||||
return instanceAnimationList;
|
||||
},
|
||||
|
||||
// add channels from instance animation to the active channels list
|
||||
_addActiveChannels: function ( t, instanceAnimation ) {
|
||||
|
||||
var instanceChannels = instanceAnimation.channels;
|
||||
for ( var i = 0, ni = instanceChannels.length; i < ni; i++ ) {
|
||||
var instanceChannel = instanceChannels[ i ];
|
||||
var type = instanceChannel.channel.type;
|
||||
instanceChannel.t = t; // reset time
|
||||
instanceChannel.instanceAnimation = instanceAnimation; // link with parent animation
|
||||
var targetID = instanceChannel.targetID;
|
||||
|
||||
if ( targetID === Target.InvalidTargetID ) continue;
|
||||
|
||||
this._activeChannelsByTypes[ type ].push( instanceChannel );
|
||||
this._targets[ targetID ].channels.push( instanceChannel );
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_removeActiveChannels: function ( instanceAnimation ) {
|
||||
|
||||
var instanceChannels = instanceAnimation.channels;
|
||||
for ( var i = 0, ni = instanceChannels.length; i < ni; i++ ) {
|
||||
var instanceChannel = instanceChannels[ i ];
|
||||
var type = instanceChannel.channel.type;
|
||||
var targetID = instanceChannel.targetID;
|
||||
|
||||
if ( targetID === Target.InvalidTargetID ) continue;
|
||||
|
||||
// remove channel instance from targetID channel list
|
||||
var targetChannelsList = this._targets[ targetID ].channels;
|
||||
var index = targetChannelsList.indexOf( instanceChannel );
|
||||
targetChannelsList.splice( index, 1 );
|
||||
|
||||
// remove channel from active channels
|
||||
var channelTypeList = this._activeChannelsByTypes[ type ];
|
||||
var channelIndex = channelTypeList.indexOf( instanceChannel );
|
||||
channelTypeList.splice( channelIndex, 1 );
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// blend value from each channels for each target
|
||||
// or copy default value if not updated by an active animation
|
||||
_updateTargetType: function ( targetList, operatorType ) {
|
||||
|
||||
for ( var i = 0, ni = targetList.length; i < ni; i++ ) {
|
||||
|
||||
var target = targetList[ i ];
|
||||
var affectedChannels = target.channels;
|
||||
var nbChannels = affectedChannels.length;
|
||||
// note operatorType operations doesn't always operate on arrays (float)
|
||||
// so we can't simply assume that target.value is an array so we need
|
||||
// to write "target.value = ..."
|
||||
|
||||
if ( nbChannels === 0 ) { // no blending ?
|
||||
target.value = operatorType.copy( target.defaultValue, target.value );
|
||||
|
||||
} else if ( nbChannels === 1 ) {
|
||||
target.value = operatorType.copy( affectedChannels[ 0 ].value, target.value );
|
||||
|
||||
} else {
|
||||
|
||||
// blend between multiple channels
|
||||
target.value = operatorType.init( target.value );
|
||||
var accumulatedWeight = 0.0;
|
||||
|
||||
// it's the same as targetOut = (v0 * w0 + v1 * w1 + ...) / (w0 + w1 + ...)
|
||||
for ( var j = 0, nj = affectedChannels.length; j < nj; j++ ) {
|
||||
|
||||
var achannel = affectedChannels[ j ];
|
||||
var weight = achannel.weight;
|
||||
accumulatedWeight += weight;
|
||||
// avoid divide by zero and useless lerp
|
||||
if ( accumulatedWeight === 0.0 || weight === 0.0 )
|
||||
continue;
|
||||
|
||||
var ratio = weight / accumulatedWeight;
|
||||
target.value = operatorType.lerp( target.value, target.value, achannel.value, ratio );
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_updateChannelsType: function ( t, channels, interpolator ) {
|
||||
|
||||
for ( var i = 0, ni = channels.length; i < ni; i++ ) {
|
||||
var channel = channels[ i ];
|
||||
var instanceAnimation = channel.instanceAnimation;
|
||||
var loop = instanceAnimation.loop;
|
||||
|
||||
var tLocal = t - channel.t;
|
||||
|
||||
// handle loop, careful in case animation is one frame
|
||||
if ( loop && instanceAnimation.duration > 0.0 ) tLocal = tLocal % instanceAnimation.duration;
|
||||
|
||||
interpolator( tLocal + instanceAnimation.firstKeyTime, channel );
|
||||
}
|
||||
},
|
||||
|
||||
_removeFinishedAnimation: function ( t ) {
|
||||
|
||||
var activeAnimationList = this._activeAnimationList;
|
||||
|
||||
var i = 0;
|
||||
while ( i < activeAnimationList.length ) {
|
||||
var instanceAnimation = activeAnimationList[ i ];
|
||||
var name = instanceAnimation.name;
|
||||
|
||||
if ( t > instanceAnimation.end && instanceAnimation.loop === false ) {
|
||||
this._removeActiveChannels( instanceAnimation );
|
||||
this._activeAnimations[ name ] = undefined;
|
||||
activeAnimationList.splice( i, 1 );
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_addActiveAnimation: function ( t, cmd ) {
|
||||
|
||||
this._activeAnimations[ cmd.name ] = cmd; // set animation in the list of active one
|
||||
|
||||
var instanceAnimation = this._instanceAnimations[ cmd.name ];
|
||||
instanceAnimation.start = t;
|
||||
instanceAnimation.end = t + instanceAnimation.duration;
|
||||
this._addActiveChannels( t, instanceAnimation );
|
||||
|
||||
// keep track of instance animation active in a list
|
||||
this._activeAnimationList.push( instanceAnimation );
|
||||
},
|
||||
|
||||
// execute start animations events
|
||||
// during the updateManager
|
||||
_processStartAnimation: function ( t ) {
|
||||
|
||||
// dont really start animation if we dont have yet targets
|
||||
if ( !this._targets.length ) return;
|
||||
|
||||
var animations = this._startAnimations;
|
||||
var keys = window.Object.keys( animations );
|
||||
for ( var i = 0, ni = keys.length; i < ni; i++ ) {
|
||||
var key = keys[ i ];
|
||||
var cmd = animations[ key ];
|
||||
var name = cmd.name;
|
||||
|
||||
if ( this.isPlaying( name ) )
|
||||
continue;
|
||||
|
||||
this._addActiveAnimation( t, cmd );
|
||||
}
|
||||
|
||||
if ( keys.length ) this._startAnimations = {};
|
||||
},
|
||||
|
||||
_resetTargets: function () {
|
||||
|
||||
this._targetMap = {};
|
||||
this._targets.length = 0;
|
||||
|
||||
for ( var i = 0, ni = this._targetsByTypes.length; i < ni; i++ ) {
|
||||
this._targetsByTypes[ i ].length = 0;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
resetAllStackedTransforms: function () {
|
||||
var anims = this._animationsUpdateCallbackArray;
|
||||
for ( var i = 0, nbAnims = anims.length; i < nbAnims; i++ ) {
|
||||
var stacked = anims[ i ].getStackedTransforms();
|
||||
for ( var j = 0, nbStacked = stacked.length; j < nbStacked; j++ ) {
|
||||
stacked[ j ].resetToDefaultValue();
|
||||
}
|
||||
|
||||
// computeChannels is not mandatory here as the following frame will call
|
||||
// this function anyway
|
||||
anims[ i ].computeChannels();
|
||||
}
|
||||
},
|
||||
|
||||
setAnimationLerpEndStart: function ( anim, lerpDuration ) {
|
||||
var channels = anim.channels;
|
||||
if ( anim.originalDuration === undefined )
|
||||
anim.originalDuration = anim.duration;
|
||||
|
||||
anim.duration = anim.originalDuration + lerpDuration;
|
||||
|
||||
var firstKey = anim.firstKeyTime;
|
||||
var animDuration = anim.originalDuration;
|
||||
|
||||
for ( var i = 0, nbChannels = channels.length; i < nbChannels; ++i ) {
|
||||
var ch = channels[ i ].channel;
|
||||
|
||||
// compare first and last key and detect if we can loop the channel or not
|
||||
// it uses an arbitrary epsilon
|
||||
if ( Math.abs( ch.start - firstKey ) > 0.01 || Math.abs( ch.duration - animDuration ) > 0.01 )
|
||||
continue;
|
||||
|
||||
// update channel end time
|
||||
if ( ch.originalEnd === undefined )
|
||||
ch.originalEnd = ch.end;
|
||||
|
||||
ch.end = ch.originalEnd + lerpDuration;
|
||||
|
||||
// add or remove additonal key and time
|
||||
|
||||
var sizeElt = TypeToSize[ ch.type ];
|
||||
var size = ch.times.buffer.byteLength / 4;
|
||||
|
||||
// no lerp between end and start
|
||||
if ( lerpDuration === 0.0 ) {
|
||||
|
||||
ch.keys = new Float32Array( ch.keys.buffer, 0, ( size - 1 ) * sizeElt );
|
||||
ch.times = new Float32Array( ch.times.buffer, 0, size - 1 );
|
||||
|
||||
} else {
|
||||
|
||||
// take full size of buffer (with additional keys)
|
||||
ch.keys = new Float32Array( ch.keys.buffer, 0, size * sizeElt );
|
||||
// copy first key
|
||||
var idLast = ( size - 1 ) * sizeElt;
|
||||
for ( var j = 0; j < sizeElt; ++j )
|
||||
ch.keys[ idLast + j ] = ch.keys[ j ];
|
||||
|
||||
ch.times = new Float32Array( ch.times.buffer, 0, size );
|
||||
ch.times[ size - 1 ] = ch.times[ size - 2 ] + lerpDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
BasicAnimationManager.TypeToSize = TypeToSize;
|
||||
|
||||
module.exports = BasicAnimationManager;
|
|
@ -1,84 +0,0 @@
|
|||
'use strict';
|
||||
var MACROUTILS = require( 'osg/Utils' );
|
||||
var vec3 = require( 'osg/glMatrix' ).vec3;
|
||||
var BoundingBox = require( 'osg/BoundingBox' );
|
||||
var mat4 = require( 'osg/glMatrix' ).mat4;
|
||||
var MatrixTransform = require( 'osg/MatrixTransform' );
|
||||
var UpdateBone = require( 'osgAnimation/UpdateBone' );
|
||||
|
||||
|
||||
/**
|
||||
* Bone
|
||||
* @class Bone
|
||||
*/
|
||||
var Bone = function ( name ) {
|
||||
if ( name !== undefined )
|
||||
this.setName( name );
|
||||
|
||||
MatrixTransform.call( this );
|
||||
this._invBindInSkeletonSpace = mat4.create();
|
||||
this._boneInSkeletonSpace = mat4.create();
|
||||
this._boneBoundingBox = new BoundingBox();
|
||||
};
|
||||
|
||||
Bone.prototype = MACROUTILS.objectLibraryClass( MACROUTILS.objectInherit( MatrixTransform.prototype, {
|
||||
|
||||
// consistent color depending of id
|
||||
// _rand: function ( id ) {
|
||||
// var x = Math.sin( id * 45.233 ) * 43758.5453;
|
||||
// return x - Math.floor( x );
|
||||
// },
|
||||
// _generateBoneColor: function ( id ) {
|
||||
// return vec3.fromValues( this._rand( id + 2.16 ), this._rand( id * 57.27 ), this._rand( id * 0.874 ) );
|
||||
// },
|
||||
|
||||
getOrCreateDebugColor: function () {
|
||||
// for bone display (debugging, etc)
|
||||
if ( this._boneColor ) return this._boneColor;
|
||||
// this._boneColor = this._generateBoneColor( this.getInstanceID() );
|
||||
this._boneColor = vec3.fromValues( Math.random(), Math.random(), Math.random() );
|
||||
return this._boneColor;
|
||||
},
|
||||
|
||||
getBoneBoundingBox: function () {
|
||||
return this._boneBoundingBox;
|
||||
},
|
||||
|
||||
setBoneBoundingBox: function ( bb ) {
|
||||
this._boneBoundingBox = bb;
|
||||
},
|
||||
|
||||
getMatrixInSkeletonSpace: function () {
|
||||
return this._boneInSkeletonSpace;
|
||||
},
|
||||
|
||||
getInvBindMatrixInSkeletonSpace: function () {
|
||||
return this._invBindInSkeletonSpace;
|
||||
},
|
||||
|
||||
setMatrixInSkeletonSpace: function ( m ) {
|
||||
mat4.copy( this._boneInSkeletonSpace, m );
|
||||
},
|
||||
|
||||
setInvBindMatrixInSkeletonSpace: function ( m ) {
|
||||
mat4.copy( this._invBindInSkeletonSpace, m );
|
||||
},
|
||||
|
||||
getBoneParent: function () {
|
||||
var parents = this.getParents();
|
||||
for ( var i = 0, l = parents.length; i < l; i++ ) {
|
||||
var typeID = parents[ i ].getTypeID();
|
||||
if ( typeID === Bone.getTypeID() ) {
|
||||
return parents[ i ];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
setDefaultUpdateCallback: function ( name ) {
|
||||
this.addUpdateCallback( new UpdateBone( ( name !== undefined ) ? name : this.getName() ) );
|
||||
}
|
||||
} ), 'osgAnimation', 'Bone' );
|
||||
MACROUTILS.setTypeID( Bone );
|
||||
|
||||
module.exports = Bone;
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue