# lib/effects/CardboardEffect.js

    import * as THREE from 'three';

    /**
     * @classdesc Google Cardboard Effect Composer
     * @constructor
     * @external CardboardEffect
     * @param {THREE.WebGLRenderer} renderer
     */
    function CardboardEffect ( renderer ) {

        var _camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );

        var _scene = new THREE.Scene();

        var _stereo = new THREE.StereoCamera();
        _stereo.aspect = 0.5;

        var _params = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat };

        var _renderTarget = new THREE.WebGLRenderTarget( 512, 512, _params );
        _renderTarget.scissorTest = true;
        _renderTarget.texture.generateMipmaps = false;

        /*
         * Distortion Mesh ported from:
         * https://github.com/borismus/webvr-boilerplate/blob/master/src/distortion/barrel-distortion-fragment.js
         */

        var distortion = new THREE.Vector2( 0.441, 0.156 );

        var geometry = new THREE.PlaneBufferGeometry( 1, 1, 10, 20 ).removeAttribute( 'normal' ).toNonIndexed();

        var positions = geometry.attributes.position.array;
        var uvs = geometry.attributes.uv.array;

        // duplicate
        geometry.attributes.position.count *= 2;
        geometry.attributes.uv.count *= 2;

        var positions2 = new Float32Array( positions.length * 2 );
        positions2.set( positions );
        positions2.set( positions, positions.length );

        var uvs2 = new Float32Array( uvs.length * 2 );
        uvs2.set( uvs );
        uvs2.set( uvs, uvs.length );

        var vector = new THREE.Vector2();
        var length = positions.length / 3;

        for ( var i = 0, l = positions2.length / 3; i < l; i ++ ) {

            vector.x = positions2[ i * 3 + 0 ];
            vector.y = positions2[ i * 3 + 1 ];

            var dot = vector.dot( vector );
            var scalar = 1.5 + ( distortion.x + distortion.y * dot ) * dot;

            var offset = i < length ? 0 : 1;

            positions2[ i * 3 + 0 ] = ( vector.x / scalar ) * 1.5 - 0.5 + offset;
            positions2[ i * 3 + 1 ] = ( vector.y / scalar ) * 3.0;

            uvs2[ i * 2 ] = ( uvs2[ i * 2 ] + offset ) * 0.5;

        }

        geometry.attributes.position.array = positions2;
        geometry.attributes.uv.array = uvs2;

        //

        var material = new THREE.MeshBasicMaterial( { map: _renderTarget.texture } );
        var mesh = new THREE.Mesh( geometry, material );
        _scene.add( mesh );

        //

        this.setSize = function ( width, height ) {

            renderer.setSize( width, height );

            var pixelRatio = renderer.getPixelRatio();

            _renderTarget.setSize( width * pixelRatio, height * pixelRatio );

        };

        this.render = function ( scene, camera ) {

            scene.updateMatrixWorld();

            if ( camera.parent === null ) camera.updateMatrixWorld();

            _stereo.update( camera );

            var width = _renderTarget.width / 2;
            var height = _renderTarget.height;

            if ( renderer.autoClear ) renderer.clear();

            _renderTarget.scissor.set( 0, 0, width, height );
            _renderTarget.viewport.set( 0, 0, width, height );
            renderer.setRenderTarget( _renderTarget );
            renderer.render( scene, _stereo.cameraL );

            renderer.clearDepth();

            _renderTarget.scissor.set( width, 0, width, height );
            _renderTarget.viewport.set( width, 0, width, height );
            renderer.setRenderTarget( _renderTarget );
            renderer.render( scene, _stereo.cameraR );

            renderer.clearDepth();

            renderer.setRenderTarget( null );
            renderer.render( _scene, _camera );
        };

    };

    export { CardboardEffect };