summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@theqtcompany.com>2015-08-17 17:05:44 +0300
committerTomi Korpipää <tomi.korpipaa@theqtcompany.com>2015-09-07 04:31:39 +0000
commit43be52c04a47e56c560c9ceb00169eeb22bf1976 (patch)
tree558c05b52ff7cabe96166548e399a2a116b89ccd /examples
parentbdcaa493148617e18c7265915771bba5d32f0d77 (diff)
Added interactive cellphone demo example
The cellphone demo creates an interactive mobile phone UI with QML and displays it on 3D model of the phone. The UI is fully interactive when phone is rotated to face the used. Change-Id: I8d3c94a75c853747b68208c9aed00429764174ea Reviewed-by: Tomi Korpipää <tomi.korpipaa@theqtcompany.com> Reviewed-by: Pasi Keränen <pasi.keranen@digia.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/canvas3d/canvas3d/3rdparty/three.js12907
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/cellphone.pro15
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/cellphone.qrc30
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/doc/src/cellphone.qdoc111
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/calendar.pngbin0 -> 7971 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/camera.pngbin0 -> 9107 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/clock.pngbin0 -> 9180 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/contacts.pngbin0 -> 9683 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/gallery.pngbin0 -> 9634 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/games.pngbin0 -> 10201 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/lock.pngbin0 -> 3978 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/mail.pngbin0 -> 8612 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/maps.pngbin0 -> 9902 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/menu_background.jpgbin0 -> 102065 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/music.pngbin0 -> 9815 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/plutomap1k.jpgbin0 -> 325111 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/qtlogo_with_alpha.pngbin0 -> 7131 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/settings.pngbin0 -> 10206 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/todo.pngbin0 -> 7918 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/images/videos.pngbin0 -> 9854 bytes
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/main.cpp49
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone.js197
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_case.json34
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_front.json34
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_icon.json34
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphoneapp.qml376
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphonecanvas.qml247
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/colorselector.qml99
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/fpsdisplay.qml89
-rw-r--r--examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/main.qml125
-rw-r--r--examples/canvas3d/canvas3d/threejs/threejs.pro3
31 files changed, 7918 insertions, 6432 deletions
diff --git a/examples/canvas3d/canvas3d/3rdparty/three.js b/examples/canvas3d/canvas3d/3rdparty/three.js
index 04823db..9dd4d75 100644
--- a/examples/canvas3d/canvas3d/3rdparty/three.js
+++ b/examples/canvas3d/canvas3d/3rdparty/three.js
@@ -25,6440 +25,12 @@ THE SOFTWARE.
*/
/**
- * QtQuick port of three.js library https://github.com/mrdoob/three.js
- * Port source code is available at https://github.com/tronlec/three.js
+ * QtQuick port of three.js library from: https://github.com/mrdoob/three.js
+ * Latest version for current stable Qt version can be found at: https://github.com/tronlec/three.js/tree/stable
+ * Latest version for current Qt version under development can be found at: https://github.com/tronlec/three.js/tree/master
* @author Pasi keränen / pasi.keranen@theqtcompany.com
*/
-// File:src/qml/QmlImageElement.js
-
-var __texImageToImageMap = {};
-
-function Image () {
- this.crossOrigin = undefined;
- this._src = undefined;
- this._onSuccessCallback = undefined;
- this._onProgressCallback = undefined;
- this._onErrorCallback = undefined;
- this._width = 0;
- this._height = 0;
- this._texImage = TextureImageFactory.newTexImage();
- __texImageToImageMap[""+this._texImage.id()] = this;
-
- // Setup mapping between the native QObject image and this image
- var _this = this;
-
- this._texImage.imageLoaded.connect(function() { _this.notifySuccess(_this) });
- this._texImage.imageLoadingFailed.connect(function() { _this.notifyError(_this) });
-
- this.__defineGetter__("src", function(){
- return _this._src;
- });
-
- this.__defineSetter__("src", function(url){
- if (url && url !== '' && url !== _this._src) {
- _this._texImage.src = ""+url;
- _this._texImage.name = ""+url;
- }
- _this._src = url;
- });
-
- this.__defineGetter__("width", function(){
- return (_this._texImage !== undefined)?_this._texImage.width:0;
- });
-
- this.__defineSetter__("width", function(url){
- console.log("TODO: Implement image resize");
- });
-
- this.__defineGetter__("height", function(){
- return (_this._texImage !== undefined)?_this._texImage.height:0;
- });
-
- this.__defineSetter__("height", function(url){
- console.log("TODO: Implement image resize");
- });
-};
-
-Image.prototype = {
- constructor: Image,
-
- addEventListener: function( eventName, callback, flag ) {
- if (eventName === 'load') {
- this._onSuccessCallback = callback;
- } else if (eventName === 'progress') {
- this._onProgressCallback = callback;
- } else if (eventName === 'error') {
- this._onErrorCallback = callback;
- }
- },
-
- notifySuccess: function(image) {
- if (this._onSuccessCallback !== undefined) {
- this._onSuccessCallback(new Event());
- }
- },
-
- notifyProgress: function(image) {
- if (this._onProgressCallback !== undefined) {
- this._onProgressCallback(new Event());
- }
- },
-
- notifyError: function(image) {
- if (this._onErrorCallback !== undefined) {
- this._onErrorCallback(new Event());
- }
- },
-
- texImage: function() {
- return this._texImage;
- },
-
- data: function() {
- console.error("Image.data not implemented!");
- }
-};
-
-// TODO: Support for resizing:
-//where.image.width = width;
-//where.image.height = height;
-//where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height );
-
-// File:src/qml/QmlHtmlElements.js
-
-// HTML document and Element wrappers/stubs
-
-function document() {
-}
-
-document.createElement = function(type) {
- if (type === "img") {
- return new Image();
- } else if (type === 'div') {
- return new HtmlDiv();
- }
-
- return new HtmlElement();
-}
-
-document.createTextNode = function(value) {
- return new HtmlElement();
-}
-
-function Event() {
-}
-
-Event.prototype = {
- constructor: Event
-}
-
-function HtmlStyle() {
- this.position = undefined;
- this.right = undefined;
- this.top = undefined;
- this.fontSize = undefined;
- this.textAlign = undefined;
- this.background = undefined;
- this.color = undefined;
- this.width = undefined;
- this.width = undefined;
- this.padding = undefined;
- this.zIndex = undefined;
-}
-
-function HtmlElement() {
- this.style = new HtmlStyle();
-}
-
-HtmlElement.prototype = {
- constructor: HtmlElement,
-
- appendChild: function(child) {
- }
-}
-
-function HtmlDiv() {
- this.innerHTML = "";
- this.style = new HtmlStyle();
-}
-
-
-
-// File:src/qml/Canvas3DRenderer.js
-
-/**
- * @author supereggbert / http://www.paulbrunt.co.uk/
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- * @author szimek / https://github.com/szimek/
- * @author pasikeranen / pasi.keranen@theqtcompany.com
- */
-
-THREE.Canvas3DRenderer = function ( parameters ) {
-
- console.log( 'THREE.Canvas3DRenderer', THREE.REVISION );
-
- parameters = parameters || {};
-
- if (parameters.canvas === undefined) {
- console.error("parameter.canvas must be set when using THREE.Canvas3DRenderer");
- return;
- }
-
- var _canvas = parameters.canvas,
- _context = parameters.context !== undefined ? parameters.context : null,
-
- pixelRatio = 1,
-
- _precision = parameters.precision !== undefined ? parameters.precision : 'highp',
-
- _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
- _depth = parameters.depth !== undefined ? parameters.depth : true,
- _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
- _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
- _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
- _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
- _logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false,
-
- _clearColor = new THREE.Color( 0x000000 ),
- _clearAlpha = parameters.clearAlpha !== undefined ? parameters.clearAlpha : 0;
-
- var lights = [];
-
- var _webglObjects = {};
- var _webglObjectsImmediate = [];
-
- var opaqueObjects = [];
- var transparentObjects = [];
-
- var sprites = [];
- var lensFlares = [];
-
- // public properties
-
- this.domElement = _canvas;
- this.context = null;
- pixelRatio = parameters.devicePixelRatio !== undefined
- ? parameters.devicePixelRatio
- : self.pixelRatio !== undefined
- ? self.pixelRatio
- : 1;
-
- // clearing
-
- this.autoClear = true;
- this.autoClearColor = true;
- this.autoClearDepth = true;
- this.autoClearStencil = true;
-
- // scene graph
-
- this.sortObjects = true;
-
- // physically based shading
-
- this.gammaFactor = 2.0; // for backwards compatibility
- this.gammaInput = false;
- this.gammaOutput = false;
-
- // shadow map
-
- this.shadowMapEnabled = false;
- this.shadowMapType = THREE.PCFShadowMap;
- this.shadowMapCullFace = THREE.CullFaceFront;
- this.shadowMapDebug = false;
- this.shadowMapCascade = false;
-
- // morphs
-
- this.maxMorphTargets = 8;
- this.maxMorphNormals = 4;
-
- // flags
-
- this.autoScaleCubemaps = true;
-
- // info
-
- this.info = {
-
- memory: {
-
- programs: 0,
- geometries: 0,
- textures: 0
-
- },
-
- render: {
-
- calls: 0,
- vertices: 0,
- faces: 0,
- points: 0
-
- }
-
- };
-
- // internal properties
-
- var _this = this,
-
- _programs = [],
-
- // internal state cache
-
- _currentProgram = null,
- _currentFramebuffer = null,
- _currentMaterialId = - 1,
- _currentGeometryProgram = '',
- _currentCamera = null,
-
- _usedTextureUnits = 0,
-
- _viewportX = 0,
- _viewportY = 0,
- _viewportWidth = _canvas.width,
- _viewportHeight = _canvas.height,
- _currentWidth = 0,
- _currentHeight = 0,
-
- // frustum
-
- _frustum = new THREE.Frustum(),
-
- // camera matrices cache
-
- _projScreenMatrix = new THREE.Matrix4(),
-
- _vector3 = new THREE.Vector3(),
-
- // light arrays cache
-
- _direction = new THREE.Vector3(),
-
- _lightsNeedUpdate = true,
-
- _lights = {
-
- ambient: [ 0, 0, 0 ],
- directional: { length: 0, colors:[], positions: [] },
- point: { length: 0, colors: [], positions: [], distances: [], decays: [] },
- spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] },
- hemi: { length: 0, skyColors: [], groundColors: [], positions: [] }
-
- };
-
- // initialize
-
- var _gl;
-
- try {
-
- var attributes = {
- alpha: _alpha,
- depth: _depth,
- stencil: _stencil,
- antialias: _antialias,
- premultipliedAlpha: _premultipliedAlpha,
- preserveDrawingBuffer: _preserveDrawingBuffer
- };
-
- _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
-
- if ( _gl === null ) {
-
- if ( _canvas.getContext( 'webgl') !== null ) {
-
- throw 'Error creating WebGL context with your selected attributes.';
-
- } else {
-
- throw 'Error creating WebGL context.';
-
- }
-
- }
-
-// _canvas.addEventListener( 'webglcontextlost', function ( event ) {
-//
-// event.preventDefault();
-//
-// resetGLState();
-// setDefaultGLState();
-//
-// _webglObjects = {};
-//
-// }, false);
-//
- } catch ( error ) {
-
- THREE.error( 'THREE.Canvas3DRenderer: ' + error );
-
- }
-
- var state = new THREE.WebGLState( _gl, paramThreeToGL );
-
- if ( _gl.getShaderPrecisionFormat === undefined ) {
-
- _gl.getShaderPrecisionFormat = function () {
-
- return {
- 'rangeMin': 1,
- 'rangeMax': 1,
- 'precision': 1
- };
-
- }
-
- }
-
- var extensions = new THREE.WebGLExtensions( _gl );
-
- extensions.get( 'OES_texture_float' );
- extensions.get( 'OES_texture_float_linear' );
- extensions.get( 'OES_texture_half_float' );
- extensions.get( 'OES_texture_half_float_linear' );
- extensions.get( 'OES_standard_derivatives' );
-
- if ( _logarithmicDepthBuffer ) {
-
- extensions.get( 'EXT_frag_depth' );
-
- }
-
- //
-
- var glClearColor = function ( r, g, b, a ) {
-
- if ( _premultipliedAlpha === true ) {
-
- r *= a; g *= a; b *= a;
-
- }
-
- _gl.clearColor( r, g, b, a );
-
- };
-
- var setDefaultGLState = function () {
-
- _gl.clearColor( 0, 0, 0, 1 );
- _gl.clearDepth( 1 );
- _gl.clearStencil( 0 );
-
- _gl.enable( _gl.DEPTH_TEST );
- _gl.depthFunc( _gl.LEQUAL );
-
- _gl.frontFace( _gl.CCW );
- _gl.cullFace( _gl.BACK );
- _gl.enable( _gl.CULL_FACE );
-
- _gl.enable( _gl.BLEND );
- _gl.blendEquation( _gl.FUNC_ADD );
- _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
-
- _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
-
- glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
-
- };
-
- var resetGLState = function () {
-
- _currentProgram = null;
- _currentCamera = null;
-
- _currentGeometryProgram = '';
- _currentMaterialId = - 1;
-
- _lightsNeedUpdate = true;
-
- state.reset();
-
- };
-
- setDefaultGLState();
-
- this.context = _gl;
- this.state = state;
-
- // GPU capabilities
-
- var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
- var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
- var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
- var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
-
- var _supportsVertexTextures = _maxVertexTextures > 0;
- var _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' );
-
- //
-
- var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
- var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
-
- var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
- var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
-
- var getCompressedTextureFormats = ( function () {
-
- var array;
-
- return function () {
-
- if ( array !== undefined ) {
-
- return array;
-
- }
-
- array = [];
-
- if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) {
-
- var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS );
-
- for ( var i = 0; i < formats.length; i ++ ) {
-
- array.push( formats[ i ] );
-
- }
-
- }
-
- return array;
-
- };
-
- } )();
-
- // clamp precision to maximum available
-
- var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
- var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
-
- if ( _precision === 'highp' && ! highpAvailable ) {
-
- if ( mediumpAvailable ) {
-
- _precision = 'mediump';
- THREE.warn( 'THREE.Canvas3DRenderer: highp not supported, using mediump.' );
-
- } else {
-
- _precision = 'lowp';
- THREE.warn( 'THREE.Canvas3DRenderer: highp and mediump not supported, using lowp.' );
-
- }
-
- }
-
- if ( _precision === 'mediump' && ! mediumpAvailable ) {
-
- _precision = 'lowp';
- THREE.warn( 'THREE.Canvas3DRenderer: mediump not supported, using lowp.' );
-
- }
-
- // Plugins
-
- var shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate );
-
- var spritePlugin = new THREE.SpritePlugin( this, sprites );
- var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares );
-
- // API
-
- this.getContext = function () {
-
- return _gl;
-
- };
-
- this.forceContextLoss = function () {
-
- //extensions.get( 'WEBGL_lose_context' ).loseContext();
-
- };
-
- this.supportsVertexTextures = function () {
-
- return _supportsVertexTextures;
-
- };
-
- this.supportsFloatTextures = function () {
-
- return extensions.get( 'OES_texture_float' );
-
- };
-
- this.supportsHalfFloatTextures = function () {
-
- return extensions.get( 'OES_texture_half_float' );
-
- };
-
- this.supportsStandardDerivatives = function () {
-
- return extensions.get( 'OES_standard_derivatives' );
-
- };
-
- this.supportsCompressedTextureS3TC = function () {
-
- return extensions.get( 'WEBGL_compressed_texture_s3tc' );
-
- };
-
- this.supportsCompressedTexturePVRTC = function () {
-
- return extensions.get( 'WEBGL_compressed_texture_pvrtc' );
-
- };
-
- this.supportsBlendMinMax = function () {
-
- return extensions.get( 'EXT_blend_minmax' );
-
- };
-
- this.getMaxAnisotropy = ( function () {
-
- var value;
-
- return function () {
-
- if ( value !== undefined ) {
-
- return value;
-
- }
-
- var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
-
- value = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
-
- return value;
-
- }
-
- } )();
-
- this.getPrecision = function () {
-
- return _precision;
-
- };
-
- this.getPixelRatio = function () {
-
- return pixelRatio;
-
- };
-
- this.setPixelRatio = function ( value ) {
-
- pixelRatio = value;
-
- };
-
- this.setSize = function ( width, height, updateStyle ) {
-
- _canvas.pixelSize = Qt.size(width * pixelRatio, height * pixelRatio)
-
- if ( updateStyle !== false ) {
-
-// Update styles is ignored in Canvas3D
-// _canvas.style.width = width + 'px';
-// _canvas.style.height = height + 'px';
-
- }
-
- this.setViewport( 0, 0, width, height );
-
- };
-
- this.setViewport = function ( x, y, width, height ) {
-
- _viewportX = x * pixelRatio;
- _viewportY = y * pixelRatio;
-
- _viewportWidth = width * pixelRatio;
- _viewportHeight = height * pixelRatio;
-
- _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
-
- };
-
- this.setScissor = function ( x, y, width, height ) {
-
- _gl.scissor(
- x * pixelRatio,
- y * pixelRatio,
- width * pixelRatio,
- height * pixelRatio
- );
-
- };
-
- this.enableScissorTest = function ( enable ) {
-
- if (enable)
- _gl.enable( _gl.SCISSOR_TEST )
- else
- _gl.disable( _gl.SCISSOR_TEST );
-
- };
-
- // Clearing
-
- this.getClearColor = function () {
-
- return _clearColor;
-
- };
-
- this.setClearColor = function ( color, alpha ) {
-
- _clearColor.set( color );
-
- _clearAlpha = alpha !== undefined ? alpha : 1;
-
- glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
-
- };
-
- this.getClearAlpha = function () {
-
- return _clearAlpha;
-
- };
-
- this.setClearAlpha = function ( alpha ) {
-
- _clearAlpha = alpha;
-
- glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
-
- };
-
- this.clear = function ( color, depth, stencil ) {
-
- var bits = 0;
-
- if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
- if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
- if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
-
- _gl.clear( bits );
-
- };
-
- this.clearColor = function () {
-
- _gl.clear( _gl.COLOR_BUFFER_BIT );
-
- };
-
- this.clearDepth = function () {
-
- _gl.clear( _gl.DEPTH_BUFFER_BIT );
-
- };
-
- this.clearStencil = function () {
-
- _gl.clear( _gl.STENCIL_BUFFER_BIT );
-
- };
-
- this.clearTarget = function ( renderTarget, color, depth, stencil ) {
-
- this.setRenderTarget( renderTarget );
- this.clear( color, depth, stencil );
-
- };
-
- // Reset
-
- this.resetGLState = resetGLState;
-
- // Buffer allocation
-
- function createParticleBuffers ( geometry ) {
-
- geometry.__webglVertexBuffer = _gl.createBuffer();
- geometry.__webglVertexBuffer.name = "Particle__webglVertexBuffer";
- geometry.__webglColorBuffer = _gl.createBuffer();
- geometry.__webglColorBuffer.name = "Particle__webglColorBuffer";
-
- _this.info.memory.geometries ++;
-
- };
-
- function createLineBuffers ( geometry ) {
-
- geometry.__webglVertexBuffer = _gl.createBuffer();
- geometry.__webglColorBuffer = _gl.createBuffer();
- geometry.__webglLineDistanceBuffer = _gl.createBuffer();
- geometry.__webglVertexBuffer.name = "Line__webglVertexBuffer";
- geometry.__webglColorBuffer.name = "Line__webglColorBuffer";
- geometry.__webglLineDistanceBuffer.name = "Line__webglLineDistanceBuffer";
-
- _this.info.memory.geometries ++;
-
- };
-
- function createMeshBuffers ( geometryGroup ) {
-
- geometryGroup.__webglVertexBuffer = _gl.createBuffer();
- geometryGroup.__webglNormalBuffer = _gl.createBuffer();
- geometryGroup.__webglTangentBuffer = _gl.createBuffer();
- geometryGroup.__webglColorBuffer = _gl.createBuffer();
- geometryGroup.__webglUVBuffer = _gl.createBuffer();
- geometryGroup.__webglUV2Buffer = _gl.createBuffer();
- geometryGroup.__webglVertexBuffer.name = "Mesh__webglVertexBuffer";
- geometryGroup.__webglNormalBuffer.name = "Mesh__webglNormalBuffer";
- geometryGroup.__webglTangentBuffer.name = "Mesh__webglTangentBuffer";
- geometryGroup.__webglColorBuffer.name = "Mesh__webglColorBuffer";
- geometryGroup.__webglUVBuffer.name = "Mesh__webglUVBuffer";
- geometryGroup.__webglUV2Buffer.name = "Mesh__webglUV2Buffer";
-
- geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer();
- geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer();
- geometryGroup.__webglSkinIndicesBuffer.name = "Mesh__webglSkinIndicesBuffer";
- geometryGroup.__webglSkinWeightsBuffer.name = "Mesh__webglSkinWeightsBuffer";
-
- geometryGroup.__webglFaceBuffer = _gl.createBuffer();
- geometryGroup.__webglLineBuffer = _gl.createBuffer();
- geometryGroup.__webglFaceBuffer.name = "Mesh__webglFaceBuffer";
- geometryGroup.__webglLineBuffer.name = "Mesh__webglLineBuffer";
-
- var m, ml;
- var numMorphTargets = geometryGroup.numMorphTargets;
-
- if ( numMorphTargets ) {
-
- geometryGroup.__webglMorphTargetsBuffers = [];
-
- for ( m = 0, ml = numMorphTargets; m < ml; m ++ ) {
- var buf = _gl.createBuffer();
- buf.name = "Mesh__MorphTarget_"+m;
- geometryGroup.__webglMorphTargetsBuffers.push(buf);
-
- }
-
- }
-
- var numMorphNormals = geometryGroup.numMorphNormals;
-
- if ( numMorphNormals ) {
-
- geometryGroup.__webglMorphNormalsBuffers = [];
-
- for ( m = 0, ml = numMorphNormals; m < ml; m ++ ) {
- var nbuf = _gl.createBuffer();
- nbuf.name = "Mesh__MorphNormal_"+m;
- geometryGroup.__webglMorphNormalsBuffers.push( nbuf );
-
- }
-
- }
-
- _this.info.memory.geometries ++;
-
- };
-
- // Events
-
- var onObjectRemoved = function ( event ) {
-
- var object = event.target;
-
- object.traverse( function ( child ) {
-
- child.removeEventListener( 'remove', onObjectRemoved );
-
- removeObject( child );
-
- } );
-
- };
-
- var onGeometryDispose = function ( event ) {
-
- var geometry = event.target;
-
- geometry.removeEventListener( 'dispose', onGeometryDispose );
-
- deallocateGeometry( geometry );
-
- };
-
- var onTextureDispose = function ( event ) {
-
- var texture = event.target;
-
- texture.removeEventListener( 'dispose', onTextureDispose );
-
- deallocateTexture( texture );
-
- _this.info.memory.textures --;
-
-
- };
-
- var onRenderTargetDispose = function ( event ) {
-
- var renderTarget = event.target;
-
- renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
-
- deallocateRenderTarget( renderTarget );
-
- _this.info.memory.textures --;
-
- };
-
- var onMaterialDispose = function ( event ) {
-
- var material = event.target;
-
- material.removeEventListener( 'dispose', onMaterialDispose );
-
- deallocateMaterial( material );
-
- };
-
- // Buffer deallocation
-
- var deleteBuffers = function ( geometry ) {
-
- var buffers = [
- '__webglVertexBuffer',
- '__webglNormalBuffer',
- '__webglTangentBuffer',
- '__webglColorBuffer',
- '__webglUVBuffer',
- '__webglUV2Buffer',
-
- '__webglSkinIndicesBuffer',
- '__webglSkinWeightsBuffer',
-
- '__webglFaceBuffer',
- '__webglLineBuffer',
-
- '__webglLineDistanceBuffer'
- ];
-
- for ( var i = 0, l = buffers.length; i < l; i ++ ) {
-
- var name = buffers[ i ];
-
- if ( geometry[ name ] !== undefined ) {
-
- _gl.deleteBuffer( geometry[ name ] );
-
- delete geometry[ name ];
-
- }
-
- }
-
- // custom attributes
-
- if ( geometry.__webglCustomAttributesList !== undefined ) {
-
- for ( var name in geometry.__webglCustomAttributesList ) {
-
- _gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer );
-
- }
-
- delete geometry.__webglCustomAttributesList;
-
- }
-
- _this.info.memory.geometries --;
-
- };
-
- var deallocateGeometry = function ( geometry ) {
-
- delete geometry.__webglInit;
-
- if ( geometry instanceof THREE.BufferGeometry ) {
-
- for ( var name in geometry.attributes ) {
-
- var attribute = geometry.attributes[ name ];
-
- if ( attribute.buffer !== undefined ) {
-
- _gl.deleteBuffer( attribute.buffer );
-
- delete attribute.buffer;
-
- }
-
- }
-
- _this.info.memory.geometries --;
-
- } else {
-
- var geometryGroupsList = geometryGroups[ geometry.id ];
-
- if ( geometryGroupsList !== undefined ) {
-
- for ( var i = 0, l = geometryGroupsList.length; i < l; i ++ ) {
-
- var geometryGroup = geometryGroupsList[ i ];
-
- if ( geometryGroup.numMorphTargets !== undefined ) {
-
- for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
-
- _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );
-
- }
-
- delete geometryGroup.__webglMorphTargetsBuffers;
-
- }
-
- if ( geometryGroup.numMorphNormals !== undefined ) {
-
- for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
-
- _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );
-
- }
-
- delete geometryGroup.__webglMorphNormalsBuffers;
-
- }
-
- deleteBuffers( geometryGroup );
-
- }
-
- delete geometryGroups[ geometry.id ];
-
- } else {
-
- deleteBuffers( geometry );
-
- }
-
- }
-
- // TOFIX: Workaround for deleted geometry being currently bound
-
- _currentGeometryProgram = '';
-
- };
-
- var deallocateTexture = function ( texture ) {
-
- if ( texture.image && texture.image.__webglTextureCube ) {
-
- // cube texture
-
- _gl.deleteTexture( texture.image.__webglTextureCube );
-
- delete texture.image.__webglTextureCube;
-
- } else {
-
- // 2D texture
-
- if ( texture.__webglInit === undefined ) return;
-
- _gl.deleteTexture( texture.__webglTexture );
-
- delete texture.__webglTexture;
- delete texture.__webglInit;
-
- }
-
- };
-
- var deallocateRenderTarget = function ( renderTarget ) {
-
- if ( ! renderTarget || renderTarget.__webglTexture === undefined ) return;
-
- _gl.deleteTexture( renderTarget.__webglTexture );
-
- delete renderTarget.__webglTexture;
-
- if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
-
- for ( var i = 0; i < 6; i ++ ) {
-
- _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );
- _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );
-
- }
-
- } else {
-
- _gl.deleteFramebuffer( renderTarget.__webglFramebuffer );
- _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer );
-
- }
-
- delete renderTarget.__webglFramebuffer;
- delete renderTarget.__webglRenderbuffer;
-
- };
-
- var deallocateMaterial = function ( material ) {
-
- var program = material.program.program;
-
- if ( program === undefined ) return;
-
- material.program = undefined;
-
- // only deallocate GL program if this was the last use of shared program
- // assumed there is only single copy of any program in the _programs list
- // (that's how it's constructed)
-
- var i, il, programInfo;
- var deleteProgram = false;
-
- for ( i = 0, il = _programs.length; i < il; i ++ ) {
-
- programInfo = _programs[ i ];
-
- if ( programInfo.program === program ) {
-
- programInfo.usedTimes --;
-
- if ( programInfo.usedTimes === 0 ) {
-
- deleteProgram = true;
-
- }
-
- break;
-
- }
-
- }
-
- if ( deleteProgram === true ) {
-
- // avoid using array.splice, this is costlier than creating new array from scratch
-
- var newPrograms = [];
-
- for ( i = 0, il = _programs.length; i < il; i ++ ) {
-
- programInfo = _programs[ i ];
-
- if ( programInfo.program !== program ) {
-
- newPrograms.push( programInfo );
-
- }
-
- }
-
- _programs = newPrograms;
-
- _gl.deleteProgram( program );
-
- _this.info.memory.programs --;
-
- }
-
- };
-
- // Buffer initialization
-
- function initCustomAttributes ( object ) {
-
- var geometry = object.geometry;
- var material = object.material;
-
- var nvertices = geometry.vertices.length;
-
- if ( material.attributes ) {
-
- if ( geometry.__webglCustomAttributesList === undefined ) {
-
- geometry.__webglCustomAttributesList = [];
-
- }
-
- for ( var name in material.attributes ) {
-
- var attribute = material.attributes[ name ];
-
- if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) {
-
- attribute.__webglInitialized = true;
-
- var size = 1; // "f" and "i"
-
- if ( attribute.type === 'v2' ) size = 2;
- else if ( attribute.type === 'v3' ) size = 3;
- else if ( attribute.type === 'v4' ) size = 4;
- else if ( attribute.type === 'c' ) size = 3;
-
- attribute.size = size;
-
- attribute.array = new Float32Array( nvertices * size );
- attribute.array.name = ""+attribute+"attribute.array";
-
- attribute.buffer = _gl.createBuffer();
- attribute.buffer.belongsToAttribute = name;
-
- attribute.needsUpdate = true;
-
- }
-
- geometry.__webglCustomAttributesList.push( attribute );
-
- }
-
- }
-
- };
-
- function initParticleBuffers ( geometry, object ) {
-
- var nvertices = geometry.vertices.length;
-
- geometry.__vertexArray = new Float32Array( nvertices * 3 );
- geometry.__colorArray = new Float32Array( nvertices * 3 );
- geometry.__vertexArray.name = "geometry.__vertexArray";
- geometry.__colorArray.name = "geometry.__colorArray";
-
- geometry.__webglParticleCount = nvertices;
-
- initCustomAttributes( object );
-
- };
-
- function initLineBuffers ( geometry, object ) {
-
- var nvertices = geometry.vertices.length;
-
- geometry.__vertexArray = new Float32Array( nvertices * 3 );
- geometry.__colorArray = new Float32Array( nvertices * 3 );
- geometry.__lineDistanceArray = new Float32Array( nvertices * 1 );
- geometry.__vertexArray.name = "geometry.__vertexArray";
- geometry.__colorArray.name = "geometry.__colorArray";
- geometry.__lineDistanceArray.name = "geometry.__lineDistanceArray";
-
- geometry.__webglLineCount = nvertices;
-
- initCustomAttributes( object );
-
- };
-
- function initMeshBuffers ( geometryGroup, object ) {
-
- var geometry = object.geometry,
- faces3 = geometryGroup.faces3,
-
- nvertices = faces3.length * 3,
- ntris = faces3.length * 1,
- nlines = faces3.length * 3,
-
- material = getBufferMaterial( object, geometryGroup );
-
- geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
- geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
- geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
- geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
- geometryGroup.__vertexArray.name = "geometryGroup.__vertexArray";
- geometryGroup.__normalArray.name = "geometryGroup.__normalArray";
- geometryGroup.__colorArray.name = "geometryGroup.__colorArray";
- geometryGroup.__uvArray.name = "geometryGroup.__uvArray";
-
- if ( geometry.faceVertexUvs.length > 1 ) {
-
- geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
- geometryGroup.__uv2Array.name = "geometryGroup.__uv2Array";
-
- }
-
- if ( geometry.hasTangents ) {
-
- geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );
- geometryGroup.__tangentArray.name = "geometryGroup.__tangentArray";
-
- }
-
- if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {
-
- geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
- geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );
- geometryGroup.__skinIndexArray.name = "geometryGroup.__skinIndexArray";
- geometryGroup.__skinWeightArray.name = "geometryGroup.__skinWeightArray";
- }
-
- var UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3
-
- geometryGroup.__typeArray = UintArray;
- geometryGroup.__faceArray = new UintArray( ntris * 3 );
- geometryGroup.__lineArray = new UintArray( nlines * 2 );
- geometryGroup.__faceArray.name = "geometryGroup.__faceArray";
- geometryGroup.__lineArray.name = "geometryGroup.__lineArray";
-
- var m, ml;
- var numMorphTargets = geometryGroup.numMorphTargets;
-
- if ( numMorphTargets ) {
-
- geometryGroup.__morphTargetsArrays = [];
-
- for ( m = 0, ml = numMorphTargets; m < ml; m ++ ) {
- var mta = new Float32Array( nvertices * 3 );
- mta.name = "morphTargetArray_"+m;
- geometryGroup.__morphTargetsArrays.push(mta);
- }
-
- }
-
- var numMorphNormals = geometryGroup.numMorphNormals;
-
- if ( numMorphNormals ) {
-
- geometryGroup.__morphNormalsArrays = [];
-
- for ( m = 0, ml = numMorphNormals; m < ml; m ++ ) {
- var mna = new Float32Array( nvertices * 3 );
- mna.name = "morphNormalsArray_"+m;
- geometryGroup.__morphNormalsArrays.push( mna );
- }
-
- }
-
- geometryGroup.__webglFaceCount = ntris * 3;
- geometryGroup.__webglLineCount = nlines * 2;
-
-
- // custom attributes
-
- if ( material.attributes ) {
-
- if ( geometryGroup.__webglCustomAttributesList === undefined ) {
-
- geometryGroup.__webglCustomAttributesList = [];
-
- }
-
- for ( var name in material.attributes ) {
-
- // Do a shallow copy of the attribute object so different geometryGroup chunks use different
- // attribute buffers which are correctly indexed in the setMeshBuffers function
-
- var originalAttribute = material.attributes[ name ];
-
- var attribute = {};
-
- for ( var property in originalAttribute ) {
-
- attribute[ property ] = originalAttribute[ property ];
-
- }
-
- if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) {
-
- attribute.__webglInitialized = true;
-
- var size = 1; // "f" and "i"
-
- if ( attribute.type === 'v2' ) size = 2;
- else if ( attribute.type === 'v3' ) size = 3;
- else if ( attribute.type === 'v4' ) size = 4;
- else if ( attribute.type === 'c' ) size = 3;
-
- attribute.size = size;
-
- attribute.array = new Float32Array( nvertices * size );
-
- attribute.buffer = _gl.createBuffer();
- attribute.buffer.belongsToAttribute = name;
-
- originalAttribute.needsUpdate = true;
- attribute.__original = originalAttribute;
-
- }
-
- geometryGroup.__webglCustomAttributesList.push( attribute );
-
- }
-
- }
-
- geometryGroup.__inittedArrays = true;
-
- };
-
- function getBufferMaterial( object, geometryGroup ) {
-
- return object.material instanceof THREE.MeshFaceMaterial
- ? object.material.materials[ geometryGroup.materialIndex ]
- : object.material;
-
- }
-
- function materialNeedsFaceNormals ( material ) {
-
- return material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading;
-
- }
-
- // Buffer setting
-
- function setParticleBuffers ( geometry, hint, object ) {
-
- var v, c, vertex, offset, color,
-
- vertices = geometry.vertices,
- vl = vertices.length,
-
- colors = geometry.colors,
- cl = colors.length,
-
- vertexArray = geometry.__vertexArray,
- colorArray = geometry.__colorArray,
-
- dirtyVertices = geometry.verticesNeedUpdate,
- dirtyColors = geometry.colorsNeedUpdate,
-
- customAttributes = geometry.__webglCustomAttributesList,
- i, il,
- ca, cal, value,
- customAttribute;
-
- if ( dirtyVertices ) {
-
- for ( v = 0; v < vl; v ++ ) {
-
- vertex = vertices[ v ];
-
- offset = v * 3;
-
- vertexArray[ offset ] = vertex.x;
- vertexArray[ offset + 1 ] = vertex.y;
- vertexArray[ offset + 2 ] = vertex.z;
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
-
- }
-
- if ( dirtyColors ) {
-
- for ( c = 0; c < cl; c ++ ) {
-
- color = colors[ c ];
-
- offset = c * 3;
-
- colorArray[ offset ] = color.r;
- colorArray[ offset + 1 ] = color.g;
- colorArray[ offset + 2 ] = color.b;
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
-
- }
-
- if ( customAttributes ) {
-
- for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
- customAttribute = customAttributes[ i ];
-
- if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) {
-
- cal = customAttribute.value.length;
-
- offset = 0;
-
- if ( customAttribute.size === 1 ) {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- customAttribute.array[ ca ] = customAttribute.value[ ca ];
-
- }
-
- } else if ( customAttribute.size === 2 ) {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- value = customAttribute.value[ ca ];
-
- customAttribute.array[ offset ] = value.x;
- customAttribute.array[ offset + 1 ] = value.y;
-
- offset += 2;
-
- }
-
- } else if ( customAttribute.size === 3 ) {
-
- if ( customAttribute.type === 'c' ) {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- value = customAttribute.value[ ca ];
-
- customAttribute.array[ offset ] = value.r;
- customAttribute.array[ offset + 1 ] = value.g;
- customAttribute.array[ offset + 2 ] = value.b;
-
- offset += 3;
-
- }
-
- } else {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- value = customAttribute.value[ ca ];
-
- customAttribute.array[ offset ] = value.x;
- customAttribute.array[ offset + 1 ] = value.y;
- customAttribute.array[ offset + 2 ] = value.z;
-
- offset += 3;
-
- }
-
- }
-
- } else if ( customAttribute.size === 4 ) {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- value = customAttribute.value[ ca ];
-
- customAttribute.array[ offset ] = value.x;
- customAttribute.array[ offset + 1 ] = value.y;
- customAttribute.array[ offset + 2 ] = value.z;
- customAttribute.array[ offset + 3 ] = value.w;
-
- offset += 4;
-
- }
-
- }
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
-
- customAttribute.needsUpdate = false;
-
- }
-
- }
-
- }
-
- function setLineBuffers ( geometry, hint ) {
-
- var v, c, d, vertex, offset, color,
-
- vertices = geometry.vertices,
- colors = geometry.colors,
- lineDistances = geometry.lineDistances,
-
- vl = vertices.length,
- cl = colors.length,
- dl = lineDistances.length,
-
- vertexArray = geometry.__vertexArray,
- colorArray = geometry.__colorArray,
- lineDistanceArray = geometry.__lineDistanceArray,
-
- dirtyVertices = geometry.verticesNeedUpdate,
- dirtyColors = geometry.colorsNeedUpdate,
- dirtyLineDistances = geometry.lineDistancesNeedUpdate,
-
- customAttributes = geometry.__webglCustomAttributesList,
-
- i, il,
- ca, cal, value,
- customAttribute;
-
- if ( dirtyVertices ) {
-
- for ( v = 0; v < vl; v ++ ) {
-
- vertex = vertices[ v ];
-
- offset = v * 3;
-
- vertexArray[ offset ] = vertex.x;
- vertexArray[ offset + 1 ] = vertex.y;
- vertexArray[ offset + 2 ] = vertex.z;
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
-
- }
-
- if ( dirtyColors ) {
-
- for ( c = 0; c < cl; c ++ ) {
-
- color = colors[ c ];
-
- offset = c * 3;
-
- colorArray[ offset ] = color.r;
- colorArray[ offset + 1 ] = color.g;
- colorArray[ offset + 2 ] = color.b;
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
-
- }
-
- if ( dirtyLineDistances ) {
-
- for ( d = 0; d < dl; d ++ ) {
-
- lineDistanceArray[ d ] = lineDistances[ d ];
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint );
-
- }
-
- if ( customAttributes ) {
-
- for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
- customAttribute = customAttributes[ i ];
-
- if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) {
-
- offset = 0;
-
- cal = customAttribute.value.length;
-
- if ( customAttribute.size === 1 ) {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- customAttribute.array[ ca ] = customAttribute.value[ ca ];
-
- }
-
- } else if ( customAttribute.size === 2 ) {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- value = customAttribute.value[ ca ];
-
- customAttribute.array[ offset ] = value.x;
- customAttribute.array[ offset + 1 ] = value.y;
-
- offset += 2;
-
- }
-
- } else if ( customAttribute.size === 3 ) {
-
- if ( customAttribute.type === 'c' ) {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- value = customAttribute.value[ ca ];
-
- customAttribute.array[ offset ] = value.r;
- customAttribute.array[ offset + 1 ] = value.g;
- customAttribute.array[ offset + 2 ] = value.b;
-
- offset += 3;
-
- }
-
- } else {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- value = customAttribute.value[ ca ];
-
- customAttribute.array[ offset ] = value.x;
- customAttribute.array[ offset + 1 ] = value.y;
- customAttribute.array[ offset + 2 ] = value.z;
-
- offset += 3;
-
- }
-
- }
-
- } else if ( customAttribute.size === 4 ) {
-
- for ( ca = 0; ca < cal; ca ++ ) {
-
- value = customAttribute.value[ ca ];
-
- customAttribute.array[ offset ] = value.x;
- customAttribute.array[ offset + 1 ] = value.y;
- customAttribute.array[ offset + 2 ] = value.z;
- customAttribute.array[ offset + 3 ] = value.w;
-
- offset += 4;
-
- }
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
-
- customAttribute.needsUpdate = false;
-
- }
-
- }
-
- }
-
- }
-
- function setMeshBuffers( geometryGroup, object, hint, dispose, material ) {
-
- if ( ! geometryGroup.__inittedArrays ) {
-
- return;
-
- }
-
- var needsFaceNormals = materialNeedsFaceNormals( material );
-
- var f, fl, fi, face,
- vertexNormals, faceNormal,
- vertexColors, faceColor,
- vertexTangents,
- uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3,
- c1, c2, c3,
- sw1, sw2, sw3,
- si1, si2, si3,
- i, il,
- vn, uvi, uv2i,
- vk, vkl, vka,
- nka, chf, faceVertexNormals,
-
- vertexIndex = 0,
-
- offset = 0,
- offset_uv = 0,
- offset_uv2 = 0,
- offset_face = 0,
- offset_normal = 0,
- offset_tangent = 0,
- offset_line = 0,
- offset_color = 0,
- offset_skin = 0,
- offset_morphTarget = 0,
- offset_custom = 0,
-
- value,
-
- vertexArray = geometryGroup.__vertexArray,
- uvArray = geometryGroup.__uvArray,
- uv2Array = geometryGroup.__uv2Array,
- normalArray = geometryGroup.__normalArray,
- tangentArray = geometryGroup.__tangentArray,
- colorArray = geometryGroup.__colorArray,
-
- skinIndexArray = geometryGroup.__skinIndexArray,
- skinWeightArray = geometryGroup.__skinWeightArray,
-
- morphTargetsArrays = geometryGroup.__morphTargetsArrays,
- morphNormalsArrays = geometryGroup.__morphNormalsArrays,
-
- customAttributes = geometryGroup.__webglCustomAttributesList,
- customAttribute,
-
- faceArray = geometryGroup.__faceArray,
- lineArray = geometryGroup.__lineArray,
-
- geometry = object.geometry, // this is shared for all chunks
-
- dirtyVertices = geometry.verticesNeedUpdate,
- dirtyElements = geometry.elementsNeedUpdate,
- dirtyUvs = geometry.uvsNeedUpdate,
- dirtyNormals = geometry.normalsNeedUpdate,
- dirtyTangents = geometry.tangentsNeedUpdate,
- dirtyColors = geometry.colorsNeedUpdate,
- dirtyMorphTargets = geometry.morphTargetsNeedUpdate,
-
- vertices = geometry.vertices,
- chunk_faces3 = geometryGroup.faces3,
- obj_faces = geometry.faces,
-
- obj_uvs = geometry.faceVertexUvs[ 0 ],
- obj_uvs2 = geometry.faceVertexUvs[ 1 ],
-
- obj_skinIndices = geometry.skinIndices,
- obj_skinWeights = geometry.skinWeights,
-
- morphTargets = geometry.morphTargets,
- morphNormals = geometry.morphNormals;
-
- if ( dirtyVertices ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- v1 = vertices[ face.a ];
- v2 = vertices[ face.b ];
- v3 = vertices[ face.c ];
-
- vertexArray[ offset ] = v1.x;
- vertexArray[ offset + 1 ] = v1.y;
- vertexArray[ offset + 2 ] = v1.z;
-
- vertexArray[ offset + 3 ] = v2.x;
- vertexArray[ offset + 4 ] = v2.y;
- vertexArray[ offset + 5 ] = v2.z;
-
- vertexArray[ offset + 6 ] = v3.x;
- vertexArray[ offset + 7 ] = v3.y;
- vertexArray[ offset + 8 ] = v3.z;
-
- offset += 9;
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
-
- }
-
- if ( dirtyMorphTargets ) {
-
- for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
-
- offset_morphTarget = 0;
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- chf = chunk_faces3[ f ];
- face = obj_faces[ chf ];
-
- // morph positions
-
- v1 = morphTargets[ vk ].vertices[ face.a ];
- v2 = morphTargets[ vk ].vertices[ face.b ];
- v3 = morphTargets[ vk ].vertices[ face.c ];
-
- vka = morphTargetsArrays[ vk ];
-
- vka[ offset_morphTarget ] = v1.x;
- vka[ offset_morphTarget + 1 ] = v1.y;
- vka[ offset_morphTarget + 2 ] = v1.z;
-
- vka[ offset_morphTarget + 3 ] = v2.x;
- vka[ offset_morphTarget + 4 ] = v2.y;
- vka[ offset_morphTarget + 5 ] = v2.z;
-
- vka[ offset_morphTarget + 6 ] = v3.x;
- vka[ offset_morphTarget + 7 ] = v3.y;
- vka[ offset_morphTarget + 8 ] = v3.z;
-
- // morph normals
-
- if ( material.morphNormals ) {
-
- if ( needsFaceNormals ) {
-
- n1 = morphNormals[ vk ].faceNormals[ chf ];
- n2 = n1;
- n3 = n1;
-
- } else {
-
- faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
-
- n1 = faceVertexNormals.a;
- n2 = faceVertexNormals.b;
- n3 = faceVertexNormals.c;
-
- }
-
- nka = morphNormalsArrays[ vk ];
-
- nka[ offset_morphTarget ] = n1.x;
- nka[ offset_morphTarget + 1 ] = n1.y;
- nka[ offset_morphTarget + 2 ] = n1.z;
-
- nka[ offset_morphTarget + 3 ] = n2.x;
- nka[ offset_morphTarget + 4 ] = n2.y;
- nka[ offset_morphTarget + 5 ] = n2.z;
-
- nka[ offset_morphTarget + 6 ] = n3.x;
- nka[ offset_morphTarget + 7 ] = n3.y;
- nka[ offset_morphTarget + 8 ] = n3.z;
-
- }
-
- //
-
- offset_morphTarget += 9;
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );
- _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );
-
- if ( material.morphNormals ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] );
- _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint );
-
- }
-
- }
-
- }
-
- if ( obj_skinWeights.length ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- // weights
-
- sw1 = obj_skinWeights[ face.a ];
- sw2 = obj_skinWeights[ face.b ];
- sw3 = obj_skinWeights[ face.c ];
-
- skinWeightArray[ offset_skin ] = sw1.x;
- skinWeightArray[ offset_skin + 1 ] = sw1.y;
- skinWeightArray[ offset_skin + 2 ] = sw1.z;
- skinWeightArray[ offset_skin + 3 ] = sw1.w;
-
- skinWeightArray[ offset_skin + 4 ] = sw2.x;
- skinWeightArray[ offset_skin + 5 ] = sw2.y;
- skinWeightArray[ offset_skin + 6 ] = sw2.z;
- skinWeightArray[ offset_skin + 7 ] = sw2.w;
-
- skinWeightArray[ offset_skin + 8 ] = sw3.x;
- skinWeightArray[ offset_skin + 9 ] = sw3.y;
- skinWeightArray[ offset_skin + 10 ] = sw3.z;
- skinWeightArray[ offset_skin + 11 ] = sw3.w;
-
- // indices
-
- si1 = obj_skinIndices[ face.a ];
- si2 = obj_skinIndices[ face.b ];
- si3 = obj_skinIndices[ face.c ];
-
- skinIndexArray[ offset_skin ] = si1.x;
- skinIndexArray[ offset_skin + 1 ] = si1.y;
- skinIndexArray[ offset_skin + 2 ] = si1.z;
- skinIndexArray[ offset_skin + 3 ] = si1.w;
-
- skinIndexArray[ offset_skin + 4 ] = si2.x;
- skinIndexArray[ offset_skin + 5 ] = si2.y;
- skinIndexArray[ offset_skin + 6 ] = si2.z;
- skinIndexArray[ offset_skin + 7 ] = si2.w;
-
- skinIndexArray[ offset_skin + 8 ] = si3.x;
- skinIndexArray[ offset_skin + 9 ] = si3.y;
- skinIndexArray[ offset_skin + 10 ] = si3.z;
- skinIndexArray[ offset_skin + 11 ] = si3.w;
-
- offset_skin += 12;
-
- }
-
- if ( offset_skin > 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );
-
- }
-
- }
-
- if ( dirtyColors ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- vertexColors = face.vertexColors;
- faceColor = face.color;
-
- if ( vertexColors.length === 3 && material.vertexColors === THREE.VertexColors ) {
-
- c1 = vertexColors[ 0 ];
- c2 = vertexColors[ 1 ];
- c3 = vertexColors[ 2 ];
-
- } else {
-
- c1 = faceColor;
- c2 = faceColor;
- c3 = faceColor;
-
- }
-
- colorArray[ offset_color ] = c1.r;
- colorArray[ offset_color + 1 ] = c1.g;
- colorArray[ offset_color + 2 ] = c1.b;
-
- colorArray[ offset_color + 3 ] = c2.r;
- colorArray[ offset_color + 4 ] = c2.g;
- colorArray[ offset_color + 5 ] = c2.b;
-
- colorArray[ offset_color + 6 ] = c3.r;
- colorArray[ offset_color + 7 ] = c3.g;
- colorArray[ offset_color + 8 ] = c3.b;
-
- offset_color += 9;
-
- }
-
- if ( offset_color > 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
-
- }
-
- }
-
- if ( dirtyTangents && geometry.hasTangents ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- vertexTangents = face.vertexTangents;
-
- t1 = vertexTangents[ 0 ];
- t2 = vertexTangents[ 1 ];
- t3 = vertexTangents[ 2 ];
-
- tangentArray[ offset_tangent ] = t1.x;
- tangentArray[ offset_tangent + 1 ] = t1.y;
- tangentArray[ offset_tangent + 2 ] = t1.z;
- tangentArray[ offset_tangent + 3 ] = t1.w;
-
- tangentArray[ offset_tangent + 4 ] = t2.x;
- tangentArray[ offset_tangent + 5 ] = t2.y;
- tangentArray[ offset_tangent + 6 ] = t2.z;
- tangentArray[ offset_tangent + 7 ] = t2.w;
-
- tangentArray[ offset_tangent + 8 ] = t3.x;
- tangentArray[ offset_tangent + 9 ] = t3.y;
- tangentArray[ offset_tangent + 10 ] = t3.z;
- tangentArray[ offset_tangent + 11 ] = t3.w;
-
- offset_tangent += 12;
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );
-
- }
-
- if ( dirtyNormals ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- vertexNormals = face.vertexNormals;
- faceNormal = face.normal;
-
- if ( vertexNormals.length === 3 && needsFaceNormals === false ) {
-
- for ( i = 0; i < 3; i ++ ) {
-
- vn = vertexNormals[ i ];
-
- normalArray[ offset_normal ] = vn.x;
- normalArray[ offset_normal + 1 ] = vn.y;
- normalArray[ offset_normal + 2 ] = vn.z;
-
- offset_normal += 3;
-
- }
-
- } else {
-
- for ( i = 0; i < 3; i ++ ) {
-
- normalArray[ offset_normal ] = faceNormal.x;
- normalArray[ offset_normal + 1 ] = faceNormal.y;
- normalArray[ offset_normal + 2 ] = faceNormal.z;
-
- offset_normal += 3;
-
- }
-
- }
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
-
- }
-
- if ( dirtyUvs && obj_uvs ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- fi = chunk_faces3[ f ];
-
- uv = obj_uvs[ fi ];
-
- if ( uv === undefined ) continue;
-
- for ( i = 0; i < 3; i ++ ) {
-
- uvi = uv[ i ];
-
- uvArray[ offset_uv ] = uvi.x;
- uvArray[ offset_uv + 1 ] = uvi.y;
-
- offset_uv += 2;
-
- }
-
- }
-
- if ( offset_uv > 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );
-
- }
-
- }
-
- if ( dirtyUvs && obj_uvs2 ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- fi = chunk_faces3[ f ];
-
- uv2 = obj_uvs2[ fi ];
-
- if ( uv2 === undefined ) continue;
-
- for ( i = 0; i < 3; i ++ ) {
-
- uv2i = uv2[ i ];
-
- uv2Array[ offset_uv2 ] = uv2i.x;
- uv2Array[ offset_uv2 + 1 ] = uv2i.y;
-
- offset_uv2 += 2;
-
- }
-
- }
-
- if ( offset_uv2 > 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );
-
- }
-
- }
-
- if ( dirtyElements ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- faceArray[ offset_face ] = vertexIndex;
- faceArray[ offset_face + 1 ] = vertexIndex + 1;
- faceArray[ offset_face + 2 ] = vertexIndex + 2;
-
- offset_face += 3;
-
- lineArray[ offset_line ] = vertexIndex;
- lineArray[ offset_line + 1 ] = vertexIndex + 1;
-
- lineArray[ offset_line + 2 ] = vertexIndex;
- lineArray[ offset_line + 3 ] = vertexIndex + 2;
-
- lineArray[ offset_line + 4 ] = vertexIndex + 1;
- lineArray[ offset_line + 5 ] = vertexIndex + 2;
-
- offset_line += 6;
-
- vertexIndex += 3;
-
- }
-
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
- _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );
-
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
- _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );
-
- }
-
- if ( customAttributes ) {
-
- for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
-
- customAttribute = customAttributes[ i ];
-
- if ( ! customAttribute.__original.needsUpdate ) continue;
-
- offset_custom = 0;
-
- if ( customAttribute.size === 1 ) {
-
- if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ];
- customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
- customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
-
- offset_custom += 3;
-
- }
-
- } else if ( customAttribute.boundTo === 'faces' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- value = customAttribute.value[ chunk_faces3[ f ] ];
-
- customAttribute.array[ offset_custom ] = value;
- customAttribute.array[ offset_custom + 1 ] = value;
- customAttribute.array[ offset_custom + 2 ] = value;
-
- offset_custom += 3;
-
- }
-
- }
-
- } else if ( customAttribute.size === 2 ) {
-
- if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- v1 = customAttribute.value[ face.a ];
- v2 = customAttribute.value[ face.b ];
- v3 = customAttribute.value[ face.c ];
-
- customAttribute.array[ offset_custom ] = v1.x;
- customAttribute.array[ offset_custom + 1 ] = v1.y;
-
- customAttribute.array[ offset_custom + 2 ] = v2.x;
- customAttribute.array[ offset_custom + 3 ] = v2.y;
-
- customAttribute.array[ offset_custom + 4 ] = v3.x;
- customAttribute.array[ offset_custom + 5 ] = v3.y;
-
- offset_custom += 6;
-
- }
-
- } else if ( customAttribute.boundTo === 'faces' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- value = customAttribute.value[ chunk_faces3[ f ] ];
-
- v1 = value;
- v2 = value;
- v3 = value;
-
- customAttribute.array[ offset_custom ] = v1.x;
- customAttribute.array[ offset_custom + 1 ] = v1.y;
-
- customAttribute.array[ offset_custom + 2 ] = v2.x;
- customAttribute.array[ offset_custom + 3 ] = v2.y;
-
- customAttribute.array[ offset_custom + 4 ] = v3.x;
- customAttribute.array[ offset_custom + 5 ] = v3.y;
-
- offset_custom += 6;
-
- }
-
- }
-
- } else if ( customAttribute.size === 3 ) {
-
- var pp;
-
- if ( customAttribute.type === 'c' ) {
-
- pp = [ 'r', 'g', 'b' ];
-
- } else {
-
- pp = [ 'x', 'y', 'z' ];
-
- }
-
- if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- v1 = customAttribute.value[ face.a ];
- v2 = customAttribute.value[ face.b ];
- v3 = customAttribute.value[ face.c ];
-
- customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
-
- customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
-
- customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
-
- offset_custom += 9;
-
- }
-
- } else if ( customAttribute.boundTo === 'faces' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- value = customAttribute.value[ chunk_faces3[ f ] ];
-
- v1 = value;
- v2 = value;
- v3 = value;
-
- customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
-
- customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
-
- customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
-
- offset_custom += 9;
-
- }
-
- } else if ( customAttribute.boundTo === 'faceVertices' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- value = customAttribute.value[ chunk_faces3[ f ] ];
-
- v1 = value[ 0 ];
- v2 = value[ 1 ];
- v3 = value[ 2 ];
-
- customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
-
- customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
-
- customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
- customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
- customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
-
- offset_custom += 9;
-
- }
-
- }
-
- } else if ( customAttribute.size === 4 ) {
-
- if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- face = obj_faces[ chunk_faces3[ f ] ];
-
- v1 = customAttribute.value[ face.a ];
- v2 = customAttribute.value[ face.b ];
- v3 = customAttribute.value[ face.c ];
-
- customAttribute.array[ offset_custom ] = v1.x;
- customAttribute.array[ offset_custom + 1 ] = v1.y;
- customAttribute.array[ offset_custom + 2 ] = v1.z;
- customAttribute.array[ offset_custom + 3 ] = v1.w;
-
- customAttribute.array[ offset_custom + 4 ] = v2.x;
- customAttribute.array[ offset_custom + 5 ] = v2.y;
- customAttribute.array[ offset_custom + 6 ] = v2.z;
- customAttribute.array[ offset_custom + 7 ] = v2.w;
-
- customAttribute.array[ offset_custom + 8 ] = v3.x;
- customAttribute.array[ offset_custom + 9 ] = v3.y;
- customAttribute.array[ offset_custom + 10 ] = v3.z;
- customAttribute.array[ offset_custom + 11 ] = v3.w;
-
- offset_custom += 12;
-
- }
-
- } else if ( customAttribute.boundTo === 'faces' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- value = customAttribute.value[ chunk_faces3[ f ] ];
-
- v1 = value;
- v2 = value;
- v3 = value;
-
- customAttribute.array[ offset_custom ] = v1.x;
- customAttribute.array[ offset_custom + 1 ] = v1.y;
- customAttribute.array[ offset_custom + 2 ] = v1.z;
- customAttribute.array[ offset_custom + 3 ] = v1.w;
-
- customAttribute.array[ offset_custom + 4 ] = v2.x;
- customAttribute.array[ offset_custom + 5 ] = v2.y;
- customAttribute.array[ offset_custom + 6 ] = v2.z;
- customAttribute.array[ offset_custom + 7 ] = v2.w;
-
- customAttribute.array[ offset_custom + 8 ] = v3.x;
- customAttribute.array[ offset_custom + 9 ] = v3.y;
- customAttribute.array[ offset_custom + 10 ] = v3.z;
- customAttribute.array[ offset_custom + 11 ] = v3.w;
-
- offset_custom += 12;
-
- }
-
- } else if ( customAttribute.boundTo === 'faceVertices' ) {
-
- for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
-
- value = customAttribute.value[ chunk_faces3[ f ] ];
-
- v1 = value[ 0 ];
- v2 = value[ 1 ];
- v3 = value[ 2 ];
-
- customAttribute.array[ offset_custom ] = v1.x;
- customAttribute.array[ offset_custom + 1 ] = v1.y;
- customAttribute.array[ offset_custom + 2 ] = v1.z;
- customAttribute.array[ offset_custom + 3 ] = v1.w;
-
- customAttribute.array[ offset_custom + 4 ] = v2.x;
- customAttribute.array[ offset_custom + 5 ] = v2.y;
- customAttribute.array[ offset_custom + 6 ] = v2.z;
- customAttribute.array[ offset_custom + 7 ] = v2.w;
-
- customAttribute.array[ offset_custom + 8 ] = v3.x;
- customAttribute.array[ offset_custom + 9 ] = v3.y;
- customAttribute.array[ offset_custom + 10 ] = v3.z;
- customAttribute.array[ offset_custom + 11 ] = v3.w;
-
- offset_custom += 12;
-
- }
-
- }
-
- }
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
-
- }
-
- }
-
- if ( dispose ) {
-
- delete geometryGroup.__inittedArrays;
- delete geometryGroup.__colorArray;
- delete geometryGroup.__normalArray;
- delete geometryGroup.__tangentArray;
- delete geometryGroup.__uvArray;
- delete geometryGroup.__uv2Array;
- delete geometryGroup.__faceArray;
- delete geometryGroup.__vertexArray;
- delete geometryGroup.__lineArray;
- delete geometryGroup.__skinIndexArray;
- delete geometryGroup.__skinWeightArray;
-
- }
-
- };
-
- // Buffer rendering
-
- this.renderBufferImmediate = function ( object, program, material ) {
-
- state.initAttributes();
-
- if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
- if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
- if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
- if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
-
- if ( object.hasPositions ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
-
- state.enableAttribute( program.attributes.position );
-
- _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- if ( object.hasNormals ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
-
- if ( material instanceof THREE.MeshPhongMaterial === false &&
- material.shading === THREE.FlatShading ) {
-
- var nx, ny, nz,
- nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
- normalArray,
- i, il = object.count * 3;
-
- for ( i = 0; i < il; i += 9 ) {
-
- normalArray = object.normalArray;
-
- nax = normalArray[ i ];
- nay = normalArray[ i + 1 ];
- naz = normalArray[ i + 2 ];
-
- nbx = normalArray[ i + 3 ];
- nby = normalArray[ i + 4 ];
- nbz = normalArray[ i + 5 ];
-
- ncx = normalArray[ i + 6 ];
- ncy = normalArray[ i + 7 ];
- ncz = normalArray[ i + 8 ];
-
- nx = ( nax + nbx + ncx ) / 3;
- ny = ( nay + nby + ncy ) / 3;
- nz = ( naz + nbz + ncz ) / 3;
-
- normalArray[ i ] = nx;
- normalArray[ i + 1 ] = ny;
- normalArray[ i + 2 ] = nz;
-
- normalArray[ i + 3 ] = nx;
- normalArray[ i + 4 ] = ny;
- normalArray[ i + 5 ] = nz;
-
- normalArray[ i + 6 ] = nx;
- normalArray[ i + 7 ] = ny;
- normalArray[ i + 8 ] = nz;
-
- }
-
- }
-
- _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
-
- state.enableAttribute( program.attributes.normal );
-
- _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- if ( object.hasUvs && material.map ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
-
- state.enableAttribute( program.attributes.uv );
-
- _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
-
- }
-
- if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
-
- state.enableAttribute( program.attributes.color );
-
- _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- state.disableUnusedAttributes();
-
- _gl.drawArrays( _gl.TRIANGLES, 0, object.count );
-
- object.count = 0;
-
- };
-
- function setupVertexAttributes( material, program, geometry, startIndex ) {
-
- var geometryAttributes = geometry.attributes;
-
- var programAttributes = program.attributes;
- var programAttributesKeys = program.attributesKeys;
-
- for ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) {
-
- var key = programAttributesKeys[ i ];
- var programAttribute = programAttributes[ key ];
-
- if ( programAttribute >= 0 ) {
-
- var geometryAttribute = geometryAttributes[ key ];
-
- if ( geometryAttribute !== undefined ) {
-
- var size = geometryAttribute.itemSize;
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer );
-
- state.enableAttribute( programAttribute );
-
- _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32
-
- } else if ( material.defaultAttributeValues !== undefined ) {
-
- if ( material.defaultAttributeValues[ key ].length === 2 ) {
-
- _gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] );
-
- } else if ( material.defaultAttributeValues[ key ].length === 3 ) {
-
- _gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] );
-
- }
-
- }
-
- }
-
- }
-
- state.disableUnusedAttributes();
-
- }
-
- this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {
-
- if ( material.visible === false ) return;
-
- updateObject( object );
-
- var program = setProgram( camera, lights, fog, material, object );
-
- var updateBuffers = false,
- wireframeBit = material.wireframe ? 1 : 0,
- geometryProgram = 'direct_' + geometry.id + '_' + program.id + '_' + wireframeBit;
-
- if ( geometryProgram !== _currentGeometryProgram ) {
-
- _currentGeometryProgram = geometryProgram;
- updateBuffers = true;
-
- }
-
- if ( updateBuffers ) {
-
- state.initAttributes();
-
- }
-
- // render mesh
-
- if ( object instanceof THREE.Mesh ) {
-
- var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES;
-
- var index = geometry.attributes.index;
-
- if ( index ) {
-
- // indexed triangles
-
- var type, size;
-
- if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
-
- type = _gl.UNSIGNED_INT;
- size = 4;
-
- } else {
-
- type = _gl.UNSIGNED_SHORT;
- size = 2;
-
- }
-
- var offsets = geometry.offsets;
-
- if ( offsets.length === 0 ) {
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, 0 );
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
-
- }
-
- _gl.drawElements( mode, index.array.length, type, 0 );
-
- _this.info.render.calls ++;
- _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared
- _this.info.render.faces += index.array.length / 3;
-
- } else {
-
- // if there is more than 1 chunk
- // must set attribute pointers to use new offsets for each chunk
- // even if geometry and materials didn't change
-
- updateBuffers = true;
-
- for ( var i = 0, il = offsets.length; i < il; i ++ ) {
-
- var startIndex = offsets[ i ].index;
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, startIndex );
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
-
- }
-
- // render indexed triangles
-
- _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );
-
- _this.info.render.calls ++;
- _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
- _this.info.render.faces += offsets[ i ].count / 3;
-
- }
-
- }
-
- } else {
-
- // non-indexed triangles
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, 0 );
-
- }
-
- var position = geometry.attributes[ 'position' ];
-
- // render non-indexed triangles
-
- _gl.drawArrays( mode, 0, position.array.length / position.itemSize );
-
- _this.info.render.calls ++;
- _this.info.render.vertices += position.array.length / position.itemSize;
- _this.info.render.faces += position.array.length / ( 3 * position.itemSize );
-
- }
-
- } else if ( object instanceof THREE.PointCloud ) {
-
- // render particles
-
- var mode = _gl.POINTS;
-
- var index = geometry.attributes.index;
-
- if ( index ) {
-
- // indexed points
-
- var type, size;
-
- if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
-
- type = _gl.UNSIGNED_INT;
- size = 4;
-
- } else {
-
- type = _gl.UNSIGNED_SHORT;
- size = 2;
-
- }
-
- var offsets = geometry.offsets;
-
- if ( offsets.length === 0 ) {
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, 0 );
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
-
- }
-
- _gl.drawElements( mode, index.array.length, type, 0);
-
- _this.info.render.calls ++;
- _this.info.render.points += index.array.length;
-
- } else {
-
- // if there is more than 1 chunk
- // must set attribute pointers to use new offsets for each chunk
- // even if geometry and materials didn't change
-
- if ( offsets.length > 1 ) updateBuffers = true;
-
- for ( var i = 0, il = offsets.length; i < il; i ++ ) {
-
- var startIndex = offsets[ i ].index;
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, startIndex );
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
-
- }
-
- // render indexed points
-
- _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );
-
- _this.info.render.calls ++;
- _this.info.render.points += offsets[ i ].count;
-
- }
-
- }
-
- } else {
-
- // non-indexed points
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, 0 );
-
- }
-
- var position = geometry.attributes.position;
- var offsets = geometry.offsets;
-
- if ( offsets.length === 0 ) {
-
- _gl.drawArrays( mode, 0, position.array.length / 3 );
-
- _this.info.render.calls ++;
- _this.info.render.points += position.array.length / 3;
-
- } else {
-
- for ( var i = 0, il = offsets.length; i < il; i ++ ) {
-
- _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count );
-
- _this.info.render.calls ++;
- _this.info.render.points += offsets[ i ].count;
-
- }
-
- }
-
- }
-
- } else if ( object instanceof THREE.Line ) {
-
- var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
-
- state.setLineWidth( material.linewidth * pixelRatio );
-
- var index = geometry.attributes.index;
-
- if ( index ) {
-
- // indexed lines
-
- var type, size;
-
- if ( index.array instanceof Uint32Array ) {
-
- type = _gl.UNSIGNED_INT;
- size = 4;
-
- } else {
-
- type = _gl.UNSIGNED_SHORT;
- size = 2;
-
- }
-
- var offsets = geometry.offsets;
-
- if ( offsets.length === 0 ) {
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, 0 );
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
-
- }
-
- _gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array
-
- _this.info.render.calls ++;
- _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared
-
- } else {
-
- // if there is more than 1 chunk
- // must set attribute pointers to use new offsets for each chunk
- // even if geometry and materials didn't change
-
- if ( offsets.length > 1 ) updateBuffers = true;
-
- for ( var i = 0, il = offsets.length; i < il; i ++ ) {
-
- var startIndex = offsets[ i ].index;
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, startIndex );
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
-
- }
-
- // render indexed lines
-
- _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array
-
- _this.info.render.calls ++;
- _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
-
- }
-
- }
-
- } else {
-
- // non-indexed lines
-
- if ( updateBuffers ) {
-
- setupVertexAttributes( material, program, geometry, 0 );
-
- }
-
- var position = geometry.attributes.position;
- var offsets = geometry.offsets;
-
- if ( offsets.length === 0 ) {
-
- _gl.drawArrays( mode, 0, position.array.length / 3 );
-
- _this.info.render.calls ++;
- _this.info.render.vertices += position.array.length / 3;
-
- } else {
-
- for ( var i = 0, il = offsets.length; i < il; i ++ ) {
-
- _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count );
-
- _this.info.render.calls ++;
- _this.info.render.vertices += offsets[ i ].count;
-
- }
-
- }
-
- }
-
- }
-
- };
-
- this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {
-
- if ( material.visible === false ) return;
-
- updateObject( object );
-
- var program = setProgram( camera, lights, fog, material, object );
-
- var attributes = program.attributes;
-
- var updateBuffers = false,
- wireframeBit = material.wireframe ? 1 : 0,
- geometryProgram = geometryGroup.id + '_' + program.id + '_' + wireframeBit;
-
- if ( geometryProgram !== _currentGeometryProgram ) {
-
- _currentGeometryProgram = geometryProgram;
- updateBuffers = true;
-
- }
-
- if ( updateBuffers ) {
-
- state.initAttributes();
-
- }
-
- // vertices
-
- if ( ! material.morphTargets && attributes.position >= 0 ) {
-
- if ( updateBuffers ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
-
- state.enableAttribute( attributes.position );
-
- _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- } else {
-
- if ( object.morphTargetBase ) {
-
- setupMorphTargets( material, geometryGroup, object );
-
- }
-
- }
-
-
- if ( updateBuffers ) {
-
- // custom attributes
-
- // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers
-
- if ( geometryGroup.__webglCustomAttributesList ) {
-
- for ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
-
- var attribute = geometryGroup.__webglCustomAttributesList[ i ];
-
- if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
-
- state.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] );
-
- _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 );
-
- }
-
- }
-
- }
-
-
- // colors
-
- if ( attributes.color >= 0 ) {
-
- if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
-
- state.enableAttribute( attributes.color );
-
- _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
-
- } else if ( material.defaultAttributeValues !== undefined ) {
-
-
- _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color );
-
- }
-
- }
-
- // normals
-
- if ( attributes.normal >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
-
- state.enableAttribute( attributes.normal );
-
- _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- // tangents
-
- if ( attributes.tangent >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
-
- state.enableAttribute( attributes.tangent );
-
- _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
-
- }
-
- // uvs
-
- if ( attributes.uv >= 0 ) {
-
- if ( object.geometry.faceVertexUvs[ 0 ] ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
-
- state.enableAttribute( attributes.uv );
-
- _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
-
- } else if ( material.defaultAttributeValues !== undefined ) {
-
-
- _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv );
-
- }
-
- }
-
- if ( attributes.uv2 >= 0 ) {
-
- if ( object.geometry.faceVertexUvs[ 1 ] ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
-
- state.enableAttribute( attributes.uv2 );
-
- _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );
-
- } else if ( material.defaultAttributeValues !== undefined ) {
-
-
- _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 );
-
- }
-
- }
-
- if ( material.skinning &&
- attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
-
- state.enableAttribute( attributes.skinIndex );
-
- _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
-
- state.enableAttribute( attributes.skinWeight );
-
- _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );
-
- }
-
- // line distances
-
- if ( attributes.lineDistance >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer );
-
- state.enableAttribute( attributes.lineDistance );
-
- _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 );
-
- }
-
- }
-
- state.disableUnusedAttributes();
-
- // render mesh
-
- if ( object instanceof THREE.Mesh ) {
-
- var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT;
-
- // wireframe
-
- if ( material.wireframe ) {
-
- state.setLineWidth( material.wireframeLinewidth * pixelRatio );
-
- if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
- _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 );
-
- // triangles
-
- } else {
-
- if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
- _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 0 );
-
- }
-
- _this.info.render.calls ++;
- _this.info.render.vertices += geometryGroup.__webglFaceCount;
- _this.info.render.faces += geometryGroup.__webglFaceCount / 3;
-
- // render lines
-
- } else if ( object instanceof THREE.Line ) {
-
- var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
-
- state.setLineWidth( material.linewidth * pixelRatio );
-
- _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount );
-
- _this.info.render.calls ++;
-
- // render particles
-
- } else if ( object instanceof THREE.PointCloud ) {
-
- _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );
-
- _this.info.render.calls ++;
- _this.info.render.points += geometryGroup.__webglParticleCount;
-
- }
-
- };
-
- function setupMorphTargets ( material, geometryGroup, object ) {
-
- // set base
-
- var attributes = material.program.attributes;
-
- if ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] );
-
- state.enableAttribute( attributes.position );
-
- _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
-
- } else if ( attributes.position >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
-
- state.enableAttribute( attributes.position );
-
- _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- if ( object.morphTargetForcedOrder.length ) {
-
- // set forced order
-
- var m = 0;
- var order = object.morphTargetForcedOrder;
- var influences = object.morphTargetInfluences;
-
- var attribute;
-
- while ( m < material.numSupportedMorphTargets && m < order.length ) {
-
- attribute = attributes[ 'morphTarget' + m ];
-
- if ( attribute >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );
-
- state.enableAttribute( attribute );
-
- _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- attribute = attributes[ 'morphNormal' + m ];
-
- if ( attribute >= 0 && material.morphNormals ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] );
-
- state.enableAttribute( attribute );
-
- _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];
-
- m ++;
-
- }
-
- } else {
-
- // find the most influencing
-
- var activeInfluenceIndices = [];
- var influences = object.morphTargetInfluences;
- var morphTargets = object.geometry.morphTargets;
-
- if ( influences.length > morphTargets.length ) {
-
- console.warn( 'THREE.Canvas3DRenderer: Influences array is bigger than morphTargets array.' );
- influences.length = morphTargets.length;
-
- }
-
- for ( var i = 0, il = influences.length; i < il; i ++ ) {
-
- var influence = influences[ i ];
-
- activeInfluenceIndices.push( [ influence, i ] );
-
- }
-
- if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) {
-
- activeInfluenceIndices.sort( numericalSort );
- activeInfluenceIndices.length = material.numSupportedMorphTargets;
-
- } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) {
-
- activeInfluenceIndices.sort( numericalSort );
-
- } else if ( activeInfluenceIndices.length === 0 ) {
-
- activeInfluenceIndices.push( [ 0, 0 ] );
-
- }
-
- var attribute;
-
- for ( var m = 0, ml = material.numSupportedMorphTargets; m < ml; m ++ ) {
-
- if ( activeInfluenceIndices[ m ] ) {
-
- var influenceIndex = activeInfluenceIndices[ m ][ 1 ];
-
- attribute = attributes[ 'morphTarget' + m ];
-
- if ( attribute >= 0 ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] );
-
- state.enableAttribute( attribute );
-
- _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- attribute = attributes[ 'morphNormal' + m ];
-
- if ( attribute >= 0 && material.morphNormals ) {
-
- _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] );
-
- state.enableAttribute( attribute );
-
- _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );
-
- }
-
- object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ];
-
- } else {
-
- /*
- _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
-
- if ( material.morphNormals ) {
-
- _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
-
- }
- */
-
- object.__webglMorphTargetInfluences[ m ] = 0;
-
- }
-
- }
-
- }
-
- // load updated influences uniform
-
- if ( material.program.uniforms.morphTargetInfluences !== null ) {
-
- _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );
-
- }
-
- }
-
- // Sorting
-
- function painterSortStable ( a, b ) {
-
- if ( a.object.renderOrder !== b.object.renderOrder ) {
-
- return a.object.renderOrder - b.object.renderOrder;
-
- } else if ( a.material.id !== b.material.id ) {
-
- return a.material.id - b.material.id;
-
- } else if ( a.z !== b.z ) {
-
- return a.z - b.z;
-
- } else {
-
- return a.id - b.id;
-
- }
-
- }
-
- function reversePainterSortStable ( a, b ) {
-
- if ( a.object.renderOrder !== b.object.renderOrder ) {
-
- return a.object.renderOrder - b.object.renderOrder;
-
- } if ( a.z !== b.z ) {
-
- return b.z - a.z;
-
- } else {
-
- return a.id - b.id;
-
- }
-
- }
-
- function numericalSort ( a, b ) {
-
- return b[ 0 ] - a[ 0 ];
-
- }
-
- // Rendering
-
- this.render = function ( scene, camera, renderTarget, forceClear ) {
-
- if ( camera instanceof THREE.Camera === false ) {
-
- THREE.error( 'THREE.Canvas3DRenderer.render: camera is not an instance of THREE.Camera.' );
- return;
-
- }
-
- var fog = scene.fog;
-
- // reset caching for this frame
-
- _currentGeometryProgram = '';
- _currentMaterialId = - 1;
- _currentCamera = null;
- _lightsNeedUpdate = true;
-
- // update scene graph
-
- if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
-
- // update camera matrices and frustum
-
- if ( camera.parent === undefined ) camera.updateMatrixWorld();
-
- // update Skeleton objects
-
- scene.traverse( function ( object ) {
-
- if ( object instanceof THREE.SkinnedMesh ) {
-
- object.skeleton.update();
-
- }
-
- } );
-
- camera.matrixWorldInverse.getInverse( camera.matrixWorld );
-
- _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
- _frustum.setFromMatrix( _projScreenMatrix );
-
- lights.length = 0;
- opaqueObjects.length = 0;
- transparentObjects.length = 0;
-
- sprites.length = 0;
- lensFlares.length = 0;
-
- projectObject( scene );
-
- if ( _this.sortObjects === true ) {
-
- opaqueObjects.sort( painterSortStable );
- transparentObjects.sort( reversePainterSortStable );
-
- }
-
- // custom render plugins (pre pass)
-
- shadowMapPlugin.render( scene, camera );
-
- //
-
- _this.info.render.calls = 0;
- _this.info.render.vertices = 0;
- _this.info.render.faces = 0;
- _this.info.render.points = 0;
-
- this.setRenderTarget( renderTarget );
-
- if ( this.autoClear || forceClear ) {
-
- this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
-
- }
-
- // set matrices for immediate objects
-
- for ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) {
-
- var webglObject = _webglObjectsImmediate[ i ];
- var object = webglObject.object;
-
- if ( object.visible ) {
-
- setupMatrices( object, camera );
-
- unrollImmediateBufferMaterial( webglObject );
-
- }
-
- }
-
- if ( scene.overrideMaterial ) {
-
- var overrideMaterial = scene.overrideMaterial;
-
- setMaterial( overrideMaterial );
-
- renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial );
- renderObjects( transparentObjects, camera, lights, fog, overrideMaterial );
- renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial );
-
- } else {
-
- // opaque pass (front-to-back order)
-
- state.setBlending( THREE.NoBlending );
-
- renderObjects( opaqueObjects, camera, lights, fog, null );
- renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null );
-
- // transparent pass (back-to-front order)
-
- renderObjects( transparentObjects, camera, lights, fog, null );
- renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null );
-
- }
-
- // custom render plugins (post pass)
-
- spritePlugin.render( scene, camera );
- lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight );
-
- // Generate mipmap if we're using any kind of mipmap filtering
-
- if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
-
- updateRenderTargetMipmap( renderTarget );
-
- }
-
- // Ensure depth buffer writing is enabled so it can be cleared on next render
-
- state.setDepthTest( true );
- state.setDepthWrite( true );
- state.setColorWrite( true );
-
- // _gl.finish();
-
- };
-
- function projectObject( object ) {
-
- if ( object.visible === false ) return;
-
- if ( object instanceof THREE.Scene || object instanceof THREE.Group ) {
-
- // skip
-
- } else {
-
- initObject( object );
-
- if ( object instanceof THREE.Light ) {
-
- lights.push( object );
-
- } else if ( object instanceof THREE.Sprite ) {
-
- sprites.push( object );
-
- } else if ( object instanceof THREE.LensFlare ) {
-
- lensFlares.push( object );
-
- } else {
-
- var webglObjects = _webglObjects[ object.id ];
-
- if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {
-
- for ( var i = 0, l = webglObjects.length; i < l; i ++ ) {
-
- var webglObject = webglObjects[ i ];
-
- unrollBufferMaterial( webglObject );
-
- webglObject.render = true;
-
- if ( _this.sortObjects === true ) {
-
- _vector3.setFromMatrixPosition( object.matrixWorld );
- _vector3.applyProjection( _projScreenMatrix );
-
- webglObject.z = _vector3.z;
-
- }
-
- }
-
- }
-
- }
-
- }
-
- for ( var i = 0, l = object.children.length; i < l; i ++ ) {
-
- projectObject( object.children[ i ] );
-
- }
-
- }
-
- function renderObjects( renderList, camera, lights, fog, overrideMaterial ) {
-
- var material;
-
- for ( var i = 0, l = renderList.length; i < l; i ++ ) {
-
- var webglObject = renderList[ i ];
-
- var object = webglObject.object;
- var buffer = webglObject.buffer;
-
- setupMatrices( object, camera );
-
- if ( overrideMaterial ) {
-
- material = overrideMaterial;
-
- } else {
-
- material = webglObject.material;
-
- if ( ! material ) continue;
-
- setMaterial( material );
-
- }
-
- _this.setMaterialFaces( material );
-
- if ( buffer instanceof THREE.BufferGeometry ) {
-
- _this.renderBufferDirect( camera, lights, fog, material, buffer, object );
-
- } else {
-
- _this.renderBuffer( camera, lights, fog, material, buffer, object );
-
- }
-
- }
-
- }
-
- function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) {
-
- var material;
-
- for ( var i = 0, l = renderList.length; i < l; i ++ ) {
-
- var webglObject = renderList[ i ];
- var object = webglObject.object;
-
- if ( object.visible ) {
-
- if ( overrideMaterial ) {
-
- material = overrideMaterial;
-
- } else {
-
- material = webglObject[ materialType ];
-
- if ( ! material ) continue;
-
- setMaterial( material );
-
- }
-
- _this.renderImmediateObject( camera, lights, fog, material, object );
-
- }
-
- }
-
- }
-
- this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
-
- var program = setProgram( camera, lights, fog, material, object );
-
- _currentGeometryProgram = '';
-
- _this.setMaterialFaces( material );
-
- if ( object.immediateRenderCallback ) {
-
- object.immediateRenderCallback( program, _gl, _frustum );
-
- } else {
-
- object.render( function ( object ) { _this.renderBufferImmediate( object, program, material ); } );
-
- }
-
- };
-
- function unrollImmediateBufferMaterial ( globject ) {
-
- var object = globject.object,
- material = object.material;
-
- if ( material.transparent ) {
-
- globject.transparent = material;
- globject.opaque = null;
-
- } else {
-
- globject.opaque = material;
- globject.transparent = null;
-
- }
-
- }
-
- function unrollBufferMaterial ( globject ) {
-
- var object = globject.object;
- var buffer = globject.buffer;
-
- var geometry = object.geometry;
- var material = object.material;
-
- if ( material instanceof THREE.MeshFaceMaterial ) {
-
- var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex;
-
- material = material.materials[ materialIndex ];
-
- globject.material = material;
-
- if ( material.transparent ) {
-
- transparentObjects.push( globject );
-
- } else {
-
- opaqueObjects.push( globject );
-
- }
-
- } else if ( material ) {
-
- globject.material = material;
-
- if ( material.transparent ) {
-
- transparentObjects.push( globject );
-
- } else {
-
- opaqueObjects.push( globject );
-
- }
-
- }
-
- }
-
- function initObject( object ) {
-
- if ( object.__webglInit === undefined ) {
-
- object.__webglInit = true;
- object._modelViewMatrix = new THREE.Matrix4();
- object._normalMatrix = new THREE.Matrix3();
-
- object.addEventListener( 'removed', onObjectRemoved );
-
- }
-
- var geometry = object.geometry;
-
- if ( geometry === undefined ) {
-
- // ImmediateRenderObject
-
- } else if ( geometry.__webglInit === undefined ) {
-
- geometry.__webglInit = true;
- geometry.addEventListener( 'dispose', onGeometryDispose );
-
- if ( geometry instanceof THREE.BufferGeometry ) {
-
- _this.info.memory.geometries ++;
-
- } else if ( object instanceof THREE.Mesh ) {
-
- initGeometryGroups( object, geometry );
-
- } else if ( object instanceof THREE.Line ) {
-
- if ( geometry.__webglVertexBuffer === undefined ) {
-
- createLineBuffers( geometry );
- initLineBuffers( geometry, object );
-
- geometry.verticesNeedUpdate = true;
- geometry.colorsNeedUpdate = true;
- geometry.lineDistancesNeedUpdate = true;
-
- }
-
- } else if ( object instanceof THREE.PointCloud ) {
-
- if ( geometry.__webglVertexBuffer === undefined ) {
-
- createParticleBuffers( geometry );
- initParticleBuffers( geometry, object );
-
- geometry.verticesNeedUpdate = true;
- geometry.colorsNeedUpdate = true;
-
- }
-
- }
-
- }
-
- if ( object.__webglActive === undefined) {
-
- object.__webglActive = true;
-
- if ( object instanceof THREE.Mesh ) {
-
- if ( geometry instanceof THREE.BufferGeometry ) {
-
- addBuffer( _webglObjects, geometry, object );
-
- } else if ( geometry instanceof THREE.Geometry ) {
-
- var geometryGroupsList = geometryGroups[ geometry.id ];
-
- for ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) {
-
- addBuffer( _webglObjects, geometryGroupsList[ i ], object );
-
- }
-
- }
-
- } else if ( object instanceof THREE.Line || object instanceof THREE.PointCloud ) {
-
- addBuffer( _webglObjects, geometry, object );
-
- } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
-
- addBufferImmediate( _webglObjectsImmediate, object );
-
- }
-
- }
-
- }
-
- // Geometry splitting
-
- var geometryGroups = {};
- var geometryGroupCounter = 0;
-
- function makeGroups( geometry, usesFaceMaterial ) {
-
- var maxVerticesInGroup = extensions.get( 'OES_element_index_uint' ) ? 4294967296 : 65535;
-
- var groupHash, hash_map = {};
-
- var numMorphTargets = geometry.morphTargets.length;
- var numMorphNormals = geometry.morphNormals.length;
-
- var group;
- var groups = {};
- var groupsList = [];
-
- for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
-
- var face = geometry.faces[ f ];
- var materialIndex = usesFaceMaterial ? face.materialIndex : 0;
-
- if ( ! ( materialIndex in hash_map ) ) {
-
- hash_map[ materialIndex ] = { hash: materialIndex, counter: 0 };
-
- }
-
- groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
-
- if ( ! ( groupHash in groups ) ) {
-
- group = {
- id: geometryGroupCounter ++,
- faces3: [],
- materialIndex: materialIndex,
- vertices: 0,
- numMorphTargets: numMorphTargets,
- numMorphNormals: numMorphNormals
- };
-
- groups[ groupHash ] = group;
- groupsList.push( group );
-
- }
-
- if ( groups[ groupHash ].vertices + 3 > maxVerticesInGroup ) {
-
- hash_map[ materialIndex ].counter += 1;
- groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
-
- if ( ! ( groupHash in groups ) ) {
-
- group = {
- id: geometryGroupCounter ++,
- faces3: [],
- materialIndex: materialIndex,
- vertices: 0,
- numMorphTargets: numMorphTargets,
- numMorphNormals: numMorphNormals
- };
-
- groups[ groupHash ] = group;
- groupsList.push( group );
-
- }
-
- }
-
- groups[ groupHash ].faces3.push( f );
- groups[ groupHash ].vertices += 3;
-
- }
-
- return groupsList;
-
- }
-
- function initGeometryGroups( object, geometry ) {
-
- var material = object.material, addBuffers = false;
-
- if ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) {
-
- delete _webglObjects[ object.id ];
-
- geometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial );
-
- geometry.groupsNeedUpdate = false;
-
- }
-
- var geometryGroupsList = geometryGroups[ geometry.id ];
-
- // create separate VBOs per geometry chunk
-
- for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {
-
- var geometryGroup = geometryGroupsList[ i ];
-
- // initialise VBO on the first access
-
- if ( geometryGroup.__webglVertexBuffer === undefined ) {
-
- createMeshBuffers( geometryGroup );
- initMeshBuffers( geometryGroup, object );
-
- geometry.verticesNeedUpdate = true;
- geometry.morphTargetsNeedUpdate = true;
- geometry.elementsNeedUpdate = true;
- geometry.uvsNeedUpdate = true;
- geometry.normalsNeedUpdate = true;
- geometry.tangentsNeedUpdate = true;
- geometry.colorsNeedUpdate = true;
-
- addBuffers = true;
-
- } else {
-
- addBuffers = false;
-
- }
-
- if ( addBuffers || object.__webglActive === undefined ) {
-
- addBuffer( _webglObjects, geometryGroup, object );
-
- }
-
- }
-
- object.__webglActive = true;
-
- }
-
- function addBuffer( objlist, buffer, object ) {
-
- var id = object.id;
- objlist[id] = objlist[id] || [];
- objlist[id].push(
- {
- id: id,
- buffer: buffer,
- object: object,
- material: null,
- z: 0
- }
- );
-
- };
-
- function addBufferImmediate( objlist, object ) {
-
- objlist.push(
- {
- id: null,
- object: object,
- opaque: null,
- transparent: null,
- z: 0
- }
- );
-
- };
-
- // Objects updates
-
- function updateObject( object ) {
-
- var geometry = object.geometry;
-
- if ( geometry instanceof THREE.BufferGeometry ) {
-
- var attributes = geometry.attributes;
- var attributesKeys = geometry.attributesKeys;
-
- for ( var i = 0, l = attributesKeys.length; i < l; i ++ ) {
-
- var key = attributesKeys[ i ];
- var attribute = attributes[ key ];
- var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER;
-
- if ( attribute.buffer === undefined ) {
-
- attribute.buffer = _gl.createBuffer();
- _gl.bindBuffer( bufferType, attribute.buffer );
- _gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW );
-
- attribute.needsUpdate = false;
-
- } else if ( attribute.needsUpdate === true ) {
-
- _gl.bindBuffer( bufferType, attribute.buffer );
-
- if ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges
-
- _gl.bufferSubData( bufferType, 0, attribute.array );
-
- } else if ( attribute.updateRange.count === 0 ) {
-
- console.error( 'THREE.Canvas3DRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' );
-
- } else {
-
- _gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT,
- attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) );
-
- attribute.updateRange.count = 0; // reset range
-
- }
-
- attribute.needsUpdate = false;
-
- }
-
- }
-
- } else if ( object instanceof THREE.Mesh ) {
-
- // check all geometry groups
-
- if ( geometry.groupsNeedUpdate === true ) {
-
- initGeometryGroups( object, geometry );
-
- }
-
- var geometryGroupsList = geometryGroups[ geometry.id ];
-
- for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {
-
- var geometryGroup = geometryGroupsList[ i ];
- var material = getBufferMaterial( object, geometryGroup );
-
- var customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
-
- if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate ||
- geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
- geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) {
-
- setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, ! geometry.dynamic, material );
-
- }
-
- }
-
- geometry.verticesNeedUpdate = false;
- geometry.morphTargetsNeedUpdate = false;
- geometry.elementsNeedUpdate = false;
- geometry.uvsNeedUpdate = false;
- geometry.normalsNeedUpdate = false;
- geometry.colorsNeedUpdate = false;
- geometry.tangentsNeedUpdate = false;
-
- if (material.attributes) clearCustomAttributes( material );
-
- } else if ( object instanceof THREE.Line ) {
-
- var material = getBufferMaterial( object, geometry );
- var customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
-
- if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) {
-
- setLineBuffers( geometry, _gl.DYNAMIC_DRAW );
-
- }
-
- geometry.verticesNeedUpdate = false;
- geometry.colorsNeedUpdate = false;
- geometry.lineDistancesNeedUpdate = false;
-
- if (material.attributes) clearCustomAttributes( material );
-
- } else if ( object instanceof THREE.PointCloud ) {
-
- var material = getBufferMaterial( object, geometry );
- var customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
-
- if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || customAttributesDirty ) {
-
- setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );
-
- }
-
- geometry.verticesNeedUpdate = false;
- geometry.colorsNeedUpdate = false;
-
- if(material.attributes) clearCustomAttributes( material );
-
- }
-
- }
-
- // Objects updates - custom attributes check
-
- function areCustomAttributesDirty( material ) {
-
- for ( var name in material.attributes ) {
-
- if ( material.attributes[ name ].needsUpdate ) return true;
-
- }
-
- return false;
-
- }
-
- function clearCustomAttributes( material ) {
-
- for ( var name in material.attributes ) {
-
- material.attributes[ name ].needsUpdate = false;
-
- }
-
- }
-
- // Objects removal
-
- function removeObject( object ) {
-
- if ( object instanceof THREE.Mesh ||
- object instanceof THREE.PointCloud ||
- object instanceof THREE.Line ) {
-
- delete _webglObjects[ object.id ];
-
- } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
-
- removeInstances( _webglObjectsImmediate, object );
-
- }
-
- delete object.__webglInit;
- delete object._modelViewMatrix;
- delete object._normalMatrix;
-
- delete object.__webglActive;
-
- }
-
- function removeInstances( objlist, object ) {
-
- for ( var o = objlist.length - 1; o >= 0; o -- ) {
-
- if ( objlist[ o ].object === object ) {
-
- objlist.splice( o, 1 );
-
- }
-
- }
-
- }
-
- // Materials
-
- var shaderIDs = {
- MeshDepthMaterial: 'depth',
- MeshNormalMaterial: 'normal',
- MeshBasicMaterial: 'basic',
- MeshLambertMaterial: 'lambert',
- MeshPhongMaterial: 'phong',
- LineBasicMaterial: 'basic',
- LineDashedMaterial: 'dashed',
- PointCloudMaterial: 'particle_basic'
- };
-
- function initMaterial( material, lights, fog, object ) {
-
- material.addEventListener( 'dispose', onMaterialDispose );
-
- var shaderID = shaderIDs[ material.type ];
-
- if ( shaderID ) {
-
- var shader = THREE.ShaderLib[ shaderID ];
-
- material.__webglShader = {
- uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
- vertexShader: shader.vertexShader,
- fragmentShader: shader.fragmentShader
- }
-
- } else {
-
- material.__webglShader = {
- uniforms: material.uniforms,
- vertexShader: material.vertexShader,
- fragmentShader: material.fragmentShader
- }
-
- }
-
- // heuristics to create shader parameters according to lights in the scene
- // (not to blow over maxLights budget)
-
- var maxLightCount = allocateLights( lights );
- var maxShadows = allocateShadows( lights );
- var maxBones = allocateBones( object );
-
- var parameters = {
-
- precision: _precision,
- supportsVertexTextures: _supportsVertexTextures,
-
- map: !! material.map,
- envMap: !! material.envMap,
- envMapMode: material.envMap && material.envMap.mapping,
- lightMap: !! material.lightMap,
- bumpMap: !! material.bumpMap,
- normalMap: !! material.normalMap,
- specularMap: !! material.specularMap,
- alphaMap: !! material.alphaMap,
-
- combine: material.combine,
-
- vertexColors: material.vertexColors,
-
- fog: fog,
- useFog: material.fog,
- fogExp: fog instanceof THREE.FogExp2,
-
- flatShading: material.shading === THREE.FlatShading,
-
- sizeAttenuation: material.sizeAttenuation,
- logarithmicDepthBuffer: _logarithmicDepthBuffer,
-
- skinning: material.skinning,
- maxBones: maxBones,
- useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture,
-
- morphTargets: material.morphTargets,
- morphNormals: material.morphNormals,
- maxMorphTargets: _this.maxMorphTargets,
- maxMorphNormals: _this.maxMorphNormals,
-
- maxDirLights: maxLightCount.directional,
- maxPointLights: maxLightCount.point,
- maxSpotLights: maxLightCount.spot,
- maxHemiLights: maxLightCount.hemi,
-
- maxShadows: maxShadows,
- shadowMapEnabled: _this.shadowMapEnabled && object.receiveShadow && maxShadows > 0,
- shadowMapType: _this.shadowMapType,
- shadowMapDebug: _this.shadowMapDebug,
- shadowMapCascade: _this.shadowMapCascade,
-
- alphaTest: material.alphaTest,
- metal: material.metal,
- wrapAround: material.wrapAround,
- doubleSided: material.side === THREE.DoubleSide,
- flipSided: material.side === THREE.BackSide
-
- };
-
- // Generate code
-
- var chunks = [];
-
- if ( shaderID ) {
-
- chunks.push( shaderID );
-
- } else {
-
- chunks.push( material.fragmentShader );
- chunks.push( material.vertexShader );
-
- }
-
- if ( material.defines !== undefined ) {
-
- for ( var name in material.defines ) {
-
- chunks.push( name );
- chunks.push( material.defines[ name ] );
-
- }
-
- }
-
- for ( var name in parameters ) {
-
- chunks.push( name );
- chunks.push( parameters[ name ] );
-
- }
-
- var code = chunks.join();
-
- var program;
-
- // Check if code has been already compiled
-
- for ( var p = 0, pl = _programs.length; p < pl; p ++ ) {
-
- var programInfo = _programs[ p ];
-
- if ( programInfo.code === code ) {
-
- program = programInfo;
- program.usedTimes ++;
-
- break;
-
- }
-
- }
-
- if ( program === undefined ) {
-
- program = new THREE.WebGLProgram( _this, code, material, parameters );
- _programs.push( program );
-
- _this.info.memory.programs = _programs.length;
-
- }
-
- material.program = program;
-
- var attributes = program.attributes;
-
- if ( material.morphTargets ) {
-
- material.numSupportedMorphTargets = 0;
-
- var id, base = 'morphTarget';
-
- for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
-
- id = base + i;
-
- if ( attributes[ id ] >= 0 ) {
-
- material.numSupportedMorphTargets ++;
-
- }
-
- }
-
- }
-
- if ( material.morphNormals ) {
-
- material.numSupportedMorphNormals = 0;
-
- var id, base = 'morphNormal';
-
- for ( i = 0; i < _this.maxMorphNormals; i ++ ) {
-
- id = base + i;
-
- if ( attributes[ id ] >= 0 ) {
-
- material.numSupportedMorphNormals ++;
-
- }
-
- }
-
- }
-
- material.uniformsList = [];
-
- for ( var u in material.__webglShader.uniforms ) {
-
- var location = material.program.uniforms[ u ];
-
- if ( location ) {
- material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
- }
-
- }
-
- }
-
- function setMaterial( material ) {
-
- if ( material.transparent === true ) {
-
- state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha );
-
- } else {
-
- state.setBlending( THREE.NoBlending );
-
- }
-
- state.setDepthTest( material.depthTest );
- state.setDepthWrite( material.depthWrite );
- state.setColorWrite( material.colorWrite );
- state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
-
- }
-
- function setProgram( camera, lights, fog, material, object ) {
-
- _usedTextureUnits = 0;
-
- if ( material.needsUpdate ) {
-
- if ( material.program ) deallocateMaterial( material );
-
- initMaterial( material, lights, fog, object );
- material.needsUpdate = false;
-
- }
-
- if ( material.morphTargets ) {
-
- if ( ! object.__webglMorphTargetInfluences ) {
-
- object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
-
- }
-
- }
-
- var refreshProgram = false;
- var refreshMaterial = false;
- var refreshLights = false;
-
- var program = material.program,
- p_uniforms = program.uniforms,
- m_uniforms = material.__webglShader.uniforms;
-
- if ( program.id !== _currentProgram ) {
-
- _gl.useProgram( program.program );
- _currentProgram = program.id;
-
- refreshProgram = true;
- refreshMaterial = true;
- refreshLights = true;
-
- }
-
- if ( material.id !== _currentMaterialId ) {
-
- if ( _currentMaterialId === -1 ) refreshLights = true;
- _currentMaterialId = material.id;
-
- refreshMaterial = true;
-
- }
-
- if ( refreshProgram || camera !== _currentCamera ) {
-
- _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
-
- if ( _logarithmicDepthBuffer ) {
-
- _gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
-
- }
-
-
- if ( camera !== _currentCamera ) _currentCamera = camera;
-
- // load material specific uniforms
- // (shader material also gets them for the sake of genericity)
-
- if ( material instanceof THREE.ShaderMaterial ||
- material instanceof THREE.MeshPhongMaterial ||
- material.envMap ) {
-
- if ( p_uniforms.cameraPosition !== null ) {
-
- _vector3.setFromMatrixPosition( camera.matrixWorld );
- _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z );
-
- }
-
- }
-
- if ( material instanceof THREE.MeshPhongMaterial ||
- material instanceof THREE.MeshLambertMaterial ||
- material instanceof THREE.MeshBasicMaterial ||
- material instanceof THREE.ShaderMaterial ||
- material.skinning ) {
-
- if ( p_uniforms.viewMatrix !== null ) {
-
- _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements );
-
- }
-
- }
-
- }
-
- // skinning uniforms must be set even if material didn't change
- // auto-setting of texture unit for bone texture must go before other textures
- // not sure why, but otherwise weird things happen
-
- if ( material.skinning ) {
-
- if ( object.bindMatrix && p_uniforms.bindMatrix !== null ) {
-
- _gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements );
-
- }
-
- if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) {
-
- _gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements );
-
- }
-
- if ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) {
-
- if ( p_uniforms.boneTexture !== null ) {
-
- var textureUnit = getTextureUnit();
-
- _gl.uniform1i( p_uniforms.boneTexture, textureUnit );
- _this.setTexture( object.skeleton.boneTexture, textureUnit );
-
- }
-
- if ( p_uniforms.boneTextureWidth !== null ) {
-
- _gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth );
-
- }
-
- if ( p_uniforms.boneTextureHeight !== null ) {
-
- _gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight );
-
- }
-
- } else if ( object.skeleton && object.skeleton.boneMatrices ) {
-
- if ( p_uniforms.boneGlobalMatrices !== null ) {
-
- _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices );
-
- }
-
- }
-
- }
-
- if ( refreshMaterial ) {
-
- // refresh uniforms common to several materials
-
- if ( fog && material.fog ) {
-
- refreshUniformsFog( m_uniforms, fog );
-
- }
-
- if ( material instanceof THREE.MeshPhongMaterial ||
- material instanceof THREE.MeshLambertMaterial ||
- material.lights ) {
-
- if ( _lightsNeedUpdate ) {
-
- refreshLights = true;
- setupLights( lights );
- _lightsNeedUpdate = false;
- }
-
- if ( refreshLights ) {
- refreshUniformsLights( m_uniforms, _lights );
- markUniformsLightsNeedsUpdate( m_uniforms, true );
- } else {
- markUniformsLightsNeedsUpdate( m_uniforms, false );
- }
-
- }
-
- if ( material instanceof THREE.MeshBasicMaterial ||
- material instanceof THREE.MeshLambertMaterial ||
- material instanceof THREE.MeshPhongMaterial ) {
-
- refreshUniformsCommon( m_uniforms, material );
-
- }
-
- // refresh single material specific uniforms
-
- if ( material instanceof THREE.LineBasicMaterial ) {
-
- refreshUniformsLine( m_uniforms, material );
-
- } else if ( material instanceof THREE.LineDashedMaterial ) {
-
- refreshUniformsLine( m_uniforms, material );
- refreshUniformsDash( m_uniforms, material );
-
- } else if ( material instanceof THREE.PointCloudMaterial ) {
-
- refreshUniformsParticle( m_uniforms, material );
-
- } else if ( material instanceof THREE.MeshPhongMaterial ) {
-
- refreshUniformsPhong( m_uniforms, material );
-
- } else if ( material instanceof THREE.MeshLambertMaterial ) {
-
- refreshUniformsLambert( m_uniforms, material );
-
- } else if ( material instanceof THREE.MeshDepthMaterial ) {
-
- m_uniforms.mNear.value = camera.near;
- m_uniforms.mFar.value = camera.far;
- m_uniforms.opacity.value = material.opacity;
-
- } else if ( material instanceof THREE.MeshNormalMaterial ) {
-
- m_uniforms.opacity.value = material.opacity;
-
- }
-
- if ( object.receiveShadow && ! material._shadowPass ) {
-
- refreshUniformsShadow( m_uniforms, lights );
-
- }
-
- // load common uniforms
-
- loadUniformsGeneric( material.uniformsList );
-
- }
-
- loadUniformsMatrices( p_uniforms, object );
-
- if ( p_uniforms.modelMatrix !== null ) {
-
- _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements );
-
- }
-
- return program;
-
- }
-
- // Uniforms (refresh uniforms objects)
-
- function refreshUniformsCommon ( uniforms, material ) {
-
- uniforms.opacity.value = material.opacity;
-
- uniforms.diffuse.value = material.color;
-
- uniforms.map.value = material.map;
- uniforms.lightMap.value = material.lightMap;
- uniforms.specularMap.value = material.specularMap;
- uniforms.alphaMap.value = material.alphaMap;
-
- if ( material.bumpMap ) {
-
- uniforms.bumpMap.value = material.bumpMap;
- uniforms.bumpScale.value = material.bumpScale;
-
- }
-
- if ( material.normalMap ) {
-
- uniforms.normalMap.value = material.normalMap;
- uniforms.normalScale.value.copy( material.normalScale );
-
- }
-
- // uv repeat and offset setting priorities
- // 1. color map
- // 2. specular map
- // 3. normal map
- // 4. bump map
- // 5. alpha map
-
- var uvScaleMap;
-
- if ( material.map ) {
-
- uvScaleMap = material.map;
-
- } else if ( material.specularMap ) {
-
- uvScaleMap = material.specularMap;
-
- } else if ( material.normalMap ) {
-
- uvScaleMap = material.normalMap;
-
- } else if ( material.bumpMap ) {
-
- uvScaleMap = material.bumpMap;
-
- } else if ( material.alphaMap ) {
-
- uvScaleMap = material.alphaMap;
-
- }
-
- if ( uvScaleMap !== undefined ) {
-
- var offset = uvScaleMap.offset;
- var repeat = uvScaleMap.repeat;
-
- uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
-
- }
-
- uniforms.envMap.value = material.envMap;
- uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1;
-
- uniforms.reflectivity.value = material.reflectivity;
- uniforms.refractionRatio.value = material.refractionRatio;
-
- }
-
- function refreshUniformsLine ( uniforms, material ) {
-
- uniforms.diffuse.value = material.color;
- uniforms.opacity.value = material.opacity;
-
- }
-
- function refreshUniformsDash ( uniforms, material ) {
-
- uniforms.dashSize.value = material.dashSize;
- uniforms.totalSize.value = material.dashSize + material.gapSize;
- uniforms.scale.value = material.scale;
-
- }
-
- function refreshUniformsParticle ( uniforms, material ) {
-
- uniforms.psColor.value = material.color;
- uniforms.opacity.value = material.opacity;
- uniforms.size.value = material.size;
- uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this.
-
- uniforms.map.value = material.map;
-
- if ( material.map !== null ) {
-
- var offset = material.map.offset;
- var repeat = material.map.repeat;
-
- uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
-
- }
-
- }
-
- function refreshUniformsFog ( uniforms, fog ) {
-
- uniforms.fogColor.value = fog.color;
-
- if ( fog instanceof THREE.Fog ) {
-
- uniforms.fogNear.value = fog.near;
- uniforms.fogFar.value = fog.far;
-
- } else if ( fog instanceof THREE.FogExp2 ) {
-
- uniforms.fogDensity.value = fog.density;
-
- }
-
- }
-
- function refreshUniformsPhong ( uniforms, material ) {
-
- uniforms.shininess.value = material.shininess;
-
- uniforms.emissive.value = material.emissive;
- uniforms.specular.value = material.specular;
-
- if ( material.wrapAround ) {
-
- uniforms.wrapRGB.value.copy( material.wrapRGB );
-
- }
-
- }
-
- function refreshUniformsLambert ( uniforms, material ) {
-
- uniforms.emissive.value = material.emissive;
-
- if ( material.wrapAround ) {
-
- uniforms.wrapRGB.value.copy( material.wrapRGB );
-
- }
-
- }
-
- function refreshUniformsLights ( uniforms, lights ) {
-
- uniforms.ambientLightColor.value = lights.ambient;
-
- uniforms.directionalLightColor.value = lights.directional.colors;
- uniforms.directionalLightDirection.value = lights.directional.positions;
-
- uniforms.pointLightColor.value = lights.point.colors;
- uniforms.pointLightPosition.value = lights.point.positions;
- uniforms.pointLightDistance.value = lights.point.distances;
- uniforms.pointLightDecay.value = lights.point.decays;
-
- uniforms.spotLightColor.value = lights.spot.colors;
- uniforms.spotLightPosition.value = lights.spot.positions;
- uniforms.spotLightDistance.value = lights.spot.distances;
- uniforms.spotLightDirection.value = lights.spot.directions;
- uniforms.spotLightAngleCos.value = lights.spot.anglesCos;
- uniforms.spotLightExponent.value = lights.spot.exponents;
- uniforms.spotLightDecay.value = lights.spot.decays;
-
- uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;
- uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
- uniforms.hemisphereLightDirection.value = lights.hemi.positions;
-
- }
-
- // If uniforms are marked as clean, they don't need to be loaded to the GPU.
-
- function markUniformsLightsNeedsUpdate ( uniforms, value ) {
-
- uniforms.ambientLightColor.needsUpdate = value;
-
- uniforms.directionalLightColor.needsUpdate = value;
- uniforms.directionalLightDirection.needsUpdate = value;
-
- uniforms.pointLightColor.needsUpdate = value;
- uniforms.pointLightPosition.needsUpdate = value;
- uniforms.pointLightDistance.needsUpdate = value;
- uniforms.pointLightDecay.needsUpdate = value;
-
- uniforms.spotLightColor.needsUpdate = value;
- uniforms.spotLightPosition.needsUpdate = value;
- uniforms.spotLightDistance.needsUpdate = value;
- uniforms.spotLightDirection.needsUpdate = value;
- uniforms.spotLightAngleCos.needsUpdate = value;
- uniforms.spotLightExponent.needsUpdate = value;
- uniforms.spotLightDecay.needsUpdate = value;
-
- uniforms.hemisphereLightSkyColor.needsUpdate = value;
- uniforms.hemisphereLightGroundColor.needsUpdate = value;
- uniforms.hemisphereLightDirection.needsUpdate = value;
-
- }
-
- function refreshUniformsShadow ( uniforms, lights ) {
-
- if ( uniforms.shadowMatrix ) {
-
- var j = 0;
-
- for ( var i = 0, il = lights.length; i < il; i ++ ) {
-
- var light = lights[ i ];
-
- if ( ! light.castShadow ) continue;
-
- if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) {
-
- uniforms.shadowMap.value[ j ] = light.shadowMap;
- uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
-
- uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
-
- uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
- uniforms.shadowBias.value[ j ] = light.shadowBias;
-
- j ++;
-
- }
-
- }
-
- }
-
- }
-
- // Uniforms (load to GPU)
-
- function loadUniformsMatrices ( uniforms, object ) {
-
- _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements );
-
- if ( uniforms.normalMatrix ) {
-
- _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements );
-
- }
-
- }
-
- function getTextureUnit() {
-
- var textureUnit = _usedTextureUnits;
-
- if ( textureUnit >= _maxTextures ) {
-
- THREE.warn( 'Canvas3DRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures );
-
- }
-
- _usedTextureUnits += 1;
-
- return textureUnit;
-
- }
-
- function loadUniformsGeneric ( uniforms ) {
-
- var texture, textureUnit, offset;
-
- for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) {
-
- var uniform = uniforms[ j ][ 0 ];
-
- // needsUpdate property is not added to all uniforms.
- if ( uniform.needsUpdate === false ) continue;
-
- var type = uniform.type;
- var value = uniform.value;
- var location = uniforms[ j ][ 1 ];
-
- switch ( type ) {
-
- case '1i':
- _gl.uniform1i( location, value );
- break;
-
- case '1f':
- _gl.uniform1f( location, value );
- break;
-
- case '2f':
- _gl.uniform2f( location, value[ 0 ], value[ 1 ] );
- break;
-
- case '3f':
- _gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] );
- break;
-
- case '4f':
- _gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] );
- break;
-
- case '1iv':
- _gl.uniform1iv( location, value );
- break;
-
- case '3iv':
- _gl.uniform3iv( location, value );
- break;
-
- case '1fv':
- _gl.uniform1fv( location, value );
- break;
-
- case '2fv':
- _gl.uniform2fv( location, value );
- break;
-
- case '3fv':
- _gl.uniform3fv( location, value );
- break;
-
- case '4fv':
- _gl.uniform4fv( location, value );
- break;
-
- case 'Matrix3fv':
- _gl.uniformMatrix3fv( location, false, value );
- break;
-
- case 'Matrix4fv':
- _gl.uniformMatrix4fv( location, false, value );
- break;
-
- //
-
- case 'i':
-
- // single integer
- _gl.uniform1i( location, value );
-
- break;
-
- case 'f':
-
- // single float
- _gl.uniform1f( location, value );
-
- break;
-
- case 'v2':
-
- // single THREE.Vector2
- _gl.uniform2f( location, value.x, value.y );
-
- break;
-
- case 'v3':
-
- // single THREE.Vector3
- _gl.uniform3f( location, value.x, value.y, value.z );
-
- break;
-
- case 'v4':
-
- // single THREE.Vector4
- _gl.uniform4f( location, value.x, value.y, value.z, value.w );
-
- break;
-
- case 'c':
-
- // single THREE.Color
- _gl.uniform3f( location, value.r, value.g, value.b );
-
- break;
-
- case 'iv1':
-
- // flat array of integers (JS or typed array)
- _gl.uniform1iv( location, value );
-
- break;
-
- case 'iv':
-
- // flat array of integers with 3 x N size (JS or typed array)
- _gl.uniform3iv( location, value );
-
- break;
-
- case 'fv1':
-
- // flat array of floats (JS or typed array)
- _gl.uniform1fv( location, value );
-
- break;
-
- case 'fv':
-
- // flat array of floats with 3 x N size (JS or typed array)
- _gl.uniform3fv( location, value );
-
- break;
-
- case 'v2v':
-
- // array of THREE.Vector2
-
- if ( uniform._array === undefined ) {
-
- uniform._array = new Float32Array( 2 * value.length );
-
- }
-
- for ( var i = 0, il = value.length; i < il; i ++ ) {
-
- offset = i * 2;
-
- uniform._array[ offset ] = value[ i ].x;
- uniform._array[ offset + 1 ] = value[ i ].y;
-
- }
-
- _gl.uniform2fv( location, uniform._array );
-
- break;
-
- case 'v3v':
-
- // array of THREE.Vector3
-
- if ( uniform._array === undefined ) {
-
- uniform._array = new Float32Array( 3 * value.length );
-
- }
-
- for ( var i = 0, il = value.length; i < il; i ++ ) {
-
- offset = i * 3;
-
- uniform._array[ offset ] = value[ i ].x;
- uniform._array[ offset + 1 ] = value[ i ].y;
- uniform._array[ offset + 2 ] = value[ i ].z;
-
- }
-
- _gl.uniform3fv( location, uniform._array );
-
- break;
-
- case 'v4v':
-
- // array of THREE.Vector4
-
- if ( uniform._array === undefined ) {
-
- uniform._array = new Float32Array( 4 * value.length );
-
- }
-
- for ( var i = 0, il = value.length; i < il; i ++ ) {
-
- offset = i * 4;
-
- uniform._array[ offset ] = value[ i ].x;
- uniform._array[ offset + 1 ] = value[ i ].y;
- uniform._array[ offset + 2 ] = value[ i ].z;
- uniform._array[ offset + 3 ] = value[ i ].w;
-
- }
-
- _gl.uniform4fv( location, uniform._array );
-
- break;
-
- case 'm3':
-
- // single THREE.Matrix3
- _gl.uniformMatrix3fv( location, false, value.elements );
-
- break;
-
- case 'm3v':
-
- // array of THREE.Matrix3
-
- if ( uniform._array === undefined ) {
-
- uniform._array = new Float32Array( 9 * value.length );
-
- }
-
- for ( var i = 0, il = value.length; i < il; i ++ ) {
-
- value[ i ].flattenToArrayOffset( uniform._array, i * 9 );
-
- }
-
- _gl.uniformMatrix3fv( location, false, uniform._array );
-
- break;
-
- case 'm4':
-
- // single THREE.Matrix4
- _gl.uniformMatrix4fv( location, false, value.elements );
-
- break;
-
- case 'm4v':
-
- // array of THREE.Matrix4
-
- if ( uniform._array === undefined ) {
-
- uniform._array = new Float32Array( 16 * value.length );
-
- }
-
- for ( var i = 0, il = value.length; i < il; i ++ ) {
-
- value[ i ].flattenToArrayOffset( uniform._array, i * 16 );
-
- }
-
- _gl.uniformMatrix4fv( location, false, uniform._array );
-
- break;
-
- case 't':
-
- // single THREE.Texture (2d or cube)
-
- texture = value;
- textureUnit = getTextureUnit();
-
- _gl.uniform1i( location, textureUnit );
-
- if ( ! texture ) continue;
-
- if ( texture instanceof THREE.CubeTexture ||
- ( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/
-
- setCubeTexture( texture, textureUnit );
-
- } else if ( texture instanceof THREE.WebGLRenderTargetCube ) {
-
- setCubeTextureDynamic( texture, textureUnit );
-
- } else {
-
- _this.setTexture( texture, textureUnit );
-
- }
-
- break;
-
- case 'tv':
-
- // array of THREE.Texture (2d)
-
- if ( uniform._array === undefined ) {
-
- uniform._array = [];
-
- }
-
- for ( var i = 0, il = uniform.value.length; i < il; i ++ ) {
-
- uniform._array[ i ] = getTextureUnit();
-
- }
-
- _gl.uniform1iv( location, uniform._array );
-
- for ( var i = 0, il = uniform.value.length; i < il; i ++ ) {
-
- texture = uniform.value[ i ];
- textureUnit = uniform._array[ i ];
-
- if ( ! texture ) continue;
-
- _this.setTexture( texture, textureUnit );
-
- }
-
- break;
-
- default:
-
- THREE.warn( 'THREE.Canvas3DRenderer: Unknown uniform type: ' + type );
-
- }
-
- }
-
- }
-
- function setupMatrices ( object, camera ) {
-
- object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
- object._normalMatrix.getNormalMatrix( object._modelViewMatrix );
-
- }
-
- function setColorLinear( array, offset, color, intensity ) {
-
- array[ offset ] = color.r * intensity;
- array[ offset + 1 ] = color.g * intensity;
- array[ offset + 2 ] = color.b * intensity;
-
- }
-
- function setupLights ( lights ) {
-
- var l, ll, light,
- r = 0, g = 0, b = 0,
- color, skyColor, groundColor,
- intensity,
- distance,
-
- zlights = _lights,
-
- dirColors = zlights.directional.colors,
- dirPositions = zlights.directional.positions,
-
- pointColors = zlights.point.colors,
- pointPositions = zlights.point.positions,
- pointDistances = zlights.point.distances,
- pointDecays = zlights.point.decays,
-
- spotColors = zlights.spot.colors,
- spotPositions = zlights.spot.positions,
- spotDistances = zlights.spot.distances,
- spotDirections = zlights.spot.directions,
- spotAnglesCos = zlights.spot.anglesCos,
- spotExponents = zlights.spot.exponents,
- spotDecays = zlights.spot.decays,
-
- hemiSkyColors = zlights.hemi.skyColors,
- hemiGroundColors = zlights.hemi.groundColors,
- hemiPositions = zlights.hemi.positions,
-
- dirLength = 0,
- pointLength = 0,
- spotLength = 0,
- hemiLength = 0,
-
- dirCount = 0,
- pointCount = 0,
- spotCount = 0,
- hemiCount = 0,
-
- dirOffset = 0,
- pointOffset = 0,
- spotOffset = 0,
- hemiOffset = 0;
-
- for ( l = 0, ll = lights.length; l < ll; l ++ ) {
-
- light = lights[ l ];
-
- if ( light.onlyShadow ) continue;
-
- color = light.color;
- intensity = light.intensity;
- distance = light.distance;
-
- if ( light instanceof THREE.AmbientLight ) {
-
- if ( ! light.visible ) continue;
-
- r += color.r;
- g += color.g;
- b += color.b;
-
- } else if ( light instanceof THREE.DirectionalLight ) {
-
- dirCount += 1;
-
- if ( ! light.visible ) continue;
-
- _direction.setFromMatrixPosition( light.matrixWorld );
- _vector3.setFromMatrixPosition( light.target.matrixWorld );
- _direction.sub( _vector3 );
- _direction.normalize();
-
- dirOffset = dirLength * 3;
-
- dirPositions[ dirOffset ] = _direction.x;
- dirPositions[ dirOffset + 1 ] = _direction.y;
- dirPositions[ dirOffset + 2 ] = _direction.z;
-
- setColorLinear( dirColors, dirOffset, color, intensity );
-
- dirLength += 1;
-
- } else if ( light instanceof THREE.PointLight ) {
-
- pointCount += 1;
-
- if ( ! light.visible ) continue;
-
- pointOffset = pointLength * 3;
-
- setColorLinear( pointColors, pointOffset, color, intensity );
-
- _vector3.setFromMatrixPosition( light.matrixWorld );
-
- pointPositions[ pointOffset ] = _vector3.x;
- pointPositions[ pointOffset + 1 ] = _vector3.y;
- pointPositions[ pointOffset + 2 ] = _vector3.z;
-
- // distance is 0 if decay is 0, because there is no attenuation at all.
- pointDistances[ pointLength ] = distance;
- pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay;
-
- pointLength += 1;
-
- } else if ( light instanceof THREE.SpotLight ) {
-
- spotCount += 1;
-
- if ( ! light.visible ) continue;
-
- spotOffset = spotLength * 3;
-
- setColorLinear( spotColors, spotOffset, color, intensity );
-
- _direction.setFromMatrixPosition( light.matrixWorld );
-
- spotPositions[ spotOffset ] = _direction.x;
- spotPositions[ spotOffset + 1 ] = _direction.y;
- spotPositions[ spotOffset + 2 ] = _direction.z;
-
- spotDistances[ spotLength ] = distance;
-
- _vector3.setFromMatrixPosition( light.target.matrixWorld );
- _direction.sub( _vector3 );
- _direction.normalize();
-
- spotDirections[ spotOffset ] = _direction.x;
- spotDirections[ spotOffset + 1 ] = _direction.y;
- spotDirections[ spotOffset + 2 ] = _direction.z;
-
- spotAnglesCos[ spotLength ] = Math.cos( light.angle );
- spotExponents[ spotLength ] = light.exponent;
- spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay;
-
- spotLength += 1;
-
- } else if ( light instanceof THREE.HemisphereLight ) {
-
- hemiCount += 1;
-
- if ( ! light.visible ) continue;
-
- _direction.setFromMatrixPosition( light.matrixWorld );
- _direction.normalize();
-
- hemiOffset = hemiLength * 3;
-
- hemiPositions[ hemiOffset ] = _direction.x;
- hemiPositions[ hemiOffset + 1 ] = _direction.y;
- hemiPositions[ hemiOffset + 2 ] = _direction.z;
-
- skyColor = light.color;
- groundColor = light.groundColor;
-
- setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity );
- setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity );
-
- hemiLength += 1;
-
- }
-
- }
-
- // null eventual remains from removed lights
- // (this is to avoid if in shader)
-
- for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0;
- for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0;
- for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0;
- for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0;
- for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0;
-
- zlights.directional.length = dirLength;
- zlights.point.length = pointLength;
- zlights.spot.length = spotLength;
- zlights.hemi.length = hemiLength;
-
- zlights.ambient[ 0 ] = r;
- zlights.ambient[ 1 ] = g;
- zlights.ambient[ 2 ] = b;
-
- }
-
- // GL state setting
-
- this.setFaceCulling = function ( cullFace, frontFaceDirection ) {
-
- if ( cullFace === THREE.CullFaceNone ) {
-
- _gl.disable( _gl.CULL_FACE );
-
- } else {
-
- if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) {
-
- _gl.frontFace( _gl.CW );
-
- } else {
-
- _gl.frontFace( _gl.CCW );
-
- }
-
- if ( cullFace === THREE.CullFaceBack ) {
-
- _gl.cullFace( _gl.BACK );
-
- } else if ( cullFace === THREE.CullFaceFront ) {
-
- _gl.cullFace( _gl.FRONT );
-
- } else {
-
- _gl.cullFace( _gl.FRONT_AND_BACK );
-
- }
-
- _gl.enable( _gl.CULL_FACE );
-
- }
-
- };
-
- this.setMaterialFaces = function ( material ) {
-
- state.setDoubleSided( material.side === THREE.DoubleSide );
- state.setFlipSided( material.side === THREE.BackSide );
-
- };
-
- // Textures
-
- function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
-
- var extension;
-
- if ( isImagePowerOfTwo ) {
-
- _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
- _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
-
- _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
- _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
-
- } else {
-
- _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
- _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
-
- if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) {
-
- THREE.warn( 'THREE.Canvas3DRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' );
-
- }
-
- _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
- _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
-
- if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) {
-
- THREE.warn( 'THREE.Canvas3DRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' );
-
- }
-
- }
-
- extension = extensions.get( 'EXT_texture_filter_anisotropic' );
-
- if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) {
-
- if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) {
-
- _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) );
- texture.__currentAnisotropy = texture.anisotropy;
-
- }
-
- }
-
- }
-
- this.uploadTexture = function ( texture ) {
-
- if ( texture.__webglInit === undefined ) {
-
- texture.__webglInit = true;
-
- texture.addEventListener( 'dispose', onTextureDispose );
-
- texture.__webglTexture = _gl.createTexture();
-
- _this.info.memory.textures ++;
-
- }
-
- _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
-
- _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
- _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
- _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
-
- texture.image = clampToMaxSize( texture.image, _maxTextureSize );
-
- var image = texture.image,
- isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
- glFormat = paramThreeToGL( texture.format ),
- glType = paramThreeToGL( texture.type );
-
- setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
-
- var mipmap, mipmaps = texture.mipmaps;
-
- if ( texture instanceof THREE.DataTexture ) {
-
- // use manually created mipmaps if available
- // if there are no manual mipmaps
- // set 0 level mipmap and then use GL to generate other mipmap levels
-
- if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
-
- for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
-
- mipmap = mipmaps[ i ];
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
-
- }
-
- texture.generateMipmaps = false;
-
- } else {
-
- _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
-
- }
-
- } else if ( texture instanceof THREE.CompressedTexture ) {
-
- for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
-
- mipmap = mipmaps[ i ];
-
- if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {
-
- if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {
-
- _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
-
- } else {
-
- THREE.warn( "THREE.Canvas3DRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" );
-
- }
-
- } else {
-
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
-
- }
-
- }
-
- } else { // regular Texture (image, video, canvas)
-
- // use manually created mipmaps if available
- // if there are no manual mipmaps
- // set 0 level mipmap and then use GL to generate other mipmap levels
-
- if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
-
- for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
-
- mipmap = mipmaps[ i ];
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
-
- }
-
- texture.generateMipmaps = false;
-
- } else {
-
- _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image.texImage() );
-
- }
-
- }
-
- if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
-
- texture.needsUpdate = false;
-
- if ( texture.onUpdate ) texture.onUpdate();
-
- };
-
- this.setTexture = function ( texture, slot ) {
-
- _gl.activeTexture( _gl.TEXTURE0 + slot );
-
- if ( texture.needsUpdate ) {
-
- _this.uploadTexture( texture );
-
- } else {
-
- _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
-
- }
-
- };
-
- function clampToMaxSize ( image, maxSize ) {
-
- if ( image.width > maxSize || image.height > maxSize ) {
-
- // Warning: Scaling through the canvas will only work with images that use
- // premultiplied alpha.
-
- var scale = maxSize / Math.max( image.width, image.height );
-
- var canvasWidth = Math.floor( image.width * scale );
- var canvasHeight = Math.floor( image.height * scale );
- var canvas = image.resize( canvasWidth, canvasHeight );
-
-
- THREE.warn( 'THREE.Canvas3DRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvasWidth + 'x' + canvasHeight, image );
-
- return canvas;
-
- }
-
- return image;
-
- }
-
- function setCubeTexture ( texture, slot ) {
-
- if ( texture.image.length === 6 ) {
-
- if ( texture.needsUpdate ) {
-
- if ( ! texture.image.__webglTextureCube ) {
-
- texture.addEventListener( 'dispose', onTextureDispose );
-
- texture.image.__webglTextureCube = _gl.createTexture();
-
- _this.info.memory.textures ++;
-
- }
-
- _gl.activeTexture( _gl.TEXTURE0 + slot );
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
-
- _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
-
- var isCompressed = texture instanceof THREE.CompressedTexture;
- var isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture;
-
- var cubeImage = [];
-
- for ( var i = 0; i < 6; i ++ ) {
-
- if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) {
-
- cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
-
- } else {
-
- cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
-
- }
-
- }
-
- var image = cubeImage[ 0 ],
- isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
- glFormat = paramThreeToGL( texture.format ),
- glType = paramThreeToGL( texture.type );
-
- setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
-
- for ( var i = 0; i < 6; i ++ ) {
-
- if ( ! isCompressed ) {
-
- if ( isDataTexture ) {
-
- _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
-
- } else {
-
- _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ].texImage() );
-
- }
-
- } else {
-
- var mipmap, mipmaps = cubeImage[ i ].mipmaps;
-
- for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
-
- mipmap = mipmaps[ j ];
-
- if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {
-
- if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {
-
- _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
-
- } else {
-
- THREE.warn( "THREE.Canvas3DRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" );
-
- }
-
- } else {
-
- _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
-
- }
-
- }
-
- }
-
- }
-
- if ( texture.generateMipmaps && isImagePowerOfTwo ) {
-
- _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
-
- }
-
- texture.needsUpdate = false;
-
- if ( texture.onUpdate ) texture.onUpdate();
-
- } else {
-
- _gl.activeTexture( _gl.TEXTURE0 + slot );
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
-
- }
-
- }
-
- }
-
- function setCubeTextureDynamic ( texture, slot ) {
-
- _gl.activeTexture( _gl.TEXTURE0 + slot );
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
-
- }
-
- // Render targets
-
- function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
-
- _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
- _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
-
- }
-
- function setupRenderBuffer ( renderbuffer, renderTarget ) {
-
- _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
-
- if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
-
- _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
-
- /* For some reason this is not working. Defaulting to RGBA4.
- } else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
-
- _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
- */
- } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
-
- _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
-
- } else {
-
- _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
-
- }
-
- }
-
- this.setRenderTarget = function ( renderTarget ) {
-
- var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
-
- if ( renderTarget && renderTarget.__webglFramebuffer === undefined ) {
-
- if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
- if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
-
- renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
-
- renderTarget.__webglTexture = _gl.createTexture();
-
- _this.info.memory.textures ++;
-
- // Setup texture, create render and frame buffers
-
- var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ),
- glFormat = paramThreeToGL( renderTarget.format ),
- glType = paramThreeToGL( renderTarget.type );
-
- if ( isCube ) {
-
- renderTarget.__webglFramebuffer = [];
- renderTarget.__webglRenderbuffer = [];
-
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
- setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
-
- for ( var i = 0; i < 6; i ++ ) {
-
- renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
- renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
-
- _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
-
- setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
- setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
-
- }
-
- if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
-
- } else {
-
- renderTarget.__webglFramebuffer = _gl.createFramebuffer();
-
- if ( renderTarget.shareDepthFrom ) {
-
- renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
-
- } else {
-
- renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
-
- }
-
- _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
- setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
-
- _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
-
- setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
-
- if ( renderTarget.shareDepthFrom ) {
-
- if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
-
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
-
- } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
-
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
-
- }
-
- } else {
-
- setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
-
- }
-
- if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
-
- }
-
- // Release everything
-
- if ( isCube ) {
-
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
-
- } else {
-
- _gl.bindTexture( _gl.TEXTURE_2D, null );
-
- }
-
- _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
- _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
-
- }
-
- var framebuffer, width, height, vx, vy;
-
- if ( renderTarget ) {
-
- if ( isCube ) {
-
- framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
-
- } else {
-
- framebuffer = renderTarget.__webglFramebuffer;
-
- }
-
- width = renderTarget.width;
- height = renderTarget.height;
-
- vx = 0;
- vy = 0;
-
- } else {
-
- framebuffer = null;
-
- width = _viewportWidth;
- height = _viewportHeight;
-
- vx = _viewportX;
- vy = _viewportY;
-
- }
-
- if ( framebuffer !== _currentFramebuffer ) {
-
- _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
- _gl.viewport( vx, vy, width, height );
-
- _currentFramebuffer = framebuffer;
-
- }
-
- _currentWidth = width;
- _currentHeight = height;
-
- };
-
- this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) {
-
- if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) {
-
- console.error( 'THREE.Canvas3DRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
- return;
-
- }
-
- if ( renderTarget.__webglFramebuffer ) {
-
- if ( renderTarget.format !== THREE.RGBAFormat ) {
-
- console.error( 'THREE.Canvas3DRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' );
- return;
-
- }
-
- var restore = false;
-
- if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) {
-
- _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer );
-
- restore = true;
-
- }
-
- if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {
-
- _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer );
-
- } else {
-
- console.error( 'THREE.Canvas3DRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
-
- }
-
- if ( restore ) {
-
- _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
-
- }
-
- }
-
- };
-
- function updateRenderTargetMipmap ( renderTarget ) {
-
- if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
-
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
- _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
-
- } else {
-
- _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
- _gl.generateMipmap( _gl.TEXTURE_2D );
- _gl.bindTexture( _gl.TEXTURE_2D, null );
-
- }
-
- }
-
- // Fallback filters for non-power-of-2 textures
-
- function filterFallback ( f ) {
-
- if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
-
- return _gl.NEAREST;
-
- }
-
- return _gl.LINEAR;
-
- }
-
- // Map three.js constants to WebGL constants
-
- function paramThreeToGL ( p ) {
-
- var extension;
-
- if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
- if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
- if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
-
- if ( p === THREE.NearestFilter ) return _gl.NEAREST;
- if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
- if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
-
- if ( p === THREE.LinearFilter ) return _gl.LINEAR;
- if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
- if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
-
- if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
- if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
- if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
- if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
-
- if ( p === THREE.ByteType ) return _gl.BYTE;
- if ( p === THREE.ShortType ) return _gl.SHORT;
- if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
- if ( p === THREE.IntType ) return _gl.INT;
- if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
- if ( p === THREE.FloatType ) return _gl.FLOAT;
-
- extension = extensions.get( 'OES_texture_half_float' );
-
- if ( extension !== null ) {
-
- if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES;
-
- }
-
- if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
- if ( p === THREE.RGBFormat ) return _gl.RGB;
- if ( p === THREE.RGBAFormat ) return _gl.RGBA;
- if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
- if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
-
- if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
- if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
- if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
-
- if ( p === THREE.ZeroFactor ) return _gl.ZERO;
- if ( p === THREE.OneFactor ) return _gl.ONE;
- if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
- if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
- if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
- if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
- if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
- if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
-
- if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
- if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
- if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
-
- extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
-
- if ( extension !== null ) {
-
- if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
- if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
- if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
- if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
-
- }
-
- extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
-
- if ( extension !== null ) {
-
- if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
- if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
- if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
- if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
-
- }
-
- extension = extensions.get( 'EXT_blend_minmax' );
-
- if ( extension !== null ) {
-
- if ( p === THREE.MinEquation ) return extension.MIN_EXT;
- if ( p === THREE.MaxEquation ) return extension.MAX_EXT;
-
- }
-
- return 0;
-
- }
-
- // Allocations
-
- function allocateBones ( object ) {
-
- if ( _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture ) {
-
- return 1024;
-
- } else {
-
- // default for when object is not specified
- // ( for example when prebuilding shader
- // to be used with multiple objects )
- //
- // - leave some extra space for other uniforms
- // - limit here is ANGLE's 254 max uniform vectors
- // (up to 54 should be safe)
-
- var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
- var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
-
- var maxBones = nVertexMatrices;
-
- if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
-
- maxBones = Math.min( object.skeleton.bones.length, maxBones );
-
- if ( maxBones < object.skeleton.bones.length ) {
-
- THREE.warn( 'Canvas3DRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' );
-
- }
-
- }
-
- return maxBones;
-
- }
-
- }
-
- function allocateLights( lights ) {
-
- var dirLights = 0;
- var pointLights = 0;
- var spotLights = 0;
- var hemiLights = 0;
-
- for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
-
- var light = lights[ l ];
-
- if ( light.onlyShadow || light.visible === false ) continue;
-
- if ( light instanceof THREE.DirectionalLight ) dirLights ++;
- if ( light instanceof THREE.PointLight ) pointLights ++;
- if ( light instanceof THREE.SpotLight ) spotLights ++;
- if ( light instanceof THREE.HemisphereLight ) hemiLights ++;
-
- }
-
- return { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights };
-
- }
-
- function allocateShadows( lights ) {
-
- var maxShadows = 0;
-
- for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
-
- var light = lights[ l ];
-
- if ( ! light.castShadow ) continue;
-
- if ( light instanceof THREE.SpotLight ) maxShadows ++;
- if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;
-
- }
-
- return maxShadows;
-
- }
-
- // DEPRECATED
-
- this.initMaterial = function () {
-
- THREE.warn( 'THREE.Canvas3DRenderer: .initMaterial() has been removed.' );
-
- };
-
- this.addPrePlugin = function () {
-
- THREE.warn( 'THREE.Canvas3DRenderer: .addPrePlugin() has been removed.' );
-
- };
-
- this.addPostPlugin = function () {
-
- THREE.warn( 'THREE.Canvas3DRenderer: .addPostPlugin() has been removed.' );
-
- };
-
- this.updateShadowMap = function () {
-
- THREE.warn( 'THREE.Canvas3DRenderer: .updateShadowMap() has been removed.' );
-
- };
-
-};
-
// File:src/Three.js
/**
@@ -35300,3 +28872,6476 @@ THREE.MorphBlendMesh.prototype.update = function ( delta ) {
};
+// File:src/qml/QmlImageElement.js
+
+var __texImageToImageMap = {};
+
+function Image () {
+ this.crossOrigin = undefined;
+ this._src = undefined;
+ this._onSuccessCallback = undefined;
+ this._onProgressCallback = undefined;
+ this._onErrorCallback = undefined;
+ this._width = 0;
+ this._height = 0;
+ this._texImage = TextureImageFactory.newTexImage();
+ __texImageToImageMap[""+this._texImage.id()] = this;
+
+ // Setup mapping between the native QObject image and this image
+ var _this = this;
+
+ this._texImage.imageLoaded.connect(function() { _this.notifySuccess(_this) });
+ this._texImage.imageLoadingFailed.connect(function() { _this.notifyError(_this) });
+
+ this.__defineGetter__("src", function(){
+ return _this._src;
+ });
+
+ this.__defineSetter__("src", function(url){
+ if (url && url !== '' && url !== _this._src) {
+ _this._texImage.src = ""+url;
+ _this._texImage.name = ""+url;
+ }
+ _this._src = url;
+ });
+
+ this.__defineGetter__("width", function(){
+ return (_this._texImage !== undefined)?_this._texImage.width:0;
+ });
+
+ this.__defineSetter__("width", function(url){
+ console.log("TODO: Implement image resize");
+ });
+
+ this.__defineGetter__("height", function(){
+ return (_this._texImage !== undefined)?_this._texImage.height:0;
+ });
+
+ this.__defineSetter__("height", function(url){
+ console.log("TODO: Implement image resize");
+ });
+};
+
+Image.prototype = {
+ constructor: Image,
+
+ addEventListener: function( eventName, callback, flag ) {
+ if (eventName === 'load') {
+ this._onSuccessCallback = callback;
+ } else if (eventName === 'progress') {
+ this._onProgressCallback = callback;
+ } else if (eventName === 'error') {
+ this._onErrorCallback = callback;
+ }
+ },
+
+ notifySuccess: function(image) {
+ if (this._onSuccessCallback !== undefined) {
+ this._onSuccessCallback(new Event());
+ }
+ },
+
+ notifyProgress: function(image) {
+ if (this._onProgressCallback !== undefined) {
+ this._onProgressCallback(new Event());
+ }
+ },
+
+ notifyError: function(image) {
+ if (this._onErrorCallback !== undefined) {
+ this._onErrorCallback(new Event());
+ }
+ },
+
+ texImage: function() {
+ return this._texImage;
+ },
+
+ data: function() {
+ console.error("Image.data not implemented!");
+ }
+};
+
+// TODO: Support for resizing:
+//where.image.width = width;
+//where.image.height = height;
+//where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height );
+
+// File:src/qml/QmlHtmlElements.js
+
+// HTML document and Element wrappers/stubs
+
+function document() {
+}
+
+document.createElement = function(type) {
+ if (type === "img") {
+ return new Image();
+ } else if (type === 'div') {
+ return new HtmlDiv();
+ }
+
+ return new HtmlElement();
+}
+
+document.createTextNode = function(value) {
+ return new HtmlElement();
+}
+
+function Event() {
+}
+
+Event.prototype = {
+ constructor: Event
+}
+
+function HtmlStyle() {
+ this.position = undefined;
+ this.right = undefined;
+ this.top = undefined;
+ this.fontSize = undefined;
+ this.textAlign = undefined;
+ this.background = undefined;
+ this.color = undefined;
+ this.width = undefined;
+ this.width = undefined;
+ this.padding = undefined;
+ this.zIndex = undefined;
+}
+
+function HtmlElement() {
+ this.style = new HtmlStyle();
+}
+
+HtmlElement.prototype = {
+ constructor: HtmlElement,
+
+ appendChild: function(child) {
+ }
+}
+
+function HtmlDiv() {
+ this.innerHTML = "";
+ this.style = new HtmlStyle();
+}
+
+
+
+// File:src/qml/Canvas3DRenderer.js
+
+/**
+ * @author supereggbert / http://www.paulbrunt.co.uk/
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ * @author szimek / https://github.com/szimek/
+ * @author pasikeranen / pasi.keranen@theqtcompany.com
+ */
+
+THREE.Canvas3DRenderer = function ( parameters ) {
+
+ console.log( 'THREE.Canvas3DRenderer', THREE.REVISION );
+
+ parameters = parameters || {};
+
+ if (parameters.canvas === undefined) {
+ console.error("parameter.canvas must be set when using THREE.Canvas3DRenderer");
+ return;
+ }
+
+ var _canvas = parameters.canvas,
+ _context = parameters.context !== undefined ? parameters.context : null,
+
+ pixelRatio = 1,
+
+ _precision = parameters.precision !== undefined ? parameters.precision : 'highp',
+
+ _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
+ _depth = parameters.depth !== undefined ? parameters.depth : true,
+ _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
+ _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
+ _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
+ _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
+ _logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false,
+
+ _clearColor = new THREE.Color( 0x000000 ),
+ _clearAlpha = parameters.clearAlpha !== undefined ? parameters.clearAlpha : 0;
+
+ var lights = [];
+
+ var _webglObjects = {};
+ var _webglObjectsImmediate = [];
+
+ var opaqueObjects = [];
+ var transparentObjects = [];
+
+ var sprites = [];
+ var lensFlares = [];
+
+ // public properties
+
+ this.domElement = _canvas;
+ this.context = null;
+ pixelRatio = parameters.devicePixelRatio !== undefined
+ ? parameters.devicePixelRatio
+ : self.pixelRatio !== undefined
+ ? self.pixelRatio
+ : 1;
+
+ // clearing
+
+ this.autoClear = true;
+ this.autoClearColor = true;
+ this.autoClearDepth = true;
+ this.autoClearStencil = true;
+
+ // scene graph
+
+ this.sortObjects = true;
+
+ // physically based shading
+
+ this.gammaFactor = 2.0; // for backwards compatibility
+ this.gammaInput = false;
+ this.gammaOutput = false;
+
+ // shadow map
+
+ this.shadowMapEnabled = false;
+ this.shadowMapType = THREE.PCFShadowMap;
+ this.shadowMapCullFace = THREE.CullFaceFront;
+ this.shadowMapDebug = false;
+ this.shadowMapCascade = false;
+
+ // morphs
+
+ this.maxMorphTargets = 8;
+ this.maxMorphNormals = 4;
+
+ // flags
+
+ this.autoScaleCubemaps = true;
+
+ // info
+
+ this.info = {
+
+ memory: {
+
+ programs: 0,
+ geometries: 0,
+ textures: 0
+
+ },
+
+ render: {
+
+ calls: 0,
+ vertices: 0,
+ faces: 0,
+ points: 0
+
+ }
+
+ };
+
+ // internal properties
+
+ var _this = this,
+
+ _programs = [],
+
+ // internal state cache
+
+ _currentProgram = null,
+ _currentFramebuffer = null,
+ _currentMaterialId = - 1,
+ _currentGeometryProgram = '',
+ _currentCamera = null,
+
+ _usedTextureUnits = 0,
+
+ _viewportX = 0,
+ _viewportY = 0,
+ _viewportWidth = _canvas.width,
+ _viewportHeight = _canvas.height,
+ _currentWidth = 0,
+ _currentHeight = 0,
+
+ // frustum
+
+ _frustum = new THREE.Frustum(),
+
+ // camera matrices cache
+
+ _projScreenMatrix = new THREE.Matrix4(),
+
+ _vector3 = new THREE.Vector3(),
+
+ // light arrays cache
+
+ _direction = new THREE.Vector3(),
+
+ _lightsNeedUpdate = true,
+
+ _lights = {
+
+ ambient: [ 0, 0, 0 ],
+ directional: { length: 0, colors:[], positions: [] },
+ point: { length: 0, colors: [], positions: [], distances: [], decays: [] },
+ spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] },
+ hemi: { length: 0, skyColors: [], groundColors: [], positions: [] }
+
+ };
+
+ // initialize
+
+ var _gl;
+
+ try {
+
+ var attributes = {
+ alpha: _alpha,
+ depth: _depth,
+ stencil: _stencil,
+ antialias: _antialias,
+ premultipliedAlpha: _premultipliedAlpha,
+ preserveDrawingBuffer: _preserveDrawingBuffer
+ };
+
+ _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
+
+ if ( _gl === null ) {
+
+ if ( _canvas.getContext( 'webgl') !== null ) {
+
+ throw 'Error creating WebGL context with your selected attributes.';
+
+ } else {
+
+ throw 'Error creating WebGL context.';
+
+ }
+
+ }
+
+// _canvas.addEventListener( 'webglcontextlost', function ( event ) {
+//
+// event.preventDefault();
+//
+// resetGLState();
+// setDefaultGLState();
+//
+// _webglObjects = {};
+//
+// }, false);
+//
+ } catch ( error ) {
+
+ THREE.error( 'THREE.Canvas3DRenderer: ' + error );
+
+ }
+
+ var state = new THREE.WebGLState( _gl, paramThreeToGL );
+
+ if ( _gl.getShaderPrecisionFormat === undefined ) {
+
+ _gl.getShaderPrecisionFormat = function () {
+
+ return {
+ 'rangeMin': 1,
+ 'rangeMax': 1,
+ 'precision': 1
+ };
+
+ }
+
+ }
+
+ var extensions = new THREE.WebGLExtensions( _gl );
+
+ extensions.get( 'OES_texture_float' );
+ extensions.get( 'OES_texture_float_linear' );
+ extensions.get( 'OES_texture_half_float' );
+ extensions.get( 'OES_texture_half_float_linear' );
+ extensions.get( 'OES_standard_derivatives' );
+
+ if ( _logarithmicDepthBuffer ) {
+
+ extensions.get( 'EXT_frag_depth' );
+
+ }
+
+ //
+
+ var glClearColor = function ( r, g, b, a ) {
+
+ if ( _premultipliedAlpha === true ) {
+
+ r *= a; g *= a; b *= a;
+
+ }
+
+ _gl.clearColor( r, g, b, a );
+
+ };
+
+ var setDefaultGLState = function () {
+
+ _gl.clearColor( 0, 0, 0, 1 );
+ _gl.clearDepth( 1 );
+ _gl.clearStencil( 0 );
+
+ _gl.enable( _gl.DEPTH_TEST );
+ _gl.depthFunc( _gl.LEQUAL );
+
+ _gl.frontFace( _gl.CCW );
+ _gl.cullFace( _gl.BACK );
+ _gl.enable( _gl.CULL_FACE );
+
+ _gl.enable( _gl.BLEND );
+ _gl.blendEquation( _gl.FUNC_ADD );
+ _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
+
+ _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
+
+ glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
+
+ };
+
+ var resetGLState = function () {
+
+ _currentProgram = null;
+ _currentCamera = null;
+
+ _currentGeometryProgram = '';
+ _currentMaterialId = - 1;
+
+ _lightsNeedUpdate = true;
+
+ state.reset();
+
+ };
+
+ setDefaultGLState();
+
+ this.context = _gl;
+ this.state = state;
+
+ // GPU capabilities
+
+ var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
+ var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
+ var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
+ var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
+
+ var _supportsVertexTextures = _maxVertexTextures > 0;
+ var _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' );
+
+ //
+
+ var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
+ var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
+
+ var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
+ var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
+
+ var getCompressedTextureFormats = ( function () {
+
+ var array;
+
+ return function () {
+
+ if ( array !== undefined ) {
+
+ return array;
+
+ }
+
+ array = [];
+
+ if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) {
+
+ var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS );
+
+ for ( var i = 0; i < formats.length; i ++ ) {
+
+ array.push( formats[ i ] );
+
+ }
+
+ }
+
+ return array;
+
+ };
+
+ } )();
+
+ // clamp precision to maximum available
+
+ var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
+ var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
+
+ if ( _precision === 'highp' && ! highpAvailable ) {
+
+ if ( mediumpAvailable ) {
+
+ _precision = 'mediump';
+ THREE.warn( 'THREE.Canvas3DRenderer: highp not supported, using mediump.' );
+
+ } else {
+
+ _precision = 'lowp';
+ THREE.warn( 'THREE.Canvas3DRenderer: highp and mediump not supported, using lowp.' );
+
+ }
+
+ }
+
+ if ( _precision === 'mediump' && ! mediumpAvailable ) {
+
+ _precision = 'lowp';
+ THREE.warn( 'THREE.Canvas3DRenderer: mediump not supported, using lowp.' );
+
+ }
+
+ // Plugins
+
+ var shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate );
+
+ var spritePlugin = new THREE.SpritePlugin( this, sprites );
+ var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares );
+
+ // API
+
+ this.getContext = function () {
+
+ return _gl;
+
+ };
+
+ this.forceContextLoss = function () {
+
+ //extensions.get( 'WEBGL_lose_context' ).loseContext();
+
+ };
+
+ this.supportsVertexTextures = function () {
+
+ return _supportsVertexTextures;
+
+ };
+
+ this.supportsFloatTextures = function () {
+
+ return extensions.get( 'OES_texture_float' );
+
+ };
+
+ this.supportsHalfFloatTextures = function () {
+
+ return extensions.get( 'OES_texture_half_float' );
+
+ };
+
+ this.supportsStandardDerivatives = function () {
+
+ return extensions.get( 'OES_standard_derivatives' );
+
+ };
+
+ this.supportsCompressedTextureS3TC = function () {
+
+ return extensions.get( 'WEBGL_compressed_texture_s3tc' );
+
+ };
+
+ this.supportsCompressedTexturePVRTC = function () {
+
+ return extensions.get( 'WEBGL_compressed_texture_pvrtc' );
+
+ };
+
+ this.supportsBlendMinMax = function () {
+
+ return extensions.get( 'EXT_blend_minmax' );
+
+ };
+
+ this.getMaxAnisotropy = ( function () {
+
+ var value;
+
+ return function () {
+
+ if ( value !== undefined ) {
+
+ return value;
+
+ }
+
+ var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
+
+ value = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
+
+ return value;
+
+ }
+
+ } )();
+
+ this.getPrecision = function () {
+
+ return _precision;
+
+ };
+
+ this.getPixelRatio = function () {
+
+ return pixelRatio;
+
+ };
+
+ this.setPixelRatio = function ( value ) {
+
+ pixelRatio = value;
+
+ };
+
+ this.setSize = function ( width, height, updateStyle ) {
+
+ _canvas.pixelSize = Qt.size(width * pixelRatio, height * pixelRatio)
+
+ if ( updateStyle !== false ) {
+
+// Update styles is ignored in Canvas3D
+// _canvas.style.width = width + 'px';
+// _canvas.style.height = height + 'px';
+
+ }
+
+ this.setViewport( 0, 0, width, height );
+
+ };
+
+ this.setViewport = function ( x, y, width, height ) {
+
+ _viewportX = x * pixelRatio;
+ _viewportY = y * pixelRatio;
+
+ _viewportWidth = width * pixelRatio;
+ _viewportHeight = height * pixelRatio;
+
+ _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
+
+ };
+
+ this.setScissor = function ( x, y, width, height ) {
+
+ _gl.scissor(
+ x * pixelRatio,
+ y * pixelRatio,
+ width * pixelRatio,
+ height * pixelRatio
+ );
+
+ };
+
+ this.enableScissorTest = function ( enable ) {
+
+ if (enable)
+ _gl.enable( _gl.SCISSOR_TEST )
+ else
+ _gl.disable( _gl.SCISSOR_TEST );
+
+ };
+
+ // Clearing
+
+ this.getClearColor = function () {
+
+ return _clearColor;
+
+ };
+
+ this.setClearColor = function ( color, alpha ) {
+
+ _clearColor.set( color );
+
+ _clearAlpha = alpha !== undefined ? alpha : 1;
+
+ glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
+
+ };
+
+ this.getClearAlpha = function () {
+
+ return _clearAlpha;
+
+ };
+
+ this.setClearAlpha = function ( alpha ) {
+
+ _clearAlpha = alpha;
+
+ glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
+
+ };
+
+ this.clear = function ( color, depth, stencil ) {
+
+ var bits = 0;
+
+ if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
+ if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
+ if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
+
+ _gl.clear( bits );
+
+ };
+
+ this.clearColor = function () {
+
+ _gl.clear( _gl.COLOR_BUFFER_BIT );
+
+ };
+
+ this.clearDepth = function () {
+
+ _gl.clear( _gl.DEPTH_BUFFER_BIT );
+
+ };
+
+ this.clearStencil = function () {
+
+ _gl.clear( _gl.STENCIL_BUFFER_BIT );
+
+ };
+
+ this.clearTarget = function ( renderTarget, color, depth, stencil ) {
+
+ this.setRenderTarget( renderTarget );
+ this.clear( color, depth, stencil );
+
+ };
+
+ // Reset
+
+ this.resetGLState = resetGLState;
+
+ // Buffer allocation
+
+ function createParticleBuffers ( geometry ) {
+
+ geometry.__webglVertexBuffer = _gl.createBuffer();
+ geometry.__webglVertexBuffer.name = "Particle__webglVertexBuffer";
+ geometry.__webglColorBuffer = _gl.createBuffer();
+ geometry.__webglColorBuffer.name = "Particle__webglColorBuffer";
+
+ _this.info.memory.geometries ++;
+
+ };
+
+ function createLineBuffers ( geometry ) {
+
+ geometry.__webglVertexBuffer = _gl.createBuffer();
+ geometry.__webglColorBuffer = _gl.createBuffer();
+ geometry.__webglLineDistanceBuffer = _gl.createBuffer();
+ geometry.__webglVertexBuffer.name = "Line__webglVertexBuffer";
+ geometry.__webglColorBuffer.name = "Line__webglColorBuffer";
+ geometry.__webglLineDistanceBuffer.name = "Line__webglLineDistanceBuffer";
+
+ _this.info.memory.geometries ++;
+
+ };
+
+ function createMeshBuffers ( geometryGroup ) {
+
+ geometryGroup.__webglVertexBuffer = _gl.createBuffer();
+ geometryGroup.__webglNormalBuffer = _gl.createBuffer();
+ geometryGroup.__webglTangentBuffer = _gl.createBuffer();
+ geometryGroup.__webglColorBuffer = _gl.createBuffer();
+ geometryGroup.__webglUVBuffer = _gl.createBuffer();
+ geometryGroup.__webglUV2Buffer = _gl.createBuffer();
+ geometryGroup.__webglVertexBuffer.name = "Mesh__webglVertexBuffer";
+ geometryGroup.__webglNormalBuffer.name = "Mesh__webglNormalBuffer";
+ geometryGroup.__webglTangentBuffer.name = "Mesh__webglTangentBuffer";
+ geometryGroup.__webglColorBuffer.name = "Mesh__webglColorBuffer";
+ geometryGroup.__webglUVBuffer.name = "Mesh__webglUVBuffer";
+ geometryGroup.__webglUV2Buffer.name = "Mesh__webglUV2Buffer";
+
+ geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer();
+ geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer();
+ geometryGroup.__webglSkinIndicesBuffer.name = "Mesh__webglSkinIndicesBuffer";
+ geometryGroup.__webglSkinWeightsBuffer.name = "Mesh__webglSkinWeightsBuffer";
+
+ geometryGroup.__webglFaceBuffer = _gl.createBuffer();
+ geometryGroup.__webglLineBuffer = _gl.createBuffer();
+ geometryGroup.__webglFaceBuffer.name = "Mesh__webglFaceBuffer";
+ geometryGroup.__webglLineBuffer.name = "Mesh__webglLineBuffer";
+
+ var m, ml;
+ var numMorphTargets = geometryGroup.numMorphTargets;
+
+ if ( numMorphTargets ) {
+
+ geometryGroup.__webglMorphTargetsBuffers = [];
+
+ for ( m = 0, ml = numMorphTargets; m < ml; m ++ ) {
+ var buf = _gl.createBuffer();
+ buf.name = "Mesh__MorphTarget_"+m;
+ geometryGroup.__webglMorphTargetsBuffers.push(buf);
+
+ }
+
+ }
+
+ var numMorphNormals = geometryGroup.numMorphNormals;
+
+ if ( numMorphNormals ) {
+
+ geometryGroup.__webglMorphNormalsBuffers = [];
+
+ for ( m = 0, ml = numMorphNormals; m < ml; m ++ ) {
+ var nbuf = _gl.createBuffer();
+ nbuf.name = "Mesh__MorphNormal_"+m;
+ geometryGroup.__webglMorphNormalsBuffers.push( nbuf );
+
+ }
+
+ }
+
+ _this.info.memory.geometries ++;
+
+ };
+
+ // Events
+
+ var onObjectRemoved = function ( event ) {
+
+ var object = event.target;
+
+ object.traverse( function ( child ) {
+
+ child.removeEventListener( 'remove', onObjectRemoved );
+
+ removeObject( child );
+
+ } );
+
+ };
+
+ var onGeometryDispose = function ( event ) {
+
+ var geometry = event.target;
+
+ geometry.removeEventListener( 'dispose', onGeometryDispose );
+
+ deallocateGeometry( geometry );
+
+ };
+
+ var onTextureDispose = function ( event ) {
+
+ var texture = event.target;
+
+ texture.removeEventListener( 'dispose', onTextureDispose );
+
+ deallocateTexture( texture );
+
+ _this.info.memory.textures --;
+
+
+ };
+
+ var onRenderTargetDispose = function ( event ) {
+
+ var renderTarget = event.target;
+
+ renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
+
+ deallocateRenderTarget( renderTarget );
+
+ _this.info.memory.textures --;
+
+ };
+
+ var onMaterialDispose = function ( event ) {
+
+ var material = event.target;
+
+ material.removeEventListener( 'dispose', onMaterialDispose );
+
+ deallocateMaterial( material );
+
+ };
+
+ // Buffer deallocation
+
+ var deleteBuffers = function ( geometry ) {
+
+ var buffers = [
+ '__webglVertexBuffer',
+ '__webglNormalBuffer',
+ '__webglTangentBuffer',
+ '__webglColorBuffer',
+ '__webglUVBuffer',
+ '__webglUV2Buffer',
+
+ '__webglSkinIndicesBuffer',
+ '__webglSkinWeightsBuffer',
+
+ '__webglFaceBuffer',
+ '__webglLineBuffer',
+
+ '__webglLineDistanceBuffer'
+ ];
+
+ for ( var i = 0, l = buffers.length; i < l; i ++ ) {
+
+ var name = buffers[ i ];
+
+ if ( geometry[ name ] !== undefined ) {
+
+ _gl.deleteBuffer( geometry[ name ] );
+
+ delete geometry[ name ];
+
+ }
+
+ }
+
+ // custom attributes
+
+ if ( geometry.__webglCustomAttributesList !== undefined ) {
+
+ for ( var name in geometry.__webglCustomAttributesList ) {
+
+ _gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer );
+
+ }
+
+ delete geometry.__webglCustomAttributesList;
+
+ }
+
+ _this.info.memory.geometries --;
+
+ };
+
+ var deallocateGeometry = function ( geometry ) {
+
+ delete geometry.__webglInit;
+
+ if ( geometry instanceof THREE.BufferGeometry ) {
+
+ for ( var name in geometry.attributes ) {
+
+ var attribute = geometry.attributes[ name ];
+
+ if ( attribute.buffer !== undefined ) {
+
+ _gl.deleteBuffer( attribute.buffer );
+
+ delete attribute.buffer;
+
+ }
+
+ }
+
+ _this.info.memory.geometries --;
+
+ } else {
+
+ var geometryGroupsList = geometryGroups[ geometry.id ];
+
+ if ( geometryGroupsList !== undefined ) {
+
+ for ( var i = 0, l = geometryGroupsList.length; i < l; i ++ ) {
+
+ var geometryGroup = geometryGroupsList[ i ];
+
+ if ( geometryGroup.numMorphTargets !== undefined ) {
+
+ for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
+
+ _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );
+
+ }
+
+ delete geometryGroup.__webglMorphTargetsBuffers;
+
+ }
+
+ if ( geometryGroup.numMorphNormals !== undefined ) {
+
+ for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
+
+ _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );
+
+ }
+
+ delete geometryGroup.__webglMorphNormalsBuffers;
+
+ }
+
+ deleteBuffers( geometryGroup );
+
+ }
+
+ delete geometryGroups[ geometry.id ];
+
+ } else {
+
+ deleteBuffers( geometry );
+
+ }
+
+ }
+
+ // TOFIX: Workaround for deleted geometry being currently bound
+
+ _currentGeometryProgram = '';
+
+ };
+
+ var deallocateTexture = function ( texture ) {
+
+ if ( texture.image && texture.image.__webglTextureCube ) {
+
+ // cube texture
+
+ _gl.deleteTexture( texture.image.__webglTextureCube );
+
+ delete texture.image.__webglTextureCube;
+
+ } else {
+
+ // 2D texture
+
+ if ( texture.__webglInit === undefined ) return;
+
+ _gl.deleteTexture( texture.__webglTexture );
+
+ delete texture.__webglTexture;
+ delete texture.__webglInit;
+
+ }
+
+ };
+
+ var deallocateRenderTarget = function ( renderTarget ) {
+
+ if ( ! renderTarget || renderTarget.__webglTexture === undefined ) return;
+
+ _gl.deleteTexture( renderTarget.__webglTexture );
+
+ delete renderTarget.__webglTexture;
+
+ if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
+
+ for ( var i = 0; i < 6; i ++ ) {
+
+ _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );
+ _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );
+
+ }
+
+ } else {
+
+ _gl.deleteFramebuffer( renderTarget.__webglFramebuffer );
+ _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer );
+
+ }
+
+ delete renderTarget.__webglFramebuffer;
+ delete renderTarget.__webglRenderbuffer;
+
+ };
+
+ var deallocateMaterial = function ( material ) {
+
+ var program = material.program.program;
+
+ if ( program === undefined ) return;
+
+ material.program = undefined;
+
+ // only deallocate GL program if this was the last use of shared program
+ // assumed there is only single copy of any program in the _programs list
+ // (that's how it's constructed)
+
+ var i, il, programInfo;
+ var deleteProgram = false;
+
+ for ( i = 0, il = _programs.length; i < il; i ++ ) {
+
+ programInfo = _programs[ i ];
+
+ if ( programInfo.program === program ) {
+
+ programInfo.usedTimes --;
+
+ if ( programInfo.usedTimes === 0 ) {
+
+ deleteProgram = true;
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ if ( deleteProgram === true ) {
+
+ // avoid using array.splice, this is costlier than creating new array from scratch
+
+ var newPrograms = [];
+
+ for ( i = 0, il = _programs.length; i < il; i ++ ) {
+
+ programInfo = _programs[ i ];
+
+ if ( programInfo.program !== program ) {
+
+ newPrograms.push( programInfo );
+
+ }
+
+ }
+
+ _programs = newPrograms;
+
+ _gl.deleteProgram( program );
+
+ _this.info.memory.programs --;
+
+ }
+
+ };
+
+ // Buffer initialization
+
+ function initCustomAttributes ( object ) {
+
+ var geometry = object.geometry;
+ var material = object.material;
+
+ var nvertices = geometry.vertices.length;
+
+ if ( material.attributes ) {
+
+ if ( geometry.__webglCustomAttributesList === undefined ) {
+
+ geometry.__webglCustomAttributesList = [];
+
+ }
+
+ for ( var name in material.attributes ) {
+
+ var attribute = material.attributes[ name ];
+
+ if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) {
+
+ attribute.__webglInitialized = true;
+
+ var size = 1; // "f" and "i"
+
+ if ( attribute.type === 'v2' ) size = 2;
+ else if ( attribute.type === 'v3' ) size = 3;
+ else if ( attribute.type === 'v4' ) size = 4;
+ else if ( attribute.type === 'c' ) size = 3;
+
+ attribute.size = size;
+
+ attribute.array = new Float32Array( nvertices * size );
+ attribute.array.name = ""+attribute+"attribute.array";
+
+ attribute.buffer = _gl.createBuffer();
+ attribute.buffer.belongsToAttribute = name;
+
+ attribute.needsUpdate = true;
+
+ }
+
+ geometry.__webglCustomAttributesList.push( attribute );
+
+ }
+
+ }
+
+ };
+
+ function initParticleBuffers ( geometry, object ) {
+
+ var nvertices = geometry.vertices.length;
+
+ geometry.__vertexArray = new Float32Array( nvertices * 3 );
+ geometry.__colorArray = new Float32Array( nvertices * 3 );
+ geometry.__vertexArray.name = "geometry.__vertexArray";
+ geometry.__colorArray.name = "geometry.__colorArray";
+
+ geometry.__webglParticleCount = nvertices;
+
+ initCustomAttributes( object );
+
+ };
+
+ function initLineBuffers ( geometry, object ) {
+
+ var nvertices = geometry.vertices.length;
+
+ geometry.__vertexArray = new Float32Array( nvertices * 3 );
+ geometry.__colorArray = new Float32Array( nvertices * 3 );
+ geometry.__lineDistanceArray = new Float32Array( nvertices * 1 );
+ geometry.__vertexArray.name = "geometry.__vertexArray";
+ geometry.__colorArray.name = "geometry.__colorArray";
+ geometry.__lineDistanceArray.name = "geometry.__lineDistanceArray";
+
+ geometry.__webglLineCount = nvertices;
+
+ initCustomAttributes( object );
+
+ };
+
+ function initMeshBuffers ( geometryGroup, object ) {
+
+ var geometry = object.geometry,
+ faces3 = geometryGroup.faces3,
+
+ nvertices = faces3.length * 3,
+ ntris = faces3.length * 1,
+ nlines = faces3.length * 3,
+
+ material = getBufferMaterial( object, geometryGroup );
+
+ geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
+ geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
+ geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
+ geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
+ geometryGroup.__vertexArray.name = "geometryGroup.__vertexArray";
+ geometryGroup.__normalArray.name = "geometryGroup.__normalArray";
+ geometryGroup.__colorArray.name = "geometryGroup.__colorArray";
+ geometryGroup.__uvArray.name = "geometryGroup.__uvArray";
+
+ if ( geometry.faceVertexUvs.length > 1 ) {
+
+ geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
+ geometryGroup.__uv2Array.name = "geometryGroup.__uv2Array";
+
+ }
+
+ if ( geometry.hasTangents ) {
+
+ geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );
+ geometryGroup.__tangentArray.name = "geometryGroup.__tangentArray";
+
+ }
+
+ if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {
+
+ geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
+ geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );
+ geometryGroup.__skinIndexArray.name = "geometryGroup.__skinIndexArray";
+ geometryGroup.__skinWeightArray.name = "geometryGroup.__skinWeightArray";
+ }
+
+ var UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3
+
+ geometryGroup.__typeArray = UintArray;
+ geometryGroup.__faceArray = new UintArray( ntris * 3 );
+ geometryGroup.__lineArray = new UintArray( nlines * 2 );
+ geometryGroup.__faceArray.name = "geometryGroup.__faceArray";
+ geometryGroup.__lineArray.name = "geometryGroup.__lineArray";
+
+ var m, ml;
+ var numMorphTargets = geometryGroup.numMorphTargets;
+
+ if ( numMorphTargets ) {
+
+ geometryGroup.__morphTargetsArrays = [];
+
+ for ( m = 0, ml = numMorphTargets; m < ml; m ++ ) {
+ var mta = new Float32Array( nvertices * 3 );
+ mta.name = "morphTargetArray_"+m;
+ geometryGroup.__morphTargetsArrays.push(mta);
+ }
+
+ }
+
+ var numMorphNormals = geometryGroup.numMorphNormals;
+
+ if ( numMorphNormals ) {
+
+ geometryGroup.__morphNormalsArrays = [];
+
+ for ( m = 0, ml = numMorphNormals; m < ml; m ++ ) {
+ var mna = new Float32Array( nvertices * 3 );
+ mna.name = "morphNormalsArray_"+m;
+ geometryGroup.__morphNormalsArrays.push( mna );
+ }
+
+ }
+
+ geometryGroup.__webglFaceCount = ntris * 3;
+ geometryGroup.__webglLineCount = nlines * 2;
+
+
+ // custom attributes
+
+ if ( material.attributes ) {
+
+ if ( geometryGroup.__webglCustomAttributesList === undefined ) {
+
+ geometryGroup.__webglCustomAttributesList = [];
+
+ }
+
+ for ( var name in material.attributes ) {
+
+ // Do a shallow copy of the attribute object so different geometryGroup chunks use different
+ // attribute buffers which are correctly indexed in the setMeshBuffers function
+
+ var originalAttribute = material.attributes[ name ];
+
+ var attribute = {};
+
+ for ( var property in originalAttribute ) {
+
+ attribute[ property ] = originalAttribute[ property ];
+
+ }
+
+ if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) {
+
+ attribute.__webglInitialized = true;
+
+ var size = 1; // "f" and "i"
+
+ if ( attribute.type === 'v2' ) size = 2;
+ else if ( attribute.type === 'v3' ) size = 3;
+ else if ( attribute.type === 'v4' ) size = 4;
+ else if ( attribute.type === 'c' ) size = 3;
+
+ attribute.size = size;
+
+ attribute.array = new Float32Array( nvertices * size );
+
+ attribute.buffer = _gl.createBuffer();
+ attribute.buffer.belongsToAttribute = name;
+
+ originalAttribute.needsUpdate = true;
+ attribute.__original = originalAttribute;
+
+ }
+
+ geometryGroup.__webglCustomAttributesList.push( attribute );
+
+ }
+
+ }
+
+ geometryGroup.__inittedArrays = true;
+
+ };
+
+ function getBufferMaterial( object, geometryGroup ) {
+
+ return object.material instanceof THREE.MeshFaceMaterial
+ ? object.material.materials[ geometryGroup.materialIndex ]
+ : object.material;
+
+ }
+
+ function materialNeedsFaceNormals ( material ) {
+
+ return material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading;
+
+ }
+
+ // Buffer setting
+
+ function setParticleBuffers ( geometry, hint, object ) {
+
+ var v, c, vertex, offset, color,
+
+ vertices = geometry.vertices,
+ vl = vertices.length,
+
+ colors = geometry.colors,
+ cl = colors.length,
+
+ vertexArray = geometry.__vertexArray,
+ colorArray = geometry.__colorArray,
+
+ dirtyVertices = geometry.verticesNeedUpdate,
+ dirtyColors = geometry.colorsNeedUpdate,
+
+ customAttributes = geometry.__webglCustomAttributesList,
+ i, il,
+ ca, cal, value,
+ customAttribute;
+
+ if ( dirtyVertices ) {
+
+ for ( v = 0; v < vl; v ++ ) {
+
+ vertex = vertices[ v ];
+
+ offset = v * 3;
+
+ vertexArray[ offset ] = vertex.x;
+ vertexArray[ offset + 1 ] = vertex.y;
+ vertexArray[ offset + 2 ] = vertex.z;
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
+
+ }
+
+ if ( dirtyColors ) {
+
+ for ( c = 0; c < cl; c ++ ) {
+
+ color = colors[ c ];
+
+ offset = c * 3;
+
+ colorArray[ offset ] = color.r;
+ colorArray[ offset + 1 ] = color.g;
+ colorArray[ offset + 2 ] = color.b;
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
+
+ }
+
+ if ( customAttributes ) {
+
+ for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
+
+ customAttribute = customAttributes[ i ];
+
+ if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) {
+
+ cal = customAttribute.value.length;
+
+ offset = 0;
+
+ if ( customAttribute.size === 1 ) {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ customAttribute.array[ ca ] = customAttribute.value[ ca ];
+
+ }
+
+ } else if ( customAttribute.size === 2 ) {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ value = customAttribute.value[ ca ];
+
+ customAttribute.array[ offset ] = value.x;
+ customAttribute.array[ offset + 1 ] = value.y;
+
+ offset += 2;
+
+ }
+
+ } else if ( customAttribute.size === 3 ) {
+
+ if ( customAttribute.type === 'c' ) {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ value = customAttribute.value[ ca ];
+
+ customAttribute.array[ offset ] = value.r;
+ customAttribute.array[ offset + 1 ] = value.g;
+ customAttribute.array[ offset + 2 ] = value.b;
+
+ offset += 3;
+
+ }
+
+ } else {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ value = customAttribute.value[ ca ];
+
+ customAttribute.array[ offset ] = value.x;
+ customAttribute.array[ offset + 1 ] = value.y;
+ customAttribute.array[ offset + 2 ] = value.z;
+
+ offset += 3;
+
+ }
+
+ }
+
+ } else if ( customAttribute.size === 4 ) {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ value = customAttribute.value[ ca ];
+
+ customAttribute.array[ offset ] = value.x;
+ customAttribute.array[ offset + 1 ] = value.y;
+ customAttribute.array[ offset + 2 ] = value.z;
+ customAttribute.array[ offset + 3 ] = value.w;
+
+ offset += 4;
+
+ }
+
+ }
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
+
+ customAttribute.needsUpdate = false;
+
+ }
+
+ }
+
+ }
+
+ function setLineBuffers ( geometry, hint ) {
+
+ var v, c, d, vertex, offset, color,
+
+ vertices = geometry.vertices,
+ colors = geometry.colors,
+ lineDistances = geometry.lineDistances,
+
+ vl = vertices.length,
+ cl = colors.length,
+ dl = lineDistances.length,
+
+ vertexArray = geometry.__vertexArray,
+ colorArray = geometry.__colorArray,
+ lineDistanceArray = geometry.__lineDistanceArray,
+
+ dirtyVertices = geometry.verticesNeedUpdate,
+ dirtyColors = geometry.colorsNeedUpdate,
+ dirtyLineDistances = geometry.lineDistancesNeedUpdate,
+
+ customAttributes = geometry.__webglCustomAttributesList,
+
+ i, il,
+ ca, cal, value,
+ customAttribute;
+
+ if ( dirtyVertices ) {
+
+ for ( v = 0; v < vl; v ++ ) {
+
+ vertex = vertices[ v ];
+
+ offset = v * 3;
+
+ vertexArray[ offset ] = vertex.x;
+ vertexArray[ offset + 1 ] = vertex.y;
+ vertexArray[ offset + 2 ] = vertex.z;
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
+
+ }
+
+ if ( dirtyColors ) {
+
+ for ( c = 0; c < cl; c ++ ) {
+
+ color = colors[ c ];
+
+ offset = c * 3;
+
+ colorArray[ offset ] = color.r;
+ colorArray[ offset + 1 ] = color.g;
+ colorArray[ offset + 2 ] = color.b;
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
+
+ }
+
+ if ( dirtyLineDistances ) {
+
+ for ( d = 0; d < dl; d ++ ) {
+
+ lineDistanceArray[ d ] = lineDistances[ d ];
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint );
+
+ }
+
+ if ( customAttributes ) {
+
+ for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
+
+ customAttribute = customAttributes[ i ];
+
+ if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) {
+
+ offset = 0;
+
+ cal = customAttribute.value.length;
+
+ if ( customAttribute.size === 1 ) {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ customAttribute.array[ ca ] = customAttribute.value[ ca ];
+
+ }
+
+ } else if ( customAttribute.size === 2 ) {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ value = customAttribute.value[ ca ];
+
+ customAttribute.array[ offset ] = value.x;
+ customAttribute.array[ offset + 1 ] = value.y;
+
+ offset += 2;
+
+ }
+
+ } else if ( customAttribute.size === 3 ) {
+
+ if ( customAttribute.type === 'c' ) {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ value = customAttribute.value[ ca ];
+
+ customAttribute.array[ offset ] = value.r;
+ customAttribute.array[ offset + 1 ] = value.g;
+ customAttribute.array[ offset + 2 ] = value.b;
+
+ offset += 3;
+
+ }
+
+ } else {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ value = customAttribute.value[ ca ];
+
+ customAttribute.array[ offset ] = value.x;
+ customAttribute.array[ offset + 1 ] = value.y;
+ customAttribute.array[ offset + 2 ] = value.z;
+
+ offset += 3;
+
+ }
+
+ }
+
+ } else if ( customAttribute.size === 4 ) {
+
+ for ( ca = 0; ca < cal; ca ++ ) {
+
+ value = customAttribute.value[ ca ];
+
+ customAttribute.array[ offset ] = value.x;
+ customAttribute.array[ offset + 1 ] = value.y;
+ customAttribute.array[ offset + 2 ] = value.z;
+ customAttribute.array[ offset + 3 ] = value.w;
+
+ offset += 4;
+
+ }
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
+
+ customAttribute.needsUpdate = false;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ function setMeshBuffers( geometryGroup, object, hint, dispose, material ) {
+
+ if ( ! geometryGroup.__inittedArrays ) {
+
+ return;
+
+ }
+
+ var needsFaceNormals = materialNeedsFaceNormals( material );
+
+ var f, fl, fi, face,
+ vertexNormals, faceNormal,
+ vertexColors, faceColor,
+ vertexTangents,
+ uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3,
+ c1, c2, c3,
+ sw1, sw2, sw3,
+ si1, si2, si3,
+ i, il,
+ vn, uvi, uv2i,
+ vk, vkl, vka,
+ nka, chf, faceVertexNormals,
+
+ vertexIndex = 0,
+
+ offset = 0,
+ offset_uv = 0,
+ offset_uv2 = 0,
+ offset_face = 0,
+ offset_normal = 0,
+ offset_tangent = 0,
+ offset_line = 0,
+ offset_color = 0,
+ offset_skin = 0,
+ offset_morphTarget = 0,
+ offset_custom = 0,
+
+ value,
+
+ vertexArray = geometryGroup.__vertexArray,
+ uvArray = geometryGroup.__uvArray,
+ uv2Array = geometryGroup.__uv2Array,
+ normalArray = geometryGroup.__normalArray,
+ tangentArray = geometryGroup.__tangentArray,
+ colorArray = geometryGroup.__colorArray,
+
+ skinIndexArray = geometryGroup.__skinIndexArray,
+ skinWeightArray = geometryGroup.__skinWeightArray,
+
+ morphTargetsArrays = geometryGroup.__morphTargetsArrays,
+ morphNormalsArrays = geometryGroup.__morphNormalsArrays,
+
+ customAttributes = geometryGroup.__webglCustomAttributesList,
+ customAttribute,
+
+ faceArray = geometryGroup.__faceArray,
+ lineArray = geometryGroup.__lineArray,
+
+ geometry = object.geometry, // this is shared for all chunks
+
+ dirtyVertices = geometry.verticesNeedUpdate,
+ dirtyElements = geometry.elementsNeedUpdate,
+ dirtyUvs = geometry.uvsNeedUpdate,
+ dirtyNormals = geometry.normalsNeedUpdate,
+ dirtyTangents = geometry.tangentsNeedUpdate,
+ dirtyColors = geometry.colorsNeedUpdate,
+ dirtyMorphTargets = geometry.morphTargetsNeedUpdate,
+
+ vertices = geometry.vertices,
+ chunk_faces3 = geometryGroup.faces3,
+ obj_faces = geometry.faces,
+
+ obj_uvs = geometry.faceVertexUvs[ 0 ],
+ obj_uvs2 = geometry.faceVertexUvs[ 1 ],
+
+ obj_skinIndices = geometry.skinIndices,
+ obj_skinWeights = geometry.skinWeights,
+
+ morphTargets = geometry.morphTargets,
+ morphNormals = geometry.morphNormals;
+
+ if ( dirtyVertices ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ v1 = vertices[ face.a ];
+ v2 = vertices[ face.b ];
+ v3 = vertices[ face.c ];
+
+ vertexArray[ offset ] = v1.x;
+ vertexArray[ offset + 1 ] = v1.y;
+ vertexArray[ offset + 2 ] = v1.z;
+
+ vertexArray[ offset + 3 ] = v2.x;
+ vertexArray[ offset + 4 ] = v2.y;
+ vertexArray[ offset + 5 ] = v2.z;
+
+ vertexArray[ offset + 6 ] = v3.x;
+ vertexArray[ offset + 7 ] = v3.y;
+ vertexArray[ offset + 8 ] = v3.z;
+
+ offset += 9;
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
+
+ }
+
+ if ( dirtyMorphTargets ) {
+
+ for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
+
+ offset_morphTarget = 0;
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ chf = chunk_faces3[ f ];
+ face = obj_faces[ chf ];
+
+ // morph positions
+
+ v1 = morphTargets[ vk ].vertices[ face.a ];
+ v2 = morphTargets[ vk ].vertices[ face.b ];
+ v3 = morphTargets[ vk ].vertices[ face.c ];
+
+ vka = morphTargetsArrays[ vk ];
+
+ vka[ offset_morphTarget ] = v1.x;
+ vka[ offset_morphTarget + 1 ] = v1.y;
+ vka[ offset_morphTarget + 2 ] = v1.z;
+
+ vka[ offset_morphTarget + 3 ] = v2.x;
+ vka[ offset_morphTarget + 4 ] = v2.y;
+ vka[ offset_morphTarget + 5 ] = v2.z;
+
+ vka[ offset_morphTarget + 6 ] = v3.x;
+ vka[ offset_morphTarget + 7 ] = v3.y;
+ vka[ offset_morphTarget + 8 ] = v3.z;
+
+ // morph normals
+
+ if ( material.morphNormals ) {
+
+ if ( needsFaceNormals ) {
+
+ n1 = morphNormals[ vk ].faceNormals[ chf ];
+ n2 = n1;
+ n3 = n1;
+
+ } else {
+
+ faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
+
+ n1 = faceVertexNormals.a;
+ n2 = faceVertexNormals.b;
+ n3 = faceVertexNormals.c;
+
+ }
+
+ nka = morphNormalsArrays[ vk ];
+
+ nka[ offset_morphTarget ] = n1.x;
+ nka[ offset_morphTarget + 1 ] = n1.y;
+ nka[ offset_morphTarget + 2 ] = n1.z;
+
+ nka[ offset_morphTarget + 3 ] = n2.x;
+ nka[ offset_morphTarget + 4 ] = n2.y;
+ nka[ offset_morphTarget + 5 ] = n2.z;
+
+ nka[ offset_morphTarget + 6 ] = n3.x;
+ nka[ offset_morphTarget + 7 ] = n3.y;
+ nka[ offset_morphTarget + 8 ] = n3.z;
+
+ }
+
+ //
+
+ offset_morphTarget += 9;
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );
+ _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );
+
+ if ( material.morphNormals ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] );
+ _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint );
+
+ }
+
+ }
+
+ }
+
+ if ( obj_skinWeights.length ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ // weights
+
+ sw1 = obj_skinWeights[ face.a ];
+ sw2 = obj_skinWeights[ face.b ];
+ sw3 = obj_skinWeights[ face.c ];
+
+ skinWeightArray[ offset_skin ] = sw1.x;
+ skinWeightArray[ offset_skin + 1 ] = sw1.y;
+ skinWeightArray[ offset_skin + 2 ] = sw1.z;
+ skinWeightArray[ offset_skin + 3 ] = sw1.w;
+
+ skinWeightArray[ offset_skin + 4 ] = sw2.x;
+ skinWeightArray[ offset_skin + 5 ] = sw2.y;
+ skinWeightArray[ offset_skin + 6 ] = sw2.z;
+ skinWeightArray[ offset_skin + 7 ] = sw2.w;
+
+ skinWeightArray[ offset_skin + 8 ] = sw3.x;
+ skinWeightArray[ offset_skin + 9 ] = sw3.y;
+ skinWeightArray[ offset_skin + 10 ] = sw3.z;
+ skinWeightArray[ offset_skin + 11 ] = sw3.w;
+
+ // indices
+
+ si1 = obj_skinIndices[ face.a ];
+ si2 = obj_skinIndices[ face.b ];
+ si3 = obj_skinIndices[ face.c ];
+
+ skinIndexArray[ offset_skin ] = si1.x;
+ skinIndexArray[ offset_skin + 1 ] = si1.y;
+ skinIndexArray[ offset_skin + 2 ] = si1.z;
+ skinIndexArray[ offset_skin + 3 ] = si1.w;
+
+ skinIndexArray[ offset_skin + 4 ] = si2.x;
+ skinIndexArray[ offset_skin + 5 ] = si2.y;
+ skinIndexArray[ offset_skin + 6 ] = si2.z;
+ skinIndexArray[ offset_skin + 7 ] = si2.w;
+
+ skinIndexArray[ offset_skin + 8 ] = si3.x;
+ skinIndexArray[ offset_skin + 9 ] = si3.y;
+ skinIndexArray[ offset_skin + 10 ] = si3.z;
+ skinIndexArray[ offset_skin + 11 ] = si3.w;
+
+ offset_skin += 12;
+
+ }
+
+ if ( offset_skin > 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );
+
+ }
+
+ }
+
+ if ( dirtyColors ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ vertexColors = face.vertexColors;
+ faceColor = face.color;
+
+ if ( vertexColors.length === 3 && material.vertexColors === THREE.VertexColors ) {
+
+ c1 = vertexColors[ 0 ];
+ c2 = vertexColors[ 1 ];
+ c3 = vertexColors[ 2 ];
+
+ } else {
+
+ c1 = faceColor;
+ c2 = faceColor;
+ c3 = faceColor;
+
+ }
+
+ colorArray[ offset_color ] = c1.r;
+ colorArray[ offset_color + 1 ] = c1.g;
+ colorArray[ offset_color + 2 ] = c1.b;
+
+ colorArray[ offset_color + 3 ] = c2.r;
+ colorArray[ offset_color + 4 ] = c2.g;
+ colorArray[ offset_color + 5 ] = c2.b;
+
+ colorArray[ offset_color + 6 ] = c3.r;
+ colorArray[ offset_color + 7 ] = c3.g;
+ colorArray[ offset_color + 8 ] = c3.b;
+
+ offset_color += 9;
+
+ }
+
+ if ( offset_color > 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
+
+ }
+
+ }
+
+ if ( dirtyTangents && geometry.hasTangents ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ vertexTangents = face.vertexTangents;
+
+ t1 = vertexTangents[ 0 ];
+ t2 = vertexTangents[ 1 ];
+ t3 = vertexTangents[ 2 ];
+
+ tangentArray[ offset_tangent ] = t1.x;
+ tangentArray[ offset_tangent + 1 ] = t1.y;
+ tangentArray[ offset_tangent + 2 ] = t1.z;
+ tangentArray[ offset_tangent + 3 ] = t1.w;
+
+ tangentArray[ offset_tangent + 4 ] = t2.x;
+ tangentArray[ offset_tangent + 5 ] = t2.y;
+ tangentArray[ offset_tangent + 6 ] = t2.z;
+ tangentArray[ offset_tangent + 7 ] = t2.w;
+
+ tangentArray[ offset_tangent + 8 ] = t3.x;
+ tangentArray[ offset_tangent + 9 ] = t3.y;
+ tangentArray[ offset_tangent + 10 ] = t3.z;
+ tangentArray[ offset_tangent + 11 ] = t3.w;
+
+ offset_tangent += 12;
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );
+
+ }
+
+ if ( dirtyNormals ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ vertexNormals = face.vertexNormals;
+ faceNormal = face.normal;
+
+ if ( vertexNormals.length === 3 && needsFaceNormals === false ) {
+
+ for ( i = 0; i < 3; i ++ ) {
+
+ vn = vertexNormals[ i ];
+
+ normalArray[ offset_normal ] = vn.x;
+ normalArray[ offset_normal + 1 ] = vn.y;
+ normalArray[ offset_normal + 2 ] = vn.z;
+
+ offset_normal += 3;
+
+ }
+
+ } else {
+
+ for ( i = 0; i < 3; i ++ ) {
+
+ normalArray[ offset_normal ] = faceNormal.x;
+ normalArray[ offset_normal + 1 ] = faceNormal.y;
+ normalArray[ offset_normal + 2 ] = faceNormal.z;
+
+ offset_normal += 3;
+
+ }
+
+ }
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
+
+ }
+
+ if ( dirtyUvs && obj_uvs ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ fi = chunk_faces3[ f ];
+
+ uv = obj_uvs[ fi ];
+
+ if ( uv === undefined ) continue;
+
+ for ( i = 0; i < 3; i ++ ) {
+
+ uvi = uv[ i ];
+
+ uvArray[ offset_uv ] = uvi.x;
+ uvArray[ offset_uv + 1 ] = uvi.y;
+
+ offset_uv += 2;
+
+ }
+
+ }
+
+ if ( offset_uv > 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );
+
+ }
+
+ }
+
+ if ( dirtyUvs && obj_uvs2 ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ fi = chunk_faces3[ f ];
+
+ uv2 = obj_uvs2[ fi ];
+
+ if ( uv2 === undefined ) continue;
+
+ for ( i = 0; i < 3; i ++ ) {
+
+ uv2i = uv2[ i ];
+
+ uv2Array[ offset_uv2 ] = uv2i.x;
+ uv2Array[ offset_uv2 + 1 ] = uv2i.y;
+
+ offset_uv2 += 2;
+
+ }
+
+ }
+
+ if ( offset_uv2 > 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );
+
+ }
+
+ }
+
+ if ( dirtyElements ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ faceArray[ offset_face ] = vertexIndex;
+ faceArray[ offset_face + 1 ] = vertexIndex + 1;
+ faceArray[ offset_face + 2 ] = vertexIndex + 2;
+
+ offset_face += 3;
+
+ lineArray[ offset_line ] = vertexIndex;
+ lineArray[ offset_line + 1 ] = vertexIndex + 1;
+
+ lineArray[ offset_line + 2 ] = vertexIndex;
+ lineArray[ offset_line + 3 ] = vertexIndex + 2;
+
+ lineArray[ offset_line + 4 ] = vertexIndex + 1;
+ lineArray[ offset_line + 5 ] = vertexIndex + 2;
+
+ offset_line += 6;
+
+ vertexIndex += 3;
+
+ }
+
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
+ _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );
+
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
+ _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );
+
+ }
+
+ if ( customAttributes ) {
+
+ for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
+
+ customAttribute = customAttributes[ i ];
+
+ if ( ! customAttribute.__original.needsUpdate ) continue;
+
+ offset_custom = 0;
+
+ if ( customAttribute.size === 1 ) {
+
+ if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ];
+ customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
+ customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
+
+ offset_custom += 3;
+
+ }
+
+ } else if ( customAttribute.boundTo === 'faces' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ value = customAttribute.value[ chunk_faces3[ f ] ];
+
+ customAttribute.array[ offset_custom ] = value;
+ customAttribute.array[ offset_custom + 1 ] = value;
+ customAttribute.array[ offset_custom + 2 ] = value;
+
+ offset_custom += 3;
+
+ }
+
+ }
+
+ } else if ( customAttribute.size === 2 ) {
+
+ if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ v1 = customAttribute.value[ face.a ];
+ v2 = customAttribute.value[ face.b ];
+ v3 = customAttribute.value[ face.c ];
+
+ customAttribute.array[ offset_custom ] = v1.x;
+ customAttribute.array[ offset_custom + 1 ] = v1.y;
+
+ customAttribute.array[ offset_custom + 2 ] = v2.x;
+ customAttribute.array[ offset_custom + 3 ] = v2.y;
+
+ customAttribute.array[ offset_custom + 4 ] = v3.x;
+ customAttribute.array[ offset_custom + 5 ] = v3.y;
+
+ offset_custom += 6;
+
+ }
+
+ } else if ( customAttribute.boundTo === 'faces' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ value = customAttribute.value[ chunk_faces3[ f ] ];
+
+ v1 = value;
+ v2 = value;
+ v3 = value;
+
+ customAttribute.array[ offset_custom ] = v1.x;
+ customAttribute.array[ offset_custom + 1 ] = v1.y;
+
+ customAttribute.array[ offset_custom + 2 ] = v2.x;
+ customAttribute.array[ offset_custom + 3 ] = v2.y;
+
+ customAttribute.array[ offset_custom + 4 ] = v3.x;
+ customAttribute.array[ offset_custom + 5 ] = v3.y;
+
+ offset_custom += 6;
+
+ }
+
+ }
+
+ } else if ( customAttribute.size === 3 ) {
+
+ var pp;
+
+ if ( customAttribute.type === 'c' ) {
+
+ pp = [ 'r', 'g', 'b' ];
+
+ } else {
+
+ pp = [ 'x', 'y', 'z' ];
+
+ }
+
+ if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ v1 = customAttribute.value[ face.a ];
+ v2 = customAttribute.value[ face.b ];
+ v3 = customAttribute.value[ face.c ];
+
+ customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
+
+ customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
+
+ customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
+
+ offset_custom += 9;
+
+ }
+
+ } else if ( customAttribute.boundTo === 'faces' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ value = customAttribute.value[ chunk_faces3[ f ] ];
+
+ v1 = value;
+ v2 = value;
+ v3 = value;
+
+ customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
+
+ customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
+
+ customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
+
+ offset_custom += 9;
+
+ }
+
+ } else if ( customAttribute.boundTo === 'faceVertices' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ value = customAttribute.value[ chunk_faces3[ f ] ];
+
+ v1 = value[ 0 ];
+ v2 = value[ 1 ];
+ v3 = value[ 2 ];
+
+ customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
+
+ customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
+
+ customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
+ customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
+ customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
+
+ offset_custom += 9;
+
+ }
+
+ }
+
+ } else if ( customAttribute.size === 4 ) {
+
+ if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ face = obj_faces[ chunk_faces3[ f ] ];
+
+ v1 = customAttribute.value[ face.a ];
+ v2 = customAttribute.value[ face.b ];
+ v3 = customAttribute.value[ face.c ];
+
+ customAttribute.array[ offset_custom ] = v1.x;
+ customAttribute.array[ offset_custom + 1 ] = v1.y;
+ customAttribute.array[ offset_custom + 2 ] = v1.z;
+ customAttribute.array[ offset_custom + 3 ] = v1.w;
+
+ customAttribute.array[ offset_custom + 4 ] = v2.x;
+ customAttribute.array[ offset_custom + 5 ] = v2.y;
+ customAttribute.array[ offset_custom + 6 ] = v2.z;
+ customAttribute.array[ offset_custom + 7 ] = v2.w;
+
+ customAttribute.array[ offset_custom + 8 ] = v3.x;
+ customAttribute.array[ offset_custom + 9 ] = v3.y;
+ customAttribute.array[ offset_custom + 10 ] = v3.z;
+ customAttribute.array[ offset_custom + 11 ] = v3.w;
+
+ offset_custom += 12;
+
+ }
+
+ } else if ( customAttribute.boundTo === 'faces' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ value = customAttribute.value[ chunk_faces3[ f ] ];
+
+ v1 = value;
+ v2 = value;
+ v3 = value;
+
+ customAttribute.array[ offset_custom ] = v1.x;
+ customAttribute.array[ offset_custom + 1 ] = v1.y;
+ customAttribute.array[ offset_custom + 2 ] = v1.z;
+ customAttribute.array[ offset_custom + 3 ] = v1.w;
+
+ customAttribute.array[ offset_custom + 4 ] = v2.x;
+ customAttribute.array[ offset_custom + 5 ] = v2.y;
+ customAttribute.array[ offset_custom + 6 ] = v2.z;
+ customAttribute.array[ offset_custom + 7 ] = v2.w;
+
+ customAttribute.array[ offset_custom + 8 ] = v3.x;
+ customAttribute.array[ offset_custom + 9 ] = v3.y;
+ customAttribute.array[ offset_custom + 10 ] = v3.z;
+ customAttribute.array[ offset_custom + 11 ] = v3.w;
+
+ offset_custom += 12;
+
+ }
+
+ } else if ( customAttribute.boundTo === 'faceVertices' ) {
+
+ for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
+
+ value = customAttribute.value[ chunk_faces3[ f ] ];
+
+ v1 = value[ 0 ];
+ v2 = value[ 1 ];
+ v3 = value[ 2 ];
+
+ customAttribute.array[ offset_custom ] = v1.x;
+ customAttribute.array[ offset_custom + 1 ] = v1.y;
+ customAttribute.array[ offset_custom + 2 ] = v1.z;
+ customAttribute.array[ offset_custom + 3 ] = v1.w;
+
+ customAttribute.array[ offset_custom + 4 ] = v2.x;
+ customAttribute.array[ offset_custom + 5 ] = v2.y;
+ customAttribute.array[ offset_custom + 6 ] = v2.z;
+ customAttribute.array[ offset_custom + 7 ] = v2.w;
+
+ customAttribute.array[ offset_custom + 8 ] = v3.x;
+ customAttribute.array[ offset_custom + 9 ] = v3.y;
+ customAttribute.array[ offset_custom + 10 ] = v3.z;
+ customAttribute.array[ offset_custom + 11 ] = v3.w;
+
+ offset_custom += 12;
+
+ }
+
+ }
+
+ }
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
+
+ }
+
+ }
+
+ if ( dispose ) {
+
+ delete geometryGroup.__inittedArrays;
+ delete geometryGroup.__colorArray;
+ delete geometryGroup.__normalArray;
+ delete geometryGroup.__tangentArray;
+ delete geometryGroup.__uvArray;
+ delete geometryGroup.__uv2Array;
+ delete geometryGroup.__faceArray;
+ delete geometryGroup.__vertexArray;
+ delete geometryGroup.__lineArray;
+ delete geometryGroup.__skinIndexArray;
+ delete geometryGroup.__skinWeightArray;
+
+ }
+
+ };
+
+ // Buffer rendering
+
+ this.renderBufferImmediate = function ( object, program, material ) {
+
+ state.initAttributes();
+
+ if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
+ if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
+ if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
+ if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
+
+ if ( object.hasPositions ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
+
+ state.enableAttribute( program.attributes.position );
+
+ _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ if ( object.hasNormals ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
+
+ if ( material instanceof THREE.MeshPhongMaterial === false &&
+ material.shading === THREE.FlatShading ) {
+
+ var nx, ny, nz,
+ nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
+ normalArray,
+ i, il = object.count * 3;
+
+ for ( i = 0; i < il; i += 9 ) {
+
+ normalArray = object.normalArray;
+
+ nax = normalArray[ i ];
+ nay = normalArray[ i + 1 ];
+ naz = normalArray[ i + 2 ];
+
+ nbx = normalArray[ i + 3 ];
+ nby = normalArray[ i + 4 ];
+ nbz = normalArray[ i + 5 ];
+
+ ncx = normalArray[ i + 6 ];
+ ncy = normalArray[ i + 7 ];
+ ncz = normalArray[ i + 8 ];
+
+ nx = ( nax + nbx + ncx ) / 3;
+ ny = ( nay + nby + ncy ) / 3;
+ nz = ( naz + nbz + ncz ) / 3;
+
+ normalArray[ i ] = nx;
+ normalArray[ i + 1 ] = ny;
+ normalArray[ i + 2 ] = nz;
+
+ normalArray[ i + 3 ] = nx;
+ normalArray[ i + 4 ] = ny;
+ normalArray[ i + 5 ] = nz;
+
+ normalArray[ i + 6 ] = nx;
+ normalArray[ i + 7 ] = ny;
+ normalArray[ i + 8 ] = nz;
+
+ }
+
+ }
+
+ _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
+
+ state.enableAttribute( program.attributes.normal );
+
+ _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ if ( object.hasUvs && material.map ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
+
+ state.enableAttribute( program.attributes.uv );
+
+ _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
+ _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
+
+ state.enableAttribute( program.attributes.color );
+
+ _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ state.disableUnusedAttributes();
+
+ _gl.drawArrays( _gl.TRIANGLES, 0, object.count );
+
+ object.count = 0;
+
+ };
+
+ function setupVertexAttributes( material, program, geometry, startIndex ) {
+
+ var geometryAttributes = geometry.attributes;
+
+ var programAttributes = program.attributes;
+ var programAttributesKeys = program.attributesKeys;
+
+ for ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) {
+
+ var key = programAttributesKeys[ i ];
+ var programAttribute = programAttributes[ key ];
+
+ if ( programAttribute >= 0 ) {
+
+ var geometryAttribute = geometryAttributes[ key ];
+
+ if ( geometryAttribute !== undefined ) {
+
+ var size = geometryAttribute.itemSize;
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer );
+
+ state.enableAttribute( programAttribute );
+
+ _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32
+
+ } else if ( material.defaultAttributeValues !== undefined ) {
+
+ if ( material.defaultAttributeValues[ key ].length === 2 ) {
+
+ _gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] );
+
+ } else if ( material.defaultAttributeValues[ key ].length === 3 ) {
+
+ _gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] );
+
+ }
+
+ }
+
+ }
+
+ }
+
+ state.disableUnusedAttributes();
+
+ }
+
+ this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {
+
+ if ( material.visible === false ) return;
+
+ updateObject( object );
+
+ var program = setProgram( camera, lights, fog, material, object );
+
+ var updateBuffers = false,
+ wireframeBit = material.wireframe ? 1 : 0,
+ geometryProgram = 'direct_' + geometry.id + '_' + program.id + '_' + wireframeBit;
+
+ if ( geometryProgram !== _currentGeometryProgram ) {
+
+ _currentGeometryProgram = geometryProgram;
+ updateBuffers = true;
+
+ }
+
+ if ( updateBuffers ) {
+
+ state.initAttributes();
+
+ }
+
+ // render mesh
+
+ if ( object instanceof THREE.Mesh ) {
+
+ var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES;
+
+ var index = geometry.attributes.index;
+
+ if ( index ) {
+
+ // indexed triangles
+
+ var type, size;
+
+ if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
+
+ type = _gl.UNSIGNED_INT;
+ size = 4;
+
+ } else {
+
+ type = _gl.UNSIGNED_SHORT;
+ size = 2;
+
+ }
+
+ var offsets = geometry.offsets;
+
+ if ( offsets.length === 0 ) {
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, 0 );
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+
+ }
+
+ _gl.drawElements( mode, index.array.length, type, 0 );
+
+ _this.info.render.calls ++;
+ _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared
+ _this.info.render.faces += index.array.length / 3;
+
+ } else {
+
+ // if there is more than 1 chunk
+ // must set attribute pointers to use new offsets for each chunk
+ // even if geometry and materials didn't change
+
+ updateBuffers = true;
+
+ for ( var i = 0, il = offsets.length; i < il; i ++ ) {
+
+ var startIndex = offsets[ i ].index;
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, startIndex );
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+
+ }
+
+ // render indexed triangles
+
+ _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );
+
+ _this.info.render.calls ++;
+ _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
+ _this.info.render.faces += offsets[ i ].count / 3;
+
+ }
+
+ }
+
+ } else {
+
+ // non-indexed triangles
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, 0 );
+
+ }
+
+ var position = geometry.attributes[ 'position' ];
+
+ // render non-indexed triangles
+
+ _gl.drawArrays( mode, 0, position.array.length / position.itemSize );
+
+ _this.info.render.calls ++;
+ _this.info.render.vertices += position.array.length / position.itemSize;
+ _this.info.render.faces += position.array.length / ( 3 * position.itemSize );
+
+ }
+
+ } else if ( object instanceof THREE.PointCloud ) {
+
+ // render particles
+
+ var mode = _gl.POINTS;
+
+ var index = geometry.attributes.index;
+
+ if ( index ) {
+
+ // indexed points
+
+ var type, size;
+
+ if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
+
+ type = _gl.UNSIGNED_INT;
+ size = 4;
+
+ } else {
+
+ type = _gl.UNSIGNED_SHORT;
+ size = 2;
+
+ }
+
+ var offsets = geometry.offsets;
+
+ if ( offsets.length === 0 ) {
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, 0 );
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+
+ }
+
+ _gl.drawElements( mode, index.array.length, type, 0);
+
+ _this.info.render.calls ++;
+ _this.info.render.points += index.array.length;
+
+ } else {
+
+ // if there is more than 1 chunk
+ // must set attribute pointers to use new offsets for each chunk
+ // even if geometry and materials didn't change
+
+ if ( offsets.length > 1 ) updateBuffers = true;
+
+ for ( var i = 0, il = offsets.length; i < il; i ++ ) {
+
+ var startIndex = offsets[ i ].index;
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, startIndex );
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+
+ }
+
+ // render indexed points
+
+ _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );
+
+ _this.info.render.calls ++;
+ _this.info.render.points += offsets[ i ].count;
+
+ }
+
+ }
+
+ } else {
+
+ // non-indexed points
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, 0 );
+
+ }
+
+ var position = geometry.attributes.position;
+ var offsets = geometry.offsets;
+
+ if ( offsets.length === 0 ) {
+
+ _gl.drawArrays( mode, 0, position.array.length / 3 );
+
+ _this.info.render.calls ++;
+ _this.info.render.points += position.array.length / 3;
+
+ } else {
+
+ for ( var i = 0, il = offsets.length; i < il; i ++ ) {
+
+ _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count );
+
+ _this.info.render.calls ++;
+ _this.info.render.points += offsets[ i ].count;
+
+ }
+
+ }
+
+ }
+
+ } else if ( object instanceof THREE.Line ) {
+
+ var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
+
+ state.setLineWidth( material.linewidth * pixelRatio );
+
+ var index = geometry.attributes.index;
+
+ if ( index ) {
+
+ // indexed lines
+
+ var type, size;
+
+ if ( index.array instanceof Uint32Array ) {
+
+ type = _gl.UNSIGNED_INT;
+ size = 4;
+
+ } else {
+
+ type = _gl.UNSIGNED_SHORT;
+ size = 2;
+
+ }
+
+ var offsets = geometry.offsets;
+
+ if ( offsets.length === 0 ) {
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, 0 );
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+
+ }
+
+ _gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array
+
+ _this.info.render.calls ++;
+ _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared
+
+ } else {
+
+ // if there is more than 1 chunk
+ // must set attribute pointers to use new offsets for each chunk
+ // even if geometry and materials didn't change
+
+ if ( offsets.length > 1 ) updateBuffers = true;
+
+ for ( var i = 0, il = offsets.length; i < il; i ++ ) {
+
+ var startIndex = offsets[ i ].index;
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, startIndex );
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+
+ }
+
+ // render indexed lines
+
+ _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array
+
+ _this.info.render.calls ++;
+ _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
+
+ }
+
+ }
+
+ } else {
+
+ // non-indexed lines
+
+ if ( updateBuffers ) {
+
+ setupVertexAttributes( material, program, geometry, 0 );
+
+ }
+
+ var position = geometry.attributes.position;
+ var offsets = geometry.offsets;
+
+ if ( offsets.length === 0 ) {
+
+ _gl.drawArrays( mode, 0, position.array.length / 3 );
+
+ _this.info.render.calls ++;
+ _this.info.render.vertices += position.array.length / 3;
+
+ } else {
+
+ for ( var i = 0, il = offsets.length; i < il; i ++ ) {
+
+ _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count );
+
+ _this.info.render.calls ++;
+ _this.info.render.vertices += offsets[ i ].count;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ };
+
+ this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {
+
+ if ( material.visible === false ) return;
+
+ updateObject( object );
+
+ var program = setProgram( camera, lights, fog, material, object );
+
+ var attributes = program.attributes;
+
+ var updateBuffers = false,
+ wireframeBit = material.wireframe ? 1 : 0,
+ geometryProgram = geometryGroup.id + '_' + program.id + '_' + wireframeBit;
+
+ if ( geometryProgram !== _currentGeometryProgram ) {
+
+ _currentGeometryProgram = geometryProgram;
+ updateBuffers = true;
+
+ }
+
+ if ( updateBuffers ) {
+
+ state.initAttributes();
+
+ }
+
+ // vertices
+
+ if ( ! material.morphTargets && attributes.position >= 0 ) {
+
+ if ( updateBuffers ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
+
+ state.enableAttribute( attributes.position );
+
+ _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ } else {
+
+ if ( object.morphTargetBase ) {
+
+ setupMorphTargets( material, geometryGroup, object );
+
+ }
+
+ }
+
+
+ if ( updateBuffers ) {
+
+ // custom attributes
+
+ // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers
+
+ if ( geometryGroup.__webglCustomAttributesList ) {
+
+ for ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
+
+ var attribute = geometryGroup.__webglCustomAttributesList[ i ];
+
+ if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
+
+ state.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] );
+
+ _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ }
+
+ }
+
+
+ // colors
+
+ if ( attributes.color >= 0 ) {
+
+ if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
+
+ state.enableAttribute( attributes.color );
+
+ _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
+
+ } else if ( material.defaultAttributeValues !== undefined ) {
+
+
+ _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color );
+
+ }
+
+ }
+
+ // normals
+
+ if ( attributes.normal >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
+
+ state.enableAttribute( attributes.normal );
+
+ _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ // tangents
+
+ if ( attributes.tangent >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
+
+ state.enableAttribute( attributes.tangent );
+
+ _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ // uvs
+
+ if ( attributes.uv >= 0 ) {
+
+ if ( object.geometry.faceVertexUvs[ 0 ] ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
+
+ state.enableAttribute( attributes.uv );
+
+ _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
+
+ } else if ( material.defaultAttributeValues !== undefined ) {
+
+
+ _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv );
+
+ }
+
+ }
+
+ if ( attributes.uv2 >= 0 ) {
+
+ if ( object.geometry.faceVertexUvs[ 1 ] ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
+
+ state.enableAttribute( attributes.uv2 );
+
+ _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );
+
+ } else if ( material.defaultAttributeValues !== undefined ) {
+
+
+ _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 );
+
+ }
+
+ }
+
+ if ( material.skinning &&
+ attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
+
+ state.enableAttribute( attributes.skinIndex );
+
+ _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
+
+ state.enableAttribute( attributes.skinWeight );
+
+ _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ // line distances
+
+ if ( attributes.lineDistance >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer );
+
+ state.enableAttribute( attributes.lineDistance );
+
+ _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ }
+
+ state.disableUnusedAttributes();
+
+ // render mesh
+
+ if ( object instanceof THREE.Mesh ) {
+
+ var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT;
+
+ // wireframe
+
+ if ( material.wireframe ) {
+
+ state.setLineWidth( material.wireframeLinewidth * pixelRatio );
+
+ if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
+ _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 );
+
+ // triangles
+
+ } else {
+
+ if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
+ _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 0 );
+
+ }
+
+ _this.info.render.calls ++;
+ _this.info.render.vertices += geometryGroup.__webglFaceCount;
+ _this.info.render.faces += geometryGroup.__webglFaceCount / 3;
+
+ // render lines
+
+ } else if ( object instanceof THREE.Line ) {
+
+ var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
+
+ state.setLineWidth( material.linewidth * pixelRatio );
+
+ _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount );
+
+ _this.info.render.calls ++;
+
+ // render particles
+
+ } else if ( object instanceof THREE.PointCloud ) {
+
+ _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );
+
+ _this.info.render.calls ++;
+ _this.info.render.points += geometryGroup.__webglParticleCount;
+
+ }
+
+ };
+
+ function setupMorphTargets ( material, geometryGroup, object ) {
+
+ // set base
+
+ var attributes = material.program.attributes;
+
+ if ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] );
+
+ state.enableAttribute( attributes.position );
+
+ _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+
+ } else if ( attributes.position >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
+
+ state.enableAttribute( attributes.position );
+
+ _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ if ( object.morphTargetForcedOrder.length ) {
+
+ // set forced order
+
+ var m = 0;
+ var order = object.morphTargetForcedOrder;
+ var influences = object.morphTargetInfluences;
+
+ var attribute;
+
+ while ( m < material.numSupportedMorphTargets && m < order.length ) {
+
+ attribute = attributes[ 'morphTarget' + m ];
+
+ if ( attribute >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );
+
+ state.enableAttribute( attribute );
+
+ _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ attribute = attributes[ 'morphNormal' + m ];
+
+ if ( attribute >= 0 && material.morphNormals ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] );
+
+ state.enableAttribute( attribute );
+
+ _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];
+
+ m ++;
+
+ }
+
+ } else {
+
+ // find the most influencing
+
+ var activeInfluenceIndices = [];
+ var influences = object.morphTargetInfluences;
+ var morphTargets = object.geometry.morphTargets;
+
+ if ( influences.length > morphTargets.length ) {
+
+ console.warn( 'THREE.Canvas3DRenderer: Influences array is bigger than morphTargets array.' );
+ influences.length = morphTargets.length;
+
+ }
+
+ for ( var i = 0, il = influences.length; i < il; i ++ ) {
+
+ var influence = influences[ i ];
+
+ activeInfluenceIndices.push( [ influence, i ] );
+
+ }
+
+ if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) {
+
+ activeInfluenceIndices.sort( numericalSort );
+ activeInfluenceIndices.length = material.numSupportedMorphTargets;
+
+ } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) {
+
+ activeInfluenceIndices.sort( numericalSort );
+
+ } else if ( activeInfluenceIndices.length === 0 ) {
+
+ activeInfluenceIndices.push( [ 0, 0 ] );
+
+ }
+
+ var attribute;
+
+ for ( var m = 0, ml = material.numSupportedMorphTargets; m < ml; m ++ ) {
+
+ if ( activeInfluenceIndices[ m ] ) {
+
+ var influenceIndex = activeInfluenceIndices[ m ][ 1 ];
+
+ attribute = attributes[ 'morphTarget' + m ];
+
+ if ( attribute >= 0 ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] );
+
+ state.enableAttribute( attribute );
+
+ _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ attribute = attributes[ 'morphNormal' + m ];
+
+ if ( attribute >= 0 && material.morphNormals ) {
+
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] );
+
+ state.enableAttribute( attribute );
+
+ _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+
+ object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ];
+
+ } else {
+
+ /*
+ _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
+
+ if ( material.morphNormals ) {
+
+ _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
+
+ }
+ */
+
+ object.__webglMorphTargetInfluences[ m ] = 0;
+
+ }
+
+ }
+
+ }
+
+ // load updated influences uniform
+
+ if ( material.program.uniforms.morphTargetInfluences !== null ) {
+
+ _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );
+
+ }
+
+ }
+
+ // Sorting
+
+ function painterSortStable ( a, b ) {
+
+ if ( a.object.renderOrder !== b.object.renderOrder ) {
+
+ return a.object.renderOrder - b.object.renderOrder;
+
+ } else if ( a.material.id !== b.material.id ) {
+
+ return a.material.id - b.material.id;
+
+ } else if ( a.z !== b.z ) {
+
+ return a.z - b.z;
+
+ } else {
+
+ return a.id - b.id;
+
+ }
+
+ }
+
+ function reversePainterSortStable ( a, b ) {
+
+ if ( a.object.renderOrder !== b.object.renderOrder ) {
+
+ return a.object.renderOrder - b.object.renderOrder;
+
+ } if ( a.z !== b.z ) {
+
+ return b.z - a.z;
+
+ } else {
+
+ return a.id - b.id;
+
+ }
+
+ }
+
+ function numericalSort ( a, b ) {
+
+ return b[ 0 ] - a[ 0 ];
+
+ }
+
+ // Rendering
+
+ this.render = function ( scene, camera, renderTarget, forceClear ) {
+
+ if ( camera instanceof THREE.Camera === false ) {
+
+ THREE.error( 'THREE.Canvas3DRenderer.render: camera is not an instance of THREE.Camera.' );
+ return;
+
+ }
+
+ var fog = scene.fog;
+
+ // reset caching for this frame
+
+ _currentGeometryProgram = '';
+ _currentMaterialId = - 1;
+ _currentCamera = null;
+ _lightsNeedUpdate = true;
+
+ // update scene graph
+
+ if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
+
+ // update camera matrices and frustum
+
+ if ( camera.parent === undefined ) camera.updateMatrixWorld();
+
+ // update Skeleton objects
+
+ scene.traverse( function ( object ) {
+
+ if ( object instanceof THREE.SkinnedMesh ) {
+
+ object.skeleton.update();
+
+ }
+
+ } );
+
+ camera.matrixWorldInverse.getInverse( camera.matrixWorld );
+
+ _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
+ _frustum.setFromMatrix( _projScreenMatrix );
+
+ lights.length = 0;
+ opaqueObjects.length = 0;
+ transparentObjects.length = 0;
+
+ sprites.length = 0;
+ lensFlares.length = 0;
+
+ projectObject( scene );
+
+ if ( _this.sortObjects === true ) {
+
+ opaqueObjects.sort( painterSortStable );
+ transparentObjects.sort( reversePainterSortStable );
+
+ }
+
+ // custom render plugins (pre pass)
+
+ shadowMapPlugin.render( scene, camera );
+
+ //
+
+ _this.info.render.calls = 0;
+ _this.info.render.vertices = 0;
+ _this.info.render.faces = 0;
+ _this.info.render.points = 0;
+
+ this.setRenderTarget( renderTarget );
+
+ if ( this.autoClear || forceClear ) {
+
+ this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
+
+ }
+
+ // set matrices for immediate objects
+
+ for ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) {
+
+ var webglObject = _webglObjectsImmediate[ i ];
+ var object = webglObject.object;
+
+ if ( object.visible ) {
+
+ setupMatrices( object, camera );
+
+ unrollImmediateBufferMaterial( webglObject );
+
+ }
+
+ }
+
+ if ( scene.overrideMaterial ) {
+
+ var overrideMaterial = scene.overrideMaterial;
+
+ setMaterial( overrideMaterial );
+
+ renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial );
+ renderObjects( transparentObjects, camera, lights, fog, overrideMaterial );
+ renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial );
+
+ } else {
+
+ // opaque pass (front-to-back order)
+
+ state.setBlending( THREE.NoBlending );
+
+ renderObjects( opaqueObjects, camera, lights, fog, null );
+ renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null );
+
+ // transparent pass (back-to-front order)
+
+ renderObjects( transparentObjects, camera, lights, fog, null );
+ renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null );
+
+ }
+
+ // custom render plugins (post pass)
+
+ spritePlugin.render( scene, camera );
+ lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight );
+
+ // Generate mipmap if we're using any kind of mipmap filtering
+
+ if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
+
+ updateRenderTargetMipmap( renderTarget );
+
+ }
+
+ // Ensure depth buffer writing is enabled so it can be cleared on next render
+
+ state.setDepthTest( true );
+ state.setDepthWrite( true );
+ state.setColorWrite( true );
+
+ // _gl.finish();
+
+ };
+
+ function projectObject( object ) {
+
+ if ( object.visible === false ) return;
+
+ if ( object instanceof THREE.Scene || object instanceof THREE.Group ) {
+
+ // skip
+
+ } else {
+
+ initObject( object );
+
+ if ( object instanceof THREE.Light ) {
+
+ lights.push( object );
+
+ } else if ( object instanceof THREE.Sprite ) {
+
+ sprites.push( object );
+
+ } else if ( object instanceof THREE.LensFlare ) {
+
+ lensFlares.push( object );
+
+ } else {
+
+ var webglObjects = _webglObjects[ object.id ];
+
+ if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {
+
+ for ( var i = 0, l = webglObjects.length; i < l; i ++ ) {
+
+ var webglObject = webglObjects[ i ];
+
+ unrollBufferMaterial( webglObject );
+
+ webglObject.render = true;
+
+ if ( _this.sortObjects === true ) {
+
+ _vector3.setFromMatrixPosition( object.matrixWorld );
+ _vector3.applyProjection( _projScreenMatrix );
+
+ webglObject.z = _vector3.z;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ for ( var i = 0, l = object.children.length; i < l; i ++ ) {
+
+ projectObject( object.children[ i ] );
+
+ }
+
+ }
+
+ function renderObjects( renderList, camera, lights, fog, overrideMaterial ) {
+
+ var material;
+
+ for ( var i = 0, l = renderList.length; i < l; i ++ ) {
+
+ var webglObject = renderList[ i ];
+
+ var object = webglObject.object;
+ var buffer = webglObject.buffer;
+
+ setupMatrices( object, camera );
+
+ if ( overrideMaterial ) {
+
+ material = overrideMaterial;
+
+ } else {
+
+ material = webglObject.material;
+
+ if ( ! material ) continue;
+
+ setMaterial( material );
+
+ }
+
+ _this.setMaterialFaces( material );
+
+ if ( buffer instanceof THREE.BufferGeometry ) {
+
+ _this.renderBufferDirect( camera, lights, fog, material, buffer, object );
+
+ } else {
+
+ _this.renderBuffer( camera, lights, fog, material, buffer, object );
+
+ }
+
+ }
+
+ }
+
+ function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) {
+
+ var material;
+
+ for ( var i = 0, l = renderList.length; i < l; i ++ ) {
+
+ var webglObject = renderList[ i ];
+ var object = webglObject.object;
+
+ if ( object.visible ) {
+
+ if ( overrideMaterial ) {
+
+ material = overrideMaterial;
+
+ } else {
+
+ material = webglObject[ materialType ];
+
+ if ( ! material ) continue;
+
+ setMaterial( material );
+
+ }
+
+ _this.renderImmediateObject( camera, lights, fog, material, object );
+
+ }
+
+ }
+
+ }
+
+ this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
+
+ var program = setProgram( camera, lights, fog, material, object );
+
+ _currentGeometryProgram = '';
+
+ _this.setMaterialFaces( material );
+
+ if ( object.immediateRenderCallback ) {
+
+ object.immediateRenderCallback( program, _gl, _frustum );
+
+ } else {
+
+ object.render( function ( object ) { _this.renderBufferImmediate( object, program, material ); } );
+
+ }
+
+ };
+
+ function unrollImmediateBufferMaterial ( globject ) {
+
+ var object = globject.object,
+ material = object.material;
+
+ if ( material.transparent ) {
+
+ globject.transparent = material;
+ globject.opaque = null;
+
+ } else {
+
+ globject.opaque = material;
+ globject.transparent = null;
+
+ }
+
+ }
+
+ function unrollBufferMaterial ( globject ) {
+
+ var object = globject.object;
+ var buffer = globject.buffer;
+
+ var geometry = object.geometry;
+ var material = object.material;
+
+ if ( material instanceof THREE.MeshFaceMaterial ) {
+
+ var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex;
+
+ material = material.materials[ materialIndex ];
+
+ globject.material = material;
+
+ if ( material.transparent ) {
+
+ transparentObjects.push( globject );
+
+ } else {
+
+ opaqueObjects.push( globject );
+
+ }
+
+ } else if ( material ) {
+
+ globject.material = material;
+
+ if ( material.transparent ) {
+
+ transparentObjects.push( globject );
+
+ } else {
+
+ opaqueObjects.push( globject );
+
+ }
+
+ }
+
+ }
+
+ function initObject( object ) {
+
+ if ( object.__webglInit === undefined ) {
+
+ object.__webglInit = true;
+ object._modelViewMatrix = new THREE.Matrix4();
+ object._normalMatrix = new THREE.Matrix3();
+
+ object.addEventListener( 'removed', onObjectRemoved );
+
+ }
+
+ var geometry = object.geometry;
+
+ if ( geometry === undefined ) {
+
+ // ImmediateRenderObject
+
+ } else if ( geometry.__webglInit === undefined ) {
+
+ geometry.__webglInit = true;
+ geometry.addEventListener( 'dispose', onGeometryDispose );
+
+ if ( geometry instanceof THREE.BufferGeometry ) {
+
+ _this.info.memory.geometries ++;
+
+ } else if ( object instanceof THREE.Mesh ) {
+
+ initGeometryGroups( object, geometry );
+
+ } else if ( object instanceof THREE.Line ) {
+
+ if ( geometry.__webglVertexBuffer === undefined ) {
+
+ createLineBuffers( geometry );
+ initLineBuffers( geometry, object );
+
+ geometry.verticesNeedUpdate = true;
+ geometry.colorsNeedUpdate = true;
+ geometry.lineDistancesNeedUpdate = true;
+
+ }
+
+ } else if ( object instanceof THREE.PointCloud ) {
+
+ if ( geometry.__webglVertexBuffer === undefined ) {
+
+ createParticleBuffers( geometry );
+ initParticleBuffers( geometry, object );
+
+ geometry.verticesNeedUpdate = true;
+ geometry.colorsNeedUpdate = true;
+
+ }
+
+ }
+
+ }
+
+ if ( object.__webglActive === undefined) {
+
+ object.__webglActive = true;
+
+ if ( object instanceof THREE.Mesh ) {
+
+ if ( geometry instanceof THREE.BufferGeometry ) {
+
+ addBuffer( _webglObjects, geometry, object );
+
+ } else if ( geometry instanceof THREE.Geometry ) {
+
+ var geometryGroupsList = geometryGroups[ geometry.id ];
+
+ for ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) {
+
+ addBuffer( _webglObjects, geometryGroupsList[ i ], object );
+
+ }
+
+ }
+
+ } else if ( object instanceof THREE.Line || object instanceof THREE.PointCloud ) {
+
+ addBuffer( _webglObjects, geometry, object );
+
+ } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
+
+ addBufferImmediate( _webglObjectsImmediate, object );
+
+ }
+
+ }
+
+ }
+
+ // Geometry splitting
+
+ var geometryGroups = {};
+ var geometryGroupCounter = 0;
+
+ function makeGroups( geometry, usesFaceMaterial ) {
+
+ var maxVerticesInGroup = extensions.get( 'OES_element_index_uint' ) ? 4294967296 : 65535;
+
+ var groupHash, hash_map = {};
+
+ var numMorphTargets = geometry.morphTargets.length;
+ var numMorphNormals = geometry.morphNormals.length;
+
+ var group;
+ var groups = {};
+ var groupsList = [];
+
+ for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
+
+ var face = geometry.faces[ f ];
+ var materialIndex = usesFaceMaterial ? face.materialIndex : 0;
+
+ if ( ! ( materialIndex in hash_map ) ) {
+
+ hash_map[ materialIndex ] = { hash: materialIndex, counter: 0 };
+
+ }
+
+ groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
+
+ if ( ! ( groupHash in groups ) ) {
+
+ group = {
+ id: geometryGroupCounter ++,
+ faces3: [],
+ materialIndex: materialIndex,
+ vertices: 0,
+ numMorphTargets: numMorphTargets,
+ numMorphNormals: numMorphNormals
+ };
+
+ groups[ groupHash ] = group;
+ groupsList.push( group );
+
+ }
+
+ if ( groups[ groupHash ].vertices + 3 > maxVerticesInGroup ) {
+
+ hash_map[ materialIndex ].counter += 1;
+ groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
+
+ if ( ! ( groupHash in groups ) ) {
+
+ group = {
+ id: geometryGroupCounter ++,
+ faces3: [],
+ materialIndex: materialIndex,
+ vertices: 0,
+ numMorphTargets: numMorphTargets,
+ numMorphNormals: numMorphNormals
+ };
+
+ groups[ groupHash ] = group;
+ groupsList.push( group );
+
+ }
+
+ }
+
+ groups[ groupHash ].faces3.push( f );
+ groups[ groupHash ].vertices += 3;
+
+ }
+
+ return groupsList;
+
+ }
+
+ function initGeometryGroups( object, geometry ) {
+
+ var material = object.material, addBuffers = false;
+
+ if ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) {
+
+ delete _webglObjects[ object.id ];
+
+ geometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial );
+
+ geometry.groupsNeedUpdate = false;
+
+ }
+
+ var geometryGroupsList = geometryGroups[ geometry.id ];
+
+ // create separate VBOs per geometry chunk
+
+ for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {
+
+ var geometryGroup = geometryGroupsList[ i ];
+
+ // initialise VBO on the first access
+
+ if ( geometryGroup.__webglVertexBuffer === undefined ) {
+
+ createMeshBuffers( geometryGroup );
+ initMeshBuffers( geometryGroup, object );
+
+ geometry.verticesNeedUpdate = true;
+ geometry.morphTargetsNeedUpdate = true;
+ geometry.elementsNeedUpdate = true;
+ geometry.uvsNeedUpdate = true;
+ geometry.normalsNeedUpdate = true;
+ geometry.tangentsNeedUpdate = true;
+ geometry.colorsNeedUpdate = true;
+
+ addBuffers = true;
+
+ } else {
+
+ addBuffers = false;
+
+ }
+
+ if ( addBuffers || object.__webglActive === undefined ) {
+
+ addBuffer( _webglObjects, geometryGroup, object );
+
+ }
+
+ }
+
+ object.__webglActive = true;
+
+ }
+
+ function addBuffer( objlist, buffer, object ) {
+
+ var id = object.id;
+ objlist[id] = objlist[id] || [];
+ objlist[id].push(
+ {
+ id: id,
+ buffer: buffer,
+ object: object,
+ material: null,
+ z: 0
+ }
+ );
+
+ };
+
+ function addBufferImmediate( objlist, object ) {
+
+ objlist.push(
+ {
+ id: null,
+ object: object,
+ opaque: null,
+ transparent: null,
+ z: 0
+ }
+ );
+
+ };
+
+ // Objects updates
+
+ function updateObject( object ) {
+
+ var geometry = object.geometry;
+
+ if ( geometry instanceof THREE.BufferGeometry ) {
+
+ var attributes = geometry.attributes;
+ var attributesKeys = geometry.attributesKeys;
+
+ for ( var i = 0, l = attributesKeys.length; i < l; i ++ ) {
+
+ var key = attributesKeys[ i ];
+ var attribute = attributes[ key ];
+ var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER;
+
+ if ( attribute.buffer === undefined ) {
+
+ attribute.buffer = _gl.createBuffer();
+ _gl.bindBuffer( bufferType, attribute.buffer );
+ _gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW );
+
+ attribute.needsUpdate = false;
+
+ } else if ( attribute.needsUpdate === true ) {
+
+ _gl.bindBuffer( bufferType, attribute.buffer );
+
+ if ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges
+
+ _gl.bufferSubData( bufferType, 0, attribute.array );
+
+ } else if ( attribute.updateRange.count === 0 ) {
+
+ console.error( 'THREE.Canvas3DRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' );
+
+ } else {
+
+ _gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT,
+ attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) );
+
+ attribute.updateRange.count = 0; // reset range
+
+ }
+
+ attribute.needsUpdate = false;
+
+ }
+
+ }
+
+ } else if ( object instanceof THREE.Mesh ) {
+
+ // check all geometry groups
+
+ if ( geometry.groupsNeedUpdate === true ) {
+
+ initGeometryGroups( object, geometry );
+
+ }
+
+ var geometryGroupsList = geometryGroups[ geometry.id ];
+
+ for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {
+
+ var geometryGroup = geometryGroupsList[ i ];
+ var material = getBufferMaterial( object, geometryGroup );
+
+ var customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
+
+ if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate ||
+ geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
+ geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) {
+
+ setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, ! geometry.dynamic, material );
+
+ }
+
+ }
+
+ geometry.verticesNeedUpdate = false;
+ geometry.morphTargetsNeedUpdate = false;
+ geometry.elementsNeedUpdate = false;
+ geometry.uvsNeedUpdate = false;
+ geometry.normalsNeedUpdate = false;
+ geometry.colorsNeedUpdate = false;
+ geometry.tangentsNeedUpdate = false;
+
+ if (material.attributes) clearCustomAttributes( material );
+
+ } else if ( object instanceof THREE.Line ) {
+
+ var material = getBufferMaterial( object, geometry );
+ var customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
+
+ if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) {
+
+ setLineBuffers( geometry, _gl.DYNAMIC_DRAW );
+
+ }
+
+ geometry.verticesNeedUpdate = false;
+ geometry.colorsNeedUpdate = false;
+ geometry.lineDistancesNeedUpdate = false;
+
+ if (material.attributes) clearCustomAttributes( material );
+
+ } else if ( object instanceof THREE.PointCloud ) {
+
+ var material = getBufferMaterial( object, geometry );
+ var customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
+
+ if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || customAttributesDirty ) {
+
+ setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );
+
+ }
+
+ geometry.verticesNeedUpdate = false;
+ geometry.colorsNeedUpdate = false;
+
+ if(material.attributes) clearCustomAttributes( material );
+
+ }
+
+ }
+
+ // Objects updates - custom attributes check
+
+ function areCustomAttributesDirty( material ) {
+
+ for ( var name in material.attributes ) {
+
+ if ( material.attributes[ name ].needsUpdate ) return true;
+
+ }
+
+ return false;
+
+ }
+
+ function clearCustomAttributes( material ) {
+
+ for ( var name in material.attributes ) {
+
+ material.attributes[ name ].needsUpdate = false;
+
+ }
+
+ }
+
+ // Objects removal
+
+ function removeObject( object ) {
+
+ if ( object instanceof THREE.Mesh ||
+ object instanceof THREE.PointCloud ||
+ object instanceof THREE.Line ) {
+
+ delete _webglObjects[ object.id ];
+
+ } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
+
+ removeInstances( _webglObjectsImmediate, object );
+
+ }
+
+ delete object.__webglInit;
+ delete object._modelViewMatrix;
+ delete object._normalMatrix;
+
+ delete object.__webglActive;
+
+ }
+
+ function removeInstances( objlist, object ) {
+
+ for ( var o = objlist.length - 1; o >= 0; o -- ) {
+
+ if ( objlist[ o ].object === object ) {
+
+ objlist.splice( o, 1 );
+
+ }
+
+ }
+
+ }
+
+ // Materials
+
+ var shaderIDs = {
+ MeshDepthMaterial: 'depth',
+ MeshNormalMaterial: 'normal',
+ MeshBasicMaterial: 'basic',
+ MeshLambertMaterial: 'lambert',
+ MeshPhongMaterial: 'phong',
+ LineBasicMaterial: 'basic',
+ LineDashedMaterial: 'dashed',
+ PointCloudMaterial: 'particle_basic'
+ };
+
+ function initMaterial( material, lights, fog, object ) {
+
+ material.addEventListener( 'dispose', onMaterialDispose );
+
+ var shaderID = shaderIDs[ material.type ];
+
+ if ( shaderID ) {
+
+ var shader = THREE.ShaderLib[ shaderID ];
+
+ material.__webglShader = {
+ uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
+ vertexShader: shader.vertexShader,
+ fragmentShader: shader.fragmentShader
+ }
+
+ } else {
+
+ material.__webglShader = {
+ uniforms: material.uniforms,
+ vertexShader: material.vertexShader,
+ fragmentShader: material.fragmentShader
+ }
+
+ }
+
+ // heuristics to create shader parameters according to lights in the scene
+ // (not to blow over maxLights budget)
+
+ var maxLightCount = allocateLights( lights );
+ var maxShadows = allocateShadows( lights );
+ var maxBones = allocateBones( object );
+
+ var parameters = {
+
+ precision: _precision,
+ supportsVertexTextures: _supportsVertexTextures,
+
+ map: !! material.map,
+ envMap: !! material.envMap,
+ envMapMode: material.envMap && material.envMap.mapping,
+ lightMap: !! material.lightMap,
+ bumpMap: !! material.bumpMap,
+ normalMap: !! material.normalMap,
+ specularMap: !! material.specularMap,
+ alphaMap: !! material.alphaMap,
+
+ combine: material.combine,
+
+ vertexColors: material.vertexColors,
+
+ fog: fog,
+ useFog: material.fog,
+ fogExp: fog instanceof THREE.FogExp2,
+
+ flatShading: material.shading === THREE.FlatShading,
+
+ sizeAttenuation: material.sizeAttenuation,
+ logarithmicDepthBuffer: _logarithmicDepthBuffer,
+
+ skinning: material.skinning,
+ maxBones: maxBones,
+ useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture,
+
+ morphTargets: material.morphTargets,
+ morphNormals: material.morphNormals,
+ maxMorphTargets: _this.maxMorphTargets,
+ maxMorphNormals: _this.maxMorphNormals,
+
+ maxDirLights: maxLightCount.directional,
+ maxPointLights: maxLightCount.point,
+ maxSpotLights: maxLightCount.spot,
+ maxHemiLights: maxLightCount.hemi,
+
+ maxShadows: maxShadows,
+ shadowMapEnabled: _this.shadowMapEnabled && object.receiveShadow && maxShadows > 0,
+ shadowMapType: _this.shadowMapType,
+ shadowMapDebug: _this.shadowMapDebug,
+ shadowMapCascade: _this.shadowMapCascade,
+
+ alphaTest: material.alphaTest,
+ metal: material.metal,
+ wrapAround: material.wrapAround,
+ doubleSided: material.side === THREE.DoubleSide,
+ flipSided: material.side === THREE.BackSide
+
+ };
+
+ // Generate code
+
+ var chunks = [];
+
+ if ( shaderID ) {
+
+ chunks.push( shaderID );
+
+ } else {
+
+ chunks.push( material.fragmentShader );
+ chunks.push( material.vertexShader );
+
+ }
+
+ if ( material.defines !== undefined ) {
+
+ for ( var name in material.defines ) {
+
+ chunks.push( name );
+ chunks.push( material.defines[ name ] );
+
+ }
+
+ }
+
+ for ( var name in parameters ) {
+
+ chunks.push( name );
+ chunks.push( parameters[ name ] );
+
+ }
+
+ var code = chunks.join();
+
+ var program;
+
+ // Check if code has been already compiled
+
+ for ( var p = 0, pl = _programs.length; p < pl; p ++ ) {
+
+ var programInfo = _programs[ p ];
+
+ if ( programInfo.code === code ) {
+
+ program = programInfo;
+ program.usedTimes ++;
+
+ break;
+
+ }
+
+ }
+
+ if ( program === undefined ) {
+
+ program = new THREE.WebGLProgram( _this, code, material, parameters );
+ _programs.push( program );
+
+ _this.info.memory.programs = _programs.length;
+
+ }
+
+ material.program = program;
+
+ var attributes = program.attributes;
+
+ if ( material.morphTargets ) {
+
+ material.numSupportedMorphTargets = 0;
+
+ var id, base = 'morphTarget';
+
+ for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
+
+ id = base + i;
+
+ if ( attributes[ id ] >= 0 ) {
+
+ material.numSupportedMorphTargets ++;
+
+ }
+
+ }
+
+ }
+
+ if ( material.morphNormals ) {
+
+ material.numSupportedMorphNormals = 0;
+
+ var id, base = 'morphNormal';
+
+ for ( i = 0; i < _this.maxMorphNormals; i ++ ) {
+
+ id = base + i;
+
+ if ( attributes[ id ] >= 0 ) {
+
+ material.numSupportedMorphNormals ++;
+
+ }
+
+ }
+
+ }
+
+ material.uniformsList = [];
+
+ for ( var u in material.__webglShader.uniforms ) {
+
+ var location = material.program.uniforms[ u ];
+
+ if ( location ) {
+ material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
+ }
+
+ }
+
+ }
+
+ function setMaterial( material ) {
+
+ if ( material.transparent === true ) {
+
+ state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha );
+
+ } else {
+
+ state.setBlending( THREE.NoBlending );
+
+ }
+
+ state.setDepthTest( material.depthTest );
+ state.setDepthWrite( material.depthWrite );
+ state.setColorWrite( material.colorWrite );
+ state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
+
+ }
+
+ function setProgram( camera, lights, fog, material, object ) {
+
+ _usedTextureUnits = 0;
+
+ if ( material.needsUpdate ) {
+
+ if ( material.program ) deallocateMaterial( material );
+
+ initMaterial( material, lights, fog, object );
+ material.needsUpdate = false;
+
+ }
+
+ if ( material.morphTargets ) {
+
+ if ( ! object.__webglMorphTargetInfluences ) {
+
+ object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
+
+ }
+
+ }
+
+ var refreshProgram = false;
+ var refreshMaterial = false;
+ var refreshLights = false;
+
+ var program = material.program,
+ p_uniforms = program.uniforms,
+ m_uniforms = material.__webglShader.uniforms;
+
+ if ( program.id !== _currentProgram ) {
+
+ _gl.useProgram( program.program );
+ _currentProgram = program.id;
+
+ refreshProgram = true;
+ refreshMaterial = true;
+ refreshLights = true;
+
+ }
+
+ if ( material.id !== _currentMaterialId ) {
+
+ if ( _currentMaterialId === -1 ) refreshLights = true;
+ _currentMaterialId = material.id;
+
+ refreshMaterial = true;
+
+ }
+
+ if ( refreshProgram || camera !== _currentCamera ) {
+
+ _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
+
+ if ( _logarithmicDepthBuffer ) {
+
+ _gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
+
+ }
+
+
+ if ( camera !== _currentCamera ) _currentCamera = camera;
+
+ // load material specific uniforms
+ // (shader material also gets them for the sake of genericity)
+
+ if ( material instanceof THREE.ShaderMaterial ||
+ material instanceof THREE.MeshPhongMaterial ||
+ material.envMap ) {
+
+ if ( p_uniforms.cameraPosition !== null ) {
+
+ _vector3.setFromMatrixPosition( camera.matrixWorld );
+ _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z );
+
+ }
+
+ }
+
+ if ( material instanceof THREE.MeshPhongMaterial ||
+ material instanceof THREE.MeshLambertMaterial ||
+ material instanceof THREE.MeshBasicMaterial ||
+ material instanceof THREE.ShaderMaterial ||
+ material.skinning ) {
+
+ if ( p_uniforms.viewMatrix !== null ) {
+
+ _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements );
+
+ }
+
+ }
+
+ }
+
+ // skinning uniforms must be set even if material didn't change
+ // auto-setting of texture unit for bone texture must go before other textures
+ // not sure why, but otherwise weird things happen
+
+ if ( material.skinning ) {
+
+ if ( object.bindMatrix && p_uniforms.bindMatrix !== null ) {
+
+ _gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements );
+
+ }
+
+ if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) {
+
+ _gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements );
+
+ }
+
+ if ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) {
+
+ if ( p_uniforms.boneTexture !== null ) {
+
+ var textureUnit = getTextureUnit();
+
+ _gl.uniform1i( p_uniforms.boneTexture, textureUnit );
+ _this.setTexture( object.skeleton.boneTexture, textureUnit );
+
+ }
+
+ if ( p_uniforms.boneTextureWidth !== null ) {
+
+ _gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth );
+
+ }
+
+ if ( p_uniforms.boneTextureHeight !== null ) {
+
+ _gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight );
+
+ }
+
+ } else if ( object.skeleton && object.skeleton.boneMatrices ) {
+
+ if ( p_uniforms.boneGlobalMatrices !== null ) {
+
+ _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices );
+
+ }
+
+ }
+
+ }
+
+ if ( refreshMaterial ) {
+
+ // refresh uniforms common to several materials
+
+ if ( fog && material.fog ) {
+
+ refreshUniformsFog( m_uniforms, fog );
+
+ }
+
+ if ( material instanceof THREE.MeshPhongMaterial ||
+ material instanceof THREE.MeshLambertMaterial ||
+ material.lights ) {
+
+ if ( _lightsNeedUpdate ) {
+
+ refreshLights = true;
+ setupLights( lights );
+ _lightsNeedUpdate = false;
+ }
+
+ if ( refreshLights ) {
+ refreshUniformsLights( m_uniforms, _lights );
+ markUniformsLightsNeedsUpdate( m_uniforms, true );
+ } else {
+ markUniformsLightsNeedsUpdate( m_uniforms, false );
+ }
+
+ }
+
+ if ( material instanceof THREE.MeshBasicMaterial ||
+ material instanceof THREE.MeshLambertMaterial ||
+ material instanceof THREE.MeshPhongMaterial ) {
+
+ refreshUniformsCommon( m_uniforms, material );
+
+ }
+
+ // refresh single material specific uniforms
+
+ if ( material instanceof THREE.LineBasicMaterial ) {
+
+ refreshUniformsLine( m_uniforms, material );
+
+ } else if ( material instanceof THREE.LineDashedMaterial ) {
+
+ refreshUniformsLine( m_uniforms, material );
+ refreshUniformsDash( m_uniforms, material );
+
+ } else if ( material instanceof THREE.PointCloudMaterial ) {
+
+ refreshUniformsParticle( m_uniforms, material );
+
+ } else if ( material instanceof THREE.MeshPhongMaterial ) {
+
+ refreshUniformsPhong( m_uniforms, material );
+
+ } else if ( material instanceof THREE.MeshLambertMaterial ) {
+
+ refreshUniformsLambert( m_uniforms, material );
+
+ } else if ( material instanceof THREE.MeshDepthMaterial ) {
+
+ m_uniforms.mNear.value = camera.near;
+ m_uniforms.mFar.value = camera.far;
+ m_uniforms.opacity.value = material.opacity;
+
+ } else if ( material instanceof THREE.MeshNormalMaterial ) {
+
+ m_uniforms.opacity.value = material.opacity;
+
+ }
+
+ if ( object.receiveShadow && ! material._shadowPass ) {
+
+ refreshUniformsShadow( m_uniforms, lights );
+
+ }
+
+ // load common uniforms
+
+ loadUniformsGeneric( material.uniformsList );
+
+ }
+
+ loadUniformsMatrices( p_uniforms, object );
+
+ if ( p_uniforms.modelMatrix !== null ) {
+
+ _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements );
+
+ }
+
+ return program;
+
+ }
+
+ // Uniforms (refresh uniforms objects)
+
+ function refreshUniformsCommon ( uniforms, material ) {
+
+ uniforms.opacity.value = material.opacity;
+
+ uniforms.diffuse.value = material.color;
+
+ uniforms.map.value = material.map;
+ uniforms.lightMap.value = material.lightMap;
+ uniforms.specularMap.value = material.specularMap;
+ uniforms.alphaMap.value = material.alphaMap;
+
+ if ( material.bumpMap ) {
+
+ uniforms.bumpMap.value = material.bumpMap;
+ uniforms.bumpScale.value = material.bumpScale;
+
+ }
+
+ if ( material.normalMap ) {
+
+ uniforms.normalMap.value = material.normalMap;
+ uniforms.normalScale.value.copy( material.normalScale );
+
+ }
+
+ // uv repeat and offset setting priorities
+ // 1. color map
+ // 2. specular map
+ // 3. normal map
+ // 4. bump map
+ // 5. alpha map
+
+ var uvScaleMap;
+
+ if ( material.map ) {
+
+ uvScaleMap = material.map;
+
+ } else if ( material.specularMap ) {
+
+ uvScaleMap = material.specularMap;
+
+ } else if ( material.normalMap ) {
+
+ uvScaleMap = material.normalMap;
+
+ } else if ( material.bumpMap ) {
+
+ uvScaleMap = material.bumpMap;
+
+ } else if ( material.alphaMap ) {
+
+ uvScaleMap = material.alphaMap;
+
+ }
+
+ if ( uvScaleMap !== undefined ) {
+
+ var offset = uvScaleMap.offset;
+ var repeat = uvScaleMap.repeat;
+
+ uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
+
+ }
+
+ uniforms.envMap.value = material.envMap;
+ uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1;
+
+ uniforms.reflectivity.value = material.reflectivity;
+ uniforms.refractionRatio.value = material.refractionRatio;
+
+ }
+
+ function refreshUniformsLine ( uniforms, material ) {
+
+ uniforms.diffuse.value = material.color;
+ uniforms.opacity.value = material.opacity;
+
+ }
+
+ function refreshUniformsDash ( uniforms, material ) {
+
+ uniforms.dashSize.value = material.dashSize;
+ uniforms.totalSize.value = material.dashSize + material.gapSize;
+ uniforms.scale.value = material.scale;
+
+ }
+
+ function refreshUniformsParticle ( uniforms, material ) {
+
+ uniforms.psColor.value = material.color;
+ uniforms.opacity.value = material.opacity;
+ uniforms.size.value = material.size;
+ uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this.
+
+ uniforms.map.value = material.map;
+
+ if ( material.map !== null ) {
+
+ var offset = material.map.offset;
+ var repeat = material.map.repeat;
+
+ uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
+
+ }
+
+ }
+
+ function refreshUniformsFog ( uniforms, fog ) {
+
+ uniforms.fogColor.value = fog.color;
+
+ if ( fog instanceof THREE.Fog ) {
+
+ uniforms.fogNear.value = fog.near;
+ uniforms.fogFar.value = fog.far;
+
+ } else if ( fog instanceof THREE.FogExp2 ) {
+
+ uniforms.fogDensity.value = fog.density;
+
+ }
+
+ }
+
+ function refreshUniformsPhong ( uniforms, material ) {
+
+ uniforms.shininess.value = material.shininess;
+
+ uniforms.emissive.value = material.emissive;
+ uniforms.specular.value = material.specular;
+
+ if ( material.wrapAround ) {
+
+ uniforms.wrapRGB.value.copy( material.wrapRGB );
+
+ }
+
+ }
+
+ function refreshUniformsLambert ( uniforms, material ) {
+
+ uniforms.emissive.value = material.emissive;
+
+ if ( material.wrapAround ) {
+
+ uniforms.wrapRGB.value.copy( material.wrapRGB );
+
+ }
+
+ }
+
+ function refreshUniformsLights ( uniforms, lights ) {
+
+ uniforms.ambientLightColor.value = lights.ambient;
+
+ uniforms.directionalLightColor.value = lights.directional.colors;
+ uniforms.directionalLightDirection.value = lights.directional.positions;
+
+ uniforms.pointLightColor.value = lights.point.colors;
+ uniforms.pointLightPosition.value = lights.point.positions;
+ uniforms.pointLightDistance.value = lights.point.distances;
+ uniforms.pointLightDecay.value = lights.point.decays;
+
+ uniforms.spotLightColor.value = lights.spot.colors;
+ uniforms.spotLightPosition.value = lights.spot.positions;
+ uniforms.spotLightDistance.value = lights.spot.distances;
+ uniforms.spotLightDirection.value = lights.spot.directions;
+ uniforms.spotLightAngleCos.value = lights.spot.anglesCos;
+ uniforms.spotLightExponent.value = lights.spot.exponents;
+ uniforms.spotLightDecay.value = lights.spot.decays;
+
+ uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;
+ uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
+ uniforms.hemisphereLightDirection.value = lights.hemi.positions;
+
+ }
+
+ // If uniforms are marked as clean, they don't need to be loaded to the GPU.
+
+ function markUniformsLightsNeedsUpdate ( uniforms, value ) {
+
+ uniforms.ambientLightColor.needsUpdate = value;
+
+ uniforms.directionalLightColor.needsUpdate = value;
+ uniforms.directionalLightDirection.needsUpdate = value;
+
+ uniforms.pointLightColor.needsUpdate = value;
+ uniforms.pointLightPosition.needsUpdate = value;
+ uniforms.pointLightDistance.needsUpdate = value;
+ uniforms.pointLightDecay.needsUpdate = value;
+
+ uniforms.spotLightColor.needsUpdate = value;
+ uniforms.spotLightPosition.needsUpdate = value;
+ uniforms.spotLightDistance.needsUpdate = value;
+ uniforms.spotLightDirection.needsUpdate = value;
+ uniforms.spotLightAngleCos.needsUpdate = value;
+ uniforms.spotLightExponent.needsUpdate = value;
+ uniforms.spotLightDecay.needsUpdate = value;
+
+ uniforms.hemisphereLightSkyColor.needsUpdate = value;
+ uniforms.hemisphereLightGroundColor.needsUpdate = value;
+ uniforms.hemisphereLightDirection.needsUpdate = value;
+
+ }
+
+ function refreshUniformsShadow ( uniforms, lights ) {
+
+ if ( uniforms.shadowMatrix ) {
+
+ var j = 0;
+
+ for ( var i = 0, il = lights.length; i < il; i ++ ) {
+
+ var light = lights[ i ];
+
+ if ( ! light.castShadow ) continue;
+
+ if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) {
+
+ uniforms.shadowMap.value[ j ] = light.shadowMap;
+ uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
+
+ uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
+
+ uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
+ uniforms.shadowBias.value[ j ] = light.shadowBias;
+
+ j ++;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Uniforms (load to GPU)
+
+ function loadUniformsMatrices ( uniforms, object ) {
+
+ _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements );
+
+ if ( uniforms.normalMatrix ) {
+
+ _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements );
+
+ }
+
+ }
+
+ function getTextureUnit() {
+
+ var textureUnit = _usedTextureUnits;
+
+ if ( textureUnit >= _maxTextures ) {
+
+ THREE.warn( 'Canvas3DRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures );
+
+ }
+
+ _usedTextureUnits += 1;
+
+ return textureUnit;
+
+ }
+
+ function loadUniformsGeneric ( uniforms ) {
+
+ var texture, textureUnit, offset;
+
+ for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) {
+
+ var uniform = uniforms[ j ][ 0 ];
+
+ // needsUpdate property is not added to all uniforms.
+ if ( uniform.needsUpdate === false ) continue;
+
+ var type = uniform.type;
+ var value = uniform.value;
+ var location = uniforms[ j ][ 1 ];
+
+ switch ( type ) {
+
+ case '1i':
+ _gl.uniform1i( location, value );
+ break;
+
+ case '1f':
+ _gl.uniform1f( location, value );
+ break;
+
+ case '2f':
+ _gl.uniform2f( location, value[ 0 ], value[ 1 ] );
+ break;
+
+ case '3f':
+ _gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] );
+ break;
+
+ case '4f':
+ _gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] );
+ break;
+
+ case '1iv':
+ _gl.uniform1iv( location, value );
+ break;
+
+ case '3iv':
+ _gl.uniform3iv( location, value );
+ break;
+
+ case '1fv':
+ _gl.uniform1fv( location, value );
+ break;
+
+ case '2fv':
+ _gl.uniform2fv( location, value );
+ break;
+
+ case '3fv':
+ _gl.uniform3fv( location, value );
+ break;
+
+ case '4fv':
+ _gl.uniform4fv( location, value );
+ break;
+
+ case 'Matrix3fv':
+ _gl.uniformMatrix3fv( location, false, value );
+ break;
+
+ case 'Matrix4fv':
+ _gl.uniformMatrix4fv( location, false, value );
+ break;
+
+ //
+
+ case 'i':
+
+ // single integer
+ _gl.uniform1i( location, value );
+
+ break;
+
+ case 'f':
+
+ // single float
+ _gl.uniform1f( location, value );
+
+ break;
+
+ case 'v2':
+
+ // single THREE.Vector2
+ _gl.uniform2f( location, value.x, value.y );
+
+ break;
+
+ case 'v3':
+
+ // single THREE.Vector3
+ _gl.uniform3f( location, value.x, value.y, value.z );
+
+ break;
+
+ case 'v4':
+
+ // single THREE.Vector4
+ _gl.uniform4f( location, value.x, value.y, value.z, value.w );
+
+ break;
+
+ case 'c':
+
+ // single THREE.Color
+ _gl.uniform3f( location, value.r, value.g, value.b );
+
+ break;
+
+ case 'iv1':
+
+ // flat array of integers (JS or typed array)
+ _gl.uniform1iv( location, value );
+
+ break;
+
+ case 'iv':
+
+ // flat array of integers with 3 x N size (JS or typed array)
+ _gl.uniform3iv( location, value );
+
+ break;
+
+ case 'fv1':
+
+ // flat array of floats (JS or typed array)
+ _gl.uniform1fv( location, value );
+
+ break;
+
+ case 'fv':
+
+ // flat array of floats with 3 x N size (JS or typed array)
+ _gl.uniform3fv( location, value );
+
+ break;
+
+ case 'v2v':
+
+ // array of THREE.Vector2
+
+ if ( uniform._array === undefined ) {
+
+ uniform._array = new Float32Array( 2 * value.length );
+
+ }
+
+ for ( var i = 0, il = value.length; i < il; i ++ ) {
+
+ offset = i * 2;
+
+ uniform._array[ offset ] = value[ i ].x;
+ uniform._array[ offset + 1 ] = value[ i ].y;
+
+ }
+
+ _gl.uniform2fv( location, uniform._array );
+
+ break;
+
+ case 'v3v':
+
+ // array of THREE.Vector3
+
+ if ( uniform._array === undefined ) {
+
+ uniform._array = new Float32Array( 3 * value.length );
+
+ }
+
+ for ( var i = 0, il = value.length; i < il; i ++ ) {
+
+ offset = i * 3;
+
+ uniform._array[ offset ] = value[ i ].x;
+ uniform._array[ offset + 1 ] = value[ i ].y;
+ uniform._array[ offset + 2 ] = value[ i ].z;
+
+ }
+
+ _gl.uniform3fv( location, uniform._array );
+
+ break;
+
+ case 'v4v':
+
+ // array of THREE.Vector4
+
+ if ( uniform._array === undefined ) {
+
+ uniform._array = new Float32Array( 4 * value.length );
+
+ }
+
+ for ( var i = 0, il = value.length; i < il; i ++ ) {
+
+ offset = i * 4;
+
+ uniform._array[ offset ] = value[ i ].x;
+ uniform._array[ offset + 1 ] = value[ i ].y;
+ uniform._array[ offset + 2 ] = value[ i ].z;
+ uniform._array[ offset + 3 ] = value[ i ].w;
+
+ }
+
+ _gl.uniform4fv( location, uniform._array );
+
+ break;
+
+ case 'm3':
+
+ // single THREE.Matrix3
+ _gl.uniformMatrix3fv( location, false, value.elements );
+
+ break;
+
+ case 'm3v':
+
+ // array of THREE.Matrix3
+
+ if ( uniform._array === undefined ) {
+
+ uniform._array = new Float32Array( 9 * value.length );
+
+ }
+
+ for ( var i = 0, il = value.length; i < il; i ++ ) {
+
+ value[ i ].flattenToArrayOffset( uniform._array, i * 9 );
+
+ }
+
+ _gl.uniformMatrix3fv( location, false, uniform._array );
+
+ break;
+
+ case 'm4':
+
+ // single THREE.Matrix4
+ _gl.uniformMatrix4fv( location, false, value.elements );
+
+ break;
+
+ case 'm4v':
+
+ // array of THREE.Matrix4
+
+ if ( uniform._array === undefined ) {
+
+ uniform._array = new Float32Array( 16 * value.length );
+
+ }
+
+ for ( var i = 0, il = value.length; i < il; i ++ ) {
+
+ value[ i ].flattenToArrayOffset( uniform._array, i * 16 );
+
+ }
+
+ _gl.uniformMatrix4fv( location, false, uniform._array );
+
+ break;
+
+ case 't':
+
+ // single THREE.Texture (2d or cube)
+
+ texture = value;
+ textureUnit = getTextureUnit();
+
+ _gl.uniform1i( location, textureUnit );
+
+ if ( ! texture ) continue;
+
+ if ( texture instanceof THREE.CubeTexture ||
+ ( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/
+
+ setCubeTexture( texture, textureUnit );
+
+ } else if ( texture instanceof THREE.WebGLRenderTargetCube ) {
+
+ setCubeTextureDynamic( texture, textureUnit );
+
+ } else {
+
+ _this.setTexture( texture, textureUnit );
+
+ }
+
+ break;
+
+ case 'tv':
+
+ // array of THREE.Texture (2d)
+
+ if ( uniform._array === undefined ) {
+
+ uniform._array = [];
+
+ }
+
+ for ( var i = 0, il = uniform.value.length; i < il; i ++ ) {
+
+ uniform._array[ i ] = getTextureUnit();
+
+ }
+
+ _gl.uniform1iv( location, uniform._array );
+
+ for ( var i = 0, il = uniform.value.length; i < il; i ++ ) {
+
+ texture = uniform.value[ i ];
+ textureUnit = uniform._array[ i ];
+
+ if ( ! texture ) continue;
+
+ _this.setTexture( texture, textureUnit );
+
+ }
+
+ break;
+
+ default:
+
+ THREE.warn( 'THREE.Canvas3DRenderer: Unknown uniform type: ' + type );
+
+ }
+
+ }
+
+ }
+
+ function setupMatrices ( object, camera ) {
+
+ object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
+ object._normalMatrix.getNormalMatrix( object._modelViewMatrix );
+
+ }
+
+ function setColorLinear( array, offset, color, intensity ) {
+
+ array[ offset ] = color.r * intensity;
+ array[ offset + 1 ] = color.g * intensity;
+ array[ offset + 2 ] = color.b * intensity;
+
+ }
+
+ function setupLights ( lights ) {
+
+ var l, ll, light,
+ r = 0, g = 0, b = 0,
+ color, skyColor, groundColor,
+ intensity,
+ distance,
+
+ zlights = _lights,
+
+ dirColors = zlights.directional.colors,
+ dirPositions = zlights.directional.positions,
+
+ pointColors = zlights.point.colors,
+ pointPositions = zlights.point.positions,
+ pointDistances = zlights.point.distances,
+ pointDecays = zlights.point.decays,
+
+ spotColors = zlights.spot.colors,
+ spotPositions = zlights.spot.positions,
+ spotDistances = zlights.spot.distances,
+ spotDirections = zlights.spot.directions,
+ spotAnglesCos = zlights.spot.anglesCos,
+ spotExponents = zlights.spot.exponents,
+ spotDecays = zlights.spot.decays,
+
+ hemiSkyColors = zlights.hemi.skyColors,
+ hemiGroundColors = zlights.hemi.groundColors,
+ hemiPositions = zlights.hemi.positions,
+
+ dirLength = 0,
+ pointLength = 0,
+ spotLength = 0,
+ hemiLength = 0,
+
+ dirCount = 0,
+ pointCount = 0,
+ spotCount = 0,
+ hemiCount = 0,
+
+ dirOffset = 0,
+ pointOffset = 0,
+ spotOffset = 0,
+ hemiOffset = 0;
+
+ for ( l = 0, ll = lights.length; l < ll; l ++ ) {
+
+ light = lights[ l ];
+
+ if ( light.onlyShadow ) continue;
+
+ color = light.color;
+ intensity = light.intensity;
+ distance = light.distance;
+
+ if ( light instanceof THREE.AmbientLight ) {
+
+ if ( ! light.visible ) continue;
+
+ r += color.r;
+ g += color.g;
+ b += color.b;
+
+ } else if ( light instanceof THREE.DirectionalLight ) {
+
+ dirCount += 1;
+
+ if ( ! light.visible ) continue;
+
+ _direction.setFromMatrixPosition( light.matrixWorld );
+ _vector3.setFromMatrixPosition( light.target.matrixWorld );
+ _direction.sub( _vector3 );
+ _direction.normalize();
+
+ dirOffset = dirLength * 3;
+
+ dirPositions[ dirOffset ] = _direction.x;
+ dirPositions[ dirOffset + 1 ] = _direction.y;
+ dirPositions[ dirOffset + 2 ] = _direction.z;
+
+ setColorLinear( dirColors, dirOffset, color, intensity );
+
+ dirLength += 1;
+
+ } else if ( light instanceof THREE.PointLight ) {
+
+ pointCount += 1;
+
+ if ( ! light.visible ) continue;
+
+ pointOffset = pointLength * 3;
+
+ setColorLinear( pointColors, pointOffset, color, intensity );
+
+ _vector3.setFromMatrixPosition( light.matrixWorld );
+
+ pointPositions[ pointOffset ] = _vector3.x;
+ pointPositions[ pointOffset + 1 ] = _vector3.y;
+ pointPositions[ pointOffset + 2 ] = _vector3.z;
+
+ // distance is 0 if decay is 0, because there is no attenuation at all.
+ pointDistances[ pointLength ] = distance;
+ pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay;
+
+ pointLength += 1;
+
+ } else if ( light instanceof THREE.SpotLight ) {
+
+ spotCount += 1;
+
+ if ( ! light.visible ) continue;
+
+ spotOffset = spotLength * 3;
+
+ setColorLinear( spotColors, spotOffset, color, intensity );
+
+ _direction.setFromMatrixPosition( light.matrixWorld );
+
+ spotPositions[ spotOffset ] = _direction.x;
+ spotPositions[ spotOffset + 1 ] = _direction.y;
+ spotPositions[ spotOffset + 2 ] = _direction.z;
+
+ spotDistances[ spotLength ] = distance;
+
+ _vector3.setFromMatrixPosition( light.target.matrixWorld );
+ _direction.sub( _vector3 );
+ _direction.normalize();
+
+ spotDirections[ spotOffset ] = _direction.x;
+ spotDirections[ spotOffset + 1 ] = _direction.y;
+ spotDirections[ spotOffset + 2 ] = _direction.z;
+
+ spotAnglesCos[ spotLength ] = Math.cos( light.angle );
+ spotExponents[ spotLength ] = light.exponent;
+ spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay;
+
+ spotLength += 1;
+
+ } else if ( light instanceof THREE.HemisphereLight ) {
+
+ hemiCount += 1;
+
+ if ( ! light.visible ) continue;
+
+ _direction.setFromMatrixPosition( light.matrixWorld );
+ _direction.normalize();
+
+ hemiOffset = hemiLength * 3;
+
+ hemiPositions[ hemiOffset ] = _direction.x;
+ hemiPositions[ hemiOffset + 1 ] = _direction.y;
+ hemiPositions[ hemiOffset + 2 ] = _direction.z;
+
+ skyColor = light.color;
+ groundColor = light.groundColor;
+
+ setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity );
+ setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity );
+
+ hemiLength += 1;
+
+ }
+
+ }
+
+ // null eventual remains from removed lights
+ // (this is to avoid if in shader)
+
+ for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0;
+ for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0;
+ for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0;
+ for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0;
+ for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0;
+
+ zlights.directional.length = dirLength;
+ zlights.point.length = pointLength;
+ zlights.spot.length = spotLength;
+ zlights.hemi.length = hemiLength;
+
+ zlights.ambient[ 0 ] = r;
+ zlights.ambient[ 1 ] = g;
+ zlights.ambient[ 2 ] = b;
+
+ }
+
+ // GL state setting
+
+ this.setFaceCulling = function ( cullFace, frontFaceDirection ) {
+
+ if ( cullFace === THREE.CullFaceNone ) {
+
+ _gl.disable( _gl.CULL_FACE );
+
+ } else {
+
+ if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) {
+
+ _gl.frontFace( _gl.CW );
+
+ } else {
+
+ _gl.frontFace( _gl.CCW );
+
+ }
+
+ if ( cullFace === THREE.CullFaceBack ) {
+
+ _gl.cullFace( _gl.BACK );
+
+ } else if ( cullFace === THREE.CullFaceFront ) {
+
+ _gl.cullFace( _gl.FRONT );
+
+ } else {
+
+ _gl.cullFace( _gl.FRONT_AND_BACK );
+
+ }
+
+ _gl.enable( _gl.CULL_FACE );
+
+ }
+
+ };
+
+ this.setMaterialFaces = function ( material ) {
+
+ state.setDoubleSided( material.side === THREE.DoubleSide );
+ state.setFlipSided( material.side === THREE.BackSide );
+
+ };
+
+ // Textures
+
+ function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
+
+ var extension;
+
+ if ( isImagePowerOfTwo ) {
+
+ _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
+ _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
+
+ _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
+ _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
+
+ } else {
+
+ _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
+ _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
+
+ if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) {
+
+ THREE.warn( 'THREE.Canvas3DRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' );
+
+ }
+
+ _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
+ _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
+
+ if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) {
+
+ THREE.warn( 'THREE.Canvas3DRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' );
+
+ }
+
+ }
+
+ extension = extensions.get( 'EXT_texture_filter_anisotropic' );
+
+ if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) {
+
+ if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) {
+
+ _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) );
+ texture.__currentAnisotropy = texture.anisotropy;
+
+ }
+
+ }
+
+ }
+
+ this.uploadTexture = function ( texture ) {
+
+ if ( texture instanceof THREE.QtQuickItemTexture ) {
+
+ var canvasTextureProvider = _gl.getExtension("QTCANVAS3D_texture_provider");
+
+ texture.__webglInit = true;
+
+ if ( canvasTextureProvider !== null )
+ texture.__webglTexture = canvasTextureProvider.createTextureFromSource(texture.quickItem);
+ else
+ texture.__webglTexture = 0;
+
+ _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+
+ var isImagePowerOfTwo = THREE.Math.isPowerOfTwo( texture.quickItem.width ) && THREE.Math.isPowerOfTwo( texture.quickItem.height );
+
+ if (isImagePowerOfTwo) {
+ _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
+ _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
+ } else if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) {
+ THREE.warn( 'THREE.Canvas3DRenderer: Quick item width and/or height are not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
+ }
+ } else {
+
+ if ( texture.__webglInit === undefined ) {
+
+ texture.__webglInit = true;
+
+ texture.addEventListener( 'dispose', onTextureDispose );
+
+ texture.__webglTexture = _gl.createTexture();
+
+ _this.info.memory.textures ++;
+
+ }
+
+ _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+
+ _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
+ _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
+ _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
+
+ texture.image = clampToMaxSize( texture.image, _maxTextureSize );
+
+ var image = texture.image,
+ isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
+ glFormat = paramThreeToGL( texture.format ),
+ glType = paramThreeToGL( texture.type );
+
+ setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
+
+ var mipmap, mipmaps = texture.mipmaps;
+
+ if ( texture instanceof THREE.DataTexture ) {
+
+ // use manually created mipmaps if available
+ // if there are no manual mipmaps
+ // set 0 level mipmap and then use GL to generate other mipmap levels
+
+ if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
+
+ for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
+
+ mipmap = mipmaps[ i ];
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
+
+ }
+
+ texture.generateMipmaps = false;
+
+ } else {
+
+ _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
+
+ }
+
+ } else if ( texture instanceof THREE.CompressedTexture ) {
+
+ for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
+
+ mipmap = mipmaps[ i ];
+
+ if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {
+
+ if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {
+
+ _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
+
+ } else {
+
+ THREE.warn( "THREE.Canvas3DRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" );
+
+ }
+
+ } else {
+
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
+
+ }
+
+ }
+
+ } else { // regular Texture (image, video, canvas)
+
+ // use manually created mipmaps if available
+ // if there are no manual mipmaps
+ // set 0 level mipmap and then use GL to generate other mipmap levels
+
+ if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
+
+ for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
+
+ mipmap = mipmaps[ i ];
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
+
+ }
+
+ texture.generateMipmaps = false;
+
+ } else {
+
+ _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image.texImage() );
+
+ }
+
+ }
+
+ if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
+ }
+
+ texture.needsUpdate = false;
+
+ if ( texture.onUpdate ) texture.onUpdate();
+
+ };
+
+ this.setTexture = function ( texture, slot ) {
+
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
+
+ if ( texture.needsUpdate ) {
+
+ _this.uploadTexture( texture );
+
+ } else {
+
+ _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+
+ }
+
+ };
+
+ function clampToMaxSize ( image, maxSize ) {
+
+ if ( image.width > maxSize || image.height > maxSize ) {
+
+ // Warning: Scaling through the canvas will only work with images that use
+ // premultiplied alpha.
+
+ var scale = maxSize / Math.max( image.width, image.height );
+
+ var canvasWidth = Math.floor( image.width * scale );
+ var canvasHeight = Math.floor( image.height * scale );
+ var canvas = image.resize( canvasWidth, canvasHeight );
+
+
+ THREE.warn( 'THREE.Canvas3DRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvasWidth + 'x' + canvasHeight, image );
+
+ return canvas;
+
+ }
+
+ return image;
+
+ }
+
+ function setCubeTexture ( texture, slot ) {
+
+ if ( texture.image.length === 6 ) {
+
+ if ( texture.needsUpdate ) {
+
+ if ( ! texture.image.__webglTextureCube ) {
+
+ texture.addEventListener( 'dispose', onTextureDispose );
+
+ texture.image.__webglTextureCube = _gl.createTexture();
+
+ _this.info.memory.textures ++;
+
+ }
+
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
+
+ _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
+
+ var isCompressed = texture instanceof THREE.CompressedTexture;
+ var isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture;
+
+ var cubeImage = [];
+
+ for ( var i = 0; i < 6; i ++ ) {
+
+ if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) {
+
+ cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
+
+ } else {
+
+ cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
+
+ }
+
+ }
+
+ var image = cubeImage[ 0 ],
+ isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
+ glFormat = paramThreeToGL( texture.format ),
+ glType = paramThreeToGL( texture.type );
+
+ setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
+
+ for ( var i = 0; i < 6; i ++ ) {
+
+ if ( ! isCompressed ) {
+
+ if ( isDataTexture ) {
+
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
+
+ } else {
+
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ].texImage() );
+
+ }
+
+ } else {
+
+ var mipmap, mipmaps = cubeImage[ i ].mipmaps;
+
+ for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
+
+ mipmap = mipmaps[ j ];
+
+ if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {
+
+ if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {
+
+ _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
+
+ } else {
+
+ THREE.warn( "THREE.Canvas3DRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" );
+
+ }
+
+ } else {
+
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if ( texture.generateMipmaps && isImagePowerOfTwo ) {
+
+ _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
+
+ }
+
+ texture.needsUpdate = false;
+
+ if ( texture.onUpdate ) texture.onUpdate();
+
+ } else {
+
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
+
+ }
+
+ }
+
+ }
+
+ function setCubeTextureDynamic ( texture, slot ) {
+
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
+
+ }
+
+ // Render targets
+
+ function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
+
+ _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+ _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
+
+ }
+
+ function setupRenderBuffer ( renderbuffer, renderTarget ) {
+
+ _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
+
+ if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
+
+ _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
+
+ /* For some reason this is not working. Defaulting to RGBA4.
+ } else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
+
+ _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
+ */
+ } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
+
+ _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
+
+ } else {
+
+ _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
+
+ }
+
+ }
+
+ this.setRenderTarget = function ( renderTarget ) {
+
+ var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
+
+ if ( renderTarget && renderTarget.__webglFramebuffer === undefined ) {
+
+ if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
+ if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
+
+ renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
+
+ renderTarget.__webglTexture = _gl.createTexture();
+
+ _this.info.memory.textures ++;
+
+ // Setup texture, create render and frame buffers
+
+ var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ),
+ glFormat = paramThreeToGL( renderTarget.format ),
+ glType = paramThreeToGL( renderTarget.type );
+
+ if ( isCube ) {
+
+ renderTarget.__webglFramebuffer = [];
+ renderTarget.__webglRenderbuffer = [];
+
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
+ setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
+
+ for ( var i = 0; i < 6; i ++ ) {
+
+ renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
+ renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
+
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
+
+ setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
+ setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
+
+ }
+
+ if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
+
+ } else {
+
+ renderTarget.__webglFramebuffer = _gl.createFramebuffer();
+
+ if ( renderTarget.shareDepthFrom ) {
+
+ renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
+
+ } else {
+
+ renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
+
+ }
+
+ _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
+ setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
+
+ _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
+
+ setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
+
+ if ( renderTarget.shareDepthFrom ) {
+
+ if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
+
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
+
+ } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
+
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
+
+ }
+
+ } else {
+
+ setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
+
+ }
+
+ if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
+
+ }
+
+ // Release everything
+
+ if ( isCube ) {
+
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
+
+ } else {
+
+ _gl.bindTexture( _gl.TEXTURE_2D, null );
+
+ }
+
+ _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
+ _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
+
+ }
+
+ var framebuffer, width, height, vx, vy;
+
+ if ( renderTarget ) {
+
+ if ( isCube ) {
+
+ framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
+
+ } else {
+
+ framebuffer = renderTarget.__webglFramebuffer;
+
+ }
+
+ width = renderTarget.width;
+ height = renderTarget.height;
+
+ vx = 0;
+ vy = 0;
+
+ } else {
+
+ framebuffer = null;
+
+ width = _viewportWidth;
+ height = _viewportHeight;
+
+ vx = _viewportX;
+ vy = _viewportY;
+
+ }
+
+ if ( framebuffer !== _currentFramebuffer ) {
+
+ _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+ _gl.viewport( vx, vy, width, height );
+
+ _currentFramebuffer = framebuffer;
+
+ }
+
+ _currentWidth = width;
+ _currentHeight = height;
+
+ };
+
+ this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) {
+
+ if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) {
+
+ console.error( 'THREE.Canvas3DRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
+ return;
+
+ }
+
+ if ( renderTarget.__webglFramebuffer ) {
+
+ if ( renderTarget.format !== THREE.RGBAFormat ) {
+
+ console.error( 'THREE.Canvas3DRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' );
+ return;
+
+ }
+
+ var restore = false;
+
+ if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) {
+
+ _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer );
+
+ restore = true;
+
+ }
+
+ if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {
+
+ _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer );
+
+ } else {
+
+ console.error( 'THREE.Canvas3DRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
+
+ }
+
+ if ( restore ) {
+
+ _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
+
+ }
+
+ }
+
+ };
+
+ function updateRenderTargetMipmap ( renderTarget ) {
+
+ if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
+
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
+ _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
+
+ } else {
+
+ _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
+ _gl.generateMipmap( _gl.TEXTURE_2D );
+ _gl.bindTexture( _gl.TEXTURE_2D, null );
+
+ }
+
+ }
+
+ // Fallback filters for non-power-of-2 textures
+
+ function filterFallback ( f ) {
+
+ if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
+
+ return _gl.NEAREST;
+
+ }
+
+ return _gl.LINEAR;
+
+ }
+
+ // Map three.js constants to WebGL constants
+
+ function paramThreeToGL ( p ) {
+
+ var extension;
+
+ if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
+ if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
+ if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
+
+ if ( p === THREE.NearestFilter ) return _gl.NEAREST;
+ if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
+ if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
+
+ if ( p === THREE.LinearFilter ) return _gl.LINEAR;
+ if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
+ if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
+
+ if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
+ if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
+ if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
+ if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
+
+ if ( p === THREE.ByteType ) return _gl.BYTE;
+ if ( p === THREE.ShortType ) return _gl.SHORT;
+ if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
+ if ( p === THREE.IntType ) return _gl.INT;
+ if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
+ if ( p === THREE.FloatType ) return _gl.FLOAT;
+
+ extension = extensions.get( 'OES_texture_half_float' );
+
+ if ( extension !== null ) {
+
+ if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES;
+
+ }
+
+ if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
+ if ( p === THREE.RGBFormat ) return _gl.RGB;
+ if ( p === THREE.RGBAFormat ) return _gl.RGBA;
+ if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
+ if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
+
+ if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
+ if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
+ if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
+
+ if ( p === THREE.ZeroFactor ) return _gl.ZERO;
+ if ( p === THREE.OneFactor ) return _gl.ONE;
+ if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
+ if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
+ if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
+ if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
+ if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
+ if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
+
+ if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
+ if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
+ if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
+
+ extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
+
+ if ( extension !== null ) {
+
+ if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
+ if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+
+ }
+
+ extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
+
+ if ( extension !== null ) {
+
+ if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+ if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
+ if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+ if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+
+ }
+
+ extension = extensions.get( 'EXT_blend_minmax' );
+
+ if ( extension !== null ) {
+
+ if ( p === THREE.MinEquation ) return extension.MIN_EXT;
+ if ( p === THREE.MaxEquation ) return extension.MAX_EXT;
+
+ }
+
+ return 0;
+
+ }
+
+ // Allocations
+
+ function allocateBones ( object ) {
+
+ if ( _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture ) {
+
+ return 1024;
+
+ } else {
+
+ // default for when object is not specified
+ // ( for example when prebuilding shader
+ // to be used with multiple objects )
+ //
+ // - leave some extra space for other uniforms
+ // - limit here is ANGLE's 254 max uniform vectors
+ // (up to 54 should be safe)
+
+ var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
+ var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
+
+ var maxBones = nVertexMatrices;
+
+ if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
+
+ maxBones = Math.min( object.skeleton.bones.length, maxBones );
+
+ if ( maxBones < object.skeleton.bones.length ) {
+
+ THREE.warn( 'Canvas3DRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' );
+
+ }
+
+ }
+
+ return maxBones;
+
+ }
+
+ }
+
+ function allocateLights( lights ) {
+
+ var dirLights = 0;
+ var pointLights = 0;
+ var spotLights = 0;
+ var hemiLights = 0;
+
+ for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
+
+ var light = lights[ l ];
+
+ if ( light.onlyShadow || light.visible === false ) continue;
+
+ if ( light instanceof THREE.DirectionalLight ) dirLights ++;
+ if ( light instanceof THREE.PointLight ) pointLights ++;
+ if ( light instanceof THREE.SpotLight ) spotLights ++;
+ if ( light instanceof THREE.HemisphereLight ) hemiLights ++;
+
+ }
+
+ return { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights };
+
+ }
+
+ function allocateShadows( lights ) {
+
+ var maxShadows = 0;
+
+ for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
+
+ var light = lights[ l ];
+
+ if ( ! light.castShadow ) continue;
+
+ if ( light instanceof THREE.SpotLight ) maxShadows ++;
+ if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;
+
+ }
+
+ return maxShadows;
+
+ }
+
+ // DEPRECATED
+
+ this.initMaterial = function () {
+
+ THREE.warn( 'THREE.Canvas3DRenderer: .initMaterial() has been removed.' );
+
+ };
+
+ this.addPrePlugin = function () {
+
+ THREE.warn( 'THREE.Canvas3DRenderer: .addPrePlugin() has been removed.' );
+
+ };
+
+ this.addPostPlugin = function () {
+
+ THREE.warn( 'THREE.Canvas3DRenderer: .addPostPlugin() has been removed.' );
+
+ };
+
+ this.updateShadowMap = function () {
+
+ THREE.warn( 'THREE.Canvas3DRenderer: .updateShadowMap() has been removed.' );
+
+ };
+
+};
+
+// File:src/qml/QtQuickItemTexture.js
+
+/**
+ * @author miheikki / miikka.heikkinen@theqtcompany.com
+ */
+
+THREE.QtQuickItemTexture = function ( quickItem, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
+
+ THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
+
+ this.generateMipmaps = false;
+ this._needsUpdate = true;
+
+ this.quickItem = quickItem;
+
+};
+
+THREE.QtQuickItemTexture.prototype = Object.create( THREE.Texture.prototype );
+THREE.QtQuickItemTexture.prototype.constructor = THREE.QtQuickItemTexture;
+
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/cellphone.pro b/examples/canvas3d/canvas3d/threejs/cellphone/cellphone.pro
new file mode 100644
index 0000000..df1b2a9
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/cellphone.pro
@@ -0,0 +1,15 @@
+TEMPLATE = app
+
+QT += qml quick
+
+target.path = $$[QT_INSTALL_EXAMPLES]/canvas3d/$$TARGET
+INSTALLS += target
+
+SOURCES += main.cpp
+
+RESOURCES += cellphone.qrc
+
+OTHER_FILES += qml/cellphone/* \
+ doc/src/* \
+ doc/images/*
+
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/cellphone.qrc b/examples/canvas3d/canvas3d/threejs/cellphone/cellphone.qrc
new file mode 100644
index 0000000..8f28b38
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/cellphone.qrc
@@ -0,0 +1,30 @@
+<RCC>
+ <qresource prefix="/">
+ <file alias="three.js">../../3rdparty/three.js</file>
+ <file alias="main.qml">qml/cellphone/main.qml</file>
+ <file alias="CellphoneApp.qml">qml/cellphone/cellphoneapp.qml</file>
+ <file alias="CellphoneCanvas.qml">qml/cellphone/cellphonecanvas.qml</file>
+ <file alias="ColorSelector.qml">qml/cellphone/colorselector.qml</file>
+ <file alias="FpsDisplay.qml">qml/cellphone/fpsdisplay.qml</file>
+ <file alias="cellphone.js">qml/cellphone/cellphone.js</file>
+ <file alias="cellphone_case.json">qml/cellphone/cellphone_case.json</file>
+ <file alias="cellphone_front.json">qml/cellphone/cellphone_front.json</file>
+ <file alias="cellphone_icon.json">qml/cellphone/cellphone_icon.json</file>
+ <file alias="menu_background.jpg">images/menu_background.jpg</file>
+ <file alias="plutomap1k.jpg">images/plutomap1k.jpg</file>
+ <file alias="qtlogo_with_alpha.png">images/qtlogo_with_alpha.png</file>
+ <file alias="calendar.png">images/calendar.png</file>
+ <file alias="camera.png">images/camera.png</file>
+ <file alias="clock.png">images/clock.png</file>
+ <file alias="contacts.png">images/contacts.png</file>
+ <file alias="gallery.png">images/gallery.png</file>
+ <file alias="games.png">images/games.png</file>
+ <file alias="lock.png">images/lock.png</file>
+ <file alias="mail.png">images/mail.png</file>
+ <file alias="maps.png">images/maps.png</file>
+ <file alias="music.png">images/music.png</file>
+ <file alias="settings.png">images/settings.png</file>
+ <file alias="todo.png">images/todo.png</file>
+ <file alias="videos.png">images/videos.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/doc/src/cellphone.qdoc b/examples/canvas3d/canvas3d/threejs/cellphone/doc/src/cellphone.qdoc
new file mode 100644
index 0000000..8c8e050
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/doc/src/cellphone.qdoc
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example canvas3d/threejs/cellphone
+ \since QtCanvas3D 1.1
+ \title Interactive Mobile Phone Example
+ \ingroup qtcanvas3d-examples
+ \brief Demonstrates using Qt Quick item as a texture with three.js.
+
+ This example demonstrates how to implement an application that uses Qt Quick 2D element
+ as a texture in a three.js scene. The example shows a 3D model of a mobile phone with an UI
+ implemented with Qt Quick. When the phone is not rotating, the UI can be interacted with.
+
+ \image cellphone-example.png
+
+ \section1 Qt Quick Implementation
+
+ The Qt Quick Implementation \l{canvas3d/threejs/cellphone/qml/cellphone/main.qml}{main.qml}
+ of the example renders the 3D model of the mobile phone using Canvas3D type.
+ The phone UI is composed of the \c textureSource Qt Quick item and its children.
+ To make it possible to use the item as a texture source for Canvas3D,
+ we must enable the layer of the item:
+
+ \snippet canvas3d/threejs/cellphone/qml/cellphone/main.qml 0
+ \dots
+
+ The texture mirroring is disabled so that the OpenGL texture generated from the item
+ is oriented as the three.js expects.
+
+ The \c textureSource item is passed as a parameter to the JavaScript function handling the
+ OpenGL initialization in Canvas3D:
+
+ \snippet canvas3d/threejs/cellphone/qml/cellphone/cellphonecanvas.qml 1
+
+ The texture generated from the \c textureSource is not interactable by itself, as it is just a
+ regular texture. To make it appear interactable, we make it so that the phone UI is interactable
+ only when the phone is not rotating and superimpose the actual \c textureSource item over the
+ Canvas3D so that both the 3D model and the \c textureSource items are perfectly aligned.
+ The 3D model and the Qt Quick UI are aligned by careful positioning of the model and
+ scaling of the \c textureSource item using its \l{Item::transform}{transform} property.
+ The \c textureSource item is set fully transparent so that there are no visual artifacts:
+
+ \snippet canvas3d/threejs/cellphone/qml/cellphone/main.qml 2
+
+ To ensure user cannot interact with the UI when the phone is rotating, we hide the
+ \c textureSource item behind the Canvas3D by adjusting its \l{Item::z}{z} property when the
+ phone starts its rotation animation.
+
+ \section1 The JavaScript Code
+
+ The JavaScript side of the implementation,
+ \l{canvas3d/threejs/cellphone/qml/cellphone/cellphone.js}{cellphone.js},
+ is done using a version of \c{three.js} that is ported for \l{Qt Canvas 3D}:
+ \l{https://github.com/tronlec/three.js}{three.js}.
+
+ The \c{initializeGL()} method creates the scene. It also adds the lights and the camera to the
+ scene and creates materials and meshes used in the scene. The part relevant to the main point
+ of this example is how the \c textureSource is handled. It is very simple to create a texture
+ from a Qt Quick texture source: simply create a new \c{THREE.QtQuickItemTexture} with the
+ \c textureSource as a parameter and you are done:
+
+ \snippet canvas3d/threejs/cellphone/qml/cellphone/cellphone.js 0
+
+ The texture created this way can be used as a map to a material just like a regular texture:
+
+ \snippet canvas3d/threejs/cellphone/qml/cellphone/cellphone.js 1
+
+ The scene is rendered in \c{paintGL()} method, which simply adjusts the rotations of the
+ phone meshes, repositions the camera and light, and renders the scene.
+
+ For more information on how to use \c {three.js} the documentation is available here:
+ \l{http://threejs.org/docs/}{three.js/docs}
+
+ The background sphere uses Pluto texture map, which is Copyright (c) by James Hastings-Trew
+ \l{http://planetpixelemporium.com/planets.html}{http://planetpixelemporium.com/planets.html}.
+ Used with permission.
+*/
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/calendar.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/calendar.png
new file mode 100644
index 0000000..80952e6
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/calendar.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/camera.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/camera.png
new file mode 100644
index 0000000..8528e44
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/camera.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/clock.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/clock.png
new file mode 100644
index 0000000..11cb76d
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/clock.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/contacts.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/contacts.png
new file mode 100644
index 0000000..a82d92f
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/contacts.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/gallery.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/gallery.png
new file mode 100644
index 0000000..059b02d
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/gallery.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/games.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/games.png
new file mode 100644
index 0000000..d96c3fa
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/games.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/lock.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/lock.png
new file mode 100644
index 0000000..9a25b69
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/lock.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/mail.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/mail.png
new file mode 100644
index 0000000..1fd155a
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/mail.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/maps.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/maps.png
new file mode 100644
index 0000000..b29f394
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/maps.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/menu_background.jpg b/examples/canvas3d/canvas3d/threejs/cellphone/images/menu_background.jpg
new file mode 100644
index 0000000..69c6938
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/menu_background.jpg
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/music.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/music.png
new file mode 100644
index 0000000..603f643
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/music.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/plutomap1k.jpg b/examples/canvas3d/canvas3d/threejs/cellphone/images/plutomap1k.jpg
new file mode 100644
index 0000000..d18bf9f
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/plutomap1k.jpg
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/qtlogo_with_alpha.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/qtlogo_with_alpha.png
new file mode 100644
index 0000000..b2f48ee
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/qtlogo_with_alpha.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/settings.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/settings.png
new file mode 100644
index 0000000..c79fac2
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/settings.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/todo.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/todo.png
new file mode 100644
index 0000000..217c59e
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/todo.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/images/videos.png b/examples/canvas3d/canvas3d/threejs/cellphone/images/videos.png
new file mode 100644
index 0000000..ee438ed
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/images/videos.png
Binary files differ
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/main.cpp b/examples/canvas3d/canvas3d/threejs/cellphone/main.cpp
new file mode 100644
index 0000000..99470cd
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/main.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtQml/QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone.js b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone.js
new file mode 100644
index 0000000..7aac698
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone.js
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+Qt.include("three.js")
+
+var camera, scene, renderer, cubeCamera;
+var caseMesh, frontMesh, iconMesh;
+var caseColor = new THREE.Color("#000000");
+var meshesReady = false;
+var canvasTextureProvider = null;
+var zeroVector = new THREE.Vector3(0, 0, 0);
+var cameraLight;
+var sphereImage, iconImage;
+var caseMeshFile, frontMeshFile, iconMeshFile;
+
+function initializeGL(canvas, textureSource) {
+ scene = new THREE.Scene();
+
+ cubeCamera = new THREE.CubeCamera(5, 100, 512);
+ cubeCamera.renderTarget.minFilter = THREE.LinearMipMapLinearFilter;
+ scene.add(cubeCamera);
+
+ // Background sphere
+ var sphere = new THREE.Mesh(
+ new THREE.SphereGeometry(40, 16, 16),
+ new THREE.MeshBasicMaterial());
+ sphere.side = THREE.BackSide;
+ sphere.scale.x = -1;
+ scene.add(sphere);
+ if (sphereImage) {
+ var sphereTexture = THREE.ImageUtils.loadTexture(sphereImage, THREE.UVMapping, updateEnvMap);
+ sphereTexture.minFilter = THREE.LinearFilter;
+ sphere.material.map = sphereTexture;
+ } else {
+ sphere.material.color = new THREE.Color("black");
+ }
+
+ camera = new THREE.PerspectiveCamera( 75, canvas.width / canvas.height, 0.001, 1000 );
+
+ var light = new THREE.AmbientLight( 0x666666 );
+ scene.add( light );
+
+ cameraLight = new THREE.DirectionalLight( 0xffffff, 1 );
+ cameraLight.position.y = 1.5;
+ scene.add( cameraLight );
+
+ var caseMaterial = new THREE.MeshPhongMaterial({ envMap: cubeCamera.renderTarget,
+ combine: THREE.MultiplyOperation,
+ reflectivity: 0.35,
+ specular: "#555555" });
+ //! [0]
+ var frontTexture = new THREE.QtQuickItemTexture( textureSource );
+ //! [0]
+ //! [1]
+ var frontMaterial = new THREE.MeshPhongMaterial( { map: frontTexture } );
+ //! [1]
+
+ var iconMaterial = new THREE.MeshPhongMaterial( { transparent:true } );
+ if (iconImage) {
+ var iconTexture = THREE.ImageUtils.loadTexture(iconImage);
+ iconTexture.minFilter = THREE.LinearFilter;
+ iconMaterial.map = iconTexture;
+ } else {
+ iconMaterial.opacity = 0;
+ }
+
+ renderer = new THREE.Canvas3DRenderer(
+ { canvas: canvas, antialias: true, devicePixelRatio: canvas.devicePixelRatio,
+ alpha: true});
+ renderer.setSize( canvas.width, canvas.height );
+
+ // The cellphone meshes were created using a third party tool (Blender).
+ // They were exported from Blender as Wavefront OBJ files and then converted into JSON format
+ // using the OBJ -> JSON conversion script provided by three.js (convert_obj_three.py).
+ var loader = new THREE.JSONLoader();
+ loader.load( caseMeshFile, function ( geometry, materials ) {
+ geometry.computeVertexNormals();
+ var bufferGeometry = new THREE.BufferGeometry();
+ bufferGeometry.fromGeometry(geometry);
+ caseMesh = new THREE.Mesh( bufferGeometry, caseMaterial );
+ if (iconMesh && frontMesh)
+ meshesReady = true;
+ caseMesh.material.color = caseColor;
+ updateEnvMap();
+ scene.add( caseMesh );
+ } );
+ loader.load( frontMeshFile, function ( geometry, materials ) {
+ var bufferGeometry = new THREE.BufferGeometry();
+ bufferGeometry.fromGeometry(geometry);
+ frontMesh = new THREE.Mesh( bufferGeometry, frontMaterial );
+ if (iconMesh && caseMesh)
+ meshesReady = true;
+ scene.add( frontMesh );
+ } );
+ loader.load( iconMeshFile, function ( geometry, materials ) {
+ var bufferGeometry = new THREE.BufferGeometry();
+ bufferGeometry.fromGeometry(geometry);
+ iconMesh = new THREE.Mesh( bufferGeometry, iconMaterial );
+ if (caseMesh && frontMesh)
+ meshesReady = true;
+ scene.add( iconMesh );
+ } );
+}
+
+function updateEnvMap() {
+ if (caseMesh) {
+ // Take a snapshot of the scene using cube camera to create environment map for case
+ caseMesh.material.envMap = cubeCamera.renderTarget;
+ cubeCamera.updateCubeMap(renderer, scene);
+ caseMesh.material.needsUpdate = true;
+ }
+}
+
+function setSphereTexture(image) {
+ sphereImage = image;
+}
+
+function setIconTexture(image) {
+ iconImage = image;
+}
+
+function setMeshFiles(caseFile, frontFile, iconFile) {
+ caseMeshFile = caseFile;
+ frontMeshFile = frontFile;
+ iconMeshFile = iconFile;
+}
+
+function setCaseColor(color) {
+ caseColor.set(color);
+ if (caseMesh)
+ caseMesh.material.color = caseColor;
+}
+
+function resizeGL(canvas) {
+ camera.aspect = canvas.width / canvas.height;
+ camera.updateProjectionMatrix();
+
+ renderer.setPixelRatio(canvas.devicePixelRatio);
+ renderer.setSize( canvas.width, canvas.height );
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function paintGL(canvas) {
+ if (meshesReady) {
+ var cameraRad = degToRad(canvas.cameraAngle);
+ var lightRad = cameraRad - 0.8;
+ caseMesh.rotation.x = degToRad(canvas.xRotAnim);
+ caseMesh.rotation.y = degToRad(canvas.yRotAnim);
+ caseMesh.rotation.z = cameraRad + degToRad(canvas.zRotAnim);
+ frontMesh.rotation.set(caseMesh.rotation.x, caseMesh.rotation.y, caseMesh.rotation.z);
+ iconMesh.rotation.set(caseMesh.rotation.x, caseMesh.rotation.y, caseMesh.rotation.z);
+ camera.lookAt(zeroVector);
+ camera.position.x = canvas.distance * Math.sin(cameraRad);
+ camera.position.z = canvas.distance * Math.cos(cameraRad);
+ cameraLight.position.x = (canvas.distance + 2) * Math.sin(lightRad);
+ cameraLight.position.z = (canvas.distance + 2) * Math.cos(lightRad);
+ }
+
+ renderer.render( scene, camera );
+
+}
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_case.json b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_case.json
new file mode 100644
index 0000000..f360722
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_case.json
@@ -0,0 +1,34 @@
+{
+
+ "metadata" :
+ {
+ "formatVersion" : 3.1,
+ "sourceFile" : "cellphone_case.obj",
+ "generatedBy" : "OBJConverter",
+ "vertices" : 220,
+ "faces" : 426,
+ "normals" : 340,
+ "colors" : 0,
+ "uvs" : 192,
+ "materials" : 0
+ },
+
+ "scale" : 1.000000,
+
+ "materials": [],
+
+ "vertices": [-0.475000,-0.025000,0.974999,-0.475000,-0.025000,-0.975000,0.475000,-0.025000,-0.974999,0.475000,-0.025000,0.975000,0.475000,0.000000,-0.999999,0.475000,0.000000,-0.999999,-0.475000,0.000000,-1.000000,-0.475000,0.000000,-1.000000,0.482727,0.000000,-0.998775,0.475000,-0.007727,-0.998775,-0.475000,-0.007727,-0.998776,-0.475000,0.007727,-0.998776,0.475000,0.007727,-0.998775,-0.482727,0.000000,-0.998776,-0.482727,0.000000,-0.998776,0.482727,0.000000,-0.998775,0.482932,0.007976,-0.997325,0.482976,-0.007932,-0.997326,0.475000,-0.014692,-0.995227,-0.475000,-0.014692,-0.995227,-0.482931,-0.007976,-0.997326,-0.482976,0.007932,-0.997326,-0.475000,0.014692,-0.995227,0.475000,0.014692,-0.995226,-0.489692,0.000000,-0.995227,-0.489692,0.000000,-0.995227,0.489692,0.000000,-0.995226,0.489366,0.007693,-0.993958,0.482693,-0.014366,-0.993958,0.475000,-0.020227,-0.989692,-0.475000,-0.020227,-0.989692,-0.482673,-0.014354,-0.993976,0.482673,0.014354,-0.993975,-0.482693,0.014366,-0.993958,-0.475000,0.020227,-0.989692,0.475000,0.020227,-0.989691,-0.489366,-0.007693,-0.993958,-0.495227,0.000000,-0.989692,-0.495227,0.000000,-0.989692,-0.489353,0.007673,-0.993976,0.489353,-0.007673,-0.993975,0.489692,0.000000,-0.995226,0.488228,0.013228,-0.991583,0.488228,-0.013228,-0.991584,0.475000,-0.023776,-0.982726,-0.475000,-0.023776,-0.982727,-0.482693,-0.018959,-0.989366,-0.488228,-0.013228,-0.991584,-0.488228,0.013228,-0.991584,0.482693,0.018959,-0.989365,-0.475000,0.023776,-0.982726,0.475000,0.023776,-0.982726,-0.498776,0.000000,-0.982727,-0.498776,0.000000,-0.982727,-0.493958,0.007693,-0.989366,0.495227,0.000000,-0.989691,0.493976,0.007673,-0.989353,0.482673,-0.018976,-0.989353,0.475000,-0.025000,-0.974999,-0.475000,-0.025000,-0.975000,-0.488228,-0.016584,-0.988228,0.488228,0.016584,-0.988227,-0.482673,0.018976,-0.989353,-0.475000,0.025000,-0.975000,0.475000,0.025000,-0.974999,-0.493976,-0.007673,-0.989353,-0.500000,0.000000,-0.975000,-0.500000,0.000000,-0.975000,-0.491584,0.013228,-0.988228,0.493958,-0.007693,-0.989366,0.491584,-0.013228,-0.988227,0.495227,0.000000,-0.989691,0.491584,0.013228,-0.988227,0.488228,-0.016584,-0.988227,0.482931,-0.022326,-0.982976,-0.482976,-0.022326,-0.982932,-0.491584,-0.013228,-0.988228,-0.488228,0.016584,-0.988227,0.482976,0.022326,-0.982931,-0.482931,0.022326,-0.982976,-0.497326,-0.007932,-0.982976,-0.500000,0.000000,0.974999,-0.500000,0.000000,0.974999,-0.497326,0.007976,-0.982931,0.498776,0.000000,-0.982726,0.497326,0.007932,-0.982975,0.482727,-0.023776,-0.974999,-0.482726,-0.023776,-0.975000,-0.489353,-0.018976,-0.982673,0.489354,0.018976,-0.982672,0.482727,0.023776,-0.974999,-0.482727,0.023776,-0.974999,-0.498776,-0.007727,-0.975000,-0.498776,-0.007727,0.974999,-0.498776,0.000000,0.982726,-0.498776,0.000000,0.982726,-0.498776,0.007727,0.974999,-0.498776,0.007727,-0.975000,-0.493976,0.014354,-0.982673,0.498776,0.000000,-0.982726,0.497326,-0.007976,-0.982931,0.493976,-0.014354,-0.982673,0.493958,0.014366,-0.982692,0.489366,-0.018959,-0.982692,0.482727,-0.023776,0.974999,0.475000,-0.025000,0.975000,-0.482727,-0.023776,0.974999,-0.475000,-0.025000,0.974999,-0.493958,-0.014366,-0.982693,-0.489366,0.018959,-0.982693,0.474999,0.025000,0.975000,0.482726,0.023776,0.975000,-0.475000,0.025000,0.974999,-0.482727,0.023776,0.974999,-0.497326,-0.007976,0.982931,-0.495227,-0.014692,-0.975000,-0.495227,-0.014692,0.974999,-0.495227,0.000000,0.989691,-0.495227,0.000000,0.989691,-0.497326,0.007932,0.982976,-0.495227,0.014692,0.974999,-0.495227,0.014692,-0.975000,0.500000,0.000000,-0.974999,0.500000,0.000000,-0.974999,0.498776,0.007727,-0.974999,0.489692,-0.020227,-0.974999,0.489692,-0.020227,0.975000,0.482976,-0.022326,0.982931,-0.482932,-0.022326,0.982976,-0.489692,-0.020227,0.974999,-0.489692,-0.020227,-0.975000,0.489692,0.020227,-0.974999,0.482931,0.022326,0.982976,0.489692,0.020227,0.975000,-0.482976,0.022326,0.982931,-0.489692,0.020227,-0.975000,-0.489692,0.020227,0.974999,-0.493976,-0.014354,0.982673,-0.493958,-0.007693,0.989366,-0.489692,0.000000,0.995227,-0.489692,0.000000,0.995226,-0.493976,0.007673,0.989353,-0.493958,0.014366,0.982692,0.498776,-0.007727,-0.974999,0.495227,-0.014692,-0.974999,0.500000,0.000000,0.975000,0.495227,0.014692,-0.974999,0.495227,-0.014692,0.975000,0.489353,-0.018976,0.982673,0.475000,-0.023776,0.982726,-0.475000,-0.023776,0.982726,-0.489366,-0.018959,0.982692,0.474999,0.023776,0.982727,0.489366,0.018959,0.982693,0.495227,0.014692,0.975000,-0.475000,0.023776,0.982726,-0.489354,0.018976,0.982672,-0.491584,-0.013228,0.988227,-0.482727,0.000000,0.998775,-0.482727,0.000000,0.998775,-0.489366,0.007693,0.993958,-0.491584,0.013228,0.988227,0.500000,0.000000,0.975000,0.498776,0.007727,0.975000,0.498776,-0.007727,0.975000,0.493958,-0.014366,0.982693,0.482693,-0.018959,0.989366,0.488228,-0.016584,0.988228,-0.482673,-0.018976,0.989353,-0.488228,-0.016584,0.988227,0.482673,0.018976,0.989354,0.488227,0.016584,0.988228,-0.482693,0.018959,0.989366,-0.488228,0.016584,0.988227,-0.489353,-0.007673,0.993976,-0.475000,0.000000,0.999999,-0.488228,0.013228,0.991584,0.498776,0.000000,0.982727,0.497326,0.007976,0.982932,0.493976,0.014354,0.982673,0.491584,-0.013228,0.988228,0.475000,-0.020227,0.989692,-0.475000,-0.020227,0.989692,-0.475000,0.020227,0.989691,0.474999,0.020227,0.989692,-0.488228,-0.013228,0.991584,-0.482976,-0.007932,0.997326,-0.475000,0.000000,0.999999,-0.482932,0.007976,0.997326,0.497326,-0.007932,0.982976,0.498776,0.000000,0.982727,0.475000,-0.014692,0.995227,-0.475000,-0.014692,0.995227,0.482673,-0.014354,0.993976,0.488228,-0.013228,0.991584,-0.482693,-0.014366,0.993958,-0.475000,0.014692,0.995226,0.474999,0.014692,0.995227,0.482693,0.014366,0.993958,0.488227,0.013228,0.991584,0.491584,0.013228,0.988228,-0.482673,0.014354,0.993975,-0.475000,-0.007727,0.998775,0.475000,0.000000,1.000000,0.475000,0.000000,1.000000,0.495227,0.000000,0.989692,0.495227,0.000000,0.989692,0.493958,0.007693,0.989366,0.493976,-0.007673,0.989353,0.475000,-0.007727,0.998776,-0.475000,0.007727,0.998775,0.475000,0.007727,0.998776,0.482726,0.000000,0.998776,0.482726,0.000000,0.998776,0.489692,0.000000,0.995227,0.489692,0.000000,0.995227,0.482931,-0.007976,0.997326,0.489366,-0.007693,0.993958,0.482976,0.007932,0.997326,0.489353,0.007673,0.993976],
+
+ "morphTargets": [],
+
+ "morphColors": [],
+
+ "normals": [0,0,1,0,-0.1565,-0.9877,0,0.1565,-0.9877,0,-1,0,0.1729,0.1541,-0.9728,0.1541,-0.1729,-0.9728,0,-0.454,-0.891,-0.1541,-0.1728,-0.9728,-0.1541,0.173,-0.9728,0,0.454,-0.891,0,1,0,0.4478,0.1639,-0.879,0.1639,-0.4478,-0.879,0,-0.7071,-0.7071,-0.1631,-0.4479,-0.8791,0.1631,0.4479,-0.8791,-0.1639,0.4478,-0.879,0,0.7071,-0.7071,-0.4638,-0.1469,-0.8737,-0.4647,0.145,-0.8735,0.4479,-0.1631,-0.8791,0.4329,0.4329,-0.7907,0.4329,-0.4329,-0.7907,0.1449,-0.6996,-0.6997,0,-0.891,-0.454,-0.145,-0.6996,-0.6996,-0.4292,-0.4292,-0.7947,-0.4329,0.4329,-0.7907,0.145,0.6996,-0.6996,-0.1449,0.6996,-0.6997,0,0.891,-0.454,-0.6996,-0.1449,-0.6997,-0.6997,0.1449,-0.6996,0.6996,0.1449,-0.6997,0.6454,0.4087,-0.6454,0.4087,-0.6454,-0.6454,0.145,-0.8735,-0.4647,0,-0.9877,-0.1565,-0.1469,-0.8737,-0.4638,-0.4087,-0.6454,-0.6454,0.4093,0.6446,-0.6457,-0.4087,0.6454,-0.6454,0.1469,0.8737,-0.4637,-0.145,0.8735,-0.4647,0,0.9877,-0.1565,-0.6453,-0.4087,-0.6454,-0.8735,-0.145,-0.4647,-0.8737,0.1469,-0.4638,-0.6454,0.4087,-0.6454,0.6996,-0.145,-0.6996,0.6446,-0.4093,-0.6457,0.1541,-0.9728,-0.1728,-0.1541,-0.9728,-0.1729,-0.4329,-0.7907,-0.4329,-0.5773,-0.5773,-0.5774,0.5774,0.5773,-0.5774,0.4329,0.7907,-0.4329,0.1541,0.9728,-0.1729,-0.1541,0.9728,-0.1728,-0.9728,-0.1541,-0.1728,-0.9728,0.1541,-0.1729,-0.7907,0.4329,-0.4329,-0.5774,0.5774,-0.5773,0.5773,-0.5774,-0.5774,0.8735,0.145,-0.4647,0.7947,0.4292,-0.4292,0.4292,-0.7947,-0.4292,-0.6446,-0.6457,-0.4093,0.6446,0.6457,-0.4093,-0.4292,0.7948,-0.4292,-0.7948,-0.4292,-0.4292,-0.9877,-0.1565,-0,-0.9877,0.1565,-0,-0.6457,0.6446,-0.4093,0.8737,-0.1469,-0.4637,0.7907,-0.4329,-0.4329,0.6457,-0.6446,-0.4093,0.1565,-0.9877,0,0.4478,-0.879,-0.1639,-0.1565,-0.9877,-0,-0.4479,-0.8791,-0.1631,0.4479,0.8791,-0.1631,0.1565,0.9877,0,-0.1565,0.9877,-0,-0.4478,0.879,-0.1639,-0.879,-0.4478,-0.1639,-0.9728,-0.1728,0.1541,-0.891,-0.454,-0,-0.9728,0.1729,0.1541,-0.891,0.454,-0,-0.8791,0.4479,-0.1631,0.9728,0.1541,-0.1728,0.879,0.4478,-0.1639,0.454,-0.891,0,0.1728,-0.9728,0.1541,-0.1729,-0.9728,0.1541,-0.454,-0.891,-0,-0.6996,-0.6996,-0.145,0.6996,0.6996,-0.145,0.173,0.9728,0.1541,0.454,0.891,0,-0.1728,0.9728,0.1541,-0.454,0.891,-0,-0.8791,-0.4479,0.1631,-0.7071,-0.7071,-0,-0.8737,-0.1469,0.4638,-0.8735,0.145,0.4647,-0.879,0.4478,0.1639,-0.7071,0.7071,-0,-0.6996,0.6996,-0.145,0.9728,-0.1541,-0.1729,0.8791,-0.4479,-0.1631,0.6996,-0.6996,-0.145,0.7071,-0.7071,0,0.4647,-0.8735,0.145,-0.4478,-0.879,0.1639,0.4478,0.879,0.1639,0.7071,0.7071,0,-0.4479,0.8791,0.1631,-0.7948,-0.4292,0.4292,-0.6996,-0.6996,0.145,-0.6997,-0.1449,0.6996,-0.6996,0.1449,0.6997,-0.7948,0.4292,0.4292,-0.6997,0.6996,0.1449,0.9877,0.1565,0,0.891,0.454,0,0.891,-0.454,0,0.6997,-0.6996,0.1449,0,-0.9877,0.1565,0.1639,-0.879,0.4478,0.4292,-0.7947,0.4292,-0.1631,-0.8791,0.4479,-0.4329,-0.7907,0.4329,-0,0.9877,0.1565,0.1631,0.8791,0.4479,0.4329,0.7907,0.4329,0.6996,0.6997,0.1449,-0.1639,0.879,0.4478,-0.4292,0.7947,0.4292,-0.6457,-0.6446,0.4093,-0.6454,-0.4087,0.6454,-0.4647,-0.145,0.8735,-0.4638,0.1469,0.8737,-0.6454,0.4087,0.6454,-0.6454,0.6454,0.4087,0.9877,-0.1565,0,0.9728,0.1728,0.1541,0.8735,0.4647,0.145,0.8737,-0.4638,0.1469,0.6454,-0.6454,0.4087,-0,-0.891,0.454,-0,0.891,0.454,0.6454,0.6454,0.4087,-0.5774,-0.5773,0.5773,-0.1729,-0.1541,0.9728,-0.4329,0.4329,0.7907,-0.5774,0.5773,0.5773,0.9728,-0.1729,0.1541,0.7907,-0.4329,0.4329,-0,-0.7071,0.7071,0.1449,-0.6997,0.6996,0.4087,-0.6454,0.6454,0.5773,-0.5774,0.5774,-0.145,-0.6996,0.6996,-0.4093,-0.6457,0.6446,-0,0.7071,0.7071,0.145,0.6996,0.6996,0.4093,0.6457,0.6446,-0.1449,0.6997,0.6996,-0.4087,0.6454,0.6454,-0.4292,-0.4292,0.7948,-0.173,0.1541,0.9728,0.879,0.1639,0.4478,0.7948,0.4292,0.4292,-0,-0.454,0.891,0.6457,-0.4093,0.6446,-0,0.454,0.891,0.5773,0.5773,0.5774,-0,-0.1564,0.9877,-0.1639,-0.4478,0.879,-0,0.1565,0.9877,-0.1631,0.4479,0.8791,0.8791,-0.1631,0.4479,0.145,-0.4648,0.8735,0.4292,-0.4292,0.7947,0.1469,0.4638,0.8737,0.4329,0.4329,0.7907,0.6446,0.4093,0.6457,0.1541,-0.1728,0.9728,0.1728,0.1541,0.9728,0.6996,-0.145,0.6996,0.6997,0.1449,0.6996,0.4478,-0.1639,0.879,0.4648,0.145,0.8735,0.1541,0.1729,-0.9728,0.1728,-0.1541,-0.9728,-0.173,-0.1541,-0.9728,-0.1728,0.1541,-0.9728,0.4638,0.1469,-0.8737,0.1469,-0.4637,-0.8737,-0.145,-0.4647,-0.8735,0.145,0.4647,-0.8735,-0.1469,0.4638,-0.8737,-0.4478,-0.1639,-0.879,-0.4479,0.1631,-0.8791,0.4648,-0.145,-0.8735,0.4292,0.4292,-0.7947,0.4292,-0.4292,-0.7948,0.145,-0.6996,-0.6996,-0.1449,-0.6997,-0.6996,-0.4329,-0.4329,-0.7907,-0.4292,0.4292,-0.7947,0.1449,0.6997,-0.6996,-0.145,0.6996,-0.6996,-0.6996,-0.145,-0.6996,-0.6996,0.145,-0.6996,0.6996,0.145,-0.6996,0.6457,0.4093,-0.6446,0.4093,-0.6457,-0.6446,0.1631,-0.8791,-0.4479,-0.1639,-0.879,-0.4478,-0.4093,-0.6446,-0.6457,0.4087,0.6454,-0.6454,-0.4093,0.6457,-0.6446,0.1639,0.879,-0.4478,-0.1631,0.8791,-0.4479,-0.6457,-0.4093,-0.6446,-0.8791,-0.1631,-0.4479,-0.879,0.1639,-0.4478,-0.6446,0.4093,-0.6457,0.6997,-0.1449,-0.6996,0.6454,-0.4087,-0.6454,0.1729,-0.9728,-0.1541,-0.1728,-0.9728,-0.1541,-0.4292,-0.7948,-0.4292,0.4292,0.7947,-0.4292,0.1728,0.9728,-0.1541,-0.173,0.9728,-0.1541,-0.9728,-0.1729,-0.1541,-0.9728,0.1728,-0.1541,-0.7948,0.4291,-0.4292,0.8791,0.1631,-0.4479,0.7907,0.4329,-0.4329,0.4329,-0.7907,-0.4329,-0.6454,-0.6454,-0.4087,0.6454,0.6454,-0.4087,-0.4329,0.7907,-0.4329,-0.7907,-0.4329,-0.4329,-0.6454,0.6454,-0.4087,0.879,-0.1639,-0.4478,0.7948,-0.4292,-0.4292,0.6454,-0.6454,-0.4087,0.4638,-0.8737,-0.1469,-0.4647,-0.8735,-0.145,0.4647,0.8735,-0.145,-0.4638,0.8737,-0.1469,-0.8737,-0.4638,-0.1469,-0.9728,-0.1541,0.1729,-0.9728,0.1541,0.1728,-0.8735,0.4647,-0.145,0.9728,0.1729,-0.1541,0.8737,0.4638,-0.1469,0.1541,-0.9728,0.1729,-0.1541,-0.9728,0.1728,-0.6997,-0.6996,-0.1449,0.6997,0.6996,-0.1449,0.1541,0.9728,0.1728,-0.1541,0.9728,0.1729,-0.8735,-0.4647,0.145,-0.879,-0.1639,0.4478,-0.8791,0.1631,0.4479,-0.8737,0.4638,0.1469,-0.6996,0.6997,-0.1449,0.9728,-0.1728,-0.1541,0.8735,-0.4647,-0.145,0.6996,-0.6997,-0.1449,0.4479,-0.8791,0.1631,-0.4638,-0.8737,0.1469,0.4638,0.8737,0.1469,-0.4647,0.8735,0.145,-0.7907,-0.4329,0.4329,-0.6996,-0.6997,0.1449,-0.6996,-0.145,0.6996,-0.6996,0.145,0.6996,-0.7907,0.4329,0.4329,-0.6996,0.6996,0.145,0.6996,-0.6996,0.145,0.1469,-0.8737,0.4638,0.4329,-0.7907,0.4329,-0.145,-0.8735,0.4647,-0.4292,-0.7948,0.4292,0.145,0.8735,0.4647,0.4292,0.7947,0.4292,0.6996,0.6996,0.145,-0.1469,0.8737,0.4637,-0.4329,0.7907,0.4329,-0.6454,-0.6454,0.4087,-0.6446,-0.4093,0.6457,-0.4479,-0.1631,0.8791,-0.4478,0.1639,0.879,-0.6457,0.4093,0.6446,-0.6446,0.6457,0.4093,0.9728,0.1541,0.1729,0.8791,0.4479,0.1631,0.879,-0.4478,0.1639,0.6446,-0.6457,0.4093,0.6457,0.6446,0.4093,-0.1541,-0.1729,0.9728,-0.4292,0.4292,0.7947,0.9728,-0.1541,0.1728,0.7948,-0.4292,0.4292,0.145,-0.6996,0.6996,0.4093,-0.6446,0.6457,-0.1449,-0.6996,0.6997,-0.4086,-0.6454,0.6454,0.1449,0.6996,0.6997,0.4086,0.6454,0.6454,-0.145,0.6996,0.6996,-0.4093,0.6446,0.6457,-0.4329,-0.4329,0.7907,-0.1541,0.1728,0.9728,0.8737,0.1469,0.4638,0.7907,0.4329,0.4329,0.6453,-0.4087,0.6454,-0,-0.1565,0.9877,-0.1469,-0.4638,0.8737,-0.145,0.4647,0.8735,0.8735,-0.145,0.4648,0.1631,-0.4479,0.8791,0.4329,-0.4329,0.7907,0.1639,0.4478,0.879,0.4292,0.4292,0.7948,0.6454,0.4087,0.6454,0.1729,-0.1541,0.9728,0.1541,0.1729,0.9728,0.6996,-0.1449,0.6997,0.6996,0.145,0.6996,0.4638,-0.1469,0.8737,0.4479,0.1631,0.8791],
+
+ "colors": [],
+
+ "uvs": [[0.97007,0.006727,0.029108,0.006969,0.97772,0.007331,0.02649,0.004848,0.031702,0.010273,0.96748,0.010031,0.021454,0.007577,0.97521,0.010828,0.9807,0.005252,0.024111,0.004138,0.97269,0.004605,0.018504,0.005483,0.023915,0.011059,0.034022,0.014417,0.96517,0.014175,0.014561,0.009336,0.98462,0.009085,0.98164,0.012386,0.98265,0.004643,0.97507,0.003895,0.02221,0.004933,0.016549,0.004887,0.9728,0.014669,0.026373,0.014929,0.035856,0.019006,0.96335,0.018762,0.012199,0.007261,0.009089,0.012077,0.017551,0.012621,0.98696,0.007009,0.98425,0.005304,0.97698,0.004688,0.020991,0.007166,0.014923,0.005552,0.011391,0.006485,0.97128,0.01849,0.027945,0.01875,0.037032,0.023592,0.96219,0.023347,0.007624,0.009561,0.00559,0.015525,0.013031,0.014898,0.99009,0.011822,0.98618,0.014643,0.97863,0.015455,0.98192,0.017099,0.98779,0.006234,0.98897,0.006719,0.98569,0.00731,0.97821,0.00692,0.020582,0.010623,0.013464,0.007583,0.01021,0.006971,0.97749,0.018241,0.020563,0.015705,0.02171,0.018491,0.97043,0.022761,0.028823,0.022988,0.037448,0.027756,0.96179,0.027511,0.008041,0.008163,0.004209,0.012646,0.004395,0.019349,0.009826,0.018163,0.017276,0.017351,0.99155,0.009294,0.99114,0.007909,0.98599,0.010807,0.97863,0.010375,0.013221,0.011059,0.008242,0.008906,0.97778,0.021761,0.96971,0.027103,0.029521,0.027354,0.002857,0.016687,0.009024,0.97891,0.008329,0.021982,0.015328,0.020456,0.9936,0.015267,0.98939,0.017869,0.98385,0.020196,0.99096,0.008649,0.005272,0.010528,0.021412,0.021998,0.00752,0.98158,0.010248,0.98269,0.995,0.012395,0.99393,0.010287,0.98499,0.98655,0.97768,0.98699,0.99173,0.01206,0.025201,0.98763,0.007473,0.012316,0.97768,0.025923,0.96096,0.96986,0.96884,0.97026,0.033932,0.97088,0.02154,0.026177,0.003904,0.014262,0.008887,0.98557,0.008585,0.984,0.013761,0.9861,0.01442,0.98008,0.018761,0.97392,0.014236,0.024329,0.99481,0.019089,0.99088,0.021723,0.98498,0.024072,0.99071,0.98529,0.98473,0.98997,0.97725,0.99039,0.02564,0.99104,0.018198,0.99065,0.012152,0.98594,0.96135,0.97398,0.96951,0.97458,0.97676,0.97143,0.033234,0.97518,0.041435,0.97459,0.04181,0.97047,0.026007,0.97206,0.009968,0.98767,0.012338,0.98863,0.019226,0.9888,0.017628,0.98328,0.019906,0.97776,0.01291,0.97628,0.99635,0.016428,0.9953,0.014003,0.99378,0.97825,0.99426,0.98334,0.98992,0.98865,0.012943,0.98931,0.017878,0.9872,0.97687,0.97557,0.98402,0.97328,0.025936,0.97619,0.012756,0.99002,0.016917,0.99089,0.026096,0.99053,0.022162,0.9855,0.02185,0.98082,0.98988,0.97562,0.9953,0.98091,0.99288,0.98703,0.98327,0.99197,0.97603,0.99259,0.98795,0.99055,0.026872,0.99323,0.019636,0.99262,0.9625,0.97852,0.97036,0.97878,0.98291,0.97711,0.03242,0.97942,0.040308,0.97914,0.026247,0.97968,0.014924,0.99121,0.016102,0.99167,0.023154,0.99262,0.03371,0.99113,0.028568,0.98704,0.025133,0.98245,0.99257,0.98203,0.98837,0.9794,0.99394,0.98491,0.99011,0.98936,0.97656,0.97904,0.98096,0.98018,0.031128,0.99326,0.030932,0.98322,0.99053,0.98796,0.02877,0.99399,0.98164,0.99261,0.97413,0.99335,0.98677,0.99102,0.02122,0.99325,0.038527,0.9837,0.9643,0.98308,0.97191,0.98257,0.97768,0.98181,0.96916,0.9905,0.036259,0.98783,0.98908,0.98544,0.98517,0.98262,0.98597,0.99023,0.96659,0.9872,0.97176,0.99262,0.97677,0.98989,0.98363,0.98815,0.9797,0.99199,0.97433,0.98642,0.98067,0.98488]],
+
+ "faces": [42,4,5,6,0,0,0,1,0,0,0,42,8,15,5,0,2,2,0,0,0,0,42,10,6,5,0,3,1,0,1,1,1,42,7,11,12,0,1,4,5,2,2,2,42,14,7,6,0,6,1,1,3,3,3,42,4,12,16,0,0,5,7,4,4,4,42,5,15,17,0,0,2,8,5,5,5,42,19,10,9,0,9,3,10,6,6,6,42,20,13,6,0,11,6,1,7,7,7,42,7,14,21,0,1,6,12,8,8,8,42,11,22,23,0,4,13,14,9,9,9,42,25,14,13,0,15,6,6,10,10,10,42,26,41,15,0,16,16,2,0,0,0,42,27,26,8,0,17,16,2,11,11,11,42,28,18,9,0,18,19,10,12,12,12,42,30,19,18,0,20,9,19,13,13,13,42,10,19,31,0,3,9,21,14,14,14,42,12,23,32,0,5,14,22,15,15,15,42,33,22,11,0,23,13,4,16,16,16,42,22,34,35,0,13,24,25,17,17,17,42,13,20,36,0,6,11,26,18,18,18,42,38,25,24,0,27,15,15,10,10,10,42,39,21,14,0,28,12,6,19,19,19,42,15,41,40,0,2,16,29,20,20,20,42,27,16,32,0,17,7,22,21,21,21,42,28,17,40,0,18,8,29,22,22,22,42,28,57,29,0,18,30,31,23,23,23,42,45,30,29,0,32,20,31,24,24,24,42,19,30,46,0,9,20,33,25,25,25,42,31,47,36,0,21,34,26,26,26,26,42,33,21,39,0,23,12,28,27,27,27,42,23,35,49,0,14,25,35,28,28,28,42,33,62,34,0,23,36,24,29,29,29,42,34,50,51,0,24,37,38,30,30,30,42,36,65,37,0,26,39,27,31,31,31,42,53,38,37,0,40,27,27,3,3,3,42,54,39,25,0,41,28,15,32,32,32,42,55,71,41,0,42,42,16,0,0,0,42,27,56,55,0,17,43,42,33,33,33,42,42,72,56,0,44,45,43,34,34,34,42,43,73,57,0,46,47,30,35,35,35,42,57,74,44,0,30,48,49,36,36,36,42,59,45,44,0,50,32,49,37,37,37,42,45,75,46,0,32,51,33,38,38,38,42,60,47,31,0,52,34,21,39,39,39,42,32,49,61,0,22,35,53,40,40,40,42,48,77,62,0,54,55,36,41,41,41,42,51,78,49,0,38,56,35,42,42,42,42,62,79,50,0,36,57,37,43,43,43,42,50,63,64,0,37,58,59,44,44,44,42,47,76,65,0,34,60,39,45,45,45,42,65,80,52,0,39,61,40,46,46,46,42,67,53,52,0,62,40,40,3,3,3,42,53,83,54,0,40,63,41,47,47,47,42,68,48,39,0,64,54,28,48,48,48,42,41,71,69,0,16,42,65,49,49,49,42,40,69,70,0,29,65,66,50,50,50,42,74,86,58,0,48,67,68,51,51,51,42,59,87,75,0,50,69,51,52,52,52,42,46,75,88,0,33,51,70,53,53,53,42,76,47,60,0,60,34,52,54,54,54,42,72,42,61,0,45,44,53,55,55,55,42,49,78,89,0,35,56,71,56,56,56,42,64,90,78,0,59,72,56,57,57,57,42,79,91,63,0,57,73,58,58,58,58,42,80,92,66,0,61,74,62,59,59,59,42,82,67,66,0,75,62,62,0,0,0,42,67,97,83,0,62,76,63,60,60,60,42,54,83,98,0,41,63,77,61,61,61,42,48,68,77,0,54,64,55,62,62,62,42,43,70,73,0,46,66,47,63,63,63,42,84,99,71,0,78,78,42,10,10,10,42,56,85,84,0,43,79,78,64,64,64,42,56,72,102,0,43,45,80,65,65,65,42,57,73,103,0,30,47,81,66,66,66,42,88,108,76,0,70,82,60,67,67,67,42,89,102,72,0,71,80,45,68,68,68,42,62,77,109,0,36,55,83,69,69,69,42,65,76,108,0,39,60,82,70,70,70,42,66,92,93,0,62,74,84,71,71,71,42,95,82,81,0,85,75,75,10,10,10,42,97,67,82,0,76,62,75,72,72,72,42,98,109,77,0,77,83,55,73,73,73,42,99,100,69,0,78,86,65,74,74,74,42,69,100,101,0,65,86,87,75,75,75,42,101,103,73,0,87,81,47,76,76,76,42,104,105,58,0,88,89,68,77,77,77,42,103,125,86,0,81,90,67,78,78,78,42,87,59,107,0,69,50,91,79,79,79,42,87,130,88,0,69,92,70,80,80,80,42,90,131,89,0,72,93,71,81,81,81,42,110,111,90,0,94,95,72,82,82,82,42,63,91,113,0,58,73,96,83,83,83,42,109,135,91,0,83,97,73,84,84,84,42,108,115,92,0,82,98,74,85,85,85,42,114,94,81,0,99,85,75,86,86,86,42,92,115,116,0,74,98,100,87,87,87,42,118,95,94,0,101,85,85,10,10,10,42,82,95,119,0,75,85,102,88,88,88,42,120,121,97,0,103,104,76,89,89,89,42,97,121,98,0,76,104,77,90,90,90,42,84,122,123,0,78,105,105,0,0,0,42,85,124,122,0,79,106,105,91,91,91,42,102,146,124,0,80,107,106,92,92,92,42,126,104,86,0,108,88,67,93,93,93,42,127,149,105,0,109,110,89,94,94,94,42,107,150,128,0,91,111,112,95,95,95,42,129,130,87,0,113,92,69,96,96,96,42,130,115,108,0,92,98,82,97,97,97,42,131,146,102,0,93,107,80,98,98,98,42,110,152,132,0,94,114,115,99,99,99,42,111,133,131,0,95,116,93,100,100,100,42,134,155,112,0,117,118,119,101,101,101,42,91,135,136,0,73,97,120,102,102,102,42,93,116,137,0,84,100,121,103,103,103,42,115,130,129,0,98,92,113,104,104,104,42,94,114,138,0,85,99,122,105,105,105,42,140,118,117,0,123,101,101,10,10,10,42,141,119,95,0,124,102,85,106,106,106,42,142,120,96,0,125,103,126,107,107,107,42,135,121,120,0,97,104,103,108,108,108,42,121,135,109,0,104,97,83,109,109,109,42,123,143,100,0,105,127,86,110,110,110,42,143,144,101,0,127,128,87,111,111,111,42,144,125,103,0,128,90,81,112,112,112,42,145,162,123,0,129,129,105,0,0,0,42,147,126,125,0,130,108,90,113,113,113,42,148,127,104,0,131,109,88,114,114,114,42,151,129,106,0,132,113,133,115,115,115,42,153,133,111,0,134,116,95,116,116,116,42,133,154,146,0,116,135,107,117,117,117,42,113,136,156,0,96,120,136,118,118,118,42,137,157,138,0,121,137,122,119,119,119,42,116,129,151,0,100,113,132,120,120,120,42,138,174,139,0,122,138,123,121,121,121,42,159,140,139,0,139,123,123,10,10,10,42,160,141,118,0,140,124,101,122,122,122,42,141,161,142,0,124,141,125,123,123,123,42,142,156,136,0,125,136,120,124,124,124,42,163,145,122,0,142,129,105,125,125,125,42,154,163,124,0,135,142,106,126,126,126,42,164,147,144,0,143,130,128,127,127,127,42,165,148,126,0,144,131,108,128,128,128,42,149,150,107,0,110,111,91,129,129,129,42,166,181,149,0,145,146,110,130,130,130,42,148,167,166,0,131,147,145,131,131,131,42,150,182,168,0,111,148,149,132,132,132,42,151,128,168,0,132,112,149,133,133,133,42,112,155,152,0,119,118,114,134,134,134,42,152,184,170,0,114,150,151,135,135,135,42,153,132,170,0,134,115,151,136,136,136,42,153,179,154,0,134,152,135,137,137,137,42,172,183,155,0,153,154,118,138,138,138,42,156,173,172,0,136,155,153,139,139,139,42,137,151,169,0,121,132,156,140,140,140,42,157,185,174,0,137,157,138,141,141,141,42,174,186,158,0,138,158,139,142,142,142,42,175,187,159,0,159,159,139,0,0,0,42,159,188,160,0,139,160,140,143,143,143,42,176,161,141,0,161,141,124,144,144,144,42,161,173,156,0,141,155,136,145,145,145,42,162,164,143,0,129,143,127,146,146,146,42,177,190,162,0,162,162,129,0,0,0,42,178,177,145,0,163,162,129,147,147,147,42,179,178,163,0,152,163,142,148,148,148,42,164,189,165,0,143,164,144,149,149,149,42,180,167,148,0,165,147,131,150,150,150,42,182,150,149,0,148,111,110,151,151,151,42,155,183,184,0,118,154,150,152,152,152,42,171,200,179,0,166,167,152,153,153,153,42,169,185,157,0,156,157,137,154,154,154,42,186,202,175,0,158,168,159,155,155,155,42,160,188,201,0,140,160,169,156,156,156,42,173,161,176,0,155,141,161,157,157,157,42,162,190,189,0,129,162,164,158,158,158,42,165,189,208,0,144,164,170,159,159,159,42,192,182,181,0,171,148,146,160,160,160,42,166,193,191,0,145,172,173,161,161,161,42,167,194,193,0,147,174,172,162,162,162,42,167,180,194,0,147,165,174,163,163,163,42,182,192,195,0,148,171,175,164,164,164,42,168,195,185,0,149,175,157,165,165,165,42,183,196,197,0,154,176,177,166,166,166,42,184,197,198,0,150,177,178,167,167,167,42,170,198,199,0,151,178,179,168,168,168,42,172,201,196,0,153,169,176,169,169,169,42,173,176,201,0,155,161,169,170,170,170,42,174,185,195,0,138,157,175,171,171,171,42,204,187,175,0,180,159,159,0,0,0,42,187,210,188,0,159,181,160,172,172,172,42,177,205,206,0,162,182,182,3,3,3,42,207,205,177,0,183,182,162,173,173,173,42,179,200,207,0,152,167,183,174,174,174,42,202,192,191,0,168,171,173,175,175,175,42,208,217,194,0,170,184,174,176,176,176,42,196,210,211,0,176,181,185,177,177,177,42,171,199,200,0,166,179,167,178,178,178,42,175,202,209,0,159,168,186,179,179,179,42,195,192,202,0,175,171,168,180,180,180,42,213,204,203,0,187,180,180,0,0,0,42,210,187,204,0,181,159,180,181,181,181,42,210,196,201,0,181,176,169,182,182,182,42,190,206,208,0,162,182,170,183,183,183,42,205,214,215,0,182,188,188,3,3,3,42,193,216,209,0,172,189,186,184,184,184,42,193,194,217,0,172,174,184,185,185,185,42,211,218,198,0,185,190,178,186,186,186,42,198,218,219,0,178,190,191,187,187,187,42,219,207,200,0,191,183,167,188,188,188,42,216,212,203,0,189,187,180,189,189,189,42,214,213,212,0,188,187,187,3,3,3,42,218,211,204,0,190,185,180,190,190,190,42,206,215,217,0,182,188,184,191,191,191,42,207,219,214,0,183,191,188,192,192,192,42,217,215,212,0,184,188,187,193,193,193,42,219,218,213,0,191,190,187,194,194,194,42,7,4,6,0,1,0,1,10,10,10,42,4,8,5,0,0,2,0,0,0,0,42,9,10,5,0,10,3,0,1,1,1,42,4,7,12,0,0,1,5,2,2,2,42,13,14,6,0,6,6,1,10,10,10,42,8,4,16,0,2,0,7,195,195,195,42,9,5,17,0,10,0,8,196,196,196,42,18,19,9,0,19,9,10,6,6,6,42,10,20,6,0,3,11,1,197,197,197,42,11,7,21,0,4,1,12,198,198,198,42,12,11,23,0,5,4,14,9,9,9,42,24,25,13,0,15,15,6,10,10,10,42,8,26,15,0,2,16,2,0,0,0,42,16,27,8,0,7,17,2,199,199,199,42,17,28,9,0,8,18,10,200,200,200,42,29,30,18,0,31,20,19,13,13,13,42,20,10,31,0,11,3,21,201,201,201,42,16,12,32,0,7,5,22,202,202,202,42,21,33,11,0,12,23,4,203,203,203,42,23,22,35,0,14,13,25,17,17,17,42,24,13,36,0,15,6,26,204,204,204,42,37,38,24,0,27,27,15,10,10,10,42,25,39,14,0,15,28,6,205,205,205,42,17,15,40,0,8,2,29,206,206,206,42,42,27,32,0,44,17,22,207,207,207,42,43,28,40,0,46,18,29,208,208,208,42,18,28,29,0,19,18,31,209,209,209,42,44,45,29,0,49,32,31,24,24,24,42,31,19,46,0,21,9,33,210,210,210,42,20,31,36,0,11,21,26,211,211,211,42,48,33,39,0,54,23,28,212,212,212,42,32,23,49,0,22,14,35,213,213,213,42,22,33,34,0,13,23,24,214,214,214,42,35,34,51,0,25,24,38,30,30,30,42,24,36,37,0,15,26,27,215,215,215,42,52,53,37,0,40,40,27,10,10,10,42,38,54,25,0,27,41,15,216,216,216,42,26,55,41,0,16,42,16,0,0,0,42,26,27,55,0,16,17,42,217,217,217,42,27,42,56,0,17,44,43,218,218,218,42,28,43,57,0,18,46,30,219,219,219,42,29,57,44,0,31,30,49,220,220,220,42,58,59,44,0,68,50,49,37,37,37,42,30,45,46,0,20,32,33,221,221,221,42,46,60,31,0,33,52,21,222,222,222,42,42,32,61,0,44,22,53,223,223,223,42,33,48,62,0,23,54,36,224,224,224,42,35,51,49,0,25,38,35,225,225,225,42,34,62,50,0,24,36,37,226,226,226,42,51,50,64,0,38,37,59,44,44,44,42,36,47,65,0,26,34,39,227,227,227,42,37,65,52,0,27,39,40,228,228,228,42,66,67,52,0,62,62,40,0,0,0,42,38,53,54,0,27,40,41,229,229,229,42,54,68,39,0,41,64,28,230,230,230,42,40,41,69,0,29,16,65,231,231,231,42,43,40,70,0,46,29,66,232,232,232,42,44,74,58,0,49,48,68,233,233,233,42,45,59,75,0,32,50,51,234,234,234,42,60,46,88,0,52,33,70,235,235,235,42,61,49,89,0,53,35,71,236,236,236,42,51,64,78,0,38,59,56,237,237,237,42,50,79,63,0,37,57,58,238,238,238,42,52,80,66,0,40,61,62,239,239,239,42,81,82,66,0,75,75,62,3,3,3,42,53,67,83,0,40,62,63,240,240,240,42,68,54,98,0,64,41,77,241,241,241,42,55,84,71,0,42,78,42,0,0,0,42,55,56,84,0,42,43,78,242,242,242,42,85,56,102,0,79,43,80,243,243,243,42,74,57,103,0,48,30,81,244,244,244,42,60,88,76,0,52,70,60,245,245,245,42,61,89,72,0,53,71,45,246,246,246,42,79,62,109,0,57,36,83,247,247,247,42,80,65,108,0,61,39,82,248,248,248,42,81,66,93,0,75,62,84,71,71,71,42,94,95,81,0,85,85,75,0,0,0,42,96,97,82,0,126,76,75,72,72,72,42,68,98,77,0,64,77,55,249,249,249,42,71,99,69,0,42,78,65,250,250,250,42,70,69,101,0,66,65,87,251,251,251,42,70,101,73,0,66,87,47,252,252,252,42,86,104,58,0,67,88,68,77,77,77,42,74,103,86,0,48,81,67,253,253,253,42,106,87,107,0,133,69,91,79,79,79,42,75,87,88,0,51,69,70,254,254,254,42,78,90,89,0,56,72,71,255,255,255,42,64,110,90,0,59,94,72,82,82,82,42,112,63,113,0,119,58,96,83,83,83,42,79,109,91,0,57,83,73,256,256,256,42,80,108,92,0,61,82,74,257,257,257,42,93,114,81,0,84,99,75,258,258,258,42,93,92,116,0,84,74,100,87,87,87,42,117,118,94,0,101,101,85,0,0,0,42,96,82,119,0,126,75,102,259,259,259,42,96,120,97,0,126,103,76,89,89,89,42,83,97,98,0,63,76,77,260,260,260,42,99,84,123,0,78,78,105,0,0,0,42,84,85,122,0,78,79,105,261,261,261,42,85,102,124,0,79,80,106,262,262,262,42,125,126,86,0,90,108,67,93,93,93,42,104,127,105,0,88,109,89,263,263,263,42,106,107,128,0,133,91,112,264,264,264,42,106,129,87,0,133,113,69,96,96,96,42,88,130,108,0,70,92,82,265,265,265,42,89,131,102,0,71,93,80,266,266,266,42,111,110,132,0,95,94,115,267,267,267,42,90,111,131,0,72,95,93,100,100,100,42,113,134,112,0,96,117,119,268,268,268,42,113,91,136,0,96,73,120,102,102,102,42,114,93,137,0,99,84,121,269,269,269,42,116,115,129,0,100,98,113,104,104,104,42,117,94,138,0,101,85,122,270,270,270,42,139,140,117,0,123,123,101,10,10,10,42,118,141,95,0,101,124,85,271,271,271,42,119,142,96,0,102,125,126,272,272,272,42,136,135,120,0,120,97,103,108,108,108,42,98,121,109,0,77,104,83,273,273,273,42,99,123,100,0,78,105,86,274,274,274,42,100,143,101,0,86,127,87,275,275,275,42,101,144,103,0,87,128,81,276,276,276,42,122,145,123,0,105,129,105,0,0,0,42,144,147,125,0,128,130,90,113,113,113,42,126,148,104,0,108,131,88,277,277,277,42,128,151,106,0,112,132,133,278,278,278,42,132,153,111,0,115,134,95,279,279,279,42,131,133,146,0,93,116,107,117,117,117,42,134,113,156,0,117,96,136,280,280,280,42,114,137,138,0,99,121,122,281,281,281,42,137,116,151,0,121,100,132,282,282,282,42,117,138,139,0,101,122,123,283,283,283,42,158,159,139,0,139,139,123,10,10,10,42,140,160,118,0,123,140,101,284,284,284,42,119,141,142,0,102,124,125,285,285,285,42,120,142,136,0,103,125,120,286,286,286,42,124,163,122,0,106,142,105,125,125,125,42,146,154,124,0,107,135,106,126,126,126,42,143,164,144,0,127,143,128,127,127,127,42,147,165,126,0,130,144,108,287,287,287,42,105,149,107,0,89,110,91,129,129,129,42,127,166,149,0,109,145,110,288,288,288,42,127,148,166,0,109,131,145,289,289,289,42,128,150,168,0,112,111,149,290,290,290,42,169,151,168,0,156,132,149,291,291,291,42,110,112,152,0,94,119,114,134,134,134,42,132,152,170,0,115,114,151,292,292,292,42,171,153,170,0,166,134,151,293,293,293,42,133,153,154,0,116,134,135,294,294,294,42,134,172,155,0,117,153,118,295,295,295,42,134,156,172,0,117,136,153,296,296,296,42,157,137,169,0,137,121,156,297,297,297,42,138,157,174,0,122,137,138,298,298,298,42,139,174,158,0,123,138,139,299,299,299,42,158,175,159,0,139,159,139,10,10,10,42,140,159,160,0,123,139,140,300,300,300,42,160,176,141,0,140,161,124,301,301,301,42,142,161,156,0,125,141,136,302,302,302,42,123,162,143,0,105,129,127,146,146,146,42,145,177,162,0,129,162,129,0,0,0,42,163,178,145,0,142,163,129,303,303,303,42,154,179,163,0,135,152,142,304,304,304,42,147,164,165,0,130,143,144,305,305,305,42,165,180,148,0,144,165,131,306,306,306,42,181,182,149,0,146,148,110,151,151,151,42,152,155,184,0,114,118,150,152,152,152,42,153,171,179,0,134,166,152,307,307,307,42,158,186,175,0,139,158,159,308,308,308,42,176,160,201,0,161,140,169,309,309,309,42,164,162,189,0,143,129,164,310,310,310,42,180,165,208,0,165,144,170,311,311,311,42,191,192,181,0,173,171,146,160,160,160,42,181,166,191,0,146,145,173,312,312,312,42,166,167,193,0,145,147,172,313,313,313,42,168,182,195,0,149,148,175,314,314,314,42,169,168,185,0,156,149,157,315,315,315,42,184,183,197,0,150,154,177,166,166,166,42,170,184,198,0,151,150,178,316,316,316,42,171,170,199,0,166,151,179,317,317,317,42,183,172,196,0,154,153,176,318,318,318,42,172,173,201,0,153,155,169,319,319,319,42,186,174,195,0,158,138,175,320,320,320,42,203,204,175,0,180,180,159,10,10,10,42,159,187,188,0,139,159,160,321,321,321,42,190,177,206,0,162,162,182,3,3,3,42,178,207,177,0,163,183,162,322,322,322,42,178,179,207,0,163,152,183,323,323,323,42,209,202,191,0,186,168,173,175,175,175,42,180,208,194,0,165,170,174,324,324,324,42,197,196,211,0,177,176,185,177,177,177,42,203,175,209,0,180,159,186,325,325,325,42,186,195,202,0,158,175,168,326,326,326,42,212,213,203,0,187,187,180,3,3,3,42,211,210,204,0,185,181,180,181,181,181,42,188,210,201,0,160,181,169,327,327,327,42,189,190,208,0,164,162,170,328,328,328,42,206,205,215,0,182,182,188,3,3,3,42,191,193,209,0,173,172,186,329,329,329,42,216,193,217,0,189,172,184,330,330,330,42,197,211,198,0,177,185,178,331,331,331,42,199,198,219,0,179,178,191,332,332,332,42,199,219,200,0,179,191,167,333,333,333,42,209,216,203,0,186,189,180,334,334,334,42,215,214,212,0,188,188,187,3,3,3,42,213,218,204,0,187,190,180,335,335,335,42,208,206,217,0,170,182,184,336,336,336,42,205,207,214,0,182,183,188,337,337,337,42,216,217,212,0,189,184,187,338,338,338,42,214,219,213,0,188,191,187,339,339,339,42,1,2,3,0,50,68,89,3,3,3,42,0,1,3,0,91,50,89,3,3,3]
+
+}
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_front.json b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_front.json
new file mode 100644
index 0000000..0094b26
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_front.json
@@ -0,0 +1,34 @@
+{
+
+ "metadata" :
+ {
+ "formatVersion" : 3.1,
+ "sourceFile" : "cellphone_front.obj",
+ "generatedBy" : "OBJConverter",
+ "vertices" : 4,
+ "faces" : 1,
+ "normals" : 1,
+ "colors" : 0,
+ "uvs" : 4,
+ "materials" : 0
+ },
+
+ "scale" : 1.000000,
+
+ "materials": [],
+
+ "vertices": [0.475000,0.025000,-0.974999,0.474999,0.025000,0.975000,-0.475000,0.025000,0.974999,-0.475000,0.025000,-0.975000],
+
+ "morphTargets": [],
+
+ "morphColors": [],
+
+ "normals": [0,1,0],
+
+ "colors": [],
+
+ "uvs": [[0,0,1,0,1,1,0,1]],
+
+ "faces": [43,0,3,2,1,0,0,1,2,3,0,0,0,0]
+
+}
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_icon.json b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_icon.json
new file mode 100644
index 0000000..4ab9d53
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphone_icon.json
@@ -0,0 +1,34 @@
+{
+
+ "metadata" :
+ {
+ "formatVersion" : 3.1,
+ "sourceFile" : "cellphone_icon.obj",
+ "generatedBy" : "OBJConverter",
+ "vertices" : 4,
+ "faces" : 2,
+ "normals" : 1,
+ "colors" : 0,
+ "uvs" : 4,
+ "materials" : 0
+ },
+
+ "scale" : 1.000000,
+
+ "materials": [],
+
+ "vertices": [-0.119373,-0.026000,0.625100,-0.119373,-0.026000,0.386354,0.119373,-0.026000,0.386354,0.119373,-0.026000,0.625100],
+
+ "morphTargets": [],
+
+ "morphColors": [],
+
+ "normals": [0,-1,0],
+
+ "colors": [],
+
+ "uvs": [[0,0,1,0,1,1,0,1]],
+
+ "faces": [42,1,2,3,0,0,1,2,0,0,0,42,0,1,3,0,3,0,2,0,0,0]
+
+}
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphoneapp.qml b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphoneapp.qml
new file mode 100644
index 0000000..6af000c
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphoneapp.qml
@@ -0,0 +1,376 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 1.2
+
+Rectangle {
+ id: mainScreen
+ property color backgroundColor
+ property color textColor
+ signal locked
+ color: backgroundColor
+ // The state indicates which app is to be shown on the screen.
+ state: "menu"
+ states: [
+ State {
+ name: "menu"
+ PropertyChanges {
+ target: menuApp; visible: true
+ }
+ },
+ State {
+ name: "about"
+ PropertyChanges {
+ target: aboutApp; visible: true
+ }
+ },
+ State {
+ name: "dummy"
+ PropertyChanges {
+ target: dummyApp; visible: true
+ }
+ }
+ ]
+
+ // This model contains names, icons, and corresponsing mainScreen states of phone apps
+ ListModel {
+ id: appGridModel
+ ListElement {
+ name: "Calendar"
+ image: "qrc:/calendar.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Camera"
+ image: "qrc:/camera.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Clock"
+ image: "qrc:/clock.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Contacts"
+ image: "qrc:/contacts.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Gallery"
+ image: "qrc:/gallery.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Games"
+ image: "qrc:/games.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Mail"
+ image: "qrc:/mail.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Maps"
+ image: "qrc:/maps.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Music"
+ image: "qrc:/music.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Settings"
+ image: "qrc:/settings.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Todo"
+ image: "qrc:/todo.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "Videos"
+ image: "qrc:/videos.png"
+ toState: "dummy"
+ }
+ ListElement {
+ name: "About"
+ image: "qrc:/qtlogo_with_alpha.png"
+ toState: "about"
+ }
+ ListElement {
+ name: "Lock"
+ image: "qrc:/lock.png"
+ toState: "lock"
+ }
+ }
+
+ Timer {
+ id: clockTimer
+ interval: 1000
+ repeat: true
+ running: lockScreen.visible || menuApp.visible
+ triggeredOnStart: true
+ onTriggered: clockLabel.text = Qt.formatDateTime(new Date(), "hh:mm:ss")
+ }
+
+ // This grid shows the app menu on the phone
+ Rectangle {
+ id: menuApp
+ visible: false
+ anchors.fill: parent
+ color: mainScreen.color
+ Image {
+ anchors.fill: parent
+ source: "qrc:/menu_background.jpg"
+ }
+ Rectangle {
+ id: menuHeader
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.margins: 16
+ height: parent.height / 24
+ color: "transparent"
+ Label {
+ id: menuClockLabel
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ width: menuHeader.width
+ text: clockLabel.text
+ color: mainScreen.textColor
+ font.pixelSize: 24
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ GridView {
+ id: menu
+ anchors.top: menuHeader.bottom
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.margins: 16
+ model: appGridModel
+ cellWidth: width / 3
+ cellHeight: cellWidth
+ interactive: false
+ delegate: Component {
+ id: appGridDelegate
+ Item {
+ id: wrapper
+ width: menu.cellWidth
+ height: menu.cellHeight
+ Column {
+ anchors.fill: parent
+ height: width
+ Image {
+ width: (parent.width * 3) / 4
+ height : width
+ source: image
+ anchors.horizontalCenter: parent.horizontalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ // Lock option is a special case, as it doesn't launch
+ // an app. Instead it simply slides the lock screen over
+ // the current app.
+ if (toState === "lock") {
+ mainScreen.lock()
+ } else if (toState === "dummy"){
+ dummyApp.dummyImage = image
+ mainScreen.state = toState
+ } else {
+ mainScreen.state = toState
+ mainScreen.resetLockTimer()
+ }
+ }
+ }
+ }
+ Text {
+ width: parent.width
+ height: parent.width / 4
+ text: name
+ font.pixelSize: 20
+ color: mainScreen.textColor
+ horizontalAlignment: Text.AlignHCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: aboutApp
+ anchors.fill: parent
+ anchors.margins: 16
+ color: mainScreen.backgroundColor
+ visible: false
+ Label {
+ anchors.fill: parent
+ text: "This example demonstrates how to use Qt Quick Item as a texture source"
+ + " for Canvas3D in conjunction with three.js."
+ + "\n\nClick outside the phone to restart the rotation animation."
+ color: mainScreen.textColor
+ font.pixelSize: 24
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ mainScreen.state = "menu"
+ mainScreen.resetLockTimer()
+ }
+ }
+ }
+
+ Rectangle {
+ id: dummyApp
+ property string dummyImage
+ anchors.fill: parent
+ anchors.margins: 16
+ color: mainScreen.backgroundColor
+ visible: false
+ Image {
+ anchors.centerIn: parent
+ width: parent.width / 2
+ height: width
+ source: parent.dummyImage
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ mainScreen.state = "menu"
+ mainScreen.resetLockTimer()
+ }
+ }
+ }
+
+ Flickable {
+ id: lockScreen
+ property int flickSpeed: 1500
+
+ anchors.fill: parent
+ z: mainScreen.z + 0.1
+ contentWidth: clock.width
+ contentHeight: clock.height
+ contentX: 0
+ boundsBehavior: Flickable.StopAtBounds
+ flickDeceleration: 0
+ onMovementStarted: {
+ // Interpret all drags as flicks instead
+ if (interactive)
+ flick(-flickSpeed, 0)
+ interactive = false
+ }
+ onFlickStarted: {
+ // All flicks will open the screen at consistent speed
+ if (interactive)
+ flick(-flickSpeed, 0)
+ interactive = false
+ }
+ onFlickEnded: {
+ if (contentX == 0) {
+ interactive = true
+ } else {
+ visible = false
+ mainScreen.resetLockTimer()
+ }
+ }
+
+ Timer {
+ id: lockTimer
+ interval: 60000
+ repeat: false
+ onTriggered: mainScreen.lock()
+ }
+
+ Item {
+ id: clock
+ width: lockScreen.width * 2
+ height: lockScreen.height
+ Rectangle {
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ x: 0
+ width: lockScreen.width
+ color: mainScreen.backgroundColor
+ Label {
+ id: clockLabel
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ width: lockScreen.width
+ text: Qt.formatDateTime(new Date(), "hh:mm:ss")
+ color: mainScreen.textColor
+ font.pixelSize: 60
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ Label {
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ height: 48
+ width: lockScreen.width
+ text: "Swipe left to unlock"
+ color: mainScreen.textColor
+ font.pixelSize: 24
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ }
+ }
+
+ function lock() {
+ lockTimer.stop()
+ lockScreen.visible = true
+ lockScreen.flick(lockScreen.flickSpeed, 0)
+ locked() // emit
+ }
+
+ function resetLockTimer() {
+ lockTimer.restart()
+ }
+}
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphonecanvas.qml b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphonecanvas.qml
new file mode 100644
index 0000000..0bc3d16
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/cellphonecanvas.qml
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtCanvas3D 1.1
+
+import "cellphone.js" as GLCode
+
+Canvas3D {
+ id: canvas3d
+ property double xRotAnim: 0
+ property double yRotAnim: 0
+ property double zRotAnim: 0
+ property double rotateDistance: 2
+ property double uiDistance: 1.51 // This distance is selected so that UI on model matches the size of QML UI
+ property double distance: rotateDistance
+ property double cameraAngle: 0
+ property string caseColor: "#eeeeee"
+ property Item textureSource
+ signal rotationStopped
+ signal rotationStarted
+
+ Component.onCompleted: {
+ GLCode.setSphereTexture("qrc:/plutomap1k.jpg")
+ GLCode.setIconTexture("qrc:/qtlogo_with_alpha.png")
+ GLCode.setMeshFiles("qrc:/cellphone_case.json",
+ "qrc:/cellphone_front.json",
+ "qrc:/cellphone_icon.json")
+ GLCode.setCaseColor(caseColor);
+ }
+ //! [1]
+ onInitializeGL: GLCode.initializeGL(canvas3d, textureSource)
+ //! [1]
+ onPaintGL: GLCode.paintGL(canvas3d)
+ onResizeGL: GLCode.resizeGL(canvas3d)
+ onCaseColorChanged: GLCode.setCaseColor(caseColor)
+
+ state: "running"
+ states: [
+ State {
+ name: "running"
+ StateChangeScript {
+ script: {
+ resetAnimationX.stop()
+ resetAnimationY.stop()
+ resetAnimationZ.stop()
+ resetAnimationDistance.stop()
+ resetAnimationDistance.duration = 2000
+ resetAnimationDistance.from = canvas3d.distance
+ resetAnimationDistance.to = canvas3d.rotateDistance
+ resetAnimationDistance.start()
+ objAnimationX.start()
+ objAnimationY.start()
+ objAnimationZ.start()
+ rotationStarted()
+ }
+ }
+ },
+ State {
+ name: "stopped"
+ StateChangeScript {
+ script: {
+ objAnimationX.stop()
+ objAnimationY.stop()
+ objAnimationZ.stop()
+ resetAnimationDistance.stop()
+ resetAnimationX.from = canvas3d.xRotAnim
+ resetAnimationY.from = canvas3d.yRotAnim
+ resetAnimationZ.from = canvas3d.zRotAnim
+ resetAnimationDistance.duration = resetAnimationX.duration
+ resetAnimationDistance.from = canvas3d.distance
+ resetAnimationDistance.to = canvas3d.uiDistance
+ resetAnimationDistance.start()
+ resetAnimationX.start()
+ resetAnimationY.start()
+ resetAnimationZ.start()
+ rotationStopped()
+ }
+ }
+ }
+ ]
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (canvas3d.state === "stopped")
+ canvas3d.state = "running"
+ else
+ canvas3d.state = "stopped"
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationX
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: -90.0
+ to: 270.0
+ duration: 9200
+ easing.type: Easing.InOutQuad
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 270.0
+ to: -90.0
+ duration: 9200
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationY
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 0.0
+ to: 360.0
+ duration: 8500
+ easing.type: Easing.InOutCubic
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 360.0
+ to: 0.0
+ duration: 8500
+ easing.type: Easing.InOutCubic
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationZ
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: 180.0
+ to: -180.0
+ duration: 7600
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: -180.0
+ to: 180.0
+ duration: 7600
+ easing.type: Easing.InOutSine
+ }
+ }
+
+ NumberAnimation {
+ id: resetAnimationX
+ running: false
+ loops: 1
+ target: canvas3d
+ property: "xRotAnim"
+ from: 0.0
+ to: -90.0
+ duration: 600
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ id: resetAnimationY
+ running: false
+ loops: 1
+ target: canvas3d
+ property: "yRotAnim"
+ from: 0.0
+ to: 0.0
+ duration: resetAnimationX.duration
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ id: resetAnimationZ
+ running: false
+ loops: 1
+ target: canvas3d
+ property: "zRotAnim"
+ from: 0.0
+ to: 180.0
+ duration: resetAnimationX.duration
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ id: resetAnimationDistance
+ running: false
+ loops: 1
+ target: canvas3d
+ property: "distance"
+ from: canvas3d.rotateDistance
+ to: canvas3d.uiDistance
+ duration: resetAnimationX.duration
+ easing.type: Easing.InOutSine
+ }
+ RotationAnimation {
+ id: cameraRotationAnimation
+ running: true
+ target: canvas3d
+ property: "cameraAngle"
+ loops: Animation.Infinite
+ from: 0
+ to: 360
+ duration: 60000
+ direction: RotationAnimation.Clockwise
+ }
+}
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/colorselector.qml b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/colorselector.qml
new file mode 100644
index 0000000..08d48bf
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/colorselector.qml
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+
+Item {
+ id: colorSelector
+ property color selectedColor
+
+ height: ((width - 4) * colorSelectorModel.count) + 4
+
+ Rectangle {
+ anchors.fill: parent
+ color: "black"
+ radius: width / 10
+ opacity: 0.3
+ }
+
+ ListModel {
+ id: colorSelectorModel
+ ListElement { caseColor: "#eeeeee" }
+ ListElement { caseColor: "#111111" }
+ ListElement { caseColor: "#ffe400" }
+ ListElement { caseColor: "#469835" }
+ ListElement { caseColor: "#fa0000" }
+ }
+
+ GridView {
+ id: colorSelectorGrid
+ anchors.fill: colorSelector
+ anchors.margins: 4
+ model: colorSelectorModel
+ interactive: false
+ cellWidth: width
+ cellHeight: cellWidth + 4
+ delegate: Component {
+ Rectangle {
+ id: colorDelegate
+ width: colorSelectorGrid.cellWidth
+ height: colorSelectorGrid.cellWidth
+ color: caseColor
+ border.color: "lightgray"
+ border.width: 2
+ radius: width / 10
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ selectedColor = parent.color
+ colorDelegateAnimation.start()
+ }
+ }
+ NumberAnimation {
+ id: colorDelegateAnimation
+ running: false
+ loops: 1
+ target: colorDelegate
+ property: "opacity"
+ from: 0.1
+ to: 1.0
+ duration: 500
+ }
+ }
+ }
+ }
+}
+
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/fpsdisplay.qml b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/fpsdisplay.qml
new file mode 100644
index 0000000..f6acc0d
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/fpsdisplay.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: fpsDisplayControl
+ property bool hidden: true
+ property real fps: 0.0
+
+ onFpsChanged: fpsDisplay.updateFps();
+
+ Rectangle {
+ anchors.fill: parent
+ id: fpsDisplay
+ color: "black"
+ visible: !fpsDisplayControl.hidden
+
+ property real maxFps: 60.0
+ property color maxFpsColor: "#00FF00"
+ property color minFpsColor: "#FF0000"
+
+ function updateFps() {
+ var scale = (fps > maxFps)?1.0:(fps/maxFps);
+ var r = (1 - scale) * minFpsColor.r + scale * maxFpsColor.r;
+ var g = (1 - scale) * minFpsColor.g + scale * maxFpsColor.g;
+ var b = (1 - scale) * minFpsColor.b + scale * maxFpsColor.b;
+ var a = (1 - scale) * minFpsColor.a + scale * maxFpsColor.a;
+ fpsCauge.height = scale * fpsDisplay.height;
+ fpsCauge.color = Qt.rgba(r,g,b,a);
+ }
+
+ Rectangle {
+ id: fpsCauge
+ width: parent.width
+ anchors.bottom: parent.bottom
+ }
+
+ Text {
+ id: fpsText
+ text: ""+(fps | 0)
+ font.family: "Helvetica"
+ font.pixelSize: 16
+ font.weight: Font.Light
+ color: "white"
+ anchors.fill: parent
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: fpsDisplayControl.hidden = !fpsDisplayControl.hidden;
+ }
+}
+
diff --git a/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/main.qml b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/main.qml
new file mode 100644
index 0000000..5598478
--- /dev/null
+++ b/examples/canvas3d/canvas3d/threejs/cellphone/qml/cellphone/main.qml
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Window 2.2
+
+Window {
+ property int initialWidth: 800
+ property int initialHeight: 600
+ id: mainView
+ width: initialWidth
+ height: initialHeight
+ visible: true
+ title: "Interactive Mobile Phone Demo"
+
+ //! [0]
+ Item {
+ id: textureSource
+ layer.enabled: true
+ layer.smooth: true
+ layer.textureMirroring: ShaderEffectSource.NoMirroring
+ //! [0]
+ anchors.centerIn: parent
+ // The dimensions of the texture source item determine the actual OpenGL texture dimensions.
+ // We want a fairly large texture, so that even the smallest text we use renders nicely.
+ width: 512
+ height: 1024
+ // Hide texture source behind the canvas normally, so you can't interact with it.
+ // It would also be possible to set visible property to false instead, but if the item
+ // is hidden, some things don't update correctly. For example, the Flickable doesn't update
+ // its content if it is not visible.
+ z: -2
+ // Specify transform to make the visual representation of the item match the size and
+ // orientation of the ui presented in Canvas. If the window initial dimensions,
+ // textureSource dimensions, or phone mesh dimensions or position are changed,
+ // scaling needs to be adjusted accordingly.
+ //! [2]
+ transform: [
+ Scale {
+ origin.y: textureSource.height / 2
+ origin.x: textureSource.width / 2
+ yScale: 0.5 * mainView.height / mainView.initialHeight
+ xScale: 0.5 * mainView.height / mainView.initialHeight
+ }
+ ]
+ opacity: 0.0
+ //! [2]
+
+ // CellphoneApp implements the UI of the phone
+ CellphoneApp {
+ id: cellphoneApp
+ anchors.fill: parent
+ backgroundColor: "black"
+ textColor: "white"
+ onLocked: canvas3d.state = "running"
+ }
+ }
+
+ // CellphoneCanvas displays the rotating phone and the color selector
+ CellphoneCanvas {
+ id: canvas3d
+ anchors.fill:parent
+ textureSource: textureSource
+ onRotationStopped: {
+ cellphoneApp.resetLockTimer()
+ // Bring the UI to the foreground so that it can be interacted with
+ textureSource.z = 1
+ }
+ onRotationStarted: {
+ // Hide the texture source behind canvas to ensure UI cannot be
+ // interacted while the phone is rotating.
+ textureSource.z = -1
+ }
+ }
+
+ ColorSelector {
+ anchors.right: parent.right
+ anchors.top: parent.top
+ width: parent.width / 16
+
+ onSelectedColorChanged: canvas3d.caseColor = selectedColor
+ }
+
+ // FPS display, initially hidden, clicking will show it
+ FpsDisplay {
+ anchors.left: parent.left
+ anchors.top: parent.top
+ width: 32
+ height: 64
+ fps: canvas3d.fps
+ }
+}
diff --git a/examples/canvas3d/canvas3d/threejs/threejs.pro b/examples/canvas3d/canvas3d/threejs/threejs.pro
index c39ab7f..2c25e84 100644
--- a/examples/canvas3d/canvas3d/threejs/threejs.pro
+++ b/examples/canvas3d/canvas3d/threejs/threejs.pro
@@ -1,5 +1,6 @@
TEMPLATE = subdirs
SUBDIRS += oneqt \
- planets
+ planets \
+ cellphone
EXAMPLE_FILES = controls