<|start_filename|>lib/extras/shaders/ocean_shaders.dart<|end_filename|>
part of three_shaders;

// Author: <NAME>
// Website: www.routter.co.tt

// Description: A deep water ocean shader set
// based on an implementation of a Tessendorf Waves
// originally presented by <NAME> ( www.david.li/waves )

// The general method is to apply shaders to simulation Framebuffers
// and then sample these framebuffers when rendering the ocean mesh

// The set uses 7 shaders:

// -- Simulation shaders
// [1] ocean_sim_vertex         -> Vertex shader used to set up a 2x2 simulation plane centered at (0,0)
// [2] ocean_subtransform       -> Fragment shader used to subtransform the mesh (generates the displacement map)
// [3] ocean_initial_spectrum   -> Fragment shader used to set intitial wave frequency at a texel coordinate
// [4] ocean_phase              -> Fragment shader used to set wave phase at a texel coordinate
// [5] ocean_spectrum           -> Fragment shader used to set current wave frequency at a texel coordinate
// [6] ocean_normal             -> Fragment shader used to set face normals at a texel coordinate

// -- Rendering Shader
// [7] ocean_main               -> Vertex and Fragment shader used to create the final render

var OceanShaders = new Map()
    ..['ocean_sim_vertex'] = {
      'varying': {
        "vUV": {
          'type': "v2"
        }
      },
      'vertexShader': [
          'varying vec2 vUV;',
          'void main (void) {',
          'vUV = position.xy * 0.5 + 0.5;',
          'gl_Position = vec4(position, 1.0 );',
          '}'].join('\n')
    }
    ..['ocean_subtransform'] = {
      'uniforms': {
        "u_input": {
          'type': "t",
          'value': null
        },
        "u_transformSize": {
          'type': "f",
          'value': 512.0
        },
        "u_subtransformSize": {
          'type': "f",
          'value': 250.0
        }
      },
      'varying': {
        "vUV": {
          'type': "v2"
        }
      },
      'fragmentShader': [//GPU FFT using a Stockham formulation
        'precision highp float;',
            'const float PI = 3.14159265359;',
            'uniform sampler2D u_input;',
            'uniform float u_transformSize;',
            'uniform float u_subtransformSize;',
            'varying vec2 vUV;',
            'vec2 multiplyComplex (vec2 a, vec2 b) {',
            'return vec2(a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]);',
            '}',
            'void main (void) {',
            '#ifdef HORIZONTAL',
            'float index = vUV.x * u_transformSize - 0.5;',
            '#else',
            'float index = vUV.y * u_transformSize - 0.5;',
            '#endif',
            'float evenIndex = floor(index / u_subtransformSize) * (u_subtransformSize * 0.5) + mod(index, u_subtransformSize * 0.5);',
            //transform two complex sequences simultaneously
        '#ifdef HORIZONTAL',
            'vec4 even = texture2D(u_input, vec2(evenIndex + 0.5, gl_FragCoord.y) / u_transformSize).rgba;',
            'vec4 odd = texture2D(u_input, vec2(evenIndex + u_transformSize * 0.5 + 0.5, gl_FragCoord.y) / u_transformSize).rgba;',
            '#else',
            'vec4 even = texture2D(u_input, vec2(gl_FragCoord.x, evenIndex + 0.5) / u_transformSize).rgba;',
            'vec4 odd = texture2D(u_input, vec2(gl_FragCoord.x, evenIndex + u_transformSize * 0.5 + 0.5) / u_transformSize).rgba;',
            '#endif',
            'float twiddleArgument = -2.0 * PI * (index / u_subtransformSize);',
            'vec2 twiddle = vec2(cos(twiddleArgument), sin(twiddleArgument));',
            'vec2 outputA = even.xy + multiplyComplex(twiddle, odd.xy);',
            'vec2 outputB = even.zw + multiplyComplex(twiddle, odd.zw);',
            'gl_FragColor = vec4(outputA, outputB);',
            '}'].join('\n')
    }
    ..['ocean_initial_spectrum'] = {
      'uniforms': {
        "u_wind": {
          'type': "v2",
          'value': new Vector2(10.0, 10.0)
        },
        "u_resolution": {
          'type': "f",
          'value': 512.0
        },
        "u_size": {
          'type': "f",
          'value': 250.0
        },
      },
      'fragmentShader': [
          'precision highp float;',
          'const float PI = 3.14159265359;',
          'const float G = 9.81;',
          'const float KM = 370.0;',
          'const float CM = 0.23;',
          'uniform vec2 u_wind;',
          'uniform float u_resolution;',
          'uniform float u_size;',
          'float square (float x) {',
          'return x * x;',
          '}',
          'float omega (float k) {',
          'return sqrt(G * k * (1.0 + square(k / KM)));',
          '}',
          'float tanh (float x) {',
          'return (1.0 - exp(-2.0 * x)) / (1.0 + exp(-2.0 * x));',
          '}',
          'void main (void) {',
          'vec2 coordinates = gl_FragCoord.xy - 0.5;',
          'float n = (coordinates.x < u_resolution * 0.5) ? coordinates.x : coordinates.x - u_resolution;',
          'float m = (coordinates.y < u_resolution * 0.5) ? coordinates.y : coordinates.y - u_resolution;',
          'vec2 K = (2.0 * PI * vec2(n, m)) / u_size;',
          'float k = length(K);',
          'float l_wind = length(u_wind);',
          'float Omega = 0.84;',
          'float kp = G * square(Omega / l_wind);',
          'float c = omega(k) / k;',
          'float cp = omega(kp) / kp;',
          'float Lpm = exp(-1.25 * square(kp / k));',
          'float gamma = 1.7;',
          'float sigma = 0.08 * (1.0 + 4.0 * pow(Omega, -3.0));',
          'float Gamma = exp(-square(sqrt(k / kp) - 1.0) / 2.0 * square(sigma));',
          'float Jp = pow(gamma, Gamma);',
          'float Fp = Lpm * Jp * exp(-Omega / sqrt(10.0) * (sqrt(k / kp) - 1.0));',
          'float alphap = 0.006 * sqrt(Omega);',
          'float Bl = 0.5 * alphap * cp / c * Fp;',
          'float z0 = 0.000037 * square(l_wind) / G * pow(l_wind / cp, 0.9);',
          'float uStar = 0.41 * l_wind / log(10.0 / z0);',
          'float alpham = 0.01 * ((uStar < CM) ? (1.0 + log(uStar / CM)) : (1.0 + 3.0 * log(uStar / CM)));',
          'float Fm = exp(-0.25 * square(k / KM - 1.0));',
          'float Bh = 0.5 * alpham * CM / c * Fm * Lpm;',
          'float a0 = log(2.0) / 4.0;',
          'float am = 0.13 * uStar / CM;',
          'float Delta = tanh(a0 + 4.0 * pow(c / cp, 2.5) + am * pow(CM / c, 2.5));',
          'float cosPhi = dot(normalize(u_wind), normalize(K));',
          'float S = (1.0 / (2.0 * PI)) * pow(k, -4.0) * (Bl + Bh) * (1.0 + Delta * (2.0 * cosPhi * cosPhi - 1.0));',
          'float dk = 2.0 * PI / u_size;',
          'float h = sqrt(S / 2.0) * dk;',
          'if (K.x == 0.0 && K.y == 0.0) {',
          'h = 0.0;',
          //no DC term
        '}', 'gl_FragColor = vec4(h, 0.0, 0.0, 0.0);', '}'].join('\n')
    }
    ..['ocean_phase'] = {
      'uniforms': {
        "u_phases": {
          'type': "t",
          'value': null
        },
        "u_deltaTime": {
          'type': "f",
          'value': null
        },
        "u_resolution": {
          'type': "f",
          'value': null
        },
        "u_size": {
          'type': "f",
          'value': null
        },
      },
      'varying': {
        "vUV": {
          'type': "v2"
        }
      },
      'fragmentShader': [
          'precision highp float;',
          'const float PI = 3.14159265359;',
          'const float G = 9.81;',
          'const float KM = 370.0;',
          'varying vec2 vUV;',
          'uniform sampler2D u_phases;',
          'uniform float u_deltaTime;',
          'uniform float u_resolution;',
          'uniform float u_size;',
          'float omega (float k) {',
          'return sqrt(G * k * (1.0 + k * k / KM * KM));',
          '}',
          'void main (void) {',
          'float deltaTime = 1.0 / 60.0;',
          'vec2 coordinates = gl_FragCoord.xy - 0.5;',
          'float n = (coordinates.x < u_resolution * 0.5) ? coordinates.x : coordinates.x - u_resolution;',
          'float m = (coordinates.y < u_resolution * 0.5) ? coordinates.y : coordinates.y - u_resolution;',
          'vec2 waveVector = (2.0 * PI * vec2(n, m)) / u_size;',
          'float phase = texture2D(u_phases, vUV).r;',
          'float deltaPhase = omega(length(waveVector)) * u_deltaTime;',
          'phase = mod(phase + deltaPhase, 2.0 * PI);',
          'gl_FragColor = vec4(phase, 0.0, 0.0, 0.0);',
          '}'].join('\n')
    }
    ..['ocean_spectrum'] = {
      'uniforms': {
        "u_size": {
          'type': "f",
          'value': null
        },
        "u_resolution": {
          'type': "f",
          'value': null
        },
        "u_choppiness": {
          'type': "f",
          'value': null
        },
        "u_phases": {
          'type': "t",
          'value': null
        },
        "u_initialSpectrum": {
          'type': "t",
          'value': null
        },
      },
      'varying': {
        "vUV": {
          'type': "v2"
        }
      },
      'fragmentShader': [
          'precision highp float;',
          'const float PI = 3.14159265359;',
          'const float G = 9.81;',
          'const float KM = 370.0;',
          'varying vec2 vUV;',
          'uniform float u_size;',
          'uniform float u_resolution;',
          'uniform float u_choppiness;',
          'uniform sampler2D u_phases;',
          'uniform sampler2D u_initialSpectrum;',
          'vec2 multiplyComplex (vec2 a, vec2 b) {',
          'return vec2(a[0] * b[0] - a[1] * b[1], a[1] * b[0] + a[0] * b[1]);',
          '}',
          'vec2 multiplyByI (vec2 z) {',
          'return vec2(-z[1], z[0]);',
          '}',
          'float omega (float k) {',
          'return sqrt(G * k * (1.0 + k * k / KM * KM));',
          '}',
          'void main (void) {',
          'vec2 coordinates = gl_FragCoord.xy - 0.5;',
          'float n = (coordinates.x < u_resolution * 0.5) ? coordinates.x : coordinates.x - u_resolution;',
          'float m = (coordinates.y < u_resolution * 0.5) ? coordinates.y : coordinates.y - u_resolution;',
          'vec2 waveVector = (2.0 * PI * vec2(n, m)) / u_size;',
          'float phase = texture2D(u_phases, vUV).r;',
          'vec2 phaseVector = vec2(cos(phase), sin(phase));',
          'vec2 h0 = texture2D(u_initialSpectrum, vUV).rg;',
          'vec2 h0Star = texture2D(u_initialSpectrum, vec2(1.0 - vUV + 1.0 / u_resolution)).rg;',
          'h0Star.y *= -1.0;',
          'vec2 h = multiplyComplex(h0, phaseVector) + multiplyComplex(h0Star, vec2(phaseVector.x, -phaseVector.y));',
          'vec2 hX = -multiplyByI(h * (waveVector.x / length(waveVector))) * u_choppiness;',
          'vec2 hZ = -multiplyByI(h * (waveVector.y / length(waveVector))) * u_choppiness;',
          //no DC term
        'if (waveVector.x == 0.0 && waveVector.y == 0.0) {',
            'h = vec2(0.0);',
            'hX = vec2(0.0);',
            'hZ = vec2(0.0);',
            '}',
            'gl_FragColor = vec4(hX + multiplyByI(h), hZ);',
            '}'].join('\n')
    }
    ..['ocean_normals'] = {
      'uniforms': {
        "u_displacementMap": {
          'type': "t",
          'value': null
        },
        "u_resolution": {
          'type': "f",
          'value': null
        },
        "u_size": {
          'type': "f",
          'value': null
        },
      },
      'varying': {
        "vUV": {
          'type': "v2"
        }
      },
      'fragmentShader': [
          'precision highp float;',
          'varying vec2 vUV;',
          'uniform sampler2D u_displacementMap;',
          'uniform float u_resolution;',
          'uniform float u_size;',
          'void main (void) {',
          'float texel = 1.0 / u_resolution;',
          'float texelSize = u_size / u_resolution;',
          'vec3 center = texture2D(u_displacementMap, vUV).rgb;',
          'vec3 right = vec3(texelSize, 0.0, 0.0) + texture2D(u_displacementMap, vUV + vec2(texel, 0.0)).rgb - center;',
          'vec3 left = vec3(-texelSize, 0.0, 0.0) + texture2D(u_displacementMap, vUV + vec2(-texel, 0.0)).rgb - center;',
          'vec3 top = vec3(0.0, 0.0, -texelSize) + texture2D(u_displacementMap, vUV + vec2(0.0, -texel)).rgb - center;',
          'vec3 bottom = vec3(0.0, 0.0, texelSize) + texture2D(u_displacementMap, vUV + vec2(0.0, texel)).rgb - center;',
          'vec3 topRight = cross(right, top);',
          'vec3 topLeft = cross(top, left);',
          'vec3 bottomLeft = cross(left, bottom);',
          'vec3 bottomRight = cross(bottom, right);',
          'gl_FragColor = vec4(normalize(topRight + topLeft + bottomLeft + bottomRight), 1.0);',
          '}'].join('\n')
    }
    ..['ocean_main'] = {
      'uniforms': {
        "u_displacementMap": {
          'type': "t",
          'value': null
        },
        "u_normalMap": {
          'type': "t",
          'value': null
        },
        "u_geometrySize": {
          'type': "f",
          'value': null
        },
        "u_size": {
          'type': "f",
          'value': null
        },
        "u_projectionMatrix": {
          'type': "m4",
          'value': null
        },
        "u_viewMatrix": {
          'type': "m4",
          'value': null
        },
        "u_cameraPosition": {
          'type': "v3",
          'value': null
        },
        "u_skyColor": {
          'type': "v3",
          'value': null
        },
        "u_oceanColor": {
          'type': "v3",
          'value': null
        },
        "u_sunDirection": {
          'type': "v3",
          'value': null
        },
        "u_exposure": {
          'type': "f",
          'value': null
        },
      },
      'varying': {
        "vPos": {
          'type': "v3"
        },
        "vUV": {
          'type': "v2"
        }
      },
      'vertexShader': [
          'precision highp float;',
          'varying vec3 vPos;',
          'varying vec2 vUV;',
          'uniform mat4 u_projectionMatrix;',
          'uniform mat4 u_viewMatrix;',
          'uniform float u_size;',
          'uniform float u_geometrySize;',
          'uniform sampler2D u_displacementMap;',
          'void main (void) {',
          'vec3 newPos = position + texture2D(u_displacementMap, uv).rgb * (u_geometrySize / u_size);',
          'vPos = newPos;',
          'vUV = uv;',
          'gl_Position = u_projectionMatrix * u_viewMatrix * vec4(newPos, 1.0);',
          '}'].join('\n'),
      'fragmentShader': [
          'precision highp float;',
          'varying vec3 vPos;',
          'varying vec2 vUV;',
          'uniform sampler2D u_displacementMap;',
          'uniform sampler2D u_normalMap;',
          'uniform vec3 u_cameraPosition;',
          'uniform vec3 u_oceanColor;',
          'uniform vec3 u_skyColor;',
          'uniform vec3 u_sunDirection;',
          'uniform float u_exposure;',
          'vec3 hdr (vec3 color, float exposure) {',
          'return 1.0 - exp(-color * exposure);',
          '}',
          'void main (void) {',
          'vec3 normal = texture2D(u_normalMap, vUV).rgb;',
          'vec3 view = normalize(u_cameraPosition - vPos);',
          'float fresnel = 0.02 + 0.98 * pow(1.0 - dot(normal, view), 5.0);',
          'vec3 sky = fresnel * u_skyColor;',
          'float diffuse = clamp(dot(normal, normalize(u_sunDirection)), 0.0, 1.0);',
          'vec3 water = (1.0 - fresnel) * u_oceanColor * u_skyColor * diffuse;',
          'vec3 color = sky + water;',
          'gl_FragColor = vec4(hdr(color, u_exposure), 1.0);',
          '}'].join('\n')
    };


<|start_filename|>example/web_gl_postprocessing_dof/depth_of_field.dart<|end_filename|>
/*
 * Ported to Dart from JS by
 * @author <NAME> / https://github.com/cgrabowski
 */

import 'dart:html';
import 'package:three/three.dart';
import 'package:three/extras/postprocessing/postprocessing.dart';
import 'package:three/extras/image_utils.dart' as ImageUtils;
import 'package:datgui/datgui.dart' as dat;
import 'package:stats/stats.dart';

const int GRID_M = 14;
const int GRID_N = 9;
const int GRID_P = 14;
const int NO_OBJECTS = GRID_M * GRID_N * GRID_P;
const int GRID_SPACING = 200;
const double SPHERE_SCALE = 60.0;
const int SPHERE_PARALLELS = 10;
const int SPHERE_MERIDIANS = 20;
const double FOCUS = 1.0;
const double APERTURE = 0.025;
const double MAX_BLUR = 1.0;

WebGLRenderer renderer;
Scene scene;
PerspectiveCamera camera;
Object3D container;
List<Material> materials;
EffectComposer composer;
BokehPass bokehPass;
Stats stats;

int winWidth = window.innerWidth;
int winHeight = window.innerHeight;
int winHalfWidth = winWidth ~/ 2;
int winHalfHeight = winHeight ~/ 2;
int mouseX = 0;
int mouseY = 0;

void main() {
  init();
  animate(0.0);
}

void init() {
  renderer = new WebGLRenderer(antialias: false)
      ..setSize(winWidth, winHeight)
      ..sortObjects = false;
  document.body.append(renderer.domElement);
  camera = new PerspectiveCamera(70.0, winWidth / winHeight, 1.0, 3000.0)..position.z = 200.0;
  container = new Object3D();
  scene = new Scene();

  Texture cubeTexture = ImageUtils.loadTextureCube(
      ['px', 'nx', 'py', 'ny', 'pz', 'nz'].map((halfaxis) => "textures/" + halfaxis + ".jpg").toList());

  SphereGeometry geometry = new SphereGeometry(1.0, SPHERE_MERIDIANS, SPHERE_PARALLELS);

  materials = new List<Material>();

  for (int m = 0; m < GRID_M; ++m) //
  for (int n = 0; n < GRID_N; ++n) //
  for (int p = 0; p < GRID_P; ++p) {

    MeshBasicMaterial material = new MeshBasicMaterial(color: 0xff1100, envMap: cubeTexture, shading: FlatShading);
    materials.add(material);
    Mesh mesh = new Mesh(geometry, material);

    double x = GRID_SPACING * (m - GRID_M / 2);
    double y = GRID_SPACING * (n - GRID_N / 2);
    double z = GRID_SPACING * (p - GRID_P / 2);

    mesh.position.setValues(x, y, z);
    mesh.scale.splat(SPHERE_SCALE);
    mesh.matrixAutoUpdate = false;
    mesh.updateMatrix();
    container.add(mesh);
    scene.add(mesh);
  }

  scene.matrixAutoUpdate = false;
  renderer.autoClear = false;

  composer = new EffectComposer(renderer)..addPass(new RenderPass(scene, camera));

  bokehPass = new BokehPass(
      scene,
      camera,
      focus: FOCUS,
      aperture: APERTURE,
      maxblur: MAX_BLUR,
      width: winWidth,
      height: winHeight)..renderToScreen = true;
  composer.addPass(bokehPass);

  window.onResize.listen(onWindowResize);
  window.onMouseMove.listen(onMouseMove);
  window.onTouchStart.listen(onTouchStart);
  window.onTouchMove.listen(onTouchMove);

  dat.GUI gui = new dat.GUI();
  gui.add(effectController, "focus", 0.0, 3.0).onChange(matChanger);
  gui.add(effectController, "aperture", 0.001, 0.2).onChange(matChanger);
  gui.add(effectController, "maxblur", 0.0, 3.0).onChange(matChanger);
  gui.close();

  stats = new Stats();
  document.body.append(stats.container);
}

var effectController = {
  'focus': 1.0,
  'aperture': 0.025,
  'maxblur': 1.0
};

void matChanger(var value) {
  bokehPass.uniforms['focus'].value = effectController['focus'];
  bokehPass.uniforms['aperture'].value = effectController['aperture'];
  bokehPass.uniforms['maxblur'].value = effectController['maxblur'];
}

double oldTime = 0.0;

void render(double time) {
  camera.position.x += (mouseX - camera.position.x) * 0.036;
  camera.position.y += (-mouseY - camera.position.y) * 0.036;
  camera.lookAt(scene.position);

  for (int i = 0; i < NO_OBJECTS; ++i) {
    double h = (360 * (i / NO_OBJECTS + time * 0.00005) % 360) / 360;
    materials[i].color.setHSL(h, 1.0, 0.5);
  }

  composer.render(0.1);

  oldTime = time;
}

void animate(double time) {
  stats.begin();
  render(time);
  stats.end();
  window.requestAnimationFrame(animate);
}

void onMouseMove(MouseEvent event) {
  mouseX = event.client.x - winHalfWidth;
  mouseY = event.client.y - winHalfHeight;
}

onTouchStart(TouchEvent event) {
  if (event.touches.length == 1) {
    event.preventDefault();
    mouseX = event.touches.first.page.x - winHalfWidth;
    mouseY = event.touches.first.page.y - winHalfHeight;
  }
}

onTouchMove(TouchEvent event) {
  if (event.touches.length == 1) {
    event.preventDefault();
    mouseX = event.touches.first.page.x - winHalfWidth;
    mouseY = event.touches.first.page.y - winHalfHeight;
  }
}

void onWindowResize(Event event) {
  winWidth = window.innerWidth;
  winHeight = window.innerHeight;
  winHalfWidth = winWidth ~/ winWidth;
  winHalfHeight = winHeight ~/ winHeight;

  camera.aspect = winWidth / winHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(winWidth, winHeight);
  composer.reset(null, winWidth, winHeight);
}


<|start_filename|>example/web_gl_morph_targets_horse/web_gl_morph_targets_horse.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:vector_math/vector_math.dart';
import 'package:three/three.dart';

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;
Mesh mesh;
var cameraTarget;

void main() {
  init();
  animate(0);
}

void init() {

  container = new Element.tag('div');
  document.body.nodes.add(container);

  camera = new PerspectiveCamera(50.0, window.innerWidth / window.innerHeight, 1.0, 10000.0);
  camera.position.y = 300.0;
  cameraTarget = new Vector3(0.0, 150.0, 0.0);

  scene = new Scene();

  var light;

  light = new DirectionalLight(0xefefff, 2.0);
  light.position.setValues(1.0, 1.0, 1.0).normalize();
  scene.add(light);

  light = new DirectionalLight(0xffefef, 2.0);
  light.position.setValues(-1.0, -1.0, -1.0).normalize();
  scene.add(light);

  var loader = new JSONLoader(showStatus: true);
  loader.load("horse.js", (geometry) {

    mesh = new Mesh(geometry, new MeshLambertMaterial(color: 0x606060, morphTargets: true));
    mesh.scale.setValues(1.5, 1.5, 1.5);
    scene.add(mesh);

  });

  renderer = new WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.sortObjects = false;

  container.nodes.add(renderer.domElement);

  window.onResize.listen(onWindowResize);

}

onWindowResize(event) {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

const radius = 600,
    duration = 1000,
    keyframes = 15,
    interpolation = duration / keyframes;

var theta = 0.0,
    lastKeyframe = 0,
    currentKeyframe = 0;

render() {

  theta += 0.1;

  camera.position.x = radius * Math.sin(degToRad(theta));
  camera.position.z = radius * Math.cos(degToRad(theta));

  camera.lookAt(cameraTarget);

  if (mesh != null) {

    // Alternate morph targets

    var time = new DateTime.now().millisecondsSinceEpoch % duration;

    var keyframe = (time / interpolation).floor().toInt();

    if (keyframe != currentKeyframe) {

      mesh.morphTargetInfluences[lastKeyframe] = 0;
      mesh.morphTargetInfluences[currentKeyframe] = 1;
      mesh.morphTargetInfluences[keyframe] = 0;

      lastKeyframe = currentKeyframe;
      currentKeyframe = keyframe;

      // console.log( mesh.morphTargetInfluences );

    }

    mesh.morphTargetInfluences[keyframe] = (time % interpolation) / interpolation;
    mesh.morphTargetInfluences[lastKeyframe] = 1 - mesh.morphTargetInfluences[keyframe];

  }

  renderer.render(scene, camera);
}


<|start_filename|>lib/extras/shaders/basic_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author mrdoob / http://www.mrdoob.com
 *
 * Simple test shader
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var BasicShader = {

  'uniforms': {},

  'vertexShader': [

    "void main() {",

      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "void main() {",

      "gl_FragColor = vec4( 1.0, 0.0, 0.0, 0.5 );",

    "}"

  ].join("\n")

};


<|start_filename|>lib/extras/geometries/sphere_geometry.dart<|end_filename|>
part of three;

class SphereGeometry extends Geometry {
  double radius;

  SphereGeometry([this.radius = 50.0, int segmentsWidth = 8, int segmentsHeight = 6, double phiStart = 0.0,
      double phiLength = Math.PI *
      2.0, double thetaStart = 0.0, double thetaLength = Math.PI]) : super() {

    int segmentsX = Math.max(3, segmentsWidth);
    int segmentsY = Math.max(2, segmentsHeight);

    List vertices = [],
        uvs = [];

    for (int y = 0; y <= segmentsY; y++) {

      var verticesRow = [];
      var uvsRow = [];

      for (int x = 0; x <= segmentsX; x++) {

        double u = x.toDouble() / segmentsX.toDouble();
        double v = y.toDouble() / segmentsY.toDouble();

        Vector3 vertex = new Vector3.zero();
        vertex.x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
        vertex.y = radius * Math.cos(thetaStart + v * thetaLength);
        vertex.z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);

        this.vertices.add(vertex);

        verticesRow.add(this.vertices.length - 1);
        uvsRow.add(new UV(u, 1 - v));

      }

      vertices.add(verticesRow);
      uvs.add(uvsRow);

    }

    for (int y = 0; y < segmentsY; y++) {

      for (int x = 0; x < segmentsX; x++) {

        var v1 = vertices[y][x + 1];
        var v2 = vertices[y][x];
        var v3 = vertices[y + 1][x];
        var v4 = vertices[y + 1][x + 1];

        var n1 = this.vertices[v1].clone().normalize();
        var n2 = this.vertices[v2].clone().normalize();
        var n3 = this.vertices[v3].clone().normalize();
        var n4 = this.vertices[v4].clone().normalize();

        var uv1 = uvs[y][x + 1].clone();
        var uv2 = uvs[y][x].clone();
        var uv3 = uvs[y + 1][x].clone();
        var uv4 = uvs[y + 1][x + 1].clone();

        if (this.vertices[v1].y.abs() == radius) {

          this.faces.add(new Face3(v1, v3, v4, [n1, n3, n4]));
          this.faceVertexUvs[0].add([uv1, uv3, uv4]);

        } else if (this.vertices[v3].y.abs() == radius) {

          this.faces.add(new Face3(v1, v2, v3, [n1, n2, n3]));
          this.faceVertexUvs[0].add([uv1, uv2, uv3]);

        } else {

          this.faces.add(new Face4(v1, v2, v3, v4, [n1, n2, n3, n4]));
          this.faceVertexUvs[0].add([uv1, uv2, uv3, uv4]);

        }

      }

    }

    this.computeCentroids();
    this.computeFaceNormals();

    this.boundingSphere = new BoundingSphere(radius: radius);

  }

}


<|start_filename|>example/web_gl_geometry_extrude_by_u_shapes/web_gl_geometry_extrude_by_u_shapes.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:vector_math/vector_math.dart';
import 'package:three/three.dart' as THREE;
import 'package:three/extras/scene_utils.dart' as SceneUtils;

Element container;

THREE.PerspectiveCamera camera;
THREE.Scene scene;
THREE.WebGLRenderer renderer;

var windowHalfX, windowHalfY;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var mouseEvts = [];

var targetRotation = 0;
var targetRotationOnMouseDown = 0;

THREE.Object3D parent, text, plane;

void main() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  init();
  animate(0);
}

_addGeometry(geometry, color, x, y, z, rx, ry, rz, s) {

  // 3d shape

  var mesh = SceneUtils.createMultiMaterialObject(
      geometry,
      [
          new THREE.MeshLambertMaterial(color: color, opacity: 0.2, transparent: true),
          new THREE.MeshBasicMaterial(color: 0x000000, wireframe: true, opacity: 0.3)]);

  mesh.position.setValues(x.toDouble(), y.toDouble(), z.toDouble() - 75);
  // mesh.rotation.set( rx, ry, rz );
  double ds = s.toDouble();
  mesh.scale.setValues(ds, ds, ds);

  // if ( geometry.debug ) mesh.add( geometry.debug );

  parent.add(mesh);

}

void init() {

  container = new Element.tag('div');
  document.body.nodes.add(container);

  camera = new THREE.PerspectiveCamera(50.0, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  camera.position.setValues(0.0, 150.0, 500.0);

  scene = new THREE.Scene();

  var light = new THREE.DirectionalLight(0xffffff);
  light.position.setValues(0.0, 0.0, 1.0);
  scene.add(light);

  parent = new THREE.Object3D();
  parent.position.y = 50.0;
  scene.add(parent);

  var extrudeAmount = 200,
      extrudeBevelEnabled = true,
      extrudeBevelSegments = 2;

  extrudeBevelEnabled = false;

  var pts = [],
      starPoints = 5,
      l;

  for (var i = 0; i < starPoints * 2; i++) {

    if (i % 2 == 1) {

      l = 5;

    } else {

      l = 10;

    }

    var a = i / starPoints * Math.PI;
    pts.add(new Vector2(Math.cos(a) * l, Math.sin(a) * l));

  }

  var starShape = new THREE.Shape(pts);

  var rnd = new Math.Random();

  var line = new THREE.LineCurve3(new Vector3.zero(), new Vector3(100.0, 0.0, 0.0));
  var line2 = new THREE.LineCurve3(new Vector3(100.0, 0.0, 0.0), new Vector3(200.0, 50.0, 0.0));

  var curvepath = new THREE.CurvePath();
  curvepath.add(line);
  curvepath.add(line2);


  var randomPoints = [new Vector3(200.0, 50.0, 0.0)];

  for (var i = 0; i < 5; i++) {

    randomPoints.add(new Vector3(rnd.nextDouble() * 200, rnd.nextDouble() * 200, rnd.nextDouble() * 200));

  }

  var randomSpline = new THREE.SplineCurve3(randomPoints);
  curvepath.add(randomSpline);



  var extrudeUSteps = new List();
  var curvepathLength = curvepath.length;
  var initU = 0;
  var curveSteps = 40;

  for (var curve in curvepath.curves) {

    if (curve is THREE.LineCurve3) {
      // Straight so we only need one step
      initU += (curve.length ~/ curvepathLength);
      extrudeUSteps.add(initU);

    } else {
      // Not Straight so we subdivide the curve steps in 'curve_steps' divisions
      for (var d = 0; d <= curveSteps; d++) {
        extrudeUSteps.add(initU + ((d / curveSteps) * (curve.length / curvepathLength)));
      }
      initU = extrudeUSteps.last;
    }
  }
  print("[WebGL_Geometry_Extrude_By_U_Shapes] ${extrudeUSteps}");

  var extrude_extrudePath = curvepath;

  // Circle

  var circleRadius = 4.0;
  var circleShape = new THREE.Shape();
  circleShape.moveTo(0, circleRadius);
  circleShape.quadraticCurveTo(circleRadius, circleRadius, circleRadius, 0.0);
  circleShape.quadraticCurveTo(circleRadius, -circleRadius, 0.0, -circleRadius);
  circleShape.quadraticCurveTo(-circleRadius, -circleRadius, -circleRadius, 0.0);
  circleShape.quadraticCurveTo(-circleRadius, circleRadius, 0.0, circleRadius);

  var rectLength = 12.0,
      rectWidth = 4.0;

  var rectShape = new THREE.Shape();

  rectShape.moveTo(-rectLength / 2, -rectWidth / 2);
  rectShape.lineTo(-rectLength / 2, rectWidth / 2);
  rectShape.lineTo(rectLength / 2, rectWidth / 2);
  rectShape.lineTo(rectLength / 2, -rectLength / 2);
  rectShape.lineTo(-rectLength / 2, -rectLength / 2);


  // Smiley

  var smileyShape = new THREE.Shape();
  smileyShape.moveTo(80, 40);
  smileyShape.arc(40, 40, 40, 0, Math.PI * 2, false);

  var smileyEye1Path = new THREE.Path();
  smileyEye1Path.moveTo(35, 20);
  smileyEye1Path.arc(25, 20, 10, 0, Math.PI * 2, true);
  smileyShape.holes.add(smileyEye1Path);

  var smileyEye2Path = new THREE.Path();
  smileyEye2Path.moveTo(65, 20);
  smileyEye2Path.arc(55, 20, 10, 0, Math.PI * 2, true);
  smileyShape.holes.add(smileyEye2Path);

  var smileyMouthPath = new THREE.Path();

  smileyMouthPath.moveTo(20, 40);
  smileyMouthPath.quadraticCurveTo(40, 60, 60, 40);
  smileyMouthPath.bezierCurveTo(70, 45, 70, 50, 60, 60);
  smileyMouthPath.quadraticCurveTo(40, 80, 20, 60);
  smileyMouthPath.quadraticCurveTo(5, 50, 20, 40);

  smileyShape.holes.add(smileyMouthPath);

  var circle3d = starShape.extrude(
      amount: extrudeAmount,
      bevelSegments: extrudeBevelSegments,
      bevelEnabled: extrudeBevelEnabled,
      steps: extrudeUSteps,
      extrudePath: extrude_extrudePath); //circleShape rectShape smileyShape starShape
  // var circle3d = new ExtrudeGeometry(circleShape, extrudeBend, extrudeSettings );

  var tube = new THREE.TubeGeometry(extrude_extrudePath, 40, 4.0, 5, false, true);
  // new TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2, debug);


  _addGeometry(circle3d, 0xff1111, -100, 0, 0, 0, 0, 0, 1);
  _addGeometry(tube, 0x00ff11, 0, 0, 0, 0, 0, 0, 1);

  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.sortObjects = false;

  container.nodes.add(renderer.domElement);

  mouseEvts = [
      document.onMouseDown.listen(onDocumentMouseDown),
      document.onTouchStart.listen(onDocumentTouchStart),
      document.onTouchMove.listen(onDocumentTouchMove)];

  window.onResize.listen(onWindowResize);
}

onWindowResize(event) {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

void cancelMouseEvts() {
  mouseEvts.forEach((s) => s.cancel());
  mouseEvts = [];
}

onDocumentMouseDown(MouseEvent event) {
  event.preventDefault();

  mouseEvts = [
      document.onMouseMove.listen(onDocumentMouseMove),
      document.onMouseUp.listen(onDocumentMouseUp),
      document.onMouseOut.listen(onDocumentMouseOut)];

  mouseXOnMouseDown = event.client.x - windowHalfX;
  targetRotationOnMouseDown = targetRotation;
}

onDocumentMouseMove(MouseEvent event) {
  mouseX = event.client.x - windowHalfX;
  targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
}

onDocumentMouseUp(event) {
  cancelMouseEvts();
}

onDocumentMouseOut(event) {
  cancelMouseEvts();
}

onDocumentTouchStart(TouchEvent event) {

  if (event.touches.length == 1) {

    event.preventDefault();

    mouseXOnMouseDown = event.touches[0].page.x - windowHalfX;
    targetRotationOnMouseDown = targetRotation;

  }

}

onDocumentTouchMove(TouchEvent event) {

  if (event.touches.length == 1) {

    event.preventDefault();

    mouseX = event.touches[0].page.x - windowHalfX;
    targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;

  }

}

void animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

render() {

  parent.rotation.y += (targetRotation - parent.rotation.y) * 0.05;

  renderer.render(scene, camera);

}


<|start_filename|>lib/extras/shaders/edge_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author zz85 / https://github.com/zz85 | https://www.lab4games.net/zz85/blog
 *
 * Edge Detection Shader using Frei-Chen filter
 * Based on http://rastergrid.com/blog/2011/01/frei-chen-edge-detector
 *
 * aspect: vec2 of (1/width, 1/height)
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var EdgeShader = {

  'uniforms': {

    "tDiffuse": {
      'type': "t",
      'value': null
    },
    "aspect": {
      'type': "v2",
      'value': new Vector2(512.0, 512.0)
    },
  },

  'vertexShader': [
      "varying vec2 vUv;",
      "void main() {",
      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
      "}"].join("\n"),

  'fragmentShader': [
      "uniform sampler2D tDiffuse;",
      "varying vec2 vUv;",
      "uniform vec2 aspect;",
      "vec2 texel = vec2(1.0 / aspect.x, 1.0 / aspect.y);",
      "mat3 G[9];",
      // hard coded matrix 'value's!!!! as suggested in https://github.com/neilmendoza/ofxPostProcessing/blob/master/src/EdgePass.cpp#L45


        "const mat3 g0 = mat3( 0.3535533845424652, 0, -0.3535533845424652, 0.5, 0, -0.5, 0.3535533845424652, 0, -0.3535533845424652 );",
        "const mat3 g1 = mat3( 0.3535533845424652, 0.5, 0.3535533845424652, 0, 0, 0, -0.3535533845424652, -0.5, -0.3535533845424652 );",
        "const mat3 g2 = mat3( 0, 0.3535533845424652, -0.5, -0.3535533845424652, 0, 0.3535533845424652, 0.5, -0.3535533845424652, 0 );",
        "const mat3 g3 = mat3( 0.5, -0.3535533845424652, 0, -0.3535533845424652, 0, 0.3535533845424652, 0, 0.3535533845424652, -0.5 );",
        "const mat3 g4 = mat3( 0, -0.5, 0, 0.5, 0, 0.5, 0, -0.5, 0 );",
        "const mat3 g5 = mat3( -0.5, 0, 0.5, 0, 0, 0, 0.5, 0, -0.5 );",
        "const mat3 g6 = mat3( 0.1666666716337204, -0.3333333432674408, 0.1666666716337204, -0.3333333432674408, 0.6666666865348816, -0.3333333432674408, 0.1666666716337204, -0.3333333432674408, 0.1666666716337204 );",
        "const mat3 g7 = mat3( -0.3333333432674408, 0.1666666716337204, -0.3333333432674408, 0.1666666716337204, 0.6666666865348816, 0.1666666716337204, -0.3333333432674408, 0.1666666716337204, -0.3333333432674408 );",
        "const mat3 g8 = mat3( 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408 );",
        "void main(void)",
        "{",
        "G[0] = g0,",
        "G[1] = g1,",
        "G[2] = g2,",
        "G[3] = g3,",
        "G[4] = g4,",
        "G[5] = g5,",
        "G[6] = g6,",
        "G[7] = g7,",
        "G[8] = g8;",
        "mat3 I;",
        "float cnv[9];",
        "vec3 sample;",
        /*
         * fetch the 3x3 neighbourhood and use the RGB vector's length as intensity 'value'
         */
    "for (float i=0.0; i<3.0; i++) {",
        "for (float j=0.0; j<3.0; j++) {",
        "sample = texture2D(tDiffuse, vUv + texel * vec2(i-1.0,j-1.0) ).rgb;",
        "I[int(i)][int(j)] = length(sample);",
        "}",
        "}",
        /*
         * calculate the convolution 'value's for all the masks
         */
    "for (int i=0; i<9; i++) {",
        "float dp3 = dot(G[i][0], I[0]) + dot(G[i][1], I[1]) + dot(G[i][2], I[2]);",
        "cnv[i] = dp3 * dp3;",
        "}",
        "float M = (cnv[0] + cnv[1]) + (cnv[2] + cnv[3]);",
        "float S = (cnv[4] + cnv[5]) + (cnv[6] + cnv[7]) + (cnv[8] + M);",
        "gl_FragColor = vec4(vec3(sqrt(M/S)), 1.0);",
        "}",].join("\n")
};


<|start_filename|>example/canvas_geometry_cube/canvas_geometry_cube.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;

import 'package:three/three.dart';
import 'package:three/extras/renderers/canvas_renderer.dart';

Element container;

PerspectiveCamera camera;
Scene scene;
CanvasRenderer renderer;

Mesh cube;
Mesh plane;

num targetRotation;
num targetRotationOnMouseDown;

num mouseX;
num mouseXOnMouseDown;

num windowHalfX;
num windowHalfY;

var evtSubscriptions = [];

void main() {
  init();
  animate(0);
}

void init() {
  targetRotation = 0;
  targetRotationOnMouseDown = 0;

  mouseX = 0;
  mouseXOnMouseDown = 0;

  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  container = new Element.tag('div');
  //document.body.appendChild( container );
  document.body.nodes.add(container);

  Element info = new Element.tag('div');
  info.style.position = 'absolute';
  info.style.top = '10px';
  info.style.width = '100%';
  info.style.textAlign = 'center';
  info.innerHtml = 'Drag to spin the cube';
  //container.appendChild( info );
  container.nodes.add(info);

  scene = new Scene();

  camera = new PerspectiveCamera(70.0, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  camera.position.y = 150.0;
  camera.position.z = 500.0;
  scene.add(camera);

  // Cube

  List materials = [];

  var rnd = new Math.Random();
  for (int i = 0; i < 6; i++) {
    materials.add(new MeshBasicMaterial(color: rnd.nextDouble() * 0xffffff));
  }

  cube = new Mesh(
      new CubeGeometry(200.0, 200.0, 200.0, 1, 1, 1, materials),
      new MeshFaceMaterial(materials));// { 'overdraw' : true }) );
  cube.position.y = 150.0;
  //cube.overdraw = true; //TODO where is this prop?
  scene.add(cube);

  // Plane

  plane = new Mesh(new PlaneGeometry(200.0, 200.0), new MeshBasicMaterial(color: 0xe0e0e0, overdraw: true));
  plane.rotation.x = -90.0 * (Math.PI / 180.0);
  //plane.overdraw = true; //TODO where is this prop?
  scene.add(plane);

  renderer = new CanvasRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);


  //container.appendChild( renderer.domElement );
  container.nodes.add(renderer.domElement);

  evtSubscriptions = [
      document.onMouseDown.listen(onDocumentMouseDown),
      document.onTouchStart.listen(onDocumentTouchStart),
      document.onTouchMove.listen(onDocumentTouchMove)];

}

void onDocumentMouseDown(event) {
  event.preventDefault();

  evtSubscriptions = [
      document.onMouseMove.listen(onDocumentMouseMove),
      document.onMouseUp.listen(onDocumentMouseUp),
      document.onMouseOut.listen(onDocumentMouseOut)];

  mouseXOnMouseDown = event.client.x - windowHalfX;
  targetRotationOnMouseDown = targetRotation;

  print('onMouseDown mouseX = $mouseXOnMouseDown targRot = $targetRotationOnMouseDown');
}

void onDocumentMouseMove(event) {
  mouseX = event.client.x - windowHalfX;

  targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;

  print('onMouseMove mouseX = $mouseX targRot = $targetRotation');
}

void cancelEvtSubscriptions() {
  evtSubscriptions.forEach((s) => s.cancel());
  evtSubscriptions = [];
}

void onDocumentMouseUp(event) {
  cancelEvtSubscriptions();
}

void onDocumentMouseOut(event) {
  cancelEvtSubscriptions();
}

void onDocumentTouchStart(event) {
  if (event.touches.length == 1) {
    event.preventDefault();

    mouseXOnMouseDown = event.touches[0].page.x - windowHalfX;
    targetRotationOnMouseDown = targetRotation;
  }
}

void onDocumentTouchMove(event) {
  if (event.touches.length == 1) {
    event.preventDefault();

    mouseX = event.touches[0].page.x - windowHalfX;
    targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;
  }
}

animate(num time) {
  window.requestAnimationFrame(animate);

  render();
}

void render() {
  plane.rotation.z = cube.rotation.y += (targetRotation - cube.rotation.y) * 0.05;
  renderer.render(scene, camera);
}


<|start_filename|>lib/extras/tween.dart<|end_filename|>
/**
 * Based on Tween.js
 *
 * @author sole / http://soledadpenades.com
 * @author mrdoob / http://mrdoob.com
 * @author <NAME> / http://www.xarg.org
 * @author Philippe / http://philippe.elsass.me
 * @author <NAME> / http://www.robertpenner.com/easing_terms_of_use.html
 * @author <NAME> / http://www.aerotwist.com/
 * @author lechecacharro
 * @author <NAME> / http://jocafa.com/
 * @author egraether / http://egraether.com/
 *
 * Ported to Dart by
 *
 * @author <NAME> / http://www.inevo.pt
 *
 */

library tween;

import 'dart:math' as Math;

const REVISION = '7';

List<Tween> _tweens = [];

List<Tween> get all => _tweens;

removeAll() => _tweens = [];

add(Tween tween) => _tweens.add(tween);

remove(Tween tween) => _tweens.removeAt(_tweens.indexOf(tween));

bool update({num time}) {

  if (_tweens.isEmpty) {
    return false;
  }

  var i = 0,
      l = _tweens.length;

  if (time == null) {
    time = new DateTime.now().millisecondsSinceEpoch;
  }

  while (i < l) {
    if (_tweens[i].update(time)) {
      i++;
    } else {
      _tweens.removeAt(i);
      l--;
    }
  }
  return true;
}

class Tween {
  var object;
  Map _valuesStart = {};
  Map _valuesEnd = {};
  num _duration = 1000;
  num _delayTime = 0;
  num _startTime = null;
  Function _easingFunction = Easing.Linear.None;
  Function _interpolationFunction = Interpolation.Linear;
  List _chainedTweens = [];
  Function _onStartCallback = null;
  bool _onStartCallbackFired = false;
  Function _onUpdateCallback = null;
  Function _onCompleteCallback = null;

  Tween(this.object);

  to(Map properties, [num duration]) {
    if (duration != null) {
      _duration = duration;
    }

    _valuesEnd = properties;
  }

  // TODO(nelsonsilva) - We just support x, y and z props for now (no mirrors yet) :(
  _setPropertyValue(String name, Object value) {
    switch (name) {
      case "x":
        object.x = value;
        break;
      case "y":
        object.y = value;
        break;
      case "z":
        object.z = value;
        break;
      default:
        throw new Exception("The supplied property name ('$name') is not supported at this time.");
    }
  }

  // TODO(nelsonsilva) - We just support x, y and z props for now (no mirrors yet) :(
  Object _getPropertyValue(String name) {
    switch (name) {
      case "x":
        return object.x;
      case "y":
        return object.y;
      case "z":
        return object.z;
      default:
        throw new Exception("The supplied property name ('$name') is not supported at this time.");
    }
  }

  start({num time}) {

    add(this);

    _onStartCallbackFired = false;

    _startTime = (time != null) ? time : new DateTime.now().millisecondsSinceEpoch;
    _startTime += _delayTime;

    _valuesEnd.forEach((property, _) {

      var value = _getPropertyValue(property);

      // This prevents the engine from interpolating null values
      if (value != null) {

        // check if an Array was provided as property value
        if (_valuesEnd[property] is List && !_valuesEnd[property].isEmpty) {

          // create a local copy of the Array with the start value at the front
          _valuesEnd[property] = [value]..add(_valuesEnd[property]);

        }

        _valuesStart[property] = value;
      }

    });

  }

  stop() => remove(this);


  set delay(num amount) {
    _delayTime = amount;
  }

  set easing(num easing(num elapsed)) {
    _easingFunction = easing;
  }

  set interpolation(Object interpolation(Object end, Object value)) {
    _interpolationFunction = interpolation;
  }

  chain(List<Tween> tweens) {
    _chainedTweens = tweens;
  }

  set onStart(Function callback(object)) {
    _onStartCallback = callback;
  }

  set onUpdate(Function callback(object, value)) {
    _onUpdateCallback = callback;
  }

  set onComplete(Function callback(object)) {
    _onCompleteCallback = callback;
  }

  bool update(num time) {

    if (time < _startTime) {
      return true;
    }

    if (!_onStartCallbackFired) {
      if (_onStartCallback != null) {
        _onStartCallback(object);
      }
      _onStartCallbackFired = true;
    }

    var elapsed = (time - _startTime) / _duration;
    elapsed = elapsed > 1 ? 1 : elapsed;

    var value = _easingFunction(elapsed);

    _valuesStart.forEach((property, start) {

      var end = _valuesEnd[property];

      if (end is List) {
        _setPropertyValue(property, _interpolationFunction(end, value));
      } else {
        _setPropertyValue(property, start + (end - start) * value);
      }
    });

    if (_onUpdateCallback != null) {
      _onUpdateCallback(object, value);
    }

    if (elapsed == 1) {

      if (_onCompleteCallback != null) {
        _onCompleteCallback(object);
      }

      _chainedTweens.forEach((t) => t.start(time: time));

      return false;

    }

    return true;

  }
}

class Easing {
  static const Linear = const _EasingLinear();
  static const Quadratic = const _EasingQuadratic();
  static const Exponential = const _EasingExponential();
}

class Interpolation {
  static Linear(List v, num k) {
    var m = v.length - 1,
        f = m * k,
        i = f.floor(),
        fn = _InterpolationUtils.Linear;

    if (k < 0) return fn(v[0], v[1], f);
    if (k > 1) return fn(v[m], v[m - 1], m - f);

    return fn(v[i], v[i + 1 > m ? m : i + 1], f - i);

  }
}

class _EasingLinear {
  const _EasingLinear();
  None(k) => k;
}

class _EasingQuadratic {
  const _EasingQuadratic();
  In(k) => k * k;
  Out(k) => k * (2 - k);
  InOut(k) {
    if ((k *= 2) < 1) return 0.5 * k * k;
    return -0.5 * (--k * (k - 2) - 1);
  }
}

class _EasingExponential {
  const _EasingExponential();
  In(k) => k == 0 ? 0 : Math.pow(1024, k - 1);
  Out(k) => k == 1 ? 1 : 1 - Math.pow(2, -10 * k);
  InOut(k) {
    if (k == 0) return 0;
    if (k == 1) return 1;
    if ((k *= 2) < 1) return 0.5 * Math.pow(1024, k - 1);
    return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);
  }
}

class _InterpolationUtils {
  static Linear(p0, p1, t) => (p1 - p0) * t + p0;
}



<|start_filename|>lib/extras/shaders/dot_screen_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Dot screen shader
 * based on glfx.js sepia shader
 * https://github.com/evanw/glfx.js
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var DotScreenShader = {

  'uniforms': {

    "tDiffuse": { 'type': "t", 'value': null },
    "tSize":    { 'type': "v2", 'value': new Vector2( 256.0, 256.0 ) },
    "center":   { 'type': "v2", 'value': new Vector2( 0.5, 0.5 ) },
    "angle":    { 'type': "f", 'value': 1.57 },
    "scale":    { 'type': "f", 'value': 1.0 }

  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform vec2 center;",
    "uniform float angle;",
    "uniform float scale;",
    "uniform vec2 tSize;",

    "uniform sampler2D tDiffuse;",

    "varying vec2 vUv;",

    "float pattern() {",

      "float s = sin( angle ), c = cos( angle );",

      "vec2 tex = vUv * tSize - center;",
      "vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;",

      "return ( sin( point.x ) * sin( point.y ) ) * 4.0;",

    "}",

    "void main() {",

      "vec4 color = texture2D( tDiffuse, vUv );",

      "float average = ( color.r + color.g + color.b ) / 3.0;",

      "gl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );",

    "}"

  ].join("\n")

};


<|start_filename|>lib/src/cameras/orthographic_camera.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author greggman / http://games.greggman.com/
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

/// Camera with orthographic projection.
class OrthographicCamera extends Camera {

  /// Camera frustum left plane.
  double left;
  /// Camera frustum right plane.
  double right;
  /// Camera frustum top plane.
  double top;
  /// Camera frustum bottom plane.
  double bottom;

  OrthographicCamera(this.left, this.right, this.top, this.bottom, [near = 0.1, far = 2000.0]) : super(near, far) {
    updateProjectionMatrix();
  }

  /// Updates the camera projection matrix.
  ///
  /// Must be called after change of parameters.
  void updateProjectionMatrix() {
    setOrthographicMatrix(projectionMatrix, left, right, bottom, top, near, far);
  }
}


<|start_filename|>lib/extras/renderers/css3d_renderer.dart<|end_filename|>
library css3d_renderer;

import 'dart:html';
import 'dart:math' as Math;

import 'package:three/three.dart';

class CSS3DObject extends Object3D {

  Element element;

  CSS3DObject(this.element) : super() {
    element.style.position = "absolute";
    element.style.transformStyle = "preserve-3d";
  }
}

class CSS3DRenderer implements Renderer {
  Projector _projector;
  Element domElement;
  Element cameraElement;
  num _width, _height, _widthHalf, _heightHalf;

  CSS3DRenderer() {

    _projector = new Projector();

    domElement = new Element.tag('div')
        ..style.overflow = 'hidden'
        ..style.transformStyle = 'preserve-3d'
        ..style.perspectiveOrigin = '50% 50%';

    // TODO: Shouldn't it be possible to remove cameraElement?

    cameraElement = new Element.tag('div')..style.transformStyle = 'preserve-3d';

    domElement.children.add(cameraElement);
  }

  setSize(num width, num height) {

    _width = width;
    _height = height;

    _widthHalf = _width / 2;
    _heightHalf = _height / 2;

    domElement.style
        ..width = '${width}px'
        ..height = '${height}px';

    cameraElement.style
        ..width = '${width}px'
        ..height = '${height}px';

  }

  num epsilon(num value) => (value.abs() < 0.000001) ? 0 : value;

  String getCameraCSSMatrix(matrix) {

    return 'matrix3d(' '${epsilon( matrix[ 0 ] )},' '${epsilon( - matrix[ 1 ] )},' '${epsilon( matrix[ 2 ] )},'
        '${epsilon( matrix[ 3 ] )},' '${epsilon( matrix[ 4 ] )},' '${epsilon( - matrix[ 5 ] )},' '${epsilon( matrix[ 6 ] )},'
        '${epsilon( matrix[ 7 ] )},' '${epsilon( matrix[ 8 ] )},' '${epsilon( - matrix[ 9 ] )},' '${epsilon( matrix[ 10 ] )},'
        '${epsilon( matrix[ 11 ] )},' '${epsilon( matrix[ 12 ] )},' '${epsilon( - matrix[ 13 ] )},'
        '${epsilon( matrix[ 14 ] )},' '${epsilon( matrix[ 15 ] )}' ')';
  }

  String getObjectCSSMatrix(matrix) {

    return 'translate3d(-50%,-50%,0px) matrix3d(' '${epsilon( matrix[ 0 ] )},' '${epsilon( matrix[ 1 ] )},'
        '${epsilon( matrix[ 2 ] )},' '${epsilon( matrix[ 3 ] )},' '${epsilon( matrix[ 4 ] )},' '${epsilon( matrix[ 5 ] )},'
        '${epsilon( matrix[ 6 ] )},' '${epsilon( matrix[ 7 ] )},' '${epsilon( matrix[ 8 ] )},' '${epsilon( matrix[ 9 ] )},'
        '${epsilon( matrix[ 10 ] )},' '${epsilon( matrix[ 11 ] )},' '${epsilon( matrix[ 12 ] )},' '${epsilon( matrix[ 13 ] )},'
        '${epsilon( matrix[ 14 ] )},' '${epsilon( matrix[ 15 ] )}' ') scale3d(1,-1,1)';

  }

  render(Scene scene, camera) {

    var fov = 0.5 / Math.tan(camera.fov * Math.PI / 360) * _height;

    domElement.style.perspective = "${fov}px";

    var style =
        "translate3d(0,0,${fov}px)${getCameraCSSMatrix( camera.matrixWorldInverse )} translate3d(${_widthHalf}px,${_heightHalf}px, 0)";

    cameraElement.style.transform = style;

    var objects = _projector.projectScene(scene, camera, false).objects;

    var il = objects.length;

    for (var i = 0; i < il; i++) {

      var object = objects[i].object;

      if (object is CSS3DObject) {

        var element = object.element;

        style = getObjectCSSMatrix(object.matrixWorld);

        element.style.transform = style;

        if (element.parent != cameraElement) {
          cameraElement.children.add(element);
        }
      }
    }
  }

}


<|start_filename|>example/misc_controls_orthotrackball/misc_controls_orthotrackball.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:three/three.dart';
import 'package:three/extras/controls/orthographic_trackball_controls.dart';

Element container;

OrthographicCamera camera;
Scene scene;
WebGLRenderer renderer;

num windowHalfX;
num windowHalfY;

OrthographicTrackballControls controls;

void main() {
  init();
  animate(0);
}

void init() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  container = new Element.tag('div');
  document.body.nodes.add(container);

  Element info = new Element.tag('div');
  info.style.position = 'absolute';
  info.style.top = '10px';
  info.style.width = '100%';
  info.style.textAlign = 'center';
  info.innerHtml = '''
                    three.dart - misc controls orthographic trackball<br />
                    MOVE mouse &amp; press LEFT/A: rotate, MIDDLE/S: zoom, RIGHT/D: pan
                  ''';
  container.nodes.add(info);

  camera = new OrthographicCamera(-windowHalfX, windowHalfX, windowHalfY, -windowHalfY, -2000.0, 1000.0);
  camera.position.x = 200.0;
  camera.position.y = 100.0;
  camera.position.z = 200.0;

  controls = new OrthographicTrackballControls(camera);

  controls.rotateSpeed = 1.0;
  controls.zoomSpeed = 1.2;
  controls.panSpeed = 0.8;

  controls.noZoom = false;
  controls.noPan = false;

  controls.staticMoving = true;
  controls.dynamicDampingFactor = 0.3;

  controls.keys = [65, 83, 68];

  controls.addEventListener('change', (_) => render());

  scene = new Scene();
  scene.fog = new FogExp2(0xcccccc, 0.002);

  var geometry;
  var material;
  var light;

  // Pyramids

  geometry = new CylinderGeometry(0.0, 10.0, 30.0, 4, 1);
  material = new MeshLambertMaterial(color: 0xffffff, shading: FlatShading);

  var rnd = new Math.Random();

  for (var i = 0; i < 500; i++) {

    var mesh = new Mesh(geometry, material);
    mesh.position.x = (rnd.nextDouble() - 0.5) * 1000;
    mesh.position.y = (rnd.nextDouble() - 0.5) * 1000;
    mesh.position.z = (rnd.nextDouble() - 0.5) * 1000;
    mesh.updateMatrix();
    mesh.matrixAutoUpdate = false;
    scene.add(mesh);

  }

  // Lights

  light = new DirectionalLight(0xffffff);
  light.position.x = 1.0;
  light.position.y = 1.0;
  light.position.z = 1.0;
  scene.add(light);

  light = new DirectionalLight(0x002288);
  light.position.x = -1.0;
  light.position.y = -1.0;
  light.position.z = -1.0;
  scene.add(light);

  light = new AmbientLight(0x222222);
  scene.add(light);

  // Renderer

  renderer = new WebGLRenderer(antialias: false);
  renderer.setClearColor(scene.fog.color, 1);
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.nodes.add(renderer.domElement);

  window.onResize.listen(onWindowResize);
}

onWindowResize(e) {

  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.left = -windowHalfX;
  camera.right = windowHalfX;
  camera.top = windowHalfY;
  camera.bottom = -windowHalfY;

  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

  controls.handleResize();

}


animate(num time) {
  window.requestAnimationFrame(animate);

  controls.update();

  render();
}

void render() {
  renderer.render(scene, camera);
}


<|start_filename|>example/canvas_geometry_hierarchy/canvas_geometry_hierarchy.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;

import 'package:three/three.dart';
import 'package:three/extras/renderers/canvas_renderer.dart';

Element container;// stats;

PerspectiveCamera camera;
Scene scene;
CanvasRenderer renderer;

CubeGeometry geometry;
Object3D group;

num mouseX = 0,
    mouseY = 0;

num windowHalfX;
num windowHalfY;

void main() {
  document.onMouseMove.listen(onDocumentMouseMove);

  init();
  animate(0);
}


void init() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  container = new Element.tag('div');
  document.body.nodes.add(container);

  scene = new Scene();

  camera = new PerspectiveCamera(60.0, window.innerWidth / window.innerHeight, 1.0, 10000.0);
  camera.position.z = 500.0;

  scene.add(camera);

  List materials = [];

  var rnd = new Math.Random();
  for (int i = 0; i < 6; i++) {
    materials.add(new MeshBasicMaterial(color: rnd.nextDouble() * 0xffffff));
  }

  geometry = new CubeGeometry(100.0, 100.0, 100.0);
  MeshNormalMaterial material = new MeshNormalMaterial();

  group = new Object3D();

  for (var i = 0; i < 200; i++) {
    Mesh mesh = new Mesh(geometry, material);
    //mesh.overdraw = true; //TODO: No such property?
    mesh.position.x = rnd.nextInt(2000).toDouble() - 1000.0;
    mesh.position.y = rnd.nextInt(2000).toDouble() - 1000.0;
    mesh.position.z = rnd.nextInt(2000).toDouble() - 1000.0;
    mesh.rotation.x = rnd.nextInt(360).toDouble() * (Math.PI / 180.0);
    mesh.rotation.y = rnd.nextInt(360).toDouble() * (Math.PI / 180.0);
    mesh.matrixAutoUpdate = false;
    mesh.updateMatrix();
    group.add(mesh);
  }

  scene.add(group);

  var options;

  renderer = new CanvasRenderer(options);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.sortObjects = false;
  //container.appendChild( renderer.domElement );
  container.nodes.add(renderer.domElement);

}

void onDocumentMouseMove(event) {
  mouseX = (event.client.x - windowHalfX) * 10;
  mouseY = (event.client.y - windowHalfY) * 10;
}

void animate(num time) {
  window.requestAnimationFrame(animate);

  render();
}

void render() {
  camera.position.x += (mouseX - camera.position.x) * .05;
  camera.position.y += (-mouseY - camera.position.y) * .05;
  camera.lookAt(scene.position);

  //TODO describe how this oscillation affects the example
  num t = new DateTime.now().millisecondsSinceEpoch;
  var oscillate = (num rate) => Math.sin(t * rate) * 0.5;
  group.rotation.x = oscillate(0.0007);
  group.rotation.y = oscillate(0.0003);
  group.rotation.z = oscillate(0.0002);

  renderer.render(scene, camera);
}


<|start_filename|>lib/extras/geometries/shape_geometry.dart<|end_filename|>
part of three;

/**
 * @author jonobr1 / http://jonobr1.com
 *
 * Creates a one-sided polygonal geometry from a path shape. Similar to
 * ExtrudeGeometry.
 *
 * parameters = {
 *
 *  curveSegments: <int>, // number of points on the curves. NOT USED AT THE MOMENT.
 *
 *  material: <int> // material index for front and back faces
 *  uvGenerator: <Object> // object that provides UV generator functions
 *
 * }
 **/

class ShapeGeometry extends Geometry {

  List<Shape> shapes;

  var shapebb;

  ShapeGeometry(this.shapes, {int curveSegments: 12, int material, ExtrudeGeometryWorldUVGenerator UVGenerator})
      : super() {

    if (shapes == null) {
      shapes = [];
      return;
    }

    shapebb = shapes.last.getBoundingBox();

    addShapeList(shapes, curveSegments, material, UVGenerator);

    computeCentroids();
    computeFaceNormals();

  }



  addShapeList(List<Shape> shapes, num curveSegments, int material, [ExtrudeGeometryWorldUVGenerator UVGenerator =
      null]) {
    var sl = shapes.length;

    for (var s = 0; s < sl; s++) {
      var shape = shapes[s];
      addShape(shape, curveSegments, material, UVGenerator);
    }
  }

  addShape(Shape shape, num curveSegments, int material, [ExtrudeGeometryWorldUVGenerator UVGenerator = null]) {

    // set UV generator
    var uvgen = (UVGenerator != null) ? UVGenerator : new ExtrudeGeometryWorldUVGenerator();

    var i, hole, s;

    var shapesOffset = this.vertices.length;
    var shapePoints = shape.extractPoints(curveSegments);

    List vertices = shapePoints["shape"];
    List<List<Vector2>> holes = shapePoints["holes"];

    var reverse = !ShapeUtils.isClockWise(vertices);

    if (reverse) {

      vertices = vertices.reversed.toList();

      // Maybe we should also check if holes are in the opposite direction, just to be safe...

      for (i = 0; i < holes.length; i++) {

        hole = holes[i];

        if (ShapeUtils.isClockWise(hole)) {

          holes[i] = hole.reversed.toList();

        }

      }

      reverse = false;

    }

    var faces = ShapeUtils.triangulateShape(vertices, holes);

    // Vertices

    var contour = vertices;

    for (i = 0; i < holes.length; i++) {

      hole = holes[i];

      vertices = new List.from(vertices);
      vertices.addAll(hole);

    }

    //

    var vert,
        vlen = vertices.length;
    var face,
        flen = faces.length;
    var cont,
        clen = contour.length;

    for (i = 0; i < vlen; i++) {

      vert = vertices[i];

      this.vertices.add(new Vector3((vert.x).toDouble(), (vert.y).toDouble(), 0.0));

    }

    for (i = 0; i < flen; i++) {

      face = faces[i];

      var a = face[0] + shapesOffset;
      var b = face[1] + shapesOffset;
      var c = face[2] + shapesOffset;

      this.faces.add(new Face3(a, b, c, null, null, material));
      faceVertexUvs[0].add(uvgen.generateBottomUV(this, shape, null, a, b, c));

    }
  }
}




<|start_filename|>lib/extras/postprocessing/pass.dart<|end_filename|>
part of three_postprocessing;

abstract class Pass {
  get enabled;
  get needsSwap;

  void render(WebGLRenderer renderer, WebGLRenderTarget writeTarget, WebGLRenderTarget readTarget, double delta,
      bool maskActive);
}


<|start_filename|>lib/extras/shaders/edge_shader2.dart<|end_filename|>
part of three_shaders;

/**
 * @author zz85 / https://github.com/zz85 | https://www.lab4games.net/zz85/blog
 *
 * Edge Detection Shader using Sobel filter
 * Based on http://rastergrid.com/blog/2011/01/frei-chen-edge-detector
 *
 * aspect: vec2 of (1/width, 1/height)
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var EdgeShader2 = {

  'uniforms': {

    "tDiffuse": { 'type': "t", 'value': null },
    "aspect":    { 'type': "v2", 'value': new Vector2( 512.0, 512.0 ) },
  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform sampler2D tDiffuse;",
    "varying vec2 vUv;",
    "uniform vec2 aspect;",


    "vec2 texel = vec2(1.0 / aspect.x, 1.0 / aspect.y);",

    "mat3 G[2];",

    "const mat3 g0 = mat3( 1.0, 2.0, 1.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0 );",
    "const mat3 g1 = mat3( 1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0 );",


    "void main(void)",
    "{",
      "mat3 I;",
      "float cnv[2];",
      "vec3 sample;",

      "G[0] = g0;",
      "G[1] = g1;",

      /*
       * fetch the 3x3 neighbourhood and use the RGB vector's length as intensity 'value'
       */
      "for (float i=0.0; i<3.0; i++)",
      "for (float j=0.0; j<3.0; j++) {",
        "sample = texture2D( tDiffuse, vUv + texel * vec2(i-1.0,j-1.0) ).rgb;",
        "I[int(i)][int(j)] = length(sample);",
      "}",

      /*
       * calculate the convolution 'value's for all the masks
       */
      "for (int i=0; i<2; i++) {",
        "float dp3 = dot(G[i][0], I[0]) + dot(G[i][1], I[1]) + dot(G[i][2], I[2]);",
        "cnv[i] = dp3 * dp3; ",
      "}",

      "gl_FragColor = vec4(0.5 * sqrt(cnv[0]*cnv[0]+cnv[1]*cnv[1]));",
    "} ",

  ].join("\n")

};


<|start_filename|>lib/extras/shaders/digital_glitch.dart<|end_filename|>
part of three_shaders;

/**
 * @author felixturner / http://airtight.cc/
 *
 * RGB Shift Shader
 * Shifts red and blue channels from center in opposite directions
 * Ported from http://kriss.cx/tom/2009/05/rgb-shift/
 * by <NAME> / http://kriss.cx/tom/
 *
 * amount: shift distance (1 is width of input)
 * angle: shift angle in radians
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var DigitalGlitch = {

  'uniforms': {

    "tDiffuse":    { 'type': "t", 'value': null },//diffuse texture
    "tDisp":    { 'type': "t", 'value': null },//displacement texture for digital glitch squares
    "byp":      { 'type': "i", 'value': 0 },//apply the glitch ?
    "amount":    { 'type': "f", 'value': 0.08 },
    "angle":    { 'type': "f", 'value': 0.02 },
    "seed":      { 'type': "f", 'value': 0.02 },
    "seed_x":    { 'type': "f", 'value': 0.02 },//-1,1
    "seed_y":    { 'type': "f", 'value': 0.02 },//-1,1
    "distortion_x":  { 'type': "f", 'value': 0.5 },
    "distortion_y":  { 'type': "f", 'value': 0.6 },
    "col_s":    { 'type': "f", 'value': 0.05 }
  },

  'vertexShader': [

    "varying vec2 vUv;",
    "void main() {",
      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
    "}"
  ].join("\n"),

  'fragmentShader': [
    "uniform int byp;",//should we apply the glitch ?
    
    "uniform sampler2D tDiffuse;",
    "uniform sampler2D tDisp;",
    
    "uniform float amount;",
    "uniform float angle;",
    "uniform float seed;",
    "uniform float seed_x;",
    "uniform float seed_y;",
    "uniform float distortion_x;",
    "uniform float distortion_y;",
    "uniform float col_s;",
      
    "varying vec2 vUv;",
    
    
    "float rand(vec2 co){",
      "return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);",
    "}",
        
    "void main() {",
      "if(byp<1) {",
        "vec2 p = vUv;",
        "float xs = floor(gl_FragCoord.x / 0.5);",
        "float ys = floor(gl_FragCoord.y / 0.5);",
        //based on staffantans glitch shader for unity https://github.com/staffantan/unityglitch
        "vec4 normal = texture2D (tDisp, p*seed*seed);",
        "if(p.y<distortion_x+col_s && p.y>distortion_x-col_s*seed) {",
          "if(seed_x>0.){",
            "p.y = 1. - (p.y + distortion_y);",
          "}",
          "else {",
            "p.y = distortion_y;",
          "}",
        "}",
        "if(p.x<distortion_y+col_s && p.x>distortion_y-col_s*seed) {",
          "if(seed_y>0.){",
            "p.x=distortion_x;",
          "}",
          "else {",
            "p.x = 1. - (p.x + distortion_x);",
          "}",
        "}",
        "p.x+=normal.x*seed_x*(seed/5.);",
        "p.y+=normal.y*seed_y*(seed/5.);",
        //base from RGB shift shader
        "vec2 offset = amount * vec2( cos(angle), sin(angle));",
        "vec4 cr = texture2D(tDiffuse, p + offset);",
        "vec4 cga = texture2D(tDiffuse, p);",
        "vec4 cb = texture2D(tDiffuse, p - offset);",
        "gl_FragColor = vec4(cr.r, cga.g, cb.b, cga.a);",
        //add noise
        "vec4 snow = 200.*amount*vec4(rand(vec2(xs * seed,ys * seed*50.))*0.2);",
        "gl_FragColor = gl_FragColor+ snow;",
      "}",
      "else {",
        "gl_FragColor=texture2D (tDiffuse, vUv);",
      "}",
    "}"

  ].join("\n")

};


<|start_filename|>lib/extras/shaders/rgb_shift_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author felixturner / http://airtight.cc/
 *
 * RGB Shift Shader
 * Shifts red and blue channels from center in opposite directions
 * Ported from http://kriss.cx/tom/2009/05/rgb-shift/
 * by <NAME> / http://kriss.cx/tom/
 *
 * amount: shift distance (1 is width of input)
 * angle: shift angle in radians
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var RGBShiftShader = {

  'uniforms': {

    "tDiffuse": { 'type': "t", 'value': null },
    "amount":   { 'type': "f", 'value': 0.005 },
    "angle":    { 'type': "f", 'value': 0.0 }

  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform sampler2D tDiffuse;",
    "uniform float amount;",
    "uniform float angle;",

    "varying vec2 vUv;",

    "void main() {",

      "vec2 offset = amount * vec2( cos(angle), sin(angle));",
      "vec4 cr = texture2D(tDiffuse, vUv + offset);",
      "vec4 cga = texture2D(tDiffuse, vUv);",
      "vec4 cb = texture2D(tDiffuse, vUv - offset);",
      "gl_FragColor = vec4(cr.r, cga.g, cb.b, cga.a);",

    "}"

  ].join("\n")

};


<|start_filename|>example/misc_controls_orbit/misc_controls_orbit.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:three/three.dart';
import 'package:three/extras/controls/orbit_controls.dart';

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

OrbitControls controls;

void main() {
  init();
  animate(0);
}

void init() {
  container = new Element.tag('div');
  document.body.nodes.add(container);

  Element info = new Element.tag('div');
  info.style.position = 'absolute';
  info.style.top = '10px';
  info.style.width = '100%';
  info.style.textAlign = 'center';
  info.innerHtml = 'three.dart - misc controls orbit';
  container.nodes.add(info);

  camera = new PerspectiveCamera(60.0, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  camera.position.z = 500.0;

  controls = new OrbitControls(camera);
  controls.addEventListener('change', (_) => render());

  scene = new Scene();
  scene.fog = new FogExp2(0xcccccc, 0.002);

  var geometry;
  var material;
  var light;

  // Pyramids

  geometry = new CylinderGeometry(0.0, 10.0, 30.0, 4, 1);
  material = new MeshLambertMaterial(color: 0xffffff, shading: FlatShading);

  var rnd = new Math.Random();

  for (var i = 0; i < 500; i++) {

    var mesh = new Mesh(geometry, material);
    mesh.position.x = (rnd.nextDouble() - 0.5) * 1000;
    mesh.position.y = (rnd.nextDouble() - 0.5) * 1000;
    mesh.position.z = (rnd.nextDouble() - 0.5) * 1000;
    mesh.updateMatrix();
    mesh.matrixAutoUpdate = false;
    scene.add(mesh);

  }

  // Lights

  light = new DirectionalLight(0xffffff);
  light.position.x = 1.0;
  light.position.y = 1.0;
  light.position.z = 1.0;
  scene.add(light);

  light = new DirectionalLight(0x002288);
  light.position.x = -1.0;
  light.position.y = -1.0;
  light.position.z = -1.0;
  scene.add(light);

  light = new AmbientLight(0x222222);
  scene.add(light);

  // Renderer

  renderer = new WebGLRenderer(antialias: false);
  renderer.setClearColor(scene.fog.color, 1);
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.nodes.add(renderer.domElement);

  window.onResize.listen(onWindowResize);
}

onWindowResize(e) {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}


animate(num time) {
  window.requestAnimationFrame(animate);

  controls.update();

  render();
}

void render() {
  renderer.render(scene, camera);
}


<|start_filename|>lib/src/materials/mesh_phong_material.dart<|end_filename|>
part of three;

/// A material for shiny surfaces, evaluated per pixel.
class MeshPhongMaterial extends Material implements Lighting, TextureMapping, EnvironmentMapping, Skinning, Morphing {

  /// Ambient color of the material, multiplied by the color of the AmbientLight. Default is white.
  Color ambient;
  /// Emissive (light) color of the material, essentially a solid color
  /// unaffected by other lighting. Default is black.
  Color emissive;
  /// Specular color of the material, i.e., how shiny the material is and the
  /// color of its shine.
  ///
  /// Setting this the same color as the diffuse value (times some intensity)
  /// makes the material more metallic-looking; setting this to some gray makes
  /// the material look more plastic. Default is dark gray.
  Color specular;
  /// How shiny the specular highlight is; a higher value gives a sharper highlight. Default is 30.
  num shininess;

  bool metal;
  bool perPixel;

  bool wrapAround;
  Vector3 wrapRGB;

  Texture map;

  var lightMap;

  var bumpMap;
  num bumpScale;

  var normalMap = null;
  var normalScale;

  var specularMap;

  var envMap;
  int combine;
  num reflectivity;
  num refractionRatio;

  /// How the triangles of a curved surface are rendered: as a smooth surface,
  /// as flat separate facets, or no shading at all.
  ///
  /// Options are SmoothShading (default), FlatShading, NoShading.
  int shading;

  /// Whether the triangles' edges are displayed instead of surfaces. Default is false.
  bool wireframe;
  /// Line thickness for wireframe mode. Default is 1.0.
  ///
  /// Due to limitations in the ANGLE layer, on Windows platforms linewidth will
  /// always be 1 regardless of the set value.
  num wireframeLinewidth;
  /// Define appearance of line ends.
  ///
  /// Possible values are "butt", "round" and "square". Default is 'round'.
  ///
  /// This setting might not have any effect when used with certain renderers.
  /// For example, it is ignored with the WebGL renderer, but does work with the
  /// Canvas renderer.
  var wireframeLinecap;
  /// Define appearance of line joints.
  ///
  /// Possible values are "round", "bevel" and "miter". Default is 'round'.
  ///
  /// This setting might not have any effect when used with certain renderers.
  /// For example, it is ignored with the WebGL renderer, but does work with the
  /// Canvas renderer.
  var wireframeLinejoin;

  /// Define whether the material uses skinning. Default is false.
  bool skinning;

  // Morphing
  /// Define whether the material uses morphTargets. Default is false.
  bool morphTargets;
  bool morphNormals;
  num numSupportedMorphTargets = 0,
      numSupportedMorphNormals = 0;

  MeshPhongMaterial({ // MeshLambertMaterial

  num color: 0xffffff, //emissive
  num ambient: 0xffffff, num emissive: 0x000000, num specular: 0x111111, this.map, this.shininess: 30, this.metal:
      false, this.perPixel: false, this.wrapAround: false, Vector3 wrapRGB, this.lightMap, this.specularMap, this.envMap,
      this.bumpMap, this.bumpScale: 1, this.normalMap: null, this.normalScale, this.combine: MultiplyOperation,
      this.reflectivity: 1, this.refractionRatio: 0.98, this.shading: SmoothShading, int vertexColors: NoColors, bool fog:
      true, this.wireframe: false, this.wireframeLinewidth: 1, this.wireframeLinecap: 'round', this.wireframeLinejoin:
      'round', this.skinning: false, this.morphTargets: false, this.morphNormals: false, // Material
  name: '', side: FrontSide, opacity: 1, transparent: false, blending: NormalBlending, blendSrc: SrcAlphaFactor,
      blendDst: OneMinusSrcAlphaFactor, blendEquation: AddEquation, depthTest: true, depthWrite: true, polygonOffset: false,
      polygonOffsetFactor: 0, polygonOffsetUnits: 0, alphaTest: 0, overdraw: false, visible: true})
      : this.ambient = new Color(ambient),
        this.emissive = new Color(emissive),
        this.specular = new Color(specular),

        this.wrapRGB = wrapRGB == null ? new Vector3(1.0, 1.0, 1.0) : wrapRGB,

        super(
          name: name,
          side: side,
          opacity: opacity,
          transparent: transparent,
          blending: blending,
          blendSrc: blendSrc,
          blendDst: blendDst,
          blendEquation: blendEquation,
          depthTest: depthTest,
          depthWrite: depthWrite,
          polygonOffset: polygonOffset,
          polygonOffsetFactor: polygonOffsetFactor,
          polygonOffsetUnits: polygonOffsetUnits,
          alphaTest: alphaTest,
          overdraw: overdraw,
          visible: visible,
          color: color,
          fog: fog,
          vertexColors: vertexColors) {

    if (normalScale == null) {
      normalScale = new Vector2(1.0, 1.0);
    }

  }

}


<|start_filename|>lib/src/textures/texture.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author szimek / https://github.com/szimek/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

class ImageList extends Object with ListMixin<ImageElement> {
  int loadCount;
  List<ImageElement> _images;
  Map<String, dynamic> props;

  // WebGL
  gl.Texture webglTextureCube;

  ImageList(size)
      : props = {},
        _images = new List<ImageElement>(size);

  ImageList.from(ImageList other)
      : props = {},
        _images = new List<ImageElement>.from(other._images);

  ImageElement operator [](int index) => _images[index];
  void operator []=(int index, ImageElement img) {
    _images[index] = img;
  }
  int get length => _images.length;
  void set length(int size) {
    _images.length = size;
  }
}

class Texture {
  int id;
  var image;
  var mapping; //UVMapping appears to be missing..
  int wrapS, wrapT, magFilter, minFilter, format, type, anisotropy;
  Vector2 offset, repeat;
  bool generateMipmaps;
  bool premultiplyAlpha;

  bool needsUpdate;
  var onUpdate;

  bool flipY;

  int unpackAlignment =
      4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)

  List mipmaps = [];

  // WebGL
  var __webglTexture;

  //TODO: resolve dynamic vars, find out what UVMapping is!
  Texture([this.image, this.mapping = null, this.wrapS = ClampToEdgeWrapping, this.wrapT = ClampToEdgeWrapping,
      this.magFilter = LinearFilter, this.minFilter = LinearMipMapLinearFilter, this.format = RGBAFormat, this.type =
      UnsignedByteType, this.anisotropy = 1]) {
    id = TextureCount++;

    this.mapping = mapping != null ? mapping : new UVMapping();

    offset = new Vector2.zero();
    repeat = new Vector2(1.0, 1.0);

    generateMipmaps = true;
    premultiplyAlpha = false;
    flipY = true;

    needsUpdate = false;
    onUpdate = null;
  }

  Texture clone() {
    Texture clonedTexture = new Texture(image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy);

    clonedTexture.mipmaps = new List.from(mipmaps);
    clonedTexture.offset.setFrom(offset);
    clonedTexture.repeat.setFrom(repeat);

    return clonedTexture;
  }

  // Quick hack to allow setting new properties (used by the renderer)
  Map __data;

  get _data {
    if (__data == null) {
      __data = {};
    }
    return __data;
  }

  operator [](String key) => _data[key];
  operator []=(String key, value) => _data[key] = value;
}


<|start_filename|>lib/src/lights/light.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

/// Abstract base class for lights.
class Light extends Object3D {
  /// Color of the light.
  Color color;

  /// This creates a light with color.
  Light(num hex)
      : color = new Color(hex),
        super();
}


<|start_filename|>example/web_gl_geometry_cube/web_gl_geometry_cube.dart<|end_filename|>
import 'dart:html';
import 'package:three/three.dart';
import 'package:three/extras/image_utils.dart' as ImageUtils; // TODO - Use Re-export

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

Mesh cube;

void main() {
  init();
  animate(0);
}

void init() {

  container = new Element.tag('div');

  document.body.nodes.add(container);

  scene = new Scene();

  camera = new PerspectiveCamera(70.0, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  camera.position.z = 400.0;

  scene.add(camera);

  var geometry = new CubeGeometry(200.0, 200.0, 200.0);
  var material = new MeshBasicMaterial(map: ImageUtils.loadTexture('textures/crate.gif'));

  cube = new Mesh(geometry, material);
  scene.add(cube);

  renderer = new WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.nodes.add(renderer.domElement);

  window.onResize.listen(onWindowResize);
}

onWindowResize(e) {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}

animate(num time) {

  window.requestAnimationFrame(animate);

  cube.rotation.x += 0.005;
  cube.rotation.y += 0.01;

  renderer.render(scene, camera);

}


<|start_filename|>example/web_gl_loader_obj/web_gl_loader_obj_mtl.dart<|end_filename|>
import 'dart:html';
import 'package:three/three.dart';

var container, stats;

var camera, cameraTarget, scene, renderer;

var mouseX = 0,
    mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

main() {
  init();
  animate(0);
}

init() {
  container = document.createElement('div');
  document.body.append(container);

  camera = new PerspectiveCamera(35.0, window.innerWidth / window.innerHeight, 1.0, 2000.0);
  camera.position.z = 100.0;

  // scene
  scene = new Scene();

  var ambient = new AmbientLight(0x101030);
  scene.add(ambient);

  var directionalLight = new DirectionalLight(0xffeedd);
  directionalLight.intensity = 1.0;
  directionalLight.position.setValues(0.0, 0.0, 1.0);
  scene.add(directionalLight);


  // model
  var loader = new OBJLoader();
  loader.load('obj/male02.obj').then((object) {
    object.position.y = -80.0;
    scene.add(object);
  });

  renderer = new WebGLRenderer(antialias: true, alpha: false);
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.append(renderer.domElement);

  document.onMouseMove.listen(onDocumentMouseMove);
}

onDocumentMouseMove(MouseEvent event) {
  mouseX = (event.client.x - windowHalfX) / 2;
  mouseY = (event.client.y - windowHalfY) / 2;
}


animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

render() {
  camera.position.x += (mouseX - camera.position.x) * 0.05;
  camera.position.y += (-mouseY - camera.position.y) * 0.05;

  camera.lookAt(scene.position);

  renderer.render(scene, camera);
}


<|start_filename|>example/css3d_periodic_table/periodic_table.dart<|end_filename|>
part of periodic_table;

var table = [
    ["H", "Hydrogen", "1.00794", 1, 1],
    ["He", "Helium", "4.002602", 18, 1],
    ["Li", "Lithium", "6.941", 1, 2],
    ["Be", "Beryllium", "9.012182", 2, 2],
    ["B", "Boron", "10.811", 13, 2],
    ["C", "Carbon", "12.0107", 14, 2],
    ["N", "Nitrogen", "14.0067", 15, 2],
    ["O", "Oxygen", "15.9994", 16, 2],
    ["F", "Fluorine", "18.9984032", 17, 2],
    ["Ne", "Neon", "20.1797", 18, 2],
    ["Na", "Sodium", "22.98976...", 1, 3],
    ["Mg", "Magnesium", "24.305", 2, 3],
    ["Al", "Aluminium", "26.9815386", 13, 3],
    ["Si", "Silicon", "28.0855", 14, 3],
    ["P", "Phosphorus", "30.973762", 15, 3],
    ["S", "Sulfur", "32.065", 16, 3],
    ["Cl", "Chlorine", "35.453", 17, 3],
    ["Ar", "Argon", "39.948", 18, 3],
    ["K", "Potassium", "39.948", 1, 4],
    ["Ca", "Calcium", "40.078", 2, 4],
    ["Sc", "Scandium", "44.955912", 3, 4],
    ["Ti", "Titanium", "47.867", 4, 4],
    ["V", "Vanadium", "50.9415", 5, 4],
    ["Cr", "Chromium", "51.9961", 6, 4],
    ["Mn", "Manganese", "54.938045", 7, 4],
    ["Fe", "Iron", "55.845", 8, 4],
    ["Co", "Cobalt", "58.933195", 9, 4],
    ["Ni", "Nickel", "58.6934", 10, 4],
    ["Cu", "Copper", "63.546", 11, 4],
    ["Zn", "Zinc", "65.38", 12, 4],
    ["Ga", "Gallium", "69.723", 13, 4],
    ["Ge", "Germanium", "72.63", 14, 4],
    ["As", "Arsenic", "74.9216", 15, 4],
    ["Se", "Selenium", "78.96", 16, 4],
    ["Br", "Bromine", "79.904", 17, 4],
    ["Kr", "Krypton", "83.798", 18, 4],
    ["Rb", "Rubidium", "85.4678", 1, 5],
    ["Sr", "Strontium", "87.62", 2, 5],
    ["Y", "Yttrium", "88.90585", 3, 5],
    ["Zr", "Zirconium", "91.224", 4, 5],
    ["Nb", "Niobium", "92.90628", 5, 5],
    ["Mo", "Molybdenum", "95.96", 6, 5],
    ["Tc", "Technetium", "(98)", 7, 5],
    ["Ru", "Ruthenium", "101.07", 8, 5],
    ["Rh", "Rhodium", "102.9055", 9, 5],
    ["Pd", "Palladium", "106.42", 10, 5],
    ["Ag", "Silver", "107.8682", 11, 5],
    ["Cd", "Cadmium", "112.411", 12, 5],
    ["In", "Indium", "114.818", 13, 5],
    ["Sn", "Tin", "118.71", 14, 5],
    ["Sb", "Antimony", "121.76", 15, 5],
    ["Te", "Tellurium", "127.6", 16, 5],
    ["I", "Iodine", "126.90447", 17, 5],
    ["Xe", "Xenon", "131.293", 18, 5],
    ["Cs", "Caesium", "132.9054", 1, 6],
    ["Ba", "Barium", "132.9054", 2, 6],
    ["La", "Lanthanum", "138.90547", 4, 9],
    ["Ce", "Cerium", "140.116", 5, 9],
    ["Pr", "Praseodymium", "140.90765", 6, 9],
    ["Nd", "Neodymium", "144.242", 7, 9],
    ["Pm", "Promethium", "(145)", 8, 9],
    ["Sm", "Samarium", "150.36", 9, 9],
    ["Eu", "Europium", "151.964", 10, 9],
    ["Gd", "Gadolinium", "157.25", 11, 9],
    ["Tb", "Terbium", "158.92535", 12, 9],
    ["Dy", "Dysprosium", "162.5", 13, 9],
    ["Ho", "Holmium", "164.93032", 14, 9],
    ["Er", "Erbium", "167.259", 15, 9],
    ["Tm", "Thulium", "168.93421", 16, 9],
    ["Yb", "Ytterbium", "173.054", 17, 9],
    ["Lu", "Lutetium", "174.9668", 18, 9],
    ["Hf", "Hafnium", "178.49", 4, 6],
    ["Ta", "Tantalum", "180.94788", 5, 6],
    ["W", "Tungsten", "183.84", 6, 6],
    ["Re", "Rhenium", "186.207", 7, 6],
    ["Os", "Osmium", "190.23", 8, 6],
    ["Ir", "Iridium", "192.217", 9, 6],
    ["Pt", "Platinum", "195.084", 10, 6],
    ["Au", "Gold", "196.966569", 11, 6],
    ["Hg", "Mercury", "200.59", 12, 6],
    ["Tl", "Thallium", "204.3833", 13, 6],
    ["Pb", "Lead", "207.2", 14, 6],
    ["Bi", "Bismuth", "208.9804", 15, 6],
    ["Po", "Polonium", "(209)", 16, 6],
    ["At", "Astatine", "(210)", 17, 6],
    ["Rn", "Radon", "(222)", 18, 6],
    ["Fr", "Francium", "(223)", 1, 7],
    ["Ra", "Radium", "(226)", 2, 7],
    ["Ac", "Actinium", "(227)", 4, 10],
    ["Th", "Thorium", "232.03806", 5, 10],
    ["Pa", "Protactinium", "231.0588", 6, 10],
    ["U", "Uranium", "238.02891", 7, 10],
    ["Np", "Neptunium", "(237)", 8, 10],
    ["Pu", "Plutonium", "(244)", 9, 10],
    ["Am", "Americium", "(243)", 10, 10],
    ["Cm", "Curium", "(247)", 11, 10],
    ["Bk", "Berkelium", "(247)", 12, 10],
    ["Cf", "Californium", "(251)", 13, 10],
    ["Es", "Einstenium", "(252)", 14, 10],
    ["Fm", "Fermium", "(257)", 15, 10],
    ["Md", "Mendelevium", "(258)", 16, 10],
    ["No", "Nobelium", "(259)", 17, 10],
    ["Lr", "Lawrencium", "(262)", 18, 10],
    ["Rf", "Rutherfordium", "(267)", 4, 7],
    ["Db", "Dubnium", "(268)", 5, 7],
    ["Sg", "Seaborgium", "(271)", 6, 7],
    ["Bh", "Bohrium", "(272)", 7, 7],
    ["Hs", "Hassium", "(270)", 8, 7],
    ["Mt", "Meitnerium", "(276)", 9, 7],
    ["Ds", "Darmstadium", "(281)", 10, 7],
    ["Rg", "Roentgenium", "(280)", 11, 7],
    ["Cn", "Copernicium", "(285)", 12, 7],
    ["Uut", "Unutrium", "(284)", 13, 7],
    ["Fl", "Flerovium", "(289)", 14, 7],
    ["Uup", "Ununpentium", "(288)", 15, 7],
    ["Lv", "Livermorium", "(293)", 16, 7],
    ["Uus", "Ununseptium", "(294)", 17, 7],
    ["Uuo", "Ununoctium", "(294)", 18, 7]];


<|start_filename|>example/web_gl_geometry_shapes/web_gl_geometry_shapes.dart<|end_filename|>
import 'dart:html' hide Path;
import 'dart:math' as Math;
import 'package:vector_math/vector_math.dart';
import 'package:three/three.dart';
import 'package:three/extras/scene_utils.dart' as SceneUtils;
import 'package:three/extras/geometry_utils.dart' as GeometryUtils;

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

var windowHalfX, windowHalfY;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var mouseEvts = [];

var targetRotation = 0;
var targetRotationOnMouseDown = 0;

Object3D parent, text, plane;

void main() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  init();
  animate(0);
}

addGeometry(geometry, points, spacedPoints, color, x, y, z, rx, ry, rz, s) {

  // 3d shape

  var mesh = SceneUtils.createMultiMaterialObject(
      geometry,
      [new MeshLambertMaterial(color: color), new MeshBasicMaterial(color: 0x000000, wireframe: true, transparent: true)]);
  mesh.position.setValues(x, y, z - 75);
  mesh.rotation.setValues(rx, ry, rz);
  mesh.scale.setValues(s, s, s);
  parent.add(mesh);

  // solid line

  var line = new Line(points, new LineBasicMaterial(color: color, linewidth: 2));
  line.position.setValues(x, y, z + 25);
  line.rotation.setValues(rx, ry, rz);
  line.scale.setValues(s, s, s);
  parent.add(line);

  // transparent line from real points

  line = new Line(points, new LineBasicMaterial(color: color, opacity: 0.5));
  line.position.setValues(x, y, z + 75);
  line.rotation.setValues(rx, ry, rz);
  line.scale.setValues(s, s, s);
  parent.add(line);

  // vertices from real points

  var pgeo = GeometryUtils.clone(points);
  var particles = new ParticleSystem(pgeo, new ParticleBasicMaterial(color: color, size: 2, opacity: 0.75));
  particles.position.setValues(x, y, z + 75);
  particles.rotation.setValues(rx, ry, rz);
  particles.scale.setValues(s, s, s);
  parent.add(particles);

  // transparent line from equidistance sampled points

  line = new Line(spacedPoints, new LineBasicMaterial(color: color, opacity: 0.2));
  line.position.setValues(x, y, z + 100);
  line.rotation.setValues(rx, ry, rz);
  line.scale.setValues(s, s, s);
  parent.add(line);

  // equidistance sampled points

  pgeo = GeometryUtils.clone(spacedPoints);
  var particles2 = new ParticleSystem(pgeo, new ParticleBasicMaterial(color: color, size: 2, opacity: 0.5));
  particles2.position.setValues(x, y, z + 100);
  particles2.rotation.setValues(rx, ry, rz);
  particles2.scale.setValues(s, s, s);
  parent.add(particles2);

}

roundedRect(ctx, x, y, width, height, radius) {

  ctx.moveTo(x, y + radius);
  ctx.lineTo(x, y + height - radius);
  ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
  ctx.lineTo(x + width - radius, y + height);
  ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
  ctx.lineTo(x + width, y + radius);
  ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
  ctx.lineTo(x + radius, y);
  ctx.quadraticCurveTo(x, y, x, y + radius);

}
void init() {

  container = new Element.tag('div');
  document.body.nodes.add(container);

  camera = new PerspectiveCamera(50.0, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  camera.position.setValues(0.0, 150.0, 500.0);

  scene = new Scene();

  var light = new DirectionalLight(0xffffff);
  light.position.setValues(0.0, 0.0, 1.0);
  scene.add(light);

  parent = new Object3D();
  parent.position.y = 50.0;
  scene.add(parent);

  var extrude_amount = 20,
      extrude_bevelEnabled = true,
      extrude_bevelSegments = 2,
      extrude_steps = 2; // bevelSegments: 2, steps: 2 , bevelSegments: 5, bevelsize: 8, bevelThickness:5,

  // California

  var californiaPts = [];

  californiaPts.add(new Vector2(610.0, 320.0));
  californiaPts.add(new Vector2(450.0, 300.0));
  californiaPts.add(new Vector2(392.0, 392.0));
  californiaPts.add(new Vector2(266.0, 438.0));
  californiaPts.add(new Vector2(190.0, 570.0));
  californiaPts.add(new Vector2(190.0, 600.0));
  californiaPts.add(new Vector2(160.0, 620.0));
  californiaPts.add(new Vector2(160.0, 650.0));
  californiaPts.add(new Vector2(180.0, 640.0));
  californiaPts.add(new Vector2(165.0, 680.0));
  californiaPts.add(new Vector2(150.0, 670.0));
  californiaPts.add(new Vector2(90.0, 737.0));
  californiaPts.add(new Vector2(80.0, 795.0));
  californiaPts.add(new Vector2(50.0, 835.0));
  californiaPts.add(new Vector2(64.0, 870.0));
  californiaPts.add(new Vector2(60.0, 945.0));
  californiaPts.add(new Vector2(300.0, 945.0));
  californiaPts.add(new Vector2(300.0, 743.0));
  californiaPts.add(new Vector2(600.0, 473.0));
  californiaPts.add(new Vector2(626.0, 425.0));
  californiaPts.add(new Vector2(600.0, 370.0));
  californiaPts.add(new Vector2(610.0, 320.0));

  var californiaShape = new Shape(californiaPts);

  var california3d = new ExtrudeGeometry([californiaShape], amount: 20);
  var californiaPoints = californiaShape.createPointsGeometry();
  var californiaSpacedPoints = californiaShape.createSpacedPointsGeometry(100);

  // Triangle

  var triangleShape = new Shape();
  triangleShape.moveTo(80.0, 20.0);
  triangleShape.lineTo(40.0, 80.0);
  triangleShape.lineTo(120.0, 80.0);
  triangleShape.lineTo(80.0, 20.0); // close path

  var triangle3d = triangleShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var trianglePoints = triangleShape.createPointsGeometry();
  var triangleSpacedPoints = triangleShape.createSpacedPointsGeometry();


  // Heart

  var x = 0.0,
      y = 0.0;

  var heartShape = new Shape(); // From http://blog.burlock.org/html5/130-paths

  heartShape.moveTo(x + 25, y + 25);
  heartShape.bezierCurveTo(x + 25, y + 25, x + 20, y, x, y);
  heartShape.bezierCurveTo(x - 30, y, x - 30, y + 35, x - 30, y + 35);
  heartShape.bezierCurveTo(x - 30, y + 55, x - 10, y + 77, x + 25, y + 95);
  heartShape.bezierCurveTo(x + 60, y + 77, x + 80, y + 55, x + 80, y + 35);
  heartShape.bezierCurveTo(x + 80, y + 35, x + 80, y, x + 50, y);
  heartShape.bezierCurveTo(x + 35, y, x + 25, y + 25, x + 25, y + 25);

  var heart3d = heartShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var heartPoints = heartShape.createPointsGeometry();
  var heartSpacedPoints = heartShape.createSpacedPointsGeometry();

  //heartShape.debug( document.getElementById("debug") );

  // Square

  var sqLength = 80.0;

  var squareShape = new Shape();
  squareShape.moveTo(0.0, 0.0);
  squareShape.lineTo(0.0, sqLength);
  squareShape.lineTo(sqLength, sqLength);
  squareShape.lineTo(sqLength, 0.0);
  squareShape.lineTo(0.0, 0.0);

  var square3d = squareShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var squarePoints = squareShape.createPointsGeometry();
  var squareSpacedPoints = squareShape.createSpacedPointsGeometry();

  // Rectangle

  var rectLength = 120.0,
      rectWidth = 40.0;

  var rectShape = new Shape();
  rectShape.moveTo(0.0, 0.0);
  rectShape.lineTo(0.0, rectWidth);
  rectShape.lineTo(rectLength, rectWidth);
  rectShape.lineTo(rectLength, 0.0);
  rectShape.lineTo(0.0, 0.0);

  var rect3d = rectShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var rectPoints = rectShape.createPointsGeometry();
  var rectSpacedPoints = rectShape.createSpacedPointsGeometry();

  // Rounded rectangle

  var roundedRectShape = new Shape();
  roundedRect(roundedRectShape, 0.0, 0.0, 50.0, 50.0, 20.0);

  var roundedRect3d = roundedRectShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var roundedRectPoints = roundedRectShape.createPointsGeometry();
  var roundedRectSpacedPoints = roundedRectShape.createSpacedPointsGeometry();

  // Circle

  var circleRadius = 40.0;
  var circleShape = new Shape();
  circleShape.moveTo(0.0, circleRadius);
  circleShape.quadraticCurveTo(circleRadius, circleRadius, circleRadius, 0.0);
  circleShape.quadraticCurveTo(circleRadius, -circleRadius, 0.0, -circleRadius);
  circleShape.quadraticCurveTo(-circleRadius, -circleRadius, -circleRadius, 0.0);
  circleShape.quadraticCurveTo(-circleRadius, circleRadius, 0.0, circleRadius);

  var circle3d = circleShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var circlePoints = circleShape.createPointsGeometry();
  var circleSpacedPoints = circleShape.createSpacedPointsGeometry();

  // Fish

  x = y = 0.0;

  var fishShape = new Shape();

  fishShape.moveTo(x, y);
  fishShape.quadraticCurveTo(x + 50, y - 80, x + 90, y - 10);
  fishShape.quadraticCurveTo(x + 100, y - 10, x + 115, y - 40);
  fishShape.quadraticCurveTo(x + 115, y, x + 115, y + 40);
  fishShape.quadraticCurveTo(x + 100, y + 10, x + 90, y + 10);
  fishShape.quadraticCurveTo(x + 50, y + 80, x, y);

  var fish3d = fishShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var fishPoints = fishShape.createPointsGeometry();
  var fishSpacedPoints = fishShape.createSpacedPointsGeometry();

  // Arc circle

  var arcShape = new Shape();
  arcShape.moveTo(50.0, 10.0);
  arcShape.absarc(10.0, 10.0, 40.0, 0.0, Math.PI * 2, false);

  var holePath = new Path();
  holePath.moveTo(20.0, 10.0);
  holePath.absarc(10.0, 10.0, 10.0, 0.0, Math.PI * 2, true);
  arcShape.holes.add(holePath);

  var arc3d = arcShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var arcPoints = arcShape.createPointsGeometry();
  var arcSpacedPoints = arcShape.createSpacedPointsGeometry();


  // Smiley

  var smileyShape = new Shape();
  smileyShape.moveTo(80.0, 40.0);
  smileyShape.absarc(40.0, 40.0, 40.0, 0.0, Math.PI * 2, false);

  var smileyEye1Path = new Path();
  smileyEye1Path.moveTo(35.0, 20.0);
  // smileyEye1Path.absarc( 25, 20, 10, 0, Math.PI*2, true );
  smileyEye1Path.absellipse(25.0, 20.0, 10.0, 10.0, 0.0, Math.PI * 2, true);

  smileyShape.holes.add(smileyEye1Path);

  var smileyEye2Path = new Path();
  smileyEye2Path.moveTo(65.0, 20.0);
  smileyEye2Path.absarc(55.0, 20.0, 10.0, 0.0, Math.PI * 2, true);
  smileyShape.holes.add(smileyEye2Path);

  var smileyMouthPath = new Path();
  // ugly box mouth
  // smileyMouthPath.moveTo( 20, 40 );
  // smileyMouthPath.lineTo( 60, 40 );
  // smileyMouthPath.lineTo( 60, 60 );
  // smileyMouthPath.lineTo( 20, 60 );
  // smileyMouthPath.lineTo( 20, 40 );

  smileyMouthPath.moveTo(20.0, 40.0);
  smileyMouthPath.quadraticCurveTo(40.0, 60.0, 60.0, 40.0);
  smileyMouthPath.bezierCurveTo(70.0, 45.0, 70.0, 50.0, 60.0, 60.0);
  smileyMouthPath.quadraticCurveTo(40.0, 80.0, 20.0, 60.0);
  smileyMouthPath.quadraticCurveTo(5.0, 50.0, 20.0, 40.0);

  smileyShape.holes.add(smileyMouthPath);


  var smiley3d = smileyShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps);
  var smileyPoints = smileyShape.createPointsGeometry();
  var smileySpacedPoints = smileyShape.createSpacedPointsGeometry();

  // Spline shape + path extrusion

  var splinepts = [];
  splinepts.add(new Vector2(350.0, 100.0));
  splinepts.add(new Vector2(400.0, 450.0));
  splinepts.add(new Vector2(-140.0, 350.0));
  splinepts.add(new Vector2.zero());

  var splineShape = new Shape();
  splineShape.moveTo(0.0, 0.0);
  splineShape.splineThru(splinepts);

  //splineShape.debug( document.getElementById("debug") );

  // TODO 3d path?

  var apath = new SplineCurve3();
  apath.points.add(new Vector3(-50.0, 150.0, 10.0));
  apath.points.add(new Vector3(-20.0, 180.0, 20.0));
  apath.points.add(new Vector3(40.0, 220.0, 50.0));
  apath.points.add(new Vector3(200.0, 290.0, 100.0));

  var extrude_extrudePath = apath;
  extrude_bevelEnabled = false;
  extrude_steps = 20;

  var splineShape3d = splineShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps,
      extrudePath: extrude_extrudePath);
  var splinePoints = splineShape.createPointsGeometry();
  var splineSpacedPoints = splineShape.createSpacedPointsGeometry();

  addGeometry(
      california3d,
      californiaPoints,
      californiaSpacedPoints,
      0xffaa00,
      -300.0,
      -100.0,
      0.0,
      0.0,
      0.0,
      0.0,
      0.25);
  addGeometry(triangle3d, trianglePoints, triangleSpacedPoints, 0xffee00, -180.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
  addGeometry(
      roundedRect3d,
      roundedRectPoints,
      roundedRectSpacedPoints,
      0x005500,
      -150.0,
      150.0,
      0.0,
      0.0,
      0.0,
      0.0,
      1.0);
  addGeometry(square3d, squarePoints, squareSpacedPoints, 0x0055ff, 150.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0);
  addGeometry(heart3d, heartPoints, heartSpacedPoints, 0xff1100, 0.0, 100.0, 0.0, Math.PI, 0.0, 0.0, 1.0);
  addGeometry(circle3d, circlePoints, circleSpacedPoints, 0x00ff11, 120.0, 250.0, 0.0, 0.0, 0.0, 0.0, 1.0);
  addGeometry(fish3d, fishPoints, fishSpacedPoints, 0x222222, -60.0, 200.0, 0.0, 0.0, 0.0, 0.0, 1.0);
  addGeometry(splineShape3d, splinePoints, splineSpacedPoints, 0x888888, -50.0, -100.0, -50.0, 0.0, 0.0, 0.0, 0.2);
  addGeometry(arc3d, arcPoints, arcSpacedPoints, 0xbb4422, 150.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
  addGeometry(smiley3d, smileyPoints, smileySpacedPoints, 0xee00ff, -270.0, 250.0, 0.0, Math.PI, 0.0, 0.0, 1.0);


  //

  renderer = new WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.sortObjects = false;

  container.nodes.add(renderer.domElement);

  mouseEvts = [
      document.onMouseDown.listen(onDocumentMouseDown),
      document.onTouchStart.listen(onDocumentTouchStart),
      document.onTouchMove.listen(onDocumentTouchMove)];


  window.onResize.listen(onWindowResize);
}

onWindowResize(event) {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

void cancelMouseEvts() {
  mouseEvts.forEach((s) => s.cancel());
  mouseEvts = [];
}

onDocumentMouseDown(MouseEvent event) {
  event.preventDefault();

  mouseEvts = [
      document.onMouseMove.listen(onDocumentMouseMove),
      document.onMouseUp.listen(onDocumentMouseUp),
      document.onMouseOut.listen(onDocumentMouseOut)];

  mouseXOnMouseDown = event.client.x - windowHalfX;
  targetRotationOnMouseDown = targetRotation;
}

onDocumentMouseMove(MouseEvent event) {
  mouseX = event.client.x - windowHalfX;
  targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
}

onDocumentMouseUp(event) {
  cancelMouseEvts();
}

onDocumentMouseOut(event) {
  cancelMouseEvts();
}

onDocumentTouchStart(TouchEvent event) {

  if (event.touches.length == 1) {

    event.preventDefault();

    mouseXOnMouseDown = event.touches[0].page.x - windowHalfX;
    targetRotationOnMouseDown = targetRotation;

  }

}

onDocumentTouchMove(TouchEvent event) {

  if (event.touches.length == 1) {

    event.preventDefault();

    mouseX = event.touches[0].page.x - windowHalfX;
    targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;

  }

}

animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

render() {

  parent.rotation.y += (targetRotation - parent.rotation.y) * 0.05;

  renderer.render(scene, camera);

}


<|start_filename|>lib/extras/core/quadratic_bezier_curve.dart<|end_filename|>
part of three;

class QuadraticBezierCurve extends Curve2D {

  Vector2 v0, v1, v2;

  QuadraticBezierCurve(this.v0, this.v1, this.v2);

  getPoint(t) {

    var tx, ty;

    tx = ShapeUtils.b2(t, v0.x, v1.x, v2.x);
    ty = ShapeUtils.b2(t, v0.y, v1.y, v2.y);

    return new Vector2(tx, ty);
  }


  getTangent(t) {

    var tx, ty;

    tx = CurveUtils.tangentQuadraticBezier(t, v0.x, v1.x, v2.x);
    ty = CurveUtils.tangentQuadraticBezier(t, v0.y, v1.y, v2.y);

    // returns unit vector
    return new Vector2(tx, ty).normalize();
  }
}


<|start_filename|>lib/extras/shaders/sepia_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Sepia tone shader
 * based on glfx.js sepia shader
 * https://github.com/evanw/glfx.js
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var SepiaShader = {

  'uniforms': {

    "tDiffuse": { 'type': "t", 'value': null },
    "amount":   { 'type': "f", 'value': 1.0 }

  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform float amount;",

    "uniform sampler2D tDiffuse;",

    "varying vec2 vUv;",

    "void main() {",

      "vec4 color = texture2D( tDiffuse, vUv );",
      "vec3 c = color.rgb;",

      "color.r = dot( c, vec3( 1.0 - 0.607 * amount, 0.769 * amount, 0.189 * amount ) );",
      "color.g = dot( c, vec3( 0.349 * amount, 1.0 - 0.314 * amount, 0.168 * amount ) );",
      "color.b = dot( c, vec3( 0.272 * amount, 0.534 * amount, 1.0 - 0.869 * amount ) );",

      "gl_FragColor = vec4( min( vec3( 1.0 ), color.rgb ), color.a );",

    "}"

  ].join("\n")

};


<|start_filename|>example/web_gl_postprocessing_volumetric_lighting/volumetric_lighting.dart<|end_filename|>
/*
 * @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
 *
 * Ported to Dart from JS by
 * @author <NAME> / https://github.com/cgrabowski
 */

import 'dart:math';
import 'dart:html';
import 'package:three/three.dart';
import 'package:three/extras/shaders/shaders.dart';
import 'package:three/extras/postprocessing/postprocessing.dart';
//import 'package:datgui/datgui.dart' as dat;
import 'package:stats/stats.dart';

const int COLOR1 = 0x77bbff;
const int COLOR11 = 0x99ddff;
const int COLOR2 = 0x8ec5e5;
const int COLOR3 = 0x97a8ba;
const double BLURINESS = 10.0;

double mouseX = 0.0;
double mouseY = 0.0;
WebGLRenderer renderer;
Scene scene, oclscene;
PerspectiveCamera camera, oclcamera;
EffectComposer oclcomposer, finalComposer;
ShaderPass hblur, vblur;
PointLight pointLight;
Mesh vlight;
ShaderPass godrayPass;
Stats stats;

void main() {
  init();
  animate(0.0);
}

void init() {
  // renderer init
  renderer = new WebGLRenderer()
      ..autoClear = false
      //..sortObjects = true
      ..setSize(window.innerWidth, window.innerHeight);
  document.body.append(renderer.domElement);

  // scenes init
  scene = new Scene();
  oclscene = new Scene();

  // cameras init
  camera = new PerspectiveCamera(70.0, window.innerWidth / window.innerHeight, 1.0, 100000.0)
      ..position.z = 280.0
      ..lookAt(scene.position);
  oclcamera = new PerspectiveCamera(70.0, window.innerWidth / window.innerHeight, 1.0, 100000.0)
      ..position = camera.position
      ..lookAt(scene.position);

  //lights init
  scene.add(new AmbientLight(0xffffff)); // primary scene lights
  pointLight = new PointLight(COLOR3)..position.setValues(0.0, 100.0, 0.0);
  scene.add(pointLight);
  PointLight cameraLight = new PointLight(0x666666);
  camera.add(cameraLight);

  oclscene.add(new AmbientLight(0xffffff)); // ocl scene lights
  vlight = new Mesh(new IcosahedronGeometry(50.0, 3), new MeshBasicMaterial(color: COLOR11));
  vlight.position = pointLight.position;
  oclscene.add(vlight);

  JSONLoader loader = new JSONLoader();

  void callback(Geometry data) {
    createScene(data);
  }
  loader.load('trondisk.json', callback);

  // postprocessing
  oclcomposer = new EffectComposer(renderer); // ocl composer
  RenderPass oclrenderPass = new RenderPass(oclscene, oclcamera);
  oclcomposer.addPass(oclrenderPass);

  hblur = new ShaderPass(new ShaderProgram.fromThreeish(HorizontalBlurShader));
  hblur.uniforms['h'].value = BLURINESS / window.innerWidth;
  //hblur.renderToScreen = true;
  oclcomposer.addPass(hblur);

  vblur = new ShaderPass(new ShaderProgram.fromThreeish(VerticalBlurShader));
  vblur.uniforms['v'].value = BLURINESS / window.innerHeight;
  //vblur.renderToScreen = true;
  oclcomposer.addPass(vblur);

  oclcomposer.addPass(hblur);
  oclcomposer.addPass(vblur);

  godrayPass = new ShaderPass(new ShaderProgram.fromThreeish(GodraysShader));
  //grPass.renderToScreen = true;
  oclcomposer.addPass(godrayPass);


  finalComposer = new EffectComposer(renderer);
  RenderPass renderModel = new RenderPass(scene, camera);
  finalComposer.addPass(renderModel);

  ShaderPass fxaaPass = new ShaderPass(new ShaderProgram.fromThreeish(FXAAShader));
  fxaaPass.uniforms['resolution'].value.setValues(1 / window.innerWidth, 1 / window.innerHeight);
  finalComposer.addPass(fxaaPass);

  ShaderPass finalPass = new ShaderPass(new ShaderProgram.fromThreeish(AdditiveShader));
  finalPass.uniforms['tAdd'].value = oclcomposer.readTarget;
  finalPass.renderToScreen = true;
  finalComposer.addPass(finalPass);

  /*
  dat.GUI gui = new dat.GUI();
  gui.add(effectController, "vblur", 1.0, 10.0).onChange(matChanger);
  gui.add(effectController, "hblur", 1.0, 10.0).onChange(matChanger);
  gui.addColor(effectController, 'color').onChange(matChanger);
  gui.close();
   */

  stats = new Stats();
  document.body.append(stats.container);

  window.onResize.listen(onWindowResize);
  document.onMouseMove.listen(onDocumentMouseMove);
}

/*
var effectController = {
  'vblur': BLURINESS,
  'hblur': BLURINESS,
  'color': COLOR11
};

void matChanger(var value) {
  vblur.uniforms['v'].value =
      effectController['vblur'] * 2.0 / window.innerHeight;
  hblur.uniforms['h'].value =
      effectController['hblur'] * 2.0 / window.innerWidth;
  vlight.material.color.setHex(effectController['color']);
  vlight.material.needsUpdate = true;
}
 */

void onDocumentMouseMove(MouseEvent event) {
  mouseX = event.client.x - window.innerWidth.toDouble();
  mouseY = event.client.y - window.innerHeight.toDouble();
}

void onWindowResize(Event event) {
  int winWidth = window.innerWidth;
  int winHeight = window.innerHeight;

  camera.aspect = winWidth / winHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(winWidth, winHeight);
}

void createScene(Geometry geometry) {
  double x = 0.0,
      y = -15.0,
      z = 0.0,
      b = 0.0;

  MeshBasicMaterial zmat = new MeshBasicMaterial();
  Mesh zmesh = new Mesh(geometry, zmat)
      ..position.setValues(x, y, z)
      ..scale.setValues(3.0, 3.0, 3.0);
  scene.add(zmesh);

  MeshBasicMaterial gmat = new MeshBasicMaterial(color: 0x000000);
  Mesh gmesh = new Mesh(geometry, gmat)
      ..position.setValues(x, y / 2, z)
      ..rotation = zmesh.rotation
      ..scale.setValues(1.5, 1.5, 1.5);
  oclscene.add(gmesh);

  // extra fancy
  Mesh m = new Mesh(geometry, zmat);
  m.position.setValues(0.0, 50.0 + y, 0.0);
  m.scale = zmesh.scale;
  scene.add(m);

  m = new Mesh(geometry, zmat);
  m.position.setValues(0.0, -50.0 + y, 0.0);
  m.scale = zmesh.scale;
  scene.add(m);

  m = new Mesh(geometry, gmat);
  m.position.setValues(0.0, 50.0 + y, 0.0);
  m.scale = zmesh.scale;
  oclscene.add(m);

  m = new Mesh(geometry, gmat);
  m.position.setValues(0.0, -50.0 + y, 0.0);
  m.scale = zmesh.scale;
  oclscene.add(m);
}

double t = 0.0;
double oldTime = 0.0;
render(double time) {
  t += 0.1;

  double delta = time - oldTime;

  //camera.position.x += (mouseX / 2 - camera.position.x) * 0.05;
  //camera.position.y += (mouseY / 2 - camera.position.y) * 0.05;

  pointLight.position.setValues(0.0, cos(t / 10) * 65.0, 0.0);
  vlight.updateMatrixWorld();


  oclcomposer.render(delta);
  finalComposer.render(delta);
  oldTime = time;
}

void animate(double time) {
  stats.begin();
  render(time);
  stats.end();
  window.requestAnimationFrame(animate);
}


<|start_filename|>lib/src/materials/particle_basic_material.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 *
 * parameters = {
 *  color: <hex>,
 *  opacity: <float>,
 *  map: new THREE.Texture( <Image> ),
 *
 *  size: <float>,
 *
 *  blending: THREE.NormalBlending,
 *  depthTest: <bool>,
 *
 *  vertexColors: false / THREE.NoColors  / THREE.VertexColors / THREE.FaceColors,
 *
 *  fog: <bool>
 * }
 */

class ParticleBasicMaterial extends Material implements TextureMapping {

  var map;
  num size;
  bool sizeAttenuation;

  ParticleBasicMaterial({ // ParticleBasicMaterial

  this.map, num color: 0xffffff, this.size: 1, this.sizeAttenuation: true, int vertexColors: NoColors, bool fog: true,
      // Material
  name: '', side: FrontSide, opacity: 1, transparent: false, blending: NormalBlending, blendSrc: SrcAlphaFactor,
      blendDst: OneMinusSrcAlphaFactor, blendEquation: AddEquation, depthTest: true, depthWrite: true, polygonOffset: false,
      polygonOffsetFactor: 0, polygonOffsetUnits: 0, alphaTest: 0, overdraw: false, visible: true})
      : super(
          name: name,
          side: side,
          opacity: opacity,
          transparent: transparent,
          blending: blending,
          blendSrc: blendSrc,
          blendDst: blendDst,
          blendEquation: blendEquation,
          depthTest: depthTest,
          depthWrite: depthWrite,
          polygonOffset: polygonOffset,
          polygonOffsetFactor: polygonOffsetFactor,
          polygonOffsetUnits: polygonOffsetUnits,
          alphaTest: alphaTest,
          overdraw: overdraw,
          visible: visible,
          color: color,
          fog: fog,
          vertexColors: vertexColors);

}







<|start_filename|>lib/src/textures/data_texture.dart<|end_filename|>
part of three;

class DataTexture extends Texture {

  DataTexture._internal(image, data, width, height, format, [type, mapping, wrapS, wrapT, magFilter, minFilter])
      : super(image, mapping, wrapS, wrapT, magFilter, minFilter, format, type);

  factory DataTexture(data, width, height, format, {type, mapping, wrapS, wrapT, magFilter, minFilter}) {
    return new DataTexture._internal({
      "data": data,
      "width": width,
      "height": height
    }, data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter);
  }

}


<|start_filename|>lib/extras/shaders/convolution_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Convolution shader
 * ported from o3d sample to WebGL / GLSL
 * http://o3d.googlecode.com/svn/trunk/samples/convolution.html
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var ConvolutionShader = {

  'defines': {

    "KERNEL_SIZE_FLOAT": "25.0",
    "KERNEL_SIZE_INT": "25",

  },

  'uniforms': {

    "tDiffuse":        { 'type': "t", 'value': null },
    "uImageIncrement": { 'type': "v2", 'value': new Vector2.array([0.001953125, 0.0]) },
    "cKernel":         { 'type': "fv1", 'value': [] }

  },

  'vertexShader': [

    "uniform vec2 uImageIncrement;",

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv - ( ( KERNEL_SIZE_FLOAT - 1.0 ) / 2.0 ) * uImageIncrement;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform float cKernel[ KERNEL_SIZE_INT ];",

    "uniform sampler2D tDiffuse;",
    "uniform vec2 uImageIncrement;",

    "varying vec2 vUv;",

    "void main() {",

      "vec2 imageCoord = vUv;",
      "vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );",

      "for( int i = 0; i < KERNEL_SIZE_INT; i ++ ) {",

        "sum += texture2D( tDiffuse, imageCoord ) * cKernel[ i ];",
        "imageCoord += uImageIncrement;",

      "}",

      "gl_FragColor = sum;",

    "}"


  ].join("\n"),

  'buildKernel': ( double sigma ) {

    // We lop off the sqrt(2 * pi) * sigma term, since we're going to normalize anyway.

    double gauss( x, sigma ) {

      return exp( - ( x * x ) / ( 2.0 * sigma * sigma ) );

    }

    var i;
    var values;
    var sum;
    var halfWidth;
    var kMaxKernelSize = 25;
    int kernelSize = 2 * (sigma * 3.0).ceil() + 1;

    if ( kernelSize > kMaxKernelSize ) kernelSize = kMaxKernelSize;
    halfWidth = ( kernelSize - 1 ) * 0.5;

    values = new List( kernelSize );
    sum = 0.0;
    for ( i = 0; i < kernelSize; ++i ) {

      values[ i ] = gauss( i - halfWidth, sigma );
      sum += values[ i ];

    }

    // normalize the kernel

    for ( i = 0; i < kernelSize; ++i ) values[ i ] /= sum;

    return values;

  }

};


<|start_filename|>lib/src/core/ray.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

/// A ray that emits from an origin in a certain direction.
class Ray {
  /// The origin of the Ray.
  Vector3 origin;
  /// The direction of the Ray. This must be normalized (with Vector3.normalize)
  /// for the methods to operate properly.
  Vector3 direction;

  num near, far;

  final num precision;

  Ray([this.origin, this.direction, this.near = 0, this.far = double.INFINITY])
      : precision = 0.0001 {

    if (this.origin == null) this.origin = new Vector3.zero();
    if (this.direction == null) this.direction = new Vector3.zero();

  }

  double _distanceFromIntersection(Vector3 origin, Vector3 direction, Vector3 position) {
    Vector3 v0 = position - origin;
    double dot = v0.dot(direction);

    Vector3 intersect = origin + direction.scaled(dot);
    double distance = position.absoluteError(intersect);

    return distance;
  }

  //http://www.blackpawn.com/texts/pointinpoly/default.html
  bool _pointInFace3(Vector3 p, Vector3 a, Vector3 b, Vector3 c) {
    num dot00, dot01, dot02, dot11, dot12, invDenom, u, v;

    Vector3 v0 = c - a;
    Vector3 v1 = b - a;
    Vector3 v2 = p - a;

    dot00 = v0.dot(v0);
    dot01 = v0.dot(v1);
    dot02 = v0.dot(v2);
    dot11 = v1.dot(v1);
    dot12 = v1.dot(v2);

    invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
    u = (dot11 * dot02 - dot01 * dot12) * invDenom;
    v = (dot00 * dot12 - dot01 * dot02) * invDenom;

    return (u >= 0) && (v >= 0) && (u + v < 1);
  }

  List<Intersect> intersectObject(Object3D object, {bool recursive: false}) {
    List<Vector3> abcd = new List.generate(4, (_) => new Vector3.zero());

    Vector3 originCopy = new Vector3.zero();
    Vector3 directionCopy = new Vector3.zero();

    Vector3 vector = new Vector3.zero();
    Vector3 normal = new Vector3.zero();
    Vector3 intersectPoint = new Vector3.zero();

    Intersect intersect;
    List intersects = [];
    int l = object.children.length;

    if (recursive) {
      object.children.forEach((child) {
        intersects.addAll(intersectObject(child));
      });
    }

    if (object is Particle) {
      num distance = _distanceFromIntersection(origin, direction, object.matrixWorld.getTranslation());

      if (distance > object.scale.x) {
        return [];
      }

      intersect = new Intersect(distance: distance, point: object.position, face: null, object: object);


      intersects.add(intersect);

    } else if (object is Mesh) {
      Mesh mesh = object;
      // Checking boundingSphere
      num distance = _distanceFromIntersection(origin, direction, object.matrixWorld.getTranslation());
      Vector3 scale = Frustum.__v1.setValues(
          object.matrixWorld.getColumn(0).length,
          object.matrixWorld.getColumn(1).length,
          object.matrixWorld.getColumn(2).length);

      if (distance > mesh.geometry.boundingSphere.radius * Math.max(scale.x, Math.max(scale.y, scale.z))) {
        return intersects;
      }

      // Checking faces

      int f;

      Face face;
      num dot, scalar;
      Geometry geometry = mesh.geometry;
      List vertices = geometry.vertices;
      Matrix4 objMatrix;
      Material material;

      List<Material> geometryMaterials = object.geometry.materials;
      bool isFaceMaterial = object.material is MeshFaceMaterial;
      int side = object.material.side;


      extractRotation(object.matrixRotationWorld, object.matrixWorld);

      int fl = geometry.faces.length;

      for (var f = 0; f < fl; f++) {

        face = geometry.faces[f];

        material = isFaceMaterial == true ? geometryMaterials[face.materialIndex] : object.material;
        if (material == null) continue;

        side = material.side;

        originCopy.setFrom(origin);
        directionCopy.setFrom(direction);

        objMatrix = object.matrixWorld;

        // determine if ray intersects the plane of the face
        // note: this works regardless of the direction of the face normal

        vector.setFrom(face.centroid);
        vector.applyProjection(objMatrix).sub(originCopy);
        normal.setFrom(face.normal);
        normal.applyProjection(object.matrixRotationWorld);
        dot = directionCopy.dot(normal);

        // bail if ray and plane are parallel
        if (dot.abs() < 0.0001) continue;

        // calc distance to plane

        scalar = normal.dot(vector) / dot;

        // if negative distance, then plane is behind ray

        if (scalar < 0) continue;

        if (side == DoubleSide || (side == FrontSide ? dot < 0 : dot > 0)) {

          intersectPoint = originCopy + directionCopy.scale(scalar);

          abcd = face.indices.map((idx) => vertices[idx].clone().applyProjection(objMatrix)).toList();

          var pointInFace;

          // TODO - Make this work a face of arbitrary size
          if (face.size == 3) {

            pointInFace = _pointInFace3(intersectPoint, abcd[0], abcd[1], abcd[2]);

          } else if (face.size == 4) {

            pointInFace =
                _pointInFace3(intersectPoint, abcd[0], abcd[1], abcd[3]) || _pointInFace3(intersectPoint, abcd[1], abcd[2], abcd[3]);

          }

          if (pointInFace) {
            intersect = new Intersect(
                distance: originCopy.absoluteError(intersectPoint),
                point: intersectPoint.clone(),
                face: face,
                object: object);

            intersects.add(intersect);
          }
        }
      }
    }

    return intersects;
  }

  List<Intersect> intersectObjects(List<Object3D> objects) {
    int l = objects.length;
    List<Intersect> intersects = [];

    objects.forEach((o) => intersects.addAll(intersectObject(o)));

    intersects.sort((a, b) => a.distance.compareTo(b.distance));

    return intersects;
  }

}

class Intersect {
  num distance;
  Vector3 point;
  Face face;
  Object3D object;

  Intersect({this.distance, this.point, this.face, this.object});
}


<|start_filename|>lib/src/lights/directional_light.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * Ported to Dart from JS by:
 * @author rob silverton / http://www.unwrong.com/
 * @author <NAME>
 *
 * rev: r56
 */

/// Affects objects using MeshLambertMaterial or MeshPhongMaterial.
class DirectionalLight extends ShadowCaster {

  Vector3 position;
  /// Target used for shadow camera orientation.
  Object3D target;
  /// Light's intensity (default: 1.0)
  double intensity;
  num distance;

  /// Orthographic shadow camera frustum parameter (default: -500)
  num shadowCameraLeft;
  /// Orthographic shadow camera frustum parameter (default: 500)
  num shadowCameraRight;
  /// Orthographic shadow camera frustum parameter (default: 500)
  num shadowCameraTop;
  /// Orthographic shadow camera frustum parameter (default: -500)
  num shadowCameraBottom;

  bool shadowCascade;

  Vector3 shadowCascadeOffset;
  num shadowCascadeCount;

  List<num> shadowCascadeBias, shadowCascadeWidth, shadowCascadeHeight, shadowCascadeNearZ, shadowCascadeFarZ,
      shadowCascadeArray;

  /// Creates a light that shines from a specific direction not from a specific position.
  ///
  /// This light will behave as though it is infinitely far away and the rays
  /// produced from it are all parallel.
  /// The best analogy would be a light source that acts like the sun: the sun
  /// is so far away that all sunlight hitting objects comes from the same angle.
  DirectionalLight(num hex, [this.intensity = 1.0, this.distance = 0]) : super(hex) {

    position = new Vector3(0.0, 1.0, 0.0);
    target = new Object3D();

    shadowCameraLeft = -500;
    shadowCameraRight = 500;
    shadowCameraTop = 500;
    shadowCameraBottom = -500;

    //

    shadowCascade = false;

    shadowCascadeOffset = new Vector3(0.0, 0.0, -1000.0);
    shadowCascadeCount = 2;

    shadowCascadeBias = [0, 0, 0];
    shadowCascadeWidth = [512, 512, 512];
    shadowCascadeHeight = [512, 512, 512];

    shadowCascadeNearZ = [-1.000, 0.990, 0.998];
    shadowCascadeFarZ = [0.990, 0.998, 1.000];

    shadowCascadeArray = [];

  }
}


<|start_filename|>lib/extras/shaders/bleach_bypass_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Bleach bypass shader [http://en.wikipedia.org/wiki/Bleach_bypass]
 * - based on Nvidia example
 * http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html#post_bleach_bypass
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var BleachBypassShader = {

  'uniforms': {

    "tDiffuse": { 'type': "t", 'value': null },
    "opacity":  { 'type': "f", 'value': 1.0 }

  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform float opacity;",

    "uniform sampler2D tDiffuse;",

    "varying vec2 vUv;",

    "void main() {",

      "vec4 base = texture2D( tDiffuse, vUv );",

      "vec3 lumCoeff = vec3( 0.25, 0.65, 0.1 );",
      "float lum = dot( lumCoeff, base.rgb );",
      "vec3 blend = vec3( lum );",

      "float L = min( 1.0, max( 0.0, 10.0 * ( lum - 0.45 ) ) );",

      "vec3 result1 = 2.0 * base.rgb * blend;",
      "vec3 result2 = 1.0 - 2.0 * ( 1.0 - blend ) * ( 1.0 - base.rgb );",

      "vec3 newColor = mix( result1, result2, L );",

      "float A2 = opacity * base.a;",
      "vec3 mixRGB = A2 * newColor.rgb;",
      "mixRGB += ( ( 1.0 - A2 ) * base.rgb );",

      "gl_FragColor = vec4( mixRGB, base.a );",

    "}"

  ].join("\n")

};


<|start_filename|>lib/extras/shaders/unpack_depth_rgba_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Unpack RGBA depth shader
 * - show RGBA encoded depth as monochrome color
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var UnpackDepthRGBAShader = {

  'uniforms': {

    "tDiffuse": { 'type': "t", 'value': null },
    "opacity":  { 'type': "f", 'value': 1.0 }

  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform float opacity;",

    "uniform sampler2D tDiffuse;",

    "varying vec2 vUv;",

    // RGBA depth

    "float unpackDepth( const in vec4 rgba_depth ) {",

      "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
      "float depth = dot( rgba_depth, bit_shift );",
      "return depth;",

    "}",

    "void main() {",

      "float depth = 1.0 - unpackDepth( texture2D( tDiffuse, vUv ) );",
      "gl_FragColor = opacity * vec4( vec3( depth ), 1.0 );",

    "}"

  ].join("\n")

};


<|start_filename|>lib/extras/core/cubic_bezier_curve.dart<|end_filename|>
part of three;

class CubicBezierCurve extends Curve2D {
  Vector2 v0, v1, v2, v3;

  CubicBezierCurve(this.v0, this.v1, this.v2, this.v3) : super();

  getPoint(t) {

    var tx, ty;

    tx = ShapeUtils.b3(t, v0.x, v1.x, v2.x, v3.x);
    ty = ShapeUtils.b3(t, v0.y, v1.y, v2.y, v3.y);

    return new Vector2(tx, ty);

  }

  getTangent(t) {

    var tx, ty;

    tx = CurveUtils.tangentCubicBezier(t, v0.x, v1.x, v2.x, v3.x);
    ty = CurveUtils.tangentCubicBezier(t, v0.y, v1.y, v2.y, v3.y);

    return new Vector2(tx, ty).normalize();

  }
}


<|start_filename|>lib/extras/postprocessing/effect_composer.dart<|end_filename|>
part of three_postprocessing;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

class EffectComposer {

  WebGLRenderer renderer;
  WebGLRenderTarget readTarget;
  WebGLRenderTarget writeTarget;
  ShaderPass copyPass;
  List<Pass> passes = new List<Pass>();
  bool maskActive = false;

  EffectComposer(this.renderer, [WebGLRenderTarget target = null]) {
    this.renderer.autoClear = false;

    if (target == null) {
      target = new WebGLRenderTarget(
          window.innerWidth,
          window.innerHeight,
          minFilter: LinearFilter,
          magFilter: LinearFilter,
          format: RGBFormat,
          stencilBuffer: false);
    }
    writeTarget = target;
    readTarget = target.clone();
    copyPass = new ShaderPass(new ShaderProgram.fromThreeish(CopyShader));
  }

  void swapBuffers() {
    var tmp = readTarget;
    readTarget = writeTarget;
    writeTarget = tmp;
  }

  void addPass(pass) => passes.add(pass);

  void insertPass(pass, index) => passes.insert(index, pass);

  void render(double delta) {

    maskActive = false;

    passes.forEach((Pass pass) {
      if (!pass.enabled) return;

      pass.render(renderer, writeTarget, readTarget, delta, maskActive);

      if (pass.needsSwap) {

        if (maskActive) {
          var context = renderer.context;

          context.stencilFunc(context.NOTEQUAL, 1, 0xffffffff);
          copyPass.render(renderer, writeTarget, readTarget, delta, maskActive);
          context.stencilFunc(context.EQUAL, 1, 0xffffffff);
        }

        swapBuffers();
      }

      /*
      if (pass is MaskPass) {
        maskActive = true;
      } else if (pass is ClearMaskPass) {
        maskActive = false;
      }
       */
    });
  }

  void reset([WebGLRenderTarget target = null, int width, int height]) {

    if (width == null) {
      width = window.innerWidth;
    }
    if (height == null) {
      height = window.innerHeight;
    }
    if (target == null) {
      target = new WebGLRenderTarget(
          width,
          height,
          minFilter: LinearFilter,
          magFilter: LinearFilter,
          format: RGBFormat,
          stencilBuffer: false);
    }
    writeTarget = target;
    readTarget = target.clone();
  }
}


<|start_filename|>lib/src/loaders/json_loader.dart<|end_filename|>
part of three;

/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.inevo.pt/
 *
 * based on r51
 */
class JSONLoader extends Loader {

  JSONLoader({bool showStatus: false}) : super(showStatus);

  load(url, LoadedCallback callback, {texturePath: null}) {

    if (texturePath == null) {
      texturePath = Loader._extractUrlBase(url);
    }

    onLoadStart();

    _loadAjaxJSON(url, callback, texturePath);
  }

  _loadAjaxJSON(String url, LoadedCallback callback, String texturePath, {LoadProgressCallback callbackProgress:
      null}) {

    HttpRequest xhr = new HttpRequest();

    var length = 0;

    xhr.onReadyStateChange.listen((Event e) {

      if (xhr.readyState == HttpRequest.DONE) {

        if (xhr.status == 200 || xhr.status == 0) {

          if (!xhr.responseText.isEmpty) {

            var json = JSON.decode(xhr.responseText);
            _createModel(json, callback, texturePath);

          } else {

            print("THREE.JSONLoader: [$url] seems to be unreachable or file there is empty");

          }

          // in context of more complex asset initialization
          // do not block on single failed file
          // maybe should go even one more level up

          onLoadComplete();

        } else {

          print("THREE.JSONLoader: Couldn't load [$url] [${xhr.status}]");

        }

      } else if (xhr.readyState == HttpRequest.LOADING) {

        if (callbackProgress != null) {

          if (length == 0) {

            length = xhr.getResponseHeader("Content-Length");

          }

          callbackProgress({
            "total": length,
            "loaded": xhr.responseText.length
          });

        }

      } else if (xhr.readyState == HttpRequest.HEADERS_RECEIVED) {

        length = xhr.getResponseHeader("Content-Length");

      }

    });

    xhr.open("GET", url);
    xhr.send(null);

  }

  bool _isBitSet(value, position) => (value & (1 << position)) > 0;

  _createModel(Map json, LoadedCallback callback, String texturePath) {

    var geometry = new Geometry(),
        scale = (json.containsKey("scale")) ? 1.0 / json["scale"] : 1.0;

    _initMaterials(geometry, json["materials"], texturePath);

    _parseModel(json, geometry, scale);

    _parseSkin(json, geometry);
    _parseMorphing(json, geometry, scale);

    geometry.computeCentroids();
    geometry.computeFaceNormals();

    if (_hasNormals(geometry)) geometry.computeTangents();

    callback(geometry);
  }

  _parseModel(Map json, Geometry geometry, num scale) {

    var i,
        j,
        fi,

        offset,
        zLength,
        nVertices,

        colorIndex,
        normalIndex,
        uvIndex,
        materialIndex,

        type,
        isQuad,
        hasMaterial,
        hasFaceUv,
        hasFaceVertexUv,
        hasFaceNormal,
        hasFaceVertexNormal,
        hasFaceColor,
        hasFaceVertexColor,

        vertex,
        face,
        color,
        normal,

        uvLayer,
        uvs,
        u,
        v,

        faces = json["faces"],
        vertices = json["vertices"],
        normals = json["normals"],
        colors = json["colors"],

        nUvLayers = 0;

    // disregard empty arrays

    for (i = 0; i < json["uvs"].length; i++) {

      if (!json["uvs"][i].isEmpty) nUvLayers++;

    }

    geometry.faceUvs = new List(nUvLayers);
    geometry.faceVertexUvs = new List(nUvLayers);

    for (i = 0; i < nUvLayers; i++) {

      geometry.faceUvs[i] = new List(faces.length);
      geometry.faceVertexUvs[i] = new List(faces.length);

    }

    offset = 0;
    zLength = vertices.length;

    while (offset < zLength) {

      vertex = new Vector3.zero();

      vertex.x = vertices[offset++] * scale;
      vertex.y = vertices[offset++] * scale;
      vertex.z = vertices[offset++] * scale;

      geometry.vertices.add(vertex);

    }

    offset = 0;
    zLength = faces.length;

    while (offset < zLength) {

      type = faces[offset++];


      isQuad = _isBitSet(type, 0);
      hasMaterial = _isBitSet(type, 1);
      hasFaceUv = _isBitSet(type, 2);
      hasFaceVertexUv = _isBitSet(type, 3);
      hasFaceNormal = _isBitSet(type, 4);
      hasFaceVertexNormal = _isBitSet(type, 5);
      hasFaceColor = _isBitSet(type, 6);
      hasFaceVertexColor = _isBitSet(type, 7);

      if (isQuad) {

        face = new Face4();

        face.a = faces[offset++];
        face.b = faces[offset++];
        face.c = faces[offset++];
        face.d = faces[offset++];

        nVertices = 4;

      } else {

        face = new Face3();

        face.a = faces[offset++];
        face.b = faces[offset++];
        face.c = faces[offset++];

        nVertices = 3;

      }

      if (hasMaterial) {

        materialIndex = faces[offset++];
        face.materialIndex = materialIndex;

      }

      // to get face <=> uv index correspondence

      fi = geometry.faces.length;

      if (hasFaceUv) {

        for (i = 0; i < nUvLayers; i++) {

          uvLayer = json["uvs"][i];

          uvIndex = faces[offset++];

          u = uvLayer[uvIndex * 2];
          v = uvLayer[uvIndex * 2 + 1];

          geometry.faceUvs[i][fi] = new UV(u.toDouble(), v.toDouble());

        }

      }

      if (hasFaceVertexUv) {

        for (i = 0; i < nUvLayers; i++) {

          uvLayer = json["uvs"][i];

          uvs = new List(nVertices);

          for (j = 0; j < nVertices; j++) {

            uvIndex = faces[offset++];

            u = uvLayer[uvIndex * 2];
            v = uvLayer[uvIndex * 2 + 1];

            uvs[j] = new UV(u.toDouble(), v.toDouble());

          }

          geometry.faceVertexUvs[i][fi] = uvs;

        }

      }

      if (hasFaceNormal) {

        normalIndex = faces[offset++] * 3;

        normal = new Vector3.zero();

        normal.x = normals[normalIndex++].toDouble();
        normal.y = normals[normalIndex++].toDouble();
        normal.z = normals[normalIndex].toDouble();

        face.normal = normal;

      }

      if (hasFaceVertexNormal) {

        for (i = 0; i < nVertices; i++) {

          normalIndex = faces[offset++] * 3;

          normal = new Vector3.zero();

          normal.x = normals[normalIndex++].toDouble();
          normal.y = normals[normalIndex++].toDouble();
          normal.z = normals[normalIndex].toDouble();

          face.vertexNormals.add(normal);

        }

      }


      if (hasFaceColor) {

        colorIndex = faces[offset++];

        color = new Color(colors[colorIndex]);
        face.color = color;

      }


      if (hasFaceVertexColor) {

        for (i = 0; i < nVertices; i++) {

          colorIndex = faces[offset++];

          color = new Color(colors[colorIndex]);
          face.vertexColors.add(color);

        }

      }

      geometry.faces.add(face);

    }

  }

  _parseSkin(Map json, Geometry geometry) {

    var i, l, x, y, z, w, a, b, c, d;

    if (json.containsKey("skinWeights")) {

      l = json["skinWeights"].length;
      for (i = 0; i < l; i += 2) {

        x = json["skinWeights"][i];
        y = json["skinWeights"][i + 1];
        z = 0.0;
        w = 0.0;

        geometry.skinWeights.add(new Vector4(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()));

      }

    }

    if (json.containsKey("skinIndices")) {

      l = json["skinIndices"].length;
      for (i = 0; i < l; i += 2) {

        a = json["skinIndices"][i];
        b = json["skinIndices"][i + 1];
        c = 0.0;
        d = 0.0;

        geometry.skinIndices.add(new Vector4(a.toDouble(), b.toDouble(), c.toDouble(), d.toDouble()));

      }

    }

    geometry.bones = json["bones"];
    geometry.animation = json["animation"];

  }

  _parseMorphing(Map json, Geometry geometry, num scale) {

    if (json.containsKey("morphTargets")) {

      var i, l, v, vl, dstVertices, srcVertices;

      geometry.morphTargets = new List(json["morphTargets"].length);

      for (i = 0; i < geometry.morphTargets.length; i++) {

        geometry.morphTargets[i] = new MorphTarget(name: json["morphTargets"][i]["name"], vertices: []);

        dstVertices = geometry.morphTargets[i].vertices;
        srcVertices = json["morphTargets"][i]["vertices"];

        vl = srcVertices.length;
        for (v = 0; v < vl; v += 3) {

          var vertex = new Vector3.zero();
          vertex.x = srcVertices[v] * scale;
          vertex.y = srcVertices[v + 1] * scale;
          vertex.z = srcVertices[v + 2] * scale;

          dstVertices.add(vertex);

        }

      }

    }

    if (json.containsKey("morphColors")) {

      var i, l, c, cl, dstColors, srcColors, color;

      geometry.morphColors = new List(json["morphColors"].length);

      for (i = 0; i < geometry.morphColors.length; i++) {

        dstColors = [];
        srcColors = json["morphColors"][i]["colors"];

        cl = srcColors.length;
        for (c = 0; c < cl; c += 3) {

          color = new Color(0xffaa00);
          color.setRGB(srcColors[c], srcColors[c + 1], srcColors[c + 2]);
          dstColors.add(color);

        }

        geometry.morphColors[i] = new MorphColors(name: json["morphColors"][i]["name"], colors: dstColors);
      }
    }
  }

}


<|start_filename|>lib/extras/postprocessing/bokeh_pass.dart<|end_filename|>
part of three_postprocessing;
/**
 * Depth-of-field post-process with bokeh shader
 *
 *  * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
  */

class BokehPass implements Pass {
  WebGLRenderTarget renderTargetColor, renderTargetDepth;
  Scene scene1, scene2;
  PerspectiveCamera camera1;
  OrthographicCamera camera2;
  ShaderProgram program;
  Map<String, Uniform> uniforms;
  MeshDepthMaterial materialDepth;
  ShaderMaterial materialBokeh;
  Mesh quad;
  bool enabled = true;
  bool needsSwap = false;
  bool renderToScreen = false;
  bool clear = false;

  BokehPass(this.scene1, this.camera1, {double focus: 1.0, double aspect, double aperture: 0.025, double maxblur: 1.0,
      int width, int height}) {

    if (width == null) {
      width = window.innerWidth;
    }
    if (height == null) {
      height = window.innerHeight;
    }

    if (aspect == null) aspect = camera1.aspect;
    renderTargetColor =
        new WebGLRenderTarget(width, height, minFilter: LinearFilter, magFilter: LinearFilter, format: RGBFormat);

    renderTargetDepth = renderTargetColor.clone();
    materialDepth = new MeshDepthMaterial();

    program = new ShaderProgram.fromThreeish(BokehShader);
    uniforms = program.uniforms;
    uniforms['tDepth'].value = renderTargetDepth;
    uniforms['focus'].value = focus;
    uniforms['aspect'].value = aspect;
    uniforms['aperture'].value = aperture;
    uniforms['maxblur'].value = maxblur;

    materialBokeh =
        new ShaderMaterial(uniforms: uniforms, vertexShader: program.vertexShader, fragmentShader: program.fragmentShader);

    scene2 = new Scene();
    camera2 = new OrthographicCamera(-1.0, 1.0, 1.0, -1.0, 0.0, 1.0);
    scene2.add(camera2);
    quad = new Mesh(new PlaneGeometry(2.0, 2.0), materialBokeh);
    scene2.add(quad);
  }

  void render(WebGLRenderer renderer, WebGLRenderTarget writeBuffer, WebGLRenderTarget readBuffer, double delta,
      bool maskActive) {

    quad.material = materialBokeh;
    scene1.overrideMaterial = materialDepth;

    renderer.renderToTarget(scene1, camera1, renderTargetDepth, true);

    uniforms['tColor'].value = readBuffer;

    if (renderToScreen) {
      renderer.render(scene2, camera2);
    } else {
      renderer.renderToTarget(scene2, camera2, writeBuffer, clear);
    }

    scene1.overrideMaterial = null;
  }
}


<|start_filename|>lib/extras/shaders/luminosity_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Luminosity
 * http://en.wikipedia.org/wiki/Luminosity
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var LuminosityShader = {

  'uniforms': {

    "tDiffuse": { 'type': "t", 'value': null }

  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",

      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform sampler2D tDiffuse;",

    "varying vec2 vUv;",

    "void main() {",

      "vec4 texel = texture2D( tDiffuse, vUv );",

      "vec3 luma = vec3( 0.299, 0.587, 0.114 );",

      "float v = dot( texel.xyz, luma );",

      "gl_FragColor = vec4( v, v, v, texel.w );",

    "}"

  ].join("\n")

};


<|start_filename|>example/css3d_periodic_table/css3d_periodic_table.dart<|end_filename|>
library periodic_table;

import 'dart:html';
import 'dart:math' as Math;

import 'package:vector_math/vector_math.dart';
import 'package:three/three.dart' as THREE;
import 'package:three/extras/renderers/css3d_renderer.dart' as THREE;
import 'package:three/extras/controls/trackball_controls.dart';
import 'package:three/extras/tween.dart' as TWEEN;

part 'periodic_table.dart';

var camera, scene, renderer;
var geometry, material, mesh;

var controls;

var objects = [];

init() {

  var targets = {
    "table": [],
    "sphere": [],
    "helix": [],
    "grid": []
  };

  camera = new THREE.PerspectiveCamera(75.0, window.innerWidth / window.innerHeight, 1.0, 5000.0);
  camera.position.z = 1800.0;

  scene = new THREE.Scene();

  for (int i = 0; i < table.length; i++) {

    var item = table[i];

    var number = new Element.tag('div')
        ..text = (i + 1).toString()
        ..classes.add('number');

    var symbol = new Element.tag('div')
        ..text = item[0]
        ..classes.add('symbol');

    var details = new Element.tag('div')
        ..classes.add('details')
        ..innerHtml = '${item[ 1 ]}<br>${item[ 2 ]}';

    var element = new Element.tag('div')
        ..classes.add('element')
        ..style.backgroundColor = 'rgba(0,127,127,${( new Math.Random().nextDouble() * 0.5 + 0.25 ) })'
        ..children.add(number)
        ..children.add(symbol)
        ..children.add(details);

    var object = new THREE.CSS3DObject(element)
        ..position.x = new Math.Random().nextDouble() * 4000 - 2000.0
        ..position.y = new Math.Random().nextDouble() * 4000 - 2000.0
        ..position.z = new Math.Random().nextDouble() * 4000 - 2000.0;

    scene.add(object);

    objects.add(object);

  }

  // table

  for (int i = 0; i < objects.length; i++) {

    var item = table[i];
    var object = objects[i];

    targets["table"].add(new THREE.Object3D()
        ..position.x = (item[3] * 160.0) - 1540.0
        ..position.y = -(item[4] * 200.0) + 1100.0);

  }

  // sphere

  var vector = new Vector3.zero();

  for (int i = 0,
      l = objects.length; i < l; i++) {

    var object = objects[i];

    var phi = Math.acos(-1 + (2 * i) / l);
    var theta = Math.sqrt(l * Math.PI) * phi;

    object = new THREE.Object3D()
        ..position.x = 1000.0 * Math.cos(theta) * Math.sin(phi)
        ..position.y = 1000.0 * Math.sin(theta) * Math.sin(phi)
        ..position.z = 1000.0 * Math.cos(phi);

    vector = object.position.clone().scale(2.0);

    object.lookAt(vector);

    targets["sphere"].add(object);

  }

  // helix

  vector = new Vector3.zero();

  for (int i = 0,
      l = objects.length; i < l; i++) {

    var object = objects[i];

    var phi = i * 0.175 + Math.PI;

    object = new THREE.Object3D()
        ..position.x = 1100.0 * Math.sin(phi)
        ..position.y = -(i * 8.0) + 450.0
        ..position.z = 1100.0 * Math.cos(phi);

    vector.setFrom(object.position);
    vector.x *= 2;
    vector.z *= 2;

    object.lookAt(vector);

    targets["helix"].add(object);

  }

  // grid

  for (int i = 0; i < objects.length; i++) {

    var object = objects[i];

    object = new THREE.Object3D()
        ..position.x = ((i % 5) * 400.0) - 800.0
        ..position.y = (-((i ~/ 5) % 5) * 400.0) + 800.0
        ..position.z = ((i ~/ 25)) * 1000.0 - 2000.0;

    targets["grid"].add(object);

  }

  //

  renderer = new THREE.CSS3DRenderer()
      ..setSize(window.innerWidth, window.innerHeight)
      ..domElement.style.position = 'absolute'
      ..domElement.style.top = "0";
  document.querySelector('#container').children.add(renderer.domElement);

  //

  controls = new TrackballControls(camera, renderer.domElement)
      ..rotateSpeed = 0.5
      ..addEventListener('change', (_) => render());

  document.querySelector('#table').onClick.listen((e) => transform(e.target, targets["table"], 2000));

  document.querySelector('#sphere').onClick.listen((e) => transform(e.target, targets["sphere"], 2000));

  document.querySelector('#helix').onClick.listen((e) => transform(e.target, targets["helix"], 2000));

  document.querySelector('#grid').onClick.listen((e) => transform(e.target, targets["grid"], 2000));

  transform(window, targets["table"], 5000);

  //

  window.onResize.listen(onWindowResize);

}

transform(target, targets, duration) {

  TWEEN.removeAll();

  for (var i = 0; i < objects.length; i++) {

    var object = objects[i];
    var target = targets[i];

    new TWEEN.Tween(object.position)
        ..to({
          "x": target.position.x,
          "y": target.position.y,
          "z": target.position.z
        }, new Math.Random().nextDouble() * duration + duration)
        ..easing = TWEEN.Easing.Exponential.InOut
        ..start();

    new TWEEN.Tween(object.rotation)
        ..to({
          "x": target.rotation.x,
          "y": target.rotation.y,
          "z": target.rotation.z
        }, new Math.Random().nextDouble() * duration + duration)
        ..easing = TWEEN.Easing.Exponential.InOut
        ..start();

  }

  new TWEEN.Tween(target)
      ..to({}, duration * 2)
      ..onUpdate = (object, value) {
        render();
      }
      ..start();
}

onWindowResize(_) {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}

animate(num time) {

  window.requestAnimationFrame(animate);

  TWEEN.update();
  controls.update();

}

render() => renderer.render(scene, camera);

main() {
  init();
  animate(0);
}


<|start_filename|>lib/extras/core/quadratic_bezier_curve3.dart<|end_filename|>
part of three;

class QuadraticBezierCurve3 extends Curve3D {
  Vector3 v0, v1, v2;
  QuadraticBezierCurve3(this.v0, this.v1, this.v2) : super();

  Vector3 getPoint(t) {

    var tx, ty, tz;

    tx = ShapeUtils.b2(t, v0.x, v1.x, v2.x);
    ty = ShapeUtils.b2(t, v0.y, v1.y, v2.y);
    tz = ShapeUtils.b2(t, v0.z, v1.z, v2.z);

    return new Vector3(tx, ty, tz);

  }
}


<|start_filename|>example/web_gl_buffer_geometry/web_gl_buffer_geometry.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:three/three.dart';

const TRIANGLES = 500;

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

Mesh mesh;

void main() {
  init();
  animate(0);
}

void init() {

  container = document.querySelector('#container');

  camera = new PerspectiveCamera(20.0, window.innerWidth / window.innerHeight, 1.0, 10000.0)..position.z = 1800.0;

  scene = new Scene();

  var geometry = new BufferGeometry()
      ..aIndex = new GeometryAttribute.int16(TRIANGLES * 3 * 3)
      ..aPosition = new GeometryAttribute.float32(TRIANGLES * 3 * 3, 3);

  var indices = geometry.aIndex.array;
  var i = 0;
  indices.forEach((_) {
    indices[i] = i++;
  });

  var rnd = new Math.Random();
  var positions = geometry.aPosition.array;

  for (var i = 0; i < positions.length; i += 9) {

    var x = rnd.nextDouble() * 400 - 200;
    var y = rnd.nextDouble() * 400 - 200;
    var z = rnd.nextDouble() * 400 - 200;

    positions[i] = x + rnd.nextDouble() * 40 - 20;
    positions[i + 1] = y + rnd.nextDouble() * 40 - 20;
    positions[i + 2] = z + rnd.nextDouble() * 40 - 20;

    positions[i + 3] = x + rnd.nextDouble() * 40 - 20;
    positions[i + 4] = y + rnd.nextDouble() * 40 - 20;
    positions[i + 5] = z + rnd.nextDouble() * 40 - 20;

    positions[i + 6] = x + rnd.nextDouble() * 40 - 20;
    positions[i + 7] = y + rnd.nextDouble() * 40 - 20;
    positions[i + 8] = z + rnd.nextDouble() * 40 - 20;

  }

  geometry.offsets = [new Chunk(start: 0, count: TRIANGLES * 3, index: 0)];

  geometry.computeBoundingSphere();
  geometry.computeVertexNormals();

  var material = new MeshLambertMaterial(color: 0x000000, side: DoubleSide);

  mesh = new Mesh(geometry, material);
  scene.add(mesh);

  renderer = new WebGLRenderer(antialias: true)..setSize(window.innerWidth, window.innerHeight);

  container.children.add(renderer.domElement);


  window.onResize.listen(onWindowResize);
}

onWindowResize(event) {
  camera
      ..aspect = window.innerWidth / window.innerHeight
      ..updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

render() {

  mesh.rotation
      ..x += 0.01
      ..y += 0.02;

  renderer.render(scene, camera);

}


<|start_filename|>lib/extras/postprocessing/render_pass.dart<|end_filename|>
part of three_postprocessing;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

class RenderPass extends Pass {
  Scene scene;
  Camera camera;
  Material overrideMaterial;
  Color clearColor;
  double clearAlpha;
  Color oldClearColor = new Color();
  double oldClearAlpha = 1.0;
  bool enabled = true;
  bool clear = true;
  bool needsSwap = true;

  RenderPass(this.scene, this.camera, [this.overrideMaterial = null, this.clearColor = null, this.clearAlpha = 1.0]);

  void render(WebGLRenderer renderer, WebGLRenderTarget writeTarget, WebGLRenderTarget readTarget, double delta,
      bool maskActive) {

    scene.overrideMaterial = overrideMaterial;
    if (clearColor != null) {
      oldClearColor.copy(renderer.getClearColor());
      oldClearAlpha = renderer.getClearAlpha();
      renderer.setClearColor(clearColor, clearAlpha);
    }

    renderer.renderToTarget(scene, camera, writeTarget, clear);

    if (clearColor != null) {
      renderer.setClearColor(oldClearColor, oldClearAlpha);
    }

    scene.overrideMaterial = null;
  }
}


<|start_filename|>lib/extras/renderers/plugins/shadow_map_plugin.dart<|end_filename|>
// r54

part of three;

/**
 * @author alteredq / http://alteredqualia.com/
 */

class ShadowMapPlugin {

  static Projector __projector = new Projector();

  Frustum _frustum;
  Matrix4 _projScreenMatrix;
  Vector3 _min, _max;

  gl.RenderingContext _gl;
  WebGLRenderer _renderer;
  Material _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin;

  ShadowMapPlugin()
      : _frustum = new Frustum(),
        _projScreenMatrix = new Matrix4.identity(),
        _min = new Vector3.zero(),
        _max = new Vector3.zero();


  init(WebGLRenderer renderer) {

    _gl = renderer.context;
    _renderer = renderer;

    var depthShader = ShaderLib["depthRGBA"];
    var depthUniforms = UniformsUtils.clone(depthShader["uniforms"]);

    _depthMaterial = new ShaderMaterial(
        fragmentShader: depthShader["fragmentShader"],
        vertexShader: depthShader["vertexShader"],
        uniforms: depthUniforms);
    _depthMaterialMorph = new ShaderMaterial(
        fragmentShader: depthShader["fragmentShader"],
        vertexShader: depthShader["vertexShader"],
        uniforms: depthUniforms,
        morphTargets: true);
    _depthMaterialSkin = new ShaderMaterial(
        fragmentShader: depthShader["fragmentShader"],
        vertexShader: depthShader["vertexShader"],
        uniforms: depthUniforms,
        skinning: true);
    _depthMaterialMorphSkin = new ShaderMaterial(
        fragmentShader: depthShader["fragmentShader"],
        vertexShader: depthShader["vertexShader"],
        uniforms: depthUniforms,
        morphTargets: true,
        skinning: true);

    _depthMaterial.shadowPass = true;
    _depthMaterialMorph.shadowPass = true;
    _depthMaterialSkin.shadowPass = true;
    _depthMaterialMorphSkin.shadowPass = true;

  }

  render(Scene scene, Camera camera, [num width, num height]) {

    if (!(_renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate)) return;

    update(scene, camera);

  }

  update(Scene scene, Camera camera) {

    var i,
        il,
        j,
        jl,
        n,

        shadowMap,
        shadowMatrix,
        shadowCamera,
        program,
        buffer,
        material,
        webglObject,
        object,
        light,
        virtualLight,
        renderList,

        lights = [],

        fog = null;

    // set GL state for depth map

    _gl.clearColor(1, 1, 1, 1);
    _gl.disable(gl.BLEND);

    _gl.enable(gl.CULL_FACE);
    _gl.frontFace(gl.CCW);

    if (_renderer.shadowMapCullFrontFaces == CullFaceFront) {

      _gl.cullFace(gl.FRONT);

    } else {

      _gl.cullFace(gl.BACK);

    }

    _renderer.setDepthTest(true);

    // preprocess lights
    //  - skip lights that are not casting shadows
    //  - create virtual lights for cascaded shadow maps
    il = scene.lights.length;
    for (i = 0; i < il; i++) {

      light = scene.lights[i];

      if (!light.castShadow) continue;

      if ((light is DirectionalLight) && light.shadowCascade) {

        for (n = 0; n < light.shadowCascadeCount; n++) {

          if (!light.shadowCascadeArray[n]) {

            virtualLight = createVirtualLight(light, n);
            virtualLight.originalCamera = camera;

            var gyro = new Gyroscope();
            gyro.position = light.shadowCascadeOffset;

            gyro.add(virtualLight);
            gyro.add(virtualLight.target);

            camera.add(gyro);

            light.shadowCascadeArray[n] = virtualLight;

            print("Created virtualLight $virtualLight");

          } else {

            virtualLight = light.shadowCascadeArray[n];

          }

          updateVirtualLight(light, n);

          lights.add(virtualLight);

        }

      } else {

        lights.add(light);

      }

    }

    // render depth map
    il = lights.length;
    for (i = 0; i < il; i++) {

      light = lights[i];

      if (light.shadowMap == null) {

        var shadowFilter = LinearFilter;

        if (_renderer.shadowMapType == PCFSoftShadowMap) {

          shadowFilter = NearestFilter;

        }

        light.shadowMap = new WebGLRenderTarget(
            light.shadowMapWidth,
            light.shadowMapHeight,
            minFilter: shadowFilter,
            magFilter: shadowFilter,
            format: RGBAFormat);
        light.shadowMapSize = new Vector2(light.shadowMapWidth.toDouble(), light.shadowMapHeight.toDouble());

        light.shadowMatrix = new Matrix4.identity();

      }

      if (light.shadowCamera == null) {

        if (light is SpotLight) {

          light.shadowCamera = new PerspectiveCamera(
              light.shadowCameraFov,
              light.shadowMapWidth / light.shadowMapHeight,
              light.shadowCameraNear,
              light.shadowCameraFar);

        } else if (light is DirectionalLight) {

          light.shadowCamera = new OrthographicCamera(
              light.shadowCameraLeft,
              light.shadowCameraRight,
              light.shadowCameraTop,
              light.shadowCameraBottom,
              light.shadowCameraNear,
              light.shadowCameraFar);

        } else {

          print("Unsupported light type for shadow");
          continue;

        }

        scene.add(light.shadowCamera);

        if (_renderer.autoUpdateScene) scene.updateMatrixWorld();

      }

      if (light.shadowCameraVisible && light.cameraHelper == null) {

        light.cameraHelper = new CameraHelper(light.shadowCamera);
        light.shadowCamera.add(light.cameraHelper);

      }

      if (light is VirtualLight && virtualLight.originalCamera == camera) {

        updateShadowCamera(camera, light);

      }

      shadowMap = light.shadowMap;
      shadowMatrix = light.shadowMatrix;
      shadowCamera = light.shadowCamera;

      shadowCamera.position = light.matrixWorld.getTranslation();
      shadowCamera.lookAt(light.target.matrixWorld.getTranslation());
      shadowCamera.updateMatrixWorld();

      shadowCamera.matrixWorldInverse.copyInverse(shadowCamera.matrixWorld);

      if (light.cameraHelper != null) light.cameraHelper.visible = light.shadowCameraVisible;
      if (light.shadowCameraVisible) light.cameraHelper.update();

      // compute shadow matrix

      shadowMatrix.setValues(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);

      shadowMatrix.multiply(shadowCamera.projectionMatrix);
      shadowMatrix.multiply(shadowCamera.matrixWorldInverse);

      // update camera matrices and frustum

      _projScreenMatrix = shadowCamera.projectionMatrix * shadowCamera.matrixWorldInverse;
      _frustum.setFromMatrix(_projScreenMatrix);

      // render shadow map

      _renderer.setRenderTarget(shadowMap);
      _renderer.clear();

      // set object matrices & frustum culling

      renderList = scene.__webglObjects;

      jl = renderList.length;
      for (j = 0; j < jl; j++) {

        webglObject = renderList[j];
        object = webglObject.object;

        webglObject.render = false;

        if (object.visible && object.castShadow) {

          if (!(object is Mesh) || (object is ParticleSystem) || !(object.frustumCulled) || _frustum.contains(object)) {

            object._modelViewMatrix = shadowCamera.matrixWorldInverse * object.matrixWorld;

            webglObject.render = true;

          }

        }

      }

      // render regular objects

      var objectMaterial, useMorphing, useSkinning;

      jl = renderList.length;
      for (j = 0; j < jl; j++) {

        webglObject = renderList[j];

        if (webglObject.render) {

          object = webglObject.object;
          buffer = webglObject.buffer;

          // culling is overriden globally for all objects
          // while rendering depth map

          // need to deal with MeshFaceMaterial somehow
          // in that case just use the first of geometry.materials for now
          // (proper solution would require to break objects by materials
          //  similarly to regular rendering and then set corresponding
          //  depth materials per each chunk instead of just once per object)

          objectMaterial = getObjectMaterial(object);

          useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
          useSkinning = object is SkinnedMesh && objectMaterial.skinning;

          if (object.customDepthMaterial != null) {

            material = object.customDepthMaterial;

          } else if (useSkinning) {

            material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;

          } else if (useMorphing) {

            material = _depthMaterialMorph;

          } else {

            material = _depthMaterial;

          }

          if (buffer is BufferGeometry) {

            _renderer.renderBufferDirect(shadowCamera, scene.lights, fog, material, buffer, object);

          } else {

            _renderer.renderBuffer(shadowCamera, scene.lights, fog, material, buffer, object);

          }

        }

      }

      // set matrices and render immediate objects

      renderList = scene.__webglObjectsImmediate;

      jl = renderList.length;
      for (j = 0; j < jl; j++) {

        webglObject = renderList[j];
        object = webglObject.object;

        if (object.visible && object.castShadow) {

          object._modelViewMatrix.multiply(shadowCamera.matrixWorldInverse);

          _renderer.renderImmediateObject(shadowCamera, scene.lights, fog, _depthMaterial, object);

        }

      }

    }

    // restore GL state

    var clearColor = _renderer._clearColor;
    var clearAlpha = _renderer._clearAlpha;

    _gl.clearColor(clearColor.r, clearColor.g, clearColor.b, clearAlpha);
    _gl.enable(gl.BLEND);

    if (_renderer.shadowMapCullFrontFaces == CullFaceFront) {

      _gl.cullFace(gl.BACK);

    }

  }

  VirtualLight createVirtualLight(DirectionalLight light, int cascade) {

    var virtualLight = new VirtualLight();

    virtualLight.onlyShadow = true;
    virtualLight.castShadow = true;

    virtualLight.shadowCameraNear = light.shadowCameraNear;
    virtualLight.shadowCameraFar = light.shadowCameraFar;

    virtualLight.shadowCameraLeft = light.shadowCameraLeft;
    virtualLight.shadowCameraRight = light.shadowCameraRight;
    virtualLight.shadowCameraBottom = light.shadowCameraBottom;
    virtualLight.shadowCameraTop = light.shadowCameraTop;

    virtualLight.shadowCameraVisible = light.shadowCameraVisible;

    virtualLight.shadowDarkness = light.shadowDarkness;

    virtualLight.shadowBias = light.shadowCascadeBias[cascade];
    virtualLight.shadowMapWidth = light.shadowCascadeWidth[cascade];
    virtualLight.shadowMapHeight = light.shadowCascadeHeight[cascade];

    virtualLight.pointsWorld = [];
    virtualLight.pointsFrustum = [];

    var pointsWorld = virtualLight.pointsWorld,
        pointsFrustum = virtualLight.pointsFrustum;

    for (var i = 0; i < 8; i++) {

      pointsWorld[i] = new Vector3.zero();
      pointsFrustum[i] = new Vector3.zero();

    }

    var nearZ = light.shadowCascadeNearZ[cascade];
    var farZ = light.shadowCascadeFarZ[cascade];

    pointsFrustum[0].set(-1, -1, nearZ);
    pointsFrustum[1].set(1, -1, nearZ);
    pointsFrustum[2].set(-1, 1, nearZ);
    pointsFrustum[3].set(1, 1, nearZ);

    pointsFrustum[4].set(-1, -1, farZ);
    pointsFrustum[5].set(1, -1, farZ);
    pointsFrustum[6].set(-1, 1, farZ);
    pointsFrustum[7].set(1, 1, farZ);

    return virtualLight;

  }

  // Synchronize virtual light with the original light

  updateVirtualLight(light, int cascade) {

    var virtualLight = light.shadowCascadeArray[cascade];

    virtualLight.position.copy(light.position);
    virtualLight.target.position.copy(light.target.position);
    virtualLight.lookAt(virtualLight.target);

    virtualLight.shadowCameraVisible = light.shadowCameraVisible;
    virtualLight.shadowDarkness = light.shadowDarkness;

    virtualLight.shadowBias = light.shadowCascadeBias[cascade];

    var nearZ = light.shadowCascadeNearZ[cascade];
    var farZ = light.shadowCascadeFarZ[cascade];

    var pointsFrustum = virtualLight.pointsFrustum;

    pointsFrustum[0].z = nearZ;
    pointsFrustum[1].z = nearZ;
    pointsFrustum[2].z = nearZ;
    pointsFrustum[3].z = nearZ;

    pointsFrustum[4].z = farZ;
    pointsFrustum[5].z = farZ;
    pointsFrustum[6].z = farZ;
    pointsFrustum[7].z = farZ;

  }

  // Fit shadow camera's ortho frustum to camera frustum

  updateShadowCamera(Camera camera, light) {

    var shadowCamera = light.shadowCamera,
        pointsFrustum = light.pointsFrustum,
        pointsWorld = light.pointsWorld;

    _min.setValues(double.INFINITY, double.INFINITY, double.INFINITY);
    _max.setValues(double.NEGATIVE_INFINITY, double.NEGATIVE_INFINITY, double.NEGATIVE_INFINITY);

    for (var i = 0; i < 8; i++) {

      var p = pointsWorld[i];

      p.copy(pointsFrustum[i]);
      __projector.unprojectVector(p, camera);

      shadowCamera.matrixWorldInverse.multiplyVector3(p);

      if (p.x < _min.x) _min.x = p.x;
      if (p.x > _max.x) _max.x = p.x;

      if (p.y < _min.y) _min.y = p.y;
      if (p.y > _max.y) _max.y = p.y;

      if (p.z < _min.z) _min.z = p.z;
      if (p.z > _max.z) _max.z = p.z;

    }

    shadowCamera.left = _min.x;
    shadowCamera.right = _max.x;
    shadowCamera.top = _max.y;
    shadowCamera.bottom = _min.y;

    // can't really fit near/far
    //shadowCamera.near = _min.z;
    //shadowCamera.far = _max.z;

    shadowCamera.updateProjectionMatrix();

  }

  // For the moment just ignore objects that have multiple materials with different animation methods
  // Only the first material will be taken into account for deciding which depth material to use for shadow maps

  Material getObjectMaterial(Object3D object) {

    return object.material is MeshFaceMaterial ? object.geometry.materials[0] : object.material;

  }

}

class VirtualLight extends DirectionalLight {
  List pointsWorld, pointsFrustum;

  VirtualLight()
      : pointsWorld = [],
        pointsFrustum = [],
        super(0);
}



<|start_filename|>lib/extras/shaders/additive.dart<|end_filename|>
part of three_shaders;

/*
 * @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
 *
 * Ported to Dart from JS by
 * @author <NAME> / https://github.com/cgrabowski
 */

// Coeff'd additive buffer blending
  var AdditiveShader = {
    'uniforms': {
      'tDiffuse': { 'type': "t", 'value': null},
      'tAdd': { 'type': "t", 'value': null},
      'fCoeff': { 'type': "f", 'value': 1.0 }
    },

    'vertexShader': [
      "varying vec2 vUv;",

      "void main() {",

        "vUv = vec2( uv.x, 1.0 - uv.y );",
        "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

      "}"
    ].join("\n"),

    'fragmentShader': [
      "uniform sampler2D tDiffuse;",
      "uniform sampler2D tAdd;",
      "uniform float fCoeff;",

      "varying vec2 vUv;",

      "void main() {",

        "vec4 texel = texture2D( tDiffuse, vUv );",
        "vec4 add = texture2D( tAdd, vUv );",
        "gl_FragColor = texel + add * fCoeff;",

      "}"
    ].join("\n")
  };


<|start_filename|>lib/src/core/vector_utils.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author kile / http://kile.stravaganza.org/
 * @author philogb / http://blog.thejit.org/
 * @author <NAME> / http://gomo.se/
 * @author egraether / http://egraether.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 * @author <NAME> / http://aforsell.blogspot.com
 *
 * (moved from three.js Vector3 to here since these are missing in vector_math's Vector3)
 */

Vector3 calcEulerFromRotationMatrix(Matrix4 m, [String order = 'XYZ']) {
  double x, y, z;

  // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

  // clamp, to handle numerical problems

  var clamp = (x) => Math.min(Math.max(x, -1), 1);

  var m11 = m[0],
      m12 = m[4],
      m13 = m[8];
  var m21 = m[1],
      m22 = m[5],
      m23 = m[9];
  var m31 = m[2],
      m32 = m[6],
      m33 = m[10];

  if (order == 'XYZ') {

    y = Math.asin(clamp(m13));

    if (m13.abs() < 0.99999) {

      x = Math.atan2(-m23, m33);
      z = Math.atan2(-m12, m11);

    } else {

      x = Math.atan2(m21, m22);
      z = 0.0;

    }

  } else if (order == 'YXZ') {

    x = Math.asin(-clamp(m23));

    if (m23.abs() < 0.99999) {

      y = Math.atan2(m13, m33);
      z = Math.atan2(m21, m22);

    } else {

      y = Math.atan2(-m31, m11);
      z = 0.0;

    }

  } else if (order == 'ZXY') {

    x = Math.asin(clamp(m32));

    if (m32.abs() < 0.99999) {

      y = Math.atan2(-m31, m33);
      z = Math.atan2(-m12, m22);

    } else {

      y = 0.0;
      z = Math.atan2(m13, m11);

    }

  } else if (order == 'ZYX') {

    y = Math.asin(-clamp(m31));

    if (m31.abs() < 0.99999) {

      x = Math.atan2(m32, m33);
      z = Math.atan2(m21, m11);

    } else {

      x = 0.0;
      z = Math.atan2(-m12, m22);

    }

  } else if (order == 'YZX') {

    z = Math.asin(clamp(m21));

    if (m21.abs() < 0.99999) {

      x = Math.atan2(-m23, m22);
      y = Math.atan2(-m31, m11);

    } else {

      x = 0.0;
      y = Math.atan2(m31, m33);

    }

  } else if (order == 'XZY') {

    z = Math.asin(-clamp(m12));

    if (m12.abs() < 0.99999) {

      x = Math.atan2(m32, m22);
      y = Math.atan2(m13, m11);

    } else {

      x = Math.atan2(-m13, m33);
      y = 0.0;

    }

  }

  return new Vector3(x, y, z);
}

Vector3 calcEulerFromQuaternion(Vector4 q, [String order = 'XYZ']) {
  double x, y, z;
  // q is assumed to be normalized

  // clamp, to handle numerical problems

  var clamp = (x) => Math.min(Math.max(x, -1), 1);

  var sqx = q.x * q.x;
  var sqy = q.y * q.y;
  var sqz = q.z * q.z;
  var sqw = q.w * q.w;

  if (order == 'XYZ') {

    x = Math.atan2(2 * (q.x * q.w - q.y * q.z), (sqw - sqx - sqy + sqz));
    y = Math.asin(clamp(2 * (q.x * q.z + q.y * q.w)));
    z = Math.atan2(2 * (q.z * q.w - q.x * q.y), (sqw + sqx - sqy - sqz));

  } else if (order == 'YXZ') {

    x = Math.asin(clamp(2 * (q.x * q.w - q.y * q.z)));
    y = Math.atan2(2 * (q.x * q.z + q.y * q.w), (sqw - sqx - sqy + sqz));
    z = Math.atan2(2 * (q.x * q.y + q.z * q.w), (sqw - sqx + sqy - sqz));

  } else if (order == 'ZXY') {

    x = Math.asin(clamp(2 * (q.x * q.w + q.y * q.z)));
    y = Math.atan2(2 * (q.y * q.w - q.z * q.x), (sqw - sqx - sqy + sqz));
    z = Math.atan2(2 * (q.z * q.w - q.x * q.y), (sqw - sqx + sqy - sqz));

  } else if (order == 'ZYX') {

    x = Math.atan2(2 * (q.x * q.w + q.z * q.y), (sqw - sqx - sqy + sqz));
    y = Math.asin(clamp(2 * (q.y * q.w - q.x * q.z)));
    z = Math.atan2(2 * (q.x * q.y + q.z * q.w), (sqw + sqx - sqy - sqz));

  } else if (order == 'YZX') {

    x = Math.atan2(2 * (q.x * q.w - q.z * q.y), (sqw - sqx + sqy - sqz));
    y = Math.atan2(2 * (q.y * q.w - q.x * q.z), (sqw + sqx - sqy - sqz));
    z = Math.asin(clamp(2 * (q.x * q.y + q.z * q.w)));

  } else if (order == 'XZY') {

    x = Math.atan2(2 * (q.x * q.w + q.y * q.z), (sqw - sqx + sqy - sqz));
    y = Math.atan2(2 * (q.x * q.z + q.y * q.w), (sqw + sqx - sqy - sqz));
    z = Math.asin(clamp(2 * (q.z * q.w - q.x * q.y)));

  }

  return new Vector3(x, y, z);
}

Vector4 lerp4(Vector4 start, Vector4 end, double percent) {
  return (start + (end - start).scale(percent));
}


<|start_filename|>lib/src/renderers/renderer.dart<|end_filename|>
part of three;

abstract class Renderer {
  Element get domElement;
  void render(Scene scene, Camera camera);
  void setSize(num width, num height);
}


<|start_filename|>lib/src/renderers/web_gl_render_target_cube.dart<|end_filename|>
part of three;

class WebGLRenderTargetCube extends WebGLRenderTarget {

  int activeCubeFace; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5

  WebGLRenderTargetCube(num width, num height, {int wrapS: ClampToEdgeWrapping, int wrapT: ClampToEdgeWrapping,
      int magFilter: LinearFilter, int minFilter: LinearMipMapLinearFilter, int anisotropy: 1, int format: RGBAFormat,
      int type: UnsignedByteType, bool depthBuffer: true, bool stencilBuffer: true})
      : activeCubeFace = 0,
        super(
          width,
          height,
          wrapS: wrapS,
          wrapT: wrapT,
          magFilter: magFilter,
          minFilter: minFilter,
          anisotropy: anisotropy,
          format: format,
          type: type,
          depthBuffer: depthBuffer,
          stencilBuffer: stencilBuffer);

}


<|start_filename|>lib/src/core/face.dart<|end_filename|>
part of three;

/// Base class for all Face types.
abstract class Face {
  List<int> indices;
  Vector3 normal;
  List vertexNormals, vertexColors, vertexTangents;
  Color color;
  int materialIndex;
  Vector3 centroid;

  /// normalOrVertexNormals and colorOrVertexColors can be either a [Vector3] or a [List<Vector3>]
  Face(this.indices, normalOrVertexNormals, colorOrVertexColors, this.materialIndex) {

    normal = normalOrVertexNormals is Vector3 ? normalOrVertexNormals : new Vector3.zero();
    vertexNormals = normalOrVertexNormals is List ? normalOrVertexNormals : [];

    color = colorOrVertexColors is Color ? colorOrVertexColors : new Color();
    vertexColors = colorOrVertexColors is List ? colorOrVertexColors : [];

    vertexTangents = [];

    centroid = new Vector3.zero();
  }

  int get size => indices.length;

  /// Copies all the values from `other` into this Face.
  Face setFrom(Face other) {
    normal.setFrom(other.normal);
    color.copy(other.color);
    centroid.setFrom(other.centroid);

    materialIndex = other.materialIndex;

    vertexNormals = other.vertexNormals.map((Vector3 v) => v.clone()).toList();
    vertexColors = other.vertexColors.map((Vector3 v) => v.clone()).toList();
    vertexTangents = other.vertexTangents.map((Vector3 v) => v.clone()).toList();

    return this;
  }

  Face clone();
}


<|start_filename|>example/web_gl_postprocessing/postprocessing.dart<|end_filename|>
import 'dart:math' show Random;
import 'dart:html' show window, document;
import 'package:three/three.dart';
import 'package:three/extras/shaders/shaders.dart';
import 'package:three/extras/postprocessing/postprocessing.dart';
import 'package:stats/stats.dart';

const double DOT_SCALE = 2.0;
const double RGB_SHIFT_AMOUNT = 0.009;

EffectComposer composer;
Object3D spheres;
Stats stats;

void main() {
  init();
  animate(0.0);
}

void init() {
  WebGLRenderer renderer = new WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.append(renderer.domElement);

  Scene scene = new Scene();
  PerspectiveCamera camera = new PerspectiveCamera(70.0, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  camera.position.z = 400.0;
  spheres = new Object3D();
  scene.add(spheres);
  SphereGeometry geometry = new SphereGeometry(1.0, 4, 4);
  MeshPhongMaterial material = new MeshPhongMaterial(color: 0xaaaaaa, shading: FlatShading);
  Random random = new Random();
  for (var i = 0; i < 100; ++i) {
    var mesh = new Mesh(geometry, material);
    mesh.position.setValues(
        random.nextDouble() - 0.5,
        random.nextDouble() - 0.5,
        random.nextDouble() - 0.5).normalize();
    mesh.position.scale(random.nextDouble() * 400);
    mesh.rotation.setValues(random.nextDouble() * 2, random.nextDouble() * 2, random.nextDouble() * 2);
    mesh.scale.x = mesh.scale.y = mesh.scale.z = random.nextDouble() * 50;
    spheres.add(mesh);
  }

  scene.add(new AmbientLight(0x222222));
  scene.add(new DirectionalLight(0xffffff)..position.setValues(1.0, 1.0, 1.0));


  // postprocessing
  composer = new EffectComposer(renderer);
  composer.addPass(new RenderPass(scene, camera));

  ShaderPass effect1 = new ShaderPass(new ShaderProgram.fromThreeish(DotScreenShader));
  effect1.uniforms['scale'].value = DOT_SCALE;
  composer.addPass(effect1);

  ShaderPass effect2 = new ShaderPass(new ShaderProgram.fromThreeish(RGBShiftShader));
  effect2.uniforms['amount'].value = RGB_SHIFT_AMOUNT;
  effect2.renderToScreen = true;
  composer.addPass(effect2);

  stats = new Stats();
  document.body.append(stats.container);

  window.onResize.listen((event) {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });
}

double oldTime = 0.0;
void animate(double time) {
  stats.begin();
  spheres.rotation.x += 0.005;
  spheres.rotation.y += 0.01;
  composer.render(time - oldTime);
  oldTime = time;
  stats.end();
  window.requestAnimationFrame(animate);
}


<|start_filename|>lib/src/cameras/camera.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author <NAME> / http://gomo.se
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

/// Abstract base class for cameras.
///
/// This class should always be inherited when you build a new camera.
class Camera extends Object3D {
  /// This is the inverse of matrixWorld. MatrixWorld contains the Matrix which has the world transform of the Camera.
  Matrix4 matrixWorldInverse;
  /// This is the matrix which contains the projection.
  Matrix4 projectionMatrix;
  Matrix4 projectionMatrixInverse;

  double near;
  double far;

  // WebGL
  Float32List _viewMatrixArray = new Float32List(16);
  Float32List _projectionMatrixArray = new Float32List(16);

  Camera(this.near, this.far)
      : matrixWorldInverse = new Matrix4.identity(),
        projectionMatrix = new Matrix4.identity(),
        projectionMatrixInverse = new Matrix4.identity(),
        super();

  /// This makes the camera look at the vector position in the global space as
  /// long as the parent of this camera is the scene or at position (0,0,0).
  void lookAt(Vector3 vector) {
    // TODO: Add hierarchy support.

    makeLookAt(matrix, position, vector, up);

    if (rotationAutoUpdate) {
      rotation = calcEulerFromRotationMatrix(matrix, eulerOrder);
    }
  }
}


<|start_filename|>lib/extras/core/closed_spline_curve3.dart<|end_filename|>
part of three;

class ClosedSplineCurve3 extends Curve3D {

  List<Vector3> points;

  ClosedSplineCurve3([this.points]) : super() {
    if (points == null) points = [];
  }

  Vector3 getPoint(t) {

    var v = new Vector3.zero();
    var c = new List<int>(4);
    var point, intPoint, weight;

    point = (points.length - 0) * t;
    // This needs to be from 0-length +1

    intPoint = point.floor();
    weight = point - intPoint;

    intPoint += intPoint > 0 ? 0 : ((intPoint.abs() / points.length).floor() + 1) * points.length;
    c[0] = (intPoint - 1) % points.length;
    c[1] = (intPoint) % points.length;
    c[2] = (intPoint + 1) % points.length;
    c[3] = (intPoint + 2) % points.length;

    v.x = CurveUtils.interpolate(points[c[0]].x, points[c[1]].x, points[c[2]].x, points[c[3]].x, weight);
    v.y = CurveUtils.interpolate(points[c[0]].y, points[c[1]].y, points[c[2]].y, points[c[3]].y, weight);
    v.z = CurveUtils.interpolate(points[c[0]].z, points[c[1]].z, points[c[2]].z, points[c[3]].z, weight);

    return v;

  }
}


<|start_filename|>lib/src/cameras/perspective_camera.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author greggman / http://games.greggman.com/
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

/// Camera with perspective projection.
class PerspectiveCamera extends Camera {
  /// Camera frustum vertical field of view, from bottom to top of view, in degrees.
  double fov;
  /// Camera frustum aspect ratio, window width divided by window height.
  double aspect;

  double _fullWidth;
  double _fullHeight;
  double _x;
  double _y;
  double _width;
  double _height;


  PerspectiveCamera([this.fov = 50.0, this.aspect = 1.0, near = 0.1, far = 2000.0])
      : super(near, far) {

    updateProjectionMatrix();
  }

  /// Uses Focal Length (in mm) to estimate and set FOV
  /// 35mm (fullframe) camera is used if frame size is not specified.
  ///
  /// Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
  void setLens(double focalLength, double frameSize) {
    frameSize = frameSize != null ? frameSize : 43.25; // 36x24mm

    fov = 2.0 * Math.atan(frameSize / (focalLength * 2.0));
    fov = 180.0 / Math.PI * fov;

    updateProjectionMatrix();
  }

  /**
   * Sets an offset in a larger frustum. This is useful for multi-window or
   * multi-monitor/multi-machine setups.
   *
   * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
   * the monitors are in grid like this
   *
   *   +---+---+---+
   *   | A | B | C |
   *   +---+---+---+
   *   | D | E | F |
   *   +---+---+---+
   *
   * then for each monitor you would call it like this
   *
   *   var w = 1920;
   *   var h = 1080;
   *   var fullWidth = w * 3;
   *   var fullHeight = h * 2;
   *
   *   --A--
   *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
   *   --B--
   *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
   *   --C--
   *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
   *   --D--
   *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
   *   --E--
   *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
   *   --F--
   *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
   *
   *   Note there is no reason monitors have to be the same size or in a grid.
   */
  void setViewOffset(double fullWidth, double fullHeight, double x, double y, double width, double height) {
    _fullWidth = fullWidth;
    _fullHeight = fullHeight;
    _x = x;
    _y = y;
    _width = width;
    _height = height;

    updateProjectionMatrix();
  }

  /// Updates the camera projection matrix.
  ///
  /// Must be called after change of parameters.
  void updateProjectionMatrix() {
    if (_fullWidth != null) {
      double aspect = _fullWidth / _fullHeight;
      double top = Math.tan(fov * Math.PI / 360.0) * near;
      double bottom = -top;
      double left = aspect * bottom;
      double right = aspect * top;
      double width = (right - left).abs();
      double height = (top - bottom).abs();

      setFrustumMatrix(
          projectionMatrix,
          left + _x * width / _fullWidth,
          left + (_x + width) * width / _fullWidth,
          top - (_y + height) * height / _fullHeight,
          top - _y * height / _fullHeight,
          near,
          far);
    } else {
      projectionMatrix = makePerspectiveMatrix(fov * (Math.PI / 180), aspect, near, far);
    }
  }
}


<|start_filename|>lib/extras/core/line_curve.dart<|end_filename|>
part of three;

class LineCurve extends Curve2D {

  Vector2 v1, v2;

  LineCurve(this.v1, this.v2) : super();

  Vector2 getPoint(t) {
    Vector2 point = v2.clone().sub(v1);
    point.scale(t).add(v1);
    return point;
  }

  // Line curve is linear, so we can overwrite default getPointAt
  Vector2 getPointAt(u) => getPoint(u);

  Vector2 getTangent(t) => v2.clone().sub(v1).normalize();

}


<|start_filename|>lib/extras/geometries/convex_geometry.dart<|end_filename|>
part of three;

class ConvexGeometry extends Geometry {
  ConvexGeometry(List vertices) : super() {

    var faces = [[0, 1, 2], [0, 2, 1]];

    var addPoint = (vertexId) {

      var vertex = vertices[vertexId].clone();

      var mag = vertex.length();
      vertex.x += mag * _randomOffset();
      vertex.y += mag * _randomOffset();
      vertex.z += mag * _randomOffset();

      List hole = [];

      for (var f = 0; f < faces.length; ) {

        var face = faces[f];

        // for each face, if the vertex can see it,
        // then we try to add the face's edges into the hole.
        if (_visible(face, vertex)) {

          for (var e = 0; e < 3; e++) {

            var edge = [face[e], face[(e + 1) % 3]];
            var boundary = true;

            // remove duplicated edges.
            for (var h = 0; h < hole.length; h++) {

              if (_equalEdge(hole[h], edge)) {

                hole[h] = hole[hole.length - 1];
                hole.removeLast();
                boundary = false;
                break;

              }

            }

            if (boundary) {

              hole.add(edge);

            }

          }

          // remove faces[ f ]
          faces[f] = faces[faces.length - 1];
          faces.removeLast();

        } else { // not visible

          f++;

        }
      }

      // construct the new faces formed by the edges of the hole and the vertex
      for (var h = 0; h < hole.length; h++) {

        faces.add([hole[h][0], hole[h][1], vertexId]);

      }
    };


    for (var i = 3; i < vertices.length; i++) {
      addPoint(i);
    }


    // Push vertices into `this.vertices`, skipping those inside the hull
    var id = 0;
    var newId = new List(vertices.length); // map from old vertex id to new id

    for (var i = 0; i < faces.length; i++) {

      var face = faces[i];

      for (var j = 0; j < 3; j++) {

        if (newId[face[j]] == null) {

          newId[face[j]] = id++;
          this.vertices.add(vertices[face[j]]);

        }
        face[j] = newId[face[j]];
      }
    }

    // Convert faces into instances of THREE.Face3
    for (var i = 0; i < faces.length; i++) {

      this.faces.add(new Face3(faces[i][0], faces[i][1], faces[i][2]));

    }

    // Compute UVs
    for (var i = 0; i < this.faces.length; i++) {

      var face = this.faces[i];

      this.faceVertexUvs[0].add(
          [_vertexUv(this.vertices[face.a]), _vertexUv(this.vertices[face.b]), _vertexUv(this.vertices[face.c])]);

    }


    this.computeCentroids();
    this.computeFaceNormals();
    this.computeVertexNormals();
  }

  /**
   * Whether the face is visible from the vertex
   */
  bool _visible(List<int> face, Vector3 vertex) {

    var va = vertices[face[0]];
    var vb = vertices[face[1]];
    var vc = vertices[face[2]];

    var n = _normal(va, vb, vc);

    // distance from face to origin
    var dist = n.dot(va);

    return n.dot(vertex) >= dist;

  }

  /**
   * Face normal
   */
  Vector3 _normal(Vector3 va, Vector3 vb, Vector3 vc) {

    Vector3 cb = new Vector3.zero();
    Vector3 ab = new Vector3.zero();

    cb = vc - vb;
    ab = va - vb;
    cb = cb.cross(ab);
    cb.normalize();

    return cb;

  }

  /**
   * Detect whether two edges are equal.
   * Note that when constructing the convex hull, two same edges can only
   * be of the negative direction.
   */
  _equalEdge(ea, eb) => ea[0] == eb[1] && ea[1] == eb[0];


  /**
   * Create a random offset between -1e-6 and 1e-6.
   */
  _randomOffset() => (new Math.Random().nextDouble() - 0.5) * 2 * 1e-6;


  /**
   * XXX: Not sure if this is the correct approach. Need someone to review.
   */
  _vertexUv(vertex) {

    var mag = vertex.length();
    return new UV(vertex.x / mag, vertex.y / mag);

  }
}


<|start_filename|>lib/extras/shaders/triangle_blur_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 * Triangle blur shader
 * based on glfx.js triangle blur shader
 * https://github.com/evanw/glfx.js
 *
 * A basic blur filter, which convolves the image with a
 * pyramid filter. The pyramid filter is separable and is applied as two
 * perpendicular triangle filters.
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var TriangleBlurShader = {

  'uniforms' : {

    "texture": { 'type': "t", 'value': null },
    "delta":   { 'type': "v2", 'value':new Vector2( 1.0, 1.0 )  }

  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "#define ITERATIONS 10.0",

    "uniform sampler2D texture;",
    "uniform vec2 delta;",

    "varying vec2 vUv;",

    "float random( vec3 scale, float seed ) {",

      // use the fragment position for a different seed per-pixel

      "return fract( sin( dot( gl_FragCoord.xyz + seed, scale ) ) * 43758.5453 + seed );",

    "}",

    "void main() {",

      "vec4 color = vec4( 0.0 );",

      "float total = 0.0;",

      // randomize the lookup 'value's to hide the fixed number of samples

      "float offset = random( vec3( 12.9898, 78.233, 151.7182 ), 0.0 );",

      "for ( float t = -ITERATIONS; t <= ITERATIONS; t ++ ) {",

        "float percent = ( t + offset - 0.5 ) / ITERATIONS;",
        "float weight = 1.0 - abs( percent );",

        "color += texture2D( texture, vUv + delta * percent ) * weight;",
        "total += weight;",

      "}",

      "gl_FragColor = color / total;",

    "}"

  ].join("\n")

};


<|start_filename|>lib/src/lights/ambient_light.dart<|end_filename|>
part of three;

/// This light's color gets applied to all the objects in the scene globally.
class AmbientLight extends Light {
  /// This creates an Ambientlight with a color.
  AmbientLight(num hex) : super(hex);
}


<|start_filename|>example/web_gl_geometry_extrude_shapes/web_gl_geometry_extrude_shapes.dart<|end_filename|>
import 'dart:html' hide Path;
import 'dart:math' as Math;
import 'package:vector_math/vector_math.dart';
import 'package:three/three.dart';
import 'package:three/extras/scene_utils.dart' as SceneUtils;

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

var windowHalfX, windowHalfY;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var mouseEvts = [];

var targetRotation = 0;
var targetRotationOnMouseDown = 0;

Object3D parent, text, plane;

void main() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  init();
  animate(0);
}

_addGeometry(geometry, color, x, y, z, rx, ry, rz, s) {

  // 3d shape

  var mesh = SceneUtils.createMultiMaterialObject(
      geometry,
      [
          new MeshLambertMaterial(color: color, opacity: 0.2, transparent: true),
          new MeshBasicMaterial(color: 0x000000, wireframe: true, opacity: 0.3)]);

  mesh.position.setValues(x.toDouble(), y.toDouble(), z.toDouble() - 75);
  // mesh.rotation.set( rx, ry, rz );
  double ds = s.toDouble();
  mesh.scale.setValues(ds, ds, ds);

  // if ( geometry.debug ) mesh.add( geometry.debug );

  parent.add(mesh);

}

void init() {

  container = new Element.tag('div');
  document.body.nodes.add(container);

  camera = new PerspectiveCamera(50.0, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  camera.position.setValues(0.0, 150.0, 500.0);

  scene = new Scene();

  var light = new DirectionalLight(0xffffff);
  light.position.setValues(0.0, 0.0, 1.0);
  scene.add(light);

  parent = new Object3D();
  parent.position.y = 50.0;
  scene.add(parent);

  var extrude_amount = 200,
      extrude_bevelEnabled = true,
      extrude_bevelSegments = 2,
      extrude_steps = 150; // bevelSegments: 2, steps: 2 , bevelSegments: 5, bevelSize: 8, bevelThickness:5,

  // var extrudePath = new Path();

  // extrudePath.moveTo( 0, 0 );
  // extrudePath.lineTo( 10, 10 );
  // extrudePath.quadraticCurveTo( 80, 60, 160, 10 );
  // extrudePath.quadraticCurveTo( 240, -40, 320, 10 );


  extrude_bevelEnabled = false;

  var extrudeBend = new SplineCurve3( //Closed
  [
      new Vector3(30.0, 12.0, 83.0),
      new Vector3(40.0, 20.0, 67.0),
      new Vector3(60.0, 40.0, 99.0),
      new Vector3(10.0, 60.0, 49.0),
      new Vector3(25.0, 80.0, 40.0)]);

  var pipeSpline = new SplineCurve3(
      [
          new Vector3(0.0, 10.0, -10.0),
          new Vector3(10.0, 0.0, -10.0),
          new Vector3(20.0, 0.0, 0.0),
          new Vector3(30.0, 0.0, 10.0),
          new Vector3(30.0, 0.0, 20.0),
          new Vector3(20.0, 0.0, 30.0),
          new Vector3(10.0, 0.0, 30.0),
          new Vector3(0.0, 0.0, 30.0),
          new Vector3(-10.0, 10.0, 30.0),
          new Vector3(-10.0, 20.0, 30.0),
          new Vector3(0.0, 30.0, 30.0),
          new Vector3(10.0, 30.0, 30.0),
          new Vector3(20.0, 30.0, 15.0),
          new Vector3(10.0, 30.0, 10.0),
          new Vector3(0.0, 30.0, 10.0),
          new Vector3(-10.0, 20.0, 10.0),
          new Vector3(-10.0, 10.0, 10.0),
          new Vector3(0.0, 0.0, 10.0),
          new Vector3(10.0, -10.0, 10.0),
          new Vector3(20.0, -15.0, 10.0),
          new Vector3(30.0, -15.0, 10.0),
          new Vector3(40.0, -15.0, 10.0),
          new Vector3(50.0, -15.0, 10.0),
          new Vector3(60.0, 0.0, 10.0),
          new Vector3(70.0, 0.0, 0.0),
          new Vector3(80.0, 0.0, 0.0),
          new Vector3(90.0, 0.0, 0.0),
          new Vector3(100.0, 0.0, 0.0)]);

  var sampleClosedSpline = new ClosedSplineCurve3(
      [
          new Vector3(0.0, -40.0, -40.0),
          new Vector3(0.0, 40.0, -40.0),
          new Vector3(0.0, 140.0, -40.0),
          new Vector3(0.0, 40.0, 40.0),
          new Vector3(0.0, -40.0, 40.0),]);

  var randomPoints = [];
  var rnd = new Math.Random();

  for (var i = 0; i < 10; i++) {

    randomPoints.add(new Vector3(rnd.nextDouble() * 200, rnd.nextDouble() * 200, rnd.nextDouble() * 200));

  }

  var randomSpline = new SplineCurve3(randomPoints);

  var extrude_extrudePath = randomSpline; // extrudeBend sampleClosedSpline pipeSpline randomSpline

  // Circle

  var circleRadius = 4.0;
  var circleShape = new Shape();
  circleShape.moveTo(0, circleRadius);
  circleShape.quadraticCurveTo(circleRadius, circleRadius, circleRadius, 0);
  circleShape.quadraticCurveTo(circleRadius, -circleRadius, 0, -circleRadius);
  circleShape.quadraticCurveTo(-circleRadius, -circleRadius, -circleRadius, 0);
  circleShape.quadraticCurveTo(-circleRadius, circleRadius, 0, circleRadius);

  var rectLength = 12,
      rectWidth = 4;

  var rectShape = new Shape();

  rectShape.moveTo(-rectLength / 2, -rectWidth / 2);
  rectShape.lineTo(-rectLength / 2, rectWidth / 2);
  rectShape.lineTo(rectLength / 2, rectWidth / 2);
  rectShape.lineTo(rectLength / 2, -rectLength / 2);
  rectShape.lineTo(-rectLength / 2, -rectLength / 2);


  var pts = [],
      starPoints = 5,
      l;

  for (var i = 0; i < starPoints * 2; i++) {

    if (i % 2 == 1) {

      l = 5;

    } else {

      l = 10;

    }

    var a = i / starPoints * Math.PI;
    pts.add(new Vector2(Math.cos(a) * l, Math.sin(a) * l));

  }

  var starShape = new Shape(pts);

  // Smiley

  var smileyShape = new Shape();
  smileyShape.moveTo(80, 40);
  smileyShape.arc(40, 40, 40, 0, Math.PI * 2, false);

  var smileyEye1Path = new Path();
  smileyEye1Path.moveTo(35, 20);
  smileyEye1Path.arc(25, 20, 10, 0, Math.PI * 2, true);
  smileyShape.holes.add(smileyEye1Path);

  var smileyEye2Path = new Path();
  smileyEye2Path.moveTo(65, 20);
  smileyEye2Path.arc(55, 20, 10, 0, Math.PI * 2, true);
  smileyShape.holes.add(smileyEye2Path);

  var smileyMouthPath = new Path();

  smileyMouthPath.moveTo(20, 40);
  smileyMouthPath.quadraticCurveTo(40, 60, 60, 40);
  smileyMouthPath.bezierCurveTo(70, 45, 70, 50, 60, 60);
  smileyMouthPath.quadraticCurveTo(40, 80, 20, 60);
  smileyMouthPath.quadraticCurveTo(5, 50, 20, 40);

  smileyShape.holes.add(smileyMouthPath);

  var circle3d = starShape.extrude(
      amount: extrude_amount,
      bevelSegments: extrude_bevelSegments,
      bevelEnabled: extrude_bevelEnabled,
      steps: extrude_steps,
      extrudePath: extrude_extrudePath); //circleShape rectShape smileyShape starShape
  // var circle3d = new ExtrudeGeometry(circleShape, extrudeBend, extrudeSettings );

  var tube = new TubeGeometry(extrude_extrudePath, 150, 4.0, 5, false, true);
  // new TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2, debug);


  _addGeometry(circle3d, 0xff1111, -100, 0, 0, 0, 0, 0, 1);
  _addGeometry(tube, 0x00ff11, 0, 0, 0, 0, 0, 0, 1);

  renderer = new WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.sortObjects = false;

  container.nodes.add(renderer.domElement);

  mouseEvts = [
      document.onMouseDown.listen(onDocumentMouseDown),
      document.onTouchStart.listen(onDocumentTouchStart),
      document.onTouchMove.listen(onDocumentTouchMove)];

  window.onResize.listen(onWindowResize);
}

onWindowResize(event) {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

void cancelMouseEvts() {
  mouseEvts.forEach((s) => s.cancel());
  mouseEvts = [];
}

onDocumentMouseDown(MouseEvent event) {
  event.preventDefault();

  mouseEvts = [
      document.onMouseMove.listen(onDocumentMouseMove),
      document.onMouseUp.listen(onDocumentMouseUp),
      document.onMouseOut.listen(onDocumentMouseOut)];

  mouseXOnMouseDown = event.client.x - windowHalfX;
  targetRotationOnMouseDown = targetRotation;
}

onDocumentMouseMove(MouseEvent event) {
  mouseX = event.client.x - windowHalfX;
  targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
}

onDocumentMouseUp(event) {
  cancelMouseEvts();
}

onDocumentMouseOut(event) {
  cancelMouseEvts();
}

onDocumentTouchStart(TouchEvent event) {

  if (event.touches.length == 1) {

    event.preventDefault();

    mouseXOnMouseDown = event.touches[0].page.x - windowHalfX;
    targetRotationOnMouseDown = targetRotation;

  }

}

onDocumentTouchMove(TouchEvent event) {

  if (event.touches.length == 1) {

    event.preventDefault();

    mouseX = event.touches[0].page.x - windowHalfX;
    targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;

  }

}

animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

render() {

  parent.rotation.y += (targetRotation - parent.rotation.y) * 0.05;

  renderer.render(scene, camera);

}


<|start_filename|>lib/extras/shaders/shaders.dart<|end_filename|>
library three_shaders;

import 'dart:math';
import 'package:vector_math/vector_math.dart';
import 'package:three/three.dart';

part 'additive.dart';
part 'basic_shader.dart';
part 'bleach_bypass_shader.dart';
part 'blend_shader.dart';
part 'bokeh_shader.dart';
part 'bokeh_shader2.dart';
part 'brightness_contrast_shader.dart';
part 'color_correction_shader.dart';
part 'colorify_shader.dart';
part 'convolution_shader.dart';
part 'copy_shader.dart';
part 'dof_mipmap_shader.dart';
part 'digital_glitch.dart';
part 'dot_screen_shader.dart';
part 'edge_shader.dart';
part 'edge_shader2.dart';
part 'fxaa_shader.dart';
part 'godrays.dart';
part 'film_shader.dart';
part 'focus_shader.dart';
part 'fresnel_shader.dart';
part 'horizontal_blur_shader.dart';
part 'horizontal_tilt_shift_shader.dart';
part 'hue_saturation_shader.dart';
part 'kaleido_shader.dart';
part 'luminosity_shader.dart';
part 'mirror_shader.dart';
part 'normal_map_shader.dart';
part 'ocean_shaders.dart';
part 'parallax_shader.dart';
part 'rgb_shift_shader.dart';
part 'ssao_shader.dart';
part 'sepia_shader.dart';
part 'shader_program.dart';
part 'technicolor_shader.dart';
part 'triangle_blur_shader.dart';
part 'unpack_depth_rgba_shader.dart';
part 'vertical_blur_shader.dart';
part 'vertical_tilt_shift_shader.dart';
part 'vignette_shader.dart';


<|start_filename|>example/web_gl_geometry_hierarchy/web_gl_geometry_hierarchy.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:three/three.dart';

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

var windowHalfX, windowHalfY;
var mouseX = 0,
    mouseY = 0;

Object3D group;

void main() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  document.onMouseMove.listen(onDocumentMouseMove);

  init();
  animate(0);
}

void init() {

  container = new Element.tag('div');
  document.body.nodes.add(container);

  camera = new PerspectiveCamera(60.0, window.innerWidth / window.innerHeight, 1.0, 10000.0);
  camera.position.z = 500.0;

  scene = new Scene();
  scene.fog = new FogLinear(0xffffff, 1.0, 10000.0);
  scene.add(camera);

  var geometry = new CubeGeometry(100.0, 100.0, 100.0);
  var material = new MeshNormalMaterial();

  group = new Object3D();

  var rnd = new Math.Random();

  for (var i = 0; i < 1000; i++) {

    var mesh = new Mesh(geometry, material);
    mesh.position.x = rnd.nextInt(2000).toDouble() - 1000.0;
    mesh.position.y = rnd.nextInt(2000).toDouble() - 1000.0;
    mesh.position.z = rnd.nextInt(2000).toDouble() - 1000.0;

    mesh.rotation.x = rnd.nextDouble() * 360.0 * (Math.PI / 180.0);
    mesh.rotation.y = rnd.nextDouble() * 360.0 * (Math.PI / 180.0);

    mesh.matrixAutoUpdate = false;
    mesh.updateMatrix();

    group.add(mesh);

  }

  scene.add(group);

  renderer = new WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.sortObjects = false;

  container.nodes.add(renderer.domElement);

  window.onResize.listen(onWindowResize);
}

onWindowResize(event) {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

onDocumentMouseMove(MouseEvent event) {
  mouseX = (event.client.x - windowHalfX) * 10;
  mouseY = (event.client.y - windowHalfY) * 10;
}

animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

render() {

  var time = new DateTime.now().millisecondsSinceEpoch * 0.001;

  var rx = Math.sin(time * 0.7) * 0.5,
      ry = Math.sin(time * 0.3) * 0.5,
      rz = Math.sin(time * 0.2) * 0.5;

  camera.position.x += (mouseX - camera.position.x) * .05;
  camera.position.y += (-mouseY - camera.position.y) * .05;

  camera.lookAt(scene.position);

  group.rotation.x = rx;
  group.rotation.y = ry;
  group.rotation.z = rz;

  renderer.render(scene, camera);

}


<|start_filename|>lib/extras/objects/lens_flare.dart<|end_filename|>
part of three;

class LensFlare extends Object3D {
  List lensFlares;
  var customUpdateCallback;

  Vector3 positionScreen;

  LensFlare(texture, size, distance, blending, color)
      : lensFlares = [],
        customUpdateCallback = null,
        super() {

    positionScreen = new Vector3.zero();

    // TODO
    //if( texture != undefined ) {
    //  add( texture, size, distance, blending, color );
    //}

  }

}


<|start_filename|>lib/extras/postprocessing/shader_pass.dart<|end_filename|>
part of three_postprocessing;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

class ShaderPass implements Pass {
  ShaderProgram program;
  Map<String, Uniform> uniforms;
  ShaderMaterial material;
  String textureID;
  Scene scene;
  Camera camera;
  Mesh quad;
  bool renderToScreen = false;
  bool enabled = true;
  bool needsSwap = true;
  bool clear = false;

  ShaderPass(this.program, [this.textureID = 'tDiffuse']) {
    uniforms = program.uniforms;
    material =
        new ShaderMaterial(uniforms: uniforms, vertexShader: program.vertexShader, fragmentShader: program.fragmentShader);

    scene = new Scene();
    camera = new OrthographicCamera(-1.0, 1.0, 1.0, -1.0, 0.0, 1.0);
    quad = new Mesh(new PlaneGeometry(2.0, 2.0), material);
    scene.add(quad);
  }

  void render(WebGLRenderer renderer, WebGLRenderTarget writeTarget, WebGLRenderTarget readTarget, double delta,
      bool maskActive) {

    if (uniforms[textureID] != null) {
      uniforms[textureID].value = readTarget;
    }

    if (renderToScreen) {
      renderer.render(scene, camera);

    } else {
      renderer.renderToTarget(scene, camera, writeTarget, clear);
    }
  }
}


<|start_filename|>lib/extras/core/ellipse_curve.dart<|end_filename|>
part of three;

class EllipseCurve extends Curve2D {
  num aX, aY;
  num xRadius, yRadius;
  num aStartAngle, aEndAngle;
  bool aClockwise;

  EllipseCurve(this.aX, this.aY, this.xRadius, this.yRadius, this.aStartAngle, this.aEndAngle, this.aClockwise)
      : super();

  Vector2 getPoint(t) {

    var deltaAngle = aEndAngle - aStartAngle;

    if (!aClockwise) {
      t = 1 - t;
    }

    var angle = aStartAngle + t * deltaAngle;

    var tx = aX + xRadius * Math.cos(angle);
    var ty = aY + yRadius * Math.sin(angle);

    return new Vector2(tx, ty);

  }
}


<|start_filename|>lib/src/core/matrix4.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 * @author supereggbert / http://www.paulbrunt.co.uk/
 * @author philogb / http://blog.thejit.org/
 * @author jordi_ros / http://plattsoft.com
 * @author D1plo1d / http://github.com/D1plo1d
 * @author alteredq / http://alteredqualia.com/
 * @author <NAME> / http://gomo.se/
 * @author timknip / http://www.floorplanner.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

/// A 4x4 Matrix.
class Matrix4 {

  final Float32List elements;


  /// Initialises the matrix with the supplied row-major values n11..n44,
  /// or just creates an identity matrix if no values are passed.
  Matrix4([num n11 = 1.0, num n12 = 0.0, num n13 = 0.0, num n14 = 0.0, num n21 = 0.0, num n22 = 1.0, num n23 = 0.0,
      num n24 = 0.0, num n31 = 0.0, num n32 = 0.0, num n33 = 1.0, num n34 = 0.0, num n41 = 0.0, num n42 = 0.0, num n43 = 0.0,
      num n44 = 1.0])
      : elements = new Float32List(16) {

    setValues(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44);
  }


  // "set" changed to "setM" as "set" is reserved
  Matrix4 setValues(num n11, num n12, num n13, num n14, num n21, num n22, num n23, num n24, num n31, num n32, num n33,
      num n34, num n41, num n42, num n43, num n44) {
    var te = this.elements;

    te[0] = n11.toDouble();
    te[4] = n12.toDouble();
    te[8] = n13.toDouble();
    te[12] = n14.toDouble();
    te[1] = n21.toDouble();
    te[5] = n22.toDouble();
    te[9] = n23.toDouble();
    te[13] = n24.toDouble();
    te[2] = n31.toDouble();
    te[6] = n32.toDouble();
    te[10] = n33.toDouble();
    te[14] = n34.toDouble();
    te[3] = n41.toDouble();
    te[7] = n42.toDouble();
    te[11] = n43.toDouble();
    te[15] = n44.toDouble();

    return this;
  }

  /// Resets this matrix to identity.
  Matrix4 identity() {
    setValues(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);

    return this;
  }

  /// Copies a matrix m into this matrix.
  Matrix4 copy(Matrix4 m) {
    var me = m.elements;

    setValues(
        me[0],
        me[4],
        me[8],
        me[12],
        me[1],
        me[5],
        me[9],
        me[13],
        me[2],
        me[6],
        me[10],
        me[14],
        me[3],
        me[7],
        me[11],
        me[15]);

    return this;
  }

  /// Constructs a rotation matrix, looking from eye towards center with defined up vector.
  Matrix4 lookAt(Vector3 eye, Vector3 center, Vector3 up) {
    var te = elements;

    Vector3 x = __v1,
        y = __v2,
        z = __v3;

    z.sub(eye, center).normalize();

    if (z.length() == 0) {
      z.z = 1.0;
    }

    x.cross(up, z).normalize();

    if (x.length() == 0) {
      z.x += 0.0001;
      x.cross(up, z).normalize();
    }

    y.cross(z, x).normalize();

    te[0] = x.x;
    te[4] = y.x;
    te[8] = z.x;
    te[1] = x.y;
    te[5] = y.y;
    te[9] = z.y;
    te[2] = x.z;
    te[6] = y.z;
    te[10] = z.z;

    return this;
  }

  /// Sets this matrix to a * b.
  Matrix4 multiply(Matrix4 a, Matrix4 b) {
    var ae = a.elements;
    var be = b.elements;
    var te = elements;

    var a11 = ae[0],
        a12 = ae[4],
        a13 = ae[8],
        a14 = ae[12];
    var a21 = ae[1],
        a22 = ae[5],
        a23 = ae[9],
        a24 = ae[13];
    var a31 = ae[2],
        a32 = ae[6],
        a33 = ae[10],
        a34 = ae[14];
    var a41 = ae[3],
        a42 = ae[7],
        a43 = ae[11],
        a44 = ae[15];

    var b11 = be[0],
        b12 = be[4],
        b13 = be[8],
        b14 = be[12];
    var b21 = be[1],
        b22 = be[5],
        b23 = be[9],
        b24 = be[13];
    var b31 = be[2],
        b32 = be[6],
        b33 = be[10],
        b34 = be[14];
    var b41 = be[3],
        b42 = be[7],
        b43 = be[11],
        b44 = be[15];

    te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
    te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
    te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
    te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;

    te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
    te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
    te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
    te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;

    te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
    te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
    te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
    te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;

    te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
    te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
    te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
    te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;

    return this;
  }

  /// Multiplies this matrix by m.
  Matrix4 multiplySelf(Matrix4 m) => multiply(this, m);

  /// Sets this matrix to a x b and stores the result into the flat array r.
  /// r can be either a regular Array or a TypedArray.
  Matrix4 multiplyToArray(Matrix4 a, Matrix4 b, List r) {

    var te = elements;

    multiply(a, b);

    r[0] = te[0];
    r[1] = te[1];
    r[2] = te[2];
    r[3] = te[3];
    r[4] = te[4];
    r[5] = te[5];
    r[6] = te[6];
    r[7] = te[7];
    r[8] = te[8];
    r[9] = te[9];
    r[10] = te[10];
    r[11] = te[11];
    r[12] = te[12];
    r[13] = te[13];
    r[14] = te[14];
    r[15] = te[15];

    return this;
  }

  /// Multiplies this matrix by s.
  Matrix4 multiplyScalar(num s) {
    var te = elements;

    te[0] *= s;
    te[4] *= s;
    te[8] *= s;
    te[12] *= s;
    te[1] *= s;
    te[5] *= s;
    te[9] *= s;
    te[13] *= s;
    te[2] *= s;
    te[6] *= s;
    te[10] *= s;
    te[14] *= s;
    te[3] *= s;
    te[7] *= s;
    te[11] *= s;
    te[15] *= s;

    return this;
  }

  multiplyVector3(IVector3 v) {
    var te = elements;

    var vx = v.x,
        vy = v.y,
        vz = v.z;
    var d = 1.0 / (te[3] * vx + te[7] * vy + te[11] * vz + te[15]);

    v.x = (te[0] * vx + te[4] * vy + te[8] * vz + te[12]) * d;
    v.y = (te[1] * vx + te[5] * vy + te[9] * vz + te[13]) * d;
    v.z = (te[2] * vx + te[6] * vy + te[10] * vz + te[14]) * d;

    return v;
  }

  Vector4 multiplyVector4(Vector4 v) {
    var te = elements;
    var vx = v.x,
        vy = v.y,
        vz = v.z,
        vw = v.w;

    v.x = te[0] * vx + te[4] * vy + te[8] * vz + te[12] * vw;
    v.y = te[1] * vx + te[5] * vy + te[9] * vz + te[13] * vw;
    v.z = te[2] * vx + te[6] * vy + te[10] * vz + te[14] * vw;
    v.w = te[3] * vx + te[7] * vy + te[11] * vz + te[15] * vw;

    return v;
  }

  multiplyVector3Array(a) {

    var tmp = Matrix4.__v1;

    int il = a.length;

    for (var i = 0; i < il; i += 3) {

      tmp.x = a[i];
      tmp.y = a[i + 1];
      tmp.z = a[i + 2];

      multiplyVector3(tmp);

      a[i] = tmp.x;
      a[i + 1] = tmp.y;
      a[i + 2] = tmp.z;

    }

    return a;

  }

  Vector3 rotateAxis(Vector3 v) {
    var te = elements;
    var vx = v.x,
        vy = v.y,
        vz = v.z;

    v.x = vx * te[0] + vy * te[4] + vz * te[8];
    v.y = vx * te[1] + vy * te[5] + vz * te[9];
    v.z = vx * te[2] + vy * te[6] + vz * te[10];

    v.normalize();

    return v;
  }

  Vector4 crossVector(Vector4 a) {

    var te = this.elements;
    Vector4 v = new Vector4();

    v.x = te[0] * a.x + te[4] * a.y + te[8] * a.z + te[12] * a.w;
    v.y = te[1] * a.x + te[5] * a.y + te[9] * a.z + te[13] * a.w;
    v.z = te[2] * a.x + te[6] * a.y + te[10] * a.z + te[14] * a.w;

    v.w = (a.w != null) ? te[3] * a.x + te[7] * a.y + te[11] * a.z + te[15] * a.w : 1;

    return v;
  }

  /// Computes determinant of this matrix.
  ///
  /// Based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
  num determinant() {
    var te = elements;

    var n11 = te[0],
        n12 = te[4],
        n13 = te[8],
        n14 = te[12];
    var n21 = te[1],
        n22 = te[5],
        n23 = te[9],
        n24 = te[13];
    var n31 = te[2],
        n32 = te[6],
        n33 = te[10],
        n34 = te[14];
    var n41 = te[3],
        n42 = te[7],
        n43 = te[11],
        n44 = te[15];

    //TODO: make this more efficient
    //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )

    return (n14 * n23 * n32 * n41 - n13 * n24 * n32 * n41 - n14 * n22 * n33 * n41 +
        n12 * n24 * n33 * n41 +
        n13 * n22 * n34 * n41 -
        n12 * n23 * n34 * n41 -
        n14 * n23 * n31 * n42 +
        n13 * n24 * n31 * n42 +
        n14 * n21 * n33 * n42 -
        n11 * n24 * n33 * n42 -
        n13 * n21 * n34 * n42 +
        n11 * n23 * n34 * n42 +
        n14 * n22 * n31 * n43 -
        n12 * n24 * n31 * n43 -
        n14 * n21 * n32 * n43 +
        n11 * n24 * n32 * n43 +
        n12 * n21 * n34 * n43 -
        n11 * n22 * n34 * n43 -
        n13 * n22 * n31 * n44 +
        n12 * n23 * n31 * n44 +
        n13 * n21 * n32 * n44 -
        n11 * n23 * n32 * n44 -
        n12 * n21 * n33 * n44 +
        n11 * n22 * n33 * n44);
  }

  /// Transposes this matrix.
  Matrix4 transpose() {
    var te = elements;
    var tmp;

    tmp = te[1];
    te[1] = te[4];
    te[4] = tmp;
    tmp = te[2];
    te[2] = te[8];
    te[8] = tmp;
    tmp = te[6];
    te[6] = te[9];
    te[9] = tmp;

    tmp = te[3];
    te[3] = te[12];
    te[12] = tmp;
    tmp = te[7];
    te[7] = te[13];
    te[13] = tmp;
    tmp = te[11];
    te[11] = te[14];
    te[14] = tmp;

    return this;
  }

  List flattenToArray(List flat) {
    var te = elements;

    flat[0] = te[0];
    flat[1] = te[1];
    flat[2] = te[2];
    flat[3] = te[3];
    flat[4] = te[4];
    flat[5] = te[5];
    flat[6] = te[6];
    flat[7] = te[7];
    flat[8] = te[8];
    flat[9] = te[9];
    flat[10] = te[10];
    flat[11] = te[11];
    flat[12] = te[12];
    flat[13] = te[13];
    flat[14] = te[14];
    flat[15] = te[15];

    return flat;
  }

  List flattenToArrayOffset(List flat, int offset) {
    var te = elements;

    flat[offset] = te[0];
    flat[offset + 1] = te[1];
    flat[offset + 2] = te[2];
    flat[offset + 3] = te[3];

    flat[offset + 4] = te[4];
    flat[offset + 5] = te[5];
    flat[offset + 6] = te[6];
    flat[offset + 7] = te[7];

    flat[offset + 8] = te[8];
    flat[offset + 9] = te[9];
    flat[offset + 10] = te[10];
    flat[offset + 11] = te[11];

    flat[offset + 12] = te[12];
    flat[offset + 13] = te[13];
    flat[offset + 14] = te[14];
    flat[offset + 15] = te[15];

    return flat;
  }

  Vector3 getPosition() => __v1.setValues(elements[12], elements[13], elements[14]);

  /// Sets the position component for this matrix from vector v.
  Matrix4 setPosition(Vector3 v) {
    var te = elements;

    te[12] = v.x;
    te[13] = v.y;
    te[14] = v.z;

    return this;
  }

  Vector3 getColumnX() => __v1.setValues(elements[0], elements[1], elements[2]);

  Vector3 getColumnY() => __v1.setValues(elements[4], elements[5], elements[6]);

  Vector3 getColumnZ() => __v1.setValues(elements[8], elements[9], elements[10]);

  /// Sets this matrix to the inverse of matrix m.
  ///
  /// Based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm.
  Matrix4 getInverse(Matrix4 m) {
    var te = elements;
    var me = m.elements;

    num n11 = me[0],
        n12 = me[4],
        n13 = me[8],
        n14 = me[12],
        n21 = me[1],
        n22 = me[5],
        n23 = me[9],
        n24 = me[13],
        n31 = me[2],
        n32 = me[6],
        n33 = me[10],
        n34 = me[14],
        n41 = me[3],
        n42 = me[7],
        n43 = me[11],
        n44 = me[15];

    te[0] = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;
    te[4] = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;
    te[8] = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;
    te[12] = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
    te[1] = n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44;
    te[5] = n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44;
    te[9] = n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44;
    te[13] = n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34;
    te[2] = n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44;
    te[6] = n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44;
    te[10] = n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44;
    te[14] = n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34;
    te[3] = n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43;
    te[7] = n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43;
    te[11] = n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43;
    te[15] = n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33;
    this.multiplyScalar(1 / m.determinant());
    return this;
  }

  /// Sets the rotation submatrix of this matrix to the rotation specified by
  /// Euler angles, the rest of the matrix is identity.
  ///
  /// Default order is "XYZ".
  Matrix4 setRotationFromEuler(Vector3 v, [String order = 'XYZ']) {
    var te = elements;
    num x = v.x,
        y = v.y,
        z = v.z,
        a = Math.cos(x),
        b = Math.sin(x),
        c = Math.cos(y),
        d = Math.sin(y),
        e = Math.cos(z),
        f = Math.sin(z);

    switch (order) {
      case 'YXZ':

        num ce = c * e,
            cf = c * f,
            de = d * e,
            df = d * f;

        te[0] = ce + df * b;
        te[4] = de * b - cf;
        te[8] = a * d;

        te[1] = a * f;
        te[5] = a * e;
        te[9] = -b;

        te[2] = cf * b - de;
        te[6] = df + ce * b;
        te[10] = a * c;
        break;

      case 'ZXY':

        num ce = c * e,
            cf = c * f,
            de = d * e,
            df = d * f;

        te[0] = ce - df * b;
        te[4] = -a * f;
        te[8] = de + cf * b;

        te[1] = cf + de * b;
        te[5] = a * e;
        te[9] = df - ce * b;

        te[2] = -a * d;
        te[6] = b;
        te[10] = a * c;
        break;

      case 'ZYX':

        num ae = a * e,
            af = a * f,
            be = b * e,
            bf = b * f;

        te[0] = c * e;
        te[4] = be * d - af;
        te[8] = ae * d + bf;

        te[1] = c * f;
        te[5] = bf * d + ae;
        te[9] = af * d - be;

        te[2] = -d;
        te[6] = b * c;
        te[10] = a * c;
        break;

      case 'YZX':

        num ac = a * c,
            ad = a * d,
            bc = b * c,
            bd = b * d;

        te[0] = c * e;
        te[4] = bd - ac * f;
        te[8] = bc * f + ad;

        te[1] = f;
        te[5] = a * e;
        te[9] = -b * e;

        te[2] = -d * e;
        te[6] = ad * f + bc;
        te[10] = ac - bd * f;
        break;

      case 'XZY':

        num ac = a * c,
            ad = a * d,
            bc = b * c,
            bd = b * d;

        te[0] = c * e;
        te[4] = -f;
        te[8] = d * e;

        te[1] = ac * f + bd;
        te[5] = a * e;
        te[9] = ad * f - bc;

        te[2] = bc * f - ad;
        te[6] = b * e;
        te[10] = bd * f + ac;
        break;

      default: // 'XYZ'

        num ae = a * e,
            af = a * f,
            be = b * e,
            bf = b * f;

        te[0] = c * e;
        te[4] = -c * f;
        te[8] = d;

        te[1] = af + be * d;
        te[5] = ae - bf * d;
        te[9] = -b * c;

        te[2] = bf - ae * d;
        te[6] = be + af * d;
        te[10] = a * c;
        break;

    }

    return this;
  }

  /// Sets the rotation submatrix of this matrix to the rotation specified by q. The rest of the matrix is identity.
  Matrix4 setRotationFromQuaternion(Quaternion q) {
    var te = this.elements;

    num x = q.x,
        y = q.y,
        z = q.z,
        w = q.w,
        x2 = x + x,
        y2 = y + y,
        z2 = z + z,
        xx = x * x2,
        xy = x * y2,
        xz = x * z2,
        yy = y * y2,
        yz = y * z2,
        zz = z * z2,
        wx = w * x2,
        wy = w * y2,
        wz = w * z2;

    te[0] = 1.0 - (yy + zz);
    te[4] = xy - wz;
    te[8] = xz + wy;

    te[1] = xy + wz;
    te[5] = 1.0 - (xx + zz);
    te[9] = yz - wx;

    te[2] = xz - wy;
    te[6] = yz + wx;
    te[10] = 1.0 - (xx + yy);

    return this;
  }

  /// Sets this matrix to the transformation composed of translation, quaternion and scale.
  Matrix4 compose(Vector3 translation, Quaternion rotation, Vector3 s) {

    var te = elements;

    Matrix4 mRotation = __m1;
    Matrix4 mScale = __m2;

    mRotation.identity();
    mRotation.setRotationFromQuaternion(rotation);

    mScale.makeScale(s.x, s.y, s.z);

    multiply(mRotation, mScale);

    te[12] = translation.x;
    te[13] = translation.y;
    te[14] = translation.z;

    return this;
  }

  /// Decomposes this matrix into the translation, quaternion and scale components.
  /// If parameters are not passed, new instances will be created.
  List decompose(Vector3 translation, Quaternion rotation, Vector3 scale) {

    var te = elements;

    // grab the axis vectors
    Vector3 x = __v1;
    Vector3 y = __v2;
    Vector3 z = __v3;

    x.setValues(te[0], te[1], te[2]);
    y.setValues(te[4], te[5], te[6]);
    z.setValues(te[8], te[9], te[10]);

    translation = (translation is Vector3) ? translation : new Vector3(0.0, 0.0, 0.0);
    rotation = (rotation is Quaternion) ? rotation : new Quaternion.identity();
    scale = (scale is Vector3) ? scale : new Vector3(0.0, 0.0, 0.0);

    scale.x = x.length();
    scale.y = y.length();
    scale.z = z.length();

    translation.x = te[12];
    translation.y = te[13];
    translation.z = te[14];

    // scale the rotation part
    Matrix4 matrix = __m1;

    matrix.copy(this);

    matrix.elements[0] /= scale.x;
    matrix.elements[1] /= scale.x;
    matrix.elements[2] /= scale.x;

    matrix.elements[4] /= scale.y;
    matrix.elements[5] /= scale.y;
    matrix.elements[6] /= scale.y;

    matrix.elements[8] /= scale.z;
    matrix.elements[9] /= scale.z;
    matrix.elements[10] /= scale.z;

    rotation.setFromRotationMatrix(matrix);

    return [translation, rotation, scale];
  }

  Matrix4 extractPosition(Matrix4 m) {
    var te = elements;
    var me = m.elements;

    te[12] = me[12];
    te[13] = me[13];
    te[14] = me[14];

    return this;
  }

  /// Extracts the rotation of the supplied matrix m into this matrix rotation component.
  Matrix4 extractRotation(Matrix4 m) {

    var te = elements;
    var me = m.elements;

    Vector3 vector = __v1;

    var scaleX = 1.0 / vector.setValues(me[0], me[1], me[2]).length();
    var scaleY = 1.0 / vector.setValues(me[4], me[5], me[6]).length();
    var scaleZ = 1.0 / vector.setValues(me[8], me[9], me[10]).length();

    te[0] = me[0] * scaleX;
    te[1] = me[1] * scaleX;
    te[2] = me[2] * scaleX;

    te[4] = me[4] * scaleY;
    te[5] = me[5] * scaleY;
    te[6] = me[6] * scaleY;

    te[8] = me[8] * scaleZ;
    te[9] = me[9] * scaleZ;
    te[10] = me[10] * scaleZ;

    return this;
  }

  /// Sets this matrix as translation transform.
  Matrix4 translate(Vector3 v) {
    var te = elements;
    var x = v.x,
        y = v.y,
        z = v.z;

    te[12] = te[0] * x + te[4] * y + te[8] * z + te[12];
    te[13] = te[1] * x + te[5] * y + te[9] * z + te[13];
    te[14] = te[2] * x + te[6] * y + te[10] * z + te[14];
    te[15] = te[3] * x + te[7] * y + te[11] * z + te[15];

    return this;
  }

  /// Sets this matrix as rotation transform around x axis by theta radians.
  Matrix4 rotateX(num angle) {
    var te = elements;
    var m12 = te[4];
    var m22 = te[5];
    var m32 = te[6];
    var m42 = te[7];
    var m13 = te[8];
    var m23 = te[9];
    var m33 = te[10];
    var m43 = te[11];
    var c = Math.cos(angle);
    var s = Math.sin(angle);

    te[4] = c * m12 + s * m13;
    te[5] = c * m22 + s * m23;
    te[6] = c * m32 + s * m33;
    te[7] = c * m42 + s * m43;

    te[8] = c * m13 - s * m12;
    te[9] = c * m23 - s * m22;
    te[10] = c * m33 - s * m32;
    te[11] = c * m43 - s * m42;

    return this;
  }

  /// Sets this matrix as rotation transform around y axis by theta radians.
  Matrix4 rotateY(num angle) {
    var te = elements;
    var m11 = te[0];
    var m21 = te[1];
    var m31 = te[2];
    var m41 = te[3];
    var m13 = te[8];
    var m23 = te[9];
    var m33 = te[10];
    var m43 = te[11];
    var c = Math.cos(angle);
    var s = Math.sin(angle);

    te[0] = c * m11 - s * m13;
    te[1] = c * m21 - s * m23;
    te[2] = c * m31 - s * m33;
    te[3] = c * m41 - s * m43;

    te[8] = c * m13 + s * m11;
    te[9] = c * m23 + s * m21;
    te[10] = c * m33 + s * m31;
    te[11] = c * m43 + s * m41;

    return this;
  }

  /// Sets this matrix as rotation transform around z axis by theta radians.
  Matrix4 rotateZ(num angle) {
    var te = elements;
    var m11 = te[0];
    var m21 = te[1];
    var m31 = te[2];
    var m41 = te[3];
    var m12 = te[4];
    var m22 = te[5];
    var m32 = te[6];
    var m42 = te[7];
    var c = Math.cos(angle);
    var s = Math.sin(angle);

    te[0] = c * m11 + s * m12;
    te[1] = c * m21 + s * m22;
    te[2] = c * m31 + s * m32;
    te[3] = c * m41 + s * m42;

    te[4] = c * m12 - s * m11;
    te[5] = c * m22 - s * m21;
    te[6] = c * m32 - s * m31;
    te[7] = c * m42 - s * m41;

    return this;
  }

  /// Sets this matrix as rotation transform around axis by angle radians.
  ///
  /// Based on http://www.gamedev.net/reference/articles/article1199.asp.
  Matrix4 rotateByAxis(Vector3 axis, num angle) {
    var te = elements;

    // optimize by checking axis
    if (axis.x == 1.0 && axis.y == 0.0 && axis.z == 0.0) {
      return rotateX(angle);
    } else if (axis.x == 0.0 && axis.y == 1.0 && axis.z == 0.0) {
      return rotateY(angle);
    } else if (axis.x == 0.0 && axis.y == 0.0 && axis.z == 1.0) {
      return rotateZ(angle);
    }

    num x = axis.x,
        y = axis.y,
        z = axis.z,
        n = Math.sqrt(x * x + y * y + z * z);

    x /= n;
    y /= n;
    z /= n;

    num xx = x * x,
        yy = y * y,
        zz = z * z,
        c = Math.cos(angle),
        s = Math.sin(angle),
        oneMinusCosine = 1.0 - c,
        xy = x * y * oneMinusCosine,
        xz = x * z * oneMinusCosine,
        yz = y * z * oneMinusCosine,
        xs = x * s,
        ys = y * s,
        zs = z * s,

        r11 = xx + (1 - xx) * c,
        r21 = xy + zs,
        r31 = xz - ys,
        r12 = xy - zs,
        r22 = yy + (1 - yy) * c,
        r32 = yz + xs,
        r13 = xz + ys,
        r23 = yz - xs,
        r33 = zz + (1 - zz) * c;

    var m11 = te[0],
        m21 = te[1],
        m31 = te[2],
        m41 = te[3];
    var m12 = te[4],
        m22 = te[5],
        m32 = te[6],
        m42 = te[7];
    var m13 = te[8],
        m23 = te[9],
        m33 = te[10],
        m43 = te[11];
    var m14 = te[12],
        m24 = te[13],
        m34 = te[14],
        m44 = te[15];

    te[0] = r11 * m11 + r21 * m12 + r31 * m13;
    te[1] = r11 * m21 + r21 * m22 + r31 * m23;
    te[2] = r11 * m31 + r21 * m32 + r31 * m33;
    te[3] = r11 * m41 + r21 * m42 + r31 * m43;

    te[4] = r12 * m11 + r22 * m12 + r32 * m13;
    te[5] = r12 * m21 + r22 * m22 + r32 * m23;
    te[6] = r12 * m31 + r22 * m32 + r32 * m33;
    te[7] = r12 * m41 + r22 * m42 + r32 * m43;

    te[8] = r13 * m11 + r23 * m12 + r33 * m13;
    te[9] = r13 * m21 + r23 * m22 + r33 * m23;
    te[10] = r13 * m31 + r23 * m32 + r33 * m33;
    te[11] = r13 * m41 + r23 * m42 + r33 * m43;


    return this;
  }

  /// Sets this matrix as scale transform.
  Matrix4 scale(Vector3 v) {

    var te = elements;
    num x = v.x,
        y = v.y,
        z = v.z;

    te[0] *= x;
    te[4] *= y;
    te[8] *= z;
    te[1] *= x;
    te[5] *= y;
    te[9] *= z;
    te[2] *= x;
    te[6] *= y;
    te[10] *= z;
    te[3] *= x;
    te[7] *= y;
    te[11] *= z;

    return this;
  }

  /// Gets the max scale value of the 3 axes.
  double getMaxScaleOnAxis() {

    var te = elements;

    var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
    var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
    var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10];

    return Math.sqrt(Math.max(scaleXSq, Math.max(scaleYSq, scaleZSq)));

  }

  /// Sets this matrix as translation transform.
  Matrix4 makeTranslation(num x, num y, num z) {
    setValues(1.0, 0.0, 0.0, x, 0.0, 1.0, 0.0, y, 0.0, 0.0, 1.0, z, 0.0, 0.0, 0.0, 1.0);

    return this;
  }

  /// Sets this matrix as rotation transform around x axis by theta radians.
  Matrix4 makeRotationX(num theta) {
    num c = Math.cos(theta),
        s = Math.sin(theta);

    setValues(1.0, 0.0, 0.0, 0.0, 0.0, c, -s, 0.0, 0.0, s, c, 0.0, 0.0, 0.0, 0.0, 1.0);

    return this;
  }

  /// Sets this matrix as rotation transform around y axis by theta radians.
  Matrix4 makeRotationY(num theta) {
    num c = Math.cos(theta),
        s = Math.sin(theta);

    setValues(c, 0.0, s, 0.0, 0.0, 1.0, 0.0, 0.0, -s, 0.0, c, 0.0, 0.0, 0.0, 0.0, 1.0);

    return this;
  }

  ///  Sets this matrix as rotation transform around z axis by theta radians.
  Matrix4 makeRotationZ(num theta) {
    num c = Math.cos(theta),
        s = Math.sin(theta);

    setValues(c, -s, 0.0, 0.0, s, c, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);

    return this;
  }

  /// Sets this matrix as rotation transform around axis by angle radians.
  ///
  /// Based on http://www.gamedev.net/reference/articles/article1199.asp.
  Matrix4 makeRotationAxis(Vector3 axis, num angle) {
    num c = Math.cos(angle),
        s = Math.sin(angle),
        t = 1.0 - c,
        x = axis.x,
        y = axis.y,
        z = axis.z,
        tx = t * x,
        ty = t * y;

    setValues(
        tx * x + c,
        tx * y - s * z,
        tx * z + s * y,
        0.0,
        tx * y + s * z,
        ty * y + c,
        ty * z - s * x,
        0.0,
        tx * z - s * y,
        ty * z + s * x,
        t * z * z + c,
        0.0,
        0.0,
        0.0,
        0.0,
        1.0);

    return this;
  }

  /// Sets this matrix as scale transform.
  Matrix4 makeScale(num x, num y, num z) {
    setValues(x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, 1.0);

    return this;
  }

  /// Creates a frustum matrix.
  Matrix4 makeFrustum(num left, num right, num bottom, num top, num near, num far) {
    var te = elements;

    num x, y, a, b, c, d;

    x = 2 * near / (right - left);
    y = 2 * near / (top - bottom);

    a = (right + left) / (right - left);
    b = (top + bottom) / (top - bottom);
    c = -(far + near) / (far - near);
    d = -2 * far * near / (far - near);

    te[0] = x;
    te[4] = 0.0;
    te[8] = a;
    te[12] = 0.0;
    te[1] = 0.0;
    te[5] = y;
    te[9] = b;
    te[13] = 0.0;
    te[2] = 0.0;
    te[6] = 0.0;
    te[10] = c;
    te[14] = d;
    te[3] = 0.0;
    te[7] = 0.0;
    te[11] = -1.0;
    te[15] = 0.0;

    return this;
  }

  Matrix4 makePerspective(num fov, num aspect, num near, num far) {
    num ymax, ymin, xmin, xmax;

    ymax = near * Math.tan(fov * Math.PI / 360);
    ymin = -ymax;
    xmin = ymin * aspect;
    xmax = ymax * aspect;

    return makeFrustum(xmin, xmax, ymin, ymax, near, far);
  }

  /// Creates an orthographic projection matrix.
  Matrix4 makeOrthographic(num left, num right, num top, num bottom, num near, num far) {
    var te = elements;

    num x, y, z, w, h, p;

    w = right - left;
    h = top - bottom;
    p = far - near;

    x = (right + left) / w;
    y = (top + bottom) / h;
    z = (far + near) / p;

    te[0] = 2 / w;
    te[4] = 0.0;
    te[8] = 0.0;
    te[12] = -x;
    te[1] = 0.0;
    te[5] = 2 / h;
    te[9] = 0.0;
    te[13] = -y;
    te[2] = 0.0;
    te[6] = 0.0;
    te[10] = -2 / p;
    te[14] = -z;
    te[3] = 0.0;
    te[7] = 0.0;
    te[11] = 0.0;
    te[15] = 1.0;

    return this;
  }

  /// Clones this matrix.
  Matrix4 clone() {
    var te = elements;

    return new Matrix4(
        te[0],
        te[4],
        te[8],
        te[12],
        te[1],
        te[5],
        te[9],
        te[13],
        te[2],
        te[6],
        te[10],
        te[14],
        te[3],
        te[7],
        te[11],
        te[15]);
  }

  //TODO: Fix "Expected Constant Expression" problem

  // Axis Vectors, X, Y, Z
  static Vector3 ___v1;
  static Vector3 ___v2;
  static Vector3 ___v3;

  // Rotation, Scale
  static Matrix4 ___m1;
  static Matrix4 ___m2;

  static Vector3 get __v1 {
    if (___v1 == null) {
      ___v1 = new Vector3(0.0, 0.0, 0.0);
    }
    return ___v1;
  }

  static Vector3 get __v2 {
    if (___v2 == null) {
      ___v2 = new Vector3(0.0, 0.0, 0.0);
    }
    return ___v2;
  }

  static Vector3 get __v3 {
    if (___v3 == null) {
      ___v3 = new Vector3(0.0, 0.0, 0.0);
    }
    return ___v3;
  }

  static Matrix4 get __m1 {
    if (___m1 == null) {
      ___m1 = new Matrix4.identity();
    }
    return ___m1;
  }

  static Matrix4 get __m2 {
    if (___m2 == null) {
      ___m2 = new Matrix4.identity();
    }
    return ___m2;
  }
}


<|start_filename|>lib/extras/geometries/extrude_geometry.dart<|end_filename|>
part of three;

/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 * Creates extruded geometry from a path shape.
 *
 * parameters = {
 *
 *  size:       <float>,  // size of the text
 *  height:     <float>,  // thickness to extrude text
 *  curveSegments:  <int>,    // number of points on the curves
 *  steps:      <int> | <List>,    // number of points or list of U positions for z-side extrusions / used for subdividing segements of extrude spline too
 *  amount: <int>,  // Amount
 *
 *  bevelEnabled: <bool>,     // turn on bevel
 *  bevelThickness: <float>,    // how deep into text bevel goes
 *  bevelSize:    <float>,    // how far from text outline is bevel
 *  bevelSegments:  <int>,      // number of bevel layers
 *
 *  extrudePath:  <THREE.CurvePath> // 2d/3d spline path to extrude shape orthogonality to
 *  frames: <THREE.TubeGeometry.FrenetFrames> // containing arrays of tangents, normals, binormals
 *
 *  bendPath:   <THREE.CurvePath>   // 2d path for bend the shape around x/y plane
 *
 *  material:    <int>  // material index for front and back faces
 *  extrudeMaterial: <int>  // material index for extrusion and beveled faces
 *
 *  }
  **/

class ExtrudeGeometry extends Geometry {

  List shapes;

  var shapebb;

  ExtrudeGeometry(this.shapes, {amount: 100, bevelThickness: 6.0, bevelSize: null, bevelSegments: 3, bevelEnabled: true,
      curveSegments: 12, steps: 1, //can assume a number of steps or a List with all U's of steps
  bendPath, extrudePath, frames, material, extrudeMaterial}) : super() {

    if (bevelSize == null) bevelSize = bevelThickness - 2.0;

    if (shapes == null) {
      shapes = [];
      return;
    }

    shapebb = shapes.last.getBoundingBox();

    addShapeList(
        shapes,
        amount,
        bevelThickness,
        bevelSize,
        bevelSegments,
        bevelEnabled,
        curveSegments,
        steps,
        bendPath,
        extrudePath,
        frames,
        material,
        extrudeMaterial);

    computeCentroids();
    computeFaceNormals();

    // can't really use automatic vertex normals
    // as then front and back sides get smoothed too
    // should do separate smoothing just for sides

    //this.computeVertexNormals();

    //console.log( "took", ( Date.now() - startTime ) );

  }



  addShapeList(List shapes, num amount, num bevelThickness, double bevelSize, int bevelSegments, bool bevelEnabled,
      curveSegments, steps, bendPath, Curve extrudePath, TubeGeometry frames, int material, int extrudeMaterial) {
    var sl = shapes.length;

    for (var s = 0; s < sl; s++) {
      var shape = shapes[s];
      addShape(
          shape,
          amount,
          bevelThickness,
          bevelSize,
          bevelSegments,
          bevelEnabled,
          curveSegments,
          steps,
          bendPath,
          extrudePath,
          frames,
          material,
          extrudeMaterial);
    }
  }

  // addShape Helpers
  _scalePt2(Vector2 pt, Vector2 vec, num size) {
    if (vec == null) print("die");
    return vec.clone().scale(size).add(pt);
  }

  _getBevelVec2(Vector2 pt_i, Vector2 pt_j, Vector2 pt_k) {

    var a = ExtrudeGeometry.__v1,
        b = ExtrudeGeometry.__v2,
        v_hat = ExtrudeGeometry.__v3,
        w_hat = ExtrudeGeometry.__v4,
        p = ExtrudeGeometry.__v5,
        q = ExtrudeGeometry.__v6,
        v,
        w,
        v_dot_w_hat,
        q_sub_p_dot_w_hat,
        s,
        intersection;

    // good reading for line-line intersection
    // http://sputsoft.com/blog/2010/03/line-line-intersection.html

    // define a as vector j->i
    // define b as vectot k->i

    a.setValues(pt_i.x - pt_j.x, pt_i.y - pt_j.y);
    b.setValues(pt_i.x - pt_k.x, pt_i.y - pt_k.y);

    // get unit vectors

    v = a.normalize();
    w = b.normalize();

    // normals from pt i

    v_hat.setValues(-v.y, v.x);
    w_hat.setValues(w.y, -w.x);

    // pts from i

    p.setFrom(pt_i).add(v_hat);
    q.setFrom(pt_i).add(w_hat);

    if (p.x == q.x && p.y == q.y) { // TODO add vector_math ".equals(p, q)"

      //console.log("Warning: lines are straight");
      return w_hat.clone();

    }

    // Points from j, k. helps prevents points cross overover most of the time

    p.setFrom(pt_j).add(v_hat);
    q.setFrom(pt_k).add(w_hat);

    v_dot_w_hat = v.dot(w_hat);
    q_sub_p_dot_w_hat = q.sub(p).dot(w_hat);

    // We should not reach these conditions

    if (v_dot_w_hat == 0) {

      print("Either infinite or no solutions!");

      if (q_sub_p_dot_w_hat == 0) {

        print("Its finite solutions.");

      } else {

        print("Too bad, no solutions.");

      }

    }

    s = q_sub_p_dot_w_hat / v_dot_w_hat;

    if (s < 0) {

      // in case of emergecy, revert to algorithm 1.

      return _getBevelVec1(pt_i, pt_j, pt_k);

    }

    intersection = v.scale(s).add(p);

    return intersection.sub(pt_i).clone(); // Don't normalize!, otherwise sharp corners become ugly

  }


  static var RAD_TO_DEGREES = 180 / Math.PI;


// Algorithm 2
  _getBevelVec(pt_i, pt_j, pt_k) => _getBevelVec2(pt_i, pt_j, pt_k);

  _getBevelVec1(pt_i, pt_j, pt_k) {

    var anglea = Math.atan2(pt_j.y - pt_i.y, pt_j.x - pt_i.x);
    var angleb = Math.atan2(pt_k.y - pt_i.y, pt_k.x - pt_i.x);

    if (anglea > angleb) {

      angleb += Math.PI * 2;

    }

    var anglec = (anglea + angleb) / 2;
    var x = -Math.cos(anglec);
    var y = -Math.sin(anglec);

    var vec = new Vector2(x, y); //.normalize();

    return vec;

  }

  _v(x, y, z) {
    vertices.add(new Vector3(x, y, z));
  }


  // TODO - This is a helper function to reverse a list added by nelsonsilva
  List _reverse(List list) {
    List reversed = [];
    var i = list.length;
    while (i > 0) {
      reversed.add(list[--i]);
    }
    return reversed;
  }

  addShape(Shape shape, num amount, num bevelThickness, double bevelSize, int bevelSegments, bool bevelEnabled,
      curveSegments, steps, bendPath, Curve extrudePath, TubeGeometry frames, int material, int extrudeMaterial,
      {ExtrudeGeometryWorldUVGenerator UVGenerator}) {


    var extrudePts,
        extrudeByPath = false;

    //shapebb = shape.getBoundingBox();

    // set UV generator
    var uvgen = (UVGenerator != null) ? UVGenerator : new ExtrudeGeometryWorldUVGenerator();

    TubeGeometry splineTube;
    Vector3 binormal, normal, position2;

    var nSteps = (steps is List) ? steps.length : steps;

    if (extrudePath != null) {

      if (steps is List) {
        List divisions = [0];
        divisions.addAll(steps);
        extrudePts = extrudePath.getUPoints(divisions);
      } else {
        extrudePts = extrudePath.getSpacedPoints(steps);
      }

      extrudeByPath = true;
      bevelEnabled = false; // bevels not supported for path extrusion

      // SETUP TNB variables

      // Reuse TNB from TubeGeomtry for now.
      // TODO1 - have a .isClosed in spline?
      splineTube = (frames != null) ? frames : new TubeGeometry.FrenetFrames(extrudePath, steps, false);
      binormal = new Vector3.zero();
      normal = new Vector3.zero();
      position2 = new Vector3.zero();

    }

    // Safeguards if bevels are not enabled

    if (!bevelEnabled) {

      bevelSegments = 0;
      bevelThickness = 0.0;
      bevelSize = 0.0;

    }

    // Variables initalization

    List<Vector2> ahole;
    var h, hl; // looping of holes

    var bevelPoints = [];

    var shapesOffset = this.vertices.length;

    if (bendPath != null) {

      shape.addWrapPath(bendPath);

    }

    var shapePoints = shape.extractPoints();

    List vertices = shapePoints["shape"];
    List<List<Vector2>> holes = shapePoints["holes"];

    var reverse = !ShapeUtils.isClockWise(vertices);

    if (reverse) {

      vertices = _reverse(vertices);

      // Maybe we should also check if holes are in the opposite direction, just to be safe ...

      for (h = 0; h < holes.length; h++) {

        ahole = holes[h];

        if (ShapeUtils.isClockWise(ahole)) {

          holes[h] = _reverse(ahole);

        }

      }

      reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)!

    }



    var faces = ShapeUtils.triangulateShape(vertices, holes);
    //var faces = THREE.Shape.Utils.triangulate2( vertices, holes );

    // Would it be better to move points after triangulation?
    // shapePoints = shape.extractAllPointsWithBend( curveSegments, bendPath );
    //  vertices = shapePoints.shape;
    //  holes = shapePoints.holes;

    //console.log(faces);

    ////
    ///   Handle Vertices
    ////

    var contour = vertices; // vertices has all points but contour has only points of circumference

    for (h = 0; h < holes.length; h++) {

      ahole = holes[h];

      vertices = new List.from(vertices);
      vertices.addAll(ahole);

    }


    var b,
        bs,
        t,
        z,
        vert,
        vlen = vertices.length,
        face,
        flen = faces.length,
        cont,
        clen = contour.length;


    //------
    // Find directions for point movement
    //



    var contourMovements = new List(contour.length);

    num i = 0,
        il = contour.length,
        j = il - 1,
        k = i + 1;
    for (i = 0; i < il; i++) {

      if (j == il) j = 0;
      if (k == il) k = 0;

      //  (j)---(i)---(k)
      // console.log('i,j,k', i, j , k)

      var pt_i = contour[i];
      var pt_j = contour[j];
      var pt_k = contour[k];

      contourMovements[i] = _getBevelVec(contour[i], contour[j], contour[k]);
      j++;
      k++;
    }

    List holesMovements = [],
        oneHoleMovements,
        verticesMovements = new List.from(contourMovements);

    for (h = 0; h < holes.length; h++) {

      ahole = holes[h];

      oneHoleMovements = new List(ahole.length);

      i = 0;
      il = ahole.length;
      j = il - 1;
      k = i + 1;

      for (i = 0; i < il; i++) {

        if (j == il) j = 0;
        if (k == il) k = 0;

        //  (j)---(i)---(k)
        oneHoleMovements[i] = _getBevelVec(ahole[i], ahole[j], ahole[k]);
        j++;
        k++;
      }

      holesMovements.add(oneHoleMovements);
      verticesMovements.addAll(oneHoleMovements);

    }


    // Loop bevelSegments, 1 for the front, 1 for the back

    for (b = 0; b < bevelSegments; b++) {
      //for ( b = bevelSegments; b > 0; b -- ) {

      t = b / bevelSegments;
      z = bevelThickness * (1 - t);

      //z = bevelThickness * t;
      bs = bevelSize * (Math.sin(t * Math.PI / 2)); // curved
      //bs = bevelSize * t ; // linear

      // contract shape

      for (i = 0; i < contour.length; i++) {

        vert = _scalePt2(contour[i], contourMovements[i], bs);
        //vert = scalePt( contour[ i ], contourCentroid, bs, false );
        _v(vert.x, vert.y, -z);

      }

      // expand holes

      for (h = 0; h < holes.length; h++) {

        ahole = holes[h];
        oneHoleMovements = holesMovements[h];

        for (i = 0; i < ahole.length; i++) {

          vert = _scalePt2(ahole[i], oneHoleMovements[i], bs);
          //vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true );

          _v(vert.x, vert.y, -z);

        }

      }

    }


    bs = bevelSize;

    // Back facing vertices

    for (i = 0; i < vlen; i++) {

      vert = bevelEnabled ? _scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i];

      if (!extrudeByPath) {

        _v(vert.x, vert.y, 0.0);

      } else {

        // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );

        normal.setFrom(splineTube.normals[0]).scale(vert.x);
        binormal.setFrom(splineTube.binormals[0]).scale(vert.y);

        position2.setFrom(extrudePts[0]).add(normal).add(binormal);

        _v(position2.x, position2.y, position2.z);

      }

    }

    // Add stepped vertices...
    // Including front facing vertices

    var s;

    for (s = 1; s <= nSteps; s++) {

      for (i = 0; i < vlen; i++) {

        vert = bevelEnabled ? _scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i];

        if (!extrudeByPath) {

          _v(vert.x, vert.y, amount / nSteps * s);

        } else {

          // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );

          normal.setFrom(splineTube.normals[s]).scale(vert.x);
          binormal.setFrom(splineTube.binormals[s]).scale(vert.y);

          position2.setFrom(extrudePts[s]).add(normal).add(binormal);

          _v(position2.x, position2.y, position2.z);

        }

      }

    }


    // Add bevel segments planes

    //for ( b = 1; b <= bevelSegments; b ++ ) {
    for (b = bevelSegments - 1; b >= 0; b--) {

      t = b / bevelSegments;
      z = bevelThickness * (1 - t);
      //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) );
      bs = bevelSize * Math.sin(t * Math.PI / 2);

      // contract shape

      for (i = 0; i < contour.length; i++) {

        vert = _scalePt2(contour[i], contourMovements[i], bs);
        _v(vert.x, vert.y, amount + z);

      }

      // expand holes

      for (h = 0; h < holes.length; h++) {

        ahole = holes[h];
        oneHoleMovements = holesMovements[h];

        for (i = 0; i < ahole.length; i++) {

          vert = _scalePt2(ahole[i], oneHoleMovements[i], bs);

          if (!extrudeByPath) {

            _v(vert.x, vert.y, amount + z);

          } else {

            _v(vert.x, vert.y + extrudePts[nSteps - 1].y, extrudePts[nSteps - 1].x + z);

          }

        }

      }

    }


    ////
    ///   Handle Faces
    ////

    /////  Internal functions

    f3(a, b, c, isBottom) {
      a += shapesOffset;
      b += shapesOffset;
      c += shapesOffset;

      // normal, color, material
      this.faces.add(new Face3(a, b, c, null, null, material));

      var uvs =
          isBottom ? uvgen.generateBottomUV(this, shape, null, a, b, c) : uvgen.generateTopUV(this, shape, null, a, b, c);

      this.faceVertexUvs[0].add(uvs);
    }

    f4(a, b, c, d, wallContour, stepIndex, stepsLength) {
      a += shapesOffset;
      b += shapesOffset;
      c += shapesOffset;
      d += shapesOffset;

      this.faces.add(new Face4(a, b, c, d, null, null, extrudeMaterial));

      var uvs = uvgen.generateSideWallUV(this, shape, wallContour, null, a, b, c, d, stepIndex, stepsLength);
      this.faceVertexUvs[0].add(uvs);
    }

    // Top and bottom faces
    //buildLidFaces() {
    if (bevelEnabled) {

      var layer = 0; // steps + 1
      var offset = vlen * layer;

      // Bottom faces

      for (i = 0; i < flen; i++) {

        face = faces[i];
        f3(face[2] + offset, face[1] + offset, face[0] + offset, true);

      }

      layer = nSteps + bevelSegments * 2;
      offset = vlen * layer;

      // Top faces

      for (i = 0; i < flen; i++) {
        face = faces[i];
        f3(face[0] + offset, face[1] + offset, face[2] + offset, false);
      }
    } else {

      // Bottom faces

      for (i = 0; i < flen; i++) {
        face = faces[i];
        f3(face[2], face[1], face[0], true);
      }

      // Top faces

      for (i = 0; i < flen; i++) {
        face = faces[i];
        f3(face[0] + vlen * nSteps, face[1] + vlen * nSteps, face[2] + vlen * nSteps, false);
      }
    }

    sidewalls(List contour, int layeroffset) {
      var i, j, k;
      i = contour.length;

      while (--i >= 0) {
        j = i;
        k = i - 1;
        if (k < 0) k = contour.length - 1;

        //console.log('b', i,j, i-1, k,vertices.length);

        var s = 0,
            sl = nSteps + bevelSegments * 2;

        for (s = 0; s < sl; s++) {
          var slen1 = vlen * s;
          var slen2 = vlen * (s + 1);
          var a = layeroffset + j + slen1,
              b = layeroffset + k + slen1,
              c = layeroffset + k + slen2,
              d = layeroffset + j + slen2;

          f4(a, b, c, d, contour, s, sl);
        }
      }
    }

    // Sides faces
    //buildSideFaces() {
    // Create faces for the z-sides of the shape
    var layeroffset = 0;
    sidewalls(contour, layeroffset);
    layeroffset += contour.length;

    for (h = 0; h < holes.length; h++) {
      ahole = holes[h];
      sidewalls(ahole, layeroffset);

      //, true
      layeroffset += ahole.length;
    }
  }


  static Vector2 ___v1 = null;
  static get __v1 => (___v1 == null) ? ___v1 = new Vector2.zero() : ___v1;
  static Vector2 ___v2 = null;
  static get __v2 => (___v2 == null) ? ___v2 = new Vector2.zero() : ___v2;
  static Vector2 ___v3 = null;
  static get __v3 => (___v3 == null) ? ___v3 = new Vector2.zero() : ___v3;
  static Vector2 ___v4 = null;
  static get __v4 => (___v4 == null) ? ___v4 = new Vector2.zero() : ___v4;
  static Vector2 ___v5 = null;
  static get __v5 => (___v5 == null) ? ___v5 = new Vector2.zero() : ___v5;
  static Vector2 ___v6 = null;
  static get __v6 => (___v6 == null) ? ___v6 = new Vector2.zero() : ___v6;
}

class ExtrudeGeometryWorldUVGenerator {
  List<UV> generateTopUV(Geometry geometry, extrudedShape, extrudeOptions, int indexA, int indexB, int indexC) {
    var ax = geometry.vertices[indexA].x,
        ay = geometry.vertices[indexA].y,

        bx = geometry.vertices[indexB].x,
        by = geometry.vertices[indexB].y,

        cx = geometry.vertices[indexC].x,
        cy = geometry.vertices[indexC].y;

    return [new UV(ax, 1 - ay), new UV(bx, 1 - by), new UV(cx, 1 - cy)];
  }

  List<UV> generateBottomUV(Geometry geometry, extrudedShape, extrudeOptions, int indexA, int indexB, int indexC) {
    return generateTopUV(geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC);
  }

  List<UV> generateSideWallUV(Geometry geometry, extrudedShape, wallContour, extrudeOptions, int indexA, int indexB,
      int indexC, int indexD, stepIndex, stepsLength) {
    var ax = geometry.vertices[indexA].x,
        ay = geometry.vertices[indexA].y,
        az = geometry.vertices[indexA].z,

        bx = geometry.vertices[indexB].x,
        by = geometry.vertices[indexB].y,
        bz = geometry.vertices[indexB].z,

        cx = geometry.vertices[indexC].x,
        cy = geometry.vertices[indexC].y,
        cz = geometry.vertices[indexC].z,

        dx = geometry.vertices[indexD].x,
        dy = geometry.vertices[indexD].y,
        dz = geometry.vertices[indexD].z;

    if ((ay - by).abs() < 0.01) {
      return [new UV(ax, az), new UV(bx, bz), new UV(cx, cz), new UV(dx, dz)];
    } else {
      return [new UV(ay, az), new UV(by, bz), new UV(cy, cz), new UV(dy, dz)];
    }
  }
}




<|start_filename|>lib/extras/shaders/bokeh_shader2.dart<|end_filename|>
part of three_shaders;

/**
 * @author zz85 / https://github.com/zz85 | twitter.com/blurspline
 *
 * Depth-of-field shader with bokeh
 * ported from GLSL shader by <NAME>
 * http://blenderartists.org/forum/showthread.php?237488-GLSL-depth-of-field-with-bokeh-v2-4-(update)
 *
 * Requires #define RINGS and SAMPLES integers
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */



var BokehShader2 = {

  'uniforms': {

    "textureWidth":  { 'type': "f", 'value': 1.0 },
    "textureHeight":  { 'type': "f", 'value': 1.0 },

    "focalDepth":   { 'type': "f", 'value': 1.0 },
    "focalLength":   { 'type': "f", 'value': 24.0 },
    "fstop": { 'type': "f", 'value': 0.9 },

    "tColor":   { 'type': "t", 'value': null },
    "tDepth":   { 'type': "t", 'value': null },

    "maxblur":  { 'type': "f", 'value': 1.0 },

    "showFocus":   { 'type': "i", 'value': 0 },
    "manualdof":   { 'type': "i", 'value': 0 },
    "vignetting":   { 'type': "i", 'value': 0 },
    "depthblur":   { 'type': "i", 'value': 0 },

    "threshold":  { 'type': "f", 'value': 0.5 },
    "gain":  { 'type': "f", 'value': 2.0 },
    "bias":  { 'type': "f", 'value': 0.5 },
    "fringe":  { 'type': "f", 'value': 0.7 },

    "znear":  { 'type': "f", 'value': 0.1 },
    "zfar":  { 'type': "f", 'value': 100 },

    "noise":  { 'type': "i", 'value': 1 },
    "dithering":  { 'type': "f", 'value': 0.0001 },
    "pentagon": { 'type': "i", 'value': 0 },

    "shaderFocus":  { 'type': "i", 'value': 1 },
    "focusCoords":  { 'type': "v2", 'value': new Vector2.zero()},


  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "varying vec2 vUv;",

    "uniform sampler2D tColor;",
    "uniform sampler2D tDepth;",
    "uniform float textureWidth;",
    "uniform float textureHeight;",

    "const float PI = 3.14159265;",

    "float width = textureWidth; //texture width",
    "float height = textureHeight; //texture height",

    "vec2 texel = vec2(1.0/width,1.0/height);",

    "uniform float focalDepth;  //focal distance 'value' in meters, but you may use autofocus option below",
    "uniform float focalLength; //focal length in mm",
    "uniform float fstop; //f-stop 'value'",
    "uniform bool showFocus; //show debug focus point and focal range (red = focal point, green = focal range)",

    "/*",
    "make sure that these two 'value's are the same for your camera, otherwise distances will be wrong.",
    "*/",

    "uniform float znear; // camera clipping start",
    "uniform float zfar; // camera clipping end",

    "//------------------------------------------",
    "//user variables",

    "const int samples = SAMPLES; //samples on the first ring",
    "const int rings = RINGS; //ring count",

    "const int maxringsamples = rings * samples;",

    "uniform bool manualdof; // manual dof calculation",
    "float ndofstart = 1.0; // near dof blur start",
    "float ndofdist = 2.0; // near dof blur falloff distance",
    "float fdofstart = 1.0; // far dof blur start",
    "float fdofdist = 3.0; // far dof blur falloff distance",

    "float CoC = 0.03; //circle of confusion size in mm (35mm film = 0.03mm)",

    "uniform bool vignetting; // use optical lens vignetting",

    "float vignout = 1.3; // vignetting outer border",
    "float vignin = 0.0; // vignetting inner border",
    "float vignfade = 22.0; // f-stops till vignete fades",

    "uniform bool shaderFocus;",

    "bool autofocus = shaderFocus;",
    "//use autofocus in shader - use with focusCoords",
    "// disable if you use external focalDepth 'value'",

    "uniform vec2 focusCoords;",
    "// autofocus point on screen (0.0,0.0 - left lower corner, 1.0,1.0 - upper right)",
    "// if center of screen use vec2(0.5, 0.5);",

    "uniform float maxblur;",
    "//clamp 'value' of max blur (0.0 = no blur, 1.0 default)",

    "uniform float threshold; // highlight threshold;",
    "uniform float gain; // highlight gain;",

    "uniform float bias; // bokeh edge bias",
    "uniform float fringe; // bokeh chromatic aberration / fringing",

    "uniform bool noise; //use noise instead of pattern for sample dithering",

    "uniform float dithering;",
    "float namount = dithering; //dither amount",

    "uniform bool depthblur; // blur the depth buffer",
    "float dbsize = 1.25; // depth blur size",

    "/*",
    "next part is experimental",
    "not looking good with small sample and ring count",
    "looks okay starting from samples = 4, rings = 4",
    "*/",

    "uniform bool pentagon; //use pentagon as bokeh shape?",
    "float feather = 0.4; //pentagon shape feather",

    "//------------------------------------------",

    "float penta(vec2 coords) {",
      "//pentagonal shape",
      "float scale = float(rings) - 1.3;",
      "vec4  HS0 = vec4( 1.0,         0.0,         0.0,  1.0);",
      "vec4  HS1 = vec4( 0.309016994, 0.951056516, 0.0,  1.0);",
      "vec4  HS2 = vec4(-0.809016994, 0.587785252, 0.0,  1.0);",
      "vec4  HS3 = vec4(-0.809016994,-0.587785252, 0.0,  1.0);",
      "vec4  HS4 = vec4( 0.309016994,-0.951056516, 0.0,  1.0);",
      "vec4  HS5 = vec4( 0.0        ,0.0         , 1.0,  1.0);",

      "vec4  one = vec4( 1.0 );",

      "vec4 P = vec4((coords),vec2(scale, scale));",

      "vec4 dist = vec4(0.0);",
      "float inorout = -4.0;",

      "dist.x = dot( P, HS0 );",
      "dist.y = dot( P, HS1 );",
      "dist.z = dot( P, HS2 );",
      "dist.w = dot( P, HS3 );",

      "dist = smoothstep( -feather, feather, dist );",

      "inorout += dot( dist, one );",

      "dist.x = dot( P, HS4 );",
      "dist.y = HS5.w - abs( P.z );",

      "dist = smoothstep( -feather, feather, dist );",
      "inorout += dist.x;",

      "return clamp( inorout, 0.0, 1.0 );",
    "}",

    "float bdepth(vec2 coords) {",
      "// Depth buffer blur",
      "float d = 0.0;",
      "float kernel[9];",
      "vec2 offset[9];",

      "vec2 wh = vec2(texel.x, texel.y) * dbsize;",

      "offset[0] = vec2(-wh.x,-wh.y);",
      "offset[1] = vec2( 0.0, -wh.y);",
      "offset[2] = vec2( wh.x -wh.y);",

      "offset[3] = vec2(-wh.x,  0.0);",
      "offset[4] = vec2( 0.0,   0.0);",
      "offset[5] = vec2( wh.x,  0.0);",

      "offset[6] = vec2(-wh.x, wh.y);",
      "offset[7] = vec2( 0.0,  wh.y);",
      "offset[8] = vec2( wh.x, wh.y);",

      "kernel[0] = 1.0/16.0;   kernel[1] = 2.0/16.0;   kernel[2] = 1.0/16.0;",
      "kernel[3] = 2.0/16.0;   kernel[4] = 4.0/16.0;   kernel[5] = 2.0/16.0;",
      "kernel[6] = 1.0/16.0;   kernel[7] = 2.0/16.0;   kernel[8] = 1.0/16.0;",


      "for( int i=0; i<9; i++ ) {",
        "float tmp = texture2D(tDepth, coords + offset[i]).r;",
        "d += tmp * kernel[i];",
      "}",

      "return d;",
    "}",


    "vec3 color(vec2 coords,float blur) {",
      "//processing the sample",

      "vec3 col = vec3(0.0);",

      "col.r = texture2D(tColor,coords + vec2(0.0,1.0)*texel*fringe*blur).r;",
      "col.g = texture2D(tColor,coords + vec2(-0.866,-0.5)*texel*fringe*blur).g;",
      "col.b = texture2D(tColor,coords + vec2(0.866,-0.5)*texel*fringe*blur).b;",

      "vec3 lumcoeff = vec3(0.299,0.587,0.114);",
      "float lum = dot(col.rgb, lumcoeff);",
      "float thresh = max((lum-threshold)*gain, 0.0);",
      "return col+mix(vec3(0.0),col,thresh*blur);",
    "}",

    "vec2 rand(vec2 coord) {",
      "// generating noise / pattern texture for dithering",

      "float noiseX = ((fract(1.0-coord.s*(width/2.0))*0.25)+(fract(coord.t*(height/2.0))*0.75))*2.0-1.0;",
      "float noiseY = ((fract(1.0-coord.s*(width/2.0))*0.75)+(fract(coord.t*(height/2.0))*0.25))*2.0-1.0;",

      "if (noise) {",
        "noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0;",
        "noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0;",
      "}",

      "return vec2(noiseX,noiseY);",
    "}",

    "vec3 debugFocus(vec3 col, float blur, float depth) {",
      "float edge = 0.002*depth; //distance based edge smoothing",
      "float m = clamp(smoothstep(0.0,edge,blur),0.0,1.0);",
      "float e = clamp(smoothstep(1.0-edge,1.0,blur),0.0,1.0);",

      "col = mix(col,vec3(1.0,0.5,0.0),(1.0-m)*0.6);",
      "col = mix(col,vec3(0.0,0.5,1.0),((1.0-e)-(1.0-m))*0.2);",

      "return col;",
    "}",

    "float linearize(float depth) {",
      "return -zfar * znear / (depth * (zfar - znear) - zfar);",
    "}",


    "float vignette() {",
      "float dist = distance(vUv.xy, vec2(0.5,0.5));",
      "dist = smoothstep(vignout+(fstop/vignfade), vignin+(fstop/vignfade), dist);",
      "return clamp(dist,0.0,1.0);",
    "}",

    "float gather(float i, float j, int ringsamples, inout vec3 col, float w, float h, float blur) {",
      "float rings2 = float(rings);",
      "float step = PI*2.0 / float(ringsamples);",
      "float pw = cos(j*step)*i;",
      "float ph = sin(j*step)*i;",
      "float p = 1.0;",
      "if (pentagon) {",
        "p = penta(vec2(pw,ph));",
      "}",
      "col += color(vUv.xy + vec2(pw*w,ph*h), blur) * mix(1.0, i/rings2, bias) * p;",
      "return 1.0 * mix(1.0, i /rings2, bias) * p;",
    "}",

    "void main() {",
      "//scene depth calculation",

      "float depth = linearize(texture2D(tDepth,vUv.xy).x);",

      "// Blur depth?",
      "if (depthblur) {",
        "depth = linearize(bdepth(vUv.xy));",
      "}",

      "//focal plane calculation",

      "float fDepth = focalDepth;",

      "if (autofocus) {",

        "fDepth = linearize(texture2D(tDepth,focusCoords).x);",

      "}",

      "// dof blur factor calculation",

      "float blur = 0.0;",

      "if (manualdof) {",
        "float a = depth-fDepth; // Focal plane",
        "float b = (a-fdofstart)/fdofdist; // Far DoF",
        "float c = (-a-ndofstart)/ndofdist; // Near Dof",
        "blur = (a>0.0) ? b : c;",
      "} else {",
        "float f = focalLength; // focal length in mm",
        "float d = fDepth*1000.0; // focal plane in mm",
        "float o = depth*1000.0; // depth in mm",

        "float a = (o*f)/(o-f);",
        "float b = (d*f)/(d-f);",
        "float c = (d-f)/(d*fstop*CoC);",

        "blur = abs(a-b)*c;",
      "}",

      "blur = clamp(blur,0.0,1.0);",

      "// calculation of pattern for dithering",

      "vec2 noise = rand(vUv.xy)*namount*blur;",

      "// getting blur x and y step factor",

      "float w = (1.0/width)*blur*maxblur+noise.x;",
      "float h = (1.0/height)*blur*maxblur+noise.y;",

      "// calculation of final color",

      "vec3 col = vec3(0.0);",

      "if(blur < 0.05) {",
        "//some optimization thingy",
        "col = texture2D(tColor, vUv.xy).rgb;",
      "} else {",
        "col = texture2D(tColor, vUv.xy).rgb;",
        "float s = 1.0;",
        "int ringsamples;",

        "for (int i = 1; i <= rings; i++) {",
          "/*unboxstart*/",
          "ringsamples = i * samples;",

          "for (int j = 0 ; j < maxringsamples ; j++) {",
            "if (j >= ringsamples) break;",
            "s += gather(float(i), float(j), ringsamples, col, w, h, blur);",
          "}",
          "/*unboxend*/",
        "}",

        "col /= s; //divide by sample count",
      "}",

      "if (showFocus) {",
        "col = debugFocus(col, blur, depth);",
      "}",

      "if (vignetting) {",
        "col *= vignette();",
      "}",

      "gl_FragColor.rgb = col;",
      "gl_FragColor.a = 1.0;",
    "} "

  ].join("\n")

};


<|start_filename|>lib/extras/controls/orbit_controls.dart<|end_filename|>
/**
 * @author qiao / https://github.com/qiao
 * @author mrdoob / http://mrdoob.com
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author erich666 / http://erichaines.com
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/adamjcook
 *
 * @overview
 * [OrbitControls] is a set of controls performs orbiting, dollying (zooming) 
 * and panning. It maintains the "up" direction as +Y, unlike [TrackballControls].
 * Touch events on tablet and phone form-factors are also supported.
 * 
 * * Orbit - left mouse / touch: one finger move
 * * Zoom  - middle mouse, or mousewheel / touch: two finger spread or squish
 * * Pan   - right mouse, or arrow keys / touch: three finger swipe
 * 
 * [OrbitControls] is a drop-in replacement for most of the examples which use
 * [TrackballControls].
 * 
 * Only [PerspectiveCamera] and [OrthographicCamera] are supported with this 
 * control.
 **/
library OrbitControls;

import "dart:html";
import "dart:async";
import "dart:math" as Math;
import 'package:vector_math/vector_math.dart';
import "package:three/three.dart";

class STATE {
  static const NONE = -1;
  static const ROTATE = 0;
  static const DOLLY = 1;
  static const PAN = 2;
  static const TOUCH_ROTATE = 3;
  static const TOUCH_DOLLY = 4;
  static const TOUCH_PAN = 5;
}

// Key mappings for directional controls.
class KEYS {
  static const LEFT = 37;
  static const UP = 38;
  static const RIGHT = 39;
  static const BOTTOM = 40;
}

class OrbitControls extends EventEmitter {

  int _state;
  Object3D object;
  dynamic domElement;
  bool enabled;
  Math.Rectangle screen;
  num rotateSpeed, zoomSpeed, keyPanSpeed;
  bool noZoom, noRotate, noPan;
  bool autoRotate;
  num autoRotateSpeed;
  num minPolarAngle, maxPolarAngle;
  bool noKeys;
  bool staticMoving;
  num dynamicDampingFactor;
  num minDistance, maxDistance;

  double EPS;

  Vector3 target;

  Vector3 lastPosition;
  Quaternion lastQuaternion;

  Vector2 _rotateStart, _rotateEnd, _rotateDelta;
  Vector2 _panStart, _panEnd, _panDelta;
  Vector3 _panOffset;

  Vector3 _offset;

  Vector2 _dollyStart, _dollyEnd, _dollyDelta;

  num _phiDelta, _thetaDelta, _scale;
  Vector3 _pan;

  Vector3 target0, position0;

  Quaternion quaternion, quaternionInverse;

  StreamSubscription<MouseEvent> mouseMoveStream;
  StreamSubscription<MouseEvent> mouseUpStream;
  StreamSubscription<KeyboardEvent> keydownStream;

  EventEmitterEvent changeEvent;
  EventEmitterEvent startEvent;
  EventEmitterEvent endEvent;


  OrbitControls(this.object, [Element domElement]) {

    this.domElement = (domElement != null) ? domElement : document;

    // API

    // Set to false to disable this control
    enabled = true;

    EPS = 0.000001;

    // Location of focus. This is where the control orbits around and where it
    // pans with respect to.
    target = new Vector3.zero();

    // Enables/disables dollying in and out.
    noZoom = false;
    zoomSpeed = 1.0;

    // Limits the dollying in and out range.
    minDistance = 0;
    maxDistance = double.INFINITY;

    // Enables/disables rotation.
    noRotate = false;
    rotateSpeed = 1.0;

    // Enables/disabled panning.
    noPan = false;
    keyPanSpeed = 7.0;

    // Enables/disables automatic rotation around the target.
    autoRotate = false;
    autoRotateSpeed = 2.0;

    // Determines the vertical orbit limit - upper and lower limits.
    // The default range is 0.0 to Math.PI radians.
    minPolarAngle = 0; // in radians
    maxPolarAngle = Math.PI; // in radians

    // Enables/disables the ability to use the keyboard to interact with this
    // control.
    noKeys = false;


    // Internals

    target = new Vector3.zero();

    lastPosition = new Vector3.zero();
    lastQuaternion = new Quaternion.identity();

    _state = STATE.NONE;

    _rotateStart = new Vector2.zero();
    _rotateEnd = new Vector2.zero();
    _rotateDelta = new Vector2.zero();

    _panStart = new Vector2.zero();
    _panEnd = new Vector2.zero();
    _panDelta = new Vector2.zero();
    _panOffset = new Vector3.zero();

    _offset = new Vector3.zero();

    _dollyStart = new Vector2.zero();
    _dollyEnd = new Vector2.zero();
    _dollyDelta = new Vector2.zero();

    _phiDelta = 0;
    _thetaDelta = 0;
    _scale = 1;
    _pan = new Vector3.zero();

    // For reset

    target0 = target.clone();
    position0 = this.object.position.clone();

    // Establish that camera.up is the orbit axis.
    quaternion = setFromUnitVectors(object.up, new Vector3(0.0, 1.0, 0.0));
    quaternionInverse = quaternion.clone().inverse();

    changeEvent = new EventEmitterEvent(type: 'change');
    startEvent = new EventEmitterEvent(type: 'start');
    endEvent = new EventEmitterEvent(type: 'end');

    this.domElement
        ..onContextMenu.listen((event) => event.preventDefault())
        ..onMouseDown.listen(mousedown)
        ..onMouseWheel.listen(mousewheel)
        ..onTouchStart.listen(touchstart)
        ..onTouchEnd.listen(touchend)
        ..onTouchMove.listen(touchmove);

    keydownStream = window.onKeyDown.listen(keydown);

    update();
  }

  rotateLeft(angle) {

    if (angle == null) {

      angle = getAutoRotationAngle();

    }

    _thetaDelta -= angle;

  }

  rotateUp(angle) {

    if (angle == null) {

      angle = getAutoRotationAngle();

    }

    _phiDelta -= angle;

  }

  panLeft(double distance) {

    var te = object.matrix;

    // Get the X column of the object transform matrix.
    _panOffset = new Vector3(te[0], te[1], te[2]);
    _panOffset = _panOffset * -distance;

    _pan.add(_panOffset);

  }

  panUp(double distance) {

    var te = object.matrix;

    // Get the Y column of the object transform matrix.
    _panOffset = new Vector3(te[4], te[5], te[6]);
    _panOffset = _panOffset * distance;

    _pan.add(_panOffset);
  }


  pan(double deltaX, double deltaY) {

    var element = (domElement == document) ? document.body : domElement;

    if (object is PerspectiveCamera) {

      // For [PerspectiveCamera]
      var position = object.position;
      var offset = position.clone().sub(target);
      var targetDistance = offset.length;

      // Half of the FOV is the distance from the center to the top of the screen.
      targetDistance *= Math.tan(((object as PerspectiveCamera).fov / 2) * Math.PI / 180.0);

      // screenWidth is not used since [PerspectiveCamera] is fixed to screen height.
      panLeft(2.0 * deltaX * targetDistance / element.clientHeight);
      panUp(2.0 * deltaY * targetDistance / element.clientHeight);

    } else if (object is OrthographicCamera) {

      // For [OrthographicCamera]
      panLeft(
          deltaX * ((object as OrthographicCamera).right - (object as OrthographicCamera).left) / element.clientWidth);
      panUp(
          deltaY * ((object as OrthographicCamera).top - (object as OrthographicCamera).bottom) / element.clientHeight);

    } else {

      // Object is neither [PerspectiveCamera] or [OrthographicCamera]
      throw new ArgumentError('camera must be PerspectiveCamera or OrthographicCamera');
    }
  }

  dollyIn({dollyScale}) {

    if (dollyScale == null) {

      dollyScale = getZoomScale();

    }

    _scale /= dollyScale;

  }

  dollyOut({dollyScale}) {

    if (dollyScale == null) {

      dollyScale = getZoomScale();

    }

    _scale *= dollyScale;

  }

  update() {

    var position = object.position;

    _offset.setFrom(position).sub(target);

    // Rotate offset to 'Y-axis is up' space.
    quaternion.rotate(_offset);

    // Angle from Z-axis around Y-axis
    var theta = Math.atan2(_offset.x, _offset.z);

    // Angle from Y-axis
    var phi = Math.atan2(Math.sqrt(_offset.x * _offset.x + _offset.z * _offset.z), _offset.y);

    if (autoRotate) {

      rotateLeft(getAutoRotationAngle());

    }

    theta += _thetaDelta;

    phi += _phiDelta;

    // Restrict phi to be between the desired limits
    phi = Math.max(minPolarAngle, Math.min(maxPolarAngle, phi));

    // Restrict phi to be between EPS and PI-EPS
    phi = Math.max(EPS, Math.min(Math.PI - EPS, phi));

    var radius = _offset.length * _scale;

    // Restrict radius to be between desired limits
    radius = Math.max(minDistance, Math.min(maxDistance, radius));

    // Move target to panned location
    target.add(_pan);

    _offset.x = radius * Math.sin(phi) * Math.sin(theta);
    _offset.y = radius * Math.cos(phi);
    _offset.z = radius * Math.sin(phi) * Math.cos(theta);

    // Rotate offset back to 'camera-up-vector-is-up' space
    quaternionInverse.rotate(_offset);

    position.setFrom(target).add(_offset);

    object.lookAt(target);

    _thetaDelta = 0;
    _phiDelta = 0;
    _scale = 1;
    _pan = new Vector3.zero();

    // Update condition is the following:
    // * min( camera displacement, camera rotation in radians )^2 > EPS
    // * using small-angle approximation cos(x/2) = 1 - x^2 / 8
    if (lastPosition.distanceToSquared(object.position) > EPS ||
        8 * (1 - dotProductQuaternion(lastQuaternion, object.quaternion)) > EPS) {

      dispatchEvent(changeEvent);

      lastPosition.setFrom(object.position);
      lastQuaternion = object.quaternion;

    }

  }

  reset() {

    _state = STATE.NONE;

    target = target0;
    object.position = position0;

    update();

  }

  getAutoRotationAngle() {

    return 2 * Math.PI / 60 / 60 * autoRotateSpeed;

  }

  getZoomScale() {

    return Math.pow(0.95, zoomSpeed);

  }

  mousedown(event) {

    if (enabled == false) return;

    event.preventDefault();

    if (event.button == 0) {

      if (noRotate == true) return;

      _state = STATE.ROTATE;

      _rotateStart = new Vector2(event.clientX.toDouble(), event.clientY.toDouble());

    } else if (event.button == 1) {

      if (noZoom == true) return;

      _state = STATE.DOLLY;

      _dollyStart = new Vector2(event.clientX.toDouble(), event.clientY.toDouble());

    } else if (event.button == 2) {

      if (noPan == true) return;

      _state = STATE.PAN;

      _panStart = new Vector2(event.clientX.toDouble(), event.clientY.toDouble());

    }

    mouseMoveStream = document.onMouseMove.listen(mousemove);
    mouseUpStream = document.onMouseUp.listen(mouseup);
    dispatchEvent(startEvent);

  }

  mousemove(event) {

    if (enabled == false) return;

    event.preventDefault();

    var element = (domElement == document) ? document.body : domElement;

    if (_state == STATE.ROTATE) {

      if (noRotate == true) return;

      _rotateEnd = new Vector2(event.clientX.toDouble(), event.clientY.toDouble());
      _rotateDelta = _rotateEnd - _rotateStart;

      // Rotating across the whole screen is 360 degrees around.
      rotateLeft(2 * Math.PI * _rotateDelta.x / element.clientWidth * rotateSpeed);

      // Rotating up and down along the whole screen attempts to go to 360,
      // but it is limited to 180 degrees.
      rotateUp(2 * Math.PI * _rotateDelta.y / element.clientHeight * rotateSpeed);

      _rotateStart.setFrom(_rotateEnd);

    } else if (_state == STATE.DOLLY) {

      if (noZoom == true) return;

      _dollyEnd = new Vector2(event.clientX.toDouble(), event.clientY.toDouble());
      _dollyDelta = _dollyEnd - _dollyStart;

      if (_dollyDelta.y > 0) {

        dollyIn();

      } else {

        dollyOut();

      }

      _dollyStart.setFrom(_dollyEnd);

    } else if (_state == STATE.PAN) {

      if (noPan == true) return;

      _panEnd = new Vector2(event.clientX.toDouble(), event.clientY.toDouble());
      _panDelta = _panEnd - _panStart;

      pan(_panDelta.x.toDouble(), _panDelta.y.toDouble());

      _panStart.setFrom(_panEnd);

    }

    update();

  }

  mouseup(event) {

    if (enabled == false) return;

    mouseMoveStream.cancel();
    mouseUpStream.cancel();

    dispatchEvent(endEvent);

    _state = STATE.NONE;

  }

  mousewheel(event) {

    if (enabled == false || noZoom == true) return;

    event.preventDefault();
    event.stopPropagation();

    var delta = 0;

    if (event.wheelDeltaY != 0) {

      // WebKit / Opera / Internet Explorer 9
      delta = event.wheelDeltaY;

    } else if (event.detail != 0) {

      // Firefox
      delta = -event.detail;

    }

    if (delta > 0) {

      dollyOut();

    } else {

      dollyIn();

    }

    update();
    dispatchEvent(startEvent);
    dispatchEvent(endEvent);

  }

  keydown(event) {

    if (enabled == false || noKeys == true || noPan == true) return;

    switch (event.keyCode) {

      case KEYS.UP:
        pan(0.0, keyPanSpeed);
        update();
        break;

      case KEYS.BOTTOM:
        pan(0.0, -keyPanSpeed);
        update();
        break;

      case KEYS.LEFT:
        pan(keyPanSpeed, 0.0);
        update();
        break;

      case KEYS.RIGHT:
        pan(-keyPanSpeed, 0.0);
        update();
        break;
    }

  }

  touchstart(event) {

    if (enabled == false) return;

    switch (event.touches.length) {

      case 1:
        // Single finger touch - rotate
        if (noRotate == true) return;

        _state = STATE.TOUCH_ROTATE;

        _rotateStart = new Vector2(event.touches[0].pageX.toDouble(), event.touches[0].pageY.toDouble());
        break;

      case 2:
        // Two-finger touch - dolly
        if (noZoom == true) return;

        _state = STATE.TOUCH_DOLLY;

        var dx = event.touches[0].pageX.toDouble() - event.touches[1].pageX.toDouble();

        var dy = event.touches[0].pageY.toDouble() - event.touches[1].pageY.toDouble();

        var distance = Math.sqrt(dx * dx + dy * dy);

        _dollyStart = new Vector2(0.0, distance);
        break;

      case 3:
        // Three-finger touch - pan
        if (noPan == true) return;

        _state = STATE.TOUCH_PAN;

        _panStart = new Vector2(event.touches[0].pageX, event.touches[0].pageY);
        break;

      default:
        _state = STATE.NONE;
    }

    dispatchEvent(startEvent);

  }

  touchmove(event) {

    if (enabled == true) return;

    event.preventDefault();
    event.stopPropagation();

    var element = (domElement == document) ? document.body : domElement;

    switch (event.touches.length) {

      case 1:
        // Single finger touch - rotate
        if (noRotate == true) return;
        if (_state != STATE.TOUCH_ROTATE) return;

        _rotateEnd = new Vector2(event.touches[0].pageX.toDouble(), event.touches[0].pageY.toDouble());

        _rotateDelta = _rotateEnd - _rotateStart;

        // Rotating across the whole screen is 360 degrees around.
        rotateLeft(2 * Math.PI * _rotateDelta.x / element.clientWidth * rotateSpeed);

        // Rotating up and down along the whole screen attempts to go to 360,
        // but it is limited to 180 degrees.
        rotateUp(2 * Math.PI * _rotateDelta.y / element.clientHeight * rotateSpeed);

        _rotateStart = _rotateEnd;

        update();
        break;

      case 2:
        // Two-finger touch - dolly
        if (noZoom == true) return;
        if (_state != STATE.TOUCH_DOLLY) return;

        var dx = event.touches[0].pageX.toDouble() - event.touches[1].pageX.toDouble();

        var dy = event.touches[0].pageY.toDouble() - event.touches[1].pageY.toDouble();

        var distance = Math.sqrt(dx * dx + dy * dy);

        _dollyEnd = new Vector2(0.0, distance);
        _dollyDelta = _dollyEnd - _dollyStart;

        if (_dollyDelta.y > 0) {

          dollyOut();

        } else {

          dollyIn();

        }

        _dollyStart = _dollyEnd;

        update();
        break;

      case 3:
        // Three-finger touch - pan
        if (noPan == true) return;
        if (_state = STATE.TOUCH_PAN) return;

        _panEnd = new Vector2(event.touches[0].pageX.toDouble(), event.touches[0].pageY.toDouble());

        _panDelta = _panEnd - _panStart;

        pan(_panDelta.x, _panDelta.y);

        _panStart = _panEnd;

        update();
        break;

      default:
        _state = STATE.NONE;
    }

  }

  touchend(event) {

    if (enabled == false) return;

    dispatchEvent(endEvent);

    _state = STATE.NONE;

  }

  // TODO(adamjcook): Move into vector_math library? Perhaps a method of quaternion.dart?
  Quaternion setFromUnitVectors(Vector3 from, Vector3 to) {

    // Reference: http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
    // Assumes that direction vectors `from` and `to` are normalized.

    var r;
    var EPS = 0.000001;
    Vector3 v1 = new Vector3.zero();

    r = from.dot(to) + 1;

    if (r < EPS) {

      r = 0;

      if ((from.x).abs() > (from.z).abs()) {

        v1 = new Vector3(-from.y, from.x, 0.0);

      } else {

        v1 = new Vector3(0.0, -from.z, from.y);
      }

    } else {

      v1 = from.cross(to);
    }

    return new Quaternion(v1.x, v1.y, v1.z, r).normalize();

  }

  // TODO(adamjcook): Move into vector_math library? Perhaps a method of quaternion.dart?
  double dotProductQuaternion(Quaternion q1, Quaternion q2) {

    return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;

  }

}


<|start_filename|>example/web_gl_cubes/web_gl_cubes.dart<|end_filename|>
/// Port of http://alteredqualia.com/three/examples/webgl_cubes.html

import 'dart:html';
import 'dart:math' as Math;
import 'package:three/three.dart';
import 'package:vector_math/vector_math.dart';

// 150,000 cubes
// 12 triangles per cube (6 quads)

const TRIANGLES = 12 * 150000;

const D = 10.0;

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

Mesh mesh;
Map<String, Uniform> uniforms;

Color color = new Color();

Vector3 pA = new Vector3.zero(),
    pB = new Vector3.zero(),
    pC = new Vector3.zero();

Vector3 cb = new Vector3.zero();
Vector3 ab = new Vector3.zero();

Matrix4 m = new Matrix4.identity();
Matrix4 m2 = new Matrix4.identity();

Vector3 e = new Vector3(0.0, 0.0, 0.0);
Vector3 t = new Vector3.zero();
Vector3 tt = new Vector3.zero();
Vector3 u = new Vector3(0.0, 1.0, 0.0);

Vector3 v1 = new Vector3(0.0, 0.0, 0.0),
    v2 = new Vector3(D, 0.0, 0.0),
    v3 = new Vector3(D, D, 0.0),
    v4 = new Vector3(0.0, D, 0.0);

Vector3 v1b = new Vector3(0.0, 0.0, D),
    v2b = new Vector3(D, 0.0, D),
    v3b = new Vector3(D, D, D),
    v4b = new Vector3(0.0, D, D);

BufferGeometry geometry;

void main() {
  init();
  animate(0);
}

void init() {

  container = document.querySelector('#container');

  camera = new PerspectiveCamera(37.0, window.innerWidth / window.innerHeight, 1.0, 8000.0)
      ..position.z = 2750.0
      ..position.y = 1250.0;

  scene = new Scene();

  camera.lookAt(scene.position);


  // BufferGeometry with unindexed triangles
  // use vertex colors to store centers of rotations

  geometry = new BufferGeometry()
      ..aPosition = new GeometryAttribute.float32(TRIANGLES * 3 * 3, 3)
      ..aNormal = new GeometryAttribute.float32(TRIANGLES * 3 * 3, 3)
      ..aColor = new GeometryAttribute.float32(TRIANGLES * 3 * 3, 3);

  // break geometry into
  // chunks of 20,000 triangles (3 unique vertices per triangle)
  // for indices to fit into 16 bit integer number

  var chunkSize = 20000;

  // Generate a single buffer with all the cubes

  var n = 8000; // triangles spread in the cube
  var d2 = D / 2; // individual triangle size

  //

  var rnd = new Math.Random();

  for (var i = 0; i < TRIANGLES; i += 12) {

    var x = randFloat(0.1 * n, 0.2 * n) * (rnd.nextBool() ? 1 : -1) * randInt(0.5, 2);
    var y = randFloat(0.1 * n, 0.2 * n) * (rnd.nextBool() ? 1 : -1) * randInt(0.5, 2);
    var z = randFloat(0.1 * n, 0.2 * n) * (rnd.nextBool() ? 1 : -1) * randInt(0.5, 2);

    tt.setValues(rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble());

    //

    _addTriangle(i, x, y, z, v1, v2, v4);
    _addTriangle(i + 1, x, y, z, v2, v3, v4);

    _addTriangle(i + 2, x, y, z, v4b, v2b, v1b);
    _addTriangle(i + 3, x, y, z, v4b, v3b, v2b);

    //

    _addTriangle(i + 4, x, y, z, v1b, v2, v1);
    _addTriangle(i + 5, x, y, z, v1b, v2b, v2);


    _addTriangle(i + 6, x, y, z, v2b, v3, v2);
    _addTriangle(i + 7, x, y, z, v2b, v3b, v3);

    //

    _addTriangle(i + 8, x, y, z, v3b, v4, v3);
    _addTriangle(i + 9, x, y, z, v3b, v4b, v4);

    _addTriangle(i + 10, x, y, z, v1, v4, v1b);
    _addTriangle(i + 11, x, y, z, v4, v4b, v1b);


  }

  geometry.computeBoundingSphere();

  // Set up custom shader material

  uniforms = {
    "amplitude": new Uniform.float(0.0)
  };

  var material = new ShaderMaterial(
      uniforms: uniforms,
      vertexShader: document.querySelector('#vertexShader').text,
      fragmentShader: document.querySelector('#fragmentShader').text,
      vertexColors: VertexColors);

  //

  mesh = new Mesh(geometry, material);
  scene.add(mesh);

  //

  renderer = new WebGLRenderer(antialias: false, clearColorHex: 0x050505, clearAlpha: 1, alpha: false);
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.children.add(renderer.domElement);

  //

  window.onResize.listen(onWindowResize);
}

_addTriangle(int k, double x, double y, double z, Vector3 vc, Vector3 vb, Vector3 va) {

  var positions = geometry.aPosition.array,
      normals = geometry.aNormal.array,
      colors = geometry.aColor.array;

  // positions

  pA.setFrom(va);
  pB.setFrom(vb);
  pC.setFrom(vc);

  t.setValues(x, y, z);
  t.scale(0.5);

  makeLookAt(m, e, tt, u);

  m2.setIdentity().setTranslation(t);

  m2.multiply(m);

  m2.transform3(pA);
  m2.transform3(pB);
  m2.transform3(pC);

  var ax = pA.x;
  var ay = pA.y;
  var az = pA.z;

  var bx = pB.x;
  var by = pB.y;
  var bz = pB.z;

  var cx = pC.x;
  var cy = pC.y;
  var cz = pC.z;

  var j = k * 9;

  positions[j] = ax;
  positions[j + 1] = ay;
  positions[j + 2] = az;

  positions[j + 3] = bx;
  positions[j + 4] = by;
  positions[j + 5] = bz;

  positions[j + 6] = cx;
  positions[j + 7] = cy;
  positions[j + 8] = cz;

  // flat face normals

  pA.setValues(ax, ay, az);
  pB.setValues(bx, by, bz);
  pC.setValues(cx, cy, cz);

  cb.setFrom(pC - pB);
  ab.setFrom(pA - pB);
  cb = cb.cross(ab);

  cb.normalize();

  var nx = cb.x;
  var ny = cb.y;
  var nz = cb.z;

  normals[j] = nx;
  normals[j + 1] = ny;
  normals[j + 2] = nz;

  normals[j + 3] = nx;
  normals[j + 4] = ny;
  normals[j + 5] = nz;

  normals[j + 6] = nx;
  normals[j + 7] = ny;
  normals[j + 8] = nz;

  // colors

  color.setRGB(t.x, t.y, t.z);

  colors[j] = color.r;
  colors[j + 1] = color.g;
  colors[j + 2] = color.b;

  colors[j + 3] = color.r;
  colors[j + 4] = color.g;
  colors[j + 5] = color.b;

  colors[j + 6] = color.r;
  colors[j + 7] = color.g;
  colors[j + 8] = color.b;

}

onWindowResize(event) {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

animate(num time) {
  window.requestAnimationFrame(animate);
  render();
  //stats.update();
}

var _time = new DateTime.now().millisecondsSinceEpoch * 0.001;
render() {

  var time = new DateTime.now().millisecondsSinceEpoch * 0.001;
  var delta = time - _time;
  _time = time;

  //print(time);
  mesh.rotation
      ..x += (delta * 0.025)
      ..y += (delta * 0.05);

  uniforms["amplitude"].value += (2 * delta);

  renderer.render(scene, camera);

}


<|start_filename|>example/web_gl_geometry_text/web_gl_geometry_text.dart<|end_filename|>
import 'dart:html';
import "dart:async";
import 'dart:math' as Math;
import 'dart:convert' show JSON;
import 'package:vector_math/vector_math.dart';
import 'package:three/three.dart';
import 'package:three/extras/font_utils.dart' as FontUtils;
import 'package:three/extras/geometry_utils.dart' as GeometryUtils;

var container, stats, permalink, hex, color;

var camera, cameraTarget, scene, renderer;

var composer;
var effectFXAA;

var textMesh1, textMesh2, textGeo, material, parent;

var firstLetter = true,
    text = "three.dart",
    height = 20.0,
    size = 70,
    hover = 30.0,

    curveSegments = 4,

    bevelThickness = 2,
    bevelSize = 1.5,
    bevelSegments = 3,
    bevelEnabled = true,

    font = "helvetiker", // helvetiker, optimer, gentilis, droid sans, droid serif
    weight = "normal", // normal bold
    style = "normal", // normal italic

    mirror = true,

    targetRotation = 0,
    targetRotationOnMouseDown = 0,

    mouseX = 0,
    mouseXOnMouseDown = 0,

    glow = 0.9;

var windowHalfX;
var windowHalfY;

List<StreamSubscription> _mouseSubscriptions = [];

Future loadFonts() =>
    Future.wait(["fonts/helvetiker_regular.json"].map((path) => HttpRequest.getString(path).then((data) {
  FontUtils.loadFace(JSON.decode(data));
})));

void main() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  loadFonts().then((_) {
    init();
    animate(0);
  });
}

capitalize(txt) {

  return txt.substring(0, 1).toUpperCase() + txt.substring(1);
}

void init() {

  container = new Element.tag('div');

  document.body.nodes.add(container);

  // CAMERA

  camera = new PerspectiveCamera(
      30.0,
      window.innerWidth / window.innerHeight,
      1.0,
      1500.0)..position.setValues(0.0, 400.0, 700.0);

  cameraTarget = new Vector3(0.0, 150.0, 0.0);

  // SCENE

  scene = new Scene()..fog = new FogLinear(0x000000, 250.0, 1400.0);

  // LIGHTS

  var dirLight = new DirectionalLight(0xffffff, 0.125)..position.setValues(0.0, 0.0, 1.0).normalize();
  scene.add(dirLight);

  var pointLight = new PointLight(0xffffff, intensity: 1.5)..position.setValues(0.0, 100.0, 90.0);
  scene.add(pointLight);

  //text = capitalize( font ) + " " + capitalize( weight );
  //text = "abcdefghijklmnopqrstuvwxyz0123456789";
  //text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

  pointLight.color.setHSL(new Math.Random().nextDouble(), 1.0, 0.5);

  material = new MeshFaceMaterial([new MeshPhongMaterial(color: 0xffffff, shading: FlatShading), // front
    new MeshPhongMaterial(color: 0xffffff, shading: SmoothShading) // side
  ]);

  parent = new Object3D()..position.y = 100.0;

  scene.add(parent);

  createText();

  var plane =
      new Mesh(new PlaneGeometry(10000.0, 10000.0), new MeshBasicMaterial(color: 0xffffff, opacity: 0.5, transparent: true))
      ..position.y = 100.0
      ..rotation.x = -Math.PI / 2.0;
  scene.add(plane);

  // RENDERER

  renderer = new WebGLRenderer(antialias: true)
      ..setSize(window.innerWidth, window.innerHeight)
      ..setClearColor(new Color(0x000000), 1);

  container.nodes.add(renderer.domElement);

  // EVENTS

  document
      ..onMouseDown.listen(onDocumentMouseDown)
      ..onTouchStart.listen(onDocumentTouchStart)
      ..onTouchMove.listen(onDocumentTouchMove)
      ..onKeyPress.listen(onDocumentKeyPress)
      ..onKeyDown.listen(onDocumentKeyDown);

  window.onResize.listen(onWindowResize);

}

onWindowResize(e) {

  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}

onDocumentKeyDown(event) {

  if (firstLetter) {

    firstLetter = false;
    text = "";

  }

  var keyCode = event.keyCode;

  // backspace

  if (keyCode == 8) {

    event.preventDefault();

    text = text.substring(0, text.length - 1);
    refreshText();

    return false;

  }

}

onDocumentKeyPress(event) {

  var keyCode = event.which;

  // backspace

  if (keyCode == 8) {

    event.preventDefault();

  } else {

    var ch = new String.fromCharCode(keyCode);
    text += ch;

    refreshText();

  }

}

createText() {

  textGeo = new TextGeometry(
      text,
      height,
      false,
      bevelThickness,
      bevelSize,
      3,
      bevelEnabled,
      curveSegments,
      1,
      null,
      null,
      0,
      1,
      size,
      font,
      weight,
      style);

  textGeo.materials = material.materials;

  textGeo.computeBoundingBox();
  textGeo.computeVertexNormals();

  // "fix" side normals by removing z-component of normals for side faces
  // (this doesn't work well for beveled geometry as then we lose nice curvature around z-axis)

  if (!bevelEnabled) {

    var triangleAreaHeuristics = 0.1 * (height * size);

    textGeo.faces.forEach((face) {

      if (face.materialIndex == 1) {

        face.vertexNormals.forEach((normal) {

          normal
              ..z = 0.0
              ..normalize();

        });

        var va = textGeo.vertices[face.a],
            vb = textGeo.vertices[face.b],
            vc = textGeo.vertices[face.c];

        var s = GeometryUtils.triangleArea(va, vb, vc);

        if (s > triangleAreaHeuristics) {

          for (var j = 0; j < face.vertexNormals.length; j++) {

            face.vertexNormals[j].setFrom(face.normal);

          }

        }

      }

    });

  }

  var centerOffset = -0.5 * (textGeo.boundingBox.max.x - textGeo.boundingBox.min.x);

  textMesh1 = new Mesh(textGeo, material)

      ..position.x = centerOffset
      ..position.y = hover
      ..position.z = 0.0

      ..rotation.x = 0.0
      ..rotation.y = Math.PI * 2.0;

  parent.add(textMesh1);

  if (mirror) {

    textMesh2 = new Mesh(textGeo, material)

        ..position.x = centerOffset
        ..position.y = -hover
        ..position.z = height

        ..rotation.x = Math.PI
        ..rotation.y = Math.PI * 2.0;

    parent.add(textMesh2);

  }

}

refreshText() {

  // updatePermalink();

  parent.remove(textMesh1);
  if (mirror) parent.remove(textMesh2);

  if (!text) return;

  createText();

}

onDocumentMouseDown(event) {

  event.preventDefault();

  _mouseSubscriptions = [
      document.onMouseMove.listen(onDocumentMouseMove),
      document.onMouseUp.listen(onDocumentMouseUp),
      document.onMouseOut.listen(onDocumentMouseOut)];

  mouseXOnMouseDown = event.client.x - windowHalfX;
  targetRotationOnMouseDown = targetRotation;

}

onDocumentMouseMove(event) {

  mouseX = event.client.x - windowHalfX;

  targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;

}

onDocumentMouseUp(event) {
  _mouseSubscriptions.forEach((s) {
    s.cancel();
  });

}

onDocumentMouseOut(event) {
  _mouseSubscriptions.forEach((s) {
    s.cancel();
  });
}

onDocumentTouchStart(event) {

  if (event.touches.length == 1) {

    event.preventDefault();

    mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
    targetRotationOnMouseDown = targetRotation;

  }

}

onDocumentTouchMove(event) {

  if (event.touches.length == 1) {

    event.preventDefault();

    mouseX = event.touches[0].pageX - windowHalfX;
    targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;

  }

}

//

animate(num time) {

  window.requestAnimationFrame(animate);

  render();

}

render() {

  parent.rotation.y += (targetRotation - parent.rotation.y) * 0.05;

  camera.lookAt(cameraTarget);

  renderer.clear();

  renderer.render(scene, camera);

}


<|start_filename|>example/canvas_interactive_cubes/canvas_interactive_cubes.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;

import 'package:vector_math/vector_math.dart' hide Ray;
import 'package:three/three.dart';
import 'package:three/extras/renderers/canvas_renderer.dart';

Element container;//, stats;
PerspectiveCamera camera;
Scene scene;
Projector projector;
CanvasRenderer renderer;
Material particleMaterial;

List<Mesh> objects;

final num radius = 600;
num theta = 0;

void main() {
  init();
  animate(0);
}

void init() {
  objects = [];

  container = new Element.tag('div');
  document.body.nodes.add(container);

  Element info = new Element.tag('div');
  info.style.position = 'absolute';
  info.style.top = '10px';
  info.style.width = '100%';
  info.style.textAlign = 'center';
  info.innerHtml = '<a href="http://github.com/robsilv/three.dart" target="_blank">three.dart</a> - clickable objects';
  container.nodes.add(info);

  camera = new PerspectiveCamera(70.0, window.innerWidth / window.innerHeight.toDouble(), 1.0, 10000.0);
  camera.position.setValues(0.0, 300.0, 500.0);

  scene = new Scene();

  scene.add(camera);

  CubeGeometry geometry = new CubeGeometry(100.0, 100.0, 100.0);

  var rnd = new Math.Random();
  for (int i = 0; i < 10; i++) {
    Particle particle = new Particle(particleMaterial);
    particle.position.x = rnd.nextInt(800) - 400.0;
    particle.position.y = rnd.nextInt(800) - 400.0;
    particle.position.z = rnd.nextInt(800) - 400.0;
    particle.scale.x = particle.scale.y = 8.0;
    scene.add(particle);

    Mesh object = new Mesh(geometry, new MeshBasicMaterial(color: rnd.nextDouble() * 0xffffff, opacity: 0.5));
    object.position.x = rnd.nextInt(800) - 400.0;
    object.position.y = rnd.nextInt(800) - 400.0;
    object.position.z = rnd.nextInt(800) - 400.0;

    object.scale.x = rnd.nextDouble() * 2 + 1.0;
    object.scale.y = rnd.nextDouble() * 2 + 1.0;
    object.scale.z = rnd.nextDouble() * 2 + 1.0;

    object.rotation.x = (rnd.nextDouble() * 360.0) * Math.PI / 180;
    object.rotation.y = (rnd.nextDouble() * 360.0) * Math.PI / 180;
    object.rotation.z = (rnd.nextDouble() * 360.0) * Math.PI / 180;

    scene.add(object);

    objects.add(object);
  }


  particleMaterial = new ParticleCanvasMaterial(color: 0x000000, program: (CanvasRenderingContext2D context) {
    context.beginPath();
    context.arc(0, 0, 1, 0, Math.PI * 2, false);
    context.closePath();
    context.fill();
  });

  projector = new Projector();

  var options;

  renderer = new CanvasRenderer(options);
  //renderer.debug = true;
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.nodes.add(renderer.domElement);

  //stats = new Stats();
  //stats.domElement.style.position = 'absolute';
  //stats.domElement.style.top = '0px';
  //container.appendChild( stats.domElement );

  document.onMouseDown.listen(onDocumentMouseDown);
}

void onDocumentMouseDown(event) {
  event.preventDefault();

  Vector3 vector =
      new Vector3((event.client.x / window.innerWidth) * 2 - 1, -(event.client.y / window.innerHeight) * 2 + 1, 0.5);
  projector.unprojectVector(vector, camera);

  Ray ray = new Ray(camera.position, vector.sub(camera.position).normalize());

  List<Intersect> intersects = ray.intersectObjects(objects);

  if (intersects.length > 0) {
    Intersect intersect = intersects[0];
    Mesh mesh = intersect.object;
    MeshBasicMaterial material = mesh.material;
    material.color.setHex(new Math.Random().nextDouble() * 0xffffff);

    Particle particle = new Particle(particleMaterial);
    particle.position = intersect.point;
    particle.scale.x = particle.scale.y = 8.0;
    scene.add(particle);
  }

  /*
  // Parse all the faces
  for ( var i in intersects ) {
    Intersect intersect = intersects[ i ];
    //intersects[ i ].
    intersects[ i ].face.material[ 0 ].color.setHex( Math.random() * 0xffffff | 0x80000000 );
  }
  */
}

//

void animate(num time) {
  window.requestAnimationFrame(animate);

  render();
}

void render() {
  theta += 0.2;

  camera.position.x = radius * Math.sin(theta * Math.PI / 360);
  camera.position.y = radius * Math.sin(theta * Math.PI / 360);
  camera.position.z = radius * Math.cos(theta * Math.PI / 360);
  camera.lookAt(scene.position);

  renderer.render(scene, camera);
}


<|start_filename|>lib/src/lights/hemisphere_light.dart<|end_filename|>
part of three;

/// A light source positioned directly above the scene.
class HemisphereLight extends Light {
  Vector3 _position;
  /// Light's intensity.
  double intensity;
  /// Light's ground color.
  Color groundColor;

  HemisphereLight(num skyColorHex, num groundColorHex, {this.intensity: 1.0}) : super(skyColorHex) {
    groundColor = new Color(groundColorHex);

    _position = new Vector3(0.0, 100.0, 0.0);
  }
}


<|start_filename|>example/web_gl_interactive_cubes/web_gl_interactive_cubes.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:vector_math/vector_math.dart' hide Ray;
import 'package:three/three.dart';

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;
Projector projector;

double mouseX = 0.0,
    mouseY = 0.0;

Mesh INTERSECTED;
num currentHex;

void main() {
  init();
  animate(0);
}

void init() {

  container = new Element.tag('div');

  document.body.nodes.add(container);

  camera = new PerspectiveCamera(70.0, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  camera.position.setValues(0.0, 300.0, 500.0);

  scene = new Scene();
  scene.add(camera);

  var light;

  light = new DirectionalLight(0xffffff, 2.0);
  light.position.setValues(1.0, 1.0, 1.0).normalize();
  scene.add(light);

  light = new DirectionalLight(0xffffff);
  light.position.setValues(-1.0, -1.0, -1.0).normalize();
  scene.add(light);


  var geometry = new CubeGeometry(20.0, 20.0, 20.0);

  var rnd = new Math.Random();

  for (var i = 0; i < 500; i++) {

    var object = new Mesh(geometry, new MeshLambertMaterial(color: rnd.nextInt(0xffffff)));

    object.position.x = rnd.nextInt(800) - 400.0;
    object.position.y = rnd.nextInt(800) - 400.0;
    object.position.z = rnd.nextInt(800) - 400.0;

    object.rotation.x = (rnd.nextDouble() * 360) * Math.PI / 180;
    object.rotation.y = (rnd.nextDouble() * 360) * Math.PI / 180;
    object.rotation.z = (rnd.nextDouble() * 360) * Math.PI / 180;

    object.scale.x = rnd.nextDouble() * 2 + 1;
    object.scale.y = rnd.nextDouble() * 2 + 1;
    object.scale.z = rnd.nextDouble() * 2 + 1;

    scene.add(object);

  }

  projector = new Projector();

  renderer = new WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.nodes.add(renderer.domElement);

  document.onMouseMove.listen(onDocumentMouseMove);

  window.onResize.listen(onWindowResize);
}

onWindowResize(_) {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}

onDocumentMouseMove(event) {

  event.preventDefault();

  mouseX = (event.client.x / window.innerWidth) * 2 - 1;
  mouseY = -(event.client.y / window.innerHeight) * 2 + 1;

}

animate(num time) {

  window.requestAnimationFrame(animate);

  render();

}

var radius = 100;
num theta = 0;

render() {

  theta += 0.2;

  camera.position.x = radius * Math.sin(theta * Math.PI / 360);
  camera.position.y = radius * Math.sin(theta * Math.PI / 360);
  camera.position.z = radius * Math.cos(theta * Math.PI / 360);

  camera.lookAt(scene.position);

  // find intersections

  var vector = new Vector3(mouseX, mouseY, 1.0);
  projector.unprojectVector(vector, camera);

  var ray = new Ray(camera.position, vector.sub(camera.position).normalize());

  var intersects = ray.intersectObjects(scene.children);

  if (intersects.length > 0) {

    if (INTERSECTED != intersects[0].object) {

      if (INTERSECTED != null) (INTERSECTED.material as MeshLambertMaterial).emissive.setHex(currentHex);

      INTERSECTED = intersects[0].object;
      MeshLambertMaterial material = INTERSECTED.material;
      currentHex = material.emissive.getHex();
      material.emissive.setHex(0xff0000);

    }

  } else {

    if (INTERSECTED != null) (INTERSECTED.material as MeshLambertMaterial).emissive.setHex(currentHex);

    INTERSECTED = null;

  }

  renderer.render(scene, camera);

}


<|start_filename|>example/web_gl_text/web_gl_text.dart<|end_filename|>
import 'dart:html';
import "dart:async";
import 'dart:convert' show JSON;
import 'package:three/three.dart';
import 'package:three/extras/font_utils.dart' as FontUtils;

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

Mesh fontmesh;

Future loadFonts() =>
    Future.wait(["fonts/helvetiker_regular.json"].map((path) => HttpRequest.getString(path).then((data) {
  FontUtils.loadFace(JSON.decode(data));
})));

void main() {

  loadFonts().then((_) {
    init();
    animate(0);
  });
}

void init() {

  container = new Element.tag('div');

  document.body.nodes.add(container);

  scene = new Scene();

  camera = new PerspectiveCamera(70.0, window.innerWidth / window.innerHeight, 1.0, 10000.0);
  camera.position.z = 1200.0;

  scene.add(camera);

  var fontshapes = FontUtils.generateShapes("Hello world");

  MeshBasicMaterial fontmaterial = new MeshBasicMaterial(color: 0xff0000, side: DoubleSide);

  ShapeGeometry fontgeometry = new ShapeGeometry(fontshapes, curveSegments: 20);

  fontmesh = new Mesh(fontgeometry, fontmaterial);

  scene.add(fontmesh);

  renderer = new WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);

  container.nodes.add(renderer.domElement);

  window.onResize.listen(onWindowResize);
}

onWindowResize(e) {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}

animate(num time) {

  window.requestAnimationFrame(animate);

  fontmesh.rotation.x += 0.005;
  fontmesh.rotation.y += 0.01;

  renderer.render(scene, camera);

}


<|start_filename|>tool/hop_runner.dart<|end_filename|>
library hop_runner;

import 'package:hop/hop.dart';
import 'package:hop/hop_tasks.dart';

void main(List<String> args) {
  //
  // Analyzer
  //
  addTask(
      'analyze_lib',
      createAnalyzerTask(
          [
              'lib/three.dart',
              'lib/extras/controls/first_person_controls.dart',
              'lib/extras/controls/trackball_controls.dart',
              'lib/extras/core/curve_utils.dart',
              'lib/extras/core/shape_utils.dart',
              'lib/extras/font_utils.dart',
              'lib/extras/geometry_utils.dart',
              'lib/extras/image_utils.dart',
              'lib/extras/image_utils.dart',
              'lib/extras/scene_utils.dart',
              'lib/extras/shader_utils.dart',
              'lib/extras/tween.dart',
              'lib/src/core/three_math.dart']));

  //
  // Doc generation
  //
  // addTask('docs', createDartDocTask(_getLibs));

  //
  // Hop away!
  //
  runHop(args);
}


<|start_filename|>lib/extras/core/spline_curve3.dart<|end_filename|>
part of three;

/**************************************************************
 *  Spline 3D curve
 **************************************************************/
class SplineCurve3 extends Curve3D {

  List<Vector3> points;

  SplineCurve3([this.points]) : super() {
    if (points == null) points = [];
  }

  Vector3 getPoint(t) {

    var v = new Vector3.zero();
    var c = new List<int>(4);
    var point = (points.length - 1) * t,
        intPoint = point.floor().toInt(),
        weight = point - intPoint;

    c[0] = intPoint == 0 ? intPoint : intPoint - 1;
    c[1] = intPoint;
    c[2] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1;
    c[3] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2;

    var pt0 = points[c[0]],
        pt1 = points[c[1]],
        pt2 = points[c[2]],
        pt3 = points[c[3]];

    v.x = CurveUtils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight);
    v.y = CurveUtils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight);
    v.z = CurveUtils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight);

    return v;

  }

}


<|start_filename|>example/web_gl_loader_stl/web_gl_loader_stl.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:vector_math/vector_math.dart' hide Ray;
import 'package:three/three.dart';

var container, stats;

var camera, cameraTarget, scene, renderer;

main() {
  init();
  animate(0);
}

init() {

  container = document.createElement('div');
  document.body.append(container);

  camera = new PerspectiveCamera(35.0, window.innerWidth / window.innerHeight, 1.0, 15.0);
  camera.position.setValues(3.0, 0.15, 3.0);

  cameraTarget = new Vector3(0.0, -0.25, 0.0);

  scene = new Scene();
  scene.fog = new FogLinear(0x72645b, 2.0, 15.0);

  // Ground

  var plane =
      new Mesh(new PlaneGeometry(40.0, 40.0), new MeshPhongMaterial(ambient: 0x999999, color: 0x999999, specular: 0x101010));
  plane.rotation.x = -Math.PI / 2;
  plane.position.y = -0.5;
  scene.add(plane);

  plane.receiveShadow = true;


  // ASCII file

  var loader = new STLLoader();

  loader.load('models/stl/ascii/slotted_disk.stl').then((geometry) {

    var material = new MeshPhongMaterial(ambient: 0xff5533, color: 0xff5533, specular: 0x111111, shininess: 200);
    var mesh = new Mesh(geometry, material);

    mesh.position.setValues(0.0, -0.25, 0.6);
    mesh.rotation.setValues(0.0, -Math.PI / 2, 0.0);
    mesh.scale.setValues(0.5, 0.5, 0.5);

    mesh.castShadow = true;
    mesh.receiveShadow = true;

    scene.add(mesh);
  });


  // Binary files

  var material = new MeshPhongMaterial(ambient: 0x555555, color: 0xAAAAAA, specular: 0x111111, shininess: 200);

  loader = new STLLoader();

  loader.load('./models/stl/binary/pr2_head_pan.stl').then((geometry) {
    var mesh = new Mesh(geometry, material);

    mesh.position.setValues(0.0, -0.37, -0.6);
    mesh.rotation.setValues(-Math.PI / 2, 0.0, 0.0);
    mesh.scale.setValues(2.0, 2.0, 2.0);

    mesh.castShadow = true;
    mesh.receiveShadow = true;

    scene.add(mesh);
  });

  loader = new STLLoader();
  loader.load('./models/stl/binary/pr2_head_tilt.stl').then((geometry) {

    var mesh = new Mesh(geometry, material);

    mesh.position.setValues(0.136, -0.37, -0.6);
    mesh.rotation.setValues(-Math.PI / 2, 0.3, 0.0);
    mesh.scale.setValues(2.0, 2.0, 2.0);

    mesh.castShadow = true;
    mesh.receiveShadow = true;

    scene.add(mesh);

  });


  // Lights

  scene.add(new AmbientLight(0x777777));

  addShadowedLight(1.0, 1.0, 1.0, 0xffffff, 1.35);
  addShadowedLight(0.5, 1.0, -1.0, 0xffaa00, 1.0);

  // renderer

  renderer = new WebGLRenderer(antialias: true, alpha: false);
  renderer.setSize(window.innerWidth, window.innerHeight);

  renderer.setClearColor(scene.fog.color, 1);

  renderer.gammaInput = true;
  renderer.gammaOutput = true;
  renderer.physicallyBasedShading = true;

  renderer.shadowMapEnabled = true;
  //renderer.shadowMapCullFace = CullFaceBack;

  container.append(renderer.domElement);


  window.onResize.listen(onWindowResize);

}

addShadowedLight(x, y, z, color, intensity) {

  var directionalLight = new DirectionalLight(color, intensity);
  directionalLight.position.setValues(x, y, z);
  scene.add(directionalLight);

  directionalLight.castShadow = true;
  // directionalLight.shadowCameraVisible = true;

  var d = 1.0;
  directionalLight.shadowCameraLeft = -d;
  directionalLight.shadowCameraRight = d;
  directionalLight.shadowCameraTop = d;
  directionalLight.shadowCameraBottom = -d;

  directionalLight.shadowCameraNear = 1.0;
  directionalLight.shadowCameraFar = 4.0;

  directionalLight.shadowMapWidth = 1024;
  directionalLight.shadowMapHeight = 1024;

  directionalLight.shadowBias = -0.005;
  directionalLight.shadowDarkness = 0.15;

}

onWindowResize(_) {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}

animate(num time) {

  window.requestAnimationFrame(animate);

  render();

}

var start_time = null;

render() {
  if (start_time == null) {
    start_time = new DateTime.now().millisecondsSinceEpoch;
  }
  var delta = new DateTime.now().millisecondsSinceEpoch - start_time,
      delta_in_sec = delta * 0.001;

  var timer = delta_in_sec * 0.5;

  camera.position.x = Math.cos(timer) * 3;
  camera.position.z = Math.sin(timer) * 3;

  camera.lookAt(cameraTarget);

  renderer.render(scene, camera);

}


<|start_filename|>example/web_gl_morph_targets/web_gl_morph_targets.dart<|end_filename|>
import 'dart:html';
import 'package:three/three.dart';

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;
Mesh mesh;
num windowHalfX = window.innerWidth / 2,
    windowHalfY = window.innerHeight / 2;
num mouseX = 0,
    mouseY = 0;

void main() {
  init();
  animate(0);
}

void init() {

  var idx = 0;
  querySelectorAll("input[type='range']").forEach((InputElement input) {
    var n = idx++;
    input.onChange.listen((_) => mesh.morphTargetInfluences[n] = input.valueAsNumber / 100);
  });

  container = new Element.tag('div');
  document.body.nodes.add(container);

  camera = new PerspectiveCamera(45.0, window.innerWidth / window.innerHeight, 1.0, 15000.0);
  camera.position.z = 500.0;

  scene = new Scene();

  var light = new PointLight(0xff2200);
  light.position.setValues(100.0, 100.0, 100.0);
  scene.add(light);

  scene.add(new AmbientLight(0x111111));

  var geometry = new CubeGeometry(100.0, 100.0, 100.0);
  var material = new MeshLambertMaterial(color: 0xffffff, morphTargets: true);

  // construct 8 blend shapes
  for (var i = 0; i < geometry.vertices.length; i++) {

    var vertices = [];

    for (var v = 0; v < geometry.vertices.length; v++) {

      vertices.add(geometry.vertices[v].clone());

      if (v == i) {

        vertices[vertices.length - 1].x *= 2;
        vertices[vertices.length - 1].y *= 2;
        vertices[vertices.length - 1].z *= 2;

      }

    }

    geometry.morphTargets.add(new MorphTarget(name: "target$i", vertices: vertices));

  }

  mesh = new Mesh(geometry, material);

  scene.add(mesh);


  renderer = new WebGLRenderer(clearColorHex: 0x222222, clearAlpha: 1);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.sortObjects = false;

  container.nodes.add(renderer.domElement);

  window.onResize.listen(onWindowResize);
  document.onMouseMove.listen(onDocumentMouseMove);

}

onWindowResize(event) {

  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

onDocumentMouseMove(event) {
  mouseX = (event.client.x - windowHalfX);
  mouseY = (event.client.y - windowHalfY) * 2;
}

animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

render() {

  mesh.rotation.y += 0.01;

  camera.position.y += (-mouseY - camera.position.y) * .01;

  camera.lookAt(scene.position);

  renderer.render(scene, camera);
}


<|start_filename|>lib/extras/shaders/parallax_shader.dart<|end_filename|>
part of three_shaders;

// Parallax Occlusion shaders from
//    http://sunandblackcat.com/tipFullView.php?topicid=28
// No tangent-space transforms logic based on
//   http://mmikkelsen3d.blogspot.sk/2012/02/parallaxpoc-mapping-and-no-tangent.html

var ParallaxShader = {
  // Ordered from fastest to best quality.
  'modes': {
    'none':  'NO_PARALLAX',
    'basic': 'USE_BASIC_PARALLAX',
    'steep': 'USE_STEEP_PARALLAX',
    'occlusion': 'USE_OCLUSION_PARALLAX', // a.k.a. POM
    'relief': 'USE_RELIEF_PARALLAX',
  },

  'uniforms': {
    "bumpMap": { 'type': "t", 'value': null },
    "map": { 'type': "t", 'value': null },
    "parallaxScale": { 'type': "f", 'value': null },
    "parallaxMinLayers": { 'type': "f", 'value': null },
    "parallaxMaxLayers": { 'type': "f", 'value': null }
  },

  'vertexShader': [
    "varying vec2 vUv;",
    "varying vec3 vViewPosition;",
    "varying vec3 vNormal;",

    "void main() {",

      "vUv = uv;",
      "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
      "vViewPosition = -mvPosition.xyz;",
      "vNormal = normalize( normalMatrix * normal );",
      "gl_Position = projectionMatrix * mvPosition;",

    "}"

  ].join( "\n" ),

  'fragmentShader': [
    "uniform sampler2D bumpMap;",
    "uniform sampler2D map;",

    "uniform float parallaxScale;",
    "uniform float parallaxMinLayers;",
    "uniform float parallaxMaxLayers;",

    "varying vec2 vUv;",
    "varying vec3 vViewPosition;",
    "varying vec3 vNormal;",

    "#ifdef USE_BASIC_PARALLAX",

      "vec2 parallaxMap( in vec3 V ) {",

        "float initialHeight = texture2D( bumpMap, vUv ).r;",

        // No Offset Limitting: messy, floating output at grazing angles.
        //"vec2 texCoordOffset = parallaxScale * V.xy / V.z * initialHeight;",

        // Offset Limiting
        "vec2 texCoordOffset = parallaxScale * V.xy * initialHeight;",
        "return vUv - texCoordOffset;",

      "}",

    "#else",

      "vec2 parallaxMap( in vec3 V ) {",

        // Determine number of layers from angle between V and N
        "float numLayers = mix( parallaxMaxLayers, parallaxMinLayers, abs( dot( vec3( 0.0, 0.0, 1.0 ), V ) ) );",

        "float layerHeight = 1.0 / numLayers;",
        "float currentLayerHeight = 0.0;",
        // Shift of texture coordinates for each iteration
        "vec2 dtex = parallaxScale * V.xy / V.z / numLayers;",

        "vec2 currentTextureCoords = vUv;",

        "float heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;",

        // while ( heightFromTexture > currentLayerHeight )
        "for ( int i = 0; i == 0; i += 0 ) {",
          "if ( heightFromTexture <= currentLayerHeight ) {",
            "break;",
          "}",
          "currentLayerHeight += layerHeight;",
          // Shift texture coordinates along vector V
          "currentTextureCoords -= dtex;",
          "heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;",
        "}",

        "#ifdef USE_STEEP_PARALLAX",

          "return currentTextureCoords;",

        "#elif defined( USE_RELIEF_PARALLAX )",

          "vec2 deltaTexCoord = dtex / 2.0;",
          "float deltaHeight = layerHeight / 2.0;",

          // Return to the mid point of previous layer
          "currentTextureCoords += deltaTexCoord;",
          "currentLayerHeight -= deltaHeight;",

          // Binary search to increase precision of Steep Parallax Mapping
          "const int numSearches = 5;",
          "for ( int i = 0; i < numSearches; i += 1 ) {",

            "deltaTexCoord /= 2.0;",
            "deltaHeight /= 2.0;",
            "heightFromTexture = texture2D( bumpMap, currentTextureCoords ).r;",
            // Shift along or against vector V
            "if( heightFromTexture > currentLayerHeight ) {", // Below the surface

              "currentTextureCoords -= deltaTexCoord;",
              "currentLayerHeight += deltaHeight;",

            "} else {", // above the surface

              "currentTextureCoords += deltaTexCoord;",
              "currentLayerHeight -= deltaHeight;",

            "}",

          "}",
          "return currentTextureCoords;",

        "#elif defined( USE_OCLUSION_PARALLAX )",

          "vec2 prevTCoords = currentTextureCoords + dtex;",

          // Heights for linear interpolation
          "float nextH = heightFromTexture - currentLayerHeight;",
          "float prevH = texture2D( bumpMap, prevTCoords ).r - currentLayerHeight + layerHeight;",

          // Proportions for linear interpolation
          "float weight = nextH / ( nextH - prevH );",

          // Interpolation of texture coordinates
          "return prevTCoords * weight + currentTextureCoords * ( 1.0 - weight );",

        "#else", // NO_PARALLAX

          "return vUv;",

        "#endif",

      "}",
    "#endif",

    "vec2 perturbUv( vec3 surfPosition, vec3 surfNormal, vec3 viewPosition ) {",

       "vec2 texDx = dFdx( vUv );",
      "vec2 texDy = dFdy( vUv );",

      "vec3 vSigmaX = dFdx( surfPosition );",
      "vec3 vSigmaY = dFdy( surfPosition );",
      "vec3 vR1 = cross( vSigmaY, surfNormal );",
      "vec3 vR2 = cross( surfNormal, vSigmaX );",
      "float fDet = dot( vSigmaX, vR1 );",

      "vec2 vProjVscr = ( 1.0 / fDet ) * vec2( dot( vR1, viewPosition ), dot( vR2, viewPosition ) );",
      "vec3 vProjVtex;",
      "vProjVtex.xy = texDx * vProjVscr.x + texDy * vProjVscr.y;",
      "vProjVtex.z = dot( surfNormal, viewPosition );",

      "return parallaxMap( vProjVtex );",
    "}",

    "void main() {",

      "vec2 mapUv = perturbUv( -vViewPosition, normalize( vNormal ), normalize( vViewPosition ) );",
      "gl_FragColor = texture2D( map, mapUv );",

    "}",

  ].join( "\n" )

};


<|start_filename|>lib/src/materials/mesh_face_material.dart<|end_filename|>
part of three;

/**
 * @author mr.doob / http://mrdoob.com/
 *
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

/// A Material to define multiple materials for the same geometry.
///
/// The geometry decides which material is used for which faces by the face's
/// materialindex.
/// The materialindex corresponds with the index of the material in the materials array.
class MeshFaceMaterial extends Material {
  /// Get or set the materials for the geometry.
  List materials = [];

  /// Creates a MeshFaceMaterial with the correct materials.
  MeshFaceMaterial([this.materials]);

}


<|start_filename|>lib/extras/core/spline_curve.dart<|end_filename|>
part of three;

class SplineCurve extends Curve2D {
  List<Vector2> points;

  SplineCurve([this.points = null]) {
    if (points == null) points = [];
  }

  getPoint(t) {

    var v = new Vector2.zero();
    var c = new List(4);
    var point, intPoint, weight;
    point = (points.length - 1) * t;

    intPoint = point.floor().toInt();
    weight = point - intPoint;

    c[0] = intPoint == 0 ? intPoint : intPoint - 1;
    c[1] = intPoint;
    c[2] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1;
    c[3] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2;

    v.x = CurveUtils.interpolate(points[c[0]].x, points[c[1]].x, points[c[2]].x, points[c[3]].x, weight);
    v.y = CurveUtils.interpolate(points[c[0]].y, points[c[1]].y, points[c[2]].y, points[c[3]].y, weight);

    return v;

  }
}


<|start_filename|>lib/src/lights/spot_light.dart<|end_filename|>
part of three;

/// A point light that can cast shadow in one direction.
///
/// Affects objects using MeshLambertMaterial or MeshPhongMaterial.
class SpotLight extends ShadowCaster {
  /// Spotlight focus points at target.position.
  Object3D target;

  /// Light's intensity.
  double intensity;
  /// If non-zero, light will attenuate linearly from maximum intensity at
  /// light position down to zero at distance.
  double distance;
  /// Maximum extent of the spotlight, in radians, from its direction.
  /// Should be no more than Math.PI/2.
  double angle;
  /// Rapidity of the falloff of light from its target direction.
  num exponent;

  SpotLight(num hex, [this.intensity = 1.0, this.distance = 0.0, this.angle = Math.PI /
      2, this.exponent = 10]) : super(hex) {
    //THREE.Light.call( this, hex );

    position = new Vector3(0.0, 1.0, 0.0);
    target = new Object3D();

    castShadow = false;
    onlyShadow = false;

    //

    shadowCameraNear = 50.0;
    shadowCameraFar = 5000.0;
    shadowCameraFov = 50.0;

    shadowCameraVisible = false;

    shadowBias = 0;
    shadowDarkness = 0.5;

    shadowMapWidth = 512;
    shadowMapHeight = 512;

    //

    shadowMap = null;
    shadowMapSize = null;
    shadowCamera = null;
    shadowMatrix = null;

  }
}


<|start_filename|>lib/src/core/matrix3.dart<|end_filename|>
part of three;

/**
 * Ported to Dart from JS by:
 * @author <NAME> / http://www.unwrong.com/
 */

/// A 3x3 matrix.
class Matrix3 {
  Float32List elements;

  Matrix3() : elements = new Float32List(9);

  /// Set this matrix to the inverse of the passed matrix.
  Matrix3 getInverse(Matrix4 matrix) {

    // input: THREE.Matrix4
    // ( based on http://code.google.com/p/webgl-mjs/ )

    var me = matrix.elements;

    var a11 = me[10] * me[5] - me[6] * me[9];
    var a21 = -me[10] * me[1] + me[2] * me[9];
    var a31 = me[6] * me[1] - me[2] * me[5];
    var a12 = -me[10] * me[4] + me[6] * me[8];
    var a22 = me[10] * me[0] - me[2] * me[8];
    var a32 = -me[6] * me[0] + me[2] * me[4];
    var a13 = me[9] * me[4] - me[5] * me[8];
    var a23 = -me[9] * me[0] + me[1] * me[8];
    var a33 = me[5] * me[0] - me[1] * me[4];

    var det = me[0] * a11 + me[1] * a12 + me[2] * a13;

    // no inverse

    if (det == 0) {

      print("Matrix3.getInverse(): determinant == 0");

    }

    var idet = 1.0 / det;

    var m = elements;

    m[0] = idet * a11;
    m[1] = idet * a21;
    m[2] = idet * a31;
    m[3] = idet * a12;
    m[4] = idet * a22;
    m[5] = idet * a32;
    m[6] = idet * a13;
    m[7] = idet * a23;
    m[8] = idet * a33;

    return this;

  }

  /// Transposes this matrix in place.
  Matrix3 transpose() {
    var tmp,
        m = elements;

    tmp = m[1];
    m[1] = m[3];
    m[3] = tmp;
    tmp = m[2];
    m[2] = m[6];
    m[6] = tmp;
    tmp = m[5];
    m[5] = m[7];
    m[7] = tmp;

    return this;
  }

  /// Transposes this matrix into the supplied array, and returns itself.
  Matrix3 transposeIntoArray(List r) {
    var m = elements;

    r[0] = m[0];
    r[1] = m[3];
    r[2] = m[6];
    r[3] = m[1];
    r[4] = m[4];
    r[5] = m[7];
    r[6] = m[2];
    r[7] = m[5];
    r[8] = m[8];

    return this;
  }

}


<|start_filename|>lib/extras/core/line_curve3.dart<|end_filename|>
part of three;

class LineCurve3 extends Curve3D {

  var v1, v2;

  LineCurve3(this.v1, this.v2) : super();

  Vector3 getPoint(double t) {

    Vector3 r = v2 - v1; // diff
    r.scale(t);
    r.add(v1);

    return r;

  }
}


<|start_filename|>lib/extras/geometries/polyhedron_geometry.dart<|end_filename|>
part of three;

class PolyhedronGeometry extends Geometry {

  List _midpoints;

  // nelsonsilva - We're using a PolyhedronGeometryVertex decorator to allow adding index and uv properties
  List<PolyhedronGeometryVertex> _p = [];

  PolyhedronGeometry(List<List<num>> lvertices, List<List<num>> lfaces, [double radius = 1.0, num detail = 0])
      : super() {

    _midpoints = [];

    lvertices.forEach((vertex) {
      _prepare(new PolyhedronGeometryVertex(vertex[0], vertex[1], vertex[2]));
    });

    lfaces.forEach((face) => _make(_p[face[0]], _p[face[1]], _p[face[2]], detail));

    // TODO No need to unwrap ? (now unwrapp and add the original Vector3 to the vertices)
    _p.forEach((v) => this.vertices.add(v));

    mergeVertices();

    // Apply radius

    this.vertices.forEach((Vector3 vertex) => vertex.scale(radius));

    computeCentroids();

    boundingSphere = new BoundingSphere(radius: radius);

  }

  // Project vector onto sphere's surface
  PolyhedronGeometryVertex _prepare(PolyhedronGeometryVertex vertex) {

    vertex.normalize();
    _p.add(vertex);
    vertex.index = _p.length - 1;

    // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle.

    var u = _azimuth(vertex) / 2 / Math.PI + 0.5;
    var v = _inclination(vertex) / Math.PI + 0.5;
    vertex.uv = new UV(u, 1 - v);

    return vertex;

  }


  // Approximate a curved face with recursively sub-divided triangles.

  _make(PolyhedronGeometryVertex v1, PolyhedronGeometryVertex v2, PolyhedronGeometryVertex v3, num detail) {

    if (detail < 1) {

      var face = new Face3(v1.index, v2.index, v3.index, [v1.clone(), v2.clone(), v3.clone()]);
      face.centroid.add(v1).add(v2).add(v3).scale(1.0 / 3.0);
      face.normal = face.centroid.clone().normalize();
      this.faces.add(face);

      var azi = _azimuth(face.centroid);
      this.faceVertexUvs[0].add([_correctUV(v1.uv, v1, azi), _correctUV(v2.uv, v2, azi), _correctUV(v3.uv, v3, azi)]);

    } else {

      detail -= 1;

      // split triangle into 4 smaller triangles

      _make(v1, _midpoint(v1, v2), _midpoint(v1, v3), detail); // top quadrant
      _make(_midpoint(v1, v2), v2, _midpoint(v2, v3), detail); // left quadrant
      _make(_midpoint(v1, v3), _midpoint(v2, v3), v3, detail); // right quadrant
      _make(_midpoint(v1, v2), _midpoint(v2, v3), _midpoint(v1, v3), detail); // center quadrant

    }

  }

  _midpoint(v1, v2) {

    // TODO - nelsonsilva - refactor this code
    // arrays don't "automagically" grow in Dart!
    if (_midpoints.length < v1.index + 1) {
      _midpoints.length = v1.index + 1;
      _midpoints[v1.index] = [];
    }
    if (_midpoints.length < v2.index + 1) {
      _midpoints.length = v2.index + 1;
      _midpoints[v2.index] = [];
    }

    // prepare _midpoints[ v1.index ][ v2.index ]
    if (_midpoints[v1.index] == null) {
      _midpoints[v1.index] = [];
    }

    if (_midpoints[v1.index].length < v2.index + 1) {
      _midpoints[v1.index].length = v2.index + 1;
    }

    // prepare _midpoints[ v2.index ][ v1.index ]
    if (_midpoints[v2.index] == null) {
      _midpoints[v2.index] = [];
    }

    if (_midpoints[v2.index].length < v1.index + 1) {
      _midpoints[v2.index].length = v1.index + 1;
    }

    var mid = _midpoints[v1.index][v2.index];

    if (mid == null) {

      // generate mean point and project to surface with prepare()
      mid = _prepare(new PolyhedronGeometryVertex.fromVector3((v1 + v2).scale(0.5)));
      _midpoints[v1.index][v2.index] = mid;
      _midpoints[v2.index][v1.index] = mid;
    }

    return mid;

  }

  /// Angle around the Y axis, counter-clockwise when looking from above.
  double _azimuth(Vector3 vector) => Math.atan2(vector.z, -vector.x);

  /// Angle above the XZ plane.
  double _inclination(Vector3 vector) =>
      Math.atan2(-vector.y, Math.sqrt((vector.x * vector.x) + (vector.z * vector.z)));

  /// Texture fixing helper. Spheres have some odd behaviours.
  UV _correctUV(UV uv, Vector3 vector, double azimuth) {
    if ((azimuth < 0) && (uv.u == 1)) uv = new UV(uv.u - 1, uv.v);
    if ((vector.x == 0) && (vector.z == 0)) uv = new UV(azimuth / 2 / Math.PI + 0.5, uv.v);
    return uv;

  }
}

/**
 * [PolyhedronGeometryVertex] is a [Vector3] decorator to allow introducing [index] and [uv].
 * */
class PolyhedronGeometryVertex extends Vector3 {
  int index;
  UV uv;
  PolyhedronGeometryVertex([num x = 0.0, num y = 0.0, num z = 0.0]) : super(x.toDouble(), y.toDouble(), z.toDouble());

  PolyhedronGeometryVertex.fromVector3(Vector3 other) : super.copy(other);
}


<|start_filename|>lib/extras/geometries/tube_geometry.dart<|end_filename|>
part of three;

/**
 * @author WestLangley / https://github.com/WestLangley
 * @author zz85 / https://github.com/zz85
 * @author miningold / https://github.com/miningold
 *
 * Modified from the TorusKnotGeometry by @oosmoxiecode
 *
 * Creates a tube which extrudes along a 3d spline
 *
 * Uses parallel transport frames as described in
 * http://www.cs.indiana.edu/pub/techreports/TR425.pdf
 */

class TubeGeometry extends Geometry {

  var path, segments;
  num nSegments, radius, segmentsRadius;
  bool closed;

  var grid;
  List<Vector3> tangents, normals, binormals;

  Object3D debug;

  TubeGeometry(path, [int segments = 64, this.radius = 1.0, this.segmentsRadius = 8, bool closed = false, bool debug])
      : grid = [],
        super() {

    if (debug) this.debug = new Object3D();

    var tangent,
        normal,
        binormal,

        numpoints = segments + 1,

        x,
        y,
        z,
        tx,
        ty,
        tz,
        u,
        v,

        cx,
        cy,
        pos,
        pos2 = new Vector3.zero(),
        i,
        j,
        ip,
        jp,
        a,
        b,
        c,
        d,
        uva,
        uvb,
        uvc,
        uvd;

    var frames = _frenetFrames(path, segments, closed);

    // consruct the grid
    grid.length = numpoints;

    for (i = 0; i < numpoints; i++) {

      grid[i] = new List(this.segmentsRadius);

      u = i / (numpoints - 1);

      pos = path.getPointAt(u);

      tangent = tangents[i];
      normal = normals[i];
      binormal = binormals[i];

      if (debug) {

        this.debug.add(new ArrowHelper(tangent, pos, radius, 0x0000ff));
        this.debug.add(new ArrowHelper(normal, pos, radius, 0xff0000));
        this.debug.add(new ArrowHelper(binormal, pos, radius, 0x00ff00));

      }

      for (j = 0; j < this.segmentsRadius; j++) {

        v = j / this.segmentsRadius * 2 * Math.PI;

        cx = -this.radius * Math.cos(v); // TODO: Hack: Negating it so it faces outside.
        cy = this.radius * Math.sin(v);

        pos2.setFrom(pos);
        pos2.x += cx * normal.x + cy * binormal.x;
        pos2.y += cx * normal.y + cy * binormal.y;
        pos2.z += cx * normal.z + cy * binormal.z;

        this.grid[i][j] = _vert(pos2.x, pos2.y, pos2.z);

      }
    }


    // construct the mesh

    for (i = 0; i < this.nSegments; i++) {

      for (j = 0; j < this.segmentsRadius; j++) {

        ip = (closed) ? (i + 1) % this.nSegments : i + 1;
        jp = (j + 1) % this.segmentsRadius;

        a = this.grid[i][j]; // *** NOT NECESSARILY PLANAR ! ***
        b = this.grid[ip][j];
        c = this.grid[ip][jp];
        d = this.grid[i][jp];

        uva = new UV(i / this.nSegments, j / this.segmentsRadius);
        uvb = new UV((i + 1) / this.nSegments, j / this.segmentsRadius);
        uvc = new UV((i + 1) / this.nSegments, (j + 1) / this.segmentsRadius);
        uvd = new UV(i / this.nSegments, (j + 1) / this.segmentsRadius);

        this.faces.add(new Face4(a, b, c, d));
        this.faceVertexUvs[0].add([uva, uvb, uvc, uvd]);

      }
    }

    computeCentroids();
    computeFaceNormals();
    computeVertexNormals();

  }


  int _vert(double x, double y, double z) {
    vertices.add(new Vector3(x, y, z));
    return vertices.length - 1;
  }


  // FrenetFrames


  TubeGeometry.FrenetFrames(path, segments, closed) {
    _frenetFrames(path, segments, closed);
  }

// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
  _frenetFrames(ppath, psegments, bool pclosed) {

    this.path = ppath;
    this.segments = psegments;

    this.closed = pclosed;

    var tangent = new Vector3.zero(),
        normal = new Vector3.zero(),
        binormal = new Vector3.zero(),

        mat = new Matrix4.identity(),
        theta,
        epsilon = 0.0001,
        smallest,

        tx,
        ty,
        tz,
        i,
        u,
        v;

    if (segments is num) {
      var length = segments;
      segments = [];
      for (i = 1; i <= length; i++) {
        segments.add(i / (length));
      }
    }
    this.nSegments = segments.length;
    var numpoints = this.nSegments + 1;

    // expose internals
    tangents = new List<Vector3>(numpoints);
    normals = new List<Vector3>(numpoints);
    binormals = new List<Vector3>(numpoints);

    // compute the tangent vectors for each segment on the path

    for (i = 0; i < numpoints; i++) {
      tangents[i] = (i == 0) ? path.getTangentAt(0) : path.getTangentAt(segments[i - 1]);
      tangents[i].normalize();
    }

    _initialNormal1([lastBinormal = null]) {
      // fixed start binormal. Has dangers of 0 vectors
      if (lastBinormal == null) lastBinormal = new Vector3(0.0, 0.0, 1.0);
      normals[0] = lastBinormal.cross(tangents[0]).normalize();
      binormals[0] = tangents[0].cross(normals[0]).normalize();
    }

    _initialNormal2() {
      // This uses the Frenet-Serret formula for deriving binormal
      var t2 = path.getTangentAt(epsilon);

      normals[0] = (t2 - tangents[0]).normalize();
      binormals[0] = tangents[0].cross(normals[0]);

      normals[0] = binormals[0].cross(tangents[0]).normalize(); // last binormal x tangent
      binormals[0] = tangents[0].cross(normals[0]).normalize();

    }

    _initialNormal3() {
      // select an initial normal vector perpenicular to the first tangent vector,
      // and in the direction of the smallest tangent xyz component

      smallest = double.INFINITY;
      tx = (tangents[0].x).abs();
      ty = (tangents[0].y).abs();
      tz = (tangents[0].z).abs();

      if (tx <= smallest) {
        smallest = tx;
        normal.setValues(1.0, 0.0, 0.0);
      }

      if (ty <= smallest) {
        smallest = ty;
        normal.setValues(0.0, 1.0, 0.0);
      }

      if (tz <= smallest) {
        normal.setValues(0.0, 0.0, 1.0);
      }

      Vector3 vec = tangents[0].cross(normal).normalize();

      normals[0] = tangents[0].cross(vec);
      binormals[0] = tangents[0].cross(normals[0]);
    }

    _initialNormal3();


    // compute the slowly-varying normal and binormal vectors for each segment on the path

    for (i = 1; i < numpoints; i++) {

      normals[i] = normals[i - 1].clone();

      binormals[i] = binormals[i - 1].clone();

      Vector3 vec = tangents[i - 1].cross(tangents[i]);

      if (vec.length > epsilon) {

        vec.normalize();

        theta = Math.acos(tangents[i - 1].dot(tangents[i]));

        normals[i].applyProjection(makeRotationAxis(mat, vec, theta));
      }

      binormals[i] = tangents[i].cross(normals[i]);

    }


    // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same

    if (closed) {

      theta = Math.acos(normals[0].dot(normals[numpoints - 1]));
      theta /= (numpoints - 1);

      if (tangents[0].dot(normals[0].cross(normals[numpoints - 1])) > 0) {

        theta = -theta;

      }

      for (i = 1; i < numpoints; i++) {

        // twist a little...
        normals[i].applyProjection(makeRotationAxis(mat, tangents[i], theta * i));
        binormals[i] = tangents[i].cross(normals[i]);

      }

    }
  }
}


<|start_filename|>lib/extras/shaders/blend_shader.dart<|end_filename|>
part of three_shaders;

/**
 * @author alteredq / http://alteredqualia.com/
 *
 * Blend two textures
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

var BlendShader = {

  'uniforms': {

    "tDiffuse1": { 'type': "t", 'value': null },
    "tDiffuse2": { 'type': "t", 'value': null },
    "mixRatio":  { 'type': "f", 'value': 0.5 },
    "opacity":   { 'type': "f", 'value': 1.0 }

  },

  'vertexShader': [

    "varying vec2 vUv;",

    "void main() {",

      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

    "}"

  ].join("\n"),

  'fragmentShader': [

    "uniform float opacity;",
    "uniform float mixRatio;",

    "uniform sampler2D tDiffuse1;",
    "uniform sampler2D tDiffuse2;",

    "varying vec2 vUv;",

    "void main() {",

      "vec4 texel1 = texture2D( tDiffuse1, vUv );",
      "vec4 texel2 = texture2D( tDiffuse2, vUv );",
      "gl_FragColor = opacity * mix( texel1, texel2, mixRatio );",

    "}"

  ].join("\n")

};


<|start_filename|>lib/extras/geometries/torus_geometry.dart<|end_filename|>
part of three;

class TorusGeometry extends Geometry {
  num radius, tube, segmentsR, segmentsT, arc;

  TorusGeometry([this.radius = 100, this.tube = 40, this.segmentsR = 8, this.segmentsT = 6, this.arc = Math.PI *
      2]) : super() {

    var center = new Vector3.zero();
    var uvs = <UV>[];
    var normals = <Vector3>[];

    for (var j = 0; j <= this.segmentsR; j++) {

      for (var i = 0; i <= this.segmentsT; i++) {

        var u = i / this.segmentsT * this.arc;
        var v = j / this.segmentsR * Math.PI * 2;

        center.x = this.radius * Math.cos(u);
        center.y = this.radius * Math.sin(u);

        var vertex = new Vector3.zero();
        vertex.x = (this.radius + this.tube * Math.cos(v)) * Math.cos(u);
        vertex.y = (this.radius + this.tube * Math.cos(v)) * Math.sin(u);
        vertex.z = this.tube * Math.sin(v);

        this.vertices.add(vertex);

        uvs.add(new UV(i / this.segmentsT, j / this.segmentsR));
        normals.add(vertex.clone().sub(center).normalize());

      }
    }


    for (var j = 1; j <= this.segmentsR; j++) {

      for (var i = 1; i <= this.segmentsT; i++) {

        var a = (this.segmentsT + 1) * j + i - 1;
        var b = (this.segmentsT + 1) * (j - 1) + i - 1;
        var c = (this.segmentsT + 1) * (j - 1) + i;
        var d = (this.segmentsT + 1) * j + i;

        var face = new Face4(a, b, c, d, [normals[a], normals[b], normals[c], normals[d]]);
        face.normal.add(normals[a]);
        face.normal.add(normals[b]);
        face.normal.add(normals[c]);
        face.normal.add(normals[d]);
        face.normal.normalize();

        this.faces.add(face);

        this.faceVertexUvs[0].add([uvs[a].clone(), uvs[b].clone(), uvs[c].clone(), uvs[d].clone()]);
      }

    }

    this.computeCentroids();

  }
}


<|start_filename|>example/web_gl_performance/web_gl_performance.dart<|end_filename|>
import 'dart:html';
import 'dart:math' as Math;
import 'package:three/three.dart';

Element container;

PerspectiveCamera camera;
Scene scene;
WebGLRenderer renderer;

var windowHalfX, windowHalfY;
var mouseX = 0,
    mouseY = 0;

List objects = [];

void main() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  document.onMouseMove.listen(onDocumentMouseMove);

  init();
  animate(0);
}

void init() {

  container = new Element.tag('div');
  document.body.nodes.add(container);

  camera = new PerspectiveCamera(60.0, window.innerWidth / window.innerHeight, 1.0, 10000.0);
  camera.position.z = 3200.0;

  scene = new Scene();

  var material = new MeshNormalMaterial(shading: SmoothShading);

  var loader = new JSONLoader();
  loader.load('obj/Suzanne.js', (geometry) {

    geometry.computeVertexNormals();

    var rnd = new Math.Random();

    for (int i = 0; i < 5000; i++) {

      var mesh = new Mesh(geometry, material);

      mesh.position.x = rnd.nextDouble() * 8000 - 4000;
      mesh.position.y = rnd.nextDouble() * 8000 - 4000;
      mesh.position.z = rnd.nextDouble() * 8000 - 4000;
      mesh.rotation.x = rnd.nextDouble() * 360 * (Math.PI / 180);
      mesh.rotation.y = rnd.nextDouble() * 360 * (Math.PI / 180);
      mesh.scale.x = mesh.scale.y = mesh.scale.z = rnd.nextDouble() * 50 + 100;

      objects.add(mesh);

      scene.add(mesh);

    }

  });

  renderer = new WebGLRenderer(clearColorHex: 0xffffff);
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.children.add(renderer.domElement);

  window.onResize.listen(onWindowResize);
}

onWindowResize(event) {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

onDocumentMouseMove(MouseEvent event) {
  mouseX = (event.client.x - windowHalfX) * 10;
  mouseY = (event.client.y - windowHalfY) * 10;
}

animate(num time) {
  window.requestAnimationFrame(animate);
  render();
}

render() {

  camera.position.x += (mouseX - camera.position.x) * .05;
  camera.position.y += (-mouseY - camera.position.y) * .05;
  camera.lookAt(scene.position);

  for (var i = 0,
      il = objects.length; i < il; i++) {

    objects[i].rotation.x += 0.01;
    objects[i].rotation.y += 0.02;

  }


  renderer.render(scene, camera);

}


<|start_filename|>lib/extras/postprocessing/postprocessing.dart<|end_filename|>
library three_postprocessing;

/*
 * Three.js Postprocessing Library
 *
 * Ported to Dart from JS by:
 * @author <NAME> / https://github.com/cgrabowski
 */

import 'dart:html';
import 'package:three/three.dart';
import 'package:three/extras/shaders/shaders.dart';

part 'bokeh_pass.dart';
part 'effect_composer.dart';
part 'pass.dart';
part 'render_pass.dart';
part 'shader_pass.dart';
