diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/plaincanvas3d/glcode.js b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/plaincanvas3d/glcode.js index 690cad8758a..154e85b8090 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/plaincanvas3d/glcode.js +++ b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/plaincanvas3d/glcode.js @@ -1,6 +1,5 @@ // -// Draws a cube that has different colors assigned to the vertices. -// Each face of the cube has the linear interpolation of the corner colors. +// Draws a plain green cube. // var gl; @@ -8,10 +7,8 @@ var vertexPositionAttrLoc; var shaderProgram; var cubeVertexPositionBuffer; var cubeVertexIndexBuffer; -var cubeVertexColorBuffer; var vertexShader; var fragmentShader; -var vertexColorAttrLoc; var pMatrixUniformLoc; var mvMatrixUniformLoc; @@ -26,7 +23,6 @@ function initializeGL(canvas) { // Setup the OpenGL state gl.enable(gl.DEPTH_TEST); - gl.enable(gl.DEPTH_WRITE); gl.depthMask(true); gl.enable(gl.CULL_FACE); gl.cullFace(gl.BACK); @@ -35,7 +31,7 @@ function initializeGL(canvas) { // Set viewport gl.viewport(0, 0, canvas.width * canvas.devicePixelRatio, canvas.height * canvas.devicePixelRatio); - // Initialize vertex and color buffers + // Initialize vertex and element array buffers initBuffers(); // Initialize the shader program @@ -78,17 +74,13 @@ function paintGL(canvas) { gl.enableVertexAttribArray(vertexPositionAttrLoc); gl.vertexAttribPointer(vertexPositionAttrLoc, 3, gl.FLOAT, false, 0, 0); - gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer); - gl.enableVertexAttribArray(vertexColorAttrLoc); - gl.vertexAttribPointer(vertexColorAttrLoc, 4, gl.FLOAT, false, 0, 0); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); } function initBuffers() { - // Create a cubeVertexPositionBuffer and put a single clipspace rectangle in - // it (2 triangles) + // Create a buffer for cube vertices. Since we are not using textures, we don't need unique + // vertices for each face. We can define the cube using 8 vertices. cubeVertexPositionBuffer = gl.createBuffer(); cubeVertexPositionBuffer.name = "cubeVertexPositionBuffer"; gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer); @@ -107,6 +99,8 @@ function initBuffers() { ]), gl.STATIC_DRAW); + // Create buffer for element array indices. We define six sides, each composed of two + // triangles, using the vertices defined above. cubeVertexIndexBuffer = gl.createBuffer(); cubeVertexIndexBuffer.name = "cubeVertexIndexBuffer"; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); @@ -131,36 +125,17 @@ function initBuffers() { 6, 2, 1 ]), gl.STATIC_DRAW); - - cubeVertexColorBuffer = gl.createBuffer(); - cubeVertexColorBuffer.name = "cubeVertexColorBuffer"; - gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([// front - 0.000, 1.000, 0.000, - 1.000, 0.000, 1.000, - 1.000, 1.000, 0.000, - 1.000, 0.000, 0.000, - // back - 0.435, 0.602, 0.223, - 0.310, 0.747, 0.185, - 1.000, 1.000, 1.000, - 0.000, 0.000, 1.000 - ]), gl.STATIC_DRAW); } function initShaders() { vertexShader = getShader(gl, "attribute highp vec3 aVertexPosition; \ - attribute highp vec4 aVertexColor; \ uniform highp mat4 uMVMatrix; \ uniform highp mat4 uPMatrix; \ - varying highp vec4 vColor; \ void main(void) { \ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); \ - vColor = aVertexColor; \ }", gl.VERTEX_SHADER); - fragmentShader = getShader(gl, "varying highp vec4 vColor; \ - void main(void) { \ - gl_FragColor = vColor; \ + fragmentShader = getShader(gl, "void main(void) { \ + gl_FragColor = vec4(0.5, 0.76, 0.26, 1.0); \ }", gl.FRAGMENT_SHADER); shaderProgram = gl.createProgram(); @@ -179,8 +154,6 @@ function initShaders() { // look up where the vertex data needs to go. vertexPositionAttrLoc = gl.getAttribLocation(shaderProgram, "aVertexPosition"); gl.enableVertexAttribArray(vertexPositionAttrLoc); - vertexColorAttrLoc = gl.getAttribLocation(shaderProgram, "aVertexColor"); - gl.enableVertexAttribArray(vertexColorAttrLoc); pMatrixUniformLoc = gl.getUniformLocation(shaderProgram, "uPMatrix"); pMatrixUniformLoc.name = "pMatrixUniformLoc"; diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/threejs/3rdparty/three.js b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/threejs/3rdparty/three.js index 04823db120c..be4298c93cf 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/threejs/3rdparty/three.js +++ b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/threejs/3rdparty/three.js @@ -30,6435 +30,6 @@ THE SOFTWARE. * @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 +28871,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.QuickItemTexture ) { + + 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/QuickItemTexture.js + +/** + * @author miheikki / miikka.heikkinen@theqtcompany.com + */ + +THREE.QuickItemTexture = 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.QuickItemTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.QuickItemTexture.prototype.constructor = THREE.QuickItemTexture; + diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/threejs/glcode.js b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/threejs/glcode.js index 8202b42181d..082d605d951 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/threejs/glcode.js +++ b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/threejs/glcode.js @@ -13,6 +13,7 @@ function initializeGL(canvas) { shading: THREE.SmoothShading }); var cubeGeometry = new THREE.BoxGeometry(1, 1, 1); cube = new THREE.Mesh(cubeGeometry, material); + cube.rotation.set(0.785, 0.785, 0.0); scene.add(cube); renderer = new THREE.Canvas3DRenderer( @@ -29,8 +30,5 @@ function resizeGL(canvas) { } function paintGL(canvas) { - cube.rotation.x += 0.01; - cube.rotation.y += 0.01; - renderer.render(scene, camera); }